iommu/amd: Handle PPR log overflow
authorVasant Hegde <vasant.hegde@amd.com>
Wed, 28 Jun 2023 05:16:24 +0000 (05:16 +0000)
committerJoerg Roedel <jroedel@suse.de>
Fri, 14 Jul 2023 14:19:36 +0000 (16:19 +0200)
Some ATS-capable peripherals can issue requests to the processor to service
peripheral page requests using PCIe PRI (the Page Request Interface). IOMMU
supports PRI using PPR log buffer. IOMMU writes PRI request to PPR log
buffer and sends PPR interrupt to host. When there is no space in the
PPR log buffer (PPR log overflow) it will set PprOverflow bit in 'MMIO
Offset 2020h IOMMU Status Register'. When this happens PPR log needs to be
restarted as specified in IOMMU spec [1] section 2.6.2.

When handling the event it just resumes the PPR log without resizing
(similar to the way event and GA log overflow is handled).

Failing to handle PPR overflow means device may not work properly as
IOMMU stops processing new PPR events from device.

[1] https://www.amd.com/system/files/TechDocs/48882_3.07_PUB.pdf

Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
Reviewed-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Reviewed-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: Vasant Hegde <vasant.hegde@amd.com>
Link: https://lore.kernel.org/r/20230628051624.5792-3-vasant.hegde@amd.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/amd/amd_iommu.h
drivers/iommu/amd/amd_iommu_types.h
drivers/iommu/amd/init.c
drivers/iommu/amd/iommu.c

index 0c35018239cecfa2308a4e10c737f751289149ce..8c61c19dabc4fea8b8fe9c1922ebdd3c2ac51fdc 100644 (file)
@@ -16,6 +16,7 @@ irqreturn_t amd_iommu_int_handler(int irq, void *data);
 void amd_iommu_apply_erratum_63(struct amd_iommu *iommu, u16 devid);
 void amd_iommu_restart_event_logging(struct amd_iommu *iommu);
 void amd_iommu_restart_ga_log(struct amd_iommu *iommu);
+void amd_iommu_restart_ppr_log(struct amd_iommu *iommu);
 int amd_iommu_init_devices(void);
 void amd_iommu_uninit_devices(void);
 void amd_iommu_init_notifier(void);
index 7c436ba2a0a2362da82a30e1cb8caadd0aa2d931..c8150eaf5c0e22f9d2ba22324de5691cfc15d44f 100644 (file)
 #define MMIO_STATUS_EVT_INT_MASK               BIT(1)
 #define MMIO_STATUS_COM_WAIT_INT_MASK          BIT(2)
 #define MMIO_STATUS_EVT_RUN_MASK               BIT(3)
+#define MMIO_STATUS_PPR_OVERFLOW_MASK          BIT(5)
 #define MMIO_STATUS_PPR_INT_MASK               BIT(6)
+#define MMIO_STATUS_PPR_RUN_MASK               BIT(7)
 #define MMIO_STATUS_GALOG_RUN_MASK             BIT(8)
 #define MMIO_STATUS_GALOG_OVERFLOW_MASK                BIT(9)
 #define MMIO_STATUS_GALOG_INT_MASK             BIT(10)
index 7fab6ecb629584293f9f50d7cc92c567ada121b5..e78d7c4f41bd46c68af7c4826597d248790abe84 100644 (file)
@@ -799,6 +799,17 @@ void amd_iommu_restart_ga_log(struct amd_iommu *iommu)
                              MMIO_STATUS_GALOG_OVERFLOW_MASK);
 }
 
+/*
+ * This function restarts ppr logging in case the IOMMU experienced
+ * PPR log overflow.
+ */
+void amd_iommu_restart_ppr_log(struct amd_iommu *iommu)
+{
+       amd_iommu_restart_log(iommu, "PPR", CONTROL_PPRINT_EN,
+                             CONTROL_PPRLOG_EN, MMIO_STATUS_PPR_RUN_MASK,
+                             MMIO_STATUS_PPR_OVERFLOW_MASK);
+}
+
 /*
  * This function resets the command buffer if the IOMMU stopped fetching
  * commands from it.
index 86c0ae34373b53dd46e836a59da20246da9c9b92..f8316901a178094c7f78615e17c1b3b952d61578 100644 (file)
@@ -844,6 +844,7 @@ amd_iommu_set_pci_msi_domain(struct device *dev, struct amd_iommu *iommu) { }
 #define AMD_IOMMU_INT_MASK     \
        (MMIO_STATUS_EVT_OVERFLOW_MASK | \
         MMIO_STATUS_EVT_INT_MASK | \
+        MMIO_STATUS_PPR_OVERFLOW_MASK | \
         MMIO_STATUS_PPR_INT_MASK | \
         MMIO_STATUS_GALOG_OVERFLOW_MASK | \
         MMIO_STATUS_GALOG_INT_MASK)
@@ -863,11 +864,17 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data)
                        iommu_poll_events(iommu);
                }
 
-               if (status & MMIO_STATUS_PPR_INT_MASK) {
+               if (status & (MMIO_STATUS_PPR_INT_MASK |
+                             MMIO_STATUS_PPR_OVERFLOW_MASK)) {
                        pr_devel("Processing IOMMU PPR Log\n");
                        iommu_poll_ppr_log(iommu);
                }
 
+               if (status & MMIO_STATUS_PPR_OVERFLOW_MASK) {
+                       pr_info_ratelimited("IOMMU PPR log overflow\n");
+                       amd_iommu_restart_ppr_log(iommu);
+               }
+
 #ifdef CONFIG_IRQ_REMAP
                if (status & (MMIO_STATUS_GALOG_INT_MASK |
                              MMIO_STATUS_GALOG_OVERFLOW_MASK)) {