diff options
Diffstat (limited to 'arch/ia64/kernel/acpi.c')
-rw-r--r-- | arch/ia64/kernel/acpi.c | 419 |
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 -} |