iommu/amd: Refactor IOMMU interrupt handling logic for Event, PPR, and GA logs

The AMD IOMMU has three log buffers (i.e. Event, PPR, and GA). The IOMMU
driver processes these log entries when it receive an IOMMU interrupt.
Then, it needs to clear the corresponding interrupt status bits. Also, when
an overflow occurs, it needs to handle the log overflow by clearing the
specific overflow status bit and restart the log.

Since, logic for handling these logs is the same, refactor the code into a
helper function called amd_iommu_handle_irq(), which handles the steps
described. Then, reuse it for all types of log.

Reviewed-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: Vasant Hegde<vasant.hegde@amd.com>
Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
Link: https://lore.kernel.org/r/20230628053222.5962-2-vasant.hegde@amd.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
Vasant Hegde 2023-06-28 05:32:21 +00:00 committed by Joerg Roedel
parent 274c2218b8
commit 2379f34852
2 changed files with 53 additions and 43 deletions

View File

@ -12,6 +12,9 @@
#include "amd_iommu_types.h"
irqreturn_t amd_iommu_int_thread(int irq, void *data);
irqreturn_t amd_iommu_int_thread_evtlog(int irq, void *data);
irqreturn_t amd_iommu_int_thread_pprlog(int irq, void *data);
irqreturn_t amd_iommu_int_thread_galog(int irq, void *data);
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);

View File

@ -841,57 +841,27 @@ static inline void
amd_iommu_set_pci_msi_domain(struct device *dev, struct amd_iommu *iommu) { }
#endif /* !CONFIG_IRQ_REMAP */
#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)
irqreturn_t amd_iommu_int_thread(int irq, void *data)
static void amd_iommu_handle_irq(void *data, const char *evt_type,
u32 int_mask, u32 overflow_mask,
void (*int_handler)(struct amd_iommu *),
void (*overflow_handler)(struct amd_iommu *))
{
struct amd_iommu *iommu = (struct amd_iommu *) data;
u32 status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
u32 mask = int_mask | overflow_mask;
while (status & AMD_IOMMU_INT_MASK) {
while (status & mask) {
/* Enable interrupt sources again */
writel(AMD_IOMMU_INT_MASK,
iommu->mmio_base + MMIO_STATUS_OFFSET);
writel(mask, iommu->mmio_base + MMIO_STATUS_OFFSET);
if (status & MMIO_STATUS_EVT_INT_MASK) {
pr_devel("Processing IOMMU Event Log\n");
iommu_poll_events(iommu);
if (int_handler) {
pr_devel("Processing IOMMU (ivhd%d) %s Log\n",
iommu->index, evt_type);
int_handler(iommu);
}
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)) {
pr_devel("Processing IOMMU GA Log\n");
iommu_poll_ga_log(iommu);
}
if (status & MMIO_STATUS_GALOG_OVERFLOW_MASK) {
pr_info_ratelimited("IOMMU GA Log overflow\n");
amd_iommu_restart_ga_log(iommu);
}
#endif
if (status & MMIO_STATUS_EVT_OVERFLOW_MASK) {
pr_info_ratelimited("IOMMU event log overflow\n");
amd_iommu_restart_event_logging(iommu);
}
if ((status & overflow_mask) && overflow_handler)
overflow_handler(iommu);
/*
* Hardware bug: ERBT1312
@ -908,6 +878,43 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data)
*/
status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
}
}
irqreturn_t amd_iommu_int_thread_evtlog(int irq, void *data)
{
amd_iommu_handle_irq(data, "Evt", MMIO_STATUS_EVT_INT_MASK,
MMIO_STATUS_EVT_OVERFLOW_MASK,
iommu_poll_events, amd_iommu_restart_event_logging);
return IRQ_HANDLED;
}
irqreturn_t amd_iommu_int_thread_pprlog(int irq, void *data)
{
amd_iommu_handle_irq(data, "PPR", MMIO_STATUS_PPR_INT_MASK,
MMIO_STATUS_PPR_OVERFLOW_MASK,
iommu_poll_ppr_log, amd_iommu_restart_ppr_log);
return IRQ_HANDLED;
}
irqreturn_t amd_iommu_int_thread_galog(int irq, void *data)
{
#ifdef CONFIG_IRQ_REMAP
amd_iommu_handle_irq(data, "GA", MMIO_STATUS_GALOG_INT_MASK,
MMIO_STATUS_GALOG_OVERFLOW_MASK,
iommu_poll_ga_log, amd_iommu_restart_ga_log);
#endif
return IRQ_HANDLED;
}
irqreturn_t amd_iommu_int_thread(int irq, void *data)
{
amd_iommu_int_thread_evtlog(irq, data);
amd_iommu_int_thread_pprlog(irq, data);
amd_iommu_int_thread_galog(irq, data);
return IRQ_HANDLED;
}