projects/linux·blob master · refs

386 lines · 9.5 KiB

1// SPDX-License-Identifier: GPL-2.0
2/*
3 * AMD IOMMU driver
4 *
5 * Copyright (C) 2018 Advanced Micro Devices, Inc.
6 *
7 * Author: Gary R Hook <[email protected]>
8 */
9
10#include <linux/debugfs.h>
11#include <linux/pci.h>
12
13#include "amd_iommu.h"
14#include "../irq_remapping.h"
15
16static struct dentry *amd_iommu_debugfs;
17
18#define MAX_NAME_LEN 20
19#define OFS_IN_SZ 8
20#define DEVID_IN_SZ 16
21
22static int sbdf = -1;
23
24static ssize_t iommu_mmio_write(struct file *filp, const char __user *ubuf,
25 size_t cnt, loff_t *ppos)
26{
27 struct seq_file *m = filp->private_data;
28 struct amd_iommu *iommu = m->private;
29 int ret, dbg_mmio_offset = iommu->dbg_mmio_offset = -1;
30
31 if (cnt > OFS_IN_SZ)
32 return -EINVAL;
33
34 ret = kstrtos32_from_user(ubuf, cnt, 0, &dbg_mmio_offset);
35 if (ret)
36 return ret;
37
38 if (dbg_mmio_offset < 0 || dbg_mmio_offset >
39 iommu->mmio_phys_end - sizeof(u64))
40 return -EINVAL;
41
42 iommu->dbg_mmio_offset = dbg_mmio_offset;
43 return cnt;
44}
45
46static int iommu_mmio_show(struct seq_file *m, void *unused)
47{
48 struct amd_iommu *iommu = m->private;
49 u64 value;
50 int dbg_mmio_offset = iommu->dbg_mmio_offset;
51
52 if (dbg_mmio_offset < 0 || dbg_mmio_offset >
53 iommu->mmio_phys_end - sizeof(u64)) {
54 seq_puts(m, "Please provide mmio register's offset\n");
55 return 0;
56 }
57
58 value = readq(iommu->mmio_base + dbg_mmio_offset);
59 seq_printf(m, "Offset:0x%x Value:0x%016llx\n", dbg_mmio_offset, value);
60
61 return 0;
62}
63DEFINE_SHOW_STORE_ATTRIBUTE(iommu_mmio);
64
65static ssize_t iommu_capability_write(struct file *filp, const char __user *ubuf,
66 size_t cnt, loff_t *ppos)
67{
68 struct seq_file *m = filp->private_data;
69 struct amd_iommu *iommu = m->private;
70 int ret, dbg_cap_offset = iommu->dbg_cap_offset = -1;
71
72 if (cnt > OFS_IN_SZ)
73 return -EINVAL;
74
75 ret = kstrtos32_from_user(ubuf, cnt, 0, &dbg_cap_offset);
76 if (ret)
77 return ret;
78
79 /* Capability register at offset 0x14 is the last IOMMU capability register. */
80 if (dbg_cap_offset < 0 || dbg_cap_offset > 0x14)
81 return -EINVAL;
82
83 iommu->dbg_cap_offset = dbg_cap_offset;
84 return cnt;
85}
86
87static int iommu_capability_show(struct seq_file *m, void *unused)
88{
89 struct amd_iommu *iommu = m->private;
90 u32 value;
91 int err, dbg_cap_offset = iommu->dbg_cap_offset;
92
93 if (dbg_cap_offset < 0 || dbg_cap_offset > 0x14) {
94 seq_puts(m, "Please provide capability register's offset in the range [0x00 - 0x14]\n");
95 return 0;
96 }
97
98 err = pci_read_config_dword(iommu->dev, iommu->cap_ptr + dbg_cap_offset, &value);
99 if (err) {
100 seq_printf(m, "Not able to read capability register at 0x%x\n",
101 dbg_cap_offset);
102 return 0;
103 }
104
105 seq_printf(m, "Offset:0x%x Value:0x%08x\n", dbg_cap_offset, value);
106
107 return 0;
108}
109DEFINE_SHOW_STORE_ATTRIBUTE(iommu_capability);
110
111static int iommu_cmdbuf_show(struct seq_file *m, void *unused)
112{
113 struct amd_iommu *iommu = m->private;
114 struct iommu_cmd *cmd;
115 unsigned long flag;
116 u32 head, tail;
117 int i;
118
119 raw_spin_lock_irqsave(&iommu->lock, flag);
120 head = readl(iommu->mmio_base + MMIO_CMD_HEAD_OFFSET);
121 tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
122 seq_printf(m, "CMD Buffer Head Offset:%d Tail Offset:%d\n",
123 (head >> 4) & 0x7fff, (tail >> 4) & 0x7fff);
124 for (i = 0; i < CMD_BUFFER_ENTRIES; i++) {
125 cmd = (struct iommu_cmd *)(iommu->cmd_buf + i * sizeof(*cmd));
126 seq_printf(m, "%3d: %08x %08x %08x %08x\n", i, cmd->data[0],
127 cmd->data[1], cmd->data[2], cmd->data[3]);
128 }
129 raw_spin_unlock_irqrestore(&iommu->lock, flag);
130
131 return 0;
132}
133DEFINE_SHOW_ATTRIBUTE(iommu_cmdbuf);
134
135static ssize_t devid_write(struct file *filp, const char __user *ubuf,
136 size_t cnt, loff_t *ppos)
137{
138 struct amd_iommu_pci_seg *pci_seg;
139 int seg, bus, slot, func;
140 struct amd_iommu *iommu;
141 char *srcid_ptr;
142 u16 devid;
143 int i;
144
145 sbdf = -1;
146
147 if (cnt >= DEVID_IN_SZ)
148 return -EINVAL;
149
150 srcid_ptr = memdup_user_nul(ubuf, cnt);
151 if (IS_ERR(srcid_ptr))
152 return PTR_ERR(srcid_ptr);
153
154 i = sscanf(srcid_ptr, "%x:%x:%x.%x", &seg, &bus, &slot, &func);
155 if (i != 4) {
156 i = sscanf(srcid_ptr, "%x:%x.%x", &bus, &slot, &func);
157 if (i != 3) {
158 kfree(srcid_ptr);
159 return -EINVAL;
160 }
161 seg = 0;
162 }
163
164 devid = PCI_DEVID(bus, PCI_DEVFN(slot, func));
165
166 /* Check if user device id input is a valid input */
167 for_each_pci_segment(pci_seg) {
168 if (pci_seg->id != seg)
169 continue;
170 if (devid > pci_seg->last_bdf) {
171 kfree(srcid_ptr);
172 return -EINVAL;
173 }
174 iommu = pci_seg->rlookup_table[devid];
175 if (!iommu) {
176 kfree(srcid_ptr);
177 return -ENODEV;
178 }
179 sbdf = PCI_SEG_DEVID_TO_SBDF(seg, devid);
180 kfree(srcid_ptr);
181 return cnt;
182 }
183
184 kfree(srcid_ptr);
185 return -EINVAL;
186}
187
188static int devid_show(struct seq_file *m, void *unused)
189{
190 u16 devid;
191 int sbdf_shadow = sbdf;
192
193 if (sbdf_shadow >= 0) {
194 devid = PCI_SBDF_TO_DEVID(sbdf_shadow);
195 seq_printf(m, "%04x:%02x:%02x.%x\n", PCI_SBDF_TO_SEGID(sbdf_shadow),
196 PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid));
197 } else
198 seq_puts(m, "No or Invalid input provided\n");
199
200 return 0;
201}
202DEFINE_SHOW_STORE_ATTRIBUTE(devid);
203
204static void dump_dte(struct seq_file *m, struct amd_iommu_pci_seg *pci_seg, u16 devid)
205{
206 struct dev_table_entry *dev_table;
207 struct amd_iommu *iommu;
208
209 iommu = pci_seg->rlookup_table[devid];
210 if (!iommu)
211 return;
212
213 dev_table = get_dev_table(iommu);
214 if (!dev_table) {
215 seq_puts(m, "Device table not found");
216 return;
217 }
218
219 seq_printf(m, "%-12s %16s %16s %16s %16s iommu\n", "DeviceId",
220 "QWORD[3]", "QWORD[2]", "QWORD[1]", "QWORD[0]");
221 seq_printf(m, "%04x:%02x:%02x.%x ", pci_seg->id, PCI_BUS_NUM(devid),
222 PCI_SLOT(devid), PCI_FUNC(devid));
223 for (int i = 3; i >= 0; --i)
224 seq_printf(m, "%016llx ", dev_table[devid].data[i]);
225 seq_printf(m, "iommu%d\n", iommu->index);
226}
227
228static int iommu_devtbl_show(struct seq_file *m, void *unused)
229{
230 struct amd_iommu_pci_seg *pci_seg;
231 u16 seg, devid;
232 int sbdf_shadow = sbdf;
233
234 if (sbdf_shadow < 0) {
235 seq_puts(m, "Enter a valid device ID to 'devid' file\n");
236 return 0;
237 }
238 seg = PCI_SBDF_TO_SEGID(sbdf_shadow);
239 devid = PCI_SBDF_TO_DEVID(sbdf_shadow);
240
241 for_each_pci_segment(pci_seg) {
242 if (pci_seg->id != seg)
243 continue;
244 dump_dte(m, pci_seg, devid);
245 break;
246 }
247
248 return 0;
249}
250DEFINE_SHOW_ATTRIBUTE(iommu_devtbl);
251
252static void dump_128_irte(struct seq_file *m, struct irq_remap_table *table, u16 int_tab_len)
253{
254 struct irte_ga *ptr, *irte;
255 int index;
256
257 for (index = 0; index < int_tab_len; index++) {
258 ptr = (struct irte_ga *)table->table;
259 irte = &ptr[index];
260
261 if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) &&
262 !irte->lo.fields_vapic.valid)
263 continue;
264 else if (!irte->lo.fields_remap.valid)
265 continue;
266 seq_printf(m, "IRT[%04d] %016llx %016llx\n", index, irte->hi.val, irte->lo.val);
267 }
268}
269
270static void dump_32_irte(struct seq_file *m, struct irq_remap_table *table, u16 int_tab_len)
271{
272 union irte *ptr, *irte;
273 int index;
274
275 for (index = 0; index < int_tab_len; index++) {
276 ptr = (union irte *)table->table;
277 irte = &ptr[index];
278
279 if (!irte->fields.valid)
280 continue;
281 seq_printf(m, "IRT[%04d] %08x\n", index, irte->val);
282 }
283}
284
285static void dump_irte(struct seq_file *m, u16 devid, struct amd_iommu_pci_seg *pci_seg)
286{
287 struct dev_table_entry *dev_table;
288 struct irq_remap_table *table;
289 struct amd_iommu *iommu;
290 unsigned long flags;
291 u16 int_tab_len;
292
293 table = pci_seg->irq_lookup_table[devid];
294 if (!table) {
295 seq_printf(m, "IRQ lookup table not set for %04x:%02x:%02x:%x\n",
296 pci_seg->id, PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid));
297 return;
298 }
299
300 iommu = pci_seg->rlookup_table[devid];
301 if (!iommu)
302 return;
303
304 dev_table = get_dev_table(iommu);
305 if (!dev_table) {
306 seq_puts(m, "Device table not found");
307 return;
308 }
309
310 int_tab_len = dev_table[devid].data[2] & DTE_INTTABLEN_MASK;
311 if (int_tab_len != DTE_INTTABLEN_512 && int_tab_len != DTE_INTTABLEN_2K) {
312 seq_puts(m, "The device's DTE contains an invalid IRT length value.");
313 return;
314 }
315
316 seq_printf(m, "DeviceId %04x:%02x:%02x.%x\n", pci_seg->id, PCI_BUS_NUM(devid),
317 PCI_SLOT(devid), PCI_FUNC(devid));
318
319 raw_spin_lock_irqsave(&table->lock, flags);
320 if (AMD_IOMMU_GUEST_IR_GA(amd_iommu_guest_ir))
321 dump_128_irte(m, table, BIT(int_tab_len >> 1));
322 else
323 dump_32_irte(m, table, BIT(int_tab_len >> 1));
324 seq_puts(m, "\n");
325 raw_spin_unlock_irqrestore(&table->lock, flags);
326}
327
328static int iommu_irqtbl_show(struct seq_file *m, void *unused)
329{
330 struct amd_iommu_pci_seg *pci_seg;
331 u16 devid, seg;
332 int sbdf_shadow = sbdf;
333
334 if (!irq_remapping_enabled) {
335 seq_puts(m, "Interrupt remapping is disabled\n");
336 return 0;
337 }
338
339 if (sbdf_shadow < 0) {
340 seq_puts(m, "Enter a valid device ID to 'devid' file\n");
341 return 0;
342 }
343
344 seg = PCI_SBDF_TO_SEGID(sbdf_shadow);
345 devid = PCI_SBDF_TO_DEVID(sbdf_shadow);
346
347 for_each_pci_segment(pci_seg) {
348 if (pci_seg->id != seg)
349 continue;
350 dump_irte(m, devid, pci_seg);
351 break;
352 }
353
354 return 0;
355}
356DEFINE_SHOW_ATTRIBUTE(iommu_irqtbl);
357
358void amd_iommu_debugfs_setup(void)
359{
360 struct amd_iommu *iommu;
361 char name[MAX_NAME_LEN + 1];
362
363 amd_iommu_debugfs = debugfs_create_dir("amd", iommu_debugfs_dir);
364
365 for_each_iommu(iommu) {
366 iommu->dbg_mmio_offset = -1;
367 iommu->dbg_cap_offset = -1;
368
369 snprintf(name, MAX_NAME_LEN, "iommu%02d", iommu->index);
370 iommu->debugfs = debugfs_create_dir(name, amd_iommu_debugfs);
371
372 debugfs_create_file("mmio", 0644, iommu->debugfs, iommu,
373 &iommu_mmio_fops);
374 debugfs_create_file("capability", 0644, iommu->debugfs, iommu,
375 &iommu_capability_fops);
376 debugfs_create_file("cmdbuf", 0444, iommu->debugfs, iommu,
377 &iommu_cmdbuf_fops);
378 }
379
380 debugfs_create_file("devid", 0644, amd_iommu_debugfs, NULL,
381 &devid_fops);
382 debugfs_create_file("devtbl", 0444, amd_iommu_debugfs, NULL,
383 &iommu_devtbl_fops);
384 debugfs_create_file("irqtbl", 0444, amd_iommu_debugfs, NULL,
385 &iommu_irqtbl_fops);
386}