#define PREFIX "ACPI: "
+extern struct acpi_boot_flags acpi_boot;
+
+int acpi_mp_config = 0;
+
/* --------------------------------------------------------------------------
Boot-time Configuration
/* From mpparse.c */
extern void __init MP_processor_info(struct mpc_config_processor *);
+extern void __init MP_ioapic_info (struct mpc_config_ioapic *);
+extern void __init MP_lintsrc_info(struct mpc_config_lintsrc *);
int __init
acpi_parse_lapic (
acpi_table_entry_header *header)
{
struct acpi_table_lapic *cpu = NULL;
- struct mpc_config_processor proc_entry;
+ struct mpc_config_processor processor;
cpu = (struct acpi_table_lapic*) header;
if (!cpu)
* the processor ID. Processor features aren't present in
* the table.
*/
- proc_entry.mpc_type = MP_PROCESSOR;
- proc_entry.mpc_apicid = cpu->id;
- proc_entry.mpc_cpuflag = CPU_ENABLED;
+ processor.mpc_type = MP_PROCESSOR;
+ processor.mpc_apicid = cpu->id;
+ processor.mpc_cpuflag = CPU_ENABLED;
if (cpu->id == boot_cpu_physical_apicid) {
/* TBD: Circular reference trying to establish BSP */
- proc_entry.mpc_cpuflag |= CPU_BOOTPROCESSOR;
+ processor.mpc_cpuflag |= CPU_BOOTPROCESSOR;
}
- proc_entry.mpc_cpufeature = (boot_cpu_data.x86 << 8)
+ processor.mpc_cpufeature = (boot_cpu_data.x86 << 8)
| (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask;
- proc_entry.mpc_featureflag = boot_cpu_data.x86_capability[0];
- proc_entry.mpc_reserved[0] = 0;
- proc_entry.mpc_reserved[1] = 0;
- proc_entry.mpc_apicver = 0x10; /* integrated APIC */
+ processor.mpc_featureflag = boot_cpu_data.x86_capability[0];
+ processor.mpc_reserved[0] = 0;
+ processor.mpc_reserved[1] = 0;
+ processor.mpc_apicver = 0x10; /* Integrated APIC */
- MP_processor_info(&proc_entry);
+ MP_processor_info(&processor);
total_cpus++;
acpi_table_print_madt_entry(header);
- /* TBD: Support local APIC NMI entries */
+ /* TBD: Support lapic_nmi entries */
return 0;
}
acpi_table_entry_header *header)
{
struct acpi_table_ioapic *ioapic = NULL;
-
+ /*
+ struct mpc_config_ioapic mp_ioapic;
+ struct IO_APIC_reg_01 reg_01;
+ */
+
ioapic = (struct acpi_table_ioapic*) header;
if (!ioapic)
return -EINVAL;
+
+ acpi_table_print_madt_entry(header);
+
+ /*
+ * Cobble up an entry for the IOAPIC (just as we do for LAPIC entries).
+ * Note that we aren't doing anything with ioapic->vector, and
+ * mpc_apicver gets read directly from ioapic.
+ */
+
+ /*
+ * TBD: Complete I/O APIC support.
+ *
+ mp_ioapic.mpc_type = MP_IOAPIC;
+ mp_ioapic.mpc_apicid = ioapic->id;
+ mp_ioapic.mpc_flags = MPC_APIC_USABLE;
+ mp_ioapic.mpc_apicaddr = ioapic->address;
+ set_fixmap_nocache(nr_ioapics + FIX_IO_APIC_BASE_0,
+ mp_ioapic.mpc_apicaddr);
+
+ printk("mapped IOAPIC to %08lx (%08lx)\n",
+ __fix_to_virt(nr_ioapics), mp_ioapic.mpc_apicaddr);
+
+ *(int *)®_01 = io_apic_read(nr_ioapics, 1);
+ mp_ioapic.mpc_apicver = reg_01.version;
+ MP_ioapic_info(&mp_ioapic);
+ */
+
+ return 0;
+}
+
+
+int __init
+acpi_parse_int_src_ovr (
+ acpi_table_entry_header *header)
+{
+ struct acpi_table_int_src_ovr *int_src_ovr = NULL;
+ /*
+ struct mpc_config_intsrc my_intsrc;
+ int i = 0;
+ */
+
+ int_src_ovr = (struct acpi_table_int_src_ovr*) header;
+ if (!int_src_ovr)
+ return -EINVAL;
acpi_table_print_madt_entry(header);
- /* TBD: Support ioapic entries */
+ /*
+ * TBD: Complete I/O APIC support.
+ *
+ my_intsrc.mpc_type = MP_INTSRC;
+ my_intsrc.mpc_irqtype = mp_INT;
+ my_intsrc.mpc_irqflag = *(unsigned short*)(&(int_src_ovr->flags));
+ my_intsrc.mpc_srcbus = int_src_ovr->bus;
+ my_intsrc.mpc_srcbusirq = int_src_ovr->bus_irq;
+ my_intsrc.mpc_dstapic = 0;
+ my_intsrc.mpc_dstirq = int_src_ovr->global_irq;
+
+ for (i = 0; i < mp_irq_entries; i++) {
+ if (mp_irqs[i].mpc_srcbusirq == my_intsrc.mpc_srcbusirq) {
+ mp_irqs[i] = my_intsrc;
+ break;
+ }
+ }
+ */
+
+ return 0;
+}
+
+
+int __init
+acpi_parse_nmi_src (
+ acpi_table_entry_header *header)
+{
+ struct acpi_table_nmi_src *nmi_src = NULL;
+
+ nmi_src = (struct acpi_table_nmi_src*) header;
+ if (!nmi_src)
+ return -EINVAL;
+
+ acpi_table_print_madt_entry(header);
+
+ /* TBD: Support nimsrc entries */
return 0;
}
+
#endif /*CONFIG_X86_IO_APIC*/
}
-#endif /*CONFIG_ACPI_BOOT*/
+int __init
+acpi_boot_init (
+ char *cmdline)
+{
+ int result = 0;
+ /* Initialize the ACPI boot-time table parser */
+ result = acpi_table_init(cmdline);
+ if (0 != result)
+ return result;
+
+#ifdef CONFIG_X86_LOCAL_APIC
+#ifdef CONFIG_X86_IO_APIC
+
+ /*
+ * MADT
+ * ----
+ * Parse the Multiple APIC Description Table (MADT), if exists.
+ * Note that this table provides platform SMP configuration
+ * information -- the successor to MPS tables.
+ */
+
+ if (!acpi_boot.madt) {
+ printk(KERN_INFO PREFIX "MADT parsing disabled via command-line\n");
+ return 0;
+ }
+
+ result = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
+ if (0 == result) {
+ printk(KERN_WARNING PREFIX "MADT not present\n");
+ return 0;
+ }
+ else if (0 > result) {
+ printk(KERN_ERR PREFIX "Error parsing MADT\n");
+ return result;
+ }
+ else if (1 < result)
+ printk(KERN_WARNING PREFIX "Multiple MADT tables exist\n");
+
+ /* Local APIC */
+
+ result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr);
+ if (0 > result) {
+ printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n");
+ return result;
+ }
+
+ result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic);
+ if (1 > result) {
+ printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries!\n");
+ return -ENODEV;
+ }
+
+ result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi);
+ if (0 > result) {
+ printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
+ return result;
+ }
+
+ /* I/O APIC */
+
+ result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic);
+ if (1 > result) {
+ printk(KERN_ERR PREFIX "Error parsing MADT - no IOAPIC entries!\n");
+ return -ENODEV;
+ }
+
+ acpi_mp_config = 1;
+
+ /*
+ * TBD: Complete I/O APIC support.
+ *
+ construct_default_ACPI_table();
+ */
+
+ result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr);
+ if (0 > result) {
+ printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n");
+ return result;
+ }
+
+ result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src);
+ if (0 > result) {
+ printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
+ return result;
+ }
+
+ /* Make boot-up look pretty */
+ printk("%d CPUs total\n", total_cpus);
+
+#endif /*CONFIG_X86_IO_APIC*/
+#endif /*CONFIG_X86_LOCAL_APIC*/
+
+#ifdef CONFIG_SERIAL_ACPI
+ /*
+ * TBD: Need phased approach to table parsing (only do those absolutely
+ * required during boot-up). Recommend expanding concept of fix-
+ * feature devices (ACPI Bus driver) to include table-based devices
+ * such as serial ports, EC, SMBus, etc.
+ */
+ /* acpi_table_parse(ACPI_SPCR, acpi_parse_spcr);*/
+#endif /*CONFIG_SERIAL_ACPI*/
+
+ return 0;
+}
+
+#endif /*CONFIG_ACPI_BOOT*/
-/* --------------------------------------------------------------------------
- PCI Interrupt Routing Support
- -------------------------------------------------------------------------- */
-#ifdef CONFIG_ACPI_PCI
int __init
acpi_get_interrupt_model (
int *type)
return -EINVAL;
#ifdef CONFIG_X86_IO_APIC
- if (io_apic_assign_pci_irqs)
- *type = ACPI_PCI_ROUTING_IOAPIC;
- else
+ *type = ACPI_INT_MODEL_IOAPIC;
+#else
+ *type = ACPI_INT_MODEL_PIC;
#endif
- *type = ACPI_PCI_ROUTING_PIC;
return 0;
}
-#endif
/* --------------------------------------------------------------------------
addw $(wakeup_data - wakeup_code) >> 4, %ax
movw %ax, %ds
+ movw %ax, %ss
+ mov $(wakeup_stack - wakeup_data), %sp # Private stack is needed for ASUS board
# set up page table
movl (real_save_cr3 - wakeup_data), %eax
#include <linux/mm.h>
#include <linux/irq.h>
-#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/config.h>
#include <linux/mc146818rtc.h>
#include <asm/smp.h>
+#include <asm/acpi.h>
#include <asm/mtrr.h>
#include <asm/mpspec.h>
#include <asm/pgalloc.h>
/* Have we found an MP table */
int smp_found_config;
-/* Have we found an ACPI MADT table */
-int acpi_found_madt = 0;
-
/*
* Various Linux-internal data structures created from the
* MP-table.
int apic_version [MAX_APICS];
int mp_bus_id_to_type [MAX_MP_BUSSES];
int mp_bus_id_to_node [MAX_MP_BUSSES];
-int mp_bus_id_to_local [MAX_MP_BUSSES];
-int quad_local_to_mp_bus_id [NR_CPUS/4][4];
int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
int mp_current_pci_id;
/* Bitmask of physically existing CPUs */
unsigned long phys_cpu_present_map;
-/* ACPI MADT entry parsing functions */
-#ifdef CONFIG_ACPI_BOOT
-extern struct acpi_boot_flags acpi_boot;
-#ifdef CONFIG_X86_LOCAL_APIC
-extern int acpi_parse_lapic (acpi_table_entry_header *header);
-extern int acpi_parse_lapic_addr_ovr (acpi_table_entry_header *header);
-extern int acpi_parse_lapic_nmi (acpi_table_entry_header *header);
-#endif /*CONFIG_X86_LOCAL_APIC*/
-#ifdef CONFIG_X86_IO_APIC
-extern int acpi_parse_ioapic (acpi_table_entry_header *header);
-#endif /*CONFIG_X86_IO_APIC*/
-#endif /*CONFIG_ACPI_BOOT*/
-
/*
* Intel MP BIOS table parsing routines:
*/
return n;
}
-/*
+/*
* Have to match translation table entries to main table entries by counter
* hence the mpc_record variable .... can't see a less disgusting way of
* doing this ....
static void __init MP_bus_info (struct mpc_config_bus *m)
{
char str[7];
- int quad;
memcpy(str, m->mpc_bustype, 6);
str[6] = 0;
if (clustered_apic_mode) {
- quad = translation_table[mpc_record]->trans_quad;
- mp_bus_id_to_node[m->mpc_busid] = quad;
- mp_bus_id_to_local[m->mpc_busid] = translation_table[mpc_record]->trans_local;
- quad_local_to_mp_bus_id[quad][translation_table[mpc_record]->trans_local] = m->mpc_busid;
- printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, quad);
+ mp_bus_id_to_node[m->mpc_busid] = translation_table[mpc_record]->trans_quad;
+ printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, mp_bus_id_to_node[m->mpc_busid]);
} else {
Dprintk("Bus #%d is %s\n", m->mpc_busid, str);
}
static void __init MP_translation_info (struct mpc_config_translation *m)
{
- printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, m->trans_quad, m->trans_global, m->trans_local);
+ printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type,
+ m->trans_quad, m->trans_global, m->trans_local);
if (mpc_record >= MAX_MPC_ENTRY)
printk("MAX_MPC_ENTRY exceeded!\n");
else
translation_table[mpc_record] = m; /* stash this for later */
- if (m->trans_quad+1 > numnodes)
- numnodes = m->trans_quad+1;
}
/*
printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
- /*
- * Save the local APIC address, it might be non-default,
- * but only if we're not using the ACPI tables
+ /*
+ * Save the local APIC address (it might be non-default), but only
+ * if we're not using the ACPI tables.
*/
- if (!acpi_found_madt)
+ if (!acpi_mp_config)
mp_lapic_addr = mpc->mpc_lapic;
if (clustered_apic_mode && mpc->mpc_oemptr) {
(struct mpc_config_processor *)mpt;
/* ACPI may already have provided this one for us */
- if (!acpi_found_madt)
+ if (!acpi_mp_config)
MP_processor_info(m);
mpt += sizeof(*m);
count += sizeof(*m);
}
++mpc_record;
}
+ if (clustered_apic_mode && nr_ioapics > 2) {
+ /* don't initialise IO apics on secondary quads */
+ nr_ioapics = 2;
+ }
if (!num_processors)
printk(KERN_ERR "SMP mptable: no processors registered!\n");
return num_processors;
{
struct intel_mp_floating *mpf = mpf_found;
-#ifdef CONFIG_ACPI_BOOT
- /*
- * Check if the MADT exists, and if so, use it to get processor
- * information (ACPI_MADT_LAPIC). The MADT supports the concept
- * of both logical (e.g. HT) and physical processor(s); where the
- * MPS only supports physical.
- */
- if (acpi_boot.madt) {
- acpi_found_madt = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
- if (acpi_found_madt > 0)
- acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic);
- }
-#endif /*CONFIG_ACPI_BOOT*/
-
printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification);
if (mpf->mpf_feature2 & (1<<7)) {
printk(" IMCR and PIC compatibility mode.\n");
pirq_router_dev->slot_name);
}
+static struct irq_info *pirq_get_info(struct pci_dev *dev)
+{
+ struct irq_routing_table *rt = pirq_table;
+ int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
+ struct irq_info *info;
+
+ for (info = rt->slots; entries--; info++)
+ if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn))
+ return info;
+ return NULL;
+}
+
static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
}
/* TBD: Select IRQ from possible to improve routing performance. */
result = acpi_prt_get_irq(dev, pin, &irq);
- if ((0 != result) || !irq) {
- printk(KERN_ERR "PCI: Unable to resolve IRQ for device %s\n",
- dev->slot_name);
+ if (!irq)
+ result = -ENODEV;
+ if (0 != result) {
+ printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s\n",
+ 'A'+pin, dev->slot_name);
return result;
}
- printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", irq,
- dev->slot_name);
-
dev->irq = irq;
- pirq_penalty[irq]++;
+ if (!assign) {
+ /* only check for the IRQ */
+ printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", irq,
+ dev->slot_name);
+ return 1;
+ }
+
+ /* also assign an IRQ */
+ if (irq && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
+ result = acpi_prt_set_irq(dev, pin, irq);
+ if (0 != result) {
+ printk(KERN_WARNING "PCI: Could not assign IRQ %d to device %s\n", irq, dev->slot_name);
+ return result;
+ }
+
+ eisa_set_level_irq(irq);
+
+ printk(KERN_INFO "PCI: Assigned IRQ %d for device %s\n", irq, dev->slot_name);
+ }
return 1;
}
#endif /* CONFIG_ACPI_PCI */
-static struct irq_info *pirq_get_info(struct pci_dev *dev)
+static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
{
- struct irq_routing_table *rt = pirq_table;
- int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
+ u8 pin;
struct irq_info *info;
-
- for (info = rt->slots; entries--; info++)
- if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn))
- return info;
- return NULL;
-}
-
-static int pirq_lookup_irq(struct pci_dev *dev, u8 pin, int assign)
-{
+ int i, pirq, newirq;
+ int irq = 0;
+ u32 mask;
struct irq_router *r = pirq_router;
- struct irq_info *info;
- int newirq, pirq, i, irq = 0;
struct pci_dev *dev2;
char *msg = NULL;
- u32 mask;
- if (!pirq_table)
+ /* Find IRQ pin */
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (!pin) {
+ DBG(" -> no interrupt pin\n");
return 0;
+ }
+ pin = pin - 1;
+
+#ifdef CONFIG_ACPI_PCI
+ /* Use ACPI to lookup IRQ */
+ if (pci_use_acpi_routing)
+ return acpi_lookup_irq(dev, pin, assign);
+#endif
+
+ /* Find IRQ routing entry */
+ if (!pirq_table)
+ return 0;
+
DBG("IRQ for %s:%d", dev->slot_name, pin);
info = pirq_get_info(dev);
if (!info) {
DBG(" -> not found in routing table\n");
return 0;
}
-
pirq = info->irq[pin].link;
mask = info->irq[pin].bitmap;
if (!pirq) {
* reported by the device if possible.
*/
newirq = dev->irq;
- if (!((1 << newirq) & mask)) {
- if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0;
- else printk(KERN_WARNING "PCI: IRQ %i for device %s doesn't match PIRQ mask - try pci=usepirqmask\n", newirq, dev->slot_name);
- }
if (!newirq && assign) {
for (i = 0; i < 16; i++) {
if (!(mask & (1 << i)))
irq = pirq & 0xf;
DBG(" -> hardcoded IRQ %d\n", irq);
msg = "Hardcoded";
- } else if ( r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \
- ((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask)) ) {
+ } else if (r->get && (irq = r->get(pirq_router_dev, dev, pirq))) {
DBG(" -> got IRQ %d\n", irq);
msg = "Found";
} else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
continue;
if (info->irq[pin].link == pirq) {
/* We refuse to override the dev->irq information. Give a warning! */
- if ( dev2->irq && dev2->irq != irq && \
- (!(pci_probe & PCI_USE_PIRQ_MASK) || \
- ((1 << dev2->irq) & mask)) ) {
+ if (dev2->irq && dev2->irq != irq) {
printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n",
dev2->slot_name, dev2->irq, irq);
continue;
return 1;
}
-static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
-{
- u8 pin;
-
- /* Find IRQ routing entry */
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (!pin) {
- DBG("PCI: %s: no interrupt pin\n", dev->slot_name);
- return 0;
- }
- pin -= 1;
-
-#ifdef CONFIG_ACPI_PCI
- if (pci_use_acpi_routing)
- return acpi_lookup_irq(dev, pin, assign);
- else
-#endif
- return pirq_lookup_irq(dev, pin, assign);
-}
-
void __init pcibios_irq_init(void)
{
DBG("PCI: IRQ init\n");
#ifdef CONFIG_ACPI_PCI
- if (acpi_prts.count && !(pci_probe & PCI_NO_ACPI_ROUTING)) {
- printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
- pci_use_acpi_routing = 1;
- return;
+ if (!(pci_probe & PCI_NO_ACPI_ROUTING)) {
+ if (acpi_prts.count) {
+ printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
+ pci_use_acpi_routing = 1;
+ return;
+ }
+ else
+ printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n");
}
- if (!acpi_prts.count)
- printk(KERN_INFO "PCI: Invalid acpi_prts [%d]\n", acpi_prts.count);
#endif
pirq_table = pirq_find_routing_table();