diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-02-26 14:55:06 -0800 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-02-27 09:46:52 -0800 |
commit | bb4c18cbba474ae20c84171819255598cf975158 (patch) | |
tree | 4c370809b4dffdadd59314e86c97d0fca48e9978 | |
parent | d3dcc2cb2cd86b1db68f0d87d610f1f14406f928 (diff) | |
download | linux-bb4c18cbba474ae20c84171819255598cf975158.tar.bz2 |
[SPARC64]: Fix PCI interrupts on E450 et al.
When the PCI controller OBP node lacks an interrupt-map
and interrupt-map-mask property, we need to form the
INO by hand. The PCI swizzle logic was not doing that
properly.
This was a regression added by the of_device code.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | arch/sparc64/kernel/of_device.c | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index b0f3e0082a0d..ad74e5e8778e 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -708,7 +708,7 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp, unsigned int irq) { struct linux_prom_pci_registers *regs; - unsigned int devfn, slot, ret; + unsigned int bus, devfn, slot, ret; if (irq < 1 || irq > 4) return irq; @@ -717,10 +717,46 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp, if (!regs) return irq; + bus = (regs->phys_hi >> 16) & 0xff; devfn = (regs->phys_hi >> 8) & 0xff; slot = (devfn >> 3) & 0x1f; - ret = ((irq - 1 + (slot & 3)) & 3) + 1; + if (pp->irq_trans) { + /* Derived from Table 8-3, U2P User's Manual. This branch + * is handling a PCI controller that lacks a proper set of + * interrupt-map and interrupt-map-mask properties. The + * Ultra-E450 is one example. + * + * The bit layout is BSSLL, where: + * B: 0 on bus A, 1 on bus B + * D: 2-bit slot number, derived from PCI device number as + * (dev - 1) for bus A, or (dev - 2) for bus B + * L: 2-bit line number + * + * Actually, more "portable" way to calculate the funky + * slot number is to subtract pbm->pci_first_slot from the + * device number, and that's exactly what the pre-OF + * sparc64 code did, but we're building this stuff generically + * using the OBP tree, not in the PCI controller layer. + */ + if (bus & 0x80) { + /* PBM-A */ + bus = 0x00; + slot = (slot - 1) << 2; + } else { + /* PBM-B */ + bus = 0x10; + slot = (slot - 2) << 2; + } + irq -= 1; + + ret = (bus | slot | irq); + } else { + /* Going through a PCI-PCI bridge that lacks a set of + * interrupt-map and interrupt-map-mask properties. + */ + ret = ((irq - 1 + (slot & 3)) & 3) + 1; + } return ret; } |