diff options
Diffstat (limited to 'arch/sparc64/kernel/isa.c')
-rw-r--r-- | arch/sparc64/kernel/isa.c | 101 |
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 | ||
8 | struct sparc_isa_bridge *isa_chain; | 10 | struct 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 | */ | ||
59 | static 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 | |||
72 | static 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 | |||
105 | static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev, | 51 | static 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 | |||
141 | route_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 | |||
148 | no_irq: | ||
149 | isa_dev->irq = PCI_IRQ_NONE; | ||
150 | } | 61 | } |
151 | 62 | ||
152 | static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev) | 63 | static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev) |