ofw_machdep.c revision 207243
1/*-
2 * Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>.
3 * Copyright (c) 2005 - 2010 by Marius Strobl <marius@FreeBSD.org>.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
24 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/sparc64/sparc64/ofw_machdep.c 207243 2010-04-26 19:13:10Z marius $");
29
30/*
31 * Some Open Firmware helper functions that are likely machine dependent.
32 */
33
34#include <sys/param.h>
35#include <sys/bus.h>
36#include <sys/systm.h>
37
38#include <net/ethernet.h>
39
40#include <dev/ofw/ofw_bus.h>
41#include <dev/ofw/ofw_pci.h>
42#include <dev/ofw/openfirm.h>
43
44#include <machine/bus.h>
45#include <machine/idprom.h>
46#include <machine/ofw_machdep.h>
47
48void
49OF_getetheraddr(device_t dev, u_char *addr)
50{
51	char buf[sizeof("true")];
52	phandle_t node;
53	struct idprom idp;
54
55	if ((node = OF_finddevice("/options")) > 0 &&
56	    OF_getprop(node, "local-mac-address?", buf, sizeof(buf)) > 0) {
57		buf[sizeof(buf) - 1] = '\0';
58		if (strcmp(buf, "true") == 0 &&
59		    (node = ofw_bus_get_node(dev)) > 0 &&
60		    OF_getprop(node, "local-mac-address", addr,
61		    ETHER_ADDR_LEN) == ETHER_ADDR_LEN)
62			return;
63	}
64
65	node = OF_peer(0);
66	if (node <= 0 || OF_getprop(node, "idprom", &idp, sizeof(idp)) == -1)
67		panic("Could not determine the machine Ethernet address");
68	bcopy(&idp.id_ether, addr, ETHER_ADDR_LEN);
69}
70
71u_int
72OF_getscsinitid(device_t dev)
73{
74	phandle_t node;
75	uint32_t id;
76
77	for (node = ofw_bus_get_node(dev); node != 0; node = OF_parent(node))
78		if (OF_getprop(node, "scsi-initiator-id", &id,
79		    sizeof(id)) > 0)
80			return (id);
81	return (7);
82}
83
84static __inline uint32_t
85phys_hi_mask_space(const char *bus, uint32_t phys_hi)
86{
87
88	if (strcmp(bus, "ebus") == 0 || strcmp(bus, "isa") == 0)
89		phys_hi &= 0x1;
90	else if (strcmp(bus, "pci") == 0)
91		phys_hi &= OFW_PCI_PHYS_HI_SPACEMASK;
92	/* The phys.hi cells of the other busses only contain space bits. */
93	return (phys_hi);
94}
95
96/*
97 * Return the physical address and the bus space to use for a node
98 * referenced by its package handle and the index of the register bank
99 * to decode.  Intended to be used to together with sparc64_fake_bustag()
100 * by console drivers in early boot only.
101 * Works by mapping the address of the node's bank given in the address
102 * space of its parent upward in the device tree at each bridge along the
103 * path.
104 * Currently only really deals with max. 64-bit addresses, i.e. addresses
105 * consisting of max. 2 phys cells (phys.hi and phys.lo).  If we encounter
106 * a 3 phys cells address (as with PCI addresses) we assume phys.hi can
107 * be ignored except for the space bits (generally contained in phys.hi)
108 * and treat phys.mid as phys.hi.
109 */
110int
111OF_decode_addr(phandle_t node, int bank, int *space, bus_addr_t *addr)
112{
113	char name[32];
114	uint64_t cend, cstart, end, phys, pphys, sz, start;
115	pcell_t addrc, szc, paddrc;
116	phandle_t bus, lbus, pbus;
117	uint32_t banks[10 * 5];	/* 10 PCI banks */
118	uint32_t cspc, pspc, spc;
119	int i, j, nbank;
120
121	/*
122	 * In general the addresses are contained in the "reg" property
123	 * of a node.  The first address in the "reg" property of a PCI
124	 * node however is the address of its configuration registers in
125	 * the configuration space of the host bridge.  Additional entries
126	 * denote the memory and I/O addresses.  For relocatable addresses
127	 * the "reg" property contains the BAR, for non-relocatable
128	 * addresses it contains the absolute PCI address.  The PCI-only
129	 * "assigned-addresses" property however always contains the
130	 * absolute PCI addresses.
131	 * The "assigned-addresses" and "reg" properties are arrays of
132	 * address structures consisting of #address-cells 32-bit phys
133	 * cells and #size-cells 32-bit size cells.  If a parent lacks
134	 * the "#address-cells" or "#size-cells" property the default
135	 * for #address-cells to use is 2 and for #size-cells 1.
136	 */
137	bus = OF_parent(node);
138	if (bus == 0)
139		return (ENXIO);
140	if (OF_getprop(bus, "name", name, sizeof(name)) == -1)
141		return (ENXIO);
142	name[sizeof(name) - 1] = '\0';
143	if (OF_getprop(bus, "#address-cells", &addrc, sizeof(addrc)) == -1)
144		addrc = 2;
145	if (OF_getprop(bus, "#size-cells", &szc, sizeof(szc)) == -1)
146		szc = 1;
147	if (addrc < 2 || addrc > 3 || szc < 1 || szc > 2)
148		return (ENXIO);
149	if (strcmp(name, "pci") == 0) {
150		if (addrc > 3)
151			return (ENXIO);
152		nbank = OF_getprop(node, "assigned-addresses", &banks,
153		    sizeof(banks));
154	} else {
155		if (addrc > 2)
156			return (ENXIO);
157		nbank = OF_getprop(node, "reg", &banks, sizeof(banks));
158	}
159	if (nbank == -1)
160		return (ENXIO);
161	nbank /= sizeof(banks[0]) * (addrc + szc);
162	if (bank < 0 || bank > nbank - 1)
163		return (ENXIO);
164	bank *= addrc + szc;
165	spc = phys_hi_mask_space(name, banks[bank]);
166	/* Skip the high cell for 3-cell addresses. */
167	bank += addrc - 2;
168	phys = 0;
169	for (i = 0; i < MIN(2, addrc); i++)
170		phys = ((uint64_t)phys << 32) | banks[bank++];
171	sz = 0;
172	for (i = 0; i < szc; i++)
173		sz = ((uint64_t)sz << 32) | banks[bank++];
174	start = phys;
175	end = phys + sz - 1;
176
177	/*
178	 * Map upward in the device tree at every bridge we encounter
179	 * using their "ranges" properties.
180	 * The "ranges" property of a bridge is an array of a structure
181	 * consisting of that bridge's #address-cells 32-bit child-phys
182	 * cells, its parent bridge #address-cells 32-bit parent-phys
183	 * cells and that bridge's #size-cells 32-bit size cells.
184	 * If a bridge doesn't have a "ranges" property no mapping is
185	 * necessary at that bridge.
186	 */
187	cspc = 0;
188	lbus = bus;
189	while ((pbus = OF_parent(bus)) != 0) {
190		if (OF_getprop(pbus, "#address-cells", &paddrc,
191		    sizeof(paddrc)) == -1)
192			paddrc = 2;
193		if (paddrc < 2 || paddrc > 3)
194			return (ENXIO);
195		nbank = OF_getprop(bus, "ranges", &banks, sizeof(banks));
196		if (nbank == -1) {
197			if (OF_getprop(pbus, "name", name, sizeof(name)) == -1)
198				return (ENXIO);
199			name[sizeof(name) - 1] = '\0';
200			goto skip;
201		}
202		if (OF_getprop(bus, "#size-cells", &szc, sizeof(szc)) == -1)
203			szc = 1;
204		if (szc < 1 || szc > 2)
205			return (ENXIO);
206		nbank /= sizeof(banks[0]) * (addrc + paddrc + szc);
207		bank = 0;
208		for (i = 0; i < nbank; i++) {
209			cspc = phys_hi_mask_space(name, banks[bank]);
210			if (cspc != spc) {
211				bank += addrc + paddrc + szc;
212				continue;
213			}
214			/* Skip the high cell for 3-cell addresses. */
215			bank += addrc - 2;
216			phys = 0;
217			for (j = 0; j < MIN(2, addrc); j++)
218				phys = ((uint64_t)phys << 32) | banks[bank++];
219			pspc = banks[bank];
220			/* Skip the high cell for 3-cell addresses. */
221			bank += paddrc - 2;
222			pphys = 0;
223			for (j = 0; j < MIN(2, paddrc); j++)
224				pphys =
225				    ((uint64_t)pphys << 32) | banks[bank++];
226			sz = 0;
227			for (j = 0; j < szc; j++)
228				sz = ((uint64_t)sz << 32) | banks[bank++];
229			cstart = phys;
230			cend = phys + sz - 1;
231			if (start < cstart || start > cend)
232				continue;
233			if (end < cstart || end > cend)
234				return (ENXIO);
235			if (OF_getprop(pbus, "name", name, sizeof(name)) == -1)
236				return (ENXIO);
237			name[sizeof(name) - 1] = '\0';
238			spc = phys_hi_mask_space(name, pspc);
239			start += pphys - cstart;
240			end += pphys - cstart;
241			break;
242		}
243		if (i == nbank)
244			return (ENXIO);
245		lbus = bus;
246 skip:
247		addrc = paddrc;
248		bus = pbus;
249	}
250
251	*addr = start;
252	/* Determine the bus space based on the last bus we mapped. */
253	if (OF_parent(lbus) == 0) {
254		*space = NEXUS_BUS_SPACE;
255		return (0);
256	}
257	if (OF_getprop(lbus, "name", name, sizeof(name)) == -1)
258		return (ENXIO);
259	name[sizeof(name) - 1] = '\0';
260	if (strcmp(name, "central") == 0 || strcmp(name, "ebus") == 0 ||
261	    strcmp(name, "upa") == 0) {
262		*space = NEXUS_BUS_SPACE;
263		return (0);
264	} else if (strcmp(name, "pci") == 0) {
265		switch (cspc) {
266		case OFW_PCI_PHYS_HI_SPACE_IO:
267			*space = PCI_IO_BUS_SPACE;
268			return (0);
269		case OFW_PCI_PHYS_HI_SPACE_MEM32:
270			*space = PCI_MEMORY_BUS_SPACE;
271			return (0);
272		}
273	} else if (strcmp(name, "sbus") == 0) {
274		*space = SBUS_BUS_SPACE;
275		return (0);
276	}
277	return (ENXIO);
278}
279