Annotation of sys/arch/hppa/hppa/autoconf.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: autoconf.c,v 1.50 2007/06/01 22:40:33 miod Exp $ */
2:
3: /*
4: * Copyright (c) 1998-2003 Michael Shalayeff
5: * Copyright (c) 1992, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * This software was developed by the Computer Systems Engineering group
9: * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
10: * contributed to Berkeley.
11: *
12: * All advertising materials mentioning features or use of this software
13: * must display the following acknowledgement:
14: * This product includes software developed by the University of
15: * California, Lawrence Berkeley Laboratory.
16: *
17: * Redistribution and use in source and binary forms, with or without
18: * modification, are permitted provided that the following conditions
19: * are met:
20: * 1. Redistributions of source code must retain the above copyright
21: * notice, this list of conditions and the following disclaimer.
22: * 2. Redistributions in binary form must reproduce the above copyright
23: * notice, this list of conditions and the following disclaimer in the
24: * documentation and/or other materials provided with the distribution.
25: * 3. Neither the name of the University nor the names of its contributors
26: * may be used to endorse or promote products derived from this software
27: * without specific prior written permission.
28: *
29: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39: * SUCH DAMAGE.
40: *
41: * @(#)autoconf.c 8.4 (Berkeley) 10/1/93
42: */
43:
44: #include "pci.h"
45:
46: #include <sys/param.h>
47: #include <sys/systm.h>
48: #include <sys/buf.h>
49: #include <sys/disklabel.h>
50: #include <sys/conf.h>
51: #include <sys/reboot.h>
52: #include <sys/device.h>
53: #include <sys/timeout.h>
54:
55: #include <uvm/uvm_extern.h>
56:
57: #include <machine/iomod.h>
58: #include <machine/autoconf.h>
59:
60: #include <dev/cons.h>
61:
62: #include <hppa/dev/cpudevs.h>
63:
64: #if NPCI > 0
65: #include <dev/pci/pcivar.h>
66: #include <dev/pci/pcireg.h>
67: #endif
68:
69: /* device we booted from */
70: struct device *bootdv;
71: void dumpconf(void);
72:
73: void (*cold_hook)(int); /* see below */
74:
75: /*
76: * LED blinking thing
77: */
78: #ifdef USELEDS
79: #include <sys/dkstat.h>
80: #include <sys/kernel.h>
81:
82: struct timeout heartbeat_tmo;
83: void heartbeat(void *);
84: #endif
85:
86: #include "cd.h"
87: #include "sd.h"
88: #include "st.h"
89: #if NCD > 0 || NSD > 0 || NST > 0
90: #include <scsi/scsi_all.h>
91: #include <scsi/scsiconf.h>
92: #endif
93:
94: #ifdef USELEDS
95: /*
96: * turn the heartbeat alive.
97: * right thing would be to pass counter to each subsequent timeout
98: * as an argument to heartbeat() incrementing every turn,
99: * i.e. avoiding the static hbcnt, but doing timeout_set() on each
100: * timeout_add() sounds ugly, guts of struct timeout looks ugly
101: * to ponder in even more.
102: */
103: void
104: heartbeat(v)
105: void *v;
106: {
107: static u_int hbcnt = 0, ocp_total, ocp_idle;
108: int toggle, cp_mask, cp_total, cp_idle;
109:
110: timeout_add(&heartbeat_tmo, hz / 16);
111:
112: cp_idle = cp_time[CP_IDLE];
113: cp_total = cp_time[CP_USER] + cp_time[CP_NICE] + cp_time[CP_SYS] +
114: cp_time[CP_INTR] + cp_time[CP_IDLE];
115: if (cp_total == ocp_total)
116: cp_total = ocp_total + 1;
117: if (cp_idle == ocp_idle)
118: cp_idle = ocp_idle + 1;
119: cp_mask = 0xf0 >> (cp_idle - ocp_idle) * 4 / (cp_total - ocp_total);
120: cp_mask &= 0xf0;
121: ocp_total = cp_total;
122: ocp_idle = cp_idle;
123: /*
124: * do this:
125: *
126: * |~| |~|
127: * _| |_| |_,_,_,_
128: * 0 1 2 3 4 6 7
129: */
130: toggle = 0;
131: if (hbcnt++ < 8 && hbcnt & 1)
132: toggle = PALED_HEARTBEAT;
133: hbcnt &= 15;
134: ledctl(cp_mask,
135: (~cp_mask & 0xf0) | PALED_NETRCV | PALED_NETSND | PALED_DISK,
136: toggle);
137: }
138: #endif
139:
140: /*
141: * This is called by configure to set dumplo and dumpsize.
142: * Dumps always skip the first CLBYTES of disk space
143: * in case there might be a disk label stored there.
144: * If there is extra space, put dump at the end to
145: * reduce the chance that swapping trashes it.
146: */
147: void
148: dumpconf(void)
149: {
150: extern int dumpsize;
151: int nblks, dumpblks; /* size of dump area */
152:
153: if (dumpdev == NODEV ||
154: (nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0)
155: return;
156: if (nblks <= ctod(1))
157: return;
158:
159: dumpblks = cpu_dumpsize();
160: if (dumpblks < 0)
161: return;
162: dumpblks += ctod(physmem);
163:
164: /* If dump won't fit (incl. room for possible label), punt. */
165: if (dumpblks > (nblks - ctod(1)))
166: return;
167:
168: /* Put dump at end of partition */
169: dumplo = nblks - dumpblks;
170:
171: /* dumpsize is in page units, and doesn't include headers. */
172: dumpsize = physmem;
173: }
174:
175: void
176: print_devpath(const char *label, struct pz_device *pz)
177: {
178: int i;
179:
180: printf("%s: ", label);
181:
182: for (i = 0; i < 6; i++)
183: if (pz->pz_bc[i] >= 0)
184: printf("%d/", pz->pz_bc[i]);
185:
186: printf("%d.%x", pz->pz_mod, pz->pz_layers[0]);
187: for (i = 1; i < 6 && pz->pz_layers[i]; i++)
188: printf(".%x", pz->pz_layers[i]);
189:
190: printf(" class=%d flags=%b hpa=%p spa=%p io=%p\n", pz->pz_class,
191: pz->pz_flags, PZF_BITS, pz->pz_hpa, pz->pz_spa, pz->pz_iodc_io);
192: }
193:
194: struct pdc_memmap pdc_memmap PDC_ALIGNMENT;
195: struct pdc_sysmap_find pdc_find PDC_ALIGNMENT;
196: struct pdc_sysmap_addrs pdc_addr PDC_ALIGNMENT;
197: struct pdc_iodc_read pdc_iodc_read PDC_ALIGNMENT;
198:
199: void
200: pdc_scanbus(self, ca, maxmod, hpa)
201: struct device *self;
202: struct confargs *ca;
203: int maxmod;
204: hppa_hpa_t hpa;
205: {
206: int i;
207:
208: for (i = maxmod; i--; ) {
209: struct confargs nca;
210: int error;
211:
212: bzero(&nca, sizeof(nca));
213: nca.ca_iot = ca->ca_iot;
214: nca.ca_dmatag = ca->ca_dmatag;
215: nca.ca_dp.dp_bc[0] = ca->ca_dp.dp_bc[1];
216: nca.ca_dp.dp_bc[1] = ca->ca_dp.dp_bc[2];
217: nca.ca_dp.dp_bc[2] = ca->ca_dp.dp_bc[3];
218: nca.ca_dp.dp_bc[3] = ca->ca_dp.dp_bc[4];
219: nca.ca_dp.dp_bc[4] = ca->ca_dp.dp_bc[5];
220: nca.ca_dp.dp_bc[5] = ca->ca_dp.dp_mod;
221: nca.ca_dp.dp_mod = i;
222: nca.ca_hpamask = ca->ca_hpamask;
223: nca.ca_naddrs = 0;
224: nca.ca_hpa = 0;
225:
226: if (hpa) {
227: nca.ca_hpa = hpa + IOMOD_HPASIZE * i;
228: nca.ca_dp.dp_mod = i;
229: } else if ((error = pdc_call((iodcio_t)pdc, 0, PDC_MEMMAP,
230: PDC_MEMMAP_HPA, &pdc_memmap, &nca.ca_dp)) == 0)
231: nca.ca_hpa = pdc_memmap.hpa;
232: else if ((error = pdc_call((iodcio_t)pdc, 0, PDC_SYSMAP,
233: PDC_SYSMAP_HPA, &pdc_memmap, &nca.ca_dp)) == 0) {
234: struct device_path path;
235: int im, ia;
236:
237: nca.ca_hpa = pdc_memmap.hpa;
238:
239: for (im = 0; !(error = pdc_call((iodcio_t)pdc, 0,
240: PDC_SYSMAP, PDC_SYSMAP_FIND,
241: &pdc_find, &path, im)) &&
242: pdc_find.hpa != nca.ca_hpa; im++)
243: ;
244:
245: if (!error)
246: nca.ca_hpasz = pdc_find.size << PGSHIFT;
247:
248: if (!error && pdc_find.naddrs) {
249: nca.ca_naddrs = pdc_find.naddrs;
250: if (nca.ca_naddrs > 16) {
251: nca.ca_naddrs = 16;
252: printf("WARNING: too many (%d) addrs\n",
253: pdc_find.naddrs);
254: }
255:
256: if (autoconf_verbose)
257: printf(">> ADDRS:");
258:
259: for (ia = 0; !(error = pdc_call((iodcio_t)pdc,
260: 0, PDC_SYSMAP, PDC_SYSMAP_ADDR, &pdc_addr,
261: im, ia)) && ia < nca.ca_naddrs; ia++) {
262: nca.ca_addrs[ia].addr = pdc_addr.hpa;
263: nca.ca_addrs[ia].size =
264: pdc_addr.size << PGSHIFT;
265:
266: if (autoconf_verbose)
267: printf(" 0x%lx[0x%x]",
268: nca.ca_addrs[ia].addr,
269: nca.ca_addrs[ia].size);
270: }
271: if (autoconf_verbose)
272: printf("\n");
273: }
274: }
275:
276: if (!nca.ca_hpa)
277: continue;
278:
279: if (autoconf_verbose)
280: printf(">> HPA 0x%lx[0x%x]\n",
281: nca.ca_hpa, nca.ca_hpasz);
282:
283: if ((error = pdc_call((iodcio_t)pdc, 0, PDC_IODC,
284: PDC_IODC_READ, &pdc_iodc_read, nca.ca_hpa, IODC_DATA,
285: &nca.ca_type, sizeof(nca.ca_type))) < 0) {
286: if (autoconf_verbose)
287: printf(">> iodc_data error %d\n", error);
288: continue;
289: }
290:
291: nca.ca_pdc_iodc_read = &pdc_iodc_read;
292: nca.ca_name = hppa_mod_info(nca.ca_type.iodc_type,
293: nca.ca_type.iodc_sv_model);
294:
295: if (autoconf_verbose) {
296: printf(">> probing: flags %b bc %d/%d/%d/%d/%d/%d ",
297: nca.ca_dp.dp_flags, PZF_BITS,
298: nca.ca_dp.dp_bc[0], nca.ca_dp.dp_bc[1],
299: nca.ca_dp.dp_bc[2], nca.ca_dp.dp_bc[3],
300: nca.ca_dp.dp_bc[4], nca.ca_dp.dp_bc[5]);
301: printf("mod %x hpa %lx type %x sv %x\n",
302: nca.ca_dp.dp_mod, nca.ca_hpa,
303: nca.ca_type.iodc_type, nca.ca_type.iodc_sv_model);
304: }
305:
306: config_found_sm(self, &nca, mbprint, mbsubmatch);
307: }
308: }
309:
310: const struct hppa_mod_info hppa_knownmods[] = {
311: #include <hppa/dev/cpudevs_data.h>
312: };
313:
314: const char *
315: hppa_mod_info(type, sv)
316: int type, sv;
317: {
318: const struct hppa_mod_info *mi;
319: static char fakeid[32];
320:
321: for (mi = hppa_knownmods; mi->mi_type >= 0 &&
322: (mi->mi_type != type || mi->mi_sv != sv); mi++);
323:
324: if (mi->mi_type < 0) {
325: snprintf(fakeid, sizeof fakeid, "type %x, sv %x", type, sv);
326: return fakeid;
327: } else
328: return mi->mi_name;
329: }
330:
331: void
332: device_register(struct device *dev, void *aux)
333: {
334: #if NPCI > 0
335: extern struct cfdriver pci_cd;
336: #endif
337: struct confargs *ca = aux;
338: char *basename;
339: static struct device *elder = NULL;
340:
341: if (bootdv != NULL)
342: return; /* We already have a winner */
343:
344: #if NPCI > 0
345: if (dev->dv_parent &&
346: dev->dv_parent->dv_cfdata->cf_driver == &pci_cd) {
347: struct pci_attach_args *pa = aux;
348: pcireg_t addr;
349: int reg;
350:
351: for (reg = PCI_MAPREG_START; reg < PCI_MAPREG_END; reg += 4) {
352: addr = pci_conf_read(pa->pa_pc, pa->pa_tag, reg);
353: if (PCI_MAPREG_TYPE(addr) == PCI_MAPREG_TYPE_IO)
354: addr = PCI_MAPREG_IO_ADDR(addr);
355: else
356: addr = PCI_MAPREG_MEM_ADDR(addr);
357:
358: if (addr == (pcireg_t)PAGE0->mem_boot.pz_hpa) {
359: elder = dev;
360: break;
361: }
362: }
363: } else
364: #endif
365: if (ca->ca_hpa == (hppa_hpa_t)PAGE0->mem_boot.pz_hpa) {
366: /*
367: * If hpa matches, the only thing we know is that the
368: * booted device is either this one or one of its children.
369: * And the children will not necessarily have the correct
370: * hpa value.
371: * Save this elder for now.
372: */
373: elder = dev;
374: } else if (elder == NULL) {
375: return; /* not the device we booted from */
376: }
377:
378: /*
379: * Unfortunately, we can not match on pz_class vs dv_class on
380: * older snakes netbooting using the rbootd protocol.
381: * In this case, we'll end up with pz_class == PCL_RANDOM...
382: * Instead, trust the device class from what the kernel attached
383: * now...
384: */
385: switch (dev->dv_class) {
386: case DV_IFNET:
387: /*
388: * Netboot is the top elder
389: */
390: if (elder == dev) {
391: bootdv = dev;
392: }
393: return;
394: case DV_DISK:
395: if ((PAGE0->mem_boot.pz_class & PCL_CLASS_MASK) != PCL_RANDOM)
396: return;
397: break;
398: case DV_TAPE:
399: if ((PAGE0->mem_boot.pz_class & PCL_CLASS_MASK) != PCL_SEQU)
400: return;
401: break;
402: default:
403: /* No idea what we were booted from, but better ask the user */
404: return;
405: }
406:
407: /*
408: * If control goes here, we are booted from a block device and we
409: * matched a block device.
410: */
411: basename = dev->dv_cfdata->cf_driver->cd_name;
412:
413: /*
414: * We only grok SCSI boot currently. Match on proper device hierarchy,
415: * name and unit/lun values.
416: */
417: #if NCD > 0 || NSD > 0 || NST > 0
418: if (strcmp(basename, "sd") == 0 || strcmp(basename, "cd") == 0 ||
419: strcmp(basename, "st") == 0) {
420: struct scsi_attach_args *sa = aux;
421: struct scsi_link *sl = sa->sa_sc_link;
422:
423: /*
424: * sd/st/cd is attached to scsibus which is attached to
425: * the controller. Hence the grandparent here should be
426: * the elder.
427: */
428: if (dev->dv_parent == NULL ||
429: dev->dv_parent->dv_parent != elder) {
430: return;
431: }
432:
433: /*
434: * And now check for proper target and lun values
435: */
436: if (sl->target == PAGE0->mem_boot.pz_layers[0] &&
437: sl->lun == PAGE0->mem_boot.pz_layers[1]) {
438: bootdv = dev;
439: }
440: }
441: #endif
442: }
443:
444: /*
445: * cpu_configure:
446: * called at boot time, configure all devices on system
447: */
448: void
449: cpu_configure(void)
450: {
451: splhigh();
452: if (config_rootfound("mainbus", "mainbus") == NULL)
453: panic("no mainbus found");
454:
455: cpu_intr_init();
456: spl0();
457:
458: print_devpath("bootpath", &PAGE0->mem_boot);
459:
460: if (cold_hook)
461: (*cold_hook)(HPPA_COLD_HOT);
462:
463: #ifdef USELEDS
464: timeout_set(&heartbeat_tmo, heartbeat, NULL);
465: heartbeat(NULL);
466: #endif
467: cold = 0;
468: }
469:
470: void
471: diskconf(void)
472: {
473: setroot(bootdv, 0, RB_USERREQ);
474: dumpconf();
475: }
476:
477: struct nam2blk nam2blk[] = {
478: { "rd", 3 },
479: { "sd", 4 },
480: { "st", 5 },
481: { "cd", 6 },
482: { "fd", 7 },
483: { "wd", 8 },
484: { NULL, -1 }
485: };
CVSweb