drivers/iommu/intel/pasid.c

Source file repositories/reference/linux-study-clean/drivers/iommu/intel/pasid.c

File Facts

System
Linux kernel
Corpus path
drivers/iommu/intel/pasid.c
Extension
.c
Size
25845 bytes
Lines
987
Domain
Driver Families
Bucket
drivers/iommu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!pasid_pte_is_fault_disabled(pte)) {
			WARN_ON(READ_ONCE(pte->val[0]) != 0);
			spin_unlock(&iommu->lock);
			return;
		}

		/*
		 * When a PASID is used for SVA by a device, it's possible
		 * that the pasid entry is non-present with the Fault
		 * Processing Disabled bit set. Clear the pasid entry and
		 * drain the PRQ for the PASID before return.
		 */
		pasid_clear_entry(pte);
		spin_unlock(&iommu->lock);
		intel_iommu_drain_pasid_prq(dev, pasid);

		return;
	}

	did = pasid_get_domain_id(pte);
	pgtt = pasid_pte_get_pgtt(pte);
	pasid_clear_present(pte);
	spin_unlock(&iommu->lock);

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

	pasid_cache_invalidation_with_pasid(iommu, did, pasid);

	if (pgtt == PASID_ENTRY_PGTT_PT || pgtt == PASID_ENTRY_PGTT_FL_ONLY)
		qi_flush_piotlb_all(iommu, did, pasid);
	else
		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);

	devtlb_invalidation_with_pasid(iommu, dev, pasid);
	intel_pasid_clear_entry(dev, pasid, fault_ignore);
	if (!ecap_coherent(iommu->ecap))
		clflush_cache_range(pte, sizeof(*pte));

	if (!fault_ignore)
		intel_iommu_drain_pasid_prq(dev, pasid);
}

/*
 * This function flushes cache for a newly setup pasid table entry.
 * Caller of it should not modify the in-use pasid table entries.
 */
static void pasid_flush_caches(struct intel_iommu *iommu,
				struct pasid_entry *pte,
			       u32 pasid, u16 did)
{
	if (!ecap_coherent(iommu->ecap))
		clflush_cache_range(pte, sizeof(*pte));

	if (cap_caching_mode(iommu->cap)) {
		pasid_cache_invalidation_with_pasid(iommu, did, pasid);
		qi_flush_piotlb_all(iommu, did, pasid);
	} else {
		iommu_flush_write_buffer(iommu);
	}
}

/*
 * This function is supposed to be used after caller updates the fields
 * except for the SSADE and P bit of a pasid table entry. It does the
 * below:
 * - Flush cacheline if needed
 * - Flush the caches per Table 28 ”Guidance to Software for Invalidations“
 *   of VT-d spec 5.0.
 */
static void intel_pasid_flush_present(struct intel_iommu *iommu,
				      struct device *dev,
				      u32 pasid, u16 did,
				      struct pasid_entry *pte)
{
	if (!ecap_coherent(iommu->ecap))
		clflush_cache_range(pte, sizeof(*pte));

	/*
	 * VT-d spec 5.0 table28 states guides for cache invalidation:
	 *
	 * - PASID-selective-within-Domain PASID-cache invalidation
	 * - PASID-selective PASID-based IOTLB invalidation
	 * - If (pasid is RID_PASID)
	 *    - Global Device-TLB invalidation to affected functions
	 *   Else
	 *    - PASID-based Device-TLB invalidation (with S=1 and
	 *      Addr[63:12]=0x7FFFFFFF_FFFFF) to affected functions
	 */
	pasid_cache_invalidation_with_pasid(iommu, did, pasid);

Annotation

Implementation Notes