1/*- 2 * Copyright (c) 1999 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Paul Kranenburg. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 * 29 * from: NetBSD: if_hme_sbus.c,v 1.19 2004/03/17 17:04:58 pk Exp 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD$"); 34 35/* 36 * SBus front-end device driver for the HME ethernet device. 37 */ 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/bus.h> 42#include <sys/lock.h> 43#include <sys/kernel.h> 44#include <sys/module.h> 45#include <sys/mutex.h> 46#include <sys/resource.h> 47#include <sys/socket.h> 48 49#include <dev/ofw/ofw_bus.h> 50 51#include <machine/bus.h> 52#include <machine/ofw_machdep.h> 53#include <machine/resource.h> 54 55#include <sys/rman.h> 56 57#include <net/if.h> 58#include <net/if_media.h> 59#include <net/ethernet.h> 60 61#include <dev/mii/mii.h> 62#include <dev/mii/miivar.h> 63 64#include <sparc64/sbus/sbusvar.h> 65 66#include <dev/hme/if_hmereg.h> 67#include <dev/hme/if_hmevar.h> 68 69#include "miibus_if.h" 70 71struct hme_sbus_softc { 72 struct hme_softc hsc_hme; /* HME device */ 73 struct resource *hsc_seb_res; 74 struct resource *hsc_etx_res; 75 struct resource *hsc_erx_res; 76 struct resource *hsc_mac_res; 77 struct resource *hsc_mif_res; 78 struct resource *hsc_ires; 79 void *hsc_ih; 80}; 81 82static int hme_sbus_probe(device_t); 83static int hme_sbus_attach(device_t); 84static int hme_sbus_detach(device_t); 85static int hme_sbus_suspend(device_t); 86static int hme_sbus_resume(device_t); 87 88static device_method_t hme_sbus_methods[] = { 89 /* Device interface */ 90 DEVMETHOD(device_probe, hme_sbus_probe), 91 DEVMETHOD(device_attach, hme_sbus_attach), 92 DEVMETHOD(device_detach, hme_sbus_detach), 93 DEVMETHOD(device_suspend, hme_sbus_suspend), 94 DEVMETHOD(device_resume, hme_sbus_resume), 95 /* Can just use the suspend method here. */ 96 DEVMETHOD(device_shutdown, hme_sbus_suspend), 97 98 /* MII interface */ 99 DEVMETHOD(miibus_readreg, hme_mii_readreg), 100 DEVMETHOD(miibus_writereg, hme_mii_writereg), 101 DEVMETHOD(miibus_statchg, hme_mii_statchg), 102 103 DEVMETHOD_END 104}; 105 106static driver_t hme_sbus_driver = { 107 "hme", 108 hme_sbus_methods, 109 sizeof(struct hme_sbus_softc) 110}; 111 112DRIVER_MODULE(hme, sbus, hme_sbus_driver, hme_devclass, 0, 0); 113MODULE_DEPEND(hme, sbus, 1, 1, 1); 114MODULE_DEPEND(hme, ether, 1, 1, 1); 115 116static int 117hme_sbus_probe(device_t dev) 118{ 119 const char *name; 120 121 name = ofw_bus_get_name(dev); 122 if (strcmp(name, "SUNW,qfe") == 0 || 123 strcmp(name, "SUNW,hme") == 0) { 124 device_set_desc(dev, "Sun HME 10/100 Ethernet"); 125 return (0); 126 } 127 return (ENXIO); 128} 129 130static int 131hme_sbus_attach(device_t dev) 132{ 133 struct hme_sbus_softc *hsc; 134 struct hme_softc *sc; 135 u_long start, count; 136 uint32_t burst; 137 int i, error = 0; 138 139 hsc = device_get_softc(dev); 140 sc = &hsc->hsc_hme; 141 mtx_init(&sc->sc_lock, device_get_nameunit(dev), MTX_NETWORK_LOCK, 142 MTX_DEF); 143 /* 144 * Map five register banks: 145 * 146 * bank 0: HME SEB registers 147 * bank 1: HME ETX registers 148 * bank 2: HME ERX registers 149 * bank 3: HME MAC registers 150 * bank 4: HME MIF registers 151 * 152 */ 153 i = 0; 154 hsc->hsc_seb_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 155 &i, RF_ACTIVE); 156 if (hsc->hsc_seb_res == NULL) { 157 device_printf(dev, "cannot map SEB registers\n"); 158 error = ENXIO; 159 goto fail_mtx_res; 160 } 161 sc->sc_sebt = rman_get_bustag(hsc->hsc_seb_res); 162 sc->sc_sebh = rman_get_bushandle(hsc->hsc_seb_res); 163 164 i = 1; 165 hsc->hsc_etx_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 166 &i, RF_ACTIVE); 167 if (hsc->hsc_etx_res == NULL) { 168 device_printf(dev, "cannot map ETX registers\n"); 169 error = ENXIO; 170 goto fail_seb_res; 171 } 172 sc->sc_etxt = rman_get_bustag(hsc->hsc_etx_res); 173 sc->sc_etxh = rman_get_bushandle(hsc->hsc_etx_res); 174 175 i = 2; 176 hsc->hsc_erx_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 177 &i, RF_ACTIVE); 178 if (hsc->hsc_erx_res == NULL) { 179 device_printf(dev, "cannot map ERX registers\n"); 180 error = ENXIO; 181 goto fail_etx_res; 182 } 183 sc->sc_erxt = rman_get_bustag(hsc->hsc_erx_res); 184 sc->sc_erxh = rman_get_bushandle(hsc->hsc_erx_res); 185 186 i = 3; 187 hsc->hsc_mac_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 188 &i, RF_ACTIVE); 189 if (hsc->hsc_mac_res == NULL) { 190 device_printf(dev, "cannot map MAC registers\n"); 191 error = ENXIO; 192 goto fail_erx_res; 193 } 194 sc->sc_mact = rman_get_bustag(hsc->hsc_mac_res); 195 sc->sc_mach = rman_get_bushandle(hsc->hsc_mac_res); 196 197 /* 198 * At least on some HMEs, the MIF registers seem to be inside the MAC 199 * range, so try to kludge around it. 200 */ 201 i = 4; 202 hsc->hsc_mif_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 203 &i, RF_ACTIVE); 204 if (hsc->hsc_mif_res == NULL) { 205 if (bus_get_resource(dev, SYS_RES_MEMORY, i, 206 &start, &count) != 0) { 207 device_printf(dev, "cannot get MIF registers\n"); 208 error = ENXIO; 209 goto fail_mac_res; 210 } 211 if (start < rman_get_start(hsc->hsc_mac_res) || 212 start + count - 1 > rman_get_end(hsc->hsc_mac_res)) { 213 device_printf(dev, "cannot move MIF registers to MAC " 214 "bank\n"); 215 error = ENXIO; 216 goto fail_mac_res; 217 } 218 sc->sc_mift = sc->sc_mact; 219 bus_space_subregion(sc->sc_mact, sc->sc_mach, 220 start - rman_get_start(hsc->hsc_mac_res), count, 221 &sc->sc_mifh); 222 } else { 223 sc->sc_mift = rman_get_bustag(hsc->hsc_mif_res); 224 sc->sc_mifh = rman_get_bushandle(hsc->hsc_mif_res); 225 } 226 227 i = 0; 228 hsc->hsc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 229 &i, RF_SHAREABLE | RF_ACTIVE); 230 if (hsc->hsc_ires == NULL) { 231 device_printf(dev, "could not allocate interrupt\n"); 232 error = ENXIO; 233 goto fail_mif_res; 234 } 235 236 OF_getetheraddr(dev, sc->sc_enaddr); 237 238 burst = sbus_get_burstsz(dev); 239 /* Translate into plain numerical format */ 240 if ((burst & SBUS_BURST_64)) 241 sc->sc_burst = 64; 242 else if ((burst & SBUS_BURST_32)) 243 sc->sc_burst = 32; 244 else if ((burst & SBUS_BURST_16)) 245 sc->sc_burst = 16; 246 else 247 sc->sc_burst = 0; 248 249 sc->sc_dev = dev; 250 sc->sc_flags = 0; 251 252 if ((error = hme_config(sc)) != 0) { 253 device_printf(dev, "could not be configured\n"); 254 goto fail_ires; 255 } 256 257 if ((error = bus_setup_intr(dev, hsc->hsc_ires, INTR_TYPE_NET | 258 INTR_MPSAFE, NULL, hme_intr, sc, &hsc->hsc_ih)) != 0) { 259 device_printf(dev, "couldn't establish interrupt\n"); 260 hme_detach(sc); 261 goto fail_ires; 262 } 263 return (0); 264 265fail_ires: 266 bus_release_resource(dev, SYS_RES_IRQ, 267 rman_get_rid(hsc->hsc_ires), hsc->hsc_ires); 268fail_mif_res: 269 if (hsc->hsc_mif_res != NULL) { 270 bus_release_resource(dev, SYS_RES_MEMORY, 271 rman_get_rid(hsc->hsc_mif_res), hsc->hsc_mif_res); 272 } 273fail_mac_res: 274 bus_release_resource(dev, SYS_RES_MEMORY, 275 rman_get_rid(hsc->hsc_mac_res), hsc->hsc_mac_res); 276fail_erx_res: 277 bus_release_resource(dev, SYS_RES_MEMORY, 278 rman_get_rid(hsc->hsc_erx_res), hsc->hsc_erx_res); 279fail_etx_res: 280 bus_release_resource(dev, SYS_RES_MEMORY, 281 rman_get_rid(hsc->hsc_etx_res), hsc->hsc_etx_res); 282fail_seb_res: 283 bus_release_resource(dev, SYS_RES_MEMORY, 284 rman_get_rid(hsc->hsc_seb_res), hsc->hsc_seb_res); 285fail_mtx_res: 286 mtx_destroy(&sc->sc_lock); 287 return (error); 288} 289 290static int 291hme_sbus_detach(device_t dev) 292{ 293 struct hme_sbus_softc *hsc; 294 struct hme_softc *sc; 295 296 hsc = device_get_softc(dev); 297 sc = &hsc->hsc_hme; 298 bus_teardown_intr(dev, hsc->hsc_ires, hsc->hsc_ih); 299 hme_detach(sc); 300 bus_release_resource(dev, SYS_RES_IRQ, 301 rman_get_rid(hsc->hsc_ires), hsc->hsc_ires); 302 if (hsc->hsc_mif_res != NULL) { 303 bus_release_resource(dev, SYS_RES_MEMORY, 304 rman_get_rid(hsc->hsc_mif_res), hsc->hsc_mif_res); 305 } 306 bus_release_resource(dev, SYS_RES_MEMORY, 307 rman_get_rid(hsc->hsc_mac_res), hsc->hsc_mac_res); 308 bus_release_resource(dev, SYS_RES_MEMORY, 309 rman_get_rid(hsc->hsc_erx_res), hsc->hsc_erx_res); 310 bus_release_resource(dev, SYS_RES_MEMORY, 311 rman_get_rid(hsc->hsc_etx_res), hsc->hsc_etx_res); 312 bus_release_resource(dev, SYS_RES_MEMORY, 313 rman_get_rid(hsc->hsc_seb_res), hsc->hsc_seb_res); 314 mtx_destroy(&sc->sc_lock); 315 return (0); 316} 317 318static int 319hme_sbus_suspend(device_t dev) 320{ 321 struct hme_sbus_softc *hsc; 322 323 hsc = device_get_softc(dev); 324 hme_suspend(&hsc->hsc_hme); 325 return (0); 326} 327 328static int 329hme_sbus_resume(device_t dev) 330{ 331 struct hme_sbus_softc *hsc; 332 333 hsc = device_get_softc(dev); 334 hme_resume(&hsc->hsc_hme); 335 return (0); 336} 337