]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/sparc64/sparc64/ofw_machdep.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / sparc64 / sparc64 / ofw_machdep.c
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
48 void
49 OF_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
71 u_int
72 OF_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
84 static __inline uint32_t
85 phys_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  */
110 int
111 OF_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 }