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>
This commit is contained in:
committed by
Ingo Molnar
parent
a80dc3e0e0
commit
90008ee4b8
@ -55,9 +55,94 @@ static int iommu_has_npcache(struct amd_iommu *iommu)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void iommu_print_event(void *__evt)
|
||||
{
|
||||
u32 *event = __evt;
|
||||
int type = (event[1] >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK;
|
||||
int devid = (event[0] >> EVENT_DEVID_SHIFT) & EVENT_DEVID_MASK;
|
||||
int domid = (event[1] >> EVENT_DOMID_SHIFT) & EVENT_DOMID_MASK;
|
||||
int flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK;
|
||||
u64 address = (u64)(((u64)event[3]) << 32) | event[2];
|
||||
|
||||
printk(KERN_ERR "AMD IOMMU: Event logged [");
|
||||
|
||||
switch (type) {
|
||||
case EVENT_TYPE_ILL_DEV:
|
||||
printk("ILLEGAL_DEV_TABLE_ENTRY device=%02x:%02x.%x "
|
||||
"address=0x%016llx flags=0x%04x]\n",
|
||||
PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
|
||||
address, flags);
|
||||
break;
|
||||
case EVENT_TYPE_IO_FAULT:
|
||||
printk("IO_PAGE_FAULT device=%02x:%02x.%x "
|
||||
"domain=0x%04x address=0x%016llx flags=0x%04x]\n",
|
||||
PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
|
||||
domid, address, flags);
|
||||
break;
|
||||
case EVENT_TYPE_DEV_TAB_ERR:
|
||||
printk("DEV_TAB_HARDWARE_ERROR device=%02x:%02x.%x "
|
||||
"address=0x%016llx flags=0x%04x]\n",
|
||||
PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
|
||||
address, flags);
|
||||
break;
|
||||
case EVENT_TYPE_PAGE_TAB_ERR:
|
||||
printk("PAGE_TAB_HARDWARE_ERROR device=%02x:%02x.%x "
|
||||
"domain=0x%04x address=0x%016llx flags=0x%04x]\n",
|
||||
PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
|
||||
domid, address, flags);
|
||||
break;
|
||||
case EVENT_TYPE_ILL_CMD:
|
||||
printk("ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address);
|
||||
break;
|
||||
case EVENT_TYPE_CMD_HARD_ERR:
|
||||
printk("COMMAND_HARDWARE_ERROR address=0x%016llx "
|
||||
"flags=0x%04x]\n", address, flags);
|
||||
break;
|
||||
case EVENT_TYPE_IOTLB_INV_TO:
|
||||
printk("IOTLB_INV_TIMEOUT device=%02x:%02x.%x "
|
||||
"address=0x%016llx]\n",
|
||||
PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
|
||||
address);
|
||||
break;
|
||||
case EVENT_TYPE_INV_DEV_REQ:
|
||||
printk("INVALID_DEVICE_REQUEST device=%02x:%02x.%x "
|
||||
"address=0x%016llx flags=0x%04x]\n",
|
||||
PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
|
||||
address, flags);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "UNKNOWN type=0x%02x]\n", type);
|
||||
}
|
||||
}
|
||||
|
||||
static void iommu_poll_events(struct amd_iommu *iommu)
|
||||
{
|
||||
u32 head, tail;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&iommu->lock, flags);
|
||||
|
||||
head = readl(iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
|
||||
tail = readl(iommu->mmio_base + MMIO_EVT_TAIL_OFFSET);
|
||||
|
||||
while (head != tail) {
|
||||
iommu_print_event(iommu->evt_buf + head);
|
||||
head = (head + EVENT_ENTRY_SIZE) % iommu->evt_buf_size;
|
||||
}
|
||||
|
||||
writel(head, iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
|
||||
|
||||
spin_unlock_irqrestore(&iommu->lock, flags);
|
||||
}
|
||||
|
||||
irqreturn_t amd_iommu_int_handler(int irq, void *data)
|
||||
{
|
||||
return IRQ_NONE;
|
||||
struct amd_iommu *iommu;
|
||||
|
||||
list_for_each_entry(iommu, &amd_iommu_list, list)
|
||||
iommu_poll_events(iommu);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
Reference in New Issue
Block a user