summaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/acpi.c')
-rw-r--r--arch/i386/kernel/acpi.c98
1 files changed, 80 insertions, 18 deletions
diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c
index e63a45e66..d9dabac2f 100644
--- a/arch/i386/kernel/acpi.c
+++ b/arch/i386/kernel/acpi.c
@@ -144,14 +144,21 @@ static unsigned long acpi_opts = ACPI_ENABLED;
struct acpi_errata_info
{
- const char *oem;
- const char *oem_table;
- u32 oem_rev;
- unsigned long options;
+ const char *signature; // table signature (eg. "RSDT")
+ const char *oem; // OEM name
+ const char *oem_table; // OEM table identifier (optional)
+ u32 oem_rev; // OEM table revision (optional)
+ unsigned long options; // errata options
};
+/*
+ * We must identify systems that need ACPI_TRUST_TABLES solely from the
+ * RSDP ("RSD PTR "). All other options should be flagged from the
+ * RSDT ("RSDT") which can be better identified.
+ */
struct acpi_errata_info acpi_errata[] =
{
+ {"RSD PTR ", "AMI ", NULL, 0, ACPI_TRUST_TABLES | ACPI_COPY_TABLES},
{NULL, NULL, 0, 0},
};
@@ -521,6 +528,51 @@ static void acpi_destroy_table(struct acpi_table_info *info)
}
/*
+ * Match ACPI table and set options based on platform errata, if any
+ */
+static int __init acpi_find_errata(struct acpi_table *table)
+{
+ struct acpi_errata_info *info;
+ int size;
+
+ for (info = acpi_errata; info->signature && info->oem; info++) {
+ size = strlen(info->signature);
+ if (memcmp(&table->signature, info->signature, size))
+ continue;
+ if (strcmp(info->signature, "RSD PTR ")) {
+ // ordinary ACPI table
+ size = strlen(info->oem);
+ if (memcmp(table->oem, info->oem, size))
+ continue;
+ if (info->oem_table) {
+ size = strlen(info->oem_table);
+ if (memcmp(table->oem_table,
+ info->oem_table,
+ size))
+ continue;
+ }
+ if (info->oem_rev && table->oem_rev != info->oem_rev)
+ continue;
+ }
+ else {
+ // special handling for RSDP
+ size = strlen(info->oem);
+ if (memcmp(((struct acpi_rsdp*) table)->oem,
+ info->oem,
+ size))
+ continue;
+ }
+
+ printk(KERN_INFO
+ "ACPI: found platform errata 0x%08lx\n",
+ info->options);
+ acpi_opts |= info->options;
+ return 0;
+ }
+ return -1;
+}
+
+/*
* Locate and map ACPI tables
*/
static int __init acpi_find_tables(void)
@@ -556,6 +608,14 @@ static int __init acpi_find_tables(void)
if (i >= ACPI_BIOS_ROM_END)
return -ENODEV;
+ // find any errata based on the RSDP
+ if (!acpi_find_errata((struct acpi_table*) rsdp)) {
+ if (acpi_opts & ACPI_DISABLED)
+ return -EINVAL;
+ else if (acpi_opts & ACPI_CHIPSET_ONLY)
+ return -ENODEV;
+ }
+
// fetch RSDT from RSDP
rsdt = acpi_map_table(rsdp->rsdt);
if (!rsdt) {
@@ -569,6 +629,15 @@ static int __init acpi_find_tables(void)
acpi_unmap_table(rsdt);
return -EINVAL;
}
+
+ // find any errata based on the RSDT
+ if (!acpi_find_errata(rsdt)) {
+ if (acpi_opts & ACPI_DISABLED)
+ return -EINVAL;
+ else if (acpi_opts & ACPI_CHIPSET_ONLY)
+ return -ENODEV;
+ }
+
// search RSDT for FACP
acpi_facp.table = NULL;
rsdt_entry = (u32 *) (rsdt + 1);
@@ -631,11 +700,7 @@ static int __init acpi_init_piix4(struct pci_dev *dev)
if (!(pmregmisc & ACPI_PIIX4_PMIOSE))
return -ENODEV;
- pci_read_config_dword(dev, 0x40, &base);
- if (!(base & PCI_BASE_ADDRESS_SPACE_IO))
- return -ENODEV;
-
- base &= PCI_BASE_ADDRESS_IO_MASK;
+ base = dev->resource[PCI_BRIDGE_RESOURCES].start & PCI_BASE_ADDRESS_IO_MASK;
if (!base)
return -ENODEV;
@@ -688,16 +753,13 @@ static int __init acpi_init_via(struct pci_dev *dev)
if (!(tmp & 0x80))
return -ENODEV;
- pci_read_config_byte(dev, PCI_CLASS_REVISION, &tmp);
- tmp = (tmp & 0x10 ? 0x48 : 0x20);
-
- pci_read_config_dword(dev, tmp, &base);
- if (!(base & PCI_BASE_ADDRESS_SPACE_IO))
- return -ENODEV;
-
+ base = pci_resource_start(dev, PCI_BRIDGE_RESOURCES);
+ if (!base) {
+ base = pci_resource_start(dev, PCI_BASE_ADDRESS_4);
+ if (!base)
+ return -ENODEV;
+ }
base &= PCI_BASE_ADDRESS_IO_MASK;
- if (!base)
- return -ENODEV;
pci_read_config_byte(dev, 0x42, &irq);