ACPI / blacklist: add acpi_match_platform_list()
authorToshi Kani <toshi.kani@hpe.com>
Wed, 23 Aug 2017 22:54:43 +0000 (16:54 -0600)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 28 Aug 2017 23:42:48 +0000 (01:42 +0200)
ACPI OEM ID / OEM Table ID / Revision can be used to identify
a platform based on ACPI firmware info.  acpi_blacklisted(),
intel_pstate_platform_pwr_mgmt_exists(), and some other funcs,
have been using similar check to detect a list of platforms
that require special handlings.

Move the platform check in acpi_blacklisted() to a new common
utility function, acpi_match_platform_list(), so that other
drivers do not have to implement their own version.

There is no change in functionality.

Signed-off-by: Toshi Kani <toshi.kani@hpe.com>
Reviewed-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/blacklist.c
drivers/acpi/utils.c
include/linux/acpi.h

index bb542ac..037fd53 100644 (file)
 
 #include "internal.h"
 
-enum acpi_blacklist_predicates {
-       all_versions,
-       less_than_or_equal,
-       equal,
-       greater_than_or_equal,
-};
-
-struct acpi_blacklist_item {
-       char oem_id[7];
-       char oem_table_id[9];
-       u32 oem_revision;
-       char *table;
-       enum acpi_blacklist_predicates oem_revision_predicate;
-       char *reason;
-       u32 is_critical_error;
-};
-
 static struct dmi_system_id acpi_rev_dmi_table[] __initdata;
 
 /*
  * POLICY: If *anything* doesn't work, put it on the blacklist.
  *        If they are critical errors, mark it critical, and abort driver load.
  */
-static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
+static struct acpi_platform_list acpi_blacklist[] __initdata = {
        /* Compaq Presario 1700 */
        {"PTLTD ", "  DSDT  ", 0x06040000, ACPI_SIG_DSDT, less_than_or_equal,
         "Multiple problems", 1},
@@ -67,65 +50,27 @@ static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
        {"IBM   ", "TP600E  ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
         "Incorrect _ADR", 1},
 
-       {""}
+       { }
 };
 
 int __init acpi_blacklisted(void)
 {
-       int i = 0;
+       int i;
        int blacklisted = 0;
-       struct acpi_table_header table_header;
-
-       while (acpi_blacklist[i].oem_id[0] != '\0') {
-               if (acpi_get_table_header(acpi_blacklist[i].table, 0, &table_header)) {
-                       i++;
-                       continue;
-               }
-
-               if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) {
-                       i++;
-                       continue;
-               }
-
-               if (strncmp
-                   (acpi_blacklist[i].oem_table_id, table_header.oem_table_id,
-                    8)) {
-                       i++;
-                       continue;
-               }
-
-               if ((acpi_blacklist[i].oem_revision_predicate == all_versions)
-                   || (acpi_blacklist[i].oem_revision_predicate ==
-                       less_than_or_equal
-                       && table_header.oem_revision <=
-                       acpi_blacklist[i].oem_revision)
-                   || (acpi_blacklist[i].oem_revision_predicate ==
-                       greater_than_or_equal
-                       && table_header.oem_revision >=
-                       acpi_blacklist[i].oem_revision)
-                   || (acpi_blacklist[i].oem_revision_predicate == equal
-                       && table_header.oem_revision ==
-                       acpi_blacklist[i].oem_revision)) {
 
-                       printk(KERN_ERR PREFIX
-                              "Vendor \"%6.6s\" System \"%8.8s\" "
-                              "Revision 0x%x has a known ACPI BIOS problem.\n",
-                              acpi_blacklist[i].oem_id,
-                              acpi_blacklist[i].oem_table_id,
-                              acpi_blacklist[i].oem_revision);
+       i = acpi_match_platform_list(acpi_blacklist);
+       if (i >= 0) {
+               pr_err(PREFIX "Vendor \"%6.6s\" System \"%8.8s\" Revision 0x%x has a known ACPI BIOS problem.\n",
+                      acpi_blacklist[i].oem_id,
+                      acpi_blacklist[i].oem_table_id,
+                      acpi_blacklist[i].oem_revision);
 
-                       printk(KERN_ERR PREFIX
-                              "Reason: %s. This is a %s error\n",
-                              acpi_blacklist[i].reason,
-                              (acpi_blacklist[i].
-                               is_critical_error ? "non-recoverable" :
-                               "recoverable"));
+               pr_err(PREFIX "Reason: %s. This is a %s error\n",
+                      acpi_blacklist[i].reason,
+                      (acpi_blacklist[i].data ?
+                       "non-recoverable" : "recoverable"));
 
-                       blacklisted = acpi_blacklist[i].is_critical_error;
-                       break;
-               } else {
-                       i++;
-               }
+               blacklisted = acpi_blacklist[i].data;
        }
 
        (void)early_acpi_osi_init();
index b9d956c..0a9e597 100644 (file)
@@ -816,3 +816,39 @@ static int __init acpi_backlight(char *str)
        return 1;
 }
 __setup("acpi_backlight=", acpi_backlight);
+
+/**
+ * acpi_match_platform_list - Check if the system matches with a given list
+ * @plat: pointer to acpi_platform_list table terminated by a NULL entry
+ *
+ * Return the matched index if the system is found in the platform list.
+ * Otherwise, return a negative error code.
+ */
+int acpi_match_platform_list(const struct acpi_platform_list *plat)
+{
+       struct acpi_table_header hdr;
+       int idx = 0;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       for (; plat->oem_id[0]; plat++, idx++) {
+               if (ACPI_FAILURE(acpi_get_table_header(plat->table, 0, &hdr)))
+                       continue;
+
+               if (strncmp(plat->oem_id, hdr.oem_id, ACPI_OEM_ID_SIZE))
+                       continue;
+
+               if (strncmp(plat->oem_table_id, hdr.oem_table_id, ACPI_OEM_TABLE_ID_SIZE))
+                       continue;
+
+               if ((plat->pred == all_versions) ||
+                   (plat->pred == less_than_or_equal && hdr.oem_revision <= plat->oem_revision) ||
+                   (plat->pred == greater_than_or_equal && hdr.oem_revision >= plat->oem_revision) ||
+                   (plat->pred == equal && hdr.oem_revision == plat->oem_revision))
+                       return idx;
+       }
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL(acpi_match_platform_list);
index 27b4b66..1c8a97d 100644 (file)
@@ -556,6 +556,25 @@ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
 #define ACPI_OST_SC_DRIVER_LOAD_FAILURE                0x81
 #define ACPI_OST_SC_INSERT_NOT_SUPPORTED       0x82
 
+enum acpi_predicate {
+       all_versions,
+       less_than_or_equal,
+       equal,
+       greater_than_or_equal,
+};
+
+/* Table must be terminted by a NULL entry */
+struct acpi_platform_list {
+       char    oem_id[ACPI_OEM_ID_SIZE+1];
+       char    oem_table_id[ACPI_OEM_TABLE_ID_SIZE+1];
+       u32     oem_revision;
+       char    *table;
+       enum acpi_predicate pred;
+       char    *reason;
+       u32     data;
+};
+int acpi_match_platform_list(const struct acpi_platform_list *plat);
+
 extern void acpi_early_init(void);
 extern void acpi_subsystem_init(void);