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>
This commit is contained in:
committed by
Patrick Georgi
parent
6591470ae0
commit
0fa50a1990
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user