ofw_machdep.c revision 119697
1/*- 2 * Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 23 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 * $FreeBSD: head/sys/sparc64/sparc64/ofw_machdep.c 119697 2003-09-02 20:32:12Z marcel $ 26 */ 27 28/* 29 * Some OpenFirmware helper functions that are likely machine dependent. 30 */ 31 32#include <sys/param.h> 33#include <sys/systm.h> 34 35#include <net/ethernet.h> 36 37#include <dev/ofw/openfirm.h> 38 39#include <machine/bus.h> 40#include <machine/idprom.h> 41#include <machine/ofw_machdep.h> 42#include <machine/ofw_upa.h> 43#include <machine/resource.h> 44 45#include <sparc64/pci/ofw_pci.h> 46#include <sparc64/isa/ofw_isa.h> 47#include <sparc64/sbus/ofw_sbus.h> 48 49void 50OF_getetheraddr(device_t dev, u_char *addr) 51{ 52 phandle_t node; 53 struct idprom idp; 54 55 node = OF_peer(0); 56 if (node <= 0 || OF_getprop(node, "idprom", &idp, sizeof(idp)) == -1) 57 panic("Could not determine the machine ethernet address"); 58 bcopy(&idp.id_ether, addr, ETHER_ADDR_LEN); 59} 60 61int 62OF_decode_addr(phandle_t node, int *space, bus_addr_t *addr) 63{ 64 char name[32]; 65 union { 66 struct isa_ranges isa[4]; 67 struct sbus_ranges sbus[8]; 68 struct upa_ranges upa[4]; 69 } range; 70 union { 71 struct isa_regs isa; 72 struct sbus_regs sbus; 73 } reg; 74 phandle_t bus, pbus; 75 u_long child, dummy, phys; 76 int cs, i, rsz, type; 77 78 bus = OF_parent(node); 79 if (bus == NULL) 80 return (ENXIO); 81 if (OF_getprop(bus, "name", name, sizeof(name)) == -1) 82 return (ENXIO); 83 name[sizeof(name) - 1] = '\0'; 84 if (strcmp(name, "ebus") == 0) { 85 if (OF_getprop(node, "reg", ®.isa, sizeof(reg.isa)) == -1) 86 return (ENXIO); 87 rsz = OF_getprop(bus, "ranges", range.isa, sizeof(range.isa)); 88 if (rsz == -1) 89 return (ENXIO); 90 phys = ISA_REG_PHYS(®.isa); 91 dummy = phys + 1; 92 type = ofw_isa_map_iorange(range.isa, rsz / sizeof(*range.isa), 93 &phys, &dummy); 94 if (type == SYS_RES_MEMORY) { 95 cs = PCI_CS_MEM32; 96 *space = PCI_MEMORY_BUS_SPACE; 97 } else { 98 cs = PCI_CS_IO; 99 *space = PCI_IO_BUS_SPACE; 100 } 101 102 /* Find the topmost PCI node (the host bridge) */ 103 while (1) { 104 pbus = OF_parent(bus); 105 if (pbus == NULL) 106 return (ENXIO); 107 if (OF_getprop(pbus, "name", name, sizeof(name)) == -1) 108 return (ENXIO); 109 name[sizeof(name) - 1] = '\0'; 110 if (strcmp(name, "pci") != 0) 111 break; 112 bus = pbus; 113 } 114 115 /* There wasn't a PCI bridge. */ 116 if (bus == OF_parent(node)) 117 return (ENXIO); 118 119 /* Make sure we reached the UPA/PCI node. */ 120 if (OF_getprop(pbus, "device_type", name, sizeof(name)) == -1) 121 return (ENXIO); 122 name[sizeof(name) - 1] = '\0'; 123 if (strcmp(name, "upa") != 0) 124 return (ENXIO); 125 126 rsz = OF_getprop(bus, "ranges", range.upa, sizeof(range.upa)); 127 if (rsz == -1) 128 return (ENXIO); 129 for (i = 0; i < (rsz / sizeof(range.upa[0])); i++) { 130 child = UPA_RANGE_CHILD(&range.upa[i]); 131 if (UPA_RANGE_CS(&range.upa[i]) == cs && 132 phys >= child && 133 phys - child < UPA_RANGE_SIZE(&range.upa[i])) { 134 *addr = UPA_RANGE_PHYS(&range.upa[i]) + phys; 135 return (0); 136 } 137 } 138 } else if (strcmp(name, "sbus") == 0) { 139 if (OF_getprop(node, "reg", ®.sbus, sizeof(reg.sbus)) == -1) 140 return (ENXIO); 141 rsz = OF_getprop(bus, "ranges", range.sbus, 142 sizeof(range.sbus)); 143 if (rsz == -1) 144 return (ENXIO); 145 for (i = 0; i < (rsz / sizeof(range.sbus[0])); i++) { 146 if (reg.sbus.sbr_slot != range.sbus[i].cspace) 147 continue; 148 if (reg.sbus.sbr_offset < range.sbus[i].coffset || 149 reg.sbus.sbr_offset >= range.sbus[i].coffset + 150 range.sbus[i].size) 151 continue; 152 /* Found it... */ 153 phys = range.sbus[i].poffset | 154 ((bus_addr_t)range.sbus[i].pspace << 32); 155 phys += reg.sbus.sbr_offset - range.sbus[i].coffset; 156 *addr = phys; 157 *space = SBUS_BUS_SPACE; 158 return (0); 159 } 160 } 161 return (ENXIO); 162} 163