Skip to content

Commit 349ad6d

Browse files
dhsrivaswilldeacon
authored andcommitted
iommu/amd: Add debugfs support to dump IRT Table
In cases where we have an issue in the device interrupt path with IOMMU interrupt remapping enabled, dumping valid IRT table entries for the device is very useful and good input for debugging the issue. eg. -> To dump irte entries for a particular device #echo "c4:00.0" > /sys/kernel/debug/iommu/amd/devid #cat /sys/kernel/debug/iommu/amd/irqtbl | less or #echo "0000:c4:00.0" > /sys/kernel/debug/iommu/amd/devid #cat /sys/kernel/debug/iommu/amd/irqtbl | less Signed-off-by: Dheeraj Kumar Srivastava <[email protected]> Reviewed-by: Vasant Hegde <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent b484577 commit 349ad6d

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

drivers/iommu/amd/debugfs.c

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/pci.h>
1212

1313
#include "amd_iommu.h"
14+
#include "../irq_remapping.h"
1415

1516
static struct dentry *amd_iommu_debugfs;
1617

@@ -255,6 +256,111 @@ static int iommu_devtbl_show(struct seq_file *m, void *unused)
255256
}
256257
DEFINE_SHOW_ATTRIBUTE(iommu_devtbl);
257258

259+
static void dump_128_irte(struct seq_file *m, struct irq_remap_table *table, u16 int_tab_len)
260+
{
261+
struct irte_ga *ptr, *irte;
262+
int index;
263+
264+
for (index = 0; index < int_tab_len; index++) {
265+
ptr = (struct irte_ga *)table->table;
266+
irte = &ptr[index];
267+
268+
if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) &&
269+
!irte->lo.fields_vapic.valid)
270+
continue;
271+
else if (!irte->lo.fields_remap.valid)
272+
continue;
273+
seq_printf(m, "IRT[%04d] %016llx %016llx\n", index, irte->hi.val, irte->lo.val);
274+
}
275+
}
276+
277+
static void dump_32_irte(struct seq_file *m, struct irq_remap_table *table, u16 int_tab_len)
278+
{
279+
union irte *ptr, *irte;
280+
int index;
281+
282+
for (index = 0; index < int_tab_len; index++) {
283+
ptr = (union irte *)table->table;
284+
irte = &ptr[index];
285+
286+
if (!irte->fields.valid)
287+
continue;
288+
seq_printf(m, "IRT[%04d] %08x\n", index, irte->val);
289+
}
290+
}
291+
292+
static void dump_irte(struct seq_file *m, u16 devid, struct amd_iommu_pci_seg *pci_seg)
293+
{
294+
struct dev_table_entry *dev_table;
295+
struct irq_remap_table *table;
296+
struct amd_iommu *iommu;
297+
unsigned long flags;
298+
u16 int_tab_len;
299+
300+
table = pci_seg->irq_lookup_table[devid];
301+
if (!table) {
302+
seq_printf(m, "IRQ lookup table not set for %04x:%02x:%02x:%x\n",
303+
pci_seg->id, PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid));
304+
return;
305+
}
306+
307+
iommu = pci_seg->rlookup_table[devid];
308+
if (!iommu)
309+
return;
310+
311+
dev_table = get_dev_table(iommu);
312+
if (!dev_table) {
313+
seq_puts(m, "Device table not found");
314+
return;
315+
}
316+
317+
int_tab_len = dev_table[devid].data[2] & DTE_INTTABLEN_MASK;
318+
if (int_tab_len != DTE_INTTABLEN_512 && int_tab_len != DTE_INTTABLEN_2K) {
319+
seq_puts(m, "The device's DTE contains an invalid IRT length value.");
320+
return;
321+
}
322+
323+
seq_printf(m, "DeviceId %04x:%02x:%02x.%x\n", pci_seg->id, PCI_BUS_NUM(devid),
324+
PCI_SLOT(devid), PCI_FUNC(devid));
325+
326+
raw_spin_lock_irqsave(&table->lock, flags);
327+
if (AMD_IOMMU_GUEST_IR_GA(amd_iommu_guest_ir))
328+
dump_128_irte(m, table, BIT(int_tab_len >> 1));
329+
else
330+
dump_32_irte(m, table, BIT(int_tab_len >> 1));
331+
seq_puts(m, "\n");
332+
raw_spin_unlock_irqrestore(&table->lock, flags);
333+
}
334+
335+
static int iommu_irqtbl_show(struct seq_file *m, void *unused)
336+
{
337+
struct amd_iommu_pci_seg *pci_seg;
338+
u16 devid, seg;
339+
340+
if (!irq_remapping_enabled) {
341+
seq_puts(m, "Interrupt remapping is disabled\n");
342+
return 0;
343+
}
344+
345+
if (sbdf < 0) {
346+
seq_puts(m, "Enter a valid device ID to 'devid' file\n");
347+
return 0;
348+
}
349+
350+
seg = PCI_SBDF_TO_SEGID(sbdf);
351+
devid = PCI_SBDF_TO_DEVID(sbdf);
352+
353+
for_each_pci_segment(pci_seg) {
354+
if (pci_seg->id != seg)
355+
continue;
356+
dump_irte(m, devid, pci_seg);
357+
break;
358+
}
359+
360+
return 0;
361+
}
362+
DEFINE_SHOW_ATTRIBUTE(iommu_irqtbl);
363+
258364
void amd_iommu_debugfs_setup(void)
259365
{
260366
struct amd_iommu *iommu;
@@ -281,4 +387,6 @@ void amd_iommu_debugfs_setup(void)
281387
&devid_fops);
282388
debugfs_create_file("devtbl", 0444, amd_iommu_debugfs, NULL,
283389
&iommu_devtbl_fops);
390+
debugfs_create_file("irqtbl", 0444, amd_iommu_debugfs, NULL,
391+
&iommu_irqtbl_fops);
284392
}

0 commit comments

Comments
 (0)