]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
AMD IOMMU: add event handling code
authorJoerg Roedel <joerg.roedel@amd.com>
Tue, 9 Sep 2008 14:41:05 +0000 (16:41 +0200)
committerIngo Molnar <mingo@elte.hu>
Fri, 19 Sep 2008 10:59:16 +0000 (12:59 +0200)
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>
arch/x86/kernel/amd_iommu.c
arch/x86/kernel/amd_iommu_init.c
include/asm-x86/amd_iommu_types.h

index 0e494b9d5f2005a6fbab5f479c4a1cee7e4fe2f9..0cb8fd2359f52c3bda9e66df92b793ca363bcd78 100644 (file)
@@ -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;
 }
 
 /****************************************************************************
index 14a06464a6947499cdd29fe4fbb017e7aaf85334..eed488892c01417f877f83373ef617ba84ecc37e 100644 (file)
@@ -32,7 +32,6 @@
 /*
  * definitions for the ACPI scanning code
  */
-#define PCI_BUS(x) (((x) >> 8) & 0xff)
 #define IVRS_HEADER_LENGTH 48
 
 #define ACPI_IVHD_TYPE                  0x10
index 8533f09b34b7712adee76b2d8c9d56ac48456de6..d8c5a6c699553d454ebde30645e77dec969f8007 100644 (file)
 /* MMIO status bits */
 #define MMIO_STATUS_COM_WAIT_INT_MASK  0x04
 
+/* event logging constants */
+#define EVENT_ENTRY_SIZE       0x10
+#define EVENT_TYPE_SHIFT       28
+#define EVENT_TYPE_MASK                0xf
+#define EVENT_TYPE_ILL_DEV     0x1
+#define EVENT_TYPE_IO_FAULT    0x2
+#define EVENT_TYPE_DEV_TAB_ERR 0x3
+#define EVENT_TYPE_PAGE_TAB_ERR        0x4
+#define EVENT_TYPE_ILL_CMD     0x5
+#define EVENT_TYPE_CMD_HARD_ERR        0x6
+#define EVENT_TYPE_IOTLB_INV_TO        0x7
+#define EVENT_TYPE_INV_DEV_REQ 0x8
+#define EVENT_DEVID_MASK       0xffff
+#define EVENT_DEVID_SHIFT      0
+#define EVENT_DOMID_MASK       0xffff
+#define EVENT_DOMID_SHIFT      0
+#define EVENT_FLAGS_MASK       0xfff
+#define EVENT_FLAGS_SHIFT      0x10
+
 /* feature control bits */
 #define CONTROL_IOMMU_EN        0x00ULL
 #define CONTROL_HT_TUN_EN       0x01ULL
 
 #define MAX_DOMAIN_ID 65536
 
+/* FIXME: move this macro to <linux/pci.h> */
+#define PCI_BUS(x) (((x) >> 8) & 0xff)
+
 /*
  * This structure contains generic data for  IOMMU protection domains
  * independent of their use.