iommu/amd: Add support for RMP_PAGE_FAULT and RMP_HW_ERR
authorSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Wed, 23 Sep 2020 12:13:46 +0000 (12:13 +0000)
committerJoerg Roedel <jroedel@suse.de>
Thu, 24 Sep 2020 10:46:47 +0000 (12:46 +0200)
IOMMU SNP support introduces two new IOMMU events:
  * RMP Page Fault event
  * RMP Hardware Error event

Hence, add reporting functions for these events.

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Link: https://lore.kernel.org/r/20200923121347.25365-3-suravee.suthikulpanit@amd.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/amd/amd_iommu_types.h
drivers/iommu/amd/iommu.c

index 4c80483..1e7966c 100644 (file)
 #define EVENT_TYPE_IOTLB_INV_TO        0x7
 #define EVENT_TYPE_INV_DEV_REQ 0x8
 #define EVENT_TYPE_INV_PPR_REQ 0x9
+#define EVENT_TYPE_RMP_FAULT   0xd
+#define EVENT_TYPE_RMP_HW_ERR  0xe
 #define EVENT_DEVID_MASK       0xffff
 #define EVENT_DEVID_SHIFT      0
 #define EVENT_DOMID_MASK_LO    0xffff
index a23e14e..292467e 100644 (file)
@@ -486,6 +486,67 @@ static void dump_command(unsigned long phys_addr)
                pr_err("CMD[%d]: %08x\n", i, cmd->data[i]);
 }
 
+static void amd_iommu_report_rmp_hw_error(volatile u32 *event)
+{
+       struct iommu_dev_data *dev_data = NULL;
+       int devid, vmg_tag, flags;
+       struct pci_dev *pdev;
+       u64 spa;
+
+       devid   = (event[0] >> EVENT_DEVID_SHIFT) & EVENT_DEVID_MASK;
+       vmg_tag = (event[1]) & 0xFFFF;
+       flags   = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK;
+       spa     = ((u64)event[3] << 32) | (event[2] & 0xFFFFFFF8);
+
+       pdev = pci_get_domain_bus_and_slot(0, PCI_BUS_NUM(devid),
+                                          devid & 0xff);
+       if (pdev)
+               dev_data = dev_iommu_priv_get(&pdev->dev);
+
+       if (dev_data && __ratelimit(&dev_data->rs)) {
+               pci_err(pdev, "Event logged [RMP_HW_ERROR vmg_tag=0x%04x, spa=0x%llx, flags=0x%04x]\n",
+                       vmg_tag, spa, flags);
+       } else {
+               pr_err_ratelimited("Event logged [RMP_HW_ERROR device=%02x:%02x.%x, vmg_tag=0x%04x, spa=0x%llx, flags=0x%04x]\n",
+                       PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+                       vmg_tag, spa, flags);
+       }
+
+       if (pdev)
+               pci_dev_put(pdev);
+}
+
+static void amd_iommu_report_rmp_fault(volatile u32 *event)
+{
+       struct iommu_dev_data *dev_data = NULL;
+       int devid, flags_rmp, vmg_tag, flags;
+       struct pci_dev *pdev;
+       u64 gpa;
+
+       devid     = (event[0] >> EVENT_DEVID_SHIFT) & EVENT_DEVID_MASK;
+       flags_rmp = (event[0] >> EVENT_FLAGS_SHIFT) & 0xFF;
+       vmg_tag   = (event[1]) & 0xFFFF;
+       flags     = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK;
+       gpa       = ((u64)event[3] << 32) | event[2];
+
+       pdev = pci_get_domain_bus_and_slot(0, PCI_BUS_NUM(devid),
+                                          devid & 0xff);
+       if (pdev)
+               dev_data = dev_iommu_priv_get(&pdev->dev);
+
+       if (dev_data && __ratelimit(&dev_data->rs)) {
+               pci_err(pdev, "Event logged [RMP_PAGE_FAULT vmg_tag=0x%04x, gpa=0x%llx, flags_rmp=0x%04x, flags=0x%04x]\n",
+                       vmg_tag, gpa, flags_rmp, flags);
+       } else {
+               pr_err_ratelimited("Event logged [RMP_PAGE_FAULT device=%02x:%02x.%x, vmg_tag=0x%04x, gpa=0x%llx, flags_rmp=0x%04x, flags=0x%04x]\n",
+                       PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+                       vmg_tag, gpa, flags_rmp, flags);
+       }
+
+       if (pdev)
+               pci_dev_put(pdev);
+}
+
 static void amd_iommu_report_page_fault(u16 devid, u16 domain_id,
                                        u64 address, int flags)
 {
@@ -577,6 +638,12 @@ retry:
                        PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
                        pasid, address, flags);
                break;
+       case EVENT_TYPE_RMP_FAULT:
+               amd_iommu_report_rmp_fault(event);
+               break;
+       case EVENT_TYPE_RMP_HW_ERR:
+               amd_iommu_report_rmp_hw_error(event);
+               break;
        case EVENT_TYPE_INV_PPR_REQ:
                pasid = PPR_PASID(*((u64 *)__evt));
                tag = event[1] & 0x03FF;