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 49void 50OF_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")) != -1 && 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 72u_int 73OF_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 85void 86OF_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 98static __inline uint32_t 99phys_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 */ 124int 125OF_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} 293