xref: /netbsd-src/sys/arch/sun68k/sun68k/autoconf.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
1 /*	$NetBSD: autoconf.c,v 1.32 2021/08/07 16:19:06 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Adam Glass, Gordon W. Ross, and Matthew Fredette.
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  * Configure() is called at boot time.  Available devices are
36  * determined (from possibilities mentioned in ioconf.c), and
37  * the drivers are initialized.
38  */
39 
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.32 2021/08/07 16:19:06 thorpej Exp $");
42 
43 #include "opt_kgdb.h"
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/conf.h>
48 #include <sys/device.h>
49 #include <sys/reboot.h>
50 
51 #include "locators.h"
52 
53 #include "scsibus.h"
54 
55 #if NSCSIBUS > 0
56 #include <dev/scsipi/scsi_all.h>
57 #include <dev/scsipi/scsipi_all.h>
58 #include <dev/scsipi/scsiconf.h>
59 #endif /* NSCSIBUS > 0 */
60 
61 #include <machine/autoconf.h>
62 #include <machine/intr.h>
63 #include <machine/promlib.h>
64 
65 #ifdef	KGDB
66 #include <sys/kgdb.h>
67 #endif
68 
69 /*
70  * Do general device autoconfiguration,
71  * then choose root device (etc.)
72  * Called by sys/kern/subr_autoconf.c: configure()
73  */
74 void
cpu_configure(void)75 cpu_configure(void)
76 {
77 
78 	/*
79 	 * Consider stopping for a debugger before
80 	 * autoconfiguration.
81 	 */
82 	if (boothowto & RB_KDB) {
83 #ifdef KGDB
84 		/* XXX - Ask on console for kgdb_dev? */
85 		/* Note: this will just return if kgdb_dev==NODEV */
86 		kgdb_connect(1);
87 #else	/* KGDB */
88 		/* Either DDB or no debugger (just PROM). */
89 		Debugger();
90 #endif	/* KGDB */
91 	}
92 
93 	/* General device autoconfiguration. */
94 	if (config_rootfound("mainbus", NULL) == NULL)
95 		panic("%s: mainbus not found", __func__);
96 
97 	/*
98 	 * Now that device autoconfiguration is finished,
99 	 * we can safely enable interrupts.
100 	 */
101 	printf("enabling interrupts\n");
102 	(void)spl0();
103 }
104 
105 static int 	mainbus_match(device_t, cfdata_t, void *);
106 static void	mainbus_attach(device_t, device_t, void *);
107 
108 CFATTACH_DECL_NEW(mainbus, 0,
109     mainbus_match, mainbus_attach, NULL, NULL);
110 
111 /*
112  * Probe for the mainbus; always succeeds.
113  */
114 static int
mainbus_match(device_t parent,cfdata_t cf,void * aux)115 mainbus_match(device_t parent, cfdata_t cf, void *aux)
116 {
117 
118 	return 1;
119 }
120 
121 /*
122  * Do "direct" configuration for the bus types on mainbus.
123  * This controls the order of autoconfig for important things
124  * used early.  For example, idprom is used by Ether drivers.
125  */
126 static void
mainbus_attach(device_t parent,device_t self,void * args)127 mainbus_attach(device_t parent, device_t self, void *args)
128 {
129 	struct mainbus_attach_args ma;
130 	const char *const *cpp;
131 	static const char *const special[] = {
132 		/* find these first */
133 		"obio",
134 		"obmem",
135 		NULL
136 	};
137 
138 	aprint_normal("\n");
139 
140 	ma.ma_bustag = &mainbus_space_tag;
141 	ma.ma_dmatag = &mainbus_dma_tag;
142 	ma.ma_paddr = LOCATOR_FORBIDDEN;
143 	ma.ma_pri = LOCATOR_FORBIDDEN;
144 
145 	/* Find all `early' mainbus buses */
146 	for (cpp = special; *cpp != NULL; cpp++) {
147 		ma.ma_name = *cpp;
148 		(void)config_found(self, &ma, NULL, CFARGS_NONE);
149 	}
150 
151 	/* Find the remaining buses */
152 	ma.ma_name = NULL;
153 	(void)config_found(self, &ma, NULL, CFARGS_NONE);
154 
155 	/* Lastly, find the PROM console */
156 	ma.ma_name = "pcons";
157 	(void)config_found(self, &ma, NULL, CFARGS_NONE);
158 }
159 
160 /*
161  * sun68k_bus_search:
162  * This function is passed to config_search_ia() by the attach function
163  * for each of the "bus" drivers (obio, obmem, mbmem, vme, ...).
164  * The purpose of this function is to copy the "locators" into our
165  * _attach_args structure, so child drivers may use the _attach_args both
166  * as match parameters and as temporary storage for the defaulted
167  * locator values determined in the child_match and preserved for
168  * the child_attach function.  If the bus attach functions just
169  * used config_found, then we would not have an opportunity to
170  * setup the _attach_args for each child match and attach call.
171  */
172 int
sun68k_bus_search(device_t parent,cfdata_t cf,const int * ldesc,void * aux)173 sun68k_bus_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
174 {
175 	struct mainbus_attach_args *map = aux;
176 	struct mainbus_attach_args ma;
177 
178 	/* Check whether we're looking for a specifically named device */
179 	if (map->ma_name != NULL && strcmp(map->ma_name, cf->cf_name) != 0)
180 		return 0;
181 
182 #ifdef	DIAGNOSTIC
183 	if (cf->cf_fstate == FSTATE_STAR)
184 		panic("%s: FSTATE_STAR", __func__);
185 #endif
186 
187 	/*
188 	 * Prepare to copy the locators into our _attach_args.
189 	 */
190 	ma = *map;
191 	ma.ma_name = NULL;
192 
193 	/*
194 	 * Avoid entries which are missing attach information that
195 	 * they need, or that have attach information that they
196 	 * cannot have.  The individual bus attach functions tell
197 	 * us this by initializing the locator fields in the attach
198 	 * args they provide us.
199 	 *
200 	 * At the same time we copy these values into the _attach_args
201 	 * will pass to the device's match and attach functions.
202 	 */
203 #ifdef	DIAGNOSTIC
204 #define BAD_LOCATOR(ma_loc, what) \
205 	panic("%s: %s %s for: %s%d", __func__, \
206 	    map->ma_loc == LOCATOR_REQUIRED ? "missing" : "unexpected", \
207 	    what, cf->cf_name, cf->cf_unit)
208 #else
209 #define BAD_LOCATOR(ma_loc, what) return 0
210 #endif
211 
212 #define CHECK_LOCATOR(ma_loc, cf_loc, what) \
213 	if ((map->ma_loc == LOCATOR_FORBIDDEN && cf->cf_loc != -1) || \
214 	    (map->ma_loc == LOCATOR_REQUIRED && cf->cf_loc == -1)) \
215 		BAD_LOCATOR(ma_loc, what); \
216 	else \
217 		ma.ma_loc = cf->cf_loc
218 
219 	CHECK_LOCATOR(ma_paddr, cf_loc[MBIOCF_ADDR], "address");
220 	CHECK_LOCATOR(ma_pri, cf_loc[MBIOCF_IPL], "ipl");
221 
222 	/*
223 	 * Note that this allows the probe function to save
224 	 * defaulted locators in the _attach_args that will be
225 	 * preserved for the related attach call.
226 	 * XXX - This is a hack...
227 	 */
228 	if (config_probe(parent, cf, &ma)) {
229 		config_attach(parent, cf, &ma, sun68k_bus_print, CFARGS_NONE);
230 	}
231 	return 0;
232 }
233 
234 /*
235  * sun68k_bus_print:
236  * Just print out the final (non-default) locators.
237  * The parent name is non-NULL when there was no match
238  * found by config_found().
239  */
240 int
sun68k_bus_print(void * args,const char * name)241 sun68k_bus_print(void *args, const char *name)
242 {
243 	struct mainbus_attach_args *ma = args;
244 
245 	if (name)
246 		aprint_normal("%s:", name);
247 
248 	if (ma->ma_paddr != -1)
249 		aprint_normal(" addr 0x%x", (unsigned int) ma->ma_paddr);
250 	if (ma->ma_pri != -1)
251 		aprint_normal(" ipl %d", ma->ma_pri);
252 
253 	return UNCONF;
254 }
255 
256 /****************************************************************/
257 
258 /* This takes the args: name, ctlr, unit */
259 typedef device_t (*findfunc_t)(char *, int, int);
260 
261 static device_t net_find(char *, int, int);
262 #if NSCSIBUS > 0
263 static device_t scsi_find(char *, int, int);
264 #endif /* NSCSIBUS > 0 */
265 static device_t xx_find(char *, int, int);
266 
267 struct prom_n2f {
268 	const char name[4];
269 	findfunc_t func;
270 };
271 static struct prom_n2f prom_dev_table[] = {
272 	{ "ie",		net_find },
273 	{ "ec",		net_find },
274 	{ "le",		net_find },
275 #if NSCSIBUS > 0
276 	{ "sd",		scsi_find },
277 #endif /* NSCSIBUS > 0 */
278 	{ "xy",		xx_find },
279 	{ "xd",		xx_find },
280 	{ "",		0 },
281 };
282 
283 /*
284  * This converts one hex number to an integer, and returns
285  * an updated string pointer.
286  */
287 static const char *str2hex(const char *, int *);
288 static const char *
str2hex(const char * p,int * _val)289 str2hex(const char *p, int *_val)
290 {
291 	int val;
292 	int c;
293 
294 	for (val = 0;; val = (val << 4) + c, p++) {
295 		c = *((const unsigned char *)p);
296 		if (c >= 'a')
297 			c-= ('a' + 10);
298 		else if (c >= 'A')
299 			c -= ('A' + 10);
300 		else if (c >= '0')
301 			c -= '0';
302 		if (c < 0 || c > 15)
303 			break;
304 	}
305 	*_val = val;
306 	return p;
307 }
308 
309 /*
310  * Choose root and swap devices.
311  */
312 void
cpu_rootconf(void)313 cpu_rootconf(void)
314 {
315 	struct prom_n2f *nf;
316 	const char *devname;
317 	findfunc_t find;
318 	char promname[4];
319 	char partname[4];
320 	const char *prompath;
321 	int prom_ctlr, prom_unit, prom_part;
322 
323 	/* Get the PROM boot path and take it apart. */
324 	prompath = prom_getbootpath();
325 	if (prompath == NULL)
326 		prompath = "zz(0,0,0)";
327 	promname[0] = *(prompath++);
328 	promname[1] = *(prompath++);
329 	promname[2] = '\0';
330 	prom_ctlr = prom_unit = prom_part = 0;
331 	if (*prompath == '(' &&
332 	    *(prompath = str2hex(++prompath, &prom_ctlr)) == ',' &&
333 	    *(prompath = str2hex(++prompath, &prom_unit)) == ',')
334 		(void)str2hex(++prompath, &prom_part);
335 
336 	/* Default to "unknown" */
337 	booted_device = NULL;
338 	booted_partition = 0;
339 	devname = "<unknown>";
340 	partname[0] = '\0';
341 	find = NULL;
342 
343 	/* Do we know anything about the PROM boot device? */
344 	for (nf = prom_dev_table; nf->func; nf++)
345 		if (!strcmp(nf->name, promname)) {
346 			find = nf->func;
347 			break;
348 		}
349 	if (find)
350 		booted_device = (*find)(promname, prom_ctlr, prom_unit);
351 	if (booted_device) {
352 		devname = device_xname(booted_device);
353 		if (device_class(booted_device) == DV_DISK) {
354 			booted_partition = prom_part & 7;
355 			partname[0] = 'a' + booted_partition;
356 			partname[1] = '\0';
357 		}
358 	}
359 
360 	printf("boot device: %s%s\n", devname, partname);
361 	rootconf();
362 }
363 
364 /*
365  * Functions to find devices using PROM boot parameters.
366  */
367 
368 /*
369  * Network device:  Just use controller number.
370  */
371 static device_t
net_find(char * name,int ctlr,int unit)372 net_find(char *name, int ctlr, int unit)
373 {
374 
375 	return device_find_by_driver_unit(name, ctlr);
376 }
377 
378 #if NSCSIBUS > 0
379 /*
380  * SCSI device:  The controller number corresponds to the
381  * scsibus number, and the unit number is (targ*8 + LUN).
382  */
383 static device_t
scsi_find(char * name,int ctlr,int unit)384 scsi_find(char *name, int ctlr, int unit)
385 {
386 	device_t scsibus;
387 	struct scsibus_softc *sbsc;
388 	struct scsipi_periph *periph;
389 	int target, lun;
390 
391 	if ((scsibus = device_find_by_driver_unit("scsibus", ctlr)) == NULL)
392 		return NULL;
393 
394 	/* Compute SCSI target/LUN from PROM unit. */
395 	target = prom_sd_target((unit >> 3) & 7);
396 	lun = unit & 7;
397 
398 	/* Find the device at this target/LUN */
399 	sbsc = device_private(scsibus);
400 	periph = scsipi_lookup_periph(sbsc->sc_channel, target, lun);
401 	if (periph == NULL)
402 		return NULL;
403 
404 	return periph->periph_dev;
405 }
406 #endif /* NSCSIBUS > 0 */
407 
408 /*
409  * Xylogics SMD disk: (xy, xd)
410  * Assume wired-in unit numbers for now...
411  */
412 static device_t
xx_find(char * name,int ctlr,int unit)413 xx_find(char *name, int ctlr, int unit)
414 {
415 
416 	return device_find_by_driver_unit(name, ctlr * 2 + unit);
417 }
418