xref: /netbsd/sys/arch/powerpc/powerpc/ofw_machdep.c (revision bf9ec67e)
1 /*	$NetBSD: ofw_machdep.c,v 1.11 2001/08/26 02:47:39 matt Exp $	*/
2 
3 /*
4  * Copyright (C) 1996 Wolfgang Solfrank.
5  * Copyright (C) 1996 TooLs GmbH.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by TooLs GmbH.
19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 #include <sys/param.h>
34 #include <sys/buf.h>
35 #include <sys/conf.h>
36 #include <sys/device.h>
37 #include <sys/disk.h>
38 #include <sys/disklabel.h>
39 #include <sys/fcntl.h>
40 #include <sys/ioctl.h>
41 #include <sys/malloc.h>
42 #include <sys/stat.h>
43 #include <sys/systm.h>
44 
45 #include <dev/ofw/openfirm.h>
46 
47 #include <machine/powerpc.h>
48 
49 #define	OFMEM_REGIONS	32
50 static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
51 
52 /*
53  * This is called during initppc, before the system is really initialized.
54  * It shall provide the total and the available regions of RAM.
55  * Both lists must have a zero-size entry as terminator.
56  * The available regions need not take the kernel into account, but needs
57  * to provide space for two additional entry beyond the terminating one.
58  */
59 void
60 mem_regions(struct mem_region **memp, struct mem_region **availp)
61 {
62 	int phandle, i, cnt;
63 
64 	/*
65 	 * Get memory.
66 	 */
67 	if ((phandle = OF_finddevice("/memory")) == -1)
68 		goto error;
69 
70 	memset(OFmem, 0, sizeof OFmem);
71 	cnt = OF_getprop(phandle, "reg",
72 		OFmem, sizeof OFmem[0] * OFMEM_REGIONS);
73 	if (cnt <= 0)
74 		goto error;
75 
76 	/* Remove zero sized entry in the returned data. */
77 	cnt /= sizeof OFmem[0];
78 	for (i = 0; i < cnt; )
79 		if (OFmem[i].size == 0) {
80 			memmove(&OFmem[i], &OFmem[i + 1],
81 				(cnt - i) * sizeof OFmem[0]);
82 			cnt--;
83 		} else
84 			i++;
85 
86 	memset(OFavail, 0, sizeof OFavail);
87 	cnt = OF_getprop(phandle, "available",
88 		OFavail, sizeof OFavail[0] * OFMEM_REGIONS);
89 	if (cnt <= 0)
90 		goto error;
91 
92 	cnt /= sizeof OFavail[0];
93 	for (i = 0; i < cnt; )
94 		if (OFavail[i].size == 0) {
95 			memmove(&OFavail[i], &OFavail[i + 1],
96 				(cnt - i) * sizeof OFavail[0]);
97 			cnt--;
98 		} else
99 			i++;
100 
101 	*memp = OFmem;
102 	*availp = OFavail;
103 	return;
104 
105 error:
106 	panic("no memory?");
107 }
108 
109 void
110 ppc_exit(void)
111 {
112 	OF_exit();
113 }
114 
115 void
116 ppc_boot(char *str)
117 {
118 	OF_boot(str);
119 }
120 
121 #ifdef __BROKEN_DK_ESTABLISH
122 /*
123  * Establish a list of all available disks to allow specifying the
124  * root/swap/dump dev.
125  */
126 struct ofb_disk {
127 	LIST_ENTRY(ofb_disk) ofb_list;
128 	struct disk *ofb_dk;
129 	struct device *ofb_dev;
130 	int ofb_phandle;
131 	int ofb_unit;
132 };
133 
134 #include <machine/autoconf.h>
135 
136 static LIST_HEAD(ofb_list, ofb_disk) ofb_head;	/* LIST_INIT?		XXX */
137 
138 void
139 dk_establish(struct disk *dk, struct device *dev)
140 {
141 	struct ofb_disk *od;
142 	struct ofbus_softc *ofp = (void *)dev;
143 
144 	MALLOC(od, struct ofb_disk *, sizeof *od, M_TEMP, M_NOWAIT);
145 	if (!od)
146 		panic("dk_establish");
147 	od->ofb_dk = dk;
148 	od->ofb_dev = dev;
149 	od->ofb_phandle = ofp->sc_phandle;
150 	if (dev->dv_class == DV_DISK)				/* XXX */
151 		od->ofb_unit = ofp->sc_unit;
152 	else
153 		od->ofb_unit = -1;
154 	LIST_INSERT_HEAD(&ofb_head, od, ofb_list);
155 }
156 
157 /*
158  * Cleanup the list.
159  */
160 void
161 dk_cleanup(void)
162 {
163 	struct ofb_disk *od, *nd;
164 
165 	for (od = ofb_head.lh_first; od; od = nd) {
166 		nd = od->ofb_list.le_next;
167 		LIST_REMOVE(od, ofb_list);
168 		FREE(od, M_TEMP);
169 	}
170 }
171 
172 static void
173 dk_setroot(struct ofb_disk *od, int part)
174 {
175 	char type[8];
176 	int maj, unit;
177 	struct disklabel *lp;
178 	dev_t tmpdev;
179 	char *cp;
180 
181 	if (OF_getprop(od->ofb_phandle, "device_type", type, sizeof type) < 0)
182 		panic("OF_getproperty");
183 
184 	if (strcmp(type, "block") == 0) {
185 		for (maj = 0; maj < nblkdev; maj++) {
186 			if (bdevsw[maj].d_strategy ==
187 			    od->ofb_dk->dk_driver->d_strategy)
188 				break;
189 		}
190 		if (maj >= nblkdev)
191 			panic("dk_setroot: impossible");
192 
193 		/*
194 		 * Find the unit.
195 		 */
196 		unit = 0;
197 		for (cp = od->ofb_dk->dk_name; *cp; cp++) {
198 			if (*cp >= '0' && *cp <= '9')
199 				unit = unit * 10 + *cp - '0';
200 			else
201 				/* Start anew */
202 				unit = 0;
203 		}
204 
205 		/*
206 		 * Find a default partition; try partition `a', then
207 		 * fall back on RAW_PART.
208 		 */
209 		if (part == -1) {
210 			/*
211 			 * Open the disk to force an update of the in-core
212 			 * disklabel.  Use RAW_PART because all disk
213 			 * drivers allow RAW_PART to be opened.
214 			 */
215 			tmpdev = MAKEDISKDEV(maj, unit, RAW_PART);
216 
217 			if (bdevsw[maj].d_open(tmpdev, FREAD, S_IFBLK, 0)) {
218 				/*
219 				 * Open failed.  Device is probably not
220 				 * configured.  setroot() can handle this.
221 				 */
222 				return;
223 			}
224 			(void)bdevsw[maj].d_close(tmpdev, FREAD, S_IFBLK, 0);
225 			lp = od->ofb_dk->dk_label;
226 
227 			/* Check for a valid `a' partition. */
228 			if (lp->d_partitions[0].p_size > 0 &&
229 			    lp->d_partitions[0].p_fstype != FS_UNUSED)
230 				part = 0;
231 			else
232 				part = RAW_PART;
233 		}
234 		booted_device = od->ofb_dev;
235 		booted_partition = part;
236 	} else if (strcmp(type, "network") == 0) {
237 		booted_device = od->ofb_dev;
238 		booted_partition = 0;
239 	}
240 
241 	/* "Not found."  setroot() will ask for the root device. */
242 }
243 
244 /*
245  * Try to find a disk with the given name.
246  * This allows either the OpenFirmware device name,
247  * or the NetBSD device name, both with optional trailing partition.
248  */
249 int
250 dk_match(char *name)
251 {
252 	struct ofb_disk *od;
253 	char *cp;
254 	int phandle;
255 	int part, unit;
256 	int l;
257 
258 	for (od = ofb_head.lh_first; od; od = od->ofb_list.le_next) {
259 		/*
260 		 * First try the NetBSD name.
261 		 */
262 		l = strlen(od->ofb_dev->dv_xname);
263 		if (!memcmp(name, od->ofb_dev->dv_xname, l)) {
264 			if (name[l] == '\0') {
265 				/* Default partition, (or none at all) */
266 				dk_setroot(od, -1);
267 				return 0;
268 			}
269 			if (name[l + 1] == '\0') {
270 				switch (name[l]) {
271 				case '*':
272 					/* Default partition */
273 					dk_setroot(od, -1);
274 					return 0;
275 				default:
276 					if (name[l] >= 'a'
277 					    && name[l] < 'a' + MAXPARTITIONS) {
278 						/* specified partition */
279 						dk_setroot(od, name[l] - 'a');
280 						return 0;
281 					}
282 					break;
283 				}
284 			}
285 		}
286 	}
287 	/*
288 	 * Now try the OpenFirmware name
289 	 */
290 	l = strlen(name);
291 	for (cp = name + l; --cp >= name;)
292 		if (*cp == '/' || *cp == ':')
293 			break;
294 	if (cp >= name && *cp == ':')
295 		*cp++ = 0;
296 	else
297 		cp = name + l;
298 	part = *cp >= 'a' && *cp < 'a' + MAXPARTITIONS
299 		? *cp - 'a'
300 		: -1;
301 	while (cp > name && cp[-1] != '@' && cp[-1] != '/')
302 		--cp;
303 	if (cp > name && cp[-1] == '@') {
304 		for (unit = 0; *++cp >= '0' && *cp <= '9';)
305 			unit = unit * 10 + *cp - '0';
306 	} else
307 		unit = -1;
308 
309 	if ((phandle = OF_finddevice(name)) != -1) {
310 		for (od = ofb_head.lh_first; od; od = od->ofb_list.le_next) {
311 			if (phandle == od->ofb_phandle) {
312 				/* Check for matching units */
313 				if (od->ofb_dk &&
314 				    unit != -1 &&
315 				    od->ofb_unit != unit)
316 					continue;
317 				dk_setroot(od, part);
318 				return 0;
319 			}
320 		}
321 	}
322 	return ENODEV;
323 }
324 #endif /* __BROKEN_DK_ESTABLISH */
325