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