aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>2016-08-23 14:52:37 -0400
committerJoerg Roedel <jroedel@suse.de>2016-09-05 06:41:46 -0400
commitbd6fcefc66f6d038406e38edf96a95d9842f819d (patch)
tree46e42ae811db8d9944bcc8f96d1eb0e6a90906a8
parent8bda0cfbdc1a6278a1bbdba795139da682f296ff (diff)
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>
-rw-r--r--drivers/iommu/amd_iommu.c73
-rw-r--r--include/linux/amd-iommu.h20
2 files changed, 87 insertions, 6 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 99c0f4cda76c..eec37b2f54df 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -707,14 +707,74 @@ static void iommu_poll_ppr_log(struct amd_iommu *iommu)
707 } 707 }
708} 708}
709 709
710#ifdef CONFIG_IRQ_REMAP
711static int (*iommu_ga_log_notifier)(u32);
712
713int amd_iommu_register_ga_log_notifier(int (*notifier)(u32))
714{
715 iommu_ga_log_notifier = notifier;
716
717 return 0;
718}
719EXPORT_SYMBOL(amd_iommu_register_ga_log_notifier);
720
721static void iommu_poll_ga_log(struct amd_iommu *iommu)
722{
723 u32 head, tail, cnt = 0;
724
725 if (iommu->ga_log == NULL)
726 return;
727
728 head = readl(iommu->mmio_base + MMIO_GA_HEAD_OFFSET);
729 tail = readl(iommu->mmio_base + MMIO_GA_TAIL_OFFSET);
730
731 while (head != tail) {
732 volatile u64 *raw;
733 u64 log_entry;
734
735 raw = (u64 *)(iommu->ga_log + head);
736 cnt++;
737
738 /* Avoid memcpy function-call overhead */
739 log_entry = *raw;
740
741 /* Update head pointer of hardware ring-buffer */
742 head = (head + GA_ENTRY_SIZE) % GA_LOG_SIZE;
743 writel(head, iommu->mmio_base + MMIO_GA_HEAD_OFFSET);
744
745 /* Handle GA entry */
746 switch (GA_REQ_TYPE(log_entry)) {
747 case GA_GUEST_NR:
748 if (!iommu_ga_log_notifier)
749 break;
750
751 pr_debug("AMD-Vi: %s: devid=%#x, ga_tag=%#x\n",
752 __func__, GA_DEVID(log_entry),
753 GA_TAG(log_entry));
754
755 if (iommu_ga_log_notifier(GA_TAG(log_entry)) != 0)
756 pr_err("AMD-Vi: GA log notifier failed.\n");
757 break;
758 default:
759 break;
760 }
761 }
762}
763#endif /* CONFIG_IRQ_REMAP */
764
765#define AMD_IOMMU_INT_MASK \
766 (MMIO_STATUS_EVT_INT_MASK | \
767 MMIO_STATUS_PPR_INT_MASK | \
768 MMIO_STATUS_GALOG_INT_MASK)
769
710irqreturn_t amd_iommu_int_thread(int irq, void *data) 770irqreturn_t amd_iommu_int_thread(int irq, void *data)
711{ 771{
712 struct amd_iommu *iommu = (struct amd_iommu *) data; 772 struct amd_iommu *iommu = (struct amd_iommu *) data;
713 u32 status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET); 773 u32 status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
714 774
715 while (status & (MMIO_STATUS_EVT_INT_MASK | MMIO_STATUS_PPR_INT_MASK)) { 775 while (status & AMD_IOMMU_INT_MASK) {
716 /* Enable EVT and PPR interrupts again */ 776 /* Enable EVT and PPR and GA interrupts again */
717 writel((MMIO_STATUS_EVT_INT_MASK | MMIO_STATUS_PPR_INT_MASK), 777 writel(AMD_IOMMU_INT_MASK,
718 iommu->mmio_base + MMIO_STATUS_OFFSET); 778 iommu->mmio_base + MMIO_STATUS_OFFSET);
719 779
720 if (status & MMIO_STATUS_EVT_INT_MASK) { 780 if (status & MMIO_STATUS_EVT_INT_MASK) {
@@ -727,6 +787,13 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data)
727 iommu_poll_ppr_log(iommu); 787 iommu_poll_ppr_log(iommu);
728 } 788 }
729 789
790#ifdef CONFIG_IRQ_REMAP
791 if (status & MMIO_STATUS_GALOG_INT_MASK) {
792 pr_devel("AMD-Vi: Processing IOMMU GA Log\n");
793 iommu_poll_ga_log(iommu);
794 }
795#endif
796
730 /* 797 /*
731 * Hardware bug: ERBT1312 798 * Hardware bug: ERBT1312
732 * When re-enabling interrupt (by writing 1 799 * When re-enabling interrupt (by writing 1
diff --git a/include/linux/amd-iommu.h b/include/linux/amd-iommu.h
index 2b08e79f5100..465d096a5f4b 100644
--- a/include/linux/amd-iommu.h
+++ b/include/linux/amd-iommu.h
@@ -168,11 +168,25 @@ typedef void (*amd_iommu_invalidate_ctx)(struct pci_dev *pdev, int pasid);
168 168
169extern int amd_iommu_set_invalidate_ctx_cb(struct pci_dev *pdev, 169extern int amd_iommu_set_invalidate_ctx_cb(struct pci_dev *pdev,
170 amd_iommu_invalidate_ctx cb); 170 amd_iommu_invalidate_ctx cb);
171 171#else /* CONFIG_AMD_IOMMU */
172#else
173 172
174static inline int amd_iommu_detect(void) { return -ENODEV; } 173static inline int amd_iommu_detect(void) { return -ENODEV; }
175 174
176#endif 175#endif /* CONFIG_AMD_IOMMU */
176
177#if defined(CONFIG_AMD_IOMMU) && defined(CONFIG_IRQ_REMAP)
178
179/* IOMMU AVIC Function */
180extern int amd_iommu_register_ga_log_notifier(int (*notifier)(u32));
181
182#else /* defined(CONFIG_AMD_IOMMU) && defined(CONFIG_IRQ_REMAP) */
183
184static inline int
185amd_iommu_register_ga_log_notifier(int (*notifier)(u32))
186{
187 return 0;
188}
189
190#endif /* defined(CONFIG_AMD_IOMMU) && defined(CONFIG_IRQ_REMAP) */
177 191
178#endif /* _ASM_X86_AMD_IOMMU_H */ 192#endif /* _ASM_X86_AMD_IOMMU_H */