diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-02-26 17:55:06 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-02-27 12:46:52 -0500 |
commit | bb4c18cbba474ae20c84171819255598cf975158 (patch) | |
tree | 4c370809b4dffdadd59314e86c97d0fca48e9978 | |
parent | d3dcc2cb2cd86b1db68f0d87d610f1f14406f928 (diff) |
[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, | |||
708 | unsigned int irq) | 708 | unsigned int irq) |
709 | { | 709 | { |
710 | struct linux_prom_pci_registers *regs; | 710 | struct linux_prom_pci_registers *regs; |
711 | unsigned int devfn, slot, ret; | 711 | unsigned int bus, devfn, slot, ret; |
712 | 712 | ||
713 | if (irq < 1 || irq > 4) | 713 | if (irq < 1 || irq > 4) |
714 | return irq; | 714 | return irq; |
@@ -717,10 +717,46 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp, | |||
717 | if (!regs) | 717 | if (!regs) |
718 | return irq; | 718 | return irq; |
719 | 719 | ||
720 | bus = (regs->phys_hi >> 16) & 0xff; | ||
720 | devfn = (regs->phys_hi >> 8) & 0xff; | 721 | devfn = (regs->phys_hi >> 8) & 0xff; |
721 | slot = (devfn >> 3) & 0x1f; | 722 | slot = (devfn >> 3) & 0x1f; |
722 | 723 | ||
723 | ret = ((irq - 1 + (slot & 3)) & 3) + 1; | 724 | if (pp->irq_trans) { |
725 | /* Derived from Table 8-3, U2P User's Manual. This branch | ||
726 | * is handling a PCI controller that lacks a proper set of | ||
727 | * interrupt-map and interrupt-map-mask properties. The | ||
728 | * Ultra-E450 is one example. | ||
729 | * | ||
730 | * The bit layout is BSSLL, where: | ||
731 | * B: 0 on bus A, 1 on bus B | ||
732 | * D: 2-bit slot number, derived from PCI device number as | ||
733 | * (dev - 1) for bus A, or (dev - 2) for bus B | ||
734 | * L: 2-bit line number | ||
735 | * | ||
736 | * Actually, more "portable" way to calculate the funky | ||
737 | * slot number is to subtract pbm->pci_first_slot from the | ||
738 | * device number, and that's exactly what the pre-OF | ||
739 | * sparc64 code did, but we're building this stuff generically | ||
740 | * using the OBP tree, not in the PCI controller layer. | ||
741 | */ | ||
742 | if (bus & 0x80) { | ||
743 | /* PBM-A */ | ||
744 | bus = 0x00; | ||
745 | slot = (slot - 1) << 2; | ||
746 | } else { | ||
747 | /* PBM-B */ | ||
748 | bus = 0x10; | ||
749 | slot = (slot - 2) << 2; | ||
750 | } | ||
751 | irq -= 1; | ||
752 | |||
753 | ret = (bus | slot | irq); | ||
754 | } else { | ||
755 | /* Going through a PCI-PCI bridge that lacks a set of | ||
756 | * interrupt-map and interrupt-map-mask properties. | ||
757 | */ | ||
758 | ret = ((irq - 1 + (slot & 3)) & 3) + 1; | ||
759 | } | ||
724 | 760 | ||
725 | return ret; | 761 | return ret; |
726 | } | 762 | } |