ofw_autoconf.c revision 1.4.2.2 1 /* $NetBSD: ofw_autoconf.c,v 1.4.2.2 2007/12/03 19:03:59 ad Exp $ */
2 /*
3 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
4 * Copyright (C) 1995, 1996 TooLs GmbH.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by TooLs GmbH.
18 * 4. The name of TooLs GmbH may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: ofw_autoconf.c,v 1.4.2.2 2007/12/03 19:03:59 ad Exp $");
35
36 #include <sys/param.h>
37 #include <sys/conf.h>
38 #include <sys/device.h>
39 #include <sys/reboot.h>
40 #include <sys/systm.h>
41
42 #include <uvm/uvm_extern.h>
43
44 #include <machine/autoconf.h>
45 #include <machine/bus.h>
46 #include <machine/stdarg.h>
47
48 #include <dev/ofw/openfirm.h>
49 #include <dev/pci/pcivar.h>
50 #include <dev/scsipi/scsi_all.h>
51 #include <dev/scsipi/scsipi_all.h>
52 #include <dev/scsipi/scsiconf.h>
53 #include <dev/ata/atavar.h>
54 #include <dev/ic/wdcvar.h>
55
56 extern char bootpath[256];
57 char cbootpath[256];
58 int console_node = 0, console_instance = 0;
59
60 static void canonicalize_bootpath(void);
61
62 /*
63 * Determine device configuration for a machine.
64 */
65 void
66 cpu_configure(void)
67 {
68 init_interrupt();
69 canonicalize_bootpath();
70
71 if (config_rootfound("mainbus", NULL) == NULL)
72 panic("configure: mainbus not configured");
73
74 genppc_cpu_configure();
75 }
76
77 static void
78 canonicalize_bootpath(void)
79 {
80 int node;
81 char *p, *lastp;
82 char last[32];
83
84 /*
85 * If the bootpath doesn't start with a / then it isn't
86 * an OFW path and probably is an alias, so look up the alias
87 * and regenerate the full bootpath so device_register will work.
88 */
89 if (bootpath[0] != '/' && bootpath[0] != '\0') {
90 int aliases = OF_finddevice("/aliases");
91 char tmpbuf[100];
92 char aliasbuf[256];
93 if (aliases != 0) {
94 char *cp1, *cp2, *cp;
95 char saved_ch = '\0';
96 int len;
97 cp1 = strchr(bootpath, ':');
98 cp2 = strchr(bootpath, ',');
99 cp = cp1;
100 if (cp1 == NULL || (cp2 != NULL && cp2 < cp1))
101 cp = cp2;
102 tmpbuf[0] = '\0';
103 if (cp != NULL) {
104 strcpy(tmpbuf, cp);
105 saved_ch = *cp;
106 *cp = '\0';
107 }
108 len = OF_getprop(aliases, bootpath, aliasbuf,
109 sizeof(aliasbuf));
110 if (len > 0) {
111 if (aliasbuf[len-1] == '\0')
112 len--;
113 memcpy(bootpath, aliasbuf, len);
114 strcpy(&bootpath[len], tmpbuf);
115 } else {
116 *cp = saved_ch;
117 }
118 }
119 }
120
121 /*
122 * Strip kernel name. bootpath contains "OF-path"/"kernel".
123 *
124 * for example:
125 * /bandit@F2000000/gc@10/53c94@10000/sd@0,0/netbsd (OF-1.x)
126 * /pci/mac-io/ata-3@2000/disk@0:0/netbsd.new (OF-3.x)
127 */
128 strcpy(cbootpath, bootpath);
129 while ((node = OF_finddevice(cbootpath)) == -1) {
130 if ((p = strrchr(cbootpath, '/')) == NULL)
131 break;
132 *p = '\0';
133 }
134
135 if (node == -1) {
136 /* Cannot canonicalize... use bootpath anyway. */
137 strcpy(cbootpath, bootpath);
138
139 return;
140 }
141
142 /*
143 * cbootpath is a valid OF path. Use package-to-path to
144 * canonicalize pathname.
145 */
146
147 /* Back up the last component for later use. */
148 if ((p = strrchr(cbootpath, '/')) != NULL)
149 strcpy(last, p + 1);
150 else
151 last[0] = '\0';
152
153 memset(cbootpath, 0, sizeof(cbootpath));
154 OF_package_to_path(node, cbootpath, sizeof(cbootpath) - 1);
155
156 /*
157 * OF_1.x (at least) always returns addr == 0 for
158 * SCSI disks (i.e. "/bandit (at) .../.../sd@0,0").
159 */
160 lastp = strrchr(cbootpath, '/');
161 if (lastp != NULL) {
162 lastp++;
163 if (strncmp(lastp, "sd@", 3) == 0
164 && strncmp(last, "sd@", 3) == 0)
165 strcpy(lastp, last);
166 } else {
167 lastp = cbootpath;
168 }
169
170 /*
171 * At this point, cbootpath contains like:
172 * "/pci@80000000/mac-io@10/ata-3@20000/disk"
173 *
174 * The last component may have no address... so append it.
175 */
176 if (strchr(lastp, '@') == NULL) {
177 /* Append it. */
178 if ((p = strrchr(last, '@')) != NULL)
179 strcat(cbootpath, p);
180 }
181
182 if ((p = strrchr(lastp, ':')) != NULL) {
183 *p++ = '\0';
184 /* booted_partition = *p - '0'; XXX correct? */
185 }
186
187 /* XXX Does this belong here, or device_register()? */
188 if ((p = strrchr(lastp, ',')) != NULL)
189 *p = '\0';
190 }
191
192 /*
193 * device_register is called from config_attach as each device is
194 * attached. We use it to find the NetBSD device corresponding to the
195 * known OF boot device.
196 */
197 void
198 device_register(dev, aux)
199 struct device *dev;
200 void *aux;
201 {
202 static struct device *parent;
203 static char *bp = bootpath + 1, *cp = cbootpath;
204 unsigned long addr;
205 char *p;
206
207 /* Skip over devices not represented in the OF tree. */
208 if (device_is_a(dev, "mainbus")) {
209 parent = dev;
210 return;
211 }
212 if (device_is_a(dev, "atapibus") || device_is_a(dev, "pci") ||
213 device_is_a(dev, "scsibus") || device_is_a(dev, "atabus"))
214 return;
215
216 if (device_is_a(device_parent(dev), "pci")) {
217 /* see if this is going to be console */
218 struct pci_attach_args *pa = aux;
219 prop_dictionary_t dict;
220 int node;
221 char name[32];
222
223 dict = device_properties(dev);
224 node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag);
225
226 if (node != 0) {
227 prop_dictionary_set_uint32(dict, "device_node", node);
228
229 memset(name, 0, sizeof(name));
230 OF_getprop(node, "device_type", name, sizeof(name));
231 if (strcmp(name, "display") == 0) {
232 /* setup display properties for fb driver */
233 prop_dictionary_set_bool(dict, "is_console", 0);
234 copy_disp_props(dev, node, dict);
235 }
236 }
237 }
238
239 if (booted_device)
240 return;
241
242 if (device_is_a(device_parent(dev), "atapibus") ||
243 device_is_a(device_parent(dev), "atabus") ||
244 device_is_a(device_parent(dev), "pci") ||
245 device_is_a(device_parent(dev), "scsibus")) {
246 if (device_parent(device_parent(dev)) != parent)
247 return;
248 } else {
249 if (device_parent(dev) != parent)
250 return;
251 }
252
253 /* Get the address part of the current path component. The
254 * last component of the canonical bootpath may have no
255 * address (eg, "disk"), in which case we need to get the
256 * address from the original bootpath instead.
257 */
258 p = strchr(cp, '@');
259 if (!p) {
260 if (bp)
261 p = strchr(bp, '@');
262 if (!p)
263 addr = 0;
264 else {
265 addr = strtoul(p + 1, NULL, 16);
266 p = NULL;
267 }
268 } else
269 addr = strtoul(p + 1, &p, 16);
270
271 if (device_is_a(device_parent(dev), "mainbus")) {
272 struct confargs *ca = aux;
273
274 if (strcmp(ca->ca_name, "ofw") == 0) /* XXX */
275 return;
276 if (addr != ca->ca_reg[0])
277 return;
278 } else if (device_is_a(device_parent(dev), "pci")) {
279 struct pci_attach_args *pa = aux;
280
281 if (addr != pa->pa_device)
282 return;
283 } else if (device_is_a(device_parent(dev), "obio")) {
284 struct confargs *ca = aux;
285
286 if (addr != ca->ca_reg[0])
287 return;
288 } else if (device_is_a(device_parent(dev), "scsibus") ||
289 device_is_a(device_parent(dev), "atapibus")) {
290 struct scsipibus_attach_args *sa = aux;
291
292 /* periph_target is target for scsi, drive # for atapi */
293 if (addr != sa->sa_periph->periph_target)
294 return;
295 } else if (device_is_a(device_parent(device_parent(dev)), "pciide")) {
296 struct ata_device *adev = aux;
297
298 if (addr != adev->adev_drv_data->drive)
299 return;
300
301 /*
302 * OF splits channel and drive into separate path
303 * components, so check the addr part of the next
304 * component. (Ignore bp, because the canonical path
305 * will be complete in the pciide case.)
306 */
307 p = strchr(p, '@');
308 if (!p++)
309 return;
310 if (strtoul(p, &p, 16) != adev->adev_drv_data->drive)
311 return;
312 } else if (device_is_a(device_parent(device_parent(dev)), "wdc")) {
313 struct ata_device *adev = aux;
314
315 if (addr != adev->adev_drv_data->drive)
316 return;
317 } else
318 return;
319
320 /* If we reach this point, then dev is a match for the current
321 * path component.
322 */
323
324 if (p && *p) {
325 parent = dev;
326 cp = p;
327 bp = strchr(bp, '/');
328 if (bp)
329 bp++;
330 return;
331 } else {
332 booted_device = dev;
333 booted_partition = 0; /* XXX -- should be extracted from bootpath */
334 return;
335 }
336 }
337
338 /*
339 * Setup root device.
340 * Configure swap area.
341 */
342 void
343 cpu_rootconf()
344 {
345 printf("boot device: %s\n",
346 booted_device ? booted_device->dv_xname : "<unknown>");
347
348 setroot(booted_device, booted_partition);
349 }
350
351 /*
352 * Find OF-device corresponding to the PCI device.
353 */
354 int
355 pcidev_to_ofdev(pci_chipset_tag_t pc, pcitag_t tag)
356 {
357 int bus, dev, func;
358 u_int reg[5];
359 int p, q;
360 int l, b, d, f;
361
362 pci_decompose_tag(pc, tag, &bus, &dev, &func);
363
364 for (q = OF_peer(0); q; q = p) {
365 l = OF_getprop(q, "assigned-addresses", reg, sizeof(reg));
366 if (l > 4) {
367 b = (reg[0] >> 16) & 0xff;
368 d = (reg[0] >> 11) & 0x1f;
369 f = (reg[0] >> 8) & 0x07;
370
371 if (b == bus && d == dev && f == func)
372 return q;
373 }
374 if ((p = OF_child(q)))
375 continue;
376 while (q) {
377 if ((p = OF_peer(q)))
378 break;
379 q = OF_parent(q);
380 }
381 }
382 return 0;
383 }
384 /* $NetBSD: ofw_autoconf.c,v 1.4.2.2 2007/12/03 19:03:59 ad Exp $ */
385 /*
386 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
387 * Copyright (C) 1995, 1996 TooLs GmbH.
388 * All rights reserved.
389 *
390 * Redistribution and use in source and binary forms, with or without
391 * modification, are permitted provided that the following conditions
392 * are met:
393 * 1. Redistributions of source code must retain the above copyright
394 * notice, this list of conditions and the following disclaimer.
395 * 2. Redistributions in binary form must reproduce the above copyright
396 * notice, this list of conditions and the following disclaimer in the
397 * documentation and/or other materials provided with the distribution.
398 * 3. All advertising materials mentioning features or use of this software
399 * must display the following acknowledgement:
400 * This product includes software developed by TooLs GmbH.
401 * 4. The name of TooLs GmbH may not be used to endorse or promote products
402 * derived from this software without specific prior written permission.
403 *
404 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
405 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
406 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
407 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
408 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
409 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
410 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
411 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
412 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
413 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
414 */
415
416 #include <sys/cdefs.h>
417 __KERNEL_RCSID(0, "$NetBSD: ofw_autoconf.c,v 1.4.2.2 2007/12/03 19:03:59 ad Exp $");
418
419 #include <sys/param.h>
420 #include <sys/conf.h>
421 #include <sys/device.h>
422 #include <sys/reboot.h>
423 #include <sys/systm.h>
424
425 #include <uvm/uvm_extern.h>
426
427 #include <machine/autoconf.h>
428 #include <machine/bus.h>
429 #include <machine/stdarg.h>
430
431 #include <dev/ofw/openfirm.h>
432 #include <dev/pci/pcivar.h>
433 #include <dev/scsipi/scsi_all.h>
434 #include <dev/scsipi/scsipi_all.h>
435 #include <dev/scsipi/scsiconf.h>
436 #include <dev/ata/atavar.h>
437 #include <dev/ic/wdcvar.h>
438
439 extern char bootpath[256];
440 char cbootpath[256];
441 int console_node = 0, console_instance = 0;
442
443 static void canonicalize_bootpath(void);
444
445 /*
446 * Determine device configuration for a machine.
447 */
448 void
449 cpu_configure(void)
450 {
451 init_interrupt();
452 canonicalize_bootpath();
453
454 if (config_rootfound("mainbus", NULL) == NULL)
455 panic("configure: mainbus not configured");
456
457 genppc_cpu_configure();
458 }
459
460 static void
461 canonicalize_bootpath(void)
462 {
463 int node;
464 char *p, *lastp;
465 char last[32];
466
467 /*
468 * If the bootpath doesn't start with a / then it isn't
469 * an OFW path and probably is an alias, so look up the alias
470 * and regenerate the full bootpath so device_register will work.
471 */
472 if (bootpath[0] != '/' && bootpath[0] != '\0') {
473 int aliases = OF_finddevice("/aliases");
474 char tmpbuf[100];
475 char aliasbuf[256];
476 if (aliases != 0) {
477 char *cp1, *cp2, *cp;
478 char saved_ch = '\0';
479 int len;
480 cp1 = strchr(bootpath, ':');
481 cp2 = strchr(bootpath, ',');
482 cp = cp1;
483 if (cp1 == NULL || (cp2 != NULL && cp2 < cp1))
484 cp = cp2;
485 tmpbuf[0] = '\0';
486 if (cp != NULL) {
487 strcpy(tmpbuf, cp);
488 saved_ch = *cp;
489 *cp = '\0';
490 }
491 len = OF_getprop(aliases, bootpath, aliasbuf,
492 sizeof(aliasbuf));
493 if (len > 0) {
494 if (aliasbuf[len-1] == '\0')
495 len--;
496 memcpy(bootpath, aliasbuf, len);
497 strcpy(&bootpath[len], tmpbuf);
498 } else {
499 *cp = saved_ch;
500 }
501 }
502 }
503
504 /*
505 * Strip kernel name. bootpath contains "OF-path"/"kernel".
506 *
507 * for example:
508 * /bandit@F2000000/gc@10/53c94@10000/sd@0,0/netbsd (OF-1.x)
509 * /pci/mac-io/ata-3@2000/disk@0:0/netbsd.new (OF-3.x)
510 */
511 strcpy(cbootpath, bootpath);
512 while ((node = OF_finddevice(cbootpath)) == -1) {
513 if ((p = strrchr(cbootpath, '/')) == NULL)
514 break;
515 *p = '\0';
516 }
517
518 if (node == -1) {
519 /* Cannot canonicalize... use bootpath anyway. */
520 strcpy(cbootpath, bootpath);
521
522 return;
523 }
524
525 /*
526 * cbootpath is a valid OF path. Use package-to-path to
527 * canonicalize pathname.
528 */
529
530 /* Back up the last component for later use. */
531 if ((p = strrchr(cbootpath, '/')) != NULL)
532 strcpy(last, p + 1);
533 else
534 last[0] = '\0';
535
536 memset(cbootpath, 0, sizeof(cbootpath));
537 OF_package_to_path(node, cbootpath, sizeof(cbootpath) - 1);
538
539 /*
540 * OF_1.x (at least) always returns addr == 0 for
541 * SCSI disks (i.e. "/bandit (at) .../.../sd@0,0").
542 */
543 lastp = strrchr(cbootpath, '/');
544 if (lastp != NULL) {
545 lastp++;
546 if (strncmp(lastp, "sd@", 3) == 0
547 && strncmp(last, "sd@", 3) == 0)
548 strcpy(lastp, last);
549 } else {
550 lastp = cbootpath;
551 }
552
553 /*
554 * At this point, cbootpath contains like:
555 * "/pci@80000000/mac-io@10/ata-3@20000/disk"
556 *
557 * The last component may have no address... so append it.
558 */
559 if (strchr(lastp, '@') == NULL) {
560 /* Append it. */
561 if ((p = strrchr(last, '@')) != NULL)
562 strcat(cbootpath, p);
563 }
564
565 if ((p = strrchr(lastp, ':')) != NULL) {
566 *p++ = '\0';
567 /* booted_partition = *p - '0'; XXX correct? */
568 }
569
570 /* XXX Does this belong here, or device_register()? */
571 if ((p = strrchr(lastp, ',')) != NULL)
572 *p = '\0';
573 }
574
575 /*
576 * device_register is called from config_attach as each device is
577 * attached. We use it to find the NetBSD device corresponding to the
578 * known OF boot device.
579 */
580 void
581 device_register(dev, aux)
582 struct device *dev;
583 void *aux;
584 {
585 static struct device *parent;
586 static char *bp = bootpath + 1, *cp = cbootpath;
587 unsigned long addr;
588 char *p;
589
590 /* Skip over devices not represented in the OF tree. */
591 if (device_is_a(dev, "mainbus")) {
592 parent = dev;
593 return;
594 }
595 if (device_is_a(dev, "atapibus") || device_is_a(dev, "pci") ||
596 device_is_a(dev, "scsibus") || device_is_a(dev, "atabus"))
597 return;
598
599 if (device_is_a(device_parent(dev), "pci")) {
600 /* see if this is going to be console */
601 struct pci_attach_args *pa = aux;
602 prop_dictionary_t dict;
603 int node;
604 char name[32];
605
606 dict = device_properties(dev);
607 node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag);
608
609 if (node != 0) {
610 prop_dictionary_set_uint32(dict, "device_node", node);
611
612 memset(name, 0, sizeof(name));
613 OF_getprop(node, "device_type", name, sizeof(name));
614 if (strcmp(name, "display") == 0) {
615 /* setup display properties for fb driver */
616 prop_dictionary_set_bool(dict, "is_console", 0);
617 copy_disp_props(dev, node, dict);
618 }
619 }
620 }
621
622 if (booted_device)
623 return;
624
625 if (device_is_a(device_parent(dev), "atapibus") ||
626 device_is_a(device_parent(dev), "atabus") ||
627 device_is_a(device_parent(dev), "pci") ||
628 device_is_a(device_parent(dev), "scsibus")) {
629 if (device_parent(device_parent(dev)) != parent)
630 return;
631 } else {
632 if (device_parent(dev) != parent)
633 return;
634 }
635
636 /* Get the address part of the current path component. The
637 * last component of the canonical bootpath may have no
638 * address (eg, "disk"), in which case we need to get the
639 * address from the original bootpath instead.
640 */
641 p = strchr(cp, '@');
642 if (!p) {
643 if (bp)
644 p = strchr(bp, '@');
645 if (!p)
646 addr = 0;
647 else {
648 addr = strtoul(p + 1, NULL, 16);
649 p = NULL;
650 }
651 } else
652 addr = strtoul(p + 1, &p, 16);
653
654 if (device_is_a(device_parent(dev), "mainbus")) {
655 struct confargs *ca = aux;
656
657 if (strcmp(ca->ca_name, "ofw") == 0) /* XXX */
658 return;
659 if (addr != ca->ca_reg[0])
660 return;
661 } else if (device_is_a(device_parent(dev), "pci")) {
662 struct pci_attach_args *pa = aux;
663
664 if (addr != pa->pa_device)
665 return;
666 } else if (device_is_a(device_parent(dev), "obio")) {
667 struct confargs *ca = aux;
668
669 if (addr != ca->ca_reg[0])
670 return;
671 } else if (device_is_a(device_parent(dev), "scsibus") ||
672 device_is_a(device_parent(dev), "atapibus")) {
673 struct scsipibus_attach_args *sa = aux;
674
675 /* periph_target is target for scsi, drive # for atapi */
676 if (addr != sa->sa_periph->periph_target)
677 return;
678 } else if (device_is_a(device_parent(device_parent(dev)), "pciide")) {
679 struct ata_device *adev = aux;
680
681 if (addr != adev->adev_drv_data->drive)
682 return;
683
684 /*
685 * OF splits channel and drive into separate path
686 * components, so check the addr part of the next
687 * component. (Ignore bp, because the canonical path
688 * will be complete in the pciide case.)
689 */
690 p = strchr(p, '@');
691 if (!p++)
692 return;
693 if (strtoul(p, &p, 16) != adev->adev_drv_data->drive)
694 return;
695 } else if (device_is_a(device_parent(device_parent(dev)), "wdc")) {
696 struct ata_device *adev = aux;
697
698 if (addr != adev->adev_drv_data->drive)
699 return;
700 } else
701 return;
702
703 /* If we reach this point, then dev is a match for the current
704 * path component.
705 */
706
707 if (p && *p) {
708 parent = dev;
709 cp = p;
710 bp = strchr(bp, '/');
711 if (bp)
712 bp++;
713 return;
714 } else {
715 booted_device = dev;
716 booted_partition = 0; /* XXX -- should be extracted from bootpath */
717 return;
718 }
719 }
720
721 /*
722 * Setup root device.
723 * Configure swap area.
724 */
725 void
726 cpu_rootconf()
727 {
728 printf("boot device: %s\n",
729 booted_device ? booted_device->dv_xname : "<unknown>");
730
731 setroot(booted_device, booted_partition);
732 }
733
734 /*
735 * Find OF-device corresponding to the PCI device.
736 */
737 int
738 pcidev_to_ofdev(pci_chipset_tag_t pc, pcitag_t tag)
739 {
740 int bus, dev, func;
741 u_int reg[5];
742 int p, q;
743 int l, b, d, f;
744
745 pci_decompose_tag(pc, tag, &bus, &dev, &func);
746
747 for (q = OF_peer(0); q; q = p) {
748 l = OF_getprop(q, "assigned-addresses", reg, sizeof(reg));
749 if (l > 4) {
750 b = (reg[0] >> 16) & 0xff;
751 d = (reg[0] >> 11) & 0x1f;
752 f = (reg[0] >> 8) & 0x07;
753
754 if (b == bus && d == dev && f == func)
755 return q;
756 }
757 if ((p = OF_child(q)))
758 continue;
759 while (q) {
760 if ((p = OF_peer(q)))
761 break;
762 q = OF_parent(q);
763 }
764 }
765 return 0;
766 }
767 /* $NetBSD: ofw_autoconf.c,v 1.4.2.2 2007/12/03 19:03:59 ad Exp $ */
768 /*
769 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
770 * Copyright (C) 1995, 1996 TooLs GmbH.
771 * All rights reserved.
772 *
773 * Redistribution and use in source and binary forms, with or without
774 * modification, are permitted provided that the following conditions
775 * are met:
776 * 1. Redistributions of source code must retain the above copyright
777 * notice, this list of conditions and the following disclaimer.
778 * 2. Redistributions in binary form must reproduce the above copyright
779 * notice, this list of conditions and the following disclaimer in the
780 * documentation and/or other materials provided with the distribution.
781 * 3. All advertising materials mentioning features or use of this software
782 * must display the following acknowledgement:
783 * This product includes software developed by TooLs GmbH.
784 * 4. The name of TooLs GmbH may not be used to endorse or promote products
785 * derived from this software without specific prior written permission.
786 *
787 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
788 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
789 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
790 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
791 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
792 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
793 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
794 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
795 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
796 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
797 */
798
799 #include <sys/cdefs.h>
800 __KERNEL_RCSID(0, "$NetBSD: ofw_autoconf.c,v 1.4.2.2 2007/12/03 19:03:59 ad Exp $");
801
802 #include <sys/param.h>
803 #include <sys/conf.h>
804 #include <sys/device.h>
805 #include <sys/reboot.h>
806 #include <sys/systm.h>
807
808 #include <uvm/uvm_extern.h>
809
810 #include <machine/autoconf.h>
811 #include <machine/bus.h>
812 #include <machine/stdarg.h>
813
814 #include <dev/ofw/openfirm.h>
815 #include <dev/pci/pcivar.h>
816 #include <dev/scsipi/scsi_all.h>
817 #include <dev/scsipi/scsipi_all.h>
818 #include <dev/scsipi/scsiconf.h>
819 #include <dev/ata/atavar.h>
820 #include <dev/ic/wdcvar.h>
821
822 extern char bootpath[256];
823 char cbootpath[256];
824 int console_node = 0, console_instance = 0;
825
826 static void canonicalize_bootpath(void);
827
828 /*
829 * Determine device configuration for a machine.
830 */
831 void
832 cpu_configure(void)
833 {
834 init_interrupt();
835 canonicalize_bootpath();
836
837 if (config_rootfound("mainbus", NULL) == NULL)
838 panic("configure: mainbus not configured");
839
840 genppc_cpu_configure();
841 }
842
843 static void
844 canonicalize_bootpath(void)
845 {
846 int node;
847 char *p, *lastp;
848 char last[32];
849
850 /*
851 * If the bootpath doesn't start with a / then it isn't
852 * an OFW path and probably is an alias, so look up the alias
853 * and regenerate the full bootpath so device_register will work.
854 */
855 if (bootpath[0] != '/' && bootpath[0] != '\0') {
856 int aliases = OF_finddevice("/aliases");
857 char tmpbuf[100];
858 char aliasbuf[256];
859 if (aliases != 0) {
860 char *cp1, *cp2, *cp;
861 char saved_ch = '\0';
862 int len;
863 cp1 = strchr(bootpath, ':');
864 cp2 = strchr(bootpath, ',');
865 cp = cp1;
866 if (cp1 == NULL || (cp2 != NULL && cp2 < cp1))
867 cp = cp2;
868 tmpbuf[0] = '\0';
869 if (cp != NULL) {
870 strcpy(tmpbuf, cp);
871 saved_ch = *cp;
872 *cp = '\0';
873 }
874 len = OF_getprop(aliases, bootpath, aliasbuf,
875 sizeof(aliasbuf));
876 if (len > 0) {
877 if (aliasbuf[len-1] == '\0')
878 len--;
879 memcpy(bootpath, aliasbuf, len);
880 strcpy(&bootpath[len], tmpbuf);
881 } else {
882 *cp = saved_ch;
883 }
884 }
885 }
886
887 /*
888 * Strip kernel name. bootpath contains "OF-path"/"kernel".
889 *
890 * for example:
891 * /bandit@F2000000/gc@10/53c94@10000/sd@0,0/netbsd (OF-1.x)
892 * /pci/mac-io/ata-3@2000/disk@0:0/netbsd.new (OF-3.x)
893 */
894 strcpy(cbootpath, bootpath);
895 while ((node = OF_finddevice(cbootpath)) == -1) {
896 if ((p = strrchr(cbootpath, '/')) == NULL)
897 break;
898 *p = '\0';
899 }
900
901 if (node == -1) {
902 /* Cannot canonicalize... use bootpath anyway. */
903 strcpy(cbootpath, bootpath);
904
905 return;
906 }
907
908 /*
909 * cbootpath is a valid OF path. Use package-to-path to
910 * canonicalize pathname.
911 */
912
913 /* Back up the last component for later use. */
914 if ((p = strrchr(cbootpath, '/')) != NULL)
915 strcpy(last, p + 1);
916 else
917 last[0] = '\0';
918
919 memset(cbootpath, 0, sizeof(cbootpath));
920 OF_package_to_path(node, cbootpath, sizeof(cbootpath) - 1);
921
922 /*
923 * OF_1.x (at least) always returns addr == 0 for
924 * SCSI disks (i.e. "/bandit (at) .../.../sd@0,0").
925 */
926 lastp = strrchr(cbootpath, '/');
927 if (lastp != NULL) {
928 lastp++;
929 if (strncmp(lastp, "sd@", 3) == 0
930 && strncmp(last, "sd@", 3) == 0)
931 strcpy(lastp, last);
932 } else {
933 lastp = cbootpath;
934 }
935
936 /*
937 * At this point, cbootpath contains like:
938 * "/pci@80000000/mac-io@10/ata-3@20000/disk"
939 *
940 * The last component may have no address... so append it.
941 */
942 if (strchr(lastp, '@') == NULL) {
943 /* Append it. */
944 if ((p = strrchr(last, '@')) != NULL)
945 strcat(cbootpath, p);
946 }
947
948 if ((p = strrchr(lastp, ':')) != NULL) {
949 *p++ = '\0';
950 /* booted_partition = *p - '0'; XXX correct? */
951 }
952
953 /* XXX Does this belong here, or device_register()? */
954 if ((p = strrchr(lastp, ',')) != NULL)
955 *p = '\0';
956 }
957
958 /*
959 * device_register is called from config_attach as each device is
960 * attached. We use it to find the NetBSD device corresponding to the
961 * known OF boot device.
962 */
963 void
964 device_register(dev, aux)
965 struct device *dev;
966 void *aux;
967 {
968 static struct device *parent;
969 static char *bp = bootpath + 1, *cp = cbootpath;
970 unsigned long addr;
971 char *p;
972
973 /* Skip over devices not represented in the OF tree. */
974 if (device_is_a(dev, "mainbus")) {
975 parent = dev;
976 return;
977 }
978 if (device_is_a(dev, "atapibus") || device_is_a(dev, "pci") ||
979 device_is_a(dev, "scsibus") || device_is_a(dev, "atabus"))
980 return;
981
982 if (device_is_a(device_parent(dev), "pci")) {
983 /* see if this is going to be console */
984 struct pci_attach_args *pa = aux;
985 prop_dictionary_t dict;
986 int node;
987 char name[32];
988
989 dict = device_properties(dev);
990 node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag);
991
992 if (node != 0) {
993 prop_dictionary_set_uint32(dict, "device_node", node);
994
995 memset(name, 0, sizeof(name));
996 OF_getprop(node, "device_type", name, sizeof(name));
997 if (strcmp(name, "display") == 0) {
998 /* setup display properties for fb driver */
999 prop_dictionary_set_bool(dict, "is_console", 0);
1000 copy_disp_props(dev, node, dict);
1001 }
1002 }
1003 }
1004
1005 if (booted_device)
1006 return;
1007
1008 if (device_is_a(device_parent(dev), "atapibus") ||
1009 device_is_a(device_parent(dev), "atabus") ||
1010 device_is_a(device_parent(dev), "pci") ||
1011 device_is_a(device_parent(dev), "scsibus")) {
1012 if (device_parent(device_parent(dev)) != parent)
1013 return;
1014 } else {
1015 if (device_parent(dev) != parent)
1016 return;
1017 }
1018
1019 /* Get the address part of the current path component. The
1020 * last component of the canonical bootpath may have no
1021 * address (eg, "disk"), in which case we need to get the
1022 * address from the original bootpath instead.
1023 */
1024 p = strchr(cp, '@');
1025 if (!p) {
1026 if (bp)
1027 p = strchr(bp, '@');
1028 if (!p)
1029 addr = 0;
1030 else {
1031 addr = strtoul(p + 1, NULL, 16);
1032 p = NULL;
1033 }
1034 } else
1035 addr = strtoul(p + 1, &p, 16);
1036
1037 if (device_is_a(device_parent(dev), "mainbus")) {
1038 struct confargs *ca = aux;
1039
1040 if (strcmp(ca->ca_name, "ofw") == 0) /* XXX */
1041 return;
1042 if (addr != ca->ca_reg[0])
1043 return;
1044 } else if (device_is_a(device_parent(dev), "pci")) {
1045 struct pci_attach_args *pa = aux;
1046
1047 if (addr != pa->pa_device)
1048 return;
1049 } else if (device_is_a(device_parent(dev), "obio")) {
1050 struct confargs *ca = aux;
1051
1052 if (addr != ca->ca_reg[0])
1053 return;
1054 } else if (device_is_a(device_parent(dev), "scsibus") ||
1055 device_is_a(device_parent(dev), "atapibus")) {
1056 struct scsipibus_attach_args *sa = aux;
1057
1058 /* periph_target is target for scsi, drive # for atapi */
1059 if (addr != sa->sa_periph->periph_target)
1060 return;
1061 } else if (device_is_a(device_parent(device_parent(dev)), "pciide")) {
1062 struct ata_device *adev = aux;
1063
1064 if (addr != adev->adev_drv_data->drive)
1065 return;
1066
1067 /*
1068 * OF splits channel and drive into separate path
1069 * components, so check the addr part of the next
1070 * component. (Ignore bp, because the canonical path
1071 * will be complete in the pciide case.)
1072 */
1073 p = strchr(p, '@');
1074 if (!p++)
1075 return;
1076 if (strtoul(p, &p, 16) != adev->adev_drv_data->drive)
1077 return;
1078 } else if (device_is_a(device_parent(device_parent(dev)), "wdc")) {
1079 struct ata_device *adev = aux;
1080
1081 if (addr != adev->adev_drv_data->drive)
1082 return;
1083 } else
1084 return;
1085
1086 /* If we reach this point, then dev is a match for the current
1087 * path component.
1088 */
1089
1090 if (p && *p) {
1091 parent = dev;
1092 cp = p;
1093 bp = strchr(bp, '/');
1094 if (bp)
1095 bp++;
1096 return;
1097 } else {
1098 booted_device = dev;
1099 booted_partition = 0; /* XXX -- should be extracted from bootpath */
1100 return;
1101 }
1102 }
1103
1104 /*
1105 * Setup root device.
1106 * Configure swap area.
1107 */
1108 void
1109 cpu_rootconf()
1110 {
1111 printf("boot device: %s\n",
1112 booted_device ? booted_device->dv_xname : "<unknown>");
1113
1114 setroot(booted_device, booted_partition);
1115 }
1116
1117 /*
1118 * Find OF-device corresponding to the PCI device.
1119 */
1120 int
1121 pcidev_to_ofdev(pci_chipset_tag_t pc, pcitag_t tag)
1122 {
1123 int bus, dev, func;
1124 u_int reg[5];
1125 int p, q;
1126 int l, b, d, f;
1127
1128 pci_decompose_tag(pc, tag, &bus, &dev, &func);
1129
1130 for (q = OF_peer(0); q; q = p) {
1131 l = OF_getprop(q, "assigned-addresses", reg, sizeof(reg));
1132 if (l > 4) {
1133 b = (reg[0] >> 16) & 0xff;
1134 d = (reg[0] >> 11) & 0x1f;
1135 f = (reg[0] >> 8) & 0x07;
1136
1137 if (b == bus && d == dev && f == func)
1138 return q;
1139 }
1140 if ((p = OF_child(q)))
1141 continue;
1142 while (q) {
1143 if ((p = OF_peer(q)))
1144 break;
1145 q = OF_parent(q);
1146 }
1147 }
1148 return 0;
1149 }
1150