summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2016-02-15 13:42:38 +0100
committerDavid Woodhouse <David.Woodhouse@intel.com>2016-02-15 13:42:38 +0100
commit46924008273ed03bd11dbb32136e3da4cfe056e1 (patch)
tree9d77cb792ac4ccf28aa687942d1c6f1adaf5dd67
parentiommu/vt-d: Fix 64-bit accesses to 32-bit DMAR_GSTS_REG (diff)
downloadlinux-46924008273ed03bd11dbb32136e3da4cfe056e1.tar.xz
linux-46924008273ed03bd11dbb32136e3da4cfe056e1.zip
iommu/vt-d: Clear PPR bit to ensure we get more page request interrupts
According to the VT-d specification we need to clear the PPR bit in the Page Request Status register when handling page requests, or the hardware won't generate any more interrupts. This wasn't actually necessary on SKL/KBL (which may well be the subject of a hardware erratum, although it's harmless enough). But other implementations do appear to get it right, and we only ever get one interrupt unless we clear the PPR bit. Reported-by: CQ Tang <cq.tang@intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> Cc: stable@vger.kernel.org
-rw-r--r--drivers/iommu/intel-svm.c4
-rw-r--r--include/linux/intel-iommu.h3
2 files changed, 7 insertions, 0 deletions
diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c
index 97a818992d6d..d9939fa9b588 100644
--- a/drivers/iommu/intel-svm.c
+++ b/drivers/iommu/intel-svm.c
@@ -524,6 +524,10 @@ static irqreturn_t prq_event_thread(int irq, void *d)
struct intel_svm *svm = NULL;
int head, tail, handled = 0;
+ /* Clear PPR bit before reading head/tail registers, to
+ * ensure that we get a new interrupt if needed. */
+ writel(DMA_PRS_PPR, iommu->reg + DMAR_PRS_REG);
+
tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK;
head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK;
while (head != tail) {
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 821273ca4873..2d9b650047a5 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -235,6 +235,9 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
/* low 64 bit */
#define dma_frcd_page_addr(d) (d & (((u64)-1) << PAGE_SHIFT))
+/* PRS_REG */
+#define DMA_PRS_PPR ((u32)1)
+
#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
do { \
cycles_t start_time = get_cycles(); \