if_le_lebuffer.c revision 166144
1272343Sngie/*- 2272343Sngie * Copyright (c) 2006 Marius Strobl <marius@FreeBSD.org> 3272343Sngie * All rights reserved. 4272343Sngie * 5272343Sngie * Redistribution and use in source and binary forms, with or without 6272343Sngie * modification, are permitted provided that the following conditions 7272343Sngie * are met: 8272343Sngie * 1. Redistributions of source code must retain the above copyright 9272343Sngie * notice, this list of conditions and the following disclaimer. 10272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 11272343Sngie * notice, this list of conditions and the following disclaimer in the 12272343Sngie * documentation and/or other materials provided with the distribution. 13272343Sngie * 14272343Sngie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15272343Sngie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16272343Sngie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17272343Sngie * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18272343Sngie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19272343Sngie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20272343Sngie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21272343Sngie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22272343Sngie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23272343Sngie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24272343Sngie * SUCH DAMAGE. 25272343Sngie */ 26272343Sngie 27272343Sngie#include <sys/cdefs.h> 28272343Sngie__FBSDID("$FreeBSD: head/sys/dev/le/if_le_lebuffer.c 166144 2007-01-20 12:53:30Z marius $"); 29272343Sngie 30272343Sngie#include <sys/param.h> 31272343Sngie#include <sys/systm.h> 32272343Sngie#include <sys/bus.h> 33272343Sngie#include <sys/endian.h> 34272343Sngie#include <sys/kernel.h> 35272343Sngie#include <sys/lock.h> 36272343Sngie#include <sys/module.h> 37272343Sngie#include <sys/mutex.h> 38272343Sngie#include <sys/resource.h> 39272343Sngie#include <sys/rman.h> 40272343Sngie#include <sys/socket.h> 41272343Sngie 42272343Sngie#include <dev/ofw/ofw_bus.h> 43272343Sngie 44277443Sngie#include <machine/bus.h> 45277443Sngie#include <machine/ofw_machdep.h> 46277443Sngie#include <machine/resource.h> 47272343Sngie 48272343Sngie#include <net/ethernet.h> 49272343Sngie#include <net/if.h> 50272343Sngie#include <net/if_media.h> 51272343Sngie 52272343Sngie#include <dev/le/lancereg.h> 53272343Sngie#include <dev/le/lancevar.h> 54272343Sngie#include <dev/le/am7990reg.h> 55272343Sngie#include <dev/le/am7990var.h> 56272343Sngie 57272343Sngie/* 58272343Sngie * LANCE registers 59272343Sngie */ 60272343Sngie#define LEREG1_RDP 0 /* Register Data port */ 61272343Sngie#define LEREG1_RAP 2 /* Register Address port */ 62272343Sngie 63272343Sngiestruct le_lebuffer_softc { 64272343Sngie struct am7990_softc sc_am7990; /* glue to MI code */ 65272343Sngie 66272343Sngie int sc_brid; 67272343Sngie struct resource *sc_bres; 68272343Sngie bus_space_tag_t sc_buft; 69272343Sngie bus_space_handle_t sc_bufh; 70272343Sngie 71272343Sngie int sc_rrid; 72272343Sngie struct resource *sc_rres; 73272343Sngie bus_space_tag_t sc_regt; 74272343Sngie bus_space_handle_t sc_regh; 75272343Sngie 76272343Sngie int sc_irid; 77272343Sngie struct resource *sc_ires; 78272343Sngie void *sc_ih; 79272343Sngie}; 80272343Sngie 81272343Sngiestatic devclass_t le_lebuffer_devclass; 82272343Sngie 83272343Sngiestatic device_probe_t le_lebuffer_probe; 84272343Sngiestatic device_attach_t le_lebuffer_attach; 85272343Sngiestatic device_detach_t le_lebuffer_detach; 86272343Sngiestatic device_resume_t le_buffer_resume; 87272343Sngiestatic device_suspend_t le_buffer_suspend; 88272343Sngie 89272343Sngiestatic device_method_t le_lebuffer_methods[] = { 90272343Sngie /* Device interface */ 91272343Sngie DEVMETHOD(device_probe, le_lebuffer_probe), 92272343Sngie DEVMETHOD(device_attach, le_lebuffer_attach), 93272343Sngie DEVMETHOD(device_detach, le_lebuffer_detach), 94272343Sngie /* We can just use the suspend method here. */ 95272343Sngie DEVMETHOD(device_shutdown, le_buffer_suspend), 96272343Sngie DEVMETHOD(device_suspend, le_buffer_suspend), 97272343Sngie DEVMETHOD(device_resume, le_buffer_resume), 98272343Sngie 99272343Sngie { 0, 0 } 100272343Sngie}; 101272343Sngie 102272343SngieDEFINE_CLASS_0(le, le_lebuffer_driver, le_lebuffer_methods, 103272343Sngie sizeof(struct le_lebuffer_softc)); 104272343SngieDRIVER_MODULE(le, lebuffer, le_lebuffer_driver, le_lebuffer_devclass, 0, 0); 105272343SngieMODULE_DEPEND(le, ether, 1, 1, 1); 106272343Sngie 107272343Sngie/* 108272343Sngie * Media types supported 109272343Sngie */ 110272343Sngiestatic const int le_lebuffer_media[] = { 111272343Sngie IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0) 112272343Sngie}; 113272343Sngie#define NLEMEDIA \ 114272343Sngie (sizeof(le_lebuffer_media) / sizeof(le_lebuffer_media[0])) 115272343Sngie 116272343Sngiestatic void le_lebuffer_wrcsr(struct lance_softc *, uint16_t, uint16_t); 117272343Sngiestatic uint16_t le_lebuffer_rdcsr(struct lance_softc *, uint16_t); 118272343Sngiestatic void le_lebuffer_copytodesc(struct lance_softc *, void *, int, int); 119272343Sngiestatic void le_lebuffer_copyfromdesc(struct lance_softc *, void *, int, int); 120272343Sngiestatic void le_lebuffer_copytobuf(struct lance_softc *, void *, int, int); 121272343Sngiestatic void le_lebuffer_copyfrombuf(struct lance_softc *, void *, int, int); 122272343Sngiestatic void le_lebuffer_zerobuf(struct lance_softc *, int, int); 123272343Sngie 124272343Sngiestatic void 125272343Sngiele_lebuffer_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val) 126272343Sngie{ 127272343Sngie struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; 128272343Sngie 129272343Sngie bus_space_write_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, port); 130272343Sngie bus_space_barrier(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, 2, 131272343Sngie BUS_SPACE_BARRIER_WRITE); 132272343Sngie bus_space_write_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RDP, val); 133272343Sngie} 134272343Sngie 135272343Sngiestatic uint16_t 136272343Sngiele_lebuffer_rdcsr(struct lance_softc *sc, uint16_t port) 137272343Sngie{ 138272343Sngie struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; 139272343Sngie 140272343Sngie bus_space_write_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, port); 141272343Sngie bus_space_barrier(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, 2, 142272343Sngie BUS_SPACE_BARRIER_WRITE); 143272343Sngie return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RDP)); 144272343Sngie} 145272343Sngie 146272343Sngie/* 147272343Sngie * It turns out that using bus_space(9) to access the buffers and the 148272343Sngie * descriptors yields way more throughput than accessing them via the 149272343Sngie * KVA returned by rman_get_virtual(9). The descriptor rings can be 150272343Sngie * accessed using 8-bit up to 64-bit operations while the buffers can 151272343Sngie * be only accessed using 8-bit and 16-bit operations. 152272343Sngie * NB: For whatever reason setting LE_C3_BSWP has no effect with at 153272343Sngie * least the 501-2981 (although their 'busmaster-regval' property 154272343Sngie * indicates to set LE_C3_BSWP also for these cards), so we need 155272343Sngie * to manually byte swap access to the buffers, i.e. the accesses 156272343Sngie * going through the RX/TX FIFOs. 157272343Sngie */ 158272343Sngie 159272343Sngiestatic void 160272343Sngiele_lebuffer_copytodesc(struct lance_softc *sc, void *fromv, int off, int len) 161272343Sngie{ 162272343Sngie struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; 163272343Sngie caddr_t from = fromv; 164272343Sngie 165272343Sngie for (; len >= 8; len -= 8, off += 8, from += 8) 166272343Sngie bus_space_write_8(lesc->sc_buft, lesc->sc_bufh, off, 167272343Sngie be64dec(from)); 168272343Sngie for (; len >= 4; len -= 4, off += 4, from += 4) 169272343Sngie bus_space_write_4(lesc->sc_buft, lesc->sc_bufh, off, 170272343Sngie be32dec(from)); 171272343Sngie for (; len >= 2; len -= 2, off += 2, from += 2) 172272343Sngie bus_space_write_2(lesc->sc_buft, lesc->sc_bufh, off, 173272343Sngie be16dec(from)); 174272343Sngie if (len == 1) 175272343Sngie bus_space_write_1(lesc->sc_buft, lesc->sc_bufh, off, 176272343Sngie *from); 177272343Sngie} 178272343Sngie 179272343Sngiestatic void 180272343Sngiele_lebuffer_copyfromdesc(struct lance_softc *sc, void *tov, int off, int len) 181272343Sngie{ 182272343Sngie struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; 183272343Sngie caddr_t to = tov; 184272343Sngie 185272343Sngie for (; len >= 8; len -= 8, off += 8, to += 8) 186272343Sngie be64enc(to, 187272343Sngie bus_space_read_8(lesc->sc_buft, lesc->sc_bufh, off)); 188272343Sngie for (; len >= 4; len -= 4, off += 4, to += 4) 189272343Sngie be32enc(to, 190272343Sngie bus_space_read_4(lesc->sc_buft, lesc->sc_bufh, off)); 191272343Sngie for (; len >= 2; len -= 2, off += 2, to += 2) 192272343Sngie be16enc(to, 193272343Sngie bus_space_read_2(lesc->sc_buft, lesc->sc_bufh, off)); 194272343Sngie if (len == 1) 195272343Sngie *to = 196272343Sngie bus_space_read_1(lesc->sc_buft, lesc->sc_bufh, off); 197272343Sngie} 198272343Sngie 199272343Sngiestatic void 200272343Sngiele_lebuffer_copytobuf(struct lance_softc *sc, void *fromv, int off, int len) 201272343Sngie{ 202272343Sngie struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; 203272343Sngie caddr_t from = fromv; 204272343Sngie 205272343Sngie for (; len >= 2; len -= 2, off += 2, from += 2) 206272343Sngie bus_space_write_2(lesc->sc_buft, lesc->sc_bufh, off, 207272343Sngie le16dec(from)); 208272343Sngie if (len == 1) 209272343Sngie bus_space_write_1(lesc->sc_buft, lesc->sc_bufh, off + 1, 210272343Sngie *from); 211272343Sngie} 212272343Sngie 213272343Sngiestatic void 214272343Sngiele_lebuffer_copyfrombuf(struct lance_softc *sc, void *tov, int off, int len) 215272343Sngie{ 216272343Sngie struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; 217272343Sngie caddr_t to = tov; 218272343Sngie 219272343Sngie for (; len >= 2; len -= 2, off += 2, to += 2) 220272343Sngie le16enc(to, 221272343Sngie bus_space_read_2(lesc->sc_buft, lesc->sc_bufh, off)); 222272343Sngie if (len == 1) 223272343Sngie *to = 224272343Sngie bus_space_read_1(lesc->sc_buft, lesc->sc_bufh, off + 1); 225272343Sngie} 226272343Sngie 227272343Sngiestatic void 228272343Sngiele_lebuffer_zerobuf(struct lance_softc *sc, int off, int len) 229272343Sngie{ 230272343Sngie struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; 231272343Sngie 232272343Sngie for (; len >= 2; len -= 2, off += 2) 233272343Sngie bus_space_write_2(lesc->sc_buft, lesc->sc_bufh, off, 0); 234272343Sngie if (len == 1) 235272343Sngie bus_space_write_1(lesc->sc_buft, lesc->sc_bufh, off + 1, 0); 236272343Sngie} 237272343Sngie 238272343Sngiestatic int 239272343Sngiele_lebuffer_probe(device_t dev) 240272343Sngie{ 241272343Sngie 242272343Sngie if (strcmp(ofw_bus_get_name(dev), "le") == 0) { 243272343Sngie device_set_desc(dev, "LANCE Ethernet"); 244272343Sngie return (BUS_PROBE_DEFAULT); 245272343Sngie } 246272343Sngie return (ENXIO); 247272343Sngie} 248272343Sngie 249272343Sngiestatic int 250272343Sngiele_lebuffer_attach(device_t dev) 251{ 252 struct le_lebuffer_softc *lesc; 253 struct lance_softc *sc; 254 int error; 255 256 lesc = device_get_softc(dev); 257 sc = &lesc->sc_am7990.lsc; 258 259 LE_LOCK_INIT(sc, device_get_nameunit(dev)); 260 261 /* 262 * The "register space" of the parent is just a buffer where the 263 * the LANCE descriptor rings and the RX/TX buffers can be stored. 264 */ 265 lesc->sc_brid = 0; 266 lesc->sc_bres = bus_alloc_resource_any(device_get_parent(dev), 267 SYS_RES_MEMORY, &lesc->sc_brid, RF_ACTIVE); 268 if (lesc->sc_bres == NULL) { 269 device_printf(dev, "cannot allocate LANCE buffer\n"); 270 error = ENXIO; 271 goto fail_mtx; 272 } 273 lesc->sc_buft = rman_get_bustag(lesc->sc_bres); 274 lesc->sc_bufh = rman_get_bushandle(lesc->sc_bres); 275 276 /* Allocate LANCE registers. */ 277 lesc->sc_rrid = 0; 278 lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 279 &lesc->sc_rrid, RF_ACTIVE); 280 if (lesc->sc_rres == NULL) { 281 device_printf(dev, "cannot allocate LANCE registers\n"); 282 error = ENXIO; 283 goto fail_bres; 284 } 285 lesc->sc_regt = rman_get_bustag(lesc->sc_rres); 286 lesc->sc_regh = rman_get_bushandle(lesc->sc_rres); 287 288 /* Allocate LANCE interrupt. */ 289 lesc->sc_irid = 0; 290 if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 291 &lesc->sc_irid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 292 device_printf(dev, "cannot allocate interrupt\n"); 293 error = ENXIO; 294 goto fail_rres; 295 } 296 297 /* 298 * LANCE view is offset by buffer location. 299 * Note that we don't use sc->sc_mem. 300 */ 301 sc->sc_addr = 0; 302 sc->sc_memsize = rman_get_size(lesc->sc_bres); 303 sc->sc_flags = 0; 304 305 /* That old black magic... */ 306 if (OF_getprop(ofw_bus_get_node(dev), "busmaster-regval", 307 &sc->sc_conf3, sizeof(sc->sc_conf3)) == -1) 308 sc->sc_conf3 = LE_C3_ACON | LE_C3_BCON; 309 /* 310 * Make sure LE_C3_BSWP is cleared so that for cards where 311 * that flag actually works le_lebuffer_copy{from,to}buf() 312 * don't fail... 313 */ 314 sc->sc_conf3 &= ~LE_C3_BSWP; 315 316 OF_getetheraddr(dev, sc->sc_enaddr); 317 318 sc->sc_copytodesc = le_lebuffer_copytodesc; 319 sc->sc_copyfromdesc = le_lebuffer_copyfromdesc; 320 sc->sc_copytobuf = le_lebuffer_copytobuf; 321 sc->sc_copyfrombuf = le_lebuffer_copyfrombuf; 322 sc->sc_zerobuf = le_lebuffer_zerobuf; 323 324 sc->sc_rdcsr = le_lebuffer_rdcsr; 325 sc->sc_wrcsr = le_lebuffer_wrcsr; 326 sc->sc_hwreset = NULL; 327 sc->sc_hwinit = NULL; 328 sc->sc_hwintr = NULL; 329 sc->sc_nocarrier = NULL; 330 sc->sc_mediachange = NULL; 331 sc->sc_mediastatus = NULL; 332 sc->sc_supmedia = le_lebuffer_media; 333 sc->sc_nsupmedia = NLEMEDIA; 334 sc->sc_defaultmedia = le_lebuffer_media[0]; 335 336 error = am7990_config(&lesc->sc_am7990, device_get_name(dev), 337 device_get_unit(dev)); 338 if (error != 0) { 339 device_printf(dev, "cannot attach Am7990\n"); 340 goto fail_ires; 341 } 342 343 error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE, 344 am7990_intr, sc, &lesc->sc_ih); 345 if (error != 0) { 346 device_printf(dev, "cannot set up interrupt\n"); 347 goto fail_am7990; 348 } 349 350 return (0); 351 352 fail_am7990: 353 am7990_detach(&lesc->sc_am7990); 354 fail_ires: 355 bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires); 356 fail_rres: 357 bus_release_resource(dev, SYS_RES_MEMORY, lesc->sc_rrid, lesc->sc_rres); 358 fail_bres: 359 bus_release_resource(device_get_parent(dev), SYS_RES_MEMORY, 360 lesc->sc_brid, lesc->sc_bres); 361 fail_mtx: 362 LE_LOCK_DESTROY(sc); 363 return (error); 364} 365 366static int 367le_lebuffer_detach(device_t dev) 368{ 369 struct le_lebuffer_softc *lesc; 370 struct lance_softc *sc; 371 372 lesc = device_get_softc(dev); 373 sc = &lesc->sc_am7990.lsc; 374 375 bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih); 376 am7990_detach(&lesc->sc_am7990); 377 bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires); 378 bus_release_resource(dev, SYS_RES_MEMORY, lesc->sc_rrid, lesc->sc_rres); 379 bus_release_resource(device_get_parent(dev), SYS_RES_MEMORY, 380 lesc->sc_brid, lesc->sc_bres); 381 LE_LOCK_DESTROY(sc); 382 383 return (0); 384} 385 386static int 387le_buffer_suspend(device_t dev) 388{ 389 struct le_lebuffer_softc *lesc; 390 391 lesc = device_get_softc(dev); 392 393 lance_suspend(&lesc->sc_am7990.lsc); 394 395 return (0); 396} 397 398static int 399le_buffer_resume(device_t dev) 400{ 401 struct le_lebuffer_softc *lesc; 402 403 lesc = device_get_softc(dev); 404 405 lance_resume(&lesc->sc_am7990.lsc); 406 407 return (0); 408} 409