Skip to content

Commit 5ce97f4

Browse files
buytenhjoergroedel
authored andcommitted
iommu/amd: Recover from event log overflow
The AMD IOMMU logs I/O page faults and such to a ring buffer in system memory, and this ring buffer can overflow. The AMD IOMMU spec has the following to say about the interrupt status bit that signals this overflow condition: EventOverflow: Event log overflow. RW1C. Reset 0b. 1 = IOMMU event log overflow has occurred. This bit is set when a new event is to be written to the event log and there is no usable entry in the event log, causing the new event information to be discarded. An interrupt is generated when EventOverflow = 1b and MMIO Offset 0018h[EventIntEn] = 1b. No new event log entries are written while this bit is set. Software Note: To resume logging, clear EventOverflow (W1C), and write a 1 to MMIO Offset 0018h[EventLogEn]. The AMD IOMMU driver doesn't currently implement this recovery sequence, meaning that if a ring buffer overflow occurs, logging of EVT/PPR/GA events will cease entirely. This patch implements the spec-mandated reset sequence, with the minor tweak that the hardware seems to want to have a 0 written to MMIO Offset 0018h[EventLogEn] first, before writing an 1 into this field, or the IOMMU won't actually resume logging events. Signed-off-by: Lennert Buytenhek <[email protected]> Cc: [email protected] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 754e0b0 commit 5ce97f4

File tree

4 files changed

+20
-2
lines changed

4 files changed

+20
-2
lines changed

drivers/iommu/amd/amd_iommu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
extern irqreturn_t amd_iommu_int_thread(int irq, void *data);
1515
extern irqreturn_t amd_iommu_int_handler(int irq, void *data);
1616
extern void amd_iommu_apply_erratum_63(u16 devid);
17+
extern void amd_iommu_restart_event_logging(struct amd_iommu *iommu);
1718
extern void amd_iommu_reset_cmd_buffer(struct amd_iommu *iommu);
1819
extern int amd_iommu_init_devices(void);
1920
extern void amd_iommu_uninit_devices(void);

drivers/iommu/amd/amd_iommu_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
#define PASID_MASK 0x0000ffff
111111

112112
/* MMIO status bits */
113+
#define MMIO_STATUS_EVT_OVERFLOW_INT_MASK (1 << 0)
113114
#define MMIO_STATUS_EVT_INT_MASK (1 << 1)
114115
#define MMIO_STATUS_COM_WAIT_INT_MASK (1 << 2)
115116
#define MMIO_STATUS_PPR_INT_MASK (1 << 6)

drivers/iommu/amd/init.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,16 @@ static int __init alloc_command_buffer(struct amd_iommu *iommu)
657657
return iommu->cmd_buf ? 0 : -ENOMEM;
658658
}
659659

660+
/*
661+
* This function restarts event logging in case the IOMMU experienced
662+
* an event log buffer overflow.
663+
*/
664+
void amd_iommu_restart_event_logging(struct amd_iommu *iommu)
665+
{
666+
iommu_feature_disable(iommu, CONTROL_EVT_LOG_EN);
667+
iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN);
668+
}
669+
660670
/*
661671
* This function resets the command buffer if the IOMMU stopped fetching
662672
* commands from it.

drivers/iommu/amd/iommu.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,8 @@ amd_iommu_set_pci_msi_domain(struct device *dev, struct amd_iommu *iommu) { }
764764
#endif /* !CONFIG_IRQ_REMAP */
765765

766766
#define AMD_IOMMU_INT_MASK \
767-
(MMIO_STATUS_EVT_INT_MASK | \
767+
(MMIO_STATUS_EVT_OVERFLOW_INT_MASK | \
768+
MMIO_STATUS_EVT_INT_MASK | \
768769
MMIO_STATUS_PPR_INT_MASK | \
769770
MMIO_STATUS_GALOG_INT_MASK)
770771

@@ -774,7 +775,7 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data)
774775
u32 status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
775776

776777
while (status & AMD_IOMMU_INT_MASK) {
777-
/* Enable EVT and PPR and GA interrupts again */
778+
/* Enable interrupt sources again */
778779
writel(AMD_IOMMU_INT_MASK,
779780
iommu->mmio_base + MMIO_STATUS_OFFSET);
780781

@@ -795,6 +796,11 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data)
795796
}
796797
#endif
797798

799+
if (status & MMIO_STATUS_EVT_OVERFLOW_INT_MASK) {
800+
pr_info_ratelimited("IOMMU event log overflow\n");
801+
amd_iommu_restart_event_logging(iommu);
802+
}
803+
798804
/*
799805
* Hardware bug: ERBT1312
800806
* When re-enabling interrupt (by writing 1

0 commit comments

Comments
 (0)