On 11/6/24 23:45, Yi Liu wrote:
+int intel_pasid_replace_first_level(struct intel_iommu *iommu, + struct device *dev, pgd_t *pgd, + u32 pasid, u16 did, u16 old_did, + int flags) +{ + struct pasid_entry *pte; + + if (!ecap_flts(iommu->ecap)) { + pr_err("No first level translation support on %s\n", + iommu->name); + return -EINVAL; + } + + if ((flags & PASID_FLAG_FL5LP) && !cap_fl5lp_support(iommu->cap)) { + pr_err("No 5-level paging support for first-level on %s\n", + iommu->name); + return -EINVAL; + } + + spin_lock(&iommu->lock); + pte = intel_pasid_get_entry(dev, pasid); + if (!pte) { + spin_unlock(&iommu->lock); + return -ENODEV; + } + + if (!pasid_pte_is_present(pte)) { + spin_unlock(&iommu->lock); + return -EINVAL; + } + + WARN_ON(old_did != pasid_get_domain_id(pte)); + + pasid_pte_config_first_level(iommu, pte, pgd, did, flags); + spin_unlock(&iommu->lock); + + intel_pasid_flush_present(iommu, dev, pasid, old_did, pte); + intel_iommu_drain_pasid_prq(dev, pasid); + + return 0; +}
pasid_pte_config_first_level() causes the pasid entry to transition from present to non-present and then to present. In this case, calling intel_pasid_flush_present() is not accurate, as it is only intended for pasid entries transitioning from present to present, according to the specification. It's recommended to move pasid_clear_entry(pte) and pasid_set_present(pte) out to the caller, so ... For setup case (pasid from non-present to present): - pasid_clear_entry(pte) - pasid_pte_config_first_level(pte) - pasid_set_present(pte) - cache invalidations For replace case (pasid from present to present) - pasid_pte_config_first_level(pte) - cache invalidations The same applies to other types of setup and replace. -- baolu