ofw_machdep.c revision 219428
1234353Sdim/*-
2224133Sdim * Copyright (C) 1996 Wolfgang Solfrank.
3224133Sdim * Copyright (C) 1996 TooLs GmbH.
4224133Sdim * All rights reserved.
5224133Sdim *
6224133Sdim * Redistribution and use in source and binary forms, with or without
7224133Sdim * modification, are permitted provided that the following conditions
8224133Sdim * are met:
9224133Sdim * 1. Redistributions of source code must retain the above copyright
10224133Sdim *    notice, this list of conditions and the following disclaimer.
11224133Sdim * 2. Redistributions in binary form must reproduce the above copyright
12224133Sdim *    notice, this list of conditions and the following disclaimer in the
13224133Sdim *    documentation and/or other materials provided with the distribution.
14224133Sdim * 3. All advertising materials mentioning features or use of this software
15249423Sdim *    must display the following acknowledgement:
16224133Sdim *	This product includes software developed by TooLs GmbH.
17226633Sdim * 4. The name of TooLs GmbH may not be used to endorse or promote products
18224133Sdim *    derived from this software without specific prior written permission.
19224133Sdim *
20224133Sdim * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21226633Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22224133Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23224133Sdim * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24224133Sdim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25224133Sdim * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26224133Sdim * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27224133Sdim * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28224133Sdim * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29224133Sdim * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30224133Sdim *
31224133Sdim * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
32224133Sdim */
33224133Sdim
34224133Sdim#include <sys/cdefs.h>
35224133Sdim__FBSDID("$FreeBSD: head/sys/powerpc/ofw/ofw_machdep.c 219428 2011-03-09 15:03:42Z nwhitehorn $");
36224133Sdim
37224133Sdim#include <sys/param.h>
38224133Sdim#include <sys/bus.h>
39224133Sdim#include <sys/systm.h>
40226633Sdim#include <sys/conf.h>
41226633Sdim#include <sys/disk.h>
42226633Sdim#include <sys/fcntl.h>
43226633Sdim#include <sys/malloc.h>
44224133Sdim#include <sys/smp.h>
45224133Sdim#include <sys/stat.h>
46224133Sdim
47224133Sdim#include <net/ethernet.h>
48224133Sdim
49224133Sdim#include <dev/ofw/openfirm.h>
50224133Sdim#include <dev/ofw/ofw_pci.h>
51224133Sdim#include <dev/ofw/ofw_bus.h>
52224133Sdim
53226633Sdim#include <vm/vm.h>
54234353Sdim#include <vm/vm_param.h>
55234353Sdim#include <vm/vm_page.h>
56226633Sdim
57234353Sdim#include <machine/bus.h>
58226633Sdim#include <machine/cpu.h>
59226633Sdim#include <machine/md_var.h>
60226633Sdim#include <machine/platform.h>
61226633Sdim#include <machine/ofw_machdep.h>
62226633Sdim
63226633Sdim#define	OFMEM_REGIONS	32
64234353Sdimstatic struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
65234353Sdimstatic struct mem_region OFfree[OFMEM_REGIONS + 3];
66226633Sdimstatic int nOFmem;
67226633Sdim
68234353Sdimextern register_t ofmsr[5];
69226633Sdimstatic int	(*ofwcall)(void *);
70226633Sdimstatic void	*fdt;
71226633Sdimint		ofw_real_mode;
72226633Sdim
73226633Sdimint		ofw_32bit_mode_entry(void *);
74226633Sdimstatic void	ofw_quiesce(void);
75226633Sdimstatic int	openfirmware(void *args);
76226633Sdim
77226633Sdim/*
78226633Sdim * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
79226633Sdim */
80226633Sdimregister_t	ofw_sprg0_save;
81226633Sdim
82226633Sdimstatic __inline void
83226633Sdimofw_sprg_prepare(void)
84226633Sdim{
85226633Sdim	/*
86226633Sdim	 * Assume that interrupt are disabled at this point, or
87226633Sdim	 * SPRG1-3 could be trashed
88224133Sdim	 */
89224133Sdim	__asm __volatile("mfsprg0 %0\n\t"
90224133Sdim			 "mtsprg0 %1\n\t"
91226633Sdim	    		 "mtsprg1 %2\n\t"
92226633Sdim	    		 "mtsprg2 %3\n\t"
93226633Sdim			 "mtsprg3 %4\n\t"
94224133Sdim			 : "=&r"(ofw_sprg0_save)
95			 : "r"(ofmsr[1]),
96			 "r"(ofmsr[2]),
97			 "r"(ofmsr[3]),
98			 "r"(ofmsr[4]));
99}
100
101static __inline void
102ofw_sprg_restore(void)
103{
104	/*
105	 * Note that SPRG1-3 contents are irrelevant. They are scratch
106	 * registers used in the early portion of trap handling when
107	 * interrupts are disabled.
108	 *
109	 * PCPU data cannot be used until this routine is called !
110	 */
111	__asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
112}
113
114/*
115 * Memory region utilities: determine if two regions overlap,
116 * and merge two overlapping regions into one
117 */
118static int
119memr_overlap(struct mem_region *r1, struct mem_region *r2)
120{
121	if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
122	    (r2->mr_start + r2->mr_size) < r1->mr_start)
123		return (FALSE);
124
125	return (TRUE);
126}
127
128static void
129memr_merge(struct mem_region *from, struct mem_region *to)
130{
131	vm_offset_t end;
132	end = ulmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
133	to->mr_start = ulmin(from->mr_start, to->mr_start);
134	to->mr_size = end - to->mr_start;
135}
136
137static int
138parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
139{
140	cell_t address_cells, size_cells;
141	cell_t OFmem[4*(OFMEM_REGIONS + 1)];
142	int sz, i, j;
143	int apple_hack_mode;
144	phandle_t phandle;
145
146	sz = 0;
147	apple_hack_mode = 0;
148
149	/*
150	 * Get #address-cells from root node, defaulting to 1 if it cannot
151	 * be found.
152	 */
153	phandle = OF_finddevice("/");
154	if (OF_getprop(phandle, "#address-cells", &address_cells,
155	    sizeof(address_cells)) < sizeof(address_cells))
156		address_cells = 1;
157	if (OF_getprop(phandle, "#size-cells", &size_cells,
158	    sizeof(size_cells)) < sizeof(size_cells))
159		size_cells = 1;
160
161	/*
162	 * On Apple hardware, address_cells is always 1 for "available",
163	 * even when it is explicitly set to 2. Then all memory above 4 GB
164	 * should be added by hand to the available list. Detect Apple hardware
165	 * by seeing if ofw_real_mode is set -- only Apple seems to use
166	 * virtual-mode OF.
167	 */
168	if (strcmp(prop, "available") == 0 && !ofw_real_mode)
169		apple_hack_mode = 1;
170
171	if (apple_hack_mode)
172		address_cells = 1;
173
174	/*
175	 * Get memory.
176	 */
177	if ((node == -1) || (sz = OF_getprop(node, prop,
178	    OFmem, sizeof(OFmem[0]) * 4 * OFMEM_REGIONS)) <= 0)
179		panic("Physical memory map not found");
180
181	i = 0;
182	j = 0;
183	while (i < sz/sizeof(cell_t)) {
184	      #ifndef __powerpc64__
185		/* On 32-bit PPC, ignore regions starting above 4 GB */
186		if (address_cells > 1 && OFmem[i] > 0) {
187			i += address_cells + size_cells;
188			continue;
189		}
190	      #endif
191
192		output[j].mr_start = OFmem[i++];
193		if (address_cells == 2) {
194			#ifdef __powerpc64__
195			output[j].mr_start <<= 32;
196			#endif
197			output[j].mr_start += OFmem[i++];
198		}
199
200		output[j].mr_size = OFmem[i++];
201		if (size_cells == 2) {
202			#ifdef __powerpc64__
203			output[j].mr_size <<= 32;
204			#endif
205			output[j].mr_size += OFmem[i++];
206		}
207
208	      #ifndef __powerpc64__
209		/*
210		 * Check for memory regions extending above 32-bit
211		 * memory space, and restrict them to stay there.
212		 */
213		if (((uint64_t)output[j].mr_start +
214		    (uint64_t)output[j].mr_size) >
215		    BUS_SPACE_MAXADDR_32BIT) {
216			output[j].mr_size = BUS_SPACE_MAXADDR_32BIT -
217			    output[j].mr_start;
218		}
219	      #endif
220
221		j++;
222	}
223	sz = j*sizeof(output[0]);
224
225	#ifdef __powerpc64__
226	if (apple_hack_mode) {
227		/* Add in regions above 4 GB to the available list */
228		struct mem_region himem[OFMEM_REGIONS];
229		int hisz;
230
231		hisz = parse_ofw_memory(node, "reg", himem);
232		for (i = 0; i < hisz/sizeof(himem[0]); i++) {
233			if (himem[i].mr_start > BUS_SPACE_MAXADDR_32BIT) {
234				output[j].mr_start = himem[i].mr_start;
235				output[j].mr_size = himem[i].mr_size;
236				j++;
237			}
238		}
239		sz = j*sizeof(output[0]);
240	}
241	#endif
242
243	return (sz);
244}
245
246/*
247 * This is called during powerpc_init, before the system is really initialized.
248 * It shall provide the total and the available regions of RAM.
249 * Both lists must have a zero-size entry as terminator.
250 * The available regions need not take the kernel into account, but needs
251 * to provide space for two additional entry beyond the terminating one.
252 */
253void
254ofw_mem_regions(struct mem_region **memp, int *memsz,
255		struct mem_region **availp, int *availsz)
256{
257	phandle_t phandle;
258	int asz, msz, fsz;
259	int i, j;
260	int still_merging;
261
262	asz = msz = 0;
263
264	/*
265	 * Get memory.
266	 */
267	phandle = OF_finddevice("/memory");
268	if (phandle == -1)
269		phandle = OF_finddevice("/memory@0");
270
271	msz = parse_ofw_memory(phandle, "reg", OFmem);
272	nOFmem = msz / sizeof(struct mem_region);
273	asz = parse_ofw_memory(phandle, "available", OFavail);
274
275	*memp = OFmem;
276	*memsz = nOFmem;
277
278	/*
279	 * OFavail may have overlapping regions - collapse these
280	 * and copy out remaining regions to OFfree
281	 */
282	asz /= sizeof(struct mem_region);
283	do {
284		still_merging = FALSE;
285		for (i = 0; i < asz; i++) {
286			if (OFavail[i].mr_size == 0)
287				continue;
288			for (j = i+1; j < asz; j++) {
289				if (OFavail[j].mr_size == 0)
290					continue;
291				if (memr_overlap(&OFavail[j], &OFavail[i])) {
292					memr_merge(&OFavail[j], &OFavail[i]);
293					/* mark inactive */
294					OFavail[j].mr_size = 0;
295					still_merging = TRUE;
296				}
297			}
298		}
299	} while (still_merging == TRUE);
300
301	/* evict inactive ranges */
302	for (i = 0, fsz = 0; i < asz; i++) {
303		if (OFavail[i].mr_size != 0) {
304			OFfree[fsz] = OFavail[i];
305			fsz++;
306		}
307	}
308
309	*availp = OFfree;
310	*availsz = fsz;
311}
312
313void
314OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
315{
316	if (ofmsr[0] & PSL_DR)
317		ofw_real_mode = 0;
318	else
319		ofw_real_mode = 1;
320
321	ofwcall = NULL;
322
323	#ifdef __powerpc64__
324		/*
325		 * For PPC64, we need to use some hand-written
326		 * asm trampolines to get to OF.
327		 */
328		if (openfirm != NULL)
329			ofwcall = ofw_32bit_mode_entry;
330	#else
331		ofwcall = openfirm;
332	#endif
333
334	fdt = fdt_ptr;
335
336	#ifdef FDT_DTB_STATIC
337	/* Check for a statically included blob */
338	if (fdt == NULL)
339		fdt = &fdt_static_dtb;
340	#endif
341}
342
343boolean_t
344OF_bootstrap()
345{
346	boolean_t status = FALSE;
347
348	if (ofwcall != NULL) {
349		if (ofw_real_mode) {
350			status = OF_install(OFW_STD_REAL, 0);
351		} else {
352			#ifdef __powerpc64__
353			status = OF_install(OFW_STD_32BIT, 0);
354			#else
355			status = OF_install(OFW_STD_DIRECT, 0);
356			#endif
357		}
358
359		if (status != TRUE)
360			return status;
361
362		OF_init(openfirmware);
363
364		/*
365		 * On some machines, we need to quiesce OF to turn off
366		 * background processes.
367		 */
368		ofw_quiesce();
369	} else if (fdt != NULL) {
370		status = OF_install(OFW_FDT, 0);
371
372		if (status != TRUE)
373			return status;
374
375		OF_init(fdt);
376	}
377
378	return (status);
379}
380
381static void
382ofw_quiesce(void)
383{
384	phandle_t rootnode;
385	char model[32];
386	struct {
387		cell_t name;
388		cell_t nargs;
389		cell_t nreturns;
390	} args;
391
392	/*
393	 * Only quiesce Open Firmware on PowerMac11,2 and 12,1. It is
394	 * necessary there to shut down a background thread doing fan
395	 * management, and is harmful on other machines.
396	 *
397	 * Note: we don't need to worry about which OF module we are
398	 * using since this is called only from very early boot, within
399	 * OF's boot context.
400	 */
401
402	rootnode = OF_finddevice("/");
403	if (OF_getprop(rootnode, "model", model, sizeof(model)) > 0) {
404		if (strcmp(model, "PowerMac11,2") == 0 ||
405		    strcmp(model, "PowerMac12,1") == 0) {
406			args.name = (cell_t)(uintptr_t)"quiesce";
407			args.nargs = 0;
408			args.nreturns = 0;
409			openfirmware(&args);
410		}
411	}
412}
413
414static int
415openfirmware_core(void *args)
416{
417	int		result;
418	register_t	oldmsr;
419
420	/*
421	 * Turn off exceptions - we really don't want to end up
422	 * anywhere unexpected with PCPU set to something strange
423	 * or the stack pointer wrong.
424	 */
425	oldmsr = intr_disable();
426
427	ofw_sprg_prepare();
428
429#if defined(AIM) && !defined(__powerpc64__)
430	/*
431	 * Clear battable[] translations
432	 */
433	if (!(cpu_features & PPC_FEATURE_64))
434		__asm __volatile("mtdbatu 2, %0\n"
435				 "mtdbatu 3, %0" : : "r" (0));
436	isync();
437#endif
438
439	result = ofwcall(args);
440	ofw_sprg_restore();
441
442	intr_restore(oldmsr);
443
444	return (result);
445}
446
447#ifdef SMP
448struct ofw_rv_args {
449	void *args;
450	int retval;
451	volatile int in_progress;
452};
453
454static void
455ofw_rendezvous_dispatch(void *xargs)
456{
457	struct ofw_rv_args *rv_args = xargs;
458
459	/* NOTE: Interrupts are disabled here */
460
461	if (PCPU_GET(cpuid) == 0) {
462		/*
463		 * Execute all OF calls on CPU 0
464		 */
465		rv_args->retval = openfirmware_core(rv_args->args);
466		rv_args->in_progress = 0;
467	} else {
468		/*
469		 * Spin with interrupts off on other CPUs while OF has
470		 * control of the machine.
471		 */
472		while (rv_args->in_progress)
473			cpu_spinwait();
474	}
475}
476#endif
477
478static int
479openfirmware(void *args)
480{
481	int result;
482	#ifdef SMP
483	struct ofw_rv_args rv_args;
484	#endif
485
486	if (pmap_bootstrapped && ofw_real_mode)
487		args = (void *)pmap_kextract((vm_offset_t)args);
488
489	#ifdef SMP
490	rv_args.args = args;
491	rv_args.in_progress = 1;
492	smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch,
493	    smp_no_rendevous_barrier, &rv_args);
494	result = rv_args.retval;
495	#else
496	result = openfirmware_core(args);
497	#endif
498
499	return (result);
500}
501
502void
503OF_reboot()
504{
505	struct {
506		cell_t name;
507		cell_t nargs;
508		cell_t nreturns;
509		cell_t arg;
510	} args;
511
512	args.name = (cell_t)(uintptr_t)"interpret";
513	args.nargs = 1;
514	args.nreturns = 0;
515	args.arg = (cell_t)(uintptr_t)"reset-all";
516	openfirmware_core(&args); /* Don't do rendezvous! */
517
518	for (;;);	/* just in case */
519}
520
521void
522OF_getetheraddr(device_t dev, u_char *addr)
523{
524	phandle_t	node;
525
526	node = ofw_bus_get_node(dev);
527	OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
528}
529
530/*
531 * Return a bus handle and bus tag that corresponds to the register
532 * numbered regno for the device referenced by the package handle
533 * dev. This function is intended to be used by console drivers in
534 * early boot only. It works by mapping the address of the device's
535 * register in the address space of its parent and recursively walk
536 * the device tree upward this way.
537 */
538static void
539OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
540{
541	char name[16];
542	uint32_t addr, size;
543	int pci, res;
544
545	res = OF_getprop(node, "#address-cells", &addr, sizeof(addr));
546	if (res == -1)
547		addr = 2;
548	res = OF_getprop(node, "#size-cells", &size, sizeof(size));
549	if (res == -1)
550		size = 1;
551	pci = 0;
552	if (addr == 3 && size == 2) {
553		res = OF_getprop(node, "name", name, sizeof(name));
554		if (res != -1) {
555			name[sizeof(name) - 1] = '\0';
556			pci = (strcmp(name, "pci") == 0) ? 1 : 0;
557		}
558	}
559	if (addrp != NULL)
560		*addrp = addr;
561	if (sizep != NULL)
562		*sizep = size;
563	if (pcip != NULL)
564		*pcip = pci;
565}
566
567int
568OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
569    bus_space_handle_t *handle)
570{
571	uint32_t cell[32];
572	bus_addr_t addr, raddr, baddr;
573	bus_size_t size, rsize;
574	uint32_t c, nbridge, naddr, nsize;
575	phandle_t bridge, parent;
576	u_int spc, rspc;
577	int pci, pcib, res;
578
579	/* Sanity checking. */
580	if (dev == 0)
581		return (EINVAL);
582	bridge = OF_parent(dev);
583	if (bridge == 0)
584		return (EINVAL);
585	if (regno < 0)
586		return (EINVAL);
587	if (tag == NULL || handle == NULL)
588		return (EINVAL);
589
590	/* Get the requested register. */
591	OF_get_addr_props(bridge, &naddr, &nsize, &pci);
592	res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg",
593	    cell, sizeof(cell));
594	if (res == -1)
595		return (ENXIO);
596	if (res % sizeof(cell[0]))
597		return (ENXIO);
598	res /= sizeof(cell[0]);
599	regno *= naddr + nsize;
600	if (regno + naddr + nsize > res)
601		return (EINVAL);
602	spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0;
603	addr = 0;
604	for (c = 0; c < naddr; c++)
605		addr = ((uint64_t)addr << 32) | cell[regno++];
606	size = 0;
607	for (c = 0; c < nsize; c++)
608		size = ((uint64_t)size << 32) | cell[regno++];
609
610	/*
611	 * Map the address range in the bridge's decoding window as given
612	 * by the "ranges" property. If a node doesn't have such property
613	 * then no mapping is done.
614	 */
615	parent = OF_parent(bridge);
616	while (parent != 0) {
617		OF_get_addr_props(parent, &nbridge, NULL, &pcib);
618		res = OF_getprop(bridge, "ranges", cell, sizeof(cell));
619		if (res == -1)
620			goto next;
621		if (res % sizeof(cell[0]))
622			return (ENXIO);
623		res /= sizeof(cell[0]);
624		regno = 0;
625		while (regno < res) {
626			rspc = (pci)
627			    ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
628			    : ~0;
629			if (rspc != spc) {
630				regno += naddr + nbridge + nsize;
631				continue;
632			}
633			raddr = 0;
634			for (c = 0; c < naddr; c++)
635				raddr = ((uint64_t)raddr << 32) | cell[regno++];
636			rspc = (pcib)
637			    ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
638			    : ~0;
639			baddr = 0;
640			for (c = 0; c < nbridge; c++)
641				baddr = ((uint64_t)baddr << 32) | cell[regno++];
642			rsize = 0;
643			for (c = 0; c < nsize; c++)
644				rsize = ((uint64_t)rsize << 32) | cell[regno++];
645			if (addr < raddr || addr >= raddr + rsize)
646				continue;
647			addr = addr - raddr + baddr;
648			if (rspc != ~0)
649				spc = rspc;
650		}
651
652	next:
653		bridge = parent;
654		parent = OF_parent(bridge);
655		OF_get_addr_props(bridge, &naddr, &nsize, &pci);
656	}
657
658	*tag = &bs_le_tag;
659	return (bus_space_map(*tag, addr, size, 0, handle));
660}
661
662