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$");
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 #include <machine/stdarg.h>
48
49 void
50 OF_getetheraddr(device_t dev, u_char *addr)
51 {
52 char buf[sizeof("true")];
53 phandle_t node;
54 struct idprom idp;
55
56 if ((node = OF_finddevice("/options")) > 0 &&
57 OF_getprop(node, "local-mac-address?", buf, sizeof(buf)) > 0) {
58 buf[sizeof(buf) - 1] = '\0';
59 if (strcmp(buf, "true") == 0 &&
60 (node = ofw_bus_get_node(dev)) > 0 &&
61 OF_getprop(node, "local-mac-address", addr,
62 ETHER_ADDR_LEN) == ETHER_ADDR_LEN)
63 return;
64 }
65
66 node = OF_peer(0);
67 if (node <= 0 || OF_getprop(node, "idprom", &idp, sizeof(idp)) == -1)
68 panic("Could not determine the machine Ethernet address");
69 bcopy(&idp.id_ether, addr, ETHER_ADDR_LEN);
70 }
71
72 u_int
73 OF_getscsinitid(device_t dev)
74 {
75 phandle_t node;
76 uint32_t id;
77
78 for (node = ofw_bus_get_node(dev); node != 0; node = OF_parent(node))
79 if (OF_getprop(node, "scsi-initiator-id", &id,
80 sizeof(id)) > 0)
81 return (id);
82 return (7);
83 }
84
85 void
86 OF_panic(const char *fmt, ...)
87 {
88 char buf[256];
89 va_list ap;
90
91 va_start(ap, fmt);
92 (void)vsnprintf(buf, sizeof(buf), fmt, ap);
93 OF_printf("OF_panic: %s\n", buf);
94 va_end(ap);
95 OF_exit();
96 }
97
98 static __inline uint32_t
99 phys_hi_mask_space(const char *bus, uint32_t phys_hi)
100 {
101
102 if (strcmp(bus, "ebus") == 0 || strcmp(bus, "isa") == 0)
103 phys_hi &= 0x1;
104 else if (strcmp(bus, "pci") == 0)
105 phys_hi &= OFW_PCI_PHYS_HI_SPACEMASK;
106 /* The phys.hi cells of the other busses only contain space bits. */
107 return (phys_hi);
108 }
109
110 /*
111 * Return the physical address and the bus space to use for a node
112 * referenced by its package handle and the index of the register bank
113 * to decode. Intended to be used to together with sparc64_fake_bustag()
114 * by console drivers in early boot only.
115 * Works by mapping the address of the node's bank given in the address
116 * space of its parent upward in the device tree at each bridge along the
117 * path.
118 * Currently only really deals with max. 64-bit addresses, i.e. addresses
119 * consisting of max. 2 phys cells (phys.hi and phys.lo). If we encounter
120 * a 3 phys cells address (as with PCI addresses) we assume phys.hi can
121 * be ignored except for the space bits (generally contained in phys.hi)
122 * and treat phys.mid as phys.hi.
123 */
124 int
125 OF_decode_addr(phandle_t node, int bank, int *space, bus_addr_t *addr)
126 {
127 char name[32];
128 uint64_t cend, cstart, end, phys, pphys, sz, start;
129 pcell_t addrc, szc, paddrc;
130 phandle_t bus, lbus, pbus;
131 uint32_t banks[10 * 5]; /* 10 PCI banks */
132 uint32_t cspc, pspc, spc;
133 int i, j, nbank;
134
135 /*
136 * In general the addresses are contained in the "reg" property
137 * of a node. The first address in the "reg" property of a PCI
138 * node however is the address of its configuration registers in
139 * the configuration space of the host bridge. Additional entries
140 * denote the memory and I/O addresses. For relocatable addresses
141 * the "reg" property contains the BAR, for non-relocatable
142 * addresses it contains the absolute PCI address. The PCI-only
143 * "assigned-addresses" property however always contains the
144 * absolute PCI addresses.
145 * The "assigned-addresses" and "reg" properties are arrays of
146 * address structures consisting of #address-cells 32-bit phys
147 * cells and #size-cells 32-bit size cells. If a parent lacks
148 * the "#address-cells" or "#size-cells" property the default
149 * for #address-cells to use is 2 and for #size-cells 1.
150 */
151 bus = OF_parent(node);
152 if (bus == 0)
153 return (ENXIO);
154 if (OF_getprop(bus, "name", name, sizeof(name)) == -1)
155 return (ENXIO);
156 name[sizeof(name) - 1] = '\0';
157 if (OF_getprop(bus, "#address-cells", &addrc, sizeof(addrc)) == -1)
158 addrc = 2;
159 if (OF_getprop(bus, "#size-cells", &szc, sizeof(szc)) == -1)
160 szc = 1;
161 if (addrc < 2 || addrc > 3 || szc < 1 || szc > 2)
162 return (ENXIO);
163 if (strcmp(name, "pci") == 0) {
164 if (addrc > 3)
165 return (ENXIO);
166 nbank = OF_getprop(node, "assigned-addresses", &banks,
167 sizeof(banks));
168 } else {
169 if (addrc > 2)
170 return (ENXIO);
171 nbank = OF_getprop(node, "reg", &banks, sizeof(banks));
172 }
173 if (nbank == -1)
174 return (ENXIO);
175 nbank /= sizeof(banks[0]) * (addrc + szc);
176 if (bank < 0 || bank > nbank - 1)
177 return (ENXIO);
178 bank *= addrc + szc;
179 spc = phys_hi_mask_space(name, banks[bank]);
180 /* Skip the high cell for 3-cell addresses. */
181 bank += addrc - 2;
182 phys = 0;
183 for (i = 0; i < MIN(2, addrc); i++)
184 phys = ((uint64_t)phys << 32) | banks[bank++];
185 sz = 0;
186 for (i = 0; i < szc; i++)
187 sz = ((uint64_t)sz << 32) | banks[bank++];
188 start = phys;
189 end = phys + sz - 1;
190
191 /*
192 * Map upward in the device tree at every bridge we encounter
193 * using their "ranges" properties.
194 * The "ranges" property of a bridge is an array of a structure
195 * consisting of that bridge's #address-cells 32-bit child-phys
196 * cells, its parent bridge #address-cells 32-bit parent-phys
197 * cells and that bridge's #size-cells 32-bit size cells.
198 * If a bridge doesn't have a "ranges" property no mapping is
199 * necessary at that bridge.
200 */
201 cspc = 0;
202 lbus = bus;
203 while ((pbus = OF_parent(bus)) != 0) {
204 if (OF_getprop(pbus, "#address-cells", &paddrc,
205 sizeof(paddrc)) == -1)
206 paddrc = 2;
207 if (paddrc < 2 || paddrc > 3)
208 return (ENXIO);
209 nbank = OF_getprop(bus, "ranges", &banks, sizeof(banks));
210 if (nbank == -1) {
211 if (OF_getprop(pbus, "name", name, sizeof(name)) == -1)
212 return (ENXIO);
213 name[sizeof(name) - 1] = '\0';
214 goto skip;
215 }
216 if (OF_getprop(bus, "#size-cells", &szc, sizeof(szc)) == -1)
217 szc = 1;
218 if (szc < 1 || szc > 2)
219 return (ENXIO);
220 nbank /= sizeof(banks[0]) * (addrc + paddrc + szc);
221 bank = 0;
222 for (i = 0; i < nbank; i++) {
223 cspc = phys_hi_mask_space(name, banks[bank]);
224 if (cspc != spc) {
225 bank += addrc + paddrc + szc;
226 continue;
227 }
228 /* Skip the high cell for 3-cell addresses. */
229 bank += addrc - 2;
230 phys = 0;
231 for (j = 0; j < MIN(2, addrc); j++)
232 phys = ((uint64_t)phys << 32) | banks[bank++];
233 pspc = banks[bank];
234 /* Skip the high cell for 3-cell addresses. */
235 bank += paddrc - 2;
236 pphys = 0;
237 for (j = 0; j < MIN(2, paddrc); j++)
238 pphys =
239 ((uint64_t)pphys << 32) | banks[bank++];
240 sz = 0;
241 for (j = 0; j < szc; j++)
242 sz = ((uint64_t)sz << 32) | banks[bank++];
243 cstart = phys;
244 cend = phys + sz - 1;
245 if (start < cstart || start > cend)
246 continue;
247 if (end < cstart || end > cend)
248 return (ENXIO);
249 if (OF_getprop(pbus, "name", name, sizeof(name)) == -1)
250 return (ENXIO);
251 name[sizeof(name) - 1] = '\0';
252 spc = phys_hi_mask_space(name, pspc);
253 start += pphys - cstart;
254 end += pphys - cstart;
255 break;
256 }
257 if (i == nbank)
258 return (ENXIO);
259 lbus = bus;
260 skip:
261 addrc = paddrc;
262 bus = pbus;
263 }
264
265 *addr = start;
266 /* Determine the bus space based on the last bus we mapped. */
267 if (OF_parent(lbus) == 0) {
268 *space = NEXUS_BUS_SPACE;
269 return (0);
270 }
271 if (OF_getprop(lbus, "name", name, sizeof(name)) == -1)
272 return (ENXIO);
273 name[sizeof(name) - 1] = '\0';
274 if (strcmp(name, "central") == 0 || strcmp(name, "ebus") == 0 ||
275 strcmp(name, "upa") == 0) {
276 *space = NEXUS_BUS_SPACE;
277 return (0);
278 } else if (strcmp(name, "pci") == 0) {
279 switch (cspc) {
280 case OFW_PCI_PHYS_HI_SPACE_IO:
281 *space = PCI_IO_BUS_SPACE;
282 return (0);
283 case OFW_PCI_PHYS_HI_SPACE_MEM32:
284 *space = PCI_MEMORY_BUS_SPACE;
285 return (0);
286 }
287 } else if (strcmp(name, "sbus") == 0) {
288 *space = SBUS_BUS_SPACE;
289 return (0);
290 }
291 return (ENXIO);
292 }
Cache object: 339e1662239663de633fb0b9f0dcef83
|