1 /* $NetBSD: autoconf.c,v 1.4 2019/04/15 20:46:10 skrll Exp $ */ 2 3 /* $OpenBSD: autoconf.c,v 1.15 2001/06/25 00:43:10 mickey Exp $ */ 4 5 /* 6 * Copyright (c) 1992, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * This software was developed by the Computer Systems Engineering group 10 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 11 * contributed to Berkeley. 12 * 13 * All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Lawrence Berkeley Laboratory. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 1. Redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer. 23 * 2. Redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in the 25 * documentation and/or other materials provided with the distribution. 26 * 3. Neither the name of the University nor the names of its contributors 27 * may be used to endorse or promote products derived from this software 28 * without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 * 42 * @(#)autoconf.c 8.4 (Berkeley) 10/1/93 43 */ 44 45 /* 46 * Copyright (c) 1998-2001 Michael Shalayeff 47 * 48 * This software was developed by the Computer Systems Engineering group 49 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 50 * contributed to Berkeley. 51 * 52 * All advertising materials mentioning features or use of this software 53 * must display the following acknowledgement: 54 * This product includes software developed by the University of 55 * California, Lawrence Berkeley Laboratory. 56 * 57 * Redistribution and use in source and binary forms, with or without 58 * modification, are permitted provided that the following conditions 59 * are met: 60 * 1. Redistributions of source code must retain the above copyright 61 * notice, this list of conditions and the following disclaimer. 62 * 2. Redistributions in binary form must reproduce the above copyright 63 * notice, this list of conditions and the following disclaimer in the 64 * documentation and/or other materials provided with the distribution. 65 * 3. All advertising materials mentioning features or use of this software 66 * must display the following acknowledgement: 67 * This product includes software developed by the University of 68 * California, Berkeley and its contributors. 69 * 4. Neither the name of the University nor the names of its contributors 70 * may be used to endorse or promote products derived from this software 71 * without specific prior written permission. 72 * 73 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 74 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 75 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 76 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 77 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 78 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 79 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 80 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 81 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 82 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 83 * SUCH DAMAGE. 84 * 85 * @(#)autoconf.c 8.4 (Berkeley) 10/1/93 86 */ 87 88 #include <sys/cdefs.h> 89 __KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.4 2019/04/15 20:46:10 skrll Exp $"); 90 91 #include "opt_kgdb.h" 92 #include "opt_useleds.h" 93 94 #include <sys/param.h> 95 #include <sys/systm.h> 96 #include <sys/buf.h> 97 #include <sys/disklabel.h> 98 #include <sys/conf.h> 99 #include <sys/kernel.h> 100 #include <sys/reboot.h> 101 #include <sys/device.h> 102 #include <sys/callout.h> 103 #include <sys/kmem.h> 104 105 #ifdef KGDB 106 #include <sys/kgdb.h> 107 #endif 108 109 #include <machine/pdc.h> 110 #include <machine/iomod.h> 111 #include <machine/autoconf.h> 112 113 #include <dev/pci/pcivar.h> 114 115 #include <dev/scsipi/scsi_all.h> 116 #include <dev/scsipi/scsipi_all.h> 117 #include <dev/scsipi/scsiconf.h> 118 119 #include <dev/cons.h> 120 121 #include <hppa/hppa/machdep.h> 122 #include <hppa/dev/cpudevs.h> 123 #include <hppa/gsc/gscbusvar.h> 124 125 static TAILQ_HEAD(hppa_pdcmodule_head, hppa_pdcmodule) hppa_pdcmodule_list = 126 TAILQ_HEAD_INITIALIZER(hppa_pdcmodule_list); 127 128 struct hppa_pdcmodule { 129 TAILQ_ENTRY(hppa_pdcmodule) hm_link; 130 bool hm_registered; 131 struct pdc_iodc_read hm_pir; 132 struct iodc_data hm_type; 133 struct device_path hm_dp; 134 hppa_hpa_t hm_hpa; 135 u_int hm_hpasz; 136 u_int hm_naddrs; /* only PDC_SYSTEM_MAP */ 137 u_int hm_modindex; /* only PDC_SYSTEM_MAP */ 138 }; 139 140 #define HPPA_SYSTEMMAPMODULES 256 141 142 /* 143 * LED blinking thing 144 */ 145 #ifdef USELEDS 146 int _hppa_led_on_cycles[_HPPA_LEDS_BLINKABLE]; 147 static struct callout hppa_led_callout; 148 static void hppa_led_blinker(void *); 149 extern int hz; 150 #endif 151 152 void (*cold_hook)(int); /* see below */ 153 154 struct hppa_pdcmodule *hppa_pdcmodule_create(struct hppa_pdcmodule *, 155 const char *); 156 void hppa_walkbus(struct confargs *ca); 157 static void hppa_pdc_snake_scan(void); 158 static void hppa_pdc_system_map_scan(void); 159 160 /* 161 * cpu_configure: 162 * called at boot time, configure all devices on system 163 */ 164 void 165 cpu_configure(void) 166 { 167 /* 168 * Consider stopping for a debugger before 169 * autoconfiguration. 170 */ 171 if (boothowto & RB_KDB) { 172 #ifdef KGDB 173 extern int hppa_kgdb_attached; 174 if (hppa_kgdb_attached) 175 kgdb_connect(1); 176 #elif defined(DDB) 177 Debugger(); 178 #endif /* DDB */ 179 } 180 181 splhigh(); 182 if (config_rootfound("mainbus", NULL) == NULL) 183 panic("no mainbus found"); 184 185 /* Allow interrupts - we're trusting spl* here */ 186 hppa_intr_enable(); 187 spl0(); 188 189 if (cold_hook) 190 (*cold_hook)(HPPA_COLD_HOT); 191 192 #ifdef USELEDS 193 memset(_hppa_led_on_cycles, 0, sizeof(_hppa_led_on_cycles)); 194 callout_init(&hppa_led_callout, 0); 195 hppa_led_blinker((void *) 0); 196 #endif 197 } 198 199 #ifdef USELEDS 200 /* 201 * This sets LEDs. 202 */ 203 void 204 hppa_led_ctl(int off, int on, int toggle) 205 { 206 int r; 207 208 if (machine_ledaddr == NULL) 209 return; 210 211 /* The mask is reversed when pushed out to the hardware. */ 212 r = ~(machine_leds = ((machine_leds & ~off) | on) ^ toggle); 213 214 if (machine_ledword) 215 *machine_ledaddr = r; 216 else { 217 #define HPPA_LED_DATA 0x01 218 #define HPPA_LED_STROBE 0x02 219 int b; 220 for (b = 0x80; b; b >>= 1) { 221 *machine_ledaddr = (r & b)? HPPA_LED_DATA : 0; 222 DELAY(1); 223 *machine_ledaddr = ((r & b)? HPPA_LED_DATA : 0) | 224 HPPA_LED_STROBE; 225 } 226 #undef HPPA_LED_DATA 227 #undef HPPA_LED_STROBE 228 } 229 } 230 231 /* 232 * This callout handler blinks LEDs. 233 */ 234 static void 235 hppa_led_blinker(void *arg) 236 { 237 u_int led_cycle = (u_int) arg; 238 int leds, led_i, led; 239 int load; 240 241 /* 242 * Blink the heartbeat LED like this: 243 * 244 * |~| |~| 245 * _| |_| |_,_,_,_ 246 * 0 1 2 3 4 6 7 247 */ 248 #define HPPA_HEARTBEAT_CYCLES (_HPPA_LED_FREQ / 8) 249 if (led_cycle == (0 * HPPA_HEARTBEAT_CYCLES) || 250 led_cycle == (2 * HPPA_HEARTBEAT_CYCLES)) { 251 _hppa_led_on_cycles[HPPA_LED_HEARTBEAT] = 252 HPPA_HEARTBEAT_CYCLES; 253 } 254 255 /* Form the new LED mask. */ 256 leds = 0; 257 for (led_i = 0, led = (1 << 0); 258 led_i < _HPPA_LEDS_BLINKABLE; 259 led_i++, led <<= 1) { 260 if (_hppa_led_on_cycles[led_i] > 0) 261 leds |= led; 262 if (_hppa_led_on_cycles[led_i] >= 0) 263 _hppa_led_on_cycles[led_i]--; 264 } 265 266 /* Add in the system load. */ 267 load = averunnable.ldavg[0] >> FSHIFT; 268 if (load >= (1 << (_HPPA_LEDS_COUNT - _HPPA_LEDS_BLINKABLE))) 269 load = (1 << (_HPPA_LEDS_COUNT - _HPPA_LEDS_BLINKABLE)) - 1; 270 leds |= (load << _HPPA_LEDS_BLINKABLE); 271 272 /* Set the LEDs. */ 273 hppa_led_ctl(-1, leds, 0); 274 275 /* NB: this assumes _HPPA_LED_FREQ is a power of two. */ 276 led_cycle = (led_cycle + 1) & (_HPPA_LED_FREQ - 1); 277 callout_reset(&hppa_led_callout, hz / _HPPA_LED_FREQ, 278 hppa_led_blinker, (void *) led_cycle); 279 280 } 281 #endif /* USELEDS */ 282 283 /* 284 * This is called by configure to set dumplo and dumpsize. 285 * Dumps always skip the first CLBYTES of disk space 286 * in case there might be a disk label stored there. 287 * If there is extra space, put dump at the end to 288 * reduce the chance that swapping trashes it. 289 */ 290 void 291 cpu_dumpconf(void) 292 { 293 extern int dumpsize; 294 int nblks, dumpblks; /* size of dump area */ 295 296 if (dumpdev == NODEV) 297 goto bad; 298 nblks = bdev_size(dumpdev); 299 if (nblks <= ctod(1)) 300 goto bad; 301 dumpblks = cpu_dumpsize(); 302 if (dumpblks < 0) 303 goto bad; 304 dumpblks += ctod(physmem); 305 306 /* If dump won't fit (incl. room for possible label), punt. */ 307 if (dumpblks > (nblks - ctod(1))) 308 goto bad; 309 310 /* Put dump at end of partition */ 311 dumplo = nblks - dumpblks; 312 313 /* dumpsize is in page units, and doesn't include headers. */ 314 dumpsize = physmem; 315 return; 316 317 bad: 318 dumpsize = 0; 319 return; 320 } 321 322 /****************************************************************/ 323 324 device_t boot_device = NULL; 325 326 327 void 328 device_register(device_t dev, void *aux) 329 { 330 int pagezero_cookie; 331 device_t pdev; 332 333 if ((pdev = device_parent(dev)) == NULL || 334 device_parent(pdev) == NULL) 335 return; 336 pagezero_cookie = hppa_pagezero_map(); 337 338 /* 339 * The boot device is described in PAGE0->mem_boot. We need to do it 340 * this way as the MD device path (DP) information in struct confargs 341 * is only available in hppa MD devices. So boot_device is used to 342 * propagate information down the device tree. 343 * 344 * If the boot device is a GSC network device all we need to compare 345 * is the HPA or device path (DP) to get the boot device. 346 * If the boot device is a SCSI device below a GSC attached SCSI 347 * controller PAGE0->mem_boot.pz_hpa contains the HPA of the SCSI 348 * controller. In that case we remember the pointer to the 349 * controller's struct dev in boot_device. The SCSI device is located 350 * later, see below. 351 */ 352 if (device_is_a(pdev, "gsc") || device_is_a(pdev, "phantomas") || 353 device_is_a(pdev, "uturn")) { 354 struct confargs *ca = aux; 355 356 if ((hppa_hpa_t)PAGE0->mem_boot.pz_hpa == ca->ca_hpa) { 357 /* This is (the controller of) the boot device. */ 358 boot_device = dev; 359 } 360 } 361 /* 362 * If the boot device is a PCI device the HPA is the address where the 363 * firmware has mapped the PCI memory of the PCI device. This is quite 364 * device dependent, so we compare the DP. It encodes the bus routing 365 * information to the PCI bus bridge in the DP head and the PCI device 366 * and PCI function in the last two DP components. So we compare the 367 * head of the DP when a PCI bridge attaches and remember the struct 368 * dev of the PCI bridge in boot_dev if it machtes. Later, when PCI 369 * devices are attached, we look if this PCI device hangs below the 370 * boot PCI bridge. If yes we compare the PCI device and PCI function 371 * to the DP tail. In case of a network boot we found the boot device 372 * on a match. In case of a SCSI boot device we have to do the same 373 * check when SCSI devices are attached like on GSC SCSI controllers. 374 */ 375 if (device_is_a(dev, "dino") || device_is_a(dev, "elroy")) { 376 struct confargs *ca = (struct confargs *)aux; 377 int i, n; 378 379 for (n = 0 ; ca->ca_dp.dp_bc[n] < 0 ; n++) { 380 /* Skip unused DP components. */ 381 } 382 for (i = 0 ; i < 6 && n < 6 ; i++) { 383 /* Skip unused DP components... */ 384 if (PAGE0->mem_boot.pz_dp.dp_bc[i] < 0) 385 continue; 386 /* and compare the rest. */ 387 if (PAGE0->mem_boot.pz_dp.dp_bc[i] 388 != ca->ca_dp.dp_bc[n]) { 389 hppa_pagezero_unmap(pagezero_cookie); 390 return; 391 } 392 n++; 393 } 394 if (PAGE0->mem_boot.pz_dp.dp_bc[i] != ca->ca_dp.dp_mod) { 395 hppa_pagezero_unmap(pagezero_cookie); 396 return; 397 } 398 /* This is the PCI host bridge in front of the boot device. */ 399 boot_device = dev; 400 401 } 402 if (device_is_a(dev, "ppb") && boot_device == device_parent(pdev)) { 403 /* 404 * XXX Guesswork. No hardware to test how firmware handles 405 * a ppb. 406 */ 407 struct pci_attach_args *paa = (struct pci_attach_args*)aux; 408 409 if (paa->pa_device == PAGE0->mem_boot.pz_dp.dp_bc[3] && 410 paa->pa_function == PAGE0->mem_boot.pz_dp.dp_bc[4]) { 411 /* 412 * This is the PCI - PCI bridge in front of the boot 413 * device. 414 */ 415 boot_device = dev; 416 } 417 } 418 if (device_is_a(pdev, "pci") && boot_device == device_parent(pdev)) { 419 struct pci_attach_args *paa = (struct pci_attach_args*)aux; 420 421 if (paa->pa_device == PAGE0->mem_boot.pz_dp.dp_bc[5] && 422 paa->pa_function == PAGE0->mem_boot.pz_dp.dp_mod) { 423 /* 424 * This is (the controller of) the boot device. 425 */ 426 boot_device = dev; 427 } 428 } 429 /* 430 * When SCSI devices are attached, we look if the SCSI device hangs 431 * below the controller remembered in boot_device. If so, we compare 432 * the SCSI ID and LUN with the DP layer information. If they match 433 * we found the boot device. 434 */ 435 if (device_is_a(pdev, "scsibus") && 436 boot_device == device_parent(pdev)) { 437 struct scsipibus_attach_args *saa = aux; 438 struct scsipi_periph *p = saa->sa_periph; 439 440 if (p->periph_target == PAGE0->mem_boot.pz_dp.dp_layers[0] && 441 p->periph_lun == PAGE0->mem_boot.pz_dp.dp_layers[1]) { 442 /* This is the boot device. */ 443 boot_device = dev; 444 } 445 } 446 447 hppa_pagezero_unmap(pagezero_cookie); 448 return; 449 } 450 451 /* 452 * Choose root and swap devices. 453 */ 454 void 455 cpu_rootconf(void) 456 { 457 #ifdef DEBUG 458 int pagezero_cookie; 459 int n; 460 461 pagezero_cookie = hppa_pagezero_map(); 462 printf("PROM boot device: hpa %p path ", PAGE0->mem_boot.pz_hpa); 463 for (n = 0 ; n < 6 ; n++) { 464 if (PAGE0->mem_boot.pz_dp.dp_bc[n] >= 0) 465 printf("%d/", PAGE0->mem_boot.pz_dp.dp_bc[n]); 466 } 467 printf("%d dp_layers ", PAGE0->mem_boot.pz_dp.dp_mod); 468 for (n = 0 ; n < 6 ; n++) { 469 printf( "0x%x%c", PAGE0->mem_boot.pz_dp.dp_layers[n], 470 n < 5 ? '/' : ' '); 471 } 472 printf("dp_flags 0x%x pz_class 0x%x\n", PAGE0->mem_boot.pz_dp.dp_flags, 473 PAGE0->mem_boot.pz_class); 474 475 hppa_pagezero_unmap(pagezero_cookie); 476 #endif /* DEBUG */ 477 478 if (boot_device != NULL) 479 printf("boot device: %s\n", device_xname(boot_device)); 480 booted_device = boot_device; 481 rootconf(); 482 } 483 484 void 485 hppa_walkbus(struct confargs *ca) 486 { 487 struct hppa_pdcmodule nhm, *hm; 488 int i; 489 490 if (ca->ca_hpabase == 0) 491 return; 492 493 aprint_debug(">> Walking bus at HPA 0x%lx\n", ca->ca_hpabase); 494 495 for (i = 0; i < ca->ca_nmodules; i++) { 496 int error; 497 498 memset(&nhm, 0, sizeof(nhm)); 499 nhm.hm_dp.dp_bc[0] = ca->ca_dp.dp_bc[1]; 500 nhm.hm_dp.dp_bc[1] = ca->ca_dp.dp_bc[2]; 501 nhm.hm_dp.dp_bc[2] = ca->ca_dp.dp_bc[3]; 502 nhm.hm_dp.dp_bc[3] = ca->ca_dp.dp_bc[4]; 503 nhm.hm_dp.dp_bc[4] = ca->ca_dp.dp_bc[5]; 504 nhm.hm_dp.dp_bc[5] = ca->ca_dp.dp_mod; 505 nhm.hm_hpa = ca->ca_hpabase + IOMOD_HPASIZE * i; 506 nhm.hm_hpasz = 0; 507 nhm.hm_dp.dp_mod = i; 508 nhm.hm_naddrs = 0; 509 510 error = pdcproc_iodc_read(nhm.hm_hpa, IODC_DATA, NULL, 511 &nhm.hm_pir, sizeof(nhm.hm_pir), &nhm.hm_type, 512 sizeof(nhm.hm_type)); 513 if (error < 0) 514 continue; 515 516 aprint_debug(">> HPA 0x%lx[0x%x]", nhm.hm_hpa, 517 nhm.hm_hpasz); 518 519 TAILQ_FOREACH(hm, &hppa_pdcmodule_list, hm_link) { 520 if (nhm.hm_hpa == hm->hm_hpa) { 521 aprint_debug(" found by firmware\n"); 522 break; 523 } 524 } 525 526 /* If we've found the module move onto the next one. */ 527 if (hm) 528 continue; 529 530 /* Expect PDC to report devices of the following types */ 531 if (nhm.hm_type.iodc_type == HPPA_TYPE_FIO) { 532 aprint_debug(" expected to be missing\n"); 533 continue; 534 } 535 536 hppa_pdcmodule_create(&nhm, "Bus walk"); 537 } 538 } 539 540 void 541 pdc_scanbus(device_t self, struct confargs *ca, 542 device_t (*callback)(device_t, struct confargs *)) 543 { 544 struct hppa_pdcmodule *hm; 545 struct confargs nca; 546 device_t dev; 547 int ia; 548 549 hppa_walkbus(ca); 550 551 TAILQ_FOREACH(hm, &hppa_pdcmodule_list, hm_link) { 552 char buf[128]; 553 int error; 554 555 if (hm->hm_registered) 556 continue; 557 558 if (!(hm->hm_dp.dp_bc[0] == ca->ca_dp.dp_bc[1] && 559 hm->hm_dp.dp_bc[1] == ca->ca_dp.dp_bc[2] && 560 hm->hm_dp.dp_bc[2] == ca->ca_dp.dp_bc[3] && 561 hm->hm_dp.dp_bc[3] == ca->ca_dp.dp_bc[4] && 562 hm->hm_dp.dp_bc[4] == ca->ca_dp.dp_bc[5] && 563 hm->hm_dp.dp_bc[5] == ca->ca_dp.dp_mod)) 564 continue; 565 566 memset(&nca, 0, sizeof(nca)); 567 nca.ca_iot = ca->ca_iot; 568 nca.ca_dmatag = ca->ca_dmatag; 569 nca.ca_pir = hm->hm_pir; 570 nca.ca_type = hm->hm_type; 571 nca.ca_hpa = hm->hm_hpa; 572 nca.ca_dp = hm->hm_dp; 573 nca.ca_hpa = hm->hm_hpa; 574 nca.ca_hpasz = hm->hm_hpasz; 575 576 if (hm->hm_naddrs) { 577 if (hm->hm_naddrs > HPPA_MAXIOADDRS) { 578 nca.ca_naddrs = HPPA_MAXIOADDRS; 579 aprint_error("WARNING: too many (%d) addrs\n", 580 hm->hm_naddrs); 581 } else 582 nca.ca_naddrs = hm->hm_naddrs; 583 584 aprint_debug(">> ADDRS[%d/%d]: ", nca.ca_naddrs, 585 hm->hm_modindex); 586 587 KASSERT(hm->hm_modindex != -1); 588 for (ia = 0; ia < nca.ca_naddrs; ia++) { 589 struct pdc_system_map_find_addr pdc_find_addr; 590 591 error = pdcproc_system_map_find_addr( 592 &pdc_find_addr, hm->hm_modindex, ia + 1); 593 if (error < 0) 594 break; 595 nca.ca_addrs[ia].addr = pdc_find_addr.hpa; 596 nca.ca_addrs[ia].size = 597 pdc_find_addr.size << PGSHIFT; 598 599 aprint_debug(" 0x%lx[0x%x]", 600 nca.ca_addrs[ia].addr, 601 nca.ca_addrs[ia].size); 602 } 603 aprint_debug("\n"); 604 } 605 606 aprint_debug(">> HPA 0x%lx[0x%x]\n", nca.ca_hpa, 607 nca.ca_hpasz); 608 609 snprintb(buf, sizeof(buf), PZF_BITS, nca.ca_dp.dp_flags); 610 aprint_debug(">> probing: flags %s ", buf); 611 if (nca.ca_dp.dp_mod >=0) { 612 int n; 613 614 aprint_debug(" path "); 615 for (n = 0; n < 6; n++) { 616 if (nca.ca_dp.dp_bc[n] >= 0) 617 aprint_debug("%d/", 618 nca.ca_dp.dp_bc[n]); 619 } 620 aprint_debug("%d", nca.ca_dp.dp_mod); 621 } 622 623 aprint_debug(" type %x sv %x\n", 624 nca.ca_type.iodc_type, nca.ca_type.iodc_sv_model); 625 626 nca.ca_irq = HPPACF_IRQ_UNDEF; 627 nca.ca_name = hppa_mod_info(nca.ca_type.iodc_type, 628 nca.ca_type.iodc_sv_model); 629 630 dev = callback(self, &nca); 631 632 if (dev) 633 hm->hm_registered = true; 634 } 635 } 636 637 static const struct hppa_mod_info hppa_knownmods[] = { 638 #include <hppa/dev/cpudevs_data.h> 639 }; 640 641 const char * 642 hppa_mod_info(int type, int sv) 643 { 644 const struct hppa_mod_info *mi; 645 static char fakeid[32]; 646 int i; 647 648 for (i = 0, mi = hppa_knownmods; i < __arraycount(hppa_knownmods); 649 i++, mi++) { 650 if (mi->mi_type == type && mi->mi_sv == sv) { 651 break; 652 } 653 } 654 655 if (i == __arraycount(hppa_knownmods)) { 656 snprintf(fakeid, sizeof(fakeid), "type %x, sv %x", type, sv); 657 return fakeid; 658 } 659 660 return mi->mi_name; 661 } 662 663 /* 664 * Create the device on our device list. Keep the devices in order. */ 665 struct hppa_pdcmodule * 666 hppa_pdcmodule_create(struct hppa_pdcmodule *hm, const char *who) 667 { 668 struct hppa_pdcmodule *nhm, *ahm; 669 int i; 670 671 nhm = kmem_zalloc(sizeof(*nhm), KM_SLEEP); 672 673 nhm->hm_registered = false; 674 nhm->hm_pir = hm->hm_pir; 675 nhm->hm_type = hm->hm_type; 676 nhm->hm_dp = hm->hm_dp; 677 nhm->hm_hpa = hm->hm_hpa; 678 nhm->hm_hpasz = hm->hm_hpasz; 679 nhm->hm_naddrs = hm->hm_naddrs; 680 nhm->hm_modindex = hm->hm_modindex; 681 682 /* Find start of new path */ 683 for (i = 0; i < 6; i++) { 684 if (hm->hm_dp.dp_bc[i] != -1) 685 break; 686 } 687 688 /* 689 * Look, in reverse, for the first device that has a path before our 690 * new one. In reverse because PDC reports most (all?) devices in path 691 * order and therefore the common case is to add to the end of the 692 * list. 693 */ 694 TAILQ_FOREACH_REVERSE(ahm, &hppa_pdcmodule_list, hppa_pdcmodule_head, 695 hm_link) { 696 int check; 697 int j, k; 698 699 for (j = 0; j < 6; j++) { 700 if (ahm->hm_dp.dp_bc[j] != -1) 701 break; 702 } 703 704 for (check = 0, k = i; j < 7 && k < 7; j++, k++) { 705 char nid, aid; 706 707 nid = (k == 6) ? hm->hm_dp.dp_mod : hm->hm_dp.dp_bc[k]; 708 aid = (j == 6) ? ahm->hm_dp.dp_mod : ahm->hm_dp.dp_bc[j]; 709 710 if (nid == aid) 711 continue; 712 check = nid - aid; 713 break; 714 } 715 if (check >= 0) 716 break; 717 else if (check < 0) 718 continue; 719 } 720 if (ahm == NULL) 721 TAILQ_INSERT_HEAD(&hppa_pdcmodule_list, nhm, hm_link); 722 else 723 TAILQ_INSERT_AFTER(&hppa_pdcmodule_list, ahm, nhm, hm_link); 724 725 if (hm->hm_dp.dp_mod >= 0) { 726 int n; 727 728 aprint_debug(">> %s device at path ", who); 729 for (n = 0; n < 6; n++) { 730 if (hm->hm_dp.dp_bc[n] >= 0) 731 aprint_debug("%d/", hm->hm_dp.dp_bc[n]); 732 } 733 aprint_debug("%d addrs %d\n", hm->hm_dp.dp_mod, 734 hm->hm_naddrs); 735 } 736 737 return nhm; 738 } 739 740 /* 741 * This is used for Snake machines 742 */ 743 static struct hppa_pdcmodule * 744 hppa_memmap_query(struct device_path *devp) 745 { 746 static struct hppa_pdcmodule nhm; 747 struct pdc_memmap pdc_memmap; 748 int error; 749 750 error = pdcproc_memmap(&pdc_memmap, devp); 751 752 if (error < 0) 753 return NULL; 754 755 memset(&nhm, 0, sizeof(nhm)); 756 nhm.hm_dp = *devp; 757 nhm.hm_hpa = pdc_memmap.hpa; 758 nhm.hm_hpasz = pdc_memmap.morepages; 759 nhm.hm_naddrs = 0; 760 nhm.hm_modindex = -1; 761 762 error = pdcproc_iodc_read(nhm.hm_hpa, IODC_DATA, NULL, &nhm.hm_pir, 763 sizeof(nhm.hm_pir), &nhm.hm_type, sizeof(nhm.hm_type)); 764 765 if (error < 0) 766 return NULL; 767 768 return hppa_pdcmodule_create(&nhm, "PDC (memmap)"); 769 } 770 771 772 static void 773 hppa_pdc_snake_scan(void) 774 { 775 struct device_path path; 776 struct hppa_pdcmodule *hm; 777 int im, ba; 778 779 memset(&path, 0, sizeof(path)); 780 for (im = 0; im < 16; im++) { 781 path.dp_bc[0] = path.dp_bc[1] = path.dp_bc[2] = 782 path.dp_bc[3] = path.dp_bc[4] = path.dp_bc[5] = -1; 783 path.dp_mod = im; 784 785 hm = hppa_memmap_query(&path); 786 787 if (!hm) 788 continue; 789 790 if (hm->hm_type.iodc_type != HPPA_TYPE_BHA) 791 continue; 792 793 path.dp_bc[0] = path.dp_bc[1] = 794 path.dp_bc[2] = path.dp_bc[3] = -1; 795 path.dp_bc[4] = im; 796 path.dp_bc[5] = 0; 797 798 for (ba = 0; ba < 16; ba++) { 799 path.dp_mod = ba; 800 hppa_memmap_query(&path); 801 } 802 } 803 } 804 805 static void 806 hppa_pdc_system_map_scan(void) 807 { 808 struct pdc_system_map_find_mod pdc_find_mod; 809 struct device_path path; 810 struct hppa_pdcmodule hm; 811 int error; 812 int im; 813 814 for (im = 0; im < HPPA_SYSTEMMAPMODULES; im++) { 815 memset(&path, 0, sizeof(path)); 816 error = pdcproc_system_map_find_mod(&pdc_find_mod, &path, im); 817 if (error == PDC_ERR_NMOD) 818 break; 819 820 if (error < 0) 821 continue; 822 823 memset(&hm, 0, sizeof(hm)); 824 hm.hm_dp = path; 825 hm.hm_hpa = pdc_find_mod.hpa; 826 hm.hm_hpasz = pdc_find_mod.size << PGSHIFT; 827 hm.hm_naddrs = pdc_find_mod.naddrs; 828 hm.hm_modindex = im; 829 830 error = pdcproc_iodc_read(hm.hm_hpa, IODC_DATA, NULL, 831 &hm.hm_pir, sizeof(hm.hm_pir), &hm.hm_type, 832 sizeof(hm.hm_type)); 833 if (error < 0) 834 continue; 835 836 hppa_pdcmodule_create(&hm, "PDC (system map)"); 837 } 838 } 839 840 void 841 hppa_modules_scan(void) 842 { 843 switch (pdc_gettype()) { 844 case PDC_TYPE_SNAKE: 845 hppa_pdc_snake_scan(); 846 break; 847 848 case PDC_TYPE_UNKNOWN: 849 hppa_pdc_system_map_scan(); 850 } 851 } 852 853 void 854 hppa_modules_done(void) 855 { 856 struct hppa_pdcmodule *hm, *nhm; 857 858 TAILQ_FOREACH_SAFE(hm, &hppa_pdcmodule_list, hm_link, nhm) { 859 TAILQ_REMOVE(&hppa_pdcmodule_list, hm, hm_link); 860 kmem_free(hm, sizeof(*hm)); 861 } 862 } 863