Annotation of sys/arch/hppa64/hppa64/autoconf.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: autoconf.c,v 1.9 2007/06/01 19:25:09 deraadt Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1998-2005 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: #include <sys/malloc.h>
! 55:
! 56: #include <machine/iomod.h>
! 57: #include <machine/autoconf.h>
! 58: #include <machine/reg.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: void dumpconf(void);
! 70:
! 71: void (*cold_hook)(int); /* see below */
! 72:
! 73: /* device we booted from */
! 74: struct device *bootdv;
! 75:
! 76: /*
! 77: * LED blinking thing
! 78: */
! 79: #ifdef USELEDS
! 80: #include <sys/dkstat.h>
! 81: #include <sys/kernel.h>
! 82:
! 83: struct timeout heartbeat_tmo;
! 84: void heartbeat(void *);
! 85: #endif
! 86:
! 87: #include "cd.h"
! 88: #include "sd.h"
! 89: #include "st.h"
! 90: #if NCD > 0 || NSD > 0 || NST > 0
! 91: #include <scsi/scsi_all.h>
! 92: #include <scsi/scsiconf.h>
! 93: #endif
! 94:
! 95: /*
! 96: * cpu_configure:
! 97: * called at boot time, configure all devices on system
! 98: */
! 99: void
! 100: cpu_configure(void)
! 101: {
! 102: struct confargs ca;
! 103:
! 104: splhigh();
! 105: bzero(&ca, sizeof(ca));
! 106: if (config_rootfound("mainbus", &ca) == NULL)
! 107: panic("no mainbus found");
! 108:
! 109: mtctl(0xffffffffffffffffULL, CR_EIEM);
! 110: spl0();
! 111:
! 112: if (cold_hook)
! 113: (*cold_hook)(HPPA_COLD_HOT);
! 114:
! 115: #ifdef USELEDS
! 116: timeout_set(&heartbeat_tmo, heartbeat, NULL);
! 117: heartbeat(NULL);
! 118: #endif
! 119: cold = 0;
! 120: }
! 121:
! 122: void
! 123: diskconf(void)
! 124: {
! 125: print_devpath("boot path", &PAGE0->mem_boot);
! 126: setroot(bootdv, 0, RB_USERREQ);
! 127: dumpconf();
! 128: }
! 129:
! 130: #ifdef USELEDS
! 131: /*
! 132: * turn the heartbeat alive.
! 133: * right thing would be to pass counter to each subsequent timeout
! 134: * as an argument to heartbeat() incrementing every turn,
! 135: * i.e. avoiding the static hbcnt, but doing timeout_set() on each
! 136: * timeout_add() sounds ugly, guts of struct timeout looks ugly
! 137: * to ponder in even more.
! 138: */
! 139: void
! 140: heartbeat(v)
! 141: void *v;
! 142: {
! 143: static u_int hbcnt = 0, ocp_total, ocp_idle;
! 144: int toggle, cp_mask, cp_total, cp_idle;
! 145:
! 146: timeout_add(&heartbeat_tmo, hz / 16);
! 147:
! 148: cp_idle = cp_time[CP_IDLE];
! 149: cp_total = cp_time[CP_USER] + cp_time[CP_NICE] + cp_time[CP_SYS] +
! 150: cp_time[CP_INTR] + cp_time[CP_IDLE];
! 151: if (cp_total == ocp_total)
! 152: cp_total = ocp_total + 1;
! 153: if (cp_idle == ocp_idle)
! 154: cp_idle = ocp_idle + 1;
! 155: cp_mask = 0xf0 >> (cp_idle - ocp_idle) * 4 / (cp_total - ocp_total);
! 156: cp_mask &= 0xf0;
! 157: ocp_total = cp_total;
! 158: ocp_idle = cp_idle;
! 159: /*
! 160: * do this:
! 161: *
! 162: * |~| |~|
! 163: * _| |_| |_,_,_,_
! 164: * 0 1 2 3 4 6 7
! 165: */
! 166: toggle = 0;
! 167: if (hbcnt++ < 8 && hbcnt & 1)
! 168: toggle = PALED_HEARTBEAT;
! 169: hbcnt &= 15;
! 170: ledctl(cp_mask,
! 171: (~cp_mask & 0xf0) | PALED_NETRCV | PALED_NETSND | PALED_DISK,
! 172: toggle);
! 173: }
! 174: #endif
! 175:
! 176: /*
! 177: * This is called by configure to set dumplo and dumpsize.
! 178: * Dumps always skip the first CLBYTES of disk space
! 179: * in case there might be a disk label stored there.
! 180: * If there is extra space, put dump at the end to
! 181: * reduce the chance that swapping trashes it.
! 182: */
! 183: void
! 184: dumpconf(void)
! 185: {
! 186: extern int dumpsize;
! 187: int nblks, dumpblks; /* size of dump area */
! 188:
! 189: if (dumpdev == NODEV ||
! 190: (nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0)
! 191: return;
! 192: if (nblks <= ctod(1))
! 193: return;
! 194:
! 195: dumpblks = cpu_dumpsize();
! 196: if (dumpblks < 0)
! 197: return;
! 198: dumpblks += ctod(physmem);
! 199:
! 200: /* If dump won't fit (incl. room for possible label), punt. */
! 201: if (dumpblks > (nblks - ctod(1)))
! 202: return;
! 203:
! 204: /* Put dump at end of partition */
! 205: dumplo = nblks - dumpblks;
! 206:
! 207: /* dumpsize is in page units, and doesn't include headers. */
! 208: dumpsize = physmem;
! 209: }
! 210:
! 211:
! 212: void
! 213: print_devpath(const char *label, struct pz_device *pz)
! 214: {
! 215: int i;
! 216:
! 217: printf("%s: ", label);
! 218:
! 219: for (i = 0; i < 6; i++)
! 220: if (pz->pz_bc[i] >= 0)
! 221: printf("%d/", pz->pz_bc[i]);
! 222:
! 223: printf("%d.%x", pz->pz_mod, pz->pz_layers[0]);
! 224: for (i = 1; i < 6 && pz->pz_layers[i]; i++)
! 225: printf(".%x", pz->pz_layers[i]);
! 226:
! 227: printf(" class=%d flags=%b hpa=%p spa=%p io=%p\n", pz->pz_class,
! 228: pz->pz_flags, PZF_BITS, pz->pz_hpa, pz->pz_spa, pz->pz_iodc_io);
! 229: }
! 230:
! 231: u_int32_t pdc_rt[16 / 4 * sizeof(struct pdc_pat_pci_rt)] PDC_ALIGNMENT;
! 232: struct pdc_sysmap_find pdc_find PDC_ALIGNMENT;
! 233: struct pdc_iodc_read pdc_iodc_read PDC_ALIGNMENT;
! 234: struct pdc_pat_cell_id pdc_pat_cell_id PDC_ALIGNMENT;
! 235: struct pdc_pat_cell_module pdc_pat_cell_module PDC_ALIGNMENT;
! 236: struct pdc_pat_io_num pdc_pat_io_num PDC_ALIGNMENT;
! 237: const char *pat_names[] = {
! 238: "central",
! 239: "cpu",
! 240: "memory",
! 241: "sba",
! 242: "lba",
! 243: "pbc",
! 244: "cfc",
! 245: "fabric"
! 246: };
! 247:
! 248: void
! 249: pdc_scan(struct device *self, struct confargs *ca)
! 250: {
! 251: struct device_path path;
! 252: struct confargs nca;
! 253: u_long rv[16];
! 254: int i, err, mod = ca->ca_mod;
! 255:
! 256: if (pdc_call((iodcio_t)pdc, 0, PDC_PAT_CELL, PDC_PAT_CELL_GETID,
! 257: &pdc_pat_cell_id, 0))
! 258: for (i = 0; !(err = pdc_call((iodcio_t)pdc, 0, PDC_SYSMAP,
! 259: PDC_SYSMAP_FIND, &pdc_find, &path, i)); i++) {
! 260: if (autoconf_verbose)
! 261: printf(">> hpa %x/%x dp %d/%d/%d/%d/%d/%d.%d\n",
! 262: pdc_find.hpa, pdc_find.size,
! 263: path.dp_bc[0], path.dp_bc[1], path.dp_bc[2],
! 264: path.dp_bc[3], path.dp_bc[4], path.dp_bc[5],
! 265: path.dp_mod);
! 266:
! 267: if (path.dp_bc[5] == mod) {
! 268: nca = *ca;
! 269: nca.ca_name = NULL;
! 270: nca.ca_hpa = 0xffffffff00000000ULL |
! 271: (hppa_hpa_t)pdc_find.hpa;
! 272: nca.ca_hpasz = pdc_find.size;
! 273: nca.ca_mod = path.dp_mod;
! 274:
! 275: err = pdc_call((iodcio_t)pdc, 0, PDC_IODC,
! 276: PDC_IODC_READ, &pdc_iodc_read, nca.ca_hpa,
! 277: IODC_DATA, &nca.ca_type, sizeof(nca.ca_type));
! 278: if (err < 0 || pdc_iodc_read.size < 8) {
! 279: if (autoconf_verbose)
! 280: printf(">> iodc_data error %d\n", err);
! 281: bzero(&nca.ca_type, sizeof(nca.ca_type));
! 282: }
! 283:
! 284: if (autoconf_verbose) {
! 285: u_int *p = (u_int *)&nca.ca_type;
! 286: printf(">> iodc_data 0x%08x 0x%08x\n",
! 287: p[0], p[1]);
! 288: }
! 289:
! 290: config_found(self, &nca, mbprint);
! 291: }
! 292: }
! 293:
! 294: for (i = 0; !(err = pdc_call((iodcio_t)pdc, 0, PDC_PAT_CELL,
! 295: PDC_PAT_CELL_MODULE, rv, pdc_pat_cell_id.loc, i,
! 296: PDC_PAT_PAVIEW, &pdc_pat_cell_module, 0)); i++) {
! 297: if (autoconf_verbose)
! 298: printf(">> chpa %lx info %lx loc %lx "
! 299: "dp %d/%d/%d/%d/%d/%d.%d\n",
! 300: pdc_pat_cell_module.chpa, pdc_pat_cell_module.info,
! 301: pdc_pat_cell_module.loc,
! 302: pdc_pat_cell_module.dp.dp_bc[0],
! 303: pdc_pat_cell_module.dp.dp_bc[1],
! 304: pdc_pat_cell_module.dp.dp_bc[2],
! 305: pdc_pat_cell_module.dp.dp_bc[3],
! 306: pdc_pat_cell_module.dp.dp_bc[4],
! 307: pdc_pat_cell_module.dp.dp_bc[5],
! 308: pdc_pat_cell_module.dp.dp_mod);
! 309:
! 310: if (pdc_pat_cell_module.dp.dp_bc[5] == mod) {
! 311: int t;
! 312:
! 313: t = PDC_PAT_CELL_MODTYPE(pdc_pat_cell_module.info);
! 314: if (t >= sizeof(pat_names)/sizeof(pat_names[0]))
! 315: continue;
! 316:
! 317: nca = *ca;
! 318: nca.ca_name = pat_names[t];
! 319: nca.ca_hpa = pdc_pat_cell_module.chpa &
! 320: ~(u_long)PAGE_MASK;
! 321: nca.ca_hpasz =
! 322: PDC_PAT_CELL_MODSIZE(pdc_pat_cell_module.info);
! 323: nca.ca_mod = pdc_pat_cell_module.dp.dp_mod;
! 324:
! 325: err = pdc_call((iodcio_t)pdc, 0, PDC_IODC,
! 326: PDC_IODC_READ, &pdc_iodc_read, nca.ca_hpa,
! 327: IODC_DATA, &nca.ca_type, sizeof(nca.ca_type));
! 328: if (err < 0 || pdc_iodc_read.size < 8) {
! 329: if (autoconf_verbose)
! 330: printf(">> iodc_data error %d\n", err);
! 331: bzero(&nca.ca_type, sizeof(nca.ca_type));
! 332: }
! 333: if (autoconf_verbose) {
! 334: u_int *p = (u_int *)&nca.ca_type;
! 335: printf(">> iodc_data 0x%08x 0x%08x\n",
! 336: p[0], p[1]);
! 337: }
! 338:
! 339: config_found(self, &nca, mbprint);
! 340: }
! 341: }
! 342: }
! 343:
! 344: struct pdc_pat_pci_rt *
! 345: pdc_getirt(int *pn)
! 346: {
! 347: struct pdc_pat_pci_rt *rt;
! 348: int i, num, err;
! 349: long cell;
! 350:
! 351: cell = -1;
! 352: if (!pdc_call((iodcio_t)pdc, 0, PDC_PAT_CELL, PDC_PAT_CELL_GETID,
! 353: &pdc_pat_cell_id, 0)) {
! 354: cell = pdc_pat_cell_id.id;
! 355:
! 356: if ((err = pdc_call((iodcio_t)pdc, 0, PDC_PAT_IO,
! 357: PDC_PAT_IO_GET_PCI_RTSZ, &pdc_pat_io_num, cell))) {
! 358: printf("irt size error %d\n", err);
! 359: return (NULL);
! 360: }
! 361: } else if ((err = pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX,
! 362: PDC_PCI_GET_INT_TBL_SZ, &pdc_pat_io_num, cpu_gethpa(0)))) {
! 363: printf("irt size error %d\n", err);
! 364: return (NULL);
! 365: }
! 366:
! 367: printf("num %ld ", pdc_pat_io_num.num);
! 368: *pn = num = pdc_pat_io_num.num;
! 369: if (num > sizeof(pdc_rt) / sizeof(*rt)) {
! 370: printf("\nPCI IRT is too big %d\n", num);
! 371: return (NULL);
! 372: }
! 373:
! 374: if (!(rt = malloc(num * sizeof(*rt), M_DEVBUF, M_NOWAIT)))
! 375: return (NULL);
! 376:
! 377: if (cell >= 0) {
! 378: if ((err = pdc_call((iodcio_t)pdc, 0, PDC_PAT_IO,
! 379: PDC_PAT_IO_GET_PCI_RT, rt, cell))) {
! 380: printf("irt fetch error %d\n", err);
! 381: free(rt, M_DEVBUF);
! 382: return (NULL);
! 383: }
! 384: } else if ((err = pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX,
! 385: PDC_PCI_GET_INT_TBL, &pdc_pat_io_num, cpu_gethpa(0), pdc_rt))) {
! 386: printf("irt fetch error %d\n", err);
! 387: free(rt, M_DEVBUF);
! 388: return (NULL);
! 389: }
! 390: bcopy(pdc_rt, rt, num * sizeof(*rt));
! 391:
! 392: for (i = 0; i < num; i++)
! 393: printf("\n%d: ty 0x%02x it 0x%02x trig 0x%02x pin 0x%02x bus %d seg %d line %d addr 0x%llx",
! 394: i, rt[i].type, rt[i].itype, rt[i].trigger, rt[i].pin, rt[i].bus, rt[i].seg, rt[i].line, rt[i].addr);
! 395: return rt;
! 396: }
! 397:
! 398: const struct hppa_mod_info hppa_knownmods[] = {
! 399: #include <arch/hppa/dev/cpudevs_data.h>
! 400: };
! 401:
! 402: const char *
! 403: hppa_mod_info(type, sv)
! 404: int type, sv;
! 405: {
! 406: const struct hppa_mod_info *mi;
! 407: static char fakeid[32];
! 408:
! 409: for (mi = hppa_knownmods; mi->mi_type >= 0 &&
! 410: (mi->mi_type != type || mi->mi_sv != sv); mi++);
! 411:
! 412: if (mi->mi_type < 0) {
! 413: snprintf(fakeid, sizeof fakeid, "type %x, sv %x", type, sv);
! 414: return fakeid;
! 415: } else
! 416: return mi->mi_name;
! 417: }
! 418:
! 419: void
! 420: device_register(struct device *dev, void *aux)
! 421: {
! 422: #if NPCI > 0
! 423: extern struct cfdriver pci_cd;
! 424: #endif
! 425: struct confargs *ca = aux;
! 426: char *basename;
! 427: static struct device *elder = NULL;
! 428:
! 429: if (bootdv != NULL)
! 430: return; /* We already have a winner */
! 431:
! 432: #if NPCI > 0
! 433: if (dev->dv_parent &&
! 434: dev->dv_parent->dv_cfdata->cf_driver == &pci_cd) {
! 435: struct pci_attach_args *pa = aux;
! 436: pcireg_t addr;
! 437: int reg;
! 438:
! 439: for (reg = PCI_MAPREG_START; reg < PCI_MAPREG_END; reg += 4) {
! 440: addr = pci_conf_read(pa->pa_pc, pa->pa_tag, reg);
! 441: if (PCI_MAPREG_TYPE(addr) == PCI_MAPREG_TYPE_IO)
! 442: addr = PCI_MAPREG_IO_ADDR(addr);
! 443: else
! 444: addr = PCI_MAPREG_MEM_ADDR(addr);
! 445:
! 446: if (addr == (pcireg_t)(u_long)PAGE0->mem_boot.pz_hpa) {
! 447: elder = dev;
! 448: break;
! 449: }
! 450: }
! 451: } else
! 452: #endif
! 453: if (ca->ca_hpa == (hppa_hpa_t)PAGE0->mem_boot.pz_hpa) {
! 454: /*
! 455: * If hpa matches, the only thing we know is that the
! 456: * booted device is either this one or one of its children.
! 457: * And the children will not necessarily have the correct
! 458: * hpa value.
! 459: * Save this elder for now.
! 460: */
! 461: elder = dev;
! 462: } else if (elder == NULL) {
! 463: return; /* not the device we booted from */
! 464: }
! 465:
! 466: /*
! 467: * Unfortunately, we can not match on pz_class vs dv_class on
! 468: * older snakes netbooting using the rbootd protocol.
! 469: * In this case, we'll end up with pz_class == PCL_RANDOM...
! 470: * Instead, trust the device class from what the kernel attached
! 471: * now...
! 472: */
! 473: switch (dev->dv_class) {
! 474: case DV_IFNET:
! 475: /*
! 476: * Netboot is the top elder
! 477: */
! 478: if (elder == dev) {
! 479: bootdv = dev;
! 480: }
! 481: return;
! 482: case DV_DISK:
! 483: if ((PAGE0->mem_boot.pz_class & PCL_CLASS_MASK) != PCL_RANDOM)
! 484: return;
! 485: break;
! 486: case DV_TAPE:
! 487: if ((PAGE0->mem_boot.pz_class & PCL_CLASS_MASK) != PCL_SEQU)
! 488: return;
! 489: break;
! 490: default:
! 491: /* No idea what we were booted from, but better ask the user */
! 492: return;
! 493: }
! 494:
! 495: /*
! 496: * If control goes here, we are booted from a block device and we
! 497: * matched a block device.
! 498: */
! 499: basename = dev->dv_cfdata->cf_driver->cd_name;
! 500:
! 501: /* TODO wd detect */
! 502:
! 503: /*
! 504: * We only grok SCSI boot currently. Match on proper device hierarchy,
! 505: * name and unit/lun values.
! 506: */
! 507: #if NCD > 0 || NSD > 0 || NST > 0
! 508: if (strcmp(basename, "sd") == 0 || strcmp(basename, "cd") == 0 ||
! 509: strcmp(basename, "st") == 0) {
! 510: struct scsi_attach_args *sa = aux;
! 511: struct scsi_link *sl = sa->sa_sc_link;
! 512:
! 513: /*
! 514: * sd/st/cd is attached to scsibus which is attached to
! 515: * the controller. Hence the grandparent here should be
! 516: * the elder.
! 517: */
! 518: if (dev->dv_parent == NULL ||
! 519: dev->dv_parent->dv_parent != elder) {
! 520: return;
! 521: }
! 522:
! 523: /*
! 524: * And now check for proper target and lun values
! 525: */
! 526: if (sl->target == PAGE0->mem_boot.pz_layers[0] &&
! 527: sl->lun == PAGE0->mem_boot.pz_layers[1]) {
! 528: bootdv = dev;
! 529: }
! 530: }
! 531: #endif
! 532: }
! 533:
! 534: struct nam2blk nam2blk[] = {
! 535: { "rd", 3 },
! 536: { "sd", 4 },
! 537: { "st", 5 },
! 538: { "cd", 6 },
! 539: #if 0
! 540: { "wd", ? },
! 541: { "fd", 7 },
! 542: #endif
! 543: { NULL, -1 }
! 544: };
CVSweb