Home | History | Annotate | Line # | Download | only in hppa
      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