Skip to content

Commit 66ac4db

Browse files
LuBaolujoergroedel
authored andcommitted
iommu/vt-d: Add page request draining support
When a PASID is stopped or terminated, there can be pending PRQs (requests that haven't received responses) in remapping hardware. This adds the interface to drain page requests and call it when a PASID is terminated. Signed-off-by: Jacob Pan <[email protected]> Signed-off-by: Liu Yi L <[email protected]> Signed-off-by: Lu Baolu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 37e91bd commit 66ac4db

File tree

2 files changed

+106
-5
lines changed

2 files changed

+106
-5
lines changed

drivers/iommu/intel-svm.c

Lines changed: 102 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "intel-pasid.h"
2424

2525
static irqreturn_t prq_event_thread(int irq, void *d);
26+
static void intel_svm_drain_prq(struct device *dev, int pasid);
2627

2728
#define PRQ_ORDER 0
2829

@@ -66,6 +67,8 @@ int intel_svm_enable_prq(struct intel_iommu *iommu)
6667
dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL);
6768
dmar_writeq(iommu->reg + DMAR_PQA_REG, virt_to_phys(iommu->prq) | PRQ_ORDER);
6869

70+
init_completion(&iommu->prq_complete);
71+
6972
return 0;
7073
}
7174

@@ -399,12 +402,8 @@ int intel_svm_unbind_gpasid(struct device *dev, int pasid)
399402
list_del_rcu(&sdev->list);
400403
intel_pasid_tear_down_entry(iommu, dev,
401404
svm->pasid, false);
405+
intel_svm_drain_prq(dev, svm->pasid);
402406
intel_flush_svm_range_dev(svm, sdev, 0, -1, 0);
403-
/* TODO: Drain in flight PRQ for the PASID since it
404-
* may get reused soon, we don't want to
405-
* confuse with its previous life.
406-
* intel_svm_drain_prq(dev, pasid);
407-
*/
408407
kfree_rcu(sdev, rcu);
409408

410409
if (list_empty(&svm->devs)) {
@@ -643,6 +642,7 @@ int intel_svm_unbind_mm(struct device *dev, int pasid)
643642
* hard to be as defensive as we might like. */
644643
intel_pasid_tear_down_entry(iommu, dev,
645644
svm->pasid, false);
645+
intel_svm_drain_prq(dev, svm->pasid);
646646
intel_flush_svm_range_dev(svm, sdev, 0, -1, 0);
647647
kfree_rcu(sdev, rcu);
648648

@@ -721,6 +721,93 @@ static bool is_canonical_address(u64 addr)
721721
return (((saddr << shift) >> shift) == saddr);
722722
}
723723

