Commit 1b573683 authored by Weidong Han's avatar Weidong Han Committed by Joerg Roedel

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: default avatarWeidong Han <weidong.han@intel.com>
Signed-off-by: default avatarJoerg Roedel <joerg.roedel@amd.com>
parent 8c11e798
...@@ -491,6 +491,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) ...@@ -491,6 +491,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
int map_size; int map_size;
u32 ver; u32 ver;
static int iommu_allocated = 0; static int iommu_allocated = 0;
int agaw;
iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
if (!iommu) if (!iommu)
...@@ -506,6 +507,15 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) ...@@ -506,6 +507,15 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG); iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_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 */ /* the registers might be more than one page */
map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap),
cap_max_fault_reg_offset(iommu->cap)); cap_max_fault_reg_offset(iommu->cap));
......
...@@ -362,6 +362,28 @@ void free_iova_mem(struct iova *iova) ...@@ -362,6 +362,28 @@ void free_iova_mem(struct iova *iova)
kmem_cache_free(iommu_iova_cache, 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 */ /* in native case, each domain is related to only one iommu */
static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain) static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain)
{ {
......
...@@ -17,6 +17,7 @@ struct dmar_domain; ...@@ -17,6 +17,7 @@ struct dmar_domain;
struct root_entry; struct root_entry;
extern void free_dmar_iommu(struct intel_iommu *iommu); extern void free_dmar_iommu(struct intel_iommu *iommu);
extern int iommu_calculate_agaw(struct intel_iommu *iommu);
extern int dmar_disabled; extern int dmar_disabled;
......
...@@ -290,6 +290,7 @@ struct intel_iommu { ...@@ -290,6 +290,7 @@ struct intel_iommu {
u32 gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */ u32 gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */
spinlock_t register_lock; /* protect register handling */ spinlock_t register_lock; /* protect register handling */
int seq_id; /* sequence id of the iommu */ int seq_id; /* sequence id of the iommu */
int agaw; /* agaw of this iommu */
#ifdef CONFIG_DMAR #ifdef CONFIG_DMAR
unsigned long *domain_ids; /* bitmap of domains */ unsigned long *domain_ids; /* bitmap of domains */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment