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 @@
#define PREFIX "ACPI: "
extern int acpi_disabled;
/* --------------------------------------------------------------------------
Boot-time Configuration
......@@ -318,6 +319,14 @@ acpi_boot_init (
if (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
/*
......
......@@ -19,7 +19,7 @@ obj-y := acpi_ksyms.o
#
# ACPI Boot-Time Table Parsing
#
obj-$(CONFIG_ACPI_BOOT) += tables.o
obj-$(CONFIG_ACPI_BOOT) += tables.o blacklist.o
#
# ACPI Core Subsystem (Interpreter)
......
......@@ -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_reference (acpi_handle, acpi_string, acpi_object_list *, struct acpi_handle_list *);
#ifdef CONFIG_ACPI_BUS
#include <linux/proc_fs.h>
......@@ -116,26 +115,6 @@ struct acpi_driver {
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
* -----------
......
/*
* 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;
#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
......@@ -1838,59 +1807,6 @@ acpi_bus_scan_fixed (
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
acpi_bus_init_irq (void)
{
......@@ -1956,10 +1872,6 @@ acpi_bus_init (void)
goto error0;
}
if (acpi_blacklisted()) {
goto error1;
}
/*
* Get a separate copy of the FADT for use by other drivers.
*/
......
......@@ -46,7 +46,7 @@ static char *acpi_table_signatures[ACPI_TABLE_COUNT] = {
[ACPI_DSDT] = "DSDT",
[ACPI_ECDT] = "ECDT",
[ACPI_ETDT] = "ETDT",
[ACPI_FACP] = "FACP",
[ACPI_FADT] = "FACP",
[ACPI_FACS] = "FACS",
[ACPI_OEMX] = "OEM",
[ACPI_PSDT] = "PSDT",
......@@ -71,9 +71,6 @@ struct acpi_table_sdt {
static struct acpi_table_sdt sdt;
acpi_madt_entry_handler madt_handlers[ACPI_MADT_ENTRY_COUNT];
void
acpi_table_print (
struct acpi_table_header *header,
......@@ -92,7 +89,7 @@ acpi_table_print (
name = "MADT";
}
else if (!strncmp((char *) &header->signature,
acpi_table_signatures[ACPI_FACP],
acpi_table_signatures[ACPI_FADT],
sizeof(header->signature))) {
name = "FADT";
}
......@@ -222,6 +219,56 @@ acpi_table_compute_checksum (
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
acpi_table_parse_madt_family (
......@@ -460,7 +507,6 @@ acpi_table_init (
int result = 0;
memset(&sdt, 0, sizeof(struct acpi_table_sdt));
memset(&madt_handlers, 0, sizeof(madt_handlers));
/* Locate and map the Root System Description Table (RSDP) */
......
......@@ -106,6 +106,15 @@ struct acpi_table_xsdt {
u64 entry[1];
} __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) */
struct acpi_table_madt {
......@@ -314,7 +323,7 @@ enum acpi_table_id {
ACPI_DSDT,
ACPI_ECDT,
ACPI_ETDT,
ACPI_FACP,
ACPI_FADT,
ACPI_FACS,
ACPI_OEMX,
ACPI_PSDT,
......@@ -340,6 +349,7 @@ int acpi_numa_init (void);
int acpi_table_init (char *cmdline);
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_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);
......@@ -392,8 +402,8 @@ int acpi_pci_irq_init (void);
#ifdef CONFIG_ACPI
int acpi_init(void);
int acpi_blacklisted(void);
#endif /*CONFIG_ACPI*/
#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