File: /usr/src/linux/arch/sparc64/kernel/isa.c
1 #include <linux/kernel.h>
2 #include <linux/init.h>
3 #include <linux/pci.h>
4 #include <linux/slab.h>
5 #include <asm/oplib.h>
6 #include <asm/isa.h>
7
8 struct isa_bridge *isa_chain;
9
10 static void __init fatal_err(const char *reason)
11 {
12 prom_printf("ISA: fatal error, %s.\n", reason);
13 }
14
15 static void __init report_dev(struct isa_device *isa_dev, int child)
16 {
17 if (child)
18 printk(" (%s)", isa_dev->prom_name);
19 else
20 printk(" [%s", isa_dev->prom_name);
21 }
22
23 static void __init isa_dev_get_resource(struct isa_device *isa_dev)
24 {
25 struct linux_prom_registers regs[PROMREG_MAX];
26 unsigned long base, len;
27 int prop_len;
28
29 prop_len = prom_getproperty(isa_dev->prom_node, "reg",
30 (char *) regs, sizeof(regs));
31
32 if (prop_len <= 0)
33 return;
34
35 /* Only the first one is interesting. */
36 len = regs[0].reg_size;
37 base = (((unsigned long)regs[0].which_io << 32) |
38 (unsigned long)regs[0].phys_addr);
39 base += isa_dev->bus->parent->io_space.start;
40
41 isa_dev->resource.start = base;
42 isa_dev->resource.end = (base + len - 1UL);
43 isa_dev->resource.flags = IORESOURCE_IO;
44 isa_dev->resource.name = isa_dev->prom_name;
45
46 request_resource(&isa_dev->bus->parent->io_space,
47 &isa_dev->resource);
48 }
49
50 /* I can't believe they didn't put a real INO in the isa device
51 * interrupts property. The whole point of the OBP properties
52 * is to shield the kernel from IRQ routing details.
53 *
54 * The P1275 standard for ISA devices seems to also have been
55 * totally ignored.
56 */
57 static struct {
58 int obp_irq;
59 int pci_ino;
60 } grover_irq_table[] = {
61 { 1, 0x00 }, /* dma, unknown ino at this point */
62 { 2, 0x27 }, /* floppy */
63 { 3, 0x22 }, /* parallel */
64 { 4, 0x2b }, /* serial */
65 { 5, 0x25 }, /* acpi power management */
66
67 { 0, 0x00 } /* end of table */
68 };
69
70 static void __init isa_dev_get_irq(struct isa_device *isa_dev)
71 {
72 int irq_prop;
73
74 irq_prop = prom_getintdefault(isa_dev->prom_node,
75 "interrupts", -1);
76 if (irq_prop <= 0) {
77 isa_dev->irq = 0;
78 } else {
79 int i;
80
81 for (i = 0; grover_irq_table[i].obp_irq != 0; i++) {
82 if (grover_irq_table[i].obp_irq == irq_prop) {
83 struct pci_controller_info *pcic;
84 struct pci_pbm_info *pbm;
85 int ino = grover_irq_table[i].pci_ino;
86
87 if (ino == 0) {
88 isa_dev->irq = 0;
89 } else {
90 pbm = isa_dev->bus->parent;
91 pcic = pbm->parent;
92 isa_dev->irq = pcic->irq_build(pbm, NULL, ino);
93 }
94 }
95 }
96 }
97 }
98
99 static void __init isa_fill_children(struct isa_device *parent_isa_dev)
100 {
101 int node = prom_getchild(parent_isa_dev->prom_node);
102
103 if (node == 0)
104 return;
105
106 printk(" ->");
107 while (node != 0) {
108 struct isa_device *isa_dev;
109 int prop_len;
110
111 isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
112 if (!isa_dev) {
113 fatal_err("cannot allocate child isa_dev");
114 prom_halt();
115 }
116
117 memset(isa_dev, 0, sizeof(*isa_dev));
118
119 /* Link it in to parent. */
120 isa_dev->next = parent_isa_dev->child;
121 parent_isa_dev->child = isa_dev;
122
123 isa_dev->bus = parent_isa_dev->bus;
124 isa_dev->prom_node = node;
125 prop_len = prom_getproperty(node, "name",
126 (char *) isa_dev->prom_name,
127 sizeof(isa_dev->prom_name));
128 if (prop_len <= 0) {
129 fatal_err("cannot get child isa_dev OBP node name");
130 prom_halt();
131 }
132
133 prop_len = prom_getproperty(node, "compatible",
134 (char *) isa_dev->compatible,
135 sizeof(isa_dev->compatible));
136
137 /* Not having this is OK. */
138 if (prop_len <= 0)
139 isa_dev->compatible[0] = '\0';
140
141 isa_dev_get_resource(isa_dev);
142 isa_dev_get_irq(isa_dev);
143
144 report_dev(isa_dev, 1);
145
146 node = prom_getsibling(node);
147 }
148 }
149
150 static void __init isa_fill_devices(struct isa_bridge *isa_br)
151 {
152 int node = prom_getchild(isa_br->prom_node);
153
154 while (node != 0) {
155 struct isa_device *isa_dev;
156 int prop_len;
157
158 isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
159 if (!isa_dev) {
160 fatal_err("cannot allocate isa_dev");
161 prom_halt();
162 }
163
164 memset(isa_dev, 0, sizeof(*isa_dev));
165
166 /* Link it in. */
167 isa_dev->next = NULL;
168 if (isa_br->devices == NULL) {
169 isa_br->devices = isa_dev;
170 } else {
171 struct isa_device *tmp = isa_br->devices;
172
173 while (tmp->next)
174 tmp = tmp->next;
175
176 tmp->next = isa_dev;
177 }
178
179 isa_dev->bus = isa_br;
180 isa_dev->prom_node = node;
181 prop_len = prom_getproperty(node, "name",
182 (char *) isa_dev->prom_name,
183 sizeof(isa_dev->prom_name));
184 if (prop_len <= 0) {
185 fatal_err("cannot get isa_dev OBP node name");
186 prom_halt();
187 }
188
189 prop_len = prom_getproperty(node, "compatible",
190 (char *) isa_dev->compatible,
191 sizeof(isa_dev->compatible));
192
193 /* Not having this is OK. */
194 if (prop_len <= 0)
195 isa_dev->compatible[0] = '\0';
196
197 isa_dev_get_resource(isa_dev);
198 isa_dev_get_irq(isa_dev);
199
200 report_dev(isa_dev, 0);
201
202 isa_fill_children(isa_dev);
203
204 printk("]");
205
206 node = prom_getsibling(node);
207 }
208 }
209
210 void __init isa_init(void)
211 {
212 struct pci_dev *pdev;
213 unsigned short vendor, device;
214 int index = 0;
215
216 vendor = PCI_VENDOR_ID_AL;
217 device = PCI_DEVICE_ID_AL_M1533;
218
219 pdev = NULL;
220 while ((pdev = pci_find_device(vendor, device, pdev)) != NULL) {
221 struct pcidev_cookie *pdev_cookie;
222 struct pci_pbm_info *pbm;
223 struct isa_bridge *isa_br;
224 int prop_len;
225
226 pdev_cookie = pdev->sysdata;
227 if (!pdev_cookie) {
228 printk("ISA: Warning, ISA bridge ignored due to "
229 "lack of OBP data.\n");
230 continue;
231 }
232 pbm = pdev_cookie->pbm;
233
234 isa_br = kmalloc(sizeof(*isa_br), GFP_KERNEL);
235 if (!isa_br) {
236 fatal_err("cannot allocate isa_bridge");
237 prom_halt();
238 }
239
240 memset(isa_br, 0, sizeof(*isa_br));
241
242 /* Link it in. */
243 isa_br->next = isa_chain;
244 isa_chain = isa_br;
245
246 isa_br->parent = pbm;
247 isa_br->self = pdev;
248 isa_br->index = index++;
249 isa_br->prom_node = pdev_cookie->prom_node;
250 strncpy(isa_br->prom_name, pdev_cookie->prom_name,
251 sizeof(isa_br->prom_name));
252
253 prop_len = prom_getproperty(isa_br->prom_node,
254 "ranges",
255 (char *) isa_br->isa_ranges,
256 sizeof(isa_br->isa_ranges));
257 if (prop_len <= 0)
258 isa_br->num_isa_ranges = 0;
259 else
260 isa_br->num_isa_ranges =
261 (prop_len / sizeof(struct linux_prom_isa_ranges));
262
263 printk("isa%d:", isa_br->index);
264
265 isa_fill_devices(isa_br);
266
267 printk("\n");
268 }
269 }
270