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

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
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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));
+22 −0
Original line number Diff line number Diff line
@@ -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)
{
+1 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ struct dmar_domain;
struct root_entry;

extern void free_dmar_iommu(struct intel_iommu *iommu);
extern int iommu_calculate_agaw(struct intel_iommu *iommu);

extern int dmar_disabled;

+1 −0
Original line number Diff line number Diff line
@@ -290,6 +290,7 @@ struct intel_iommu {
	u32		gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */
	spinlock_t	register_lock; /* protect register handling */
	int		seq_id;	/* sequence id of the iommu */
	int		agaw; /* agaw of this iommu */

#ifdef CONFIG_DMAR
	unsigned long 	*domain_ids; /* bitmap of domains */