pci_machdep_ofw.c revision 1.10.6.1 1 /* $NetBSD: pci_machdep_ofw.c,v 1.10.6.1 2008/04/03 12:42:23 mjf Exp $ */
2
3 /*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tim Rightnour
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Generic OFW routines for pci_machdep
41 */
42
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: pci_machdep_ofw.c,v 1.10.6.1 2008/04/03 12:42:23 mjf Exp $");
45
46 #include <sys/types.h>
47 #include <sys/param.h>
48 #include <sys/time.h>
49 #include <sys/systm.h>
50 #include <sys/errno.h>
51 #include <sys/device.h>
52 #include <sys/malloc.h>
53
54 #include <uvm/uvm_extern.h>
55
56 #include <machine/bus.h>
57
58 #include <machine/autoconf.h>
59 #include <machine/pio.h>
60 #include <machine/intr.h>
61
62 #include <dev/pci/pcivar.h>
63 #include <dev/pci/pcireg.h>
64 #include <dev/pci/ppbreg.h>
65 #include <dev/pci/pcidevs.h>
66 #include <dev/pci/pciconf.h>
67
68 #include <dev/ofw/openfirm.h>
69 #include <dev/ofw/ofw_pci.h>
70
71 pcitag_t genppc_pci_indirect_make_tag(void *, int, int, int);
72 void genppc_pci_indirect_decompose_tag(void *, pcitag_t, int *, int *, int *);
73
74 ofw_pic_node_t picnodes[8];
75 int nrofpics = 0;
76
77 int
78 genofw_find_picnode(int node)
79 {
80 int i;
81
82 for (i = 0; i < 8; i++)
83 if (node == picnodes[i].node)
84 return i;
85 return -1;
86 }
87
88 void
89 genofw_find_ofpics(int startnode)
90 {
91 int node, iparent, child, iranges[6], irgot=0, i;
92 uint32_t reg[12];
93 char name[32];
94
95 for (node = startnode; node; node = OF_peer(node)) {
96 if ((child = OF_child(node)) != 0)
97 genofw_find_ofpics(child);
98 memset(name, 0, sizeof(name));
99 if (OF_getprop(node, "name", name, sizeof(name)) == -1)
100 continue;
101 if (strncmp(name, "interrupt-controller", 20) == 0)
102 goto foundic;
103
104 if (OF_getprop(node, "interrupt-controller", name,
105 sizeof(name)) > -1)
106 goto foundic;
107
108 if (OF_getprop(node, "device_type", name, sizeof(name)) == -1)
109 continue;
110 if (strncmp(name, "interrupt-controller", 20) == 0)
111 goto foundic;
112
113 /* if we didn't find one, skip to the next */
114 continue;
115 foundic:
116 picnodes[nrofpics].node = node;
117 if (OF_getprop(node, "interrupt-parent", &iparent,
118 sizeof(iparent)) == sizeof(iparent))
119 picnodes[nrofpics].parent = iparent;
120 if (OF_getprop(node, "#interrupt-cells", &iparent,
121 sizeof(iparent)) == sizeof(iparent))
122 picnodes[nrofpics].cells = iparent;
123 else
124 picnodes[nrofpics].cells = 1;
125
126 picnodes[nrofpics].intrs = 0;
127 irgot = OF_getprop(node, "interrupt-ranges", iranges,
128 sizeof(int)*6); /* XXX is this ok? */
129 if (irgot >= sizeof(int)) {
130 for (i=0; i < irgot/4; i++)
131 if (!picnodes[nrofpics].intrs)
132 picnodes[nrofpics].intrs = iranges[i];
133 }
134
135 irgot = OF_getprop(node, "reg", reg, sizeof(reg));
136
137 if (!picnodes[nrofpics].intrs)
138 picnodes[nrofpics].intrs = 16;
139
140 if (nrofpics > 0)
141 picnodes[nrofpics].offset = picnodes[nrofpics-1].offset
142 + picnodes[nrofpics-1].intrs;
143 else
144 picnodes[nrofpics].offset = 0;
145 OF_getprop(node, "device_type", name, sizeof(name));
146 if (strcmp(name, "open-pic") == 0)
147 picnodes[nrofpics].type = PICNODE_TYPE_OPENPIC;
148 if (strcmp(name, "interrupt-controller") == 0) {
149 OF_getprop(node, "compatible", name, sizeof(name));
150 if (strcmp(name, "heathrow") == 0)
151 picnodes[nrofpics].type = PICNODE_TYPE_HEATHROW;
152 if (strcmp(name, "pnpPNP,0") == 0)
153 picnodes[nrofpics].type = PICNODE_TYPE_8259;
154 if (strcmp(name, "chrp,iic") == 0) {
155 picnodes[nrofpics].type = PICNODE_TYPE_8259;
156 if (irgot >= 9 * sizeof(uint32_t) &&
157 reg[7] == 0x4d0)
158 picnodes[nrofpics].type =
159 PICNODE_TYPE_IVR;
160 }
161 }
162 if (strlen(name) == 0) {
163 /* probably a Pegasos, assume 8259 */
164 picnodes[nrofpics].type = PICNODE_TYPE_8259;
165 }
166 nrofpics++;
167 }
168 }
169
170 /* Fix up the various picnode offsets */
171 void
172 genofw_fixup_picnode_offsets(void)
173 {
174 int i, curoff;
175
176 curoff=0;
177
178 for (i=0; i < nrofpics; i++) {
179 if (picnodes[i].type == PICNODE_TYPE_8259 ||
180 picnodes[i].type == PICNODE_TYPE_IVR) {
181 picnodes[i].offset = 0;
182 curoff = picnodes[i].intrs;
183 }
184 }
185 for (i=0; i < nrofpics; i++) {
186 /* now skip the 8259 */
187 if (picnodes[i].type == PICNODE_TYPE_8259)
188 continue;
189 if (picnodes[i].type == PICNODE_TYPE_IVR)
190 continue;
191
192 picnodes[i].offset = curoff;
193 curoff += picnodes[i].intrs;
194 }
195 }
196
197 /* we are given a pci devnode, and dig from there */
198 void
199 genofw_setup_pciintr_map(void *v, struct genppc_pci_chipset_businfo *pbi,
200 int pcinode)
201 {
202 int node;
203 u_int32_t map[160];
204 int parent, len;
205 int curdev, foundirqs=0;
206 int i, reclen, nrofpcidevs=0;
207 u_int32_t acells, icells, pcells;
208 prop_dictionary_t dict;
209 prop_dictionary_t sub=0;
210 pci_chipset_tag_t pc = (pci_chipset_tag_t)v;
211
212 len = OF_getprop(pcinode, "interrupt-map", map, sizeof(map));
213 if (len == -1)
214 goto nomap;
215
216 if (OF_getprop(pcinode, "#address-cells", &acells,
217 sizeof(acells)) == -1)
218 acells = 1;
219 if (OF_getprop(pcinode, "#interrupt-cells", &icells,
220 sizeof(icells)) == -1)
221 icells = 1;
222
223 parent = map[acells+icells];
224 if (OF_getprop(parent, "#interrupt-cells", &pcells,
225 sizeof(pcells)) == -1)
226 pcells = 1;
227
228 reclen = acells+pcells+icells+1;
229 nrofpcidevs = len / (reclen * sizeof(int));
230
231 dict = prop_dictionary_create_with_capacity(nrofpcidevs*2);
232 KASSERT(dict != NULL);
233
234 curdev = -1;
235 prop_dictionary_set(pbi->pbi_properties, "ofw-pci-intrmap", dict);
236 for (i = 0; i < nrofpcidevs; i++) {
237 prop_number_t intr_num;
238 int dev, pin, pic, func;
239 char key[20];
240
241 pic = genofw_find_picnode(map[i*reclen + acells + icells]);
242 KASSERT(pic != -1);
243 dev = (map[i*reclen] >> 8) / 0x8;
244 func = (map[i*reclen] >> 8) % 0x8;
245 if (curdev != dev)
246 sub = prop_dictionary_create_with_capacity(4);
247 pin = map[i*reclen + acells];
248 intr_num = prop_number_create_integer(map[i*reclen + acells + icells + 1] + picnodes[pic].offset);
249 sprintf(key, "pin-%c", 'A' + (pin-1));
250 prop_dictionary_set(sub, key, intr_num);
251 prop_object_release(intr_num);
252 /* should we care about level? */
253
254 sprintf(key, "devfunc-%d", dev*0x8 + func);
255 prop_dictionary_set(dict, key, sub);
256 if (curdev != dev) {
257 prop_object_release(sub);
258 curdev = dev;
259 }
260 }
261 /* the mapping is complete */
262 prop_object_release(dict);
263 aprint_debug("%s\n", prop_dictionary_externalize(pbi->pbi_properties));
264 return;
265
266 nomap:
267 /* so, we have one of those annoying machines that doesn't provide
268 * a nice simple map of interrupts. We get to do this the hard
269 * way instead. Lucky us.
270 */
271 for (node = OF_child(pcinode), nrofpcidevs=0; node;
272 node = OF_peer(node))
273 nrofpcidevs++;
274 dict = prop_dictionary_create_with_capacity(nrofpcidevs*2);
275 KASSERT(dict != NULL);
276 prop_dictionary_set(pbi->pbi_properties, "ofw-pci-intrmap", dict);
277
278 for (node = OF_child(pcinode); node; node = OF_peer(node)) {
279 uint32_t irqs[4], reg[5];
280 prop_number_t intr_num;
281 int dev, pin, func;
282 char key[20];
283
284 /* walk the bus looking for pci devices and map them */
285 if (OF_getprop(node, "AAPL,interrupts", irqs, 4) > 0) {
286 dev = 0;
287 if (OF_getprop(node, "reg", reg, 5) > 0) {
288 dev = ((reg[0] & 0x0000ff00) >> 8) / 0x8;
289 func = ((reg[0] & 0x0000ff00) >> 8) % 0x8;
290 } else if (OF_getprop(node, "assigned-addresses",
291 reg, 5) > 0) {
292 dev = ((reg[0] & 0x0000ff00) >> 8) / 0x8;
293 func = ((reg[0] & 0x0000ff00) >> 8) % 0x8;
294 }
295 if (dev == 0) {
296 aprint_error("cannot figure out device num "
297 "for node 0x%x\n", node);
298 continue;
299 }
300 sub = prop_dictionary_create_with_capacity(4);
301 if (OF_getprop(node, "interrupts", &pin, 4) < 0)
302 pin = 1;
303 intr_num = prop_number_create_integer(irqs[0]);
304 sprintf(key, "pin-%c", 'A' + (pin-1));
305 prop_dictionary_set(sub, key, intr_num);
306 prop_object_release(intr_num);
307 sprintf(key, "devfunc-%d", dev*0x8 + func);
308 prop_dictionary_set(dict, key, sub);
309 prop_object_release(sub);
310 foundirqs++;
311 }
312 }
313 if (foundirqs)
314 return;
315
316 /*
317 * If we got this far, we have a super-annoying OFW.
318 * They didn't bother to fill in any interrupt properties anywhere,
319 * so we pray that they filled in the ones on the pci devices.
320 */
321 for (node = OF_child(pcinode); node; node = OF_peer(node)) {
322 uint32_t reg[5], irq;
323 prop_number_t intr_num;
324 pcitag_t tag;
325 int dev, pin, func;
326 char key[20];
327
328 if (OF_getprop(node, "reg", reg, 5) > 0) {
329 dev = ((reg[0] & 0x0000ff00) >> 8) / 0x8;
330 func = ((reg[0] & 0x0000ff00) >> 8) % 0x8;
331
332 tag = pci_make_tag(pc, pc->pc_bus, dev, func);
333 irq = PCI_INTERRUPT_LINE(pci_conf_read(pc, tag,
334 PCI_INTERRUPT_REG));
335 if (irq == 255)
336 irq = 0;
337
338 sub = prop_dictionary_create_with_capacity(4);
339 if (OF_getprop(node, "interrupts", &pin, 4) < 0)
340 pin = 1;
341 intr_num = prop_number_create_integer(irq);
342 sprintf(key, "pin-%c", 'A' + (pin-1));
343 prop_dictionary_set(sub, key, intr_num);
344 prop_object_release(intr_num);
345 sprintf(key, "devfunc-%d", dev*0x8 + func);
346 prop_dictionary_set(dict, key, sub);
347 prop_object_release(sub);
348 }
349 }
350 aprint_debug("%s\n", prop_dictionary_externalize(pbi->pbi_properties));
351 }
352
353 int
354 genofw_find_node_by_devfunc(int startnode, int bus, int dev, int func)
355 {
356 int node, sz, p=0;
357 uint32_t reg;
358
359 for (node = startnode; node; node = p) {
360 sz = OF_getprop(node, "reg", ®, sizeof(reg));
361 if (sz != sizeof(reg))
362 continue;
363 if (OFW_PCI_PHYS_HI_BUS(reg) == bus &&
364 OFW_PCI_PHYS_HI_DEVICE(reg) == dev &&
365 OFW_PCI_PHYS_HI_FUNCTION(reg) == func)
366 return node;
367 if ((p = OF_child(node)))
368 continue;
369 while (node) {
370 if ((p = OF_peer(node)))
371 break;
372 node = OF_parent(node);
373 }
374 }
375 /* couldn't find it */
376 return -1;
377 }
378
379 int
380 genofw_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
381 {
382 struct genppc_pci_chipset_businfo *pbi;
383 prop_dictionary_t dict, devsub;
384 prop_object_t pinsub;
385 prop_number_t pbus;
386 int busno, bus, pin, line, swiz, dev, origdev, func, i;
387 char key[20];
388
389 pin = pa->pa_intrpin;
390 line = pa->pa_intrline;
391 bus = busno = pa->pa_bus;
392 swiz = pa->pa_intrswiz;
393 origdev = dev = pa->pa_device;
394 func = pa->pa_function;
395 i = 0;
396
397 pbi = SIMPLEQ_FIRST(&pa->pa_pc->pc_pbi);
398 while (busno--)
399 pbi = SIMPLEQ_NEXT(pbi, next);
400 KASSERT(pbi != NULL);
401
402 dict = prop_dictionary_get(pbi->pbi_properties, "ofw-pci-intrmap");
403
404 if (dict != NULL)
405 i = prop_dictionary_count(dict);
406
407 if (dict == NULL || i == 0) {
408 /* We have an unmapped bus, now it gets hard */
409 pbus = prop_dictionary_get(pbi->pbi_properties,
410 "ofw-pcibus-parent");
411 if (pbus == NULL)
412 goto bad;
413 busno = prop_number_integer_value(pbus);
414 pbus = prop_dictionary_get(pbi->pbi_properties,
415 "ofw-pcibus-rawdevnum");
416 dev = prop_number_integer_value(pbus);
417
418 /* now that we know the parent bus, we need to find it's pbi */
419 pbi = SIMPLEQ_FIRST(&pa->pa_pc->pc_pbi);
420 while (busno--)
421 pbi = SIMPLEQ_NEXT(pbi, next);
422 KASSERT(pbi != NULL);
423
424 /* swizzle the pin */
425 pin = ((pin + origdev - 1) & 3) + 1;
426
427 /* now we have the pbi, ask for dict again */
428 dict = prop_dictionary_get(pbi->pbi_properties,
429 "ofw-pci-intrmap");
430 if (dict == NULL)
431 goto bad;
432 }
433
434 /* No IRQ used. */
435 if (pin == 0)
436 goto bad;
437 if (pin > 4) {
438 aprint_error("pci_intr_map: bad interrupt pin %d\n", pin);
439 goto bad;
440 }
441
442 sprintf(key, "devfunc-%d", dev*0x8 + func);
443 devsub = prop_dictionary_get(dict, key);
444 if (devsub == NULL)
445 goto bad;
446 sprintf(key, "pin-%c", 'A' + (pin-1));
447 pinsub = prop_dictionary_get(devsub, key);
448 if (pinsub == NULL)
449 goto bad;
450 line = prop_number_integer_value(pinsub);
451
452 if (line == 0 || line == 255) {
453 aprint_error("pci_intr_map: no mapping for pin %c\n",'@' + pin);
454 goto bad;
455 }
456
457 *ihp = line;
458 return 0;
459
460 bad:
461 *ihp = -1;
462 return 1;
463 }
464
465 int
466 genofw_pci_conf_hook(pci_chipset_tag_t pct, int bus, int dev, int func,
467 pcireg_t id)
468 {
469 struct genppc_pci_chipset_businfo *pbi;
470 prop_number_t pbus;
471 pcitag_t tag;
472 pcireg_t class;
473 int node;
474
475 /* We have already mapped MPIC's if we have them, so leave them alone */
476 if (PCI_VENDOR(id) == PCI_VENDOR_IBM &&
477 PCI_PRODUCT(id) == PCI_PRODUCT_IBM_MPIC2)
478 return 0;
479
480 if (PCI_VENDOR(id) == PCI_VENDOR_IBM &&
481 PCI_PRODUCT(id) == PCI_PRODUCT_IBM_MPIC)
482 return 0;
483
484 /* I highly doubt there are any CHRP ravens, but just in case */
485 if (PCI_VENDOR(id) == PCI_VENDOR_MOT &&
486 PCI_PRODUCT(id) == PCI_PRODUCT_MOT_RAVEN)
487 return (PCI_CONF_ALL & ~PCI_CONF_MAP_MEM);
488
489 /*
490 * Pegasos2 specific stuff.
491 */
492 if (strncmp(model_name, "Pegasos2", 8) == 0) {
493
494 /* never reconfigure the MV64361 host bridge */
495 if (PCI_VENDOR(id) == PCI_VENDOR_MARVELL &&
496 PCI_PRODUCT(id) == PCI_PRODUCT_MARVELL_GT64360)
497 return 0;
498
499 /* we want to leave viaide(4) alone */
500 if (PCI_VENDOR(id) == PCI_VENDOR_VIATECH &&
501 PCI_PRODUCT(id) == PCI_PRODUCT_VIATECH_VT82C586A_IDE)
502 return 0;
503
504 /* leave the audio IO alone */
505 if (PCI_VENDOR(id) == PCI_VENDOR_VIATECH &&
506 PCI_PRODUCT(id) == PCI_PRODUCT_VIATECH_VT82C686A_AC97)
507 return (PCI_CONF_ALL & ~PCI_CONF_MAP_IO);
508
509 }
510
511 tag = pci_make_tag(pct, bus, dev, func);
512 class = pci_conf_read(pct, tag, PCI_CLASS_REG);
513
514 /* leave video cards alone */
515 if (PCI_CLASS(class) == PCI_CLASS_DISPLAY)
516 return 0;
517
518 /* NOTE, all device specific stuff must be above this line */
519 /* don't do this on the primary host bridge */
520 if (bus == 0 && dev == 0 && func == 0)
521 return PCI_CONF_DEFAULT;
522
523 /*
524 * PCI bridges have special needs. We need to discover where they
525 * came from, and wire them appropriately.
526 */
527 if (PCI_CLASS(class) == PCI_CLASS_BRIDGE &&
528 PCI_SUBCLASS(class) == PCI_SUBCLASS_BRIDGE_PCI) {
529 pbi = malloc(sizeof(struct genppc_pci_chipset_businfo),
530 M_DEVBUF, M_NOWAIT);
531 KASSERT(pbi != NULL);
532 pbi->pbi_properties = prop_dictionary_create();
533 KASSERT(pbi->pbi_properties != NULL);
534 node = genofw_find_node_by_devfunc(pct->pc_node, bus, dev,
535 func);
536 if (node == -1) {
537 aprint_error("Cannot find node for device "
538 "bus %d dev %d func %d\n", bus, dev, func);
539 prop_object_release(pbi->pbi_properties);
540 free(pbi, M_DEVBUF);
541 return (PCI_CONF_DEFAULT);
542 }
543 genofw_setup_pciintr_map((void *)pct, pbi, node);
544
545 /* record the parent bus, and the parent device number */
546 pbus = prop_number_create_integer(bus);
547 prop_dictionary_set(pbi->pbi_properties, "ofw-pcibus-parent",
548 pbus);
549 prop_object_release(pbus);
550 pbus = prop_number_create_integer(dev);
551 prop_dictionary_set(pbi->pbi_properties, "ofw-pcibus-rawdevnum",
552 pbus);
553 prop_object_release(pbus);
554
555 SIMPLEQ_INSERT_TAIL(&pct->pc_pbi, pbi, next);
556 }
557
558 return (PCI_CONF_DEFAULT);
559 }
560