summaryrefslogtreecommitdiffstats
path: root/arch/ia64/kernel/acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/kernel/acpi.c')
-rw-r--r--arch/ia64/kernel/acpi.c419
1 files changed, 298 insertions, 121 deletions
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index a8c1ead1f..35ed564c9 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -6,6 +6,12 @@
*
* Copyright (C) 1999 VA Linux Systems
* Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
+ * Copyright (C) 2000 Hewlett-Packard Co.
+ * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2000 Intel Corp.
+ * Copyright (C) 2000 J.I. Lee <jung-ik.lee@intel.com>
+ * ACPI based kernel configuration manager.
+ * ACPI 2.0 & IA64 ext 0.71
*/
#include <linux/config.h>
@@ -36,29 +42,87 @@ int __initdata total_cpus;
void (*pm_idle)(void);
+asm (".weak iosapic_register_legacy_irq");
+asm (".weak iosapic_init");
+
+const char *
+acpi_get_sysname (void)
+{
+ /* the following should go away once we have an ACPI parser: */
+#ifdef CONFIG_IA64_GENERIC
+ return "hpsim";
+#else
+# if defined (CONFIG_IA64_HP_SIM)
+ return "hpsim";
+# elif defined (CONFIG_IA64_SGI_SN1)
+ return "sn1";
+# elif defined (CONFIG_IA64_DIG)
+ return "dig";
+# else
+# error Unknown platform. Fix acpi.c.
+# endif
+#endif
+
+}
+
/*
- * Identify usable CPU's and remember them for SMP bringup later.
+ * Configure legacy IRQ information.
*/
static void __init
-acpi_lsapic(char *p)
+acpi_legacy_irq (char *p)
{
- int add = 1;
-
- acpi_entry_lsapic_t *lsapic = (acpi_entry_lsapic_t *) p;
+ acpi_entry_int_override_t *legacy = (acpi_entry_int_override_t *) p;
+ unsigned long polarity = 0, edge_triggered = 0;
- if ((lsapic->flags & LSAPIC_PRESENT) == 0)
+ /*
+ * If the platform we're running doesn't define
+ * iosapic_register_legacy_irq(), we ignore this info...
+ */
+ if (!iosapic_register_legacy_irq)
return;
+ switch (legacy->flags) {
+ case 0x5: polarity = 1; edge_triggered = 1; break;
+ case 0x7: polarity = 0; edge_triggered = 1; break;
+ case 0xd: polarity = 1; edge_triggered = 0; break;
+ case 0xf: polarity = 0; edge_triggered = 0; break;
+ default:
+ printk(" ACPI Legacy IRQ 0x%02x: Unknown flags 0x%x\n", legacy->isa_irq,
+ legacy->flags);
+ break;
+ }
+ iosapic_register_legacy_irq(legacy->isa_irq, legacy->pin, polarity, edge_triggered);
+}
+
+/*
+ * ACPI 2.0 tables parsing functions
+ */
+
+static unsigned long
+readl_unaligned(void *p)
+{
+ unsigned long ret;
+
+ memcpy(&ret, p, sizeof(long));
+ return ret;
+}
+
+/*
+ * Identify usable CPU's and remember them for SMP bringup later.
+ */
+static void __init
+acpi20_lsapic (char *p)
+{
+ int add = 1;
+
+ acpi20_entry_lsapic_t *lsapic = (acpi20_entry_lsapic_t *) p;
printk(" CPU %d (%.04x:%.04x): ", total_cpus, lsapic->eid, lsapic->id);
if ((lsapic->flags & LSAPIC_ENABLED) == 0) {
printk("Disabled.\n");
add = 0;
- } else if (lsapic->flags & LSAPIC_PERFORMANCE_RESTRICTED) {
- printk("Performance Restricted; ignoring.\n");
- add = 0;
}
-
+
#ifdef CONFIG_SMP
smp_boot_data.cpu_phys_id[total_cpus] = -1;
#endif
@@ -73,87 +137,234 @@ acpi_lsapic(char *p)
}
/*
- * Configure legacy IRQ information in iosapic_vector
+ * Info on platform interrupt sources: NMI. PMI, INIT, etc.
*/
static void __init
-acpi_legacy_irq(char *p)
+acpi20_platform (char *p)
{
- /*
- * This is not good. ACPI is not necessarily limited to CONFIG_IA64_DIG, yet
- * ACPI does not necessarily imply IOSAPIC either. Perhaps there should be
- * a means for platform_setup() to register ACPI handlers?
- */
-#ifdef CONFIG_IA64_IRQ_ACPI
- acpi_entry_int_override_t *legacy = (acpi_entry_int_override_t *) p;
- unsigned char vector;
- int i;
+ acpi20_entry_platform_src_t *plat = (acpi20_entry_platform_src_t *) p;
+
+ printk("PLATFORM: IOSAPIC %x -> Vector %x on CPU %.04u:%.04u\n",
+ plat->iosapic_vector, plat->global_vector, plat->eid, plat->id);
+}
- vector = isa_irq_to_vector(legacy->isa_irq);
+/*
+ * Override the physical address of the local APIC in the MADT stable header.
+ */
+static void __init
+acpi20_lapic_addr_override (char *p)
+{
+ acpi20_entry_lapic_addr_override_t * lapic = (acpi20_entry_lapic_addr_override_t *) p;
+
+ if (lapic->lapic_address) {
+ iounmap((void *)ipi_base_addr);
+ ipi_base_addr = (unsigned long) ioremap(lapic->lapic_address, 0);
+
+ printk("LOCAL ACPI override to 0x%lx(p=0x%lx)\n",
+ ipi_base_addr, lapic->lapic_address);
+ }
+}
+
+/*
+ * Parse the ACPI Multiple APIC Description Table
+ */
+static void __init
+acpi20_parse_madt (acpi_madt_t *madt)
+{
+ acpi_entry_iosapic_t *iosapic;
+ char *p, *end;
+
+ /* Base address of IPI Message Block */
+ if (madt->lapic_address) {
+ ipi_base_addr = (unsigned long) ioremap(madt->lapic_address, 0);
+ printk("Lapic address set to 0x%lx\n", ipi_base_addr);
+ } else
+ printk("Lapic address set to default 0x%lx\n", ipi_base_addr);
+
+ p = (char *) (madt + 1);
+ end = p + (madt->header.length - sizeof(acpi_madt_t));
/*
- * Clobber any old pin mapping. It may be that it gets replaced later on
+ * Splitted entry parsing to ensure ordering.
*/
- for (i = 0; i < IA64_MAX_VECTORED_IRQ; i++) {
- if (i == vector)
- continue;
- if (iosapic_pin(i) == iosapic_pin(vector))
- iosapic_pin(i) = 0xff;
- }
- iosapic_pin(vector) = legacy->pin;
- iosapic_bus(vector) = BUS_ISA; /* This table only overrides the ISA devices */
- iosapic_busdata(vector) = 0;
-
- /*
- * External timer tick is special...
- */
- if (vector != TIMER_IRQ)
- iosapic_dmode(vector) = IO_SAPIC_LOWEST_PRIORITY;
- else
- iosapic_dmode(vector) = IO_SAPIC_FIXED;
+ while (p < end) {
+ switch (*p) {
+ case ACPI20_ENTRY_LOCAL_APIC_ADDR_OVERRIDE:
+ printk("ACPI 2.0 MADT: LOCAL APIC Override\n");
+ acpi20_lapic_addr_override(p);
+ break;
+
+ case ACPI20_ENTRY_LOCAL_SAPIC:
+ printk("ACPI 2.0 MADT: LOCAL SAPIC\n");
+ acpi20_lsapic(p);
+ break;
- /* See MPS 1.4 section 4.3.4 */
- switch (legacy->flags) {
- case 0x5:
- iosapic_polarity(vector) = IO_SAPIC_POL_HIGH;
- iosapic_trigger(vector) = IO_SAPIC_EDGE;
- break;
- case 0x8:
- iosapic_polarity(vector) = IO_SAPIC_POL_LOW;
- iosapic_trigger(vector) = IO_SAPIC_EDGE;
- break;
- case 0xd:
- iosapic_polarity(vector) = IO_SAPIC_POL_HIGH;
- iosapic_trigger(vector) = IO_SAPIC_LEVEL;
- break;
- case 0xf:
- iosapic_polarity(vector) = IO_SAPIC_POL_LOW;
- iosapic_trigger(vector) = IO_SAPIC_LEVEL;
- break;
- default:
- printk(" ACPI Legacy IRQ 0x%02x: Unknown flags 0x%x\n", legacy->isa_irq,
- legacy->flags);
- break;
+ case ACPI20_ENTRY_IO_SAPIC:
+ iosapic = (acpi_entry_iosapic_t *) p;
+ if (iosapic_init)
+ iosapic_init(iosapic->address, iosapic->irq_base);
+ break;
+
+ case ACPI20_ENTRY_PLATFORM_INT_SOURCE:
+ printk("ACPI 2.0 MADT: PLATFORM INT SOUCE\n");
+ acpi20_platform(p);
+ break;
+
+ case ACPI20_ENTRY_LOCAL_APIC:
+ printk("ACPI 2.0 MADT: LOCAL APIC entry\n"); break;
+ case ACPI20_ENTRY_IO_APIC:
+ printk("ACPI 2.0 MADT: IO APIC entry\n"); break;
+ case ACPI20_ENTRY_NMI_SOURCE:
+ printk("ACPI 2.0 MADT: NMI SOURCE entry\n"); break;
+ case ACPI20_ENTRY_LOCAL_APIC_NMI:
+ printk("ACPI 2.0 MADT: LOCAL APIC NMI entry\n"); break;
+ case ACPI20_ENTRY_INT_SRC_OVERRIDE:
+ break;
+ default:
+ printk("ACPI 2.0 MADT: unknown entry skip\n"); break;
+ break;
+ }
+
+ p += p[1];
+ }
+
+ p = (char *) (madt + 1);
+ end = p + (madt->header.length - sizeof(acpi_madt_t));
+
+ while (p < end) {
+
+ switch (*p) {
+ case ACPI20_ENTRY_INT_SRC_OVERRIDE:
+ printk("ACPI 2.0 MADT: INT SOURCE Override\n");
+ acpi_legacy_irq(p);
+ break;
+ default:
+ break;
+ }
+
+ p += p[1];
+ }
+
+ /* Make bootup pretty */
+ printk(" %d CPUs available, %d CPUs total\n",
+ available_cpus, total_cpus);
+}
+
+int __init
+acpi20_parse (acpi20_rsdp_t *rsdp20)
+{
+ acpi_xsdt_t *xsdt;
+ acpi_desc_table_hdr_t *hdrp;
+ int tables, i;
+
+ if (strncmp(rsdp20->signature, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN)) {
+ printk("ACPI 2.0 RSDP signature incorrect!\n");
+ return 0;
+ } else {
+ printk("ACPI 2.0 Root System Description Ptr at 0x%lx\n",
+ (unsigned long)rsdp20);
+ }
+
+ xsdt = __va(rsdp20->xsdt);
+ hdrp = &xsdt->header;
+ if (strncmp(hdrp->signature,
+ ACPI_XSDT_SIG, ACPI_XSDT_SIG_LEN)) {
+ printk("ACPI 2.0 XSDT signature incorrect. Trying RSDT\n");
+ /* RSDT parsing here */
+ return 0;
+ } else {
+ printk("ACPI 2.0 XSDT at 0x%lx (p=0x%lx)\n",
+ (unsigned long)xsdt, (unsigned long)rsdp20->xsdt);
+ }
+
+ printk("ACPI 2.0: %.6s %.8s %d.%d\n",
+ hdrp->oem_id,
+ hdrp->oem_table_id,
+ hdrp->oem_revision >> 16,
+ hdrp->oem_revision & 0xffff);
+
+#ifdef CONFIG_ACPI_KERNEL_CONFIG
+ acpi_cf_init((void *)rsdp20);
+#endif
+
+ tables =(hdrp->length -sizeof(acpi_desc_table_hdr_t))>>3;
+
+ for (i = 0; i < tables; i++) {
+ hdrp = (acpi_desc_table_hdr_t *) __va(readl_unaligned(&xsdt->entry_ptrs[i]));
+ printk(" :table %4.4s found\n", hdrp->signature);
+
+ /* Only interested int the MADT table for now ... */
+ if (strncmp(hdrp->signature,
+ ACPI_MADT_SIG, ACPI_MADT_SIG_LEN) != 0)
+ continue;
+
+ acpi20_parse_madt((acpi_madt_t *) hdrp);
+ }
+
+#ifdef CONFIG_ACPI_KERNEL_CONFIG
+ acpi_cf_terminate();
+#endif
+
+#ifdef CONFIG_SMP
+ if (available_cpus == 0) {
+ printk("ACPI: Found 0 CPUS; assuming 1\n");
+ available_cpus = 1; /* We've got at least one of these, no? */
+ }
+ smp_boot_data.cpu_count = available_cpus;
+#endif
+ return 1;
+}
+/*
+ * ACPI 1.0b with 0.71 IA64 extensions functions; should be removed once all
+ * platforms start supporting ACPI 2.0
+ */
+
+/*
+ * Identify usable CPU's and remember them for SMP bringup later.
+ */
+static void __init
+acpi_lsapic (char *p)
+{
+ int add = 1;
+
+ acpi_entry_lsapic_t *lsapic = (acpi_entry_lsapic_t *) p;
+
+ if ((lsapic->flags & LSAPIC_PRESENT) == 0)
+ return;
+
+ printk(" CPU %d (%.04x:%.04x): ", total_cpus, lsapic->eid, lsapic->id);
+
+ if ((lsapic->flags & LSAPIC_ENABLED) == 0) {
+ printk("Disabled.\n");
+ add = 0;
+ } else if (lsapic->flags & LSAPIC_PERFORMANCE_RESTRICTED) {
+ printk("Performance Restricted; ignoring.\n");
+ add = 0;
}
-# ifdef ACPI_DEBUG
- printk("Legacy ISA IRQ %x -> IA64 Vector %x IOSAPIC Pin %x Active %s %s Trigger\n",
- legacy->isa_irq, vector, iosapic_pin(vector),
- ((iosapic_polarity(vector) == IO_SAPIC_POL_LOW) ? "Low" : "High"),
- ((iosapic_trigger(vector) == IO_SAPIC_LEVEL) ? "Level" : "Edge"));
-# endif /* ACPI_DEBUG */
-#endif /* CONFIG_IA64_IRQ_ACPI */
+#ifdef CONFIG_SMP
+ smp_boot_data.cpu_phys_id[total_cpus] = -1;
+#endif
+ if (add) {
+ printk("Available.\n");
+ available_cpus++;
+#ifdef CONFIG_SMP
+ smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid;
+#endif /* CONFIG_SMP */
+ }
+ total_cpus++;
}
/*
* Info on platform interrupt sources: NMI. PMI, INIT, etc.
*/
static void __init
-acpi_platform(char *p)
+acpi_platform (char *p)
{
acpi_entry_platform_src_t *plat = (acpi_entry_platform_src_t *) p;
- printk("PLATFORM: IOSAPIC %x -> Vector %lx on CPU %.04u:%.04u\n",
+ printk("PLATFORM: IOSAPIC %x -> Vector %x on CPU %.04u:%.04u\n",
plat->iosapic_vector, plat->global_vector, plat->eid, plat->id);
}
@@ -161,8 +372,9 @@ acpi_platform(char *p)
* Parse the ACPI Multiple SAPIC Table
*/
static void __init
-acpi_parse_msapic(acpi_sapic_t *msapic)
+acpi_parse_msapic (acpi_sapic_t *msapic)
{
+ acpi_entry_iosapic_t *iosapic;
char *p, *end;
/* Base address of IPI Message Block */
@@ -172,41 +384,31 @@ acpi_parse_msapic(acpi_sapic_t *msapic)
end = p + (msapic->header.length - sizeof(acpi_sapic_t));
while (p < end) {
-
switch (*p) {
- case ACPI_ENTRY_LOCAL_SAPIC:
+ case ACPI_ENTRY_LOCAL_SAPIC:
acpi_lsapic(p);
break;
- case ACPI_ENTRY_IO_SAPIC:
- platform_register_iosapic((acpi_entry_iosapic_t *) p);
+ case ACPI_ENTRY_IO_SAPIC:
+ iosapic = (acpi_entry_iosapic_t *) p;
+ if (iosapic_init)
+ iosapic_init(iosapic->address, iosapic->irq_base);
break;
- case ACPI_ENTRY_INT_SRC_OVERRIDE:
+ case ACPI_ENTRY_INT_SRC_OVERRIDE:
acpi_legacy_irq(p);
break;
-
- case ACPI_ENTRY_PLATFORM_INT_SOURCE:
+
+ case ACPI_ENTRY_PLATFORM_INT_SOURCE:
acpi_platform(p);
break;
-
- default:
+
+ default:
break;
}
/* Move to next table entry. */
-#define BAD_ACPI_TABLE
-#ifdef BAD_ACPI_TABLE
- /*
- * Some prototype Lion's have a bad ACPI table
- * requiring this fix. Without this fix, those
- * machines crash during bootup.
- */
- if (p[1] == 0)
- p = end;
- else
-#endif
- p += p[1];
+ p += p[1];
}
/* Make bootup pretty */
@@ -214,24 +416,18 @@ acpi_parse_msapic(acpi_sapic_t *msapic)
}
int __init
-acpi_parse(acpi_rsdp_t *rsdp)
+acpi_parse (acpi_rsdp_t *rsdp)
{
acpi_rsdt_t *rsdt;
acpi_desc_table_hdr_t *hdrp;
long tables, i;
- if (!rsdp) {
- printk("Uh-oh, no ACPI Root System Description Pointer table!\n");
- return 0;
- }
-
if (strncmp(rsdp->signature, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN)) {
printk("Uh-oh, ACPI RSDP signature incorrect!\n");
return 0;
}
- rsdp->rsdt = __va(rsdp->rsdt);
- rsdt = rsdp->rsdt;
+ rsdt = __va(rsdp->rsdt);
if (strncmp(rsdt->header.signature, ACPI_RSDT_SIG, ACPI_RSDT_SIG_LEN)) {
printk("Uh-oh, ACPI RDST signature incorrect!\n");
return 0;
@@ -256,7 +452,7 @@ acpi_parse(acpi_rsdp_t *rsdp)
}
#ifdef CONFIG_ACPI_KERNEL_CONFIG
- acpi_cf_terminate();
+ acpi_cf_terminate();
#endif
#ifdef CONFIG_SMP
@@ -268,22 +464,3 @@ acpi_parse(acpi_rsdp_t *rsdp)
#endif
return 1;
}
-
-const char *
-acpi_get_sysname (void)
-{
- /* the following should go away once we have an ACPI parser: */
-#ifdef CONFIG_IA64_GENERIC
- return "hpsim";
-#else
-# if defined (CONFIG_IA64_HP_SIM)
- return "hpsim";
-# elif defined (CONFIG_IA64_SGI_SN1)
- return "sn1";
-# elif defined (CONFIG_IA64_DIG)
- return "dig";
-# else
-# error Unknown platform. Fix acpi.c.
-# endif
-#endif
-}