xref: /netbsd-src/sys/arch/prep/prep/autoconf.c (revision e5fbc36ada28f9b9a5836ecffaf4a06aa1ebb687)
1 /*	$NetBSD: autoconf.c,v 1.30 2023/12/20 15:29:06 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.30 2023/12/20 15:29:06 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
cpu_configure(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
cpu_rootconf(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
device_register(device_t dev,void * aux)104 device_register(device_t dev, void *aux)
105 {
106 	device_t parent;
107 	char devpath[256];
108 	prop_string_t str1;
109 	int n;
110 
111 	/* Certain devices will *never* be bootable.  short circuit them. */
112 
113 	if (device_is_a(dev, "com") || device_is_a(dev, "attimer") ||
114 	    device_is_a(dev, "pcppi") || device_is_a(dev, "mcclock") ||
115 	    device_is_a(dev, "mkclock") || device_is_a(dev, "lpt") ||
116 	    device_is_a(dev, "pckbc") || device_is_a(dev, "pckbd") ||
117 	    device_is_a(dev, "vga") || device_is_a(dev, "wsdisplay") ||
118 	    device_is_a(dev, "wskbd") || device_is_a(dev, "wsmouse") ||
119 	    device_is_a(dev, "pms") || device_is_a(dev, "cpu"))
120 		return;
121 
122 	if (device_is_a(dev, "pchb")) {
123 		struct pci_attach_args *pa = aux;
124 		prop_bool_t rav;
125 
126 		if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_MOT &&
127 		    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_MOT_RAVEN) {
128 			rav = prop_bool_create(true);
129 			KASSERT(rav != NULL);
130 			(void) prop_dictionary_set(
131 			    device_properties(device_parent(dev)),
132 			    "prep-raven-pchb", rav);
133 			prop_object_release(rav);
134 		}
135 	}
136 
137 	if (device_is_a(dev, "mainbus")) {
138 		str1 = prop_string_create_cstring("/");
139 		KASSERT(str1 != NULL);
140 		(void) prop_dictionary_set(device_properties(dev),
141 					   "prep-fw-path-component", str1);
142 		prop_object_release(str1);
143 		return;
144 	}
145 	parent = device_parent(dev);
146 
147 	n = 0;
148 	if (device_is_a(dev, "pci")) {
149 		if (device_is_a(parent, "ppb"))
150 			n = snprintf(devpath, sizeof(devpath), "");
151 		else
152 			n = snprintf(devpath, sizeof(devpath), "pci@%x",
153 			    prep_io_space_tag.pbs_offset);
154 	}
155 	if (device_is_a(parent, "pci")) {
156 		struct pci_attach_args *pa = aux;
157 
158 		n = snprintf(devpath, sizeof(devpath), "pci%x,%x@%x,%x",
159 		    PCI_VENDOR(pa->pa_id), PCI_PRODUCT(pa->pa_id),
160 		    pa->pa_device, pa->pa_function);
161 	}
162 	if (device_is_a(parent, "pnpbus")) {
163 		struct pnpbus_dev_attach_args *pna = aux;
164 		struct pnpbus_io *io;
165 
166 		n = snprintf(devpath, sizeof(devpath), "%s@",
167 		    pna->pna_devid);
168 		io = SIMPLEQ_FIRST(&pna->pna_res.io);
169 		if (n > sizeof(devpath))
170 			n = sizeof(devpath);
171 		if (io != NULL)
172 			n += snprintf(devpath + n, sizeof(devpath) - n, "%x",
173 			    io->minbase);
174 	}
175 
176 	if (n > sizeof(devpath))
177 		n = sizeof(devpath);
178 	/* we can't trust the device tag on the ethernet, because
179 	 * the spec lies about how it is formed.  Therefore we will leave it
180 	 * blank, and trim the end off any ethernet stuff. */
181 	if (device_class(dev) == DV_IFNET)
182 		n += snprintf(devpath + n, sizeof(devpath) - n, ":");
183 	else if (device_is_a(dev, "cd"))
184 		n = snprintf(devpath, sizeof(devpath), "cdrom@");
185 	else if (device_class(dev) == DV_DISK)
186 		n = snprintf(devpath, sizeof(devpath), "harddisk@");
187 	else if (device_class(dev) == DV_TAPE)
188 		n = snprintf(devpath, sizeof(devpath), "tape@");
189 	else if (device_is_a(dev, "fd"))
190 		n = snprintf(devpath, sizeof(devpath), "floppy@");
191 
192 	if (device_is_a(parent, "scsibus") || device_is_a(parent, "atapibus")) {
193 		struct scsipibus_attach_args *sa = aux;
194 
195 		/* periph_target is target for scsi, drive # for atapi */
196 		if (n > sizeof(devpath))
197 			n = sizeof(devpath);
198 		n += snprintf(devpath + n, sizeof(devpath) - n, "%d",
199 		    sa->sa_periph->periph_target);
200 		if (n > sizeof(devpath))
201 			n = sizeof(devpath);
202 		if (device_is_a(parent, "scsibus"))
203 			n += snprintf(devpath + n, sizeof(devpath) - n, ",%d",
204 			    sa->sa_periph->periph_lun);
205 	} else if (device_is_a(parent, "atabus") ||
206 	    device_is_a(parent, "pciide")) {
207 		struct ata_device *adev = aux;
208 
209 		if (n > sizeof(devpath))
210 			n = sizeof(devpath);
211 		n += snprintf(devpath + n, sizeof(devpath) - n, "%d",
212 		    adev->adev_drv_data->drive);
213 	} else if (device_is_a(dev, "fd")) {
214 		if (n > sizeof(devpath))
215 			n = sizeof(devpath);
216 		/* XXX device_unit() abuse */
217 		n += snprintf(devpath + n, sizeof(devpath) - n, "%d",
218 		    device_unit(dev));
219 	}
220 
221 	str1 = prop_string_create_cstring(devpath);
222 	KASSERT(str1 != NULL);
223 	(void)prop_dictionary_set(device_properties(dev),
224 	    "prep-fw-path-component", str1);
225 	prop_object_release(str1);
226 }
227 
228 static void
gen_fwpath(device_t dev)229 gen_fwpath(device_t dev)
230 {
231 	device_t parent;
232 	prop_string_t str1, str2, str3;
233 
234 	parent = device_parent(dev);
235 	str1 = prop_dictionary_get(device_properties(dev),
236 	    "prep-fw-path-component");
237 	if (str1 == NULL)
238 		return;
239 	if (parent == NULL) {
240 		prop_dictionary_set(device_properties(dev), "prep-fw-path",
241 		    str1);
242 		return;
243 	}
244 	str2 = prop_dictionary_get(device_properties(parent), "prep-fw-path");
245 	if (str2 == NULL) {
246 		prop_dictionary_set(device_properties(dev), "prep-fw-path",
247 		    str1);
248 		return;
249 	}
250 	str3 = prop_string_copy(str2);
251 	KASSERT(str3 != NULL);
252 	if (!(prop_string_equals_cstring(str3, "/") ||
253 	      prop_string_equals_cstring(str1, "")))
254 		prop_string_append_cstring(str3, "/");
255 	if (!prop_string_equals_cstring(str1, "/"))
256 		prop_string_append(str3, str1);
257 #if defined(NVRAM_DUMP)
258 	printf("%s devpath: %s+%s == %s\n", device_xname(dev),
259 	    prop_string_cstring_nocopy(str2),
260 	    prop_string_cstring_nocopy(str1),
261 	    prop_string_cstring_nocopy(str3));
262 #endif
263 	(void)prop_dictionary_set(device_properties(dev),
264 	    "prep-fw-path", str3);
265 	prop_object_release(str3);
266 }
267 
268 /*
269  * Generate properties for each device by totaling up its parent device
270  */
271 static void
build_fwpath(void)272 build_fwpath(void)
273 {
274 	device_t dev, d;
275 	deviter_t di, inner_di;
276 	prop_string_t str1;
277 
278 	/* First, find all the PCI busses */
279 	for (dev = deviter_first(&di, DEVITER_F_ROOT_FIRST); dev != NULL;
280 	     dev = deviter_next(&di)) {
281 		if (device_is_a(dev, "pci") || device_is_a(dev, "mainbus") ||
282 		    device_is_a(dev, "pcib") || device_is_a(dev, "pceb") ||
283 		    device_is_a(dev, "ppb"))
284 			gen_fwpath(dev);
285 	}
286 	deviter_release(&di);
287 
288 	/* Now go find the ISA bus and fix it up */
289 	for (dev = deviter_first(&di, DEVITER_F_ROOT_FIRST); dev != NULL;
290 	     dev = deviter_next(&di)) {
291 		if (device_is_a(dev, "isa"))
292 			gen_fwpath(dev);
293 	}
294 	deviter_release(&di);
295 
296 	for (dev = deviter_first(&di, DEVITER_F_ROOT_FIRST); dev != NULL;
297 	     dev = deviter_next(&di)) {
298 		/* skip the ones we already computed above */
299 		if (device_is_a(dev, "pci") || device_is_a(dev, "pcib") ||
300 		    device_is_a(dev, "pceb") || device_is_a(dev, "isa") ||
301 		    device_is_a(dev, "ppb"))
302 			continue;
303 		/* patch in the properties for the pnpbus */
304 		if (device_is_a(dev, "pnpbus")) {
305 			for (d = deviter_first(&inner_di, DEVITER_F_ROOT_FIRST);
306 			     d != NULL;
307 			     d = deviter_next(&inner_di)) {
308 				if (!device_is_a(d, "isa"))
309 					continue;
310 				str1 = prop_dictionary_get(device_properties(d),
311 					"prep-fw-path");
312 				if (str1 == NULL)
313 					continue;
314 				prop_dictionary_set(device_properties(dev),
315 					"prep-fw-path", str1);
316 			}
317 			deviter_release(&inner_di);
318 		} else
319 			gen_fwpath(dev);
320 	}
321 	deviter_release(&di);
322 }
323 
324 
325 /*
326  * This routine looks at each device, and tries to match them to the bootpath
327  */
328 
329 void
findroot(void)330 findroot(void)
331 {
332 	device_t d;
333 	deviter_t di;
334 	char *cp;
335 	prop_string_t str;
336 	size_t len;
337 
338 	/* first rebuild all the device paths */
339 	build_fwpath();
340 
341 	/* now trim the ethernet crap off the bootpath */
342 	cp = strchr(bootpath, ':');
343 	if (cp != NULL) {
344 		cp++;
345 		*cp = '\0';
346 	}
347 	len = strlen(bootpath);
348 #if defined(NVRAM_DUMP)
349 	printf("Modified bootpath: %s\n", bootpath);
350 #endif
351 	for (d = deviter_first(&di, DEVITER_F_ROOT_FIRST);
352 	     d != NULL;
353 	     d = deviter_next(&di)) {
354 		str = prop_dictionary_get(device_properties(d), "prep-fw-path");
355 		if (str == NULL)
356 			continue;
357 #if defined(NVRAM_DUMP)
358 		printf("dev %s: fw-path: %s\n", device_xname(d),
359 		    prop_string_cstring_nocopy(str));
360 #endif
361 		if (strncmp(prop_string_cstring_nocopy(str), bootpath,
362 		    len) == 0)
363 			break;
364 	}
365 	deviter_release(&di);
366 	if (d != NULL) {
367 		booted_device = d;
368 		booted_partition = 0; /* XXX ??? */
369 	}
370 }
371