diff options
author | Sven Schnelle <svens@stackframe.org> | 2012-06-21 22:19:48 +0200 |
---|---|---|
committer | Patrick Georgi <patrick@georgi-clan.de> | 2012-07-13 08:38:13 +0200 |
commit | 0fa50a1990fcdfca6a9f75a68f8e4ed22ddd6949 (patch) | |
tree | ff1ee24731267f351b79d321eb54fd773b51e299 /src | |
parent | 6591470ae0c9639b1ef591ede96eee4a930f35e2 (diff) |
MPTAPLE: generate from devicetree.cb
This patch adds support for autogenerating the MPTABLE from
devicetree.cb. This is done by a write_smp_table() declared
weak in mpspec.c. If the mainboard doesn't provide it's own
function, this generic implementation is called.
Syntax in devicetree.cb:
ioapic_irq <APICID> <INTA|INTB|INTC|INTD> <INTPIN>
The ioapic_irq directive can be used in pci and pci_domain
devices. If there's no directive, the autogen code traverses
the tree back to the pci_domain and stops at the first device
which such a directive, and use that information to generate the
entry according to PCI IRQ routing rules.
Change-Id: I4df5b198e8430f939d477c14c798414e398a2027
Signed-off-by: Sven Schnelle <svens@stackframe.org>
Reviewed-on: http://review.coreboot.org/1138
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <patrick@georgi-clan.de>
Diffstat (limited to 'src')
-rw-r--r-- | src/arch/x86/boot/mpspec.c | 101 | ||||
-rw-r--r-- | src/devices/device_util.c | 4 | ||||
-rw-r--r-- | src/include/device/device.h | 9 | ||||
-rw-r--r-- | src/include/device/path.h | 7 |
4 files changed, 120 insertions, 1 deletions
diff --git a/src/arch/x86/boot/mpspec.c b/src/arch/x86/boot/mpspec.c index e7d767b7ac..44236f1cca 100644 --- a/src/arch/x86/boot/mpspec.c +++ b/src/arch/x86/boot/mpspec.c @@ -6,6 +6,7 @@ #include <string.h> #include <arch/cpu.h> #include <cpu/x86/lapic.h> +#include <drivers/generic/ioapic/chip.h> /* Initialize the specified "mc" struct with initial values. */ void mptable_init(struct mp_config_table *mc, u32 lapic_addr) @@ -410,3 +411,103 @@ void *mptable_finalize(struct mp_config_table *mc) printk(BIOS_DEBUG, "Wrote the mp table end at: %p - %p\n", mc, smp_next_mpe_entry(mc)); return smp_next_mpe_entry(mc); } + +unsigned long __attribute__((weak)) write_smp_table(unsigned long addr) +{ + struct drivers_generic_ioapic_config *ioapic_config; + struct mp_config_table *mc; + int isa_bus, pin, parentpin; + device_t dev, parent, oldparent; + void *tmp, *v; + int isaioapic = -1; + + v = smp_write_floating_table(addr, 0); + mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN); + + mptable_init(mc, LOCAL_APIC_ADDR); + + smp_write_processors(mc); + + mptable_write_buses(mc, NULL, &isa_bus); + + for(dev = all_devices; dev; dev = dev->next) { + if (dev->path.type != DEVICE_PATH_IOAPIC) + continue; + + if (!(ioapic_config = dev->chip_info)) { + printk(BIOS_ERR, "%s has no config, ignoring\n", dev_path(dev)); + continue; + } + smp_write_ioapic(mc, dev->path.ioapic.ioapic_id, + ioapic_config->version, + ioapic_config->base); + + if (ioapic_config->have_isa_interrupts) { + if (isaioapic > 1) + printk(BIOS_ERR, "More than one IOAPIC with ISA interrupts?\n"); + else + isaioapic = dev->path.ioapic.ioapic_id;; + } + } + + if (isaioapic >= 0) { + /* Legacy Interrupts */ + printk(BIOS_DEBUG, "writing ISA IRQs\n"); + mptable_add_isa_interrupts(mc, isa_bus, isaioapic, 0); + } + + for(dev = all_devices; dev; dev = dev->next) { + + if (dev->path.type != DEVICE_PATH_PCI) + continue; + + pin = (dev->path.pci.devfn & 7) % 4; + + if (dev->pci_irq_info[pin].ioapic_dst_id) { + printk(BIOS_DEBUG, "fixed IRQ entry for: %s: INT%c# -> IOAPIC %d PIN %d\n", dev_path(dev), + pin + 'A', + dev->pci_irq_info[pin].ioapic_dst_id, + dev->pci_irq_info[pin].ioapic_irq_pin); + smp_write_intsrc(mc, mp_INT, + dev->pci_irq_info[pin].ioapic_flags, + dev->bus->secondary, + ((dev->path.pci.devfn & 0xf8) >> 1) | pin, + dev->pci_irq_info[pin].ioapic_dst_id, + dev->pci_irq_info[pin].ioapic_irq_pin); + } else { + oldparent = parent = dev; + while((parent = parent->bus->dev)) { + parentpin = (oldparent->path.pci.devfn >> 3) + (oldparent->path.pci.devfn & 7); + parentpin += dev->path.pci.devfn & 7; + parentpin += dev->path.pci.devfn >> 3; + parentpin %= 4; + + if (parent->pci_irq_info[parentpin].ioapic_dst_id) { + printk(BIOS_DEBUG, "automatic IRQ entry for %s: INT%c# -> IOAPIC %d PIN %d\n", + dev_path(dev), pin + 'A', + parent->pci_irq_info[parentpin].ioapic_dst_id, + parent->pci_irq_info[parentpin].ioapic_irq_pin); + smp_write_intsrc(mc, mp_INT, + parent->pci_irq_info[parentpin].ioapic_flags, + dev->bus->secondary, + ((dev->path.pci.devfn & 0xf8) >> 1) | pin, + parent->pci_irq_info[parentpin].ioapic_dst_id, + parent->pci_irq_info[parentpin].ioapic_irq_pin); + + break; + } + + if (parent->path.type == DEVICE_PATH_PCI_DOMAIN) { + printk(BIOS_WARNING, "no IRQ found for %s\n", dev_path(dev)); + break; + } + oldparent = parent; + } + } + } + + mptable_lintsrc(mc, isa_bus); + tmp = mptable_finalize(mc); + printk(BIOS_INFO, "MPTABLE len: %d\n", (unsigned int)tmp - (unsigned int)v); + return (unsigned long)tmp; +} diff --git a/src/devices/device_util.c b/src/devices/device_util.c index ecc2c13659..7c1cde9895 100644 --- a/src/devices/device_util.c +++ b/src/devices/device_util.c @@ -201,6 +201,10 @@ const char *dev_path(device_t dev) sprintf(buffer, "APIC: %02x", dev->path.apic.apic_id); break; + case DEVICE_PATH_IOAPIC: + sprintf(buffer, "IOAPIC: %02x", + dev->path.ioapic.ioapic_id); + break; case DEVICE_PATH_PCI_DOMAIN: sprintf(buffer, "PCI_DOMAIN: %04x", dev->path.pci_domain.domain); diff --git a/src/include/device/device.h b/src/include/device/device.h index 0aea1d6087..f36710ae0a 100644 --- a/src/include/device/device.h +++ b/src/include/device/device.h @@ -61,6 +61,13 @@ struct bus { * combination: */ +struct pci_irq_info { + unsigned int ioapic_irq_pin; + unsigned int ioapic_src_pin; + unsigned int ioapic_dst_id; + unsigned int ioapic_flags; +}; + struct device { struct bus * bus; /* bus this device is on, for bridge * devices, it is the up stream bus */ @@ -77,7 +84,7 @@ struct device { unsigned int enabled : 1; /* set if we should enable the device */ unsigned int initialized : 1; /* set if we have initialized the device */ unsigned int on_mainboard : 1; - + struct pci_irq_info pci_irq_info[4]; u8 command; /* Base registers for this device. I/O, MEM and Expansion ROM */ diff --git a/src/include/device/path.h b/src/include/device/path.h index 018fb9313f..3dc7625029 100644 --- a/src/include/device/path.h +++ b/src/include/device/path.h @@ -12,6 +12,7 @@ enum device_path_type { DEVICE_PATH_APIC_CLUSTER, DEVICE_PATH_CPU, DEVICE_PATH_CPU_BUS, + DEVICE_PATH_IOAPIC, }; struct pci_domain_path @@ -43,6 +44,11 @@ struct apic_path unsigned index; }; +struct ioapic_path +{ + unsigned ioapic_id; +}; + struct apic_cluster_path { unsigned cluster; @@ -66,6 +72,7 @@ struct device_path { struct pnp_path pnp; struct i2c_path i2c; struct apic_path apic; + struct ioapic_path ioapic; struct pci_domain_path pci_domain; struct apic_cluster_path apic_cluster; struct cpu_path cpu; |