Commit 6b763b66 authored by Andy Grover's avatar Andy Grover

ACPI: Blacklist improvements

1) Split blacklist code out into a separate file.
2) Move checking the blacklist to very early. Previously, we would use ACPI
tables, and then halfway through init, check the blacklist -- too late.
Now, it's early enough to completely fall-back to non-ACPI.
3) Some FACP -> FADT cleanups, too.
parent 50ac9a5a
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#define PREFIX "ACPI: " #define PREFIX "ACPI: "
extern int acpi_disabled;
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
Boot-time Configuration Boot-time Configuration
...@@ -318,6 +319,14 @@ acpi_boot_init ( ...@@ -318,6 +319,14 @@ acpi_boot_init (
if (result) if (result)
return result; return result;
result = acpi_blacklisted();
if (result) {
acpi_disabled = 1;
return result;
}
else
printk(KERN_NOTICE PREFIX "BIOS passes blacklist\n");
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
/* /*
......
...@@ -19,7 +19,7 @@ obj-y := acpi_ksyms.o ...@@ -19,7 +19,7 @@ obj-y := acpi_ksyms.o
# #
# ACPI Boot-Time Table Parsing # ACPI Boot-Time Table Parsing
# #
obj-$(CONFIG_ACPI_BOOT) += tables.o obj-$(CONFIG_ACPI_BOOT) += tables.o blacklist.o
# #
# ACPI Core Subsystem (Interpreter) # ACPI Core Subsystem (Interpreter)
......
...@@ -49,7 +49,6 @@ acpi_status acpi_extract_package (acpi_object *, acpi_buffer *, acpi_buffer *); ...@@ -49,7 +49,6 @@ acpi_status acpi_extract_package (acpi_object *, acpi_buffer *, acpi_buffer *);
acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, acpi_object_list *, unsigned long *); acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, acpi_object_list *, unsigned long *);
acpi_status acpi_evaluate_reference (acpi_handle, acpi_string, acpi_object_list *, struct acpi_handle_list *); acpi_status acpi_evaluate_reference (acpi_handle, acpi_string, acpi_object_list *, struct acpi_handle_list *);
#ifdef CONFIG_ACPI_BUS #ifdef CONFIG_ACPI_BUS
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
...@@ -116,26 +115,6 @@ struct acpi_driver { ...@@ -116,26 +115,6 @@ struct acpi_driver {
struct acpi_device_ops ops; struct acpi_device_ops ops;
}; };
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;
acpi_table_type table;
enum acpi_blacklist_predicates oem_revision_predicate;
char *reason;
u32 is_critical_error;
};
/* /*
* ACPI Device * ACPI Device
* ----------- * -----------
......
/*
* blacklist.c
*
* Check to see if the given machine has a known bad ACPI BIOS
*
* Copyright (C) 2002 Andy Grover <andrew.grover@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include "acpi_bus.h"
#define PREFIX "ACPI: "
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;
acpi_table_type table;
enum acpi_blacklist_predicates oem_revision_predicate;
char *reason;
u32 is_critical_error;
};
/*
* 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 =
{
/* Portege 7020, BIOS 8.10 */
{"TOSHIB", "7020CT ", 0x19991112, ACPI_DSDT, all_versions, "Implicit Return", 0},
/* Portege 4030 */
{"TOSHIB", "4030 ", 0x19991112, ACPI_DSDT, all_versions, "Implicit Return", 0},
/* Portege 310/320, BIOS 7.1 */
{"TOSHIB", "310 ", 0x19990511, ACPI_DSDT, all_versions, "Implicit Return", 0},
/* Seattle 2, old bios rev. */
{"INTEL ", "440BX ", 0x00001000, ACPI_DSDT, less_than_or_equal, "Field beyond end of region", 0},
/* ASUS K7M */
{"ASUS ", "K7M ", 0x00001000, ACPI_DSDT, less_than_or_equal, "Field beyond end of region", 0},
/* Intel 810 Motherboard? */
{"MNTRAL", "MO81010A", 0x00000012, ACPI_DSDT, less_than_or_equal, "Field beyond end of region", 0},
/* Compaq Presario 711FR */
{"COMAPQ", "EAGLES", 0x06040000, ACPI_DSDT, less_than_or_equal, "SCI issues (C2 disabled)", 0},
/* Compaq Presario 1700 */
{"PTLTD ", " DSDT ", 0x06040000, ACPI_DSDT, less_than_or_equal, "Multiple problems", 1},
/* Sony FX120, FX140, FX150? */
{"SONY ", "U0 ", 0x20010313, ACPI_DSDT, less_than_or_equal, "ACPI driver problem", 1},
/* Compaq Presario 800, Insyde BIOS */
{"INT440", "SYSFexxx", 0x00001001, ACPI_DSDT, less_than_or_equal, "Does not use _REG to protect EC OpRegions", 1},
/* IBM 600E - _ADR should return 7, but it returns 1 */
{"IBM ", "TP600E ", 0x00000105, ACPI_DSDT, less_than_or_equal, "Incorrect _ADR", 1},
{""}
};
int __init
acpi_blacklisted(void)
{
int i = 0;
int blacklisted = 0;
struct acpi_table_header *table_header;
while (acpi_blacklist[i].oem_id[0] != '\0')
{
if (!acpi_get_table_header_early(acpi_blacklist[i].table, &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);
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"));
blacklisted = acpi_blacklist[i].is_critical_error;
break;
}
else {
i++;
}
}
return blacklisted;
}
...@@ -59,37 +59,6 @@ struct proc_dir_entry *acpi_root_dir; ...@@ -59,37 +59,6 @@ struct proc_dir_entry *acpi_root_dir;
#define STRUCT_TO_INT(s) (*((int*)&s)) #define STRUCT_TO_INT(s) (*((int*)&s))
/*
* 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 =
{
/* Portege 7020, BIOS 8.10 */
{"TOSHIB", "7020CT ", 0x19991112, ACPI_TABLE_DSDT, all_versions, "Implicit Return", 0},
/* Portege 4030 */
{"TOSHIB", "4030 ", 0x19991112, ACPI_TABLE_DSDT, all_versions, "Implicit Return", 0},
/* Portege 310/320, BIOS 7.1 */
{"TOSHIB", "310 ", 0x19990511, ACPI_TABLE_DSDT, all_versions, "Implicit Return", 0},
/* Seattle 2, old bios rev. */
{"INTEL ", "440BX ", 0x00001000, ACPI_TABLE_DSDT, less_than_or_equal, "Field beyond end of region", 0},
/* ASUS K7M */
{"ASUS ", "K7M ", 0x00001000, ACPI_TABLE_DSDT, less_than_or_equal, "Field beyond end of region", 0},
/* Intel 810 Motherboard? */
{"MNTRAL", "MO81010A", 0x00000012, ACPI_TABLE_DSDT, less_than_or_equal, "Field beyond end of region", 0},
/* Compaq Presario 711FR */
{"COMAPQ", "EAGLES", 0x06040000, ACPI_TABLE_DSDT, less_than_or_equal, "SCI issues (C2 disabled)", 0},
/* Compaq Presario 1700 */
{"PTLTD ", " DSDT ", 0x06040000, ACPI_TABLE_DSDT, less_than_or_equal, "Multiple problems", 1},
/* Sony FX120, FX140, FX150? */
{"SONY ", "U0 ", 0x20010313, ACPI_TABLE_DSDT, less_than_or_equal, "ACPI driver problem", 1},
/* Compaq Presario 800, Insyde BIOS */
{"INT440", "SYSFexxx", 0x00001001, ACPI_TABLE_DSDT, less_than_or_equal, "Does not use _REG to protect EC OpRegions", 1},
/* IBM 600E - _ADR should return 7, but it returns 1 */
{"IBM ", "TP600E ", 0x00000105, ACPI_TABLE_DSDT, less_than_or_equal, "Incorrect _ADR", 1},
{""}
};
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
Linux Driver Model (LDM) Support Linux Driver Model (LDM) Support
...@@ -1838,59 +1807,6 @@ acpi_bus_scan_fixed ( ...@@ -1838,59 +1807,6 @@ acpi_bus_scan_fixed (
Initialization/Cleanup Initialization/Cleanup
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
int __init
acpi_blacklisted(void)
{
int i = 0;
int blacklisted = 0;
acpi_table_header table_header;
while (acpi_blacklist[i].oem_id[0] != '\0')
{
if (!ACPI_SUCCESS(acpi_get_table_header(acpi_blacklist[i].table, 1, &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);
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"));
blacklisted = acpi_blacklist[i].is_critical_error;
break;
}
else {
i++;
}
}
return blacklisted;
}
static int __init static int __init
acpi_bus_init_irq (void) acpi_bus_init_irq (void)
{ {
...@@ -1956,10 +1872,6 @@ acpi_bus_init (void) ...@@ -1956,10 +1872,6 @@ acpi_bus_init (void)
goto error0; goto error0;
} }
if (acpi_blacklisted()) {
goto error1;
}
/* /*
* Get a separate copy of the FADT for use by other drivers. * Get a separate copy of the FADT for use by other drivers.
*/ */
......
...@@ -46,7 +46,7 @@ static char *acpi_table_signatures[ACPI_TABLE_COUNT] = { ...@@ -46,7 +46,7 @@ static char *acpi_table_signatures[ACPI_TABLE_COUNT] = {
[ACPI_DSDT] = "DSDT", [ACPI_DSDT] = "DSDT",
[ACPI_ECDT] = "ECDT", [ACPI_ECDT] = "ECDT",
[ACPI_ETDT] = "ETDT", [ACPI_ETDT] = "ETDT",
[ACPI_FACP] = "FACP", [ACPI_FADT] = "FACP",
[ACPI_FACS] = "FACS", [ACPI_FACS] = "FACS",
[ACPI_OEMX] = "OEM", [ACPI_OEMX] = "OEM",
[ACPI_PSDT] = "PSDT", [ACPI_PSDT] = "PSDT",
...@@ -71,9 +71,6 @@ struct acpi_table_sdt { ...@@ -71,9 +71,6 @@ struct acpi_table_sdt {
static struct acpi_table_sdt sdt; static struct acpi_table_sdt sdt;
acpi_madt_entry_handler madt_handlers[ACPI_MADT_ENTRY_COUNT];
void void
acpi_table_print ( acpi_table_print (
struct acpi_table_header *header, struct acpi_table_header *header,
...@@ -92,7 +89,7 @@ acpi_table_print ( ...@@ -92,7 +89,7 @@ acpi_table_print (
name = "MADT"; name = "MADT";
} }
else if (!strncmp((char *) &header->signature, else if (!strncmp((char *) &header->signature,
acpi_table_signatures[ACPI_FACP], acpi_table_signatures[ACPI_FADT],
sizeof(header->signature))) { sizeof(header->signature))) {
name = "FADT"; name = "FADT";
} }
...@@ -222,6 +219,56 @@ acpi_table_compute_checksum ( ...@@ -222,6 +219,56 @@ acpi_table_compute_checksum (
return (sum & 0xFF); return (sum & 0xFF);
} }
int __init
acpi_get_table_header_early (
enum acpi_table_id id,
struct acpi_table_header **header)
{
int i;
enum acpi_table_id temp_id;
/* DSDT is different from the rest */
if (id == ACPI_DSDT)
temp_id = ACPI_FADT;
else
temp_id = id;
/* Locate the table. */
for (i = 0; i < sdt.count; i++) {
if (sdt.entry[i].id != temp_id)
continue;
*header = (void *)
__acpi_map_table(sdt.entry[i].pa, sdt.entry[i].size);
if (!*header) {
printk(KERN_WARNING PREFIX "Unable to map %s\n",
acpi_table_signatures[temp_id]);
return -ENODEV;
}
break;
}
if (!*header) {
printk(KERN_WARNING PREFIX "%s not present\n",
acpi_table_signatures[id]);
return -ENODEV;
}
/* Map the DSDT header via the pointer in the FADT */
if (id == ACPI_DSDT) {
struct acpi_table_fadt *fadt = (struct acpi_table_fadt *) *header;
*header = (void *) __acpi_map_table(fadt->dsdt_addr,
sizeof(struct acpi_table_header));
if (!*header) {
printk(KERN_WARNING PREFIX "Unable to map DSDT\n");
return -ENODEV;
}
}
return 0;
}
int __init int __init
acpi_table_parse_madt_family ( acpi_table_parse_madt_family (
...@@ -460,7 +507,6 @@ acpi_table_init ( ...@@ -460,7 +507,6 @@ acpi_table_init (
int result = 0; int result = 0;
memset(&sdt, 0, sizeof(struct acpi_table_sdt)); memset(&sdt, 0, sizeof(struct acpi_table_sdt));
memset(&madt_handlers, 0, sizeof(madt_handlers));
/* Locate and map the Root System Description Table (RSDP) */ /* Locate and map the Root System Description Table (RSDP) */
......
...@@ -106,6 +106,15 @@ struct acpi_table_xsdt { ...@@ -106,6 +106,15 @@ struct acpi_table_xsdt {
u64 entry[1]; u64 entry[1];
} __attribute__ ((packed)); } __attribute__ ((packed));
/* Fixed ACPI Description Table (FADT) */
struct acpi_table_fadt {
struct acpi_table_header header;
u32 facs_addr;
u32 dsdt_addr;
/* ... */
} __attribute__ ((packed));
/* Multiple APIC Description Table (MADT) */ /* Multiple APIC Description Table (MADT) */
struct acpi_table_madt { struct acpi_table_madt {
...@@ -314,7 +323,7 @@ enum acpi_table_id { ...@@ -314,7 +323,7 @@ enum acpi_table_id {
ACPI_DSDT, ACPI_DSDT,
ACPI_ECDT, ACPI_ECDT,
ACPI_ETDT, ACPI_ETDT,
ACPI_FACP, ACPI_FADT,
ACPI_FACS, ACPI_FACS,
ACPI_OEMX, ACPI_OEMX,
ACPI_PSDT, ACPI_PSDT,
...@@ -340,6 +349,7 @@ int acpi_numa_init (void); ...@@ -340,6 +349,7 @@ int acpi_numa_init (void);
int acpi_table_init (char *cmdline); int acpi_table_init (char *cmdline);
int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler); int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler);
int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header);
int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler); int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler);
int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler); int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler);
void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr); void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr);
...@@ -392,8 +402,8 @@ int acpi_pci_irq_init (void); ...@@ -392,8 +402,8 @@ int acpi_pci_irq_init (void);
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
int acpi_init(void); int acpi_init(void);
int acpi_blacklisted(void);
#endif /*CONFIG_ACPI*/ #endif /*CONFIG_ACPI*/
#endif /*_LINUX_ACPI_H*/ #endif /*_LINUX_ACPI_H*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment