aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/isa.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/isa.c')
-rw-r--r--arch/sparc64/kernel/isa.c101
1 files changed, 6 insertions, 95 deletions
diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c
index 24c0dc34be31..0f3aec72ef5f 100644
--- a/arch/sparc64/kernel/isa.c
+++ b/arch/sparc64/kernel/isa.c
@@ -3,6 +3,8 @@
3#include <linux/pci.h> 3#include <linux/pci.h>
4#include <linux/slab.h> 4#include <linux/slab.h>
5#include <asm/oplib.h> 5#include <asm/oplib.h>
6#include <asm/prom.h>
7#include <asm/of_device.h>
6#include <asm/isa.h> 8#include <asm/isa.h>
7 9
8struct sparc_isa_bridge *isa_chain; 10struct sparc_isa_bridge *isa_chain;
@@ -46,107 +48,16 @@ isa_dev_get_resource(struct sparc_isa_device *isa_dev)
46 return pregs; 48 return pregs;
47} 49}
48 50
49/* I can't believe they didn't put a real INO in the isa device
50 * interrupts property. The whole point of the OBP properties
51 * is to shield the kernel from IRQ routing details.
52 *
53 * The P1275 standard for ISA devices seems to also have been
54 * totally ignored.
55 *
56 * On later systems, an interrupt-map and interrupt-map-mask scheme
57 * akin to EBUS is used.
58 */
59static struct {
60 int obp_irq;
61 int pci_ino;
62} grover_irq_table[] = {
63 { 1, 0x00 }, /* dma, unknown ino at this point */
64 { 2, 0x27 }, /* floppy */
65 { 3, 0x22 }, /* parallel */
66 { 4, 0x2b }, /* serial */
67 { 5, 0x25 }, /* acpi power management */
68
69 { 0, 0x00 } /* end of table */
70};
71
72static int __init isa_dev_get_irq_using_imap(struct sparc_isa_device *isa_dev,
73 struct sparc_isa_bridge *isa_br,
74 int *interrupt,
75 struct linux_prom_registers *reg)
76{
77 struct linux_prom_ebus_intmap *imap;
78 struct linux_prom_ebus_intmask *imask;
79 unsigned int hi, lo, irq;
80 int i, len, n_imap;
81
82 imap = of_get_property(isa_br->prom_node, "interrupt-map", &len);
83 if (!imap)
84 return 0;
85 n_imap = len / sizeof(imap[0]);
86
87 imask = of_get_property(isa_br->prom_node, "interrupt-map-mask", NULL);
88 if (!imask)
89 return 0;
90
91 hi = reg->which_io & imask->phys_hi;
92 lo = reg->phys_addr & imask->phys_lo;
93 irq = *interrupt & imask->interrupt;
94 for (i = 0; i < n_imap; i++) {
95 if ((imap[i].phys_hi == hi) &&
96 (imap[i].phys_lo == lo) &&
97 (imap[i].interrupt == irq)) {
98 *interrupt = imap[i].cinterrupt;
99 return 0;
100 }
101 }
102 return -1;
103}
104
105static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev, 51static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev,
106 struct linux_prom_registers *pregs) 52 struct linux_prom_registers *pregs)
107{ 53{
108 int irq_prop; 54 struct of_device *op = of_find_device_by_node(isa_dev->prom_node);
109 55
110 irq_prop = of_getintprop_default(isa_dev->prom_node, 56 if (!op || !op->num_irqs) {
111 "interrupts", -1); 57 isa_dev->irq = PCI_IRQ_NONE;
112 if (irq_prop <= 0) {
113 goto no_irq;
114 } else { 58 } else {
115 struct pci_controller_info *pcic; 59 isa_dev->irq = op->irqs[0];
116 struct pci_pbm_info *pbm;
117 int i;
118
119 if (of_find_property(isa_dev->bus->prom_node,
120 "interrupt-map", NULL)) {
121 if (!isa_dev_get_irq_using_imap(isa_dev,
122 isa_dev->bus,
123 &irq_prop,
124 pregs))
125 goto route_irq;
126 }
127
128 for (i = 0; grover_irq_table[i].obp_irq != 0; i++) {
129 if (grover_irq_table[i].obp_irq == irq_prop) {
130 int ino = grover_irq_table[i].pci_ino;
131
132 if (ino == 0)
133 goto no_irq;
134
135 irq_prop = ino;
136 goto route_irq;
137 }
138 }
139 goto no_irq;
140
141route_irq:
142 pbm = isa_dev->bus->parent;
143 pcic = pbm->parent;
144 isa_dev->irq = pcic->irq_build(pbm, NULL, irq_prop);
145 return;
146 } 60 }
147
148no_irq:
149 isa_dev->irq = PCI_IRQ_NONE;
150} 61}
151 62
152static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev) 63static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)