Skip to content

Commit af47b0a

Browse files
jpemartinsjoergroedel
authored andcommitted
iommu/amd: Handle GALog overflows
GALog exists to propagate interrupts into all vCPUs in the system when interrupts are marked as non running (e.g. when vCPUs aren't running). A GALog overflow happens when there's in no space in the log to record the GATag of the interrupt. So when the GALOverflow condition happens, the GALog queue is processed and the GALog is restarted, as the IOMMU manual indicates in section "2.7.4 Guest Virtual APIC Log Restart Procedure": | * Wait until MMIO Offset 2020h[GALogRun]=0b so that all request | entries are completed as circumstances allow. GALogRun must be 0b to | modify the guest virtual APIC log registers safely. | * Write MMIO Offset 0018h[GALogEn]=0b. | * As necessary, change the following values (e.g., to relocate or | resize the guest virtual APIC event log): | - the Guest Virtual APIC Log Base Address Register | [MMIO Offset 00E0h], | - the Guest Virtual APIC Log Head Pointer Register | [MMIO Offset 2040h][GALogHead], and | - the Guest Virtual APIC Log Tail Pointer Register | [MMIO Offset 2048h][GALogTail]. | * Write MMIO Offset 2020h[GALOverflow] = 1b to clear the bit (W1C). | * Write MMIO Offset 0018h[GALogEn] = 1b, and either set | MMIO Offset 0018h[GAIntEn] to enable the GA log interrupt or clear | the bit to disable it. Failing to handle the GALog overflow means that none of the VFs (in any guest) will work with IOMMU AVIC forcing the user to power cycle the host. When handling the event it resumes the GALog without resizing much like how it is done in the event handler overflow. The [MMIO Offset 2020h][GALOverflow] bit might be set in status register without the [MMIO Offset 2020h][GAInt] bit, so when deciding to poll for GA events (to clear space in the galog), also check the overflow bit. [suravee: Check for GAOverflow without GAInt, toggle CONTROL_GAINT_EN] Co-developed-by: Suravee Suthikulpanit <[email protected]> Signed-off-by: Suravee Suthikulpanit <[email protected]> Signed-off-by: Joao Martins <[email protected]> Reviewed-by: Vasant Hegde <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent ed8a2f4 commit af47b0a

File tree

3 files changed

+33
-1
lines changed

3 files changed

+33
-1
lines changed

drivers/iommu/amd/amd_iommu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ 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(struct amd_iommu *iommu, u16 devid);
1717
extern void amd_iommu_restart_event_logging(struct amd_iommu *iommu);
18+
extern void amd_iommu_restart_ga_log(struct amd_iommu *iommu);
1819
extern int amd_iommu_init_devices(void);
1920
extern void amd_iommu_uninit_devices(void);
2021
extern void amd_iommu_init_notifier(void);

drivers/iommu/amd/init.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,30 @@ void amd_iommu_restart_event_logging(struct amd_iommu *iommu)
758758
iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN);
759759
}
760760

761+
/*
762+
* This function restarts event logging in case the IOMMU experienced
763+
* an GA log overflow.
764+
*/
765+
void amd_iommu_restart_ga_log(struct amd_iommu *iommu)
766+
{
767+
u32 status;
768+
769+
status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
770+
if (status & MMIO_STATUS_GALOG_RUN_MASK)
771+
return;
772+
773+
pr_info_ratelimited("IOMMU GA Log restarting\n");
774+
775+
iommu_feature_disable(iommu, CONTROL_GALOG_EN);
776+
iommu_feature_disable(iommu, CONTROL_GAINT_EN);
777+
778+
writel(MMIO_STATUS_GALOG_OVERFLOW_MASK,
779+
iommu->mmio_base + MMIO_STATUS_OFFSET);
780+
781+
iommu_feature_enable(iommu, CONTROL_GAINT_EN);
782+
iommu_feature_enable(iommu, CONTROL_GALOG_EN);
783+
}
784+
761785
/*
762786
* This function resets the command buffer if the IOMMU stopped fetching
763787
* commands from it.

drivers/iommu/amd/iommu.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,7 @@ amd_iommu_set_pci_msi_domain(struct device *dev, struct amd_iommu *iommu) { }
845845
(MMIO_STATUS_EVT_OVERFLOW_INT_MASK | \
846846
MMIO_STATUS_EVT_INT_MASK | \
847847
MMIO_STATUS_PPR_INT_MASK | \
848+
MMIO_STATUS_GALOG_OVERFLOW_MASK | \
848849
MMIO_STATUS_GALOG_INT_MASK)
849850

850851
irqreturn_t amd_iommu_int_thread(int irq, void *data)
@@ -868,10 +869,16 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data)
868869
}
869870

870871
#ifdef CONFIG_IRQ_REMAP
871-
if (status & MMIO_STATUS_GALOG_INT_MASK) {
872+
if (status & (MMIO_STATUS_GALOG_INT_MASK |
873+
MMIO_STATUS_GALOG_OVERFLOW_MASK)) {
872874
pr_devel("Processing IOMMU GA Log\n");
873875
iommu_poll_ga_log(iommu);
874876
}
877+
878+
if (status & MMIO_STATUS_GALOG_OVERFLOW_MASK) {
879+
pr_info_ratelimited("IOMMU GA Log overflow\n");
880+
amd_iommu_restart_ga_log(iommu);
881+
}
875882
#endif
876883

877884
if (status & MMIO_STATUS_EVT_OVERFLOW_INT_MASK) {

0 commit comments

Comments
 (0)