diff options
author | Jacob Pan <jacob.jun.pan@linux.intel.com> | 2016-12-06 13:14:23 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-01-12 05:39:28 -0500 |
commit | ef41459ab279edd5fa11da4efac4aa0155c06a35 (patch) | |
tree | 21af67b4ad38771cda9e180ef8e68ff05cdff6b1 | |
parent | 2148835de3c2410bfb6c64037187a1b72f6d6488 (diff) |
iommu/vt-d: Fix pasid table size encoding
commit 65ca7f5f7d1cdde6c25172fe6107cd16902f826f upstream.
Different encodings are used to represent supported PASID bits
and number of PASID table entries.
The current code assigns ecap_pss directly to extended context
table entry PTS which is wrong and could result in writing
non-zero bits to the reserved fields. IOMMU fault reason
11 will be reported when reserved bits are nonzero.
This patch converts ecap_pss to extend context entry pts encoding
based on VT-d spec. Chapter 9.4 as follows:
- number of PASID bits = ecap_pss + 1
- number of PASID table entries = 2^(pts + 5)
Software assigned limit of pasid_max value is also respected to
match the allocation limitation of PASID table.
cc: Mika Kuoppala <mika.kuoppala@linux.intel.com>
cc: Ashok Raj <ashok.raj@intel.com>
Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
Tested-by: Mika Kuoppala <mika.kuoppala@intel.com>
Fixes: 2f26e0a9c9860 ('iommu/vt-d: Add basic SVM PASID support')
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/iommu/intel-iommu.c | 23 |
1 files changed, 22 insertions, 1 deletions
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index d8376c2d18b3..96566d504d2a 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c | |||
@@ -5197,6 +5197,25 @@ static void intel_iommu_remove_device(struct device *dev) | |||
5197 | } | 5197 | } |
5198 | 5198 | ||
5199 | #ifdef CONFIG_INTEL_IOMMU_SVM | 5199 | #ifdef CONFIG_INTEL_IOMMU_SVM |
5200 | #define MAX_NR_PASID_BITS (20) | ||
5201 | static inline unsigned long intel_iommu_get_pts(struct intel_iommu *iommu) | ||
5202 | { | ||
5203 | /* | ||
5204 | * Convert ecap_pss to extend context entry pts encoding, also | ||
5205 | * respect the soft pasid_max value set by the iommu. | ||
5206 | * - number of PASID bits = ecap_pss + 1 | ||
5207 | * - number of PASID table entries = 2^(pts + 5) | ||
5208 | * Therefore, pts = ecap_pss - 4 | ||
5209 | * e.g. KBL ecap_pss = 0x13, PASID has 20 bits, pts = 15 | ||
5210 | */ | ||
5211 | if (ecap_pss(iommu->ecap) < 5) | ||
5212 | return 0; | ||
5213 | |||
5214 | /* pasid_max is encoded as actual number of entries not the bits */ | ||
5215 | return find_first_bit((unsigned long *)&iommu->pasid_max, | ||
5216 | MAX_NR_PASID_BITS) - 5; | ||
5217 | } | ||
5218 | |||
5200 | int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sdev) | 5219 | int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sdev) |
5201 | { | 5220 | { |
5202 | struct device_domain_info *info; | 5221 | struct device_domain_info *info; |
@@ -5229,7 +5248,9 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sd | |||
5229 | 5248 | ||
5230 | if (!(ctx_lo & CONTEXT_PASIDE)) { | 5249 | if (!(ctx_lo & CONTEXT_PASIDE)) { |
5231 | context[1].hi = (u64)virt_to_phys(iommu->pasid_state_table); | 5250 | context[1].hi = (u64)virt_to_phys(iommu->pasid_state_table); |
5232 | context[1].lo = (u64)virt_to_phys(iommu->pasid_table) | ecap_pss(iommu->ecap); | 5251 | context[1].lo = (u64)virt_to_phys(iommu->pasid_table) | |
5252 | intel_iommu_get_pts(iommu); | ||
5253 | |||
5233 | wmb(); | 5254 | wmb(); |
5234 | /* CONTEXT_TT_MULTI_LEVEL and CONTEXT_TT_DEV_IOTLB are both | 5255 | /* CONTEXT_TT_MULTI_LEVEL and CONTEXT_TT_DEV_IOTLB are both |
5235 | * extended to permit requests-with-PASID if the PASIDE bit | 5256 | * extended to permit requests-with-PASID if the PASIDE bit |