diff options
author | Weidong Han <weidong.han@intel.com> | 2008-12-08 02:34:06 -0500 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2009-01-03 08:02:18 -0500 |
commit | 1b5736839ae13dadc5947940144f95dd0f4a4a8c (patch) | |
tree | 2b6ce6b68850d905e4ce5d38b6872b82f6328208 /drivers | |
parent | 8c11e798eee2ce4475134eaf61302b28ea4f205d (diff) |
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 5f164ff3026e..f5a662a50acb 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c | |||
@@ -491,6 +491,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) | |||
491 | int map_size; | 491 | int map_size; |
492 | u32 ver; | 492 | u32 ver; |
493 | static int iommu_allocated = 0; | 493 | static int iommu_allocated = 0; |
494 | int agaw; | ||
494 | 495 | ||
495 | iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); | 496 | iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); |
496 | if (!iommu) | 497 | if (!iommu) |
@@ -506,6 +507,15 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) | |||
506 | iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG); | 507 | iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG); |
507 | iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); | 508 | iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); |
508 | 509 | ||
510 | agaw = iommu_calculate_agaw(iommu); | ||
511 | if (agaw < 0) { | ||
512 | printk(KERN_ERR | ||
513 | "Cannot get a valid agaw for iommu (seq_id = %d)\n", | ||
514 | iommu->seq_id); | ||
515 | goto error; | ||
516 | } | ||
517 | iommu->agaw = agaw; | ||
518 | |||
509 | /* the registers might be more than one page */ | 519 | /* the registers might be more than one page */ |
510 | map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), | 520 | map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), |
511 | cap_max_fault_reg_offset(iommu->cap)); | 521 | cap_max_fault_reg_offset(iommu->cap)); |
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 9dca689215eb..3ecfa2304c2c 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c | |||
@@ -362,6 +362,28 @@ void free_iova_mem(struct iova *iova) | |||
362 | kmem_cache_free(iommu_iova_cache, iova); | 362 | kmem_cache_free(iommu_iova_cache, iova); |
363 | } | 363 | } |
364 | 364 | ||
365 | |||
366 | static inline int width_to_agaw(int width); | ||
367 | |||
368 | /* calculate agaw for each iommu. | ||
369 | * "SAGAW" may be different across iommus, use a default agaw, and | ||
370 | * get a supported less agaw for iommus that don't support the default agaw. | ||
371 | */ | ||
372 | int iommu_calculate_agaw(struct intel_iommu *iommu) | ||
373 | { | ||
374 | unsigned long sagaw; | ||
375 | int agaw = -1; | ||
376 | |||
377 | sagaw = cap_sagaw(iommu->cap); | ||
378 | for (agaw = width_to_agaw(DEFAULT_DOMAIN_ADDRESS_WIDTH); | ||
379 | agaw >= 0; agaw--) { | ||
380 | if (test_bit(agaw, &sagaw)) | ||
381 | break; | ||
382 | } | ||
383 | |||
384 | return agaw; | ||
385 | } | ||
386 | |||
365 | /* in native case, each domain is related to only one iommu */ | 387 | /* in native case, each domain is related to only one iommu */ |
366 | static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain) | 388 | static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain) |
367 | { | 389 | { |