Merge branch 'master' into for-2.6.35
[safe/jmp/linux-2.6] / arch / x86 / kernel / amd_iommu_init.c
index 8567d16..6360abf 100644 (file)
@@ -19,8 +19,8 @@
 
 #include <linux/pci.h>
 #include <linux/acpi.h>
-#include <linux/gfp.h>
 #include <linux/list.h>
+#include <linux/slab.h>
 #include <linux/sysdev.h>
 #include <linux/interrupt.h>
 #include <linux/msi.h>
@@ -125,13 +125,6 @@ u16 amd_iommu_last_bdf;                    /* largest PCI device id we have
                                           to handle */
 LIST_HEAD(amd_iommu_unity_map);                /* a list of required unity mappings
                                           we find in ACPI */
-#ifdef CONFIG_IOMMU_STRESS
-bool amd_iommu_isolate = false;
-#else
-bool amd_iommu_isolate = true;         /* if true, device isolation is
-                                          enabled */
-#endif
-
 bool amd_iommu_unmap_flush;            /* if true, flush on every unmap */
 
 LIST_HEAD(amd_iommu_list);             /* list of all AMD IOMMUs in the
@@ -141,6 +134,20 @@ LIST_HEAD(amd_iommu_list);         /* list of all AMD IOMMUs in the
 struct amd_iommu *amd_iommus[MAX_IOMMUS];
 int amd_iommus_present;
 
+/* IOMMUs have a non-present cache? */
+bool amd_iommu_np_cache __read_mostly;
+
+/*
+ * The ACPI table parsing functions set this variable on an error
+ */
+static int __initdata amd_iommu_init_err;
+
+/*
+ * List of protection domains - used during resume
+ */
+LIST_HEAD(amd_iommu_pd_list);
+spinlock_t amd_iommu_pd_lock;
+
 /*
  * Pointer to the device table which is shared by all AMD IOMMUs
  * it is indexed by the PCI device id or the HT unit id and contains
@@ -163,12 +170,6 @@ u16 *amd_iommu_alias_table;
 struct amd_iommu **amd_iommu_rlookup_table;
 
 /*
- * The pd table (protection domain table) is used to find the protection domain
- * data structure a device belongs to. Indexed with the PCI device id too.
- */
-struct protection_domain **amd_iommu_pd_table;
-
-/*
  * AMD IOMMU allows up to 2^16 differend protection domains. This is a bitmap
  * to know which ones are already in use.
  */
@@ -390,9 +391,11 @@ static int __init find_last_devid_acpi(struct acpi_table_header *table)
         */
        for (i = 0; i < table->length; ++i)
                checksum += p[i];
-       if (checksum != 0)
+       if (checksum != 0) {
                /* ACPI table corrupt */
-               return -ENODEV;
+               amd_iommu_init_err = -ENODEV;
+               return 0;
+       }
 
        p += IVRS_HEADER_LENGTH;
 
@@ -435,7 +438,7 @@ static u8 * __init alloc_command_buffer(struct amd_iommu *iommu)
        if (cmd_buf == NULL)
                return NULL;
 
-       iommu->cmd_buf_size = CMD_BUFFER_SIZE;
+       iommu->cmd_buf_size = CMD_BUFFER_SIZE | CMD_BUFFER_UNINITIALIZED;
 
        return cmd_buf;
 }
@@ -471,12 +474,13 @@ static void iommu_enable_command_buffer(struct amd_iommu *iommu)
                    &entry, sizeof(entry));
 
        amd_iommu_reset_cmd_buffer(iommu);
+       iommu->cmd_buf_size &= ~(CMD_BUFFER_UNINITIALIZED);
 }
 
 static void __init free_command_buffer(struct amd_iommu *iommu)
 {
        free_pages((unsigned long)iommu->cmd_buf,
-                  get_order(iommu->cmd_buf_size));
+                  get_order(iommu->cmd_buf_size & ~(CMD_BUFFER_UNINITIALIZED)));
 }
 
 /* allocates the memory where the IOMMU will log its events to */
@@ -885,6 +889,9 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
        init_iommu_from_acpi(iommu, h);
        init_iommu_devices(iommu);
 
+       if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE))
+               amd_iommu_np_cache = true;
+
        return pci_enable_device(iommu->dev);
 }
 
@@ -916,11 +923,16 @@ static int __init init_iommu_all(struct acpi_table_header *table)
                                    h->mmio_phys);
 
                        iommu = kzalloc(sizeof(struct amd_iommu), GFP_KERNEL);
-                       if (iommu == NULL)
-                               return -ENOMEM;
+                       if (iommu == NULL) {
+                               amd_iommu_init_err = -ENOMEM;
+                               return 0;
+                       }
+
                        ret = init_iommu_one(iommu, h);
