| From a17d33a9a0aea02547cb15d7be274f6a98075791 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 30 Mar 2021 10:11:45 +0800 |
| Subject: iommu/vt-d: Report right snoop capability when using FL for IOVA |
| |
| From: Lu Baolu <baolu.lu@linux.intel.com> |
| |
| [ Upstream commit 6c00612d0cba10f7d0917cf1f73c945003ed4cd7 ] |
| |
| The Intel VT-d driver checks wrong register to report snoop capablility |
| when using first level page table for GPA to HPA translation. This might |
| lead the IOMMU driver to say that it supports snooping control, but in |
| reality, it does not. Fix this by always setting PASID-table-entry.PGSNP |
| whenever a pasid entry is setting up for GPA to HPA translation so that |
| the IOMMU driver could report snoop capability as long as it runs in the |
| scalable mode. |
| |
| Fixes: b802d070a52a1 ("iommu/vt-d: Use iova over first level") |
| Suggested-by: Rajesh Sankaran <rajesh.sankaran@intel.com> |
| Suggested-by: Kevin Tian <kevin.tian@intel.com> |
| Suggested-by: Ashok Raj <ashok.raj@intel.com> |
| Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com> |
| Link: https://lore.kernel.org/r/20210330021145.13824-1-baolu.lu@linux.intel.com |
| Signed-off-by: Joerg Roedel <jroedel@suse.de> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/iommu/intel/iommu.c | 12 +++++++++++- |
| drivers/iommu/intel/pasid.c | 16 ++++++++++++++++ |
| drivers/iommu/intel/pasid.h | 1 + |
| 3 files changed, 28 insertions(+), 1 deletion(-) |
| |
| diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c |
| index 005daf50107d..026041308409 100644 |
| --- a/drivers/iommu/intel/iommu.c |
| +++ b/drivers/iommu/intel/iommu.c |
| @@ -647,7 +647,14 @@ static int domain_update_iommu_snooping(struct intel_iommu *skip) |
| rcu_read_lock(); |
| for_each_active_iommu(iommu, drhd) { |
| if (iommu != skip) { |
| - if (!ecap_sc_support(iommu->ecap)) { |
| + /* |
| + * If the hardware is operating in the scalable mode, |
| + * the snooping control is always supported since we |
| + * always set PASID-table-entry.PGSNP bit if the domain |
| + * is managed outside (UNMANAGED). |
| + */ |
| + if (!sm_supported(iommu) && |
| + !ecap_sc_support(iommu->ecap)) { |
| ret = 0; |
| break; |
| } |
| @@ -2546,6 +2553,9 @@ static int domain_setup_first_level(struct intel_iommu *iommu, |
| |
| flags |= (level == 5) ? PASID_FLAG_FL5LP : 0; |
| |
| + if (domain->domain.type == IOMMU_DOMAIN_UNMANAGED) |
| + flags |= PASID_FLAG_PAGE_SNOOP; |
| + |
| return intel_pasid_setup_first_level(iommu, dev, (pgd_t *)pgd, pasid, |
| domain->iommu_did[iommu->seq_id], |
| flags); |
| diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c |
| index b92af83b79bd..ce4ef2d245e3 100644 |
| --- a/drivers/iommu/intel/pasid.c |
| +++ b/drivers/iommu/intel/pasid.c |
| @@ -411,6 +411,16 @@ static inline void pasid_set_page_snoop(struct pasid_entry *pe, bool value) |
| pasid_set_bits(&pe->val[1], 1 << 23, value << 23); |
| } |
| |
| +/* |
| + * Setup the Page Snoop (PGSNP) field (Bit 88) of a scalable mode |
| + * PASID entry. |
| + */ |
| +static inline void |
| +pasid_set_pgsnp(struct pasid_entry *pe) |
| +{ |
| + pasid_set_bits(&pe->val[1], 1ULL << 24, 1ULL << 24); |
| +} |
| + |
| /* |
| * Setup the First Level Page table Pointer field (Bit 140~191) |
| * of a scalable mode PASID entry. |
| @@ -579,6 +589,9 @@ int intel_pasid_setup_first_level(struct intel_iommu *iommu, |
| } |
| } |
| |
| + if (flags & PASID_FLAG_PAGE_SNOOP) |
| + pasid_set_pgsnp(pte); |
| + |
| pasid_set_domain_id(pte, did); |
| pasid_set_address_width(pte, iommu->agaw); |
| pasid_set_page_snoop(pte, !!ecap_smpwc(iommu->ecap)); |
| @@ -657,6 +670,9 @@ int intel_pasid_setup_second_level(struct intel_iommu *iommu, |
| pasid_set_fault_enable(pte); |
| pasid_set_page_snoop(pte, !!ecap_smpwc(iommu->ecap)); |
| |
| + if (domain->domain.type == IOMMU_DOMAIN_UNMANAGED) |
| + pasid_set_pgsnp(pte); |
| + |
| /* |
| * Since it is a second level only translation setup, we should |
| * set SRE bit as well (addresses are expected to be GPAs). |
| diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h |
| index 444c0bec221a..086ebd697319 100644 |
| --- a/drivers/iommu/intel/pasid.h |
| +++ b/drivers/iommu/intel/pasid.h |
| @@ -48,6 +48,7 @@ |
| */ |
| #define PASID_FLAG_SUPERVISOR_MODE BIT(0) |
| #define PASID_FLAG_NESTED BIT(1) |
| +#define PASID_FLAG_PAGE_SNOOP BIT(2) |
| |
| /* |
| * The PASID_FLAG_FL5LP flag Indicates using 5-level paging for first- |
| -- |
| 2.30.2 |
| |