patch-2.4.15 linux/arch/ia64/kernel/acpi.c
Next file: linux/arch/ia64/kernel/efi.c
Previous file: linux/arch/ia64/kernel/Makefile
Back to the patch index
Back to the overall index
- Lines: 377
- Date:
Fri Nov 9 14:26:17 2001
- Orig file:
v2.4.14/linux/arch/ia64/kernel/acpi.c
- Orig date:
Sun Aug 12 13:27:58 2001
diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/acpi.c linux/arch/ia64/kernel/acpi.c
@@ -9,7 +9,7 @@
* 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>
+ * Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com>
* ACPI based kernel configuration manager.
* ACPI 2.0 & IA64 ext 0.71
*/
@@ -23,6 +23,9 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/irq.h>
+#ifdef CONFIG_SERIAL_ACPI
+#include <linux/acpi_serial.h>
+#endif
#include <asm/acpi-ext.h>
#include <asm/acpikcfg.h>
@@ -34,6 +37,9 @@
#undef ACPI_DEBUG /* Guess what this does? */
+/* global array to record platform interrupt vectors for generic int routing */
+int platform_irq_list[ACPI_MAX_PLATFORM_IRQS];
+
/* These are ugly but will be reclaimed by the kernel */
int __initdata available_cpus;
int __initdata total_cpus;
@@ -41,8 +47,11 @@
void (*pm_idle) (void);
void (*pm_power_off) (void);
+asm (".weak iosapic_register_irq");
asm (".weak iosapic_register_legacy_irq");
+asm (".weak iosapic_register_platform_irq");
asm (".weak iosapic_init");
+asm (".weak iosapic_version");
const char *
acpi_get_sysname (void)
@@ -55,6 +64,8 @@
return "hpsim";
# elif defined (CONFIG_IA64_SGI_SN1)
return "sn1";
+# elif defined (CONFIG_IA64_SGI_SN2)
+ return "sn2";
# elif defined (CONFIG_IA64_DIG)
return "dig";
# else
@@ -65,6 +76,25 @@
}
/*
+ * Interrupt routing API for device drivers.
+ * Provides the interrupt vector for a generic platform event
+ * (currently only CPEI implemented)
+ */
+int
+acpi_request_vector(u32 int_type)
+{
+ int vector = -1;
+
+ if (int_type < ACPI_MAX_PLATFORM_IRQS) {
+ /* correctable platform error interrupt */
+ vector = platform_irq_list[int_type];
+ } else
+ printk("acpi_request_vector(): invalid interrupt type\n");
+
+ return vector;
+}
+
+/*
* Configure legacy IRQ information.
*/
static void __init
@@ -139,15 +169,93 @@
}
/*
- * Info on platform interrupt sources: NMI. PMI, INIT, etc.
+ * Extract iosapic info from madt (again) to determine which iosapic
+ * this platform interrupt resides in
+ */
+static int __init
+acpi20_which_iosapic (int global_vector, acpi_madt_t *madt, u32 *irq_base, char **iosapic_address)
+{
+ acpi_entry_iosapic_t *iosapic;
+ char *p, *end;
+ int ver, max_pin;
+
+ p = (char *) (madt + 1);
+ end = p + (madt->header.length - sizeof(acpi_madt_t));
+
+ while (p < end) {
+ switch (*p) {
+ case ACPI20_ENTRY_IO_SAPIC:
+ /* collect IOSAPIC info for platform int use later */
+ iosapic = (acpi_entry_iosapic_t *)p;
+ *irq_base = iosapic->irq_base;
+ *iosapic_address = ioremap(iosapic->address, 0);
+ /* is this the iosapic we're looking for? */
+ ver = iosapic_version(*iosapic_address);
+ max_pin = (ver >> 16) & 0xff;
+ if ((global_vector - *irq_base) <= max_pin)
+ return 0; /* found it! */
+ break;
+ default:
+ break;
+ }
+ p += p[1];
+ }
+ return 1;
+}
+
+/*
+ * Info on platform interrupt sources: NMI, PMI, INIT, etc.
*/
static void __init
-acpi20_platform (char *p)
+acpi20_platform (char *p, acpi_madt_t *madt)
{
+ int vector;
+ u32 irq_base;
+ char *iosapic_address;
+ unsigned long polarity = 0, trigger = 0;
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);
+
+ /* record platform interrupt vectors for generic int routing code */
+
+ if (!iosapic_register_platform_irq) {
+ printk("acpi20_platform(): no ACPI platform IRQ support\n");
+ return;
+ }
+
+ /* extract polarity and trigger info from flags */
+ switch (plat->flags) {
+ case 0x5: polarity = 1; trigger = 1; break;
+ case 0x7: polarity = 0; trigger = 1; break;
+ case 0xd: polarity = 1; trigger = 0; break;
+ case 0xf: polarity = 0; trigger = 0; break;
+ default:
+ printk("acpi20_platform(): unknown flags 0x%x\n", plat->flags);
+ break;
+ }
+
+ /* which iosapic does this IRQ belong to? */
+ if (acpi20_which_iosapic(plat->global_vector, madt, &irq_base, &iosapic_address)) {
+ printk("acpi20_platform(): I/O SAPIC not found!\n");
+ return;
+ }
+
+ /*
+ * get vector assignment for this IRQ, set attributes, and program the IOSAPIC
+ * routing table
+ */
+ vector = iosapic_register_platform_irq(plat->int_type,
+ plat->global_vector,
+ plat->iosapic_vector,
+ plat->eid,
+ plat->id,
+ polarity,
+ trigger,
+ irq_base,
+ iosapic_address);
+ platform_irq_list[plat->int_type] = vector;
}
/*
@@ -173,8 +281,10 @@
static void __init
acpi20_parse_madt (acpi_madt_t *madt)
{
- acpi_entry_iosapic_t *iosapic;
+ acpi_entry_iosapic_t *iosapic = NULL;
+ acpi20_entry_lsapic_t *lsapic = NULL;
char *p, *end;
+ int i;
/* Base address of IPI Message Block */
if (madt->lapic_address) {
@@ -186,23 +296,27 @@
p = (char *) (madt + 1);
end = p + (madt->header.length - sizeof(acpi_madt_t));
+ /* Initialize platform interrupt vector array */
+ for (i = 0; i < ACPI_MAX_PLATFORM_IRQS; i++)
+ platform_irq_list[i] = -1;
+
/*
- * Splitted entry parsing to ensure ordering.
+ * Split-up entry parsing to ensure ordering.
*/
-
while (p < end) {
switch (*p) {
- case ACPI20_ENTRY_LOCAL_APIC_ADDR_OVERRIDE:
+ 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:
+ case ACPI20_ENTRY_LOCAL_SAPIC:
printk("ACPI 2.0 MADT: LOCAL SAPIC\n");
+ lsapic = (acpi20_entry_lsapic_t *) p;
acpi20_lsapic(p);
break;
- case ACPI20_ENTRY_IO_SAPIC:
+ case ACPI20_ENTRY_IO_SAPIC:
iosapic = (acpi_entry_iosapic_t *) p;
if (iosapic_init)
/*
@@ -218,26 +332,25 @@
);
break;
- case ACPI20_ENTRY_PLATFORM_INT_SOURCE:
+ case ACPI20_ENTRY_PLATFORM_INT_SOURCE:
printk("ACPI 2.0 MADT: PLATFORM INT SOURCE\n");
- acpi20_platform(p);
+ acpi20_platform(p, madt);
break;
- case ACPI20_ENTRY_LOCAL_APIC:
+ case ACPI20_ENTRY_LOCAL_APIC:
printk("ACPI 2.0 MADT: LOCAL APIC entry\n"); break;
- case ACPI20_ENTRY_IO_APIC:
+ case ACPI20_ENTRY_IO_APIC:
printk("ACPI 2.0 MADT: IO APIC entry\n"); break;
- case ACPI20_ENTRY_NMI_SOURCE:
+ case ACPI20_ENTRY_NMI_SOURCE:
printk("ACPI 2.0 MADT: NMI SOURCE entry\n"); break;
- case ACPI20_ENTRY_LOCAL_APIC_NMI:
+ case ACPI20_ENTRY_LOCAL_APIC_NMI:
printk("ACPI 2.0 MADT: LOCAL APIC NMI entry\n"); break;
- case ACPI20_ENTRY_INT_SRC_OVERRIDE:
+ case ACPI20_ENTRY_INT_SRC_OVERRIDE:
break;
- default:
+ default:
printk("ACPI 2.0 MADT: unknown entry skip\n"); break;
break;
}
-
p += p[1];
}
@@ -245,16 +358,35 @@
end = p + (madt->header.length - sizeof(acpi_madt_t));
while (p < end) {
+ switch (*p) {
+ case ACPI20_ENTRY_LOCAL_APIC:
+ if (lsapic) break;
+ printk("ACPI 2.0 MADT: LOCAL APIC entry\n");
+ /* parse local apic if there's no local Sapic */
+ break;
+ case ACPI20_ENTRY_IO_APIC:
+ if (iosapic) break;
+ printk("ACPI 2.0 MADT: IO APIC entry\n");
+ /* parse ioapic if there's no ioSapic */
+ break;
+ default:
+ 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:
+ case ACPI20_ENTRY_INT_SRC_OVERRIDE:
printk("ACPI 2.0 MADT: INT SOURCE Override\n");
acpi_legacy_irq(p);
break;
- default:
+ default:
break;
}
-
p += p[1];
}
@@ -269,6 +401,7 @@
# ifdef CONFIG_ACPI
acpi_xsdt_t *xsdt;
acpi_desc_table_hdr_t *hdrp;
+ acpi_madt_t *madt;
int tables, i;
if (strncmp(rsdp20->signature, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN)) {
@@ -310,9 +443,76 @@
ACPI_MADT_SIG, ACPI_MADT_SIG_LEN) != 0)
continue;
- acpi20_parse_madt((acpi_madt_t *) hdrp);
+ /* Save MADT pointer for later */
+ madt = (acpi_madt_t *) hdrp;
+ acpi20_parse_madt(madt);
}
+#ifdef CONFIG_SERIAL_ACPI
+ /*
+ * Now we're interested in other tables. We want the iosapics already
+ * initialized, so we do it in a separate loop.
+ */
+ for (i = 0; i < tables; i++) {
+ hdrp = (acpi_desc_table_hdr_t *) __va(readl_unaligned(&xsdt->entry_ptrs[i]));
+ /*
+ * search for SPCR and DBGP table entries so we can enable
+ * non-pci interrupts to IO-SAPICs.
+ */
+ if (!strncmp(hdrp->signature, ACPI_SPCRT_SIG, ACPI_SPCRT_SIG_LEN) ||
+ !strncmp(hdrp->signature, ACPI_DBGPT_SIG, ACPI_DBGPT_SIG_LEN))
+ {
+ acpi_ser_t *spcr = (void *)hdrp;
+ unsigned long global_int;
+
+ setup_serial_acpi(hdrp);
+
+ /*
+ * ACPI is able to describe serial ports that live at non-standard
+ * memory space addresses and use SAPIC interrupts. If not also
+ * PCI devices, there would be no interrupt vector information for
+ * them. This checks for and fixes that situation.
+ */
+ if (spcr->length < sizeof(acpi_ser_t))
+ /* table is not long enough for full info, thus no int */
+ break;
+
+ /*
+ * If the device is not in PCI space, but uses a SAPIC interrupt,
+ * we need to program the SAPIC so that serial can autoprobe for
+ * the IA64 interrupt vector later on. If the device is in PCI
+ * space, it should already be setup via the PCI vectors
+ */
+ if (spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE &&
+ spcr->int_type == ACPI_SERIAL_INT_SAPIC)
+ {
+ u32 irq_base;
+ char *iosapic_address;
+ int vector;
+
+ /* We have a UART in memory space with a SAPIC interrupt */
+ global_int = ( (spcr->global_int[3] << 24)
+ | (spcr->global_int[2] << 16)
+ | (spcr->global_int[1] << 8)
+ | spcr->global_int[0]);
+
+ if (!iosapic_register_irq)
+ continue;
+
+ /* which iosapic does this IRQ belong to? */
+ if (acpi20_which_iosapic(global_int, madt, &irq_base,
+ &iosapic_address) == 0)
+ {
+ vector = iosapic_register_irq(global_int,
+ 1, /* active high polarity */
+ 1, /* edge triggered */
+ irq_base,
+ iosapic_address);
+ }
+ }
+ }
+ }
+#endif
acpi_cf_terminate();
# ifdef CONFIG_SMP
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)