diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2008-09-09 10:41:05 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-09-19 06:59:16 -0400 |
commit | 90008ee4b811c944455752dcb72b291a5ba81b53 (patch) | |
tree | 2c54f65efbabd7d9decbff49e12199eed00082b7 /arch/x86/kernel/amd_iommu.c | |
parent | a80dc3e0e0dc8393158de317d66ae0f345dc58f9 (diff) |
AMD IOMMU: add event handling code
This patch adds code for polling and printing out events generated by
the AMD IOMMU.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/amd_iommu.c')
-rw-r--r-- | arch/x86/kernel/amd_iommu.c | 87 |
1 files changed, 86 insertions, 1 deletions
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 0e494b9d5f20..0cb8fd2359f5 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c | |||
@@ -55,9 +55,94 @@ static int iommu_has_npcache(struct amd_iommu *iommu) | |||
55 | * | 55 | * |
56 | ****************************************************************************/ | 56 | ****************************************************************************/ |
57 | 57 | ||
58 | static void iommu_print_event(void *__evt) | ||
59 | { | ||
60 | u32 *event = __evt; | ||
61 | int type = (event[1] >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK; | ||
62 | int devid = (event[0] >> EVENT_DEVID_SHIFT) & EVENT_DEVID_MASK; | ||
63 | int domid = (event[1] >> EVENT_DOMID_SHIFT) & EVENT_DOMID_MASK; | ||
64 | int flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK; | ||
65 | u64 address = (u64)(((u64)event[3]) << 32) | event[2]; | ||
66 | |||
67 | printk(KERN_ERR "AMD IOMMU: Event logged ["); | ||
68 | |||
69 | switch (type) { | ||
70 | case EVENT_TYPE_ILL_DEV: | ||
71 | printk("ILLEGAL_DEV_TABLE_ENTRY device=%02x:%02x.%x " | ||
72 | "address=0x%016llx flags=0x%04x]\n", | ||
73 | PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid), | ||
74 | address, flags); | ||
75 | break; | ||
76 | case EVENT_TYPE_IO_FAULT: | ||
77 | printk("IO_PAGE_FAULT device=%02x:%02x.%x " | ||
78 | "domain=0x%04x address=0x%016llx flags=0x%04x]\n", | ||
79 | PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid), | ||
80 | domid, address, flags); | ||
81 | break; | ||
82 | case EVENT_TYPE_DEV_TAB_ERR: | ||
83 | printk("DEV_TAB_HARDWARE_ERROR device=%02x:%02x.%x " | ||
84 | "address=0x%016llx flags=0x%04x]\n", | ||
85 | PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid), | ||
86 | address, flags); | ||
87 | break; | ||
88 | case EVENT_TYPE_PAGE_TAB_ERR: | ||
89 | printk("PAGE_TAB_HARDWARE_ERROR device=%02x:%02x.%x " | ||
90 | "domain=0x%04x address=0x%016llx flags=0x%04x]\n", | ||
91 | PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid), | ||
92 | domid, address, flags); | ||
93 | break; | ||
94 | case EVENT_TYPE_ILL_CMD: | ||
95 | printk("ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address); | ||
96 | break; | ||
97 | case EVENT_TYPE_CMD_HARD_ERR: | ||
98 | printk("COMMAND_HARDWARE_ERROR address=0x%016llx " | ||
99 | "flags=0x%04x]\n", address, flags); | ||
100 | break; | ||
101 | case EVENT_TYPE_IOTLB_INV_TO: | ||
102 | printk("IOTLB_INV_TIMEOUT device=%02x:%02x.%x " | ||
103 | "address=0x%016llx]\n", | ||
104 | PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid), | ||
105 | address); | ||
106 | break; | ||
107 | case EVENT_TYPE_INV_DEV_REQ: | ||
108 | printk("INVALID_DEVICE_REQUEST device=%02x:%02x.%x " | ||
109 | "address=0x%016llx flags=0x%04x]\n", | ||
110 | PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid), | ||
111 | address, flags); | ||
112 | break; | ||
113 | default: | ||
114 | printk(KERN_ERR "UNKNOWN type=0x%02x]\n", type); | ||
115 | } | ||
116 | } | ||
117 | |||
118 | static void iommu_poll_events(struct amd_iommu *iommu) | ||
119 | { | ||
120 | u32 head, tail; | ||
121 | unsigned long flags; | ||
122 | |||
123 | spin_lock_irqsave(&iommu->lock, flags); | ||
124 | |||
125 | head = readl(iommu->mmio_base + MMIO_EVT_HEAD_OFFSET); | ||
126 | tail = readl(iommu->mmio_base + MMIO_EVT_TAIL_OFFSET); | ||
127 | |||
128 | while (head != tail) { | ||
129 | iommu_print_event(iommu->evt_buf + head); | ||
130 | head = (head + EVENT_ENTRY_SIZE) % iommu->evt_buf_size; | ||
131 | } | ||
132 | |||
133 | writel(head, iommu->mmio_base + MMIO_EVT_HEAD_OFFSET); | ||
134 | |||
135 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
136 | } | ||
137 | |||
58 | irqreturn_t amd_iommu_int_handler(int irq, void *data) | 138 | irqreturn_t amd_iommu_int_handler(int irq, void *data) |
59 | { | 139 | { |
60 | return IRQ_NONE; | 140 | struct amd_iommu *iommu; |
141 | |||
142 | list_for_each_entry(iommu, &amd_iommu_list, list) | ||
143 | iommu_poll_events(iommu); | ||
144 | |||
145 | return IRQ_HANDLED; | ||
61 | } | 146 | } |
62 | 147 | ||
63 | /**************************************************************************** | 148 | /**************************************************************************** |