xref: /netbsd-src/sys/arch/hppa/hppa/autoconf.c (revision d1800d86cd4579635984d51cb933ce8ee83addf4)
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
cpu_configure(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
hppa_led_ctl(int off,int on,int toggle)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
hppa_led_blinker(void * arg)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
cpu_dumpconf(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
device_register(device_t dev,void * aux)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
cpu_rootconf(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
hppa_walkbus(struct confargs * ca)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
pdc_scanbus(device_t self,struct confargs * ca,device_t (* callback)(device_t,struct confargs *))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 *
hppa_mod_info(int type,int sv)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 *
hppa_pdcmodule_create(struct hppa_pdcmodule * hm,const char * who)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 *
hppa_memmap_query(struct device_path * devp)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
hppa_pdc_snake_scan(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
hppa_pdc_system_map_scan(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
hppa_modules_scan(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
hppa_modules_done(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