Merge git://git.infradead.org/iommu-2.6
[sfrench/cifs-2.6.git] / drivers / pci / dmar.c
index 33ead97f0c4b24e2e030ae913bef26cdf435d533..0a19708074c2b5265379ec816e777771823ab861 100644 (file)
@@ -131,9 +131,10 @@ static int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
                if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
                    scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE)
                        (*cnt)++;
-               else
+               else if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_IOAPIC) {
                        printk(KERN_WARNING PREFIX
-                               "Unsupported device scope\n");
+                              "Unsupported device scope\n");
+               }
                start += scope->length;
        }
        if (*cnt == 0)
@@ -309,6 +310,8 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev)
        struct acpi_dmar_atsr *atsr;
        struct dmar_atsr_unit *atsru;
 
+       dev = pci_physfn(dev);
+
        list_for_each_entry(atsru, &dmar_atsr_units, list) {
                atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
                if (atsr->segment == pci_domain_nr(dev->bus))
@@ -358,12 +361,14 @@ dmar_parse_one_rhsa(struct acpi_dmar_header *header)
                        return 0;
                }
        }
-       WARN(1, "Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n"
-            "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
-            drhd->reg_base_addr,
-            dmi_get_system_info(DMI_BIOS_VENDOR),
-            dmi_get_system_info(DMI_BIOS_VERSION),
-            dmi_get_system_info(DMI_PRODUCT_VERSION));
+       WARN_TAINT(
+               1, TAINT_FIRMWARE_WORKAROUND,
+               "Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n"
+               "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
+               drhd->reg_base_addr,
+               dmi_get_system_info(DMI_BIOS_VENDOR),
+               dmi_get_system_info(DMI_BIOS_VERSION),
+               dmi_get_system_info(DMI_PRODUCT_VERSION));
 
        return 0;
 }
@@ -507,7 +512,7 @@ parse_dmar_table(void)
        return ret;
 }
 
-int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
+static int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
                          struct pci_dev *dev)
 {
        int index;
@@ -530,6 +535,8 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev)
        struct dmar_drhd_unit *dmaru = NULL;
        struct acpi_dmar_hardware_unit *drhd;
 
+       dev = pci_physfn(dev);
+
        list_for_each_entry(dmaru, &dmar_drhd_units, list) {
                drhd = container_of(dmaru->hdr,
                                    struct acpi_dmar_hardware_unit,
@@ -614,7 +621,17 @@ int __init dmar_table_init(void)
        return 0;
 }
 
-static int bios_warned;
+static void warn_invalid_dmar(u64 addr, const char *message)
+{
+       WARN_TAINT_ONCE(
+               1, TAINT_FIRMWARE_WORKAROUND,
+               "Your BIOS is broken; DMAR reported at address %llx%s!\n"
+               "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
+               addr, message,
+               dmi_get_system_info(DMI_BIOS_VENDOR),
+               dmi_get_system_info(DMI_BIOS_VERSION),
+               dmi_get_system_info(DMI_PRODUCT_VERSION));
+}
 
 int __init check_zero_address(void)
 {
@@ -640,13 +657,7 @@ int __init check_zero_address(void)
 
                        drhd = (void *)entry_header;
                        if (!drhd->address) {
-                               /* Promote an attitude of violence to a BIOS engineer today */
-                               WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n"
-                                    "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
-                                    dmi_get_system_info(DMI_BIOS_VENDOR),
-                                    dmi_get_system_info(DMI_BIOS_VERSION),
-                                    dmi_get_system_info(DMI_PRODUCT_VERSION));
-                               bios_warned = 1;
+                               warn_invalid_dmar(0, "");
                                goto failed;
                        }
 
@@ -659,14 +670,8 @@ int __init check_zero_address(void)
                        ecap = dmar_readq(addr + DMAR_ECAP_REG);
                        early_iounmap(addr, VTD_PAGE_SIZE);
                        if (cap == (uint64_t)-1 && ecap == (uint64_t)-1) {
-                               /* Promote an attitude of violence to a BIOS engineer today */
-                               WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n"
-                                    "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
-                                     drhd->address,
-                                     dmi_get_system_info(DMI_BIOS_VENDOR),
-                                     dmi_get_system_info(DMI_BIOS_VERSION),
-                                     dmi_get_system_info(DMI_PRODUCT_VERSION));
-                               bios_warned = 1;
+                               warn_invalid_dmar(drhd->address,
+                                                 " returns all ones");
                                goto failed;
                        }
                }
@@ -731,14 +736,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
        int msagaw = 0;
 
        if (!drhd->reg_base_addr) {
-               if (!bios_warned) {
-                       WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n"
-                            "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
-                            dmi_get_system_info(DMI_BIOS_VENDOR),
-                            dmi_get_system_info(DMI_BIOS_VERSION),
-                            dmi_get_system_info(DMI_PRODUCT_VERSION));
-                       bios_warned = 1;
-               }
+               warn_invalid_dmar(0, "");
                return -EINVAL;
        }
 
@@ -758,16 +756,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
        iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
 
        if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) {
-               if (!bios_warned) {
-                       /* Promote an attitude of violence to a BIOS engineer today */
-                       WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n"
-                            "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
-                            drhd->reg_base_addr,
-                            dmi_get_system_info(DMI_BIOS_VENDOR),
-                            dmi_get_system_info(DMI_BIOS_VERSION),
-                            dmi_get_system_info(DMI_PRODUCT_VERSION));
-                       bios_warned = 1;
-               }
+               warn_invalid_dmar(drhd->reg_base_addr, " returns all ones");
                goto err_unmap;
        }
 
@@ -806,7 +795,8 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
        }
 
        ver = readl(iommu->reg + DMAR_VER_REG);
-       pr_info("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n",
+       pr_info("IOMMU %d: reg_base_addr %llx ver %d:%d cap %llx ecap %llx\n",
+               iommu->seq_id,
                (unsigned long long)drhd->reg_base_addr,
                DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver),
                (unsigned long long)iommu->cap,
@@ -1457,9 +1447,11 @@ int dmar_reenable_qi(struct intel_iommu *iommu)
 /*
  * Check interrupt remapping support in DMAR table description.
  */
-int dmar_ir_support(void)
+int __init dmar_ir_support(void)
 {
        struct acpi_table_dmar *dmar;
        dmar = (struct acpi_table_dmar *)dmar_tbl;
+       if (!dmar)
+               return 0;
        return dmar->flags & 0x1;
 }