Commit 034004ee authored by Andy Grover's avatar Andy Grover Committed by Andy Grover

MADT parsing improvements (Paul D & Richard Schaal)

ACPI PCI IRQ improvements (Dominik Brodowski and Paul D)
Wakeup fix (Pavel Machek)
parent bb721a7a
......@@ -48,6 +48,10 @@
#define PREFIX "ACPI: "
extern struct acpi_boot_flags acpi_boot;
int acpi_mp_config = 0;
/* --------------------------------------------------------------------------
Boot-time Configuration
......@@ -104,13 +108,15 @@ static int total_cpus __initdata = 0;
/* 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)
......@@ -134,21 +140,21 @@ acpi_parse_lapic (
* 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++;
......@@ -184,7 +190,7 @@ acpi_parse_lapic_nmi (
acpi_table_print_madt_entry(header);
/* TBD: Support local APIC NMI entries */
/* TBD: Support lapic_nmi entries */
return 0;
}
......@@ -199,18 +205,102 @@ acpi_parse_ioapic (
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 *)&reg_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*/
......@@ -288,14 +378,115 @@ acpi_find_rsdp (
}
#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)
......@@ -304,15 +495,13 @@ acpi_get_interrupt_model (
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
/* --------------------------------------------------------------------------
......
......@@ -18,6 +18,8 @@ wakeup_code:
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
......
......@@ -14,7 +14,6 @@
#include <linux/mm.h>
#include <linux/irq.h>
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/config.h>
......@@ -24,6 +23,7 @@
#include <linux/mc146818rtc.h>
#include <asm/smp.h>
#include <asm/acpi.h>
#include <asm/mtrr.h>
#include <asm/mpspec.h>
#include <asm/pgalloc.h>
......@@ -31,9 +31,6 @@
/* 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.
......@@ -41,8 +38,6 @@ int acpi_found_madt = 0;
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;
......@@ -69,19 +64,6 @@ static unsigned int num_processors;
/* 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:
*/
......@@ -139,7 +121,7 @@ static char __init *mpc_family(int family,int model)
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 ....
......@@ -255,17 +237,13 @@ void __init MP_processor_info (struct mpc_config_processor *m)
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);
}
......@@ -342,14 +320,13 @@ static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m)
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;
}
/*
......@@ -439,11 +416,11 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
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) {
......@@ -464,7 +441,7 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
(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);
......@@ -515,6 +492,10 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
}
++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;
......@@ -686,20 +667,6 @@ void __init get_smp_config (void)
{
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");
......
......@@ -540,6 +540,18 @@ static void __init pirq_find_router(void)
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)
{
}
......@@ -557,55 +569,77 @@ static int acpi_lookup_irq (
/* 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) {
......@@ -629,10 +663,6 @@ static int pirq_lookup_irq(struct pci_dev *dev, u8 pin, int assign)
* 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)))
......@@ -651,8 +681,7 @@ static int pirq_lookup_irq(struct pci_dev *dev, u8 pin, int assign)
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) {
......@@ -686,9 +715,7 @@ static int pirq_lookup_irq(struct pci_dev *dev, u8 pin, int assign)
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;
......@@ -702,38 +729,20 @@ static int pirq_lookup_irq(struct pci_dev *dev, u8 pin, int assign)
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();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment