if_le_lebuffer.c revision 256281
1/*- 2 * Copyright (c) 2006 Marius Strobl <marius@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 AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: stable/10/sys/dev/le/if_le_lebuffer.c 183337 2008-09-24 21:26:46Z marius $"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/bus.h> 33#include <sys/endian.h> 34#include <sys/kernel.h> 35#include <sys/lock.h> 36#include <sys/module.h> 37#include <sys/mutex.h> 38#include <sys/resource.h> 39#include <sys/rman.h> 40#include <sys/socket.h> 41 42#include <dev/ofw/ofw_bus.h> 43 44#include <machine/bus.h> 45#include <machine/ofw_machdep.h> 46#include <machine/resource.h> 47 48#include <net/ethernet.h> 49#include <net/if.h> 50#include <net/if_media.h> 51 52#include <dev/le/lancereg.h> 53#include <dev/le/lancevar.h> 54#include <dev/le/am7990reg.h> 55#include <dev/le/am7990var.h> 56 57/* 58 * LANCE registers 59 */ 60#define LEREG1_RDP 0 /* Register Data port */ 61#define LEREG1_RAP 2 /* Register Address port */ 62 63struct le_lebuffer_softc { 64 struct am7990_softc sc_am7990; /* glue to MI code */ 65 66 struct resource *sc_bres; 67 68 struct resource *sc_rres; 69 70 struct resource *sc_ires; 71 void *sc_ih; 72}; 73 74static devclass_t le_lebuffer_devclass; 75 76static device_probe_t le_lebuffer_probe; 77static device_attach_t le_lebuffer_attach; 78static device_detach_t le_lebuffer_detach; 79static device_resume_t le_buffer_resume; 80static device_suspend_t le_buffer_suspend; 81 82static device_method_t le_lebuffer_methods[] = { 83 /* Device interface */ 84 DEVMETHOD(device_probe, le_lebuffer_probe), 85 DEVMETHOD(device_attach, le_lebuffer_attach), 86 DEVMETHOD(device_detach, le_lebuffer_detach), 87 /* We can just use the suspend method here. */ 88 DEVMETHOD(device_shutdown, le_buffer_suspend), 89 DEVMETHOD(device_suspend, le_buffer_suspend), 90 DEVMETHOD(device_resume, le_buffer_resume), 91 92 { 0, 0 } 93}; 94 95DEFINE_CLASS_0(le, le_lebuffer_driver, le_lebuffer_methods, 96 sizeof(struct le_lebuffer_softc)); 97DRIVER_MODULE(le, lebuffer, le_lebuffer_driver, le_lebuffer_devclass, 0, 0); 98MODULE_DEPEND(le, ether, 1, 1, 1); 99MODULE_DEPEND(le, lebuffer, 1, 1, 1); 100 101/* 102 * Media types supported 103 */ 104static const int le_lebuffer_media[] = { 105 IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0) 106}; 107#define NLEMEDIA \ 108 (sizeof(le_lebuffer_media) / sizeof(le_lebuffer_media[0])) 109 110static void le_lebuffer_wrcsr(struct lance_softc *, uint16_t, uint16_t); 111static uint16_t le_lebuffer_rdcsr(struct lance_softc *, uint16_t); 112static void le_lebuffer_copytodesc(struct lance_softc *, void *, int, int); 113static void le_lebuffer_copyfromdesc(struct lance_softc *, void *, int, int); 114static void le_lebuffer_copytobuf(struct lance_softc *, void *, int, int); 115static void le_lebuffer_copyfrombuf(struct lance_softc *, void *, int, int); 116static void le_lebuffer_zerobuf(struct lance_softc *, int, int); 117 118static void 119le_lebuffer_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val) 120{ 121 struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; 122 123 bus_write_2(lesc->sc_rres, LEREG1_RAP, port); 124 bus_barrier(lesc->sc_rres, LEREG1_RAP, 2, BUS_SPACE_BARRIER_WRITE); 125 bus_write_2(lesc->sc_rres, LEREG1_RDP, val); 126} 127 128static uint16_t 129le_lebuffer_rdcsr(struct lance_softc *sc, uint16_t port) 130{ 131 struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; 132 133 bus_write_2(lesc->sc_rres, LEREG1_RAP, port); 134 bus_barrier(lesc->sc_rres, LEREG1_RAP, 2, BUS_SPACE_BARRIER_WRITE); 135 return (bus_read_2(lesc->sc_rres, LEREG1_RDP)); 136} 137 138/* 139 * It turns out that using bus_space(9) to access the buffers and the 140 * descriptors yields way more throughput than accessing them via the 141 * KVA returned by rman_get_virtual(9). The descriptor rings can be 142 * accessed using 8-bit up to 64-bit operations while the buffers can 143 * be only accessed using 8-bit and 16-bit operations. 144 * NB: For whatever reason setting LE_C3_BSWP has no effect with at 145 * least the 501-2981 (although their 'busmaster-regval' property 146 * indicates to set LE_C3_BSWP also for these cards), so we need 147 * to manually byte swap access to the buffers, i.e. the accesses 148 * going through the RX/TX FIFOs. 149 */ 150 151static void 152le_lebuffer_copytodesc(struct lance_softc *sc, void *fromv, int off, int len) 153{ 154 struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; 155 caddr_t from = fromv; 156 157 for (; len >= 8; len -= 8, off += 8, from += 8) 158 bus_write_8(lesc->sc_bres, off, be64dec(from)); 159 for (; len >= 4; len -= 4, off += 4, from += 4) 160 bus_write_4(lesc->sc_bres, off, be32dec(from)); 161 for (; len >= 2; len -= 2, off += 2, from += 2) 162 bus_write_2(lesc->sc_bres, off, be16dec(from)); 163 if (len == 1) 164 bus_write_1(lesc->sc_bres, off, *from); 165} 166 167static void 168le_lebuffer_copyfromdesc(struct lance_softc *sc, void *tov, int off, int len) 169{ 170 struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; 171 caddr_t to = tov; 172 173 for (; len >= 8; len -= 8, off += 8, to += 8) 174 be64enc(to, 175 bus_read_8(lesc->sc_bres, off)); 176 for (; len >= 4; len -= 4, off += 4, to += 4) 177 be32enc(to, 178 bus_read_4(lesc->sc_bres, off)); 179 for (; len >= 2; len -= 2, off += 2, to += 2) 180 be16enc(to, 181 bus_read_2(lesc->sc_bres, off)); 182 if (len == 1) 183 *to = bus_read_1(lesc->sc_bres, off); 184} 185 186static void 187le_lebuffer_copytobuf(struct lance_softc *sc, void *fromv, int off, int len) 188{ 189 struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; 190 caddr_t from = fromv; 191 192 for (; len >= 2; len -= 2, off += 2, from += 2) 193 bus_write_2(lesc->sc_bres, off, le16dec(from)); 194 if (len == 1) 195 bus_write_1(lesc->sc_bres, off + 1, *from); 196} 197 198static void 199le_lebuffer_copyfrombuf(struct lance_softc *sc, void *tov, int off, int len) 200{ 201 struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; 202 caddr_t to = tov; 203 204 for (; len >= 2; len -= 2, off += 2, to += 2) 205 le16enc(to, 206 bus_read_2(lesc->sc_bres, off)); 207 if (len == 1) 208 *to = bus_read_1(lesc->sc_bres, off + 1); 209} 210 211static void 212le_lebuffer_zerobuf(struct lance_softc *sc, int off, int len) 213{ 214 struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; 215 216 for (; len >= 2; len -= 2, off += 2) 217 bus_write_2(lesc->sc_bres, off, 0); 218 if (len == 1) 219 bus_write_1(lesc->sc_bres, off + 1, 0); 220} 221 222static int 223le_lebuffer_probe(device_t dev) 224{ 225 226 if (strcmp(ofw_bus_get_name(dev), "le") == 0) { 227 device_set_desc(dev, "LANCE Ethernet"); 228 return (BUS_PROBE_DEFAULT); 229 } 230 return (ENXIO); 231} 232 233static int 234le_lebuffer_attach(device_t dev) 235{ 236 struct le_lebuffer_softc *lesc; 237 struct lance_softc *sc; 238 int error, i; 239 240 lesc = device_get_softc(dev); 241 sc = &lesc->sc_am7990.lsc; 242 243 LE_LOCK_INIT(sc, device_get_nameunit(dev)); 244 245 /* 246 * The "register space" of the parent is just a buffer where the 247 * the LANCE descriptor rings and the RX/TX buffers can be stored. 248 */ 249 i = 0; 250 lesc->sc_bres = bus_alloc_resource_any(device_get_parent(dev), 251 SYS_RES_MEMORY, &i, RF_ACTIVE); 252 if (lesc->sc_bres == NULL) { 253 device_printf(dev, "cannot allocate LANCE buffer\n"); 254 error = ENXIO; 255 goto fail_mtx; 256 } 257 258 /* Allocate LANCE registers. */ 259 i = 0; 260 lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 261 &i, RF_ACTIVE); 262 if (lesc->sc_rres == NULL) { 263 device_printf(dev, "cannot allocate LANCE registers\n"); 264 error = ENXIO; 265 goto fail_bres; 266 } 267 268 /* Allocate LANCE interrupt. */ 269 i = 0; 270 if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 271 &i, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 272 device_printf(dev, "cannot allocate interrupt\n"); 273 error = ENXIO; 274 goto fail_rres; 275 } 276 277 /* 278 * LANCE view is offset by buffer location. 279 * Note that we don't use sc->sc_mem. 280 */ 281 sc->sc_addr = 0; 282 sc->sc_memsize = rman_get_size(lesc->sc_bres); 283 sc->sc_flags = 0; 284 285 /* That old black magic... */ 286 if (OF_getprop(ofw_bus_get_node(dev), "busmaster-regval", 287 &sc->sc_conf3, sizeof(sc->sc_conf3)) == -1) 288 sc->sc_conf3 = LE_C3_ACON | LE_C3_BCON; 289 /* 290 * Make sure LE_C3_BSWP is cleared so that for cards where 291 * that flag actually works le_lebuffer_copy{from,to}buf() 292 * don't fail... 293 */ 294 sc->sc_conf3 &= ~LE_C3_BSWP; 295 296 OF_getetheraddr(dev, sc->sc_enaddr); 297 298 sc->sc_copytodesc = le_lebuffer_copytodesc; 299 sc->sc_copyfromdesc = le_lebuffer_copyfromdesc; 300 sc->sc_copytobuf = le_lebuffer_copytobuf; 301 sc->sc_copyfrombuf = le_lebuffer_copyfrombuf; 302 sc->sc_zerobuf = le_lebuffer_zerobuf; 303 304 sc->sc_rdcsr = le_lebuffer_rdcsr; 305 sc->sc_wrcsr = le_lebuffer_wrcsr; 306 sc->sc_hwreset = NULL; 307 sc->sc_hwinit = NULL; 308 sc->sc_hwintr = NULL; 309 sc->sc_nocarrier = NULL; 310 sc->sc_mediachange = NULL; 311 sc->sc_mediastatus = NULL; 312 sc->sc_supmedia = le_lebuffer_media; 313 sc->sc_nsupmedia = NLEMEDIA; 314 sc->sc_defaultmedia = le_lebuffer_media[0]; 315 316 error = am7990_config(&lesc->sc_am7990, device_get_name(dev), 317 device_get_unit(dev)); 318 if (error != 0) { 319 device_printf(dev, "cannot attach Am7990\n"); 320 goto fail_ires; 321 } 322 323 error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE, 324 NULL, am7990_intr, sc, &lesc->sc_ih); 325 if (error != 0) { 326 device_printf(dev, "cannot set up interrupt\n"); 327 goto fail_am7990; 328 } 329 330 return (0); 331 332 fail_am7990: 333 am7990_detach(&lesc->sc_am7990); 334 fail_ires: 335 bus_release_resource(dev, SYS_RES_IRQ, 336 rman_get_rid(lesc->sc_ires), lesc->sc_ires); 337 fail_rres: 338 bus_release_resource(dev, SYS_RES_MEMORY, 339 rman_get_rid(lesc->sc_rres), lesc->sc_rres); 340 fail_bres: 341 bus_release_resource(device_get_parent(dev), SYS_RES_MEMORY, 342 rman_get_rid(lesc->sc_bres), lesc->sc_bres); 343 fail_mtx: 344 LE_LOCK_DESTROY(sc); 345 return (error); 346} 347 348static int 349le_lebuffer_detach(device_t dev) 350{ 351 struct le_lebuffer_softc *lesc; 352 struct lance_softc *sc; 353 354 lesc = device_get_softc(dev); 355 sc = &lesc->sc_am7990.lsc; 356 357 bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih); 358 am7990_detach(&lesc->sc_am7990); 359 bus_release_resource(dev, SYS_RES_IRQ, 360 rman_get_rid(lesc->sc_ires), lesc->sc_ires); 361 bus_release_resource(dev, SYS_RES_MEMORY, 362 rman_get_rid(lesc->sc_rres), lesc->sc_rres); 363 bus_release_resource(device_get_parent(dev), SYS_RES_MEMORY, 364 rman_get_rid(lesc->sc_bres), lesc->sc_bres); 365 LE_LOCK_DESTROY(sc); 366 367 return (0); 368} 369 370static int 371le_buffer_suspend(device_t dev) 372{ 373 struct le_lebuffer_softc *lesc; 374 375 lesc = device_get_softc(dev); 376 377 lance_suspend(&lesc->sc_am7990.lsc); 378 379 return (0); 380} 381 382static int 383le_buffer_resume(device_t dev) 384{ 385 struct le_lebuffer_softc *lesc; 386 387 lesc = device_get_softc(dev); 388 389 lance_resume(&lesc->sc_am7990.lsc); 390 391 return (0); 392} 393