x86: mpspec: Allow platform to determine how PIRQ is connected to I/O APIC

Currently during writing MP table I/O interrupt assignment entry, we
assume the PIRQ is directly mapped to I/O APIC INTPIN#16-23, which
however is not always the case on some platforms.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Acked-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Bin Meng 2015-07-22 01:21:09 -07:00 committed by Simon Glass
parent a277194341
commit abab912813
2 changed files with 34 additions and 7 deletions

View File

@ -431,6 +431,23 @@ void mp_write_compat_address_space(struct mp_config_table *mc, int busid,
*/
u32 mptable_finalize(struct mp_config_table *mc);
/**
* mp_determine_pci_dstirq() - Determine PCI device's int pin on the I/O APIC
*
* This determines a PCI device's interrupt pin number on the I/O APIC.
*
* This can be implemented by platform codes to handle specifal cases, which
* do not conform to the normal chipset/board design where PIRQ[A-H] are mapped
* directly to I/O APIC INTPIN#16-23.
*
* @bus: bus number of the pci device
* @dev: device number of the pci device
* @func: function number of the pci device
* @pirq: PIRQ number the PCI device's interrupt pin is routed to
* @return: interrupt pin number on the I/O APIC
*/
int mp_determine_pci_dstirq(int bus, int dev, int func, int pirq);
/**
* write_mp_table() - Write MP table
*

View File

@ -269,6 +269,13 @@ static bool check_dup_entry(struct mpc_config_intsrc *intsrc_base,
return (i == entry_num) ? false : true;
}
/* TODO: move this to driver model */
__weak int mp_determine_pci_dstirq(int bus, int dev, int func, int pirq)
{
/* PIRQ[A-H] are connected to I/O APIC INTPIN#16-23 */
return pirq + 16;
}
static int mptable_add_intsrc(struct mp_config_table *mc,
int bus_isa, int apicid)
{
@ -304,24 +311,27 @@ static int mptable_add_intsrc(struct mp_config_table *mc,
for (i = 0; i < count; i++) {
struct pirq_routing pr;
int bus, dev, func;
int dstirq;
pr.bdf = fdt_addr_to_cpu(cell[0]);
pr.pin = fdt_addr_to_cpu(cell[1]);
pr.pirq = fdt_addr_to_cpu(cell[2]);
bus = PCI_BUS(pr.bdf);
dev = PCI_DEV(pr.bdf);
func = PCI_FUNC(pr.bdf);
if (check_dup_entry(intsrc_base, intsrc_entries,
PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), pr.pin)) {
bus, dev, pr.pin)) {
debug("found entry for bus %d device %d INT%c, skipping\n",
PCI_BUS(pr.bdf), PCI_DEV(pr.bdf),
'A' + pr.pin - 1);
bus, dev, 'A' + pr.pin - 1);
cell += sizeof(struct pirq_routing) / sizeof(u32);
continue;
}
/* PIRQ[A-H] are always connected to I/O APIC INTPIN#16-23 */
mp_write_pci_intsrc(mc, MP_INT, PCI_BUS(pr.bdf),
PCI_DEV(pr.bdf), pr.pin, apicid,
pr.pirq + 16);
dstirq = mp_determine_pci_dstirq(bus, dev, func, pr.pirq);
mp_write_pci_intsrc(mc, MP_INT, bus, dev, pr.pin,
apicid, dstirq);
intsrc_entries++;
cell += sizeof(struct pirq_routing) / sizeof(u32);
}