-                       if (ret)
-                               return ret;
+                       if (ret) {
+                               amd_iommu_init_err = ret;
+                               return 0;
+                       }
                        break;
                default:
                        break;
@@ -1205,6 +1217,10 @@ static int __init amd_iommu_init(void)
        if (acpi_table_parse("IVRS", find_last_devid_acpi) != 0)
                return -ENODEV;
 
+       ret = amd_iommu_init_err;
+       if (ret)
+               goto out;
+
        dev_table_size     = tbl_size(DEV_TABLE_ENTRY_SIZE);
        alias_table_size   = tbl_size(ALIAS_TABLE_ENTRY_SIZE);
        rlookup_table_size = tbl_size(RLOOKUP_TABLE_ENTRY_SIZE);
@@ -1233,15 +1249,6 @@ static int __init amd_iommu_init(void)
        if (amd_iommu_rlookup_table == NULL)
                goto free;
 
-       /*
-        * Protection Domain table - maps devices to protection domains
-        * This table has the same size as the rlookup_table
-        */
-       amd_iommu_pd_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
-                                    get_order(rlookup_table_size));
-       if (amd_iommu_pd_table == NULL)
-               goto free;
-
        amd_iommu_pd_alloc_bitmap = (void *)__get_free_pages(
                                            GFP_KERNEL | __GFP_ZERO,
                                            get_order(MAX_DOMAIN_ID/8));
@@ -1263,6 +1270,8 @@ static int __init amd_iommu_init(void)
         */
        amd_iommu_pd_alloc_bitmap[0] = 1;
 
+       spin_lock_init(&amd_iommu_pd_lock);
+
        /*
         * now the data structures are allocated and basically initialized
         * start the real acpi table scan
@@ -1271,9 +1280,19 @@ static int __init amd_iommu_init(void)
        if (acpi_table_parse("IVRS", init_iommu_all) != 0)
                goto free;
 
+       if (amd_iommu_init_err) {
+               ret = amd_iommu_init_err;
+               goto free;
+       }
+
        if (acpi_table_parse("IVRS", init_memory_definitions) != 0)
                goto free;
 
+       if (amd_iommu_init_err) {
+               ret = amd_iommu_init_err;
+               goto free;
+       }
+
        ret = sysdev_class_register(&amd_iommu_sysdev_class);
        if (ret)
                goto free;
@@ -1282,24 +1301,27 @@ static int __init amd_iommu_init(void)
        if (ret)
                goto free;
 
+       ret = amd_iommu_init_devices();
+       if (ret)
+               goto free;
+
+       enable_iommus();
+
        if (iommu_pass_through)
                ret = amd_iommu_init_passthrough();
        else
                ret = amd_iommu_init_dma_ops();
+
        if (ret)
                goto free;
 
-       enable_iommus();
+       amd_iommu_init_api();
+
+       amd_iommu_init_notifier();
 
        if (iommu_pass_through)
                goto out;
 
-       printk(KERN_INFO "AMD-Vi: device isolation ");
-       if (amd_iommu_isolate)
-               printk("enabled\n");
-       else
-               printk("disabled\n");
-
        if (amd_iommu_unmap_flush)
                printk(KERN_INFO "AMD-Vi: IO/TLB flush on unmap enabled\n");
        else
@@ -1310,12 +1332,13 @@ out:
        return ret;
 
 free:
+       disable_iommus();
+
+       amd_iommu_uninit_devices();
+
        free_pages((unsigned long)amd_iommu_pd_alloc_bitmap,
                   get_order(MAX_DOMAIN_ID/8));
 
-       free_pages((unsigned long)amd_iommu_pd_table,
-                  get_order(rlookup_table_size));
-
        free_pages((unsigned long)amd_iommu_rlookup_table,
                   get_order(rlookup_table_size));
 
@@ -1353,6 +1376,9 @@ void __init amd_iommu_detect(void)
                iommu_detected = 1;
                amd_iommu_detected = 1;
                x86_init.iommu.iommu_init = amd_iommu_init;
+
+               /* Make sure ACS will be enabled */
+               pci_request_acs();
        }
 }
 
@@ -1373,10 +1399,6 @@ static int __init parse_amd_iommu_dump(char *str)
 static int __init parse_amd_iommu_options(char *str)
 {
        for (; *str; ++str) {
-               if (strncmp(str, "isolate", 7) == 0)
-                       amd_iommu_isolate = true;
-               if (strncmp(str, "share", 5) == 0)
-                       amd_iommu_isolate = false;
                if (strncmp(str, "fullflush", 9) == 0)
                        amd_iommu_unmap_flush = true;
        }