diff options
author | Weidong Han <weidong.han@intel.com> | 2008-12-08 15:34:06 +0800 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2009-01-03 14:02:18 +0100 |
commit | 1b5736839ae13dadc5947940144f95dd0f4a4a8c (patch) | |
tree | 2b6ce6b68850d905e4ce5d38b6872b82f6328208 /drivers | |
parent | 8c11e798eee2ce4475134eaf61302b28ea4f205d (diff) | |
download | op-kernel-dev-1b5736839ae13dadc5947940144f95dd0f4a4a8c.zip op-kernel-dev-1b5736839ae13dadc5947940144f95dd0f4a4a8c.tar.gz |
calculate agaw for each iommu
"SAGAW" capability may be different across iommus. Use a default agaw, but if default agaw is not supported in some iommus, choose a less supported agaw.
Signed-off-by: Weidong Han <weidong.han@intel.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pci/dmar.c | 10 | ||||
-rw-r--r-- | drivers/pci/intel-iommu.c | 22 |
2 files changed, 32 insertions, 0 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 5f164ff..f5a662a 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -491,6 +491,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) int map_size; u32 ver; static int iommu_allocated = 0; + int agaw; iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); if (!iommu) @@ -506,6 +507,15 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG); iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); + agaw = iommu_calculate_agaw(iommu); + if (agaw < 0) { + printk(KERN_ERR + "Cannot get a valid agaw for iommu (seq_id = %d)\n", + iommu->seq_id); + goto error; + } + iommu->agaw = agaw; + /* the registers might be more than one page */ map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), cap_max_fault_reg_offset(iommu->cap)); diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 9dca689..3ecfa23 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -362,6 +362,28 @@ void free_iova_mem(struct iova *iova) kmem_cache_free(iommu_iova_cache, iova); } + +static inline int width_to_agaw(int width); + +/* calculate agaw for each iommu. + * "SAGAW" may be different across iommus, use a default agaw, and + * get a supported less agaw for iommus that don't support the default agaw. + */ +int iommu_calculate_agaw(struct intel_iommu *iommu) +{ + unsigned long sagaw; + int agaw = -1; + + sagaw = cap_sagaw(iommu->cap); + for (agaw = width_to_agaw(DEFAULT_DOMAIN_ADDRESS_WIDTH); + agaw >= 0; agaw--) { + if (test_bit(agaw, &sagaw)) + break; + } + + return agaw; +} + /* in native case, each domain is related to only one iommu */ static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain) { |