Home | History | Annotate | Line # | Download | only in prep
      1 /*	$NetBSD: autoconf.c,v 1.31 2025/10/04 04:46:56 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2006 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Tim Rightnour
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Setup the system to run on the current machine.
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 __KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.31 2025/10/04 04:46:56 thorpej Exp $");
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/buf.h>
     42 #include <sys/disklabel.h>
     43 #include <sys/conf.h>
     44 #include <sys/reboot.h>
     45 #include <sys/device.h>
     46 #include <sys/queue.h>
     47 
     48 #include <machine/pte.h>
     49 #include <machine/intr.h>
     50 
     51 #include <dev/pci/pcivar.h>
     52 #include <dev/pci/pcidevs.h>
     53 #include <dev/scsipi/scsi_all.h>
     54 #include <dev/scsipi/scsipi_all.h>
     55 #include <dev/scsipi/scsiconf.h>
     56 #include <dev/ata/atavar.h>
     57 #include <dev/ic/wdcvar.h>
     58 #include <machine/isa_machdep.h>
     59 #include <dev/isa/isareg.h>
     60 #include <prep/pnpbus/pnpbusvar.h>
     61 
     62 #include "opt_nvram.h"
     63 
     64 u_long	bootdev = 0;		/* should be dev_t, but not until 32 bits */
     65 extern char bootpath[256];
     66 
     67 static void findroot(void);
     68 
     69 /*
     70  * Determine i/o configuration for a machine.
     71  */
     72 void
     73 cpu_configure(void)
     74 {
     75 	if (config_rootfound("mainbus", NULL) == NULL)
     76 		panic("configure: mainbus not configured");
     77 
     78 	genppc_cpu_configure();
     79 }
     80 
     81 void
     82 cpu_rootconf(void)
     83 {
     84 	findroot();
     85 
     86 	aprint_normal("boot device: %s\n",
     87 	    booted_device ? device_xname(booted_device) : "<unknown>");
     88 
     89 	rootconf();
     90 }
     91 
     92 /*
     93  * On the PReP, we do not have the fw-boot-device readable until the NVRAM
     94  * device is attached.  This occurs rather late in the autoconf process.
     95  * We build a OWF-like device node name for each device and store it in
     96  * fw-path.  Later when trying to figure out our boot device, we will match
     97  * it against these strings.  This serves a dual purpose, because if we ever
     98  * wish to change the bootlist on the machine via the NVRAM, we will have to
     99  * plug in these addresses for each device we want to use.  The kernel can
    100  * then query each device for fw-path, and generate a bootlist string.
    101  */
    102 
    103 void
    104 device_register(device_t dev, void *aux)
    105 {
    106 	device_t parent;
    107 	char devpath[256];
    108 	int n;
    109 
    110 	/* Certain devices will *never* be bootable.  short circuit them. */
    111 
    112 	if (device_is_a(dev, "com") || device_is_a(dev, "attimer") ||
    113 	    device_is_a(dev, "pcppi") || device_is_a(dev, "mcclock") ||
    114 	    device_is_a(dev, "mkclock") || device_is_a(dev, "lpt") ||
    115 	    device_is_a(dev, "pckbc") || device_is_a(dev, "pckbd") ||
    116 	    device_is_a(dev, "vga") || device_is_a(dev, "wsdisplay") ||
    117 	    device_is_a(dev, "wskbd") || device_is_a(dev, "wsmouse") ||
    118 	    device_is_a(dev, "pms") || device_is_a(dev, "cpu"))
    119 		return;
    120 
    121 	if (device_is_a(dev, "pchb")) {
    122 		struct pci_attach_args *pa = aux;
    123 
    124 		if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_MOT &&
    125 		    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_MOT_RAVEN) {
    126 			device_setprop_bool(dev, "prep-raven-pchb", true);
    127 		}
    128 	}
    129 
    130 	if (device_is_a(dev, "mainbus")) {
    131 		device_setprop_string(dev, "prep-fw-path-component", "/");
    132 		return;
    133 	}
    134 	parent = device_parent(dev);
    135 
    136 	n = 0;
    137 	if (device_is_a(dev, "pci")) {
    138 		if (device_is_a(parent, "ppb"))
    139 			n = snprintf(devpath, sizeof(devpath), "");
    140 		else
    141 			n = snprintf(devpath, sizeof(devpath), "pci@%x",
    142 			    prep_io_space_tag.pbs_offset);
    143 	}
    144 	if (device_is_a(parent, "pci")) {
    145 		struct pci_attach_args *pa = aux;
    146 
    147 		n = snprintf(devpath, sizeof(devpath), "pci%x,%x@%x,%x",
    148 		    PCI_VENDOR(pa->pa_id), PCI_PRODUCT(pa->pa_id),
    149 		    pa->pa_device, pa->pa_function);
    150 	}
    151 	if (device_is_a(parent, "pnpbus")) {
    152 		struct pnpbus_dev_attach_args *pna = aux;
    153 		struct pnpbus_io *io;
    154 
    155 		n = snprintf(devpath, sizeof(devpath), "%s@",
    156 		    pna->pna_devid);
    157 		io = SIMPLEQ_FIRST(&pna->pna_res.io);
    158 		if (n > sizeof(devpath))
    159 			n = sizeof(devpath);
    160 		if (io != NULL)
    161 			n += snprintf(devpath + n, sizeof(devpath) - n, "%x",
    162 			    io->minbase);
    163 	}
    164 
    165 	if (n > sizeof(devpath))
    166 		n = sizeof(devpath);
    167 	/* we can't trust the device tag on the ethernet, because
    168 	 * the spec lies about how it is formed.  Therefore we will leave it
    169 	 * blank, and trim the end off any ethernet stuff. */
    170 	if (device_class(dev) == DV_IFNET)
    171 		n += snprintf(devpath + n, sizeof(devpath) - n, ":");
    172 	else if (device_is_a(dev, "cd"))
    173 		n = snprintf(devpath, sizeof(devpath), "cdrom@");
    174 	else if (device_class(dev) == DV_DISK)
    175 		n = snprintf(devpath, sizeof(devpath), "harddisk@");
    176 	else if (device_class(dev) == DV_TAPE)
    177 		n = snprintf(devpath, sizeof(devpath), "tape@");
    178 	else if (device_is_a(dev, "fd"))
    179 		n = snprintf(devpath, sizeof(devpath), "floppy@");
    180 
    181 	if (device_is_a(parent, "scsibus") || device_is_a(parent, "atapibus")) {
    182 		struct scsipibus_attach_args *sa = aux;
    183 
    184 		/* periph_target is target for scsi, drive # for atapi */
    185 		if (n > sizeof(devpath))
    186 			n = sizeof(devpath);
    187 		n += snprintf(devpath + n, sizeof(devpath) - n, "%d",
    188 		    sa->sa_periph->periph_target);
    189 		if (n > sizeof(devpath))
    190 			n = sizeof(devpath);
    191 		if (device_is_a(parent, "scsibus"))
    192 			n += snprintf(devpath + n, sizeof(devpath) - n, ",%d",
    193 			    sa->sa_periph->periph_lun);
    194 	} else if (device_is_a(parent, "atabus") ||
    195 	    device_is_a(parent, "pciide")) {
    196 		struct ata_device *adev = aux;
    197 
    198 		if (n > sizeof(devpath))
    199 			n = sizeof(devpath);
    200 		n += snprintf(devpath + n, sizeof(devpath) - n, "%d",
    201 		    adev->adev_drv_data->drive);
    202 	} else if (device_is_a(dev, "fd")) {
    203 		if (n > sizeof(devpath))
    204 			n = sizeof(devpath);
    205 		/* XXX device_unit() abuse */
    206 		n += snprintf(devpath + n, sizeof(devpath) - n, "%d",
    207 		    device_unit(dev));
    208 	}
    209 
    210 	device_setprop_string(dev, "prep-fw-path-component", devpath);
    211 }
    212 
    213 static void
    214 gen_fwpath(device_t dev)
    215 {
    216 	device_t parent;
    217 	prop_string_t str1, str2, str3;
    218 
    219 	parent = device_parent(dev);
    220 	str1 = prop_dictionary_get(device_properties(dev),
    221 	    "prep-fw-path-component");
    222 	if (str1 == NULL)
    223 		return;
    224 	if (parent == NULL) {
    225 		prop_dictionary_set(device_properties(dev), "prep-fw-path",
    226 		    str1);
    227 		return;
    228 	}
    229 	str2 = prop_dictionary_get(device_properties(parent), "prep-fw-path");
    230 	if (str2 == NULL) {
    231 		prop_dictionary_set(device_properties(dev), "prep-fw-path",
    232 		    str1);
    233 		return;
    234 	}
    235 	str3 = prop_string_copy(str2);
    236 	KASSERT(str3 != NULL);
    237 	if (!(prop_string_equals_cstring(str3, "/") ||
    238 	      prop_string_equals_cstring(str1, "")))
    239 		prop_string_append_cstring(str3, "/");
    240 	if (!prop_string_equals_cstring(str1, "/"))
    241 		prop_string_append(str3, str1);
    242 #if defined(NVRAM_DUMP)
    243 	printf("%s devpath: %s+%s == %s\n", device_xname(dev),
    244 	    prop_string_cstring_nocopy(str2),
    245 	    prop_string_cstring_nocopy(str1),
    246 	    prop_string_cstring_nocopy(str3));
    247 #endif
    248 	(void)prop_dictionary_set(device_properties(dev),
    249 	    "prep-fw-path", str3);
    250 	prop_object_release(str3);
    251 }
    252 
    253 /*
    254  * Generate properties for each device by totaling up its parent device
    255  */
    256 static void
    257 build_fwpath(void)
    258 {
    259 	device_t dev, d;
    260 	deviter_t di, inner_di;
    261 	prop_string_t str1;
    262 
    263 	/* First, find all the PCI busses */
    264 	for (dev = deviter_first(&di, DEVITER_F_ROOT_FIRST); dev != NULL;
    265 	     dev = deviter_next(&di)) {
    266 		if (device_is_a(dev, "pci") || device_is_a(dev, "mainbus") ||
    267 		    device_is_a(dev, "pcib") || device_is_a(dev, "pceb") ||
    268 		    device_is_a(dev, "ppb"))
    269 			gen_fwpath(dev);
    270 	}
    271 	deviter_release(&di);
    272 
    273 	/* Now go find the ISA bus and fix it up */
    274 	for (dev = deviter_first(&di, DEVITER_F_ROOT_FIRST); dev != NULL;
    275 	     dev = deviter_next(&di)) {
    276 		if (device_is_a(dev, "isa"))
    277 			gen_fwpath(dev);
    278 	}
    279 	deviter_release(&di);
    280 
    281 	for (dev = deviter_first(&di, DEVITER_F_ROOT_FIRST); dev != NULL;
    282 	     dev = deviter_next(&di)) {
    283 		/* skip the ones we already computed above */
    284 		if (device_is_a(dev, "pci") || device_is_a(dev, "pcib") ||
    285 		    device_is_a(dev, "pceb") || device_is_a(dev, "isa") ||
    286 		    device_is_a(dev, "ppb"))
    287 			continue;
    288 		/* patch in the properties for the pnpbus */
    289 		if (device_is_a(dev, "pnpbus")) {
    290 			for (d = deviter_first(&inner_di, DEVITER_F_ROOT_FIRST);
    291 			     d != NULL;
    292 			     d = deviter_next(&inner_di)) {
    293 				if (!device_is_a(d, "isa"))
    294 					continue;
    295 				str1 = prop_dictionary_get(device_properties(d),
    296 					"prep-fw-path");
    297 				if (str1 == NULL)
    298 					continue;
    299 				prop_dictionary_set(device_properties(dev),
    300 					"prep-fw-path", str1);
    301 			}
    302 			deviter_release(&inner_di);
    303 		} else
    304 			gen_fwpath(dev);
    305 	}
    306 	deviter_release(&di);
    307 }
    308 
    309 
    310 /*
    311  * This routine looks at each device, and tries to match them to the bootpath
    312  */
    313 
    314 void
    315 findroot(void)
    316 {
    317 	device_t d;
    318 	deviter_t di;
    319 	char *cp;
    320 	prop_string_t str;
    321 	size_t len;
    322 
    323 	/* first rebuild all the device paths */
    324 	build_fwpath();
    325 
    326 	/* now trim the ethernet crap off the bootpath */
    327 	cp = strchr(bootpath, ':');
    328 	if (cp != NULL) {
    329 		cp++;
    330 		*cp = '\0';
    331 	}
    332 	len = strlen(bootpath);
    333 #if defined(NVRAM_DUMP)
    334 	printf("Modified bootpath: %s\n", bootpath);
    335 #endif
    336 	for (d = deviter_first(&di, DEVITER_F_ROOT_FIRST);
    337 	     d != NULL;
    338 	     d = deviter_next(&di)) {
    339 		str = prop_dictionary_get(device_properties(d), "prep-fw-path");
    340 		if (str == NULL)
    341 			continue;
    342 #if defined(NVRAM_DUMP)
    343 		printf("dev %s: fw-path: %s\n", device_xname(d),
    344 		    prop_string_cstring_nocopy(str));
    345 #endif
    346 		if (strncmp(prop_string_cstring_nocopy(str), bootpath,
    347 		    len) == 0)
    348 			break;
    349 	}
    350 	deviter_release(&di);
    351 	if (d != NULL) {
    352 		booted_device = d;
    353 		booted_partition = 0; /* XXX ??? */
    354 	}
    355 }
    356