iommu/amd: Adding GALOG interrupt handler

This patch adds AMD IOMMU guest virtual APIC log (GALOG) handler.
When IOMMU hardware receives an interrupt targeting a blocking vcpu,
it creates an entry in the GALOG, and generates an interrupt to notify
the AMD IOMMU driver.

At this point, the driver processes the log entry, and notify the SVM
driver via the registered iommu_ga_log_notifier function.

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
Suravee Suthikulpanit 2016-08-23 13:52:37 -05:00 committed by Joerg Roedel
parent 8bda0cfbdc
commit bd6fcefc66
2 changed files with 87 additions and 6 deletions

View File

@ -707,14 +707,74 @@ static void iommu_poll_ppr_log(struct amd_iommu *iommu)
} }
} }
#ifdef CONFIG_IRQ_REMAP
static int (*iommu_ga_log_notifier)(u32);
int amd_iommu_register_ga_log_notifier(int (*notifier)(u32))
{
iommu_ga_log_notifier = notifier;
return 0;
}
EXPORT_SYMBOL(amd_iommu_register_ga_log_notifier);
static void iommu_poll_ga_log(struct amd_iommu *iommu)
{
u32 head, tail, cnt = 0;
if (iommu->ga_log == NULL)
return;
head = readl(iommu->mmio_base + MMIO_GA_HEAD_OFFSET);
tail = readl(iommu->mmio_base + MMIO_GA_TAIL_OFFSET);
while (head != tail) {
volatile u64 *raw;
u64 log_entry;
raw = (u64 *)(iommu->ga_log + head);
cnt++;
/* Avoid memcpy function-call overhead */
log_entry = *raw;
/* Update head pointer of hardware ring-buffer */
head = (head + GA_ENTRY_SIZE) % GA_LOG_SIZE;
writel(head, iommu->mmio_base + MMIO_GA_HEAD_OFFSET);
/* Handle GA entry */
switch (GA_REQ_TYPE(log_entry)) {
case GA_GUEST_NR:
if (!iommu_ga_log_notifier)
break;
pr_debug("AMD-Vi: %s: devid=%#x, ga_tag=%#x\n",
__func__, GA_DEVID(log_entry),
GA_TAG(log_entry));
if (iommu_ga_log_notifier(GA_TAG(log_entry)) != 0)
pr_err("AMD-Vi: GA log notifier failed.\n");
break;
default:
break;
}
}
}
#endif /* CONFIG_IRQ_REMAP */
#define AMD_IOMMU_INT_MASK \
(MMIO_STATUS_EVT_INT_MASK | \
MMIO_STATUS_PPR_INT_MASK | \
MMIO_STATUS_GALOG_INT_MASK)
irqreturn_t amd_iommu_int_thread(int irq, void *data) irqreturn_t amd_iommu_int_thread(int irq, void *data)
{ {
struct amd_iommu *iommu = (struct amd_iommu *) data; struct amd_iommu *iommu = (struct amd_iommu *) data;
u32 status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET); u32 status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
while (status & (MMIO_STATUS_EVT_INT_MASK | MMIO_STATUS_PPR_INT_MASK)) { while (status & AMD_IOMMU_INT_MASK) {
/* Enable EVT and PPR interrupts again */ /* Enable EVT and PPR and GA interrupts again */
writel((MMIO_STATUS_EVT_INT_MASK | MMIO_STATUS_PPR_INT_MASK), writel(AMD_IOMMU_INT_MASK,
iommu->mmio_base + MMIO_STATUS_OFFSET); iommu->mmio_base + MMIO_STATUS_OFFSET);
if (status & MMIO_STATUS_EVT_INT_MASK) { if (status & MMIO_STATUS_EVT_INT_MASK) {
@ -727,6 +787,13 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data)
iommu_poll_ppr_log(iommu); iommu_poll_ppr_log(iommu);
} }
#ifdef CONFIG_IRQ_REMAP
if (status & MMIO_STATUS_GALOG_INT_MASK) {
pr_devel("AMD-Vi: Processing IOMMU GA Log\n");
iommu_poll_ga_log(iommu);
}
#endif
/* /*
* Hardware bug: ERBT1312 * Hardware bug: ERBT1312
* When re-enabling interrupt (by writing 1 * When re-enabling interrupt (by writing 1

View File

@ -168,11 +168,25 @@ typedef void (*amd_iommu_invalidate_ctx)(struct pci_dev *pdev, int pasid);
extern int amd_iommu_set_invalidate_ctx_cb(struct pci_dev *pdev, extern int amd_iommu_set_invalidate_ctx_cb(struct pci_dev *pdev,
amd_iommu_invalidate_ctx cb); amd_iommu_invalidate_ctx cb);
#else /* CONFIG_AMD_IOMMU */
#else
static inline int amd_iommu_detect(void) { return -ENODEV; } static inline int amd_iommu_detect(void) { return -ENODEV; }
#endif #endif /* CONFIG_AMD_IOMMU */
#if defined(CONFIG_AMD_IOMMU) && defined(CONFIG_IRQ_REMAP)
/* IOMMU AVIC Function */
extern int amd_iommu_register_ga_log_notifier(int (*notifier)(u32));
#else /* defined(CONFIG_AMD_IOMMU) && defined(CONFIG_IRQ_REMAP) */
static inline int
amd_iommu_register_ga_log_notifier(int (*notifier)(u32))
{
return 0;
}
#endif /* defined(CONFIG_AMD_IOMMU) && defined(CONFIG_IRQ_REMAP) */
#endif /* _ASM_X86_AMD_IOMMU_H */ #endif /* _ASM_X86_AMD_IOMMU_H */