diff options
| author | Jacob Pan <jacob.jun.pan@linux.intel.com> | 2016-12-06 13:14:23 -0500 |
|---|---|---|
| committer | Joerg Roedel <jroedel@suse.de> | 2017-01-04 09:18:57 -0500 |
| commit | 65ca7f5f7d1cdde6c25172fe6107cd16902f826f (patch) | |
| tree | 6fff0dccb8fcf28797336c23e973f7dfbd8a20a4 | |
| parent | aec0e86172a79eb5e44aff1055bb953fe4d47c59 (diff) | |
iommu/vt-d: Fix pasid table size encoding
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>
| -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 8862dc1e88eb..8a185250ae5a 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c | |||
| @@ -5204,6 +5204,25 @@ static void intel_iommu_remove_device(struct device *dev) | |||
| 5204 | } | 5204 | } |
| 5205 | 5205 | ||
| 5206 | #ifdef CONFIG_INTEL_IOMMU_SVM | 5206 | #ifdef CONFIG_INTEL_IOMMU_SVM |
| 5207 | #define MAX_NR_PASID_BITS (20) | ||
| 5208 | static inline unsigned long intel_iommu_get_pts(struct intel_iommu *iommu) | ||
| 5209 | { | ||
| 5210 | /* | ||
| 5211 | * Convert ecap_pss to extend context entry pts encoding, also | ||
| 5212 | * respect the soft pasid_max value set by the iommu. | ||
| 5213 | * - number of PASID bits = ecap_pss + 1 | ||
| 5214 | * - number of PASID table entries = 2^(pts + 5) | ||
| 5215 | * Therefore, pts = ecap_pss - 4 | ||
| 5216 | * e.g. KBL ecap_pss = 0x13, PASID has 20 bits, pts = 15 | ||
| 5217 | */ | ||
| 5218 | if (ecap_pss(iommu->ecap) < 5) | ||
| 5219 | return 0; | ||
| 5220 | |||
| 5221 | /* pasid_max is encoded as actual number of entries not the bits */ | ||
| 5222 | return find_first_bit((unsigned long *)&iommu->pasid_max, | ||
| 5223 | MAX_NR_PASID_BITS) - 5; | ||
| 5224 | } | ||
| 5225 | |||
| 5207 | int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sdev) | 5226 | int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sdev) |
| 5208 | { | 5227 | { |
| 5209 | struct device_domain_info *info; | 5228 | struct device_domain_info *info; |
| @@ -5236,7 +5255,9 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sd | |||
| 5236 | 5255 | ||
| 5237 | if (!(ctx_lo & CONTEXT_PASIDE)) { | 5256 | if (!(ctx_lo & CONTEXT_PASIDE)) { |
| 5238 | context[1].hi = (u64)virt_to_phys(iommu->pasid_state_table); | 5257 | context[1].hi = (u64)virt_to_phys(iommu->pasid_state_table); |
| 5239 | context[1].lo = (u64)virt_to_phys(iommu->pasid_table) | ecap_pss(iommu->ecap); | 5258 | context[1].lo = (u64)virt_to_phys(iommu->pasid_table) | |
| 5259 | intel_iommu_get_pts(iommu); | ||
| 5260 | |||
| 5240 | wmb(); | 5261 | wmb(); |
| 5241 | /* CONTEXT_TT_MULTI_LEVEL and CONTEXT_TT_DEV_IOTLB are both | 5262 | /* CONTEXT_TT_MULTI_LEVEL and CONTEXT_TT_DEV_IOTLB are both |
| 5242 | * extended to permit requests-with-PASID if the PASIDE bit | 5263 | * extended to permit requests-with-PASID if the PASIDE bit |
