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