calculate agaw for each iommu
authorWeidong Han <weidong.han@intel.com>
Mon, 8 Dec 2008 07:34:06 +0000 (15:34 +0800)
committerJoerg Roedel <joerg.roedel@amd.com>
Sat, 3 Jan 2009 13:02:18 +0000 (14:02 +0100)
"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>
drivers/pci/dmar.c
drivers/pci/intel-iommu.c
include/linux/dma_remapping.h
include/linux/intel-iommu.h

index 5f164ff3026eb1cb4e91fd0acdb5bba2810ffbc6..f5a662a50acb12edea158dc114002cf1be33a418 100644 (file)
@@ -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));
index 9dca689215eb9b33f0735be5b3f82d9714690988..3ecfa2304c2c8a65524c47ff0684841c5514ed4e 100644 (file)
@@ -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)
 {
index 7799a85614c178a45f904fef28c8da38574f4103..136f170cecc294bd1c2b5b792bb93d89c025c021 100644 (file)
@@ -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;
 
index 1bff7bf1bc2cf6e0b44170940ecc26a5a768bed5..06349fd5871bfcfa7b11297e7618e9dd6b2aa1ae 100644 (file)
@@ -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 */