724+
/**
725+
* intel_svm_drain_prq - Drain page requests and responses for a pasid
726+
* @dev: target device
727+
* @pasid: pasid for draining
728+
*
729+
* Drain all pending page requests and responses related to @pasid in both
730+
* software and hardware. This is supposed to be called after the device
731+
* driver has stopped DMA, the pasid entry has been cleared, and both IOTLB
732+
* and DevTLB have been invalidated.
733+
*
734+
* It waits until all pending page requests for @pasid in the page fault
735+
* queue are completed by the prq handling thread. Then follow the steps
736+
* described in VT-d spec CH7.10 to drain all page requests and page
737+
* responses pending in the hardware.
738+
*/
739+
static void intel_svm_drain_prq(struct device *dev, int pasid)
740+
{
741+
struct device_domain_info *info;
742+
struct dmar_domain *domain;
743+
struct intel_iommu *iommu;
744+
struct qi_desc desc[3];
745+
struct pci_dev *pdev;
746+
int head, tail;
747+
u16 sid, did;
748+
int qdep;
749+
750+
info = get_domain_info(dev);
751+
if (WARN_ON(!info || !dev_is_pci(dev)))
752+
return;
753+
754+
if (!info->pri_enabled)
755+
return;
756+
757+
iommu = info->iommu;
758+
domain = info->domain;
759+
pdev = to_pci_dev(dev);
760+
sid = PCI_DEVID(info->bus, info->devfn);
761+
did = domain->iommu_did[iommu->seq_id];
762+
qdep = pci_ats_queue_depth(pdev);
763+
764+
/*
765+
* Check and wait until all pending page requests in the queue are
766+
* handled by the prq handling thread.
767+
*/
768+
prq_retry:
769+
reinit_completion(&iommu->prq_complete);
770+
tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK;
771+
head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK;
772+
while (head != tail) {
773+
struct page_req_dsc *req;
774+
775+
req = &iommu->prq[head / sizeof(*req)];
776+
if (!req->pasid_present || req->pasid != pasid) {
777+
head = (head + sizeof(*req)) & PRQ_RING_MASK;
778+
continue;
779+
}
780+
781+
wait_for_completion(&iommu->prq_complete);
782+
goto prq_retry;
783+
}
784+
785+
/*
786+
* Perform steps described in VT-d spec CH7.10 to drain page
787+
* requests and responses in hardware.
788+
*/
789+
memset(desc, 0, sizeof(desc));
790+
desc[0].qw0 = QI_IWD_STATUS_DATA(QI_DONE) |
791+
QI_IWD_FENCE |
792+
QI_IWD_TYPE;
793+
desc[1].qw0 = QI_EIOTLB_PASID(pasid) |
794+
QI_EIOTLB_DID(did) |
795+
QI_EIOTLB_GRAN(QI_GRAN_NONG_PASID) |
796+
QI_EIOTLB_TYPE;
797+
desc[2].qw0 = QI_DEV_EIOTLB_PASID(pasid) |
798+
QI_DEV_EIOTLB_SID(sid) |
799+
QI_DEV_EIOTLB_QDEP(qdep) |
800+
QI_DEIOTLB_TYPE |
801+
QI_DEV_IOTLB_PFSID(info->pfsid);
802+
qi_retry:
803+
reinit_completion(&iommu->prq_complete);
804+
qi_submit_sync(iommu, desc, 3, QI_OPT_WAIT_DRAIN);
805+
if (readl(iommu->reg + DMAR_PRS_REG) & DMA_PRS_PRO) {
806+
wait_for_completion(&iommu->prq_complete);
807+
goto qi_retry;
808+
}
809+
}
810+
724811
static irqreturn_t prq_event_thread(int irq, void *d)
725812
{
726813
struct intel_iommu *iommu = d;
@@ -856,6 +943,16 @@ static irqreturn_t prq_event_thread(int irq, void *d)
856943

857944
dmar_writeq(iommu->reg + DMAR_PQH_REG, tail);
858945

946+
/*
947+
* Clear the page request overflow bit and wake up all threads that
948+
* are waiting for the completion of this handling.
949+
*/
950+
if (readl(iommu->reg + DMAR_PRS_REG) & DMA_PRS_PRO)
951+
writel(DMA_PRS_PRO, iommu->reg + DMAR_PRS_REG);
952+
953+
if (!completion_done(&iommu->prq_complete))
954+
complete(&iommu->prq_complete);
955+
859956
return IRQ_RETVAL(handled);
860957
}
861958

include/linux/intel-iommu.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,8 @@
292292

293293
/* PRS_REG */
294294
#define DMA_PRS_PPR ((u32)1)
295+
#define DMA_PRS_PRO ((u32)2)
296+
295297
#define DMA_VCS_PAS ((u64)1)
296298

297299
#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
@@ -333,6 +335,7 @@ enum {
333335

334336
#define QI_IWD_STATUS_DATA(d) (((u64)d) << 32)
335337
#define QI_IWD_STATUS_WRITE (((u64)1) << 5)
338+
#define QI_IWD_FENCE (((u64)1) << 6)
336339
#define QI_IWD_PRQ_DRAIN (((u64)1) << 7)
337340

338341
#define QI_IOTLB_DID(did) (((u64)did) << 16)
@@ -582,6 +585,7 @@ struct intel_iommu {
582585
#ifdef CONFIG_INTEL_IOMMU_SVM
583586
struct page_req_dsc *prq;
584587
unsigned char prq_name[16]; /* Name for PRQ interrupt */
588+
struct completion prq_complete;
585589
struct ioasid_allocator_ops pasid_allocator; /* Custom allocator for PASIDs */
586590
#endif
587591
struct q_inval *qi; /* Queued invalidation info */

0 commit comments

Comments
 (0)