Skip to content

Commit 8798d36

Browse files
yiliu1765joergroedel
authored andcommitted
iommu/vt-d: Fix incomplete cache flush in intel_pasid_tear_down_entry()
This fixes improper iotlb invalidation in intel_pasid_tear_down_entry(). When a PASID was used as nested mode, released and reused, the following error message will appear: [ 180.187556] Unexpected page request in Privilege Mode [ 180.187565] Unexpected page request in Privilege Mode [ 180.279933] Unexpected page request in Privilege Mode [ 180.279937] Unexpected page request in Privilege Mode Per chapter 6.5.3.3 of VT-d spec 3.3, when tear down a pasid entry, the software should use Domain selective IOTLB flush if the PGTT of the pasid entry is SL only or Nested, while for the pasid entries whose PGTT is FL only or PT using PASID-based IOTLB flush is enough. Fixes: 2cd1311 ("iommu/vt-d: Add set domain DOMAIN_ATTR_NESTING attr") Signed-off-by: Kumar Sanjay K <[email protected]> Signed-off-by: Liu Yi L <[email protected]> Tested-by: Yi Sun <[email protected]> Link: https://lore.kernel.org/r/[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 62ef907 commit 8798d36

File tree

2 files changed

+14
-2
lines changed

2 files changed

+14
-2
lines changed

drivers/iommu/intel/pasid.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
511511
u32 pasid, bool fault_ignore)
512512
{
513513
struct pasid_entry *pte;
514-
u16 did;
514+
u16 did, pgtt;
515515

516516
pte = intel_pasid_get_entry(dev, pasid);
517517
if (WARN_ON(!pte))
@@ -521,13 +521,19 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
521521
return;
522522

523523
did = pasid_get_domain_id(pte);
524+
pgtt = pasid_pte_get_pgtt(pte);
525+
524526
intel_pasid_clear_entry(dev, pasid, fault_ignore);
525527

526528
if (!ecap_coherent(iommu->ecap))
527529
clflush_cache_range(pte, sizeof(*pte));
528530

529531
pasid_cache_invalidation_with_pasid(iommu, did, pasid);
530-
qi_flush_piotlb(iommu, did, pasid, 0, -1, 0);
532+
533+
if (pgtt == PASID_ENTRY_PGTT_PT || pgtt == PASID_ENTRY_PGTT_FL_ONLY)
534+
qi_flush_piotlb(iommu, did, pasid, 0, -1, 0);
535+
else
536+
iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
531537

532538
/* Device IOTLB doesn't need to be flushed in caching mode. */
533539
if (!cap_caching_mode(iommu->cap))

drivers/iommu/intel/pasid.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ static inline bool pasid_pte_is_present(struct pasid_entry *pte)
9999
return READ_ONCE(pte->val[0]) & PASID_PTE_PRESENT;
100100
}
101101

102+
/* Get PGTT field of a PASID table entry */
103+
static inline u16 pasid_pte_get_pgtt(struct pasid_entry *pte)
104+
{
105+
return (u16)((READ_ONCE(pte->val[0]) >> 6) & 0x7);
106+
}
107+
102108
extern unsigned int intel_pasid_max_id;
103109
int intel_pasid_alloc_table(struct device *dev);
104110
void intel_pasid_free_table(struct device *dev);

0 commit comments

Comments
 (0)