if_rue.c revision 188746
1184610Salfred/*- 2184610Salfred * Copyright (c) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>. 3184610Salfred * Copyright (c) 1997, 1998, 1999, 2000 Bill Paul <wpaul@ee.columbia.edu>. 4184610Salfred * All rights reserved. 5184610Salfred * 6184610Salfred * Redistribution and use in source and binary forms, with or without 7184610Salfred * modification, are permitted provided that the following conditions 8184610Salfred * are met: 9184610Salfred * 1. Redistributions of source code must retain the above copyright 10184610Salfred * notice, this list of conditions and the following disclaimer. 11184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 12184610Salfred * notice, this list of conditions and the following disclaimer in the 13184610Salfred * documentation and/or other materials provided with the distribution. 14184610Salfred * 15184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25184610Salfred * SUCH DAMAGE. 26184610Salfred */ 27184610Salfred/*- 28184610Salfred * Copyright (c) 1997, 1998, 1999, 2000 29184610Salfred * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. 30184610Salfred * 31184610Salfred * Redistribution and use in source and binary forms, with or without 32184610Salfred * modification, are permitted provided that the following conditions 33184610Salfred * are met: 34184610Salfred * 1. Redistributions of source code must retain the above copyright 35184610Salfred * notice, this list of conditions and the following disclaimer. 36184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 37184610Salfred * notice, this list of conditions and the following disclaimer in the 38184610Salfred * documentation and/or other materials provided with the distribution. 39184610Salfred * 3. All advertising materials mentioning features or use of this software 40184610Salfred * must display the following acknowledgement: 41184610Salfred * This product includes software developed by Bill Paul. 42184610Salfred * 4. Neither the name of the author nor the names of any co-contributors 43184610Salfred * may be used to endorse or promote products derived from this software 44184610Salfred * without specific prior written permission. 45184610Salfred * 46184610Salfred * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 47184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 50184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 51184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 52184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 53184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 54184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 55184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 56184610Salfred * THE POSSIBILITY OF SUCH DAMAGE. 57184610Salfred */ 58184610Salfred 59184610Salfred#include <sys/cdefs.h> 60184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb2/ethernet/if_rue2.c 188746 2009-02-18 06:33:10Z thompsa $"); 61184610Salfred 62184610Salfred/* 63184610Salfred * RealTek RTL8150 USB to fast ethernet controller driver. 64184610Salfred * Datasheet is available from 65184610Salfred * ftp://ftp.realtek.com.tw/lancard/data_sheet/8150/. 66184610Salfred */ 67184610Salfred 68188746Sthompsa#include "usbdevs.h" 69184610Salfred#include <dev/usb2/include/usb2_standard.h> 70184610Salfred#include <dev/usb2/include/usb2_mfunc.h> 71184610Salfred#include <dev/usb2/include/usb2_error.h> 72184610Salfred 73184610Salfred#define USB_DEBUG_VAR rue_debug 74184610Salfred 75184610Salfred#include <dev/usb2/core/usb2_core.h> 76184610Salfred#include <dev/usb2/core/usb2_lookup.h> 77184610Salfred#include <dev/usb2/core/usb2_process.h> 78184610Salfred#include <dev/usb2/core/usb2_debug.h> 79184610Salfred#include <dev/usb2/core/usb2_request.h> 80184610Salfred#include <dev/usb2/core/usb2_busdma.h> 81184610Salfred#include <dev/usb2/core/usb2_util.h> 82184610Salfred 83184610Salfred#include <dev/usb2/ethernet/usb2_ethernet.h> 84187192Sthompsa#include <dev/usb2/ethernet/if_ruereg.h> 85184610Salfred 86184610Salfred#if USB_DEBUG 87184610Salfredstatic int rue_debug = 0; 88184610Salfred 89184610SalfredSYSCTL_NODE(_hw_usb2, OID_AUTO, rue, CTLFLAG_RW, 0, "USB rue"); 90184610SalfredSYSCTL_INT(_hw_usb2_rue, OID_AUTO, debug, CTLFLAG_RW, 91184610Salfred &rue_debug, 0, "Debug level"); 92184610Salfred#endif 93184610Salfred 94184610Salfred/* 95184610Salfred * Various supported device vendors/products. 96184610Salfred */ 97184610Salfred 98184610Salfredstatic const struct usb2_device_id rue_devs[] = { 99184610Salfred {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX, 0)}, 100184610Salfred {USB_VPI(USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_USBKR100, 0)}, 101184610Salfred}; 102184610Salfred 103184610Salfred/* prototypes */ 104184610Salfred 105184610Salfredstatic device_probe_t rue_probe; 106184610Salfredstatic device_attach_t rue_attach; 107184610Salfredstatic device_detach_t rue_detach; 108184610Salfredstatic device_shutdown_t rue_shutdown; 109184610Salfred 110188412Sthompsastatic miibus_readreg_t rue_miibus_readreg; 111188412Sthompsastatic miibus_writereg_t rue_miibus_writereg; 112188412Sthompsastatic miibus_statchg_t rue_miibus_statchg; 113188412Sthompsa 114184610Salfredstatic usb2_callback_t rue_intr_callback; 115184610Salfredstatic usb2_callback_t rue_bulk_read_callback; 116184610Salfredstatic usb2_callback_t rue_bulk_write_callback; 117184610Salfred 118188412Sthompsastatic usb2_ether_fn_t rue_attach_post; 119188412Sthompsastatic usb2_ether_fn_t rue_init; 120188412Sthompsastatic usb2_ether_fn_t rue_stop; 121188412Sthompsastatic usb2_ether_fn_t rue_start; 122188412Sthompsastatic usb2_ether_fn_t rue_tick; 123188412Sthompsastatic usb2_ether_fn_t rue_setmulti; 124188412Sthompsastatic usb2_ether_fn_t rue_setpromisc; 125184610Salfred 126188412Sthompsastatic int rue_read_mem(struct rue_softc *, uint16_t, void *, int); 127188412Sthompsastatic int rue_write_mem(struct rue_softc *, uint16_t, void *, int); 128188412Sthompsastatic uint8_t rue_csr_read_1(struct rue_softc *, uint16_t); 129188412Sthompsastatic uint16_t rue_csr_read_2(struct rue_softc *, uint16_t); 130188412Sthompsastatic int rue_csr_write_1(struct rue_softc *, uint16_t, uint8_t); 131188412Sthompsastatic int rue_csr_write_2(struct rue_softc *, uint16_t, uint16_t); 132188412Sthompsastatic int rue_csr_write_4(struct rue_softc *, int, uint32_t); 133184610Salfred 134188412Sthompsastatic void rue_reset(struct rue_softc *); 135188412Sthompsastatic int rue_ifmedia_upd(struct ifnet *); 136188412Sthompsastatic void rue_ifmedia_sts(struct ifnet *, struct ifmediareq *); 137184610Salfred 138187259Sthompsastatic const struct usb2_config rue_config[RUE_N_TRANSFER] = { 139184610Salfred 140187259Sthompsa [RUE_BULK_DT_WR] = { 141184610Salfred .type = UE_BULK, 142184610Salfred .endpoint = UE_ADDR_ANY, 143184610Salfred .direction = UE_DIR_OUT, 144184610Salfred .mh.bufsize = MCLBYTES, 145184610Salfred .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 146188412Sthompsa .mh.callback = rue_bulk_write_callback, 147184610Salfred .mh.timeout = 10000, /* 10 seconds */ 148184610Salfred }, 149184610Salfred 150187259Sthompsa [RUE_BULK_DT_RD] = { 151184610Salfred .type = UE_BULK, 152184610Salfred .endpoint = UE_ADDR_ANY, 153184610Salfred .direction = UE_DIR_IN, 154184610Salfred .mh.bufsize = (MCLBYTES + 4), 155184610Salfred .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 156188412Sthompsa .mh.callback = rue_bulk_read_callback, 157184610Salfred .mh.timeout = 0, /* no timeout */ 158184610Salfred }, 159184610Salfred 160187259Sthompsa [RUE_INTR_DT_RD] = { 161184610Salfred .type = UE_INTERRUPT, 162184610Salfred .endpoint = UE_ADDR_ANY, 163184610Salfred .direction = UE_DIR_IN, 164184610Salfred .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 165184610Salfred .mh.bufsize = 0, /* use wMaxPacketSize */ 166188412Sthompsa .mh.callback = rue_intr_callback, 167184610Salfred }, 168184610Salfred}; 169184610Salfred 170184610Salfredstatic device_method_t rue_methods[] = { 171184610Salfred /* Device interface */ 172184610Salfred DEVMETHOD(device_probe, rue_probe), 173184610Salfred DEVMETHOD(device_attach, rue_attach), 174184610Salfred DEVMETHOD(device_detach, rue_detach), 175184610Salfred DEVMETHOD(device_shutdown, rue_shutdown), 176184610Salfred 177184610Salfred /* Bus interface */ 178184610Salfred DEVMETHOD(bus_print_child, bus_generic_print_child), 179184610Salfred DEVMETHOD(bus_driver_added, bus_generic_driver_added), 180184610Salfred 181184610Salfred /* MII interface */ 182188412Sthompsa DEVMETHOD(miibus_readreg, rue_miibus_readreg), 183188412Sthompsa DEVMETHOD(miibus_writereg, rue_miibus_writereg), 184188412Sthompsa DEVMETHOD(miibus_statchg, rue_miibus_statchg), 185184610Salfred 186184610Salfred {0, 0} 187184610Salfred}; 188184610Salfred 189184610Salfredstatic driver_t rue_driver = { 190184610Salfred .name = "rue", 191184610Salfred .methods = rue_methods, 192184610Salfred .size = sizeof(struct rue_softc), 193184610Salfred}; 194184610Salfred 195184610Salfredstatic devclass_t rue_devclass; 196184610Salfred 197184610SalfredDRIVER_MODULE(rue, ushub, rue_driver, rue_devclass, NULL, 0); 198184610SalfredDRIVER_MODULE(miibus, rue, miibus_driver, miibus_devclass, 0, 0); 199184610SalfredMODULE_DEPEND(rue, usb2_ethernet, 1, 1, 1); 200184610SalfredMODULE_DEPEND(rue, usb2_core, 1, 1, 1); 201184610SalfredMODULE_DEPEND(rue, ether, 1, 1, 1); 202184610SalfredMODULE_DEPEND(rue, miibus, 1, 1, 1); 203184610Salfred 204188412Sthompsastatic const struct usb2_ether_methods rue_ue_methods = { 205188412Sthompsa .ue_attach_post = rue_attach_post, 206188412Sthompsa .ue_start = rue_start, 207188412Sthompsa .ue_init = rue_init, 208188412Sthompsa .ue_stop = rue_stop, 209188412Sthompsa .ue_tick = rue_tick, 210188412Sthompsa .ue_setmulti = rue_setmulti, 211188412Sthompsa .ue_setpromisc = rue_setpromisc, 212188412Sthompsa .ue_mii_upd = rue_ifmedia_upd, 213188412Sthompsa .ue_mii_sts = rue_ifmedia_sts, 214188412Sthompsa}; 215184610Salfred 216188412Sthompsa#define RUE_SETBIT(sc, reg, x) \ 217188412Sthompsa rue_csr_write_1(sc, reg, rue_csr_read_1(sc, reg) | (x)) 218184610Salfred 219188412Sthompsa#define RUE_CLRBIT(sc, reg, x) \ 220188412Sthompsa rue_csr_write_1(sc, reg, rue_csr_read_1(sc, reg) & ~(x)) 221184610Salfred 222188412Sthompsastatic int 223188412Sthompsarue_read_mem(struct rue_softc *sc, uint16_t addr, void *buf, int len) 224184610Salfred{ 225184610Salfred struct usb2_device_request req; 226184610Salfred 227184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 228184610Salfred req.bRequest = UR_SET_ADDRESS; 229184610Salfred USETW(req.wValue, addr); 230184610Salfred USETW(req.wIndex, 0); 231184610Salfred USETW(req.wLength, len); 232184610Salfred 233188412Sthompsa return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000)); 234184610Salfred} 235184610Salfred 236188412Sthompsastatic int 237188412Sthompsarue_write_mem(struct rue_softc *sc, uint16_t addr, void *buf, int len) 238184610Salfred{ 239184610Salfred struct usb2_device_request req; 240184610Salfred 241184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 242184610Salfred req.bRequest = UR_SET_ADDRESS; 243184610Salfred USETW(req.wValue, addr); 244184610Salfred USETW(req.wIndex, 0); 245184610Salfred USETW(req.wLength, len); 246184610Salfred 247188412Sthompsa return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000)); 248184610Salfred} 249184610Salfred 250184610Salfredstatic uint8_t 251188412Sthompsarue_csr_read_1(struct rue_softc *sc, uint16_t reg) 252184610Salfred{ 253184610Salfred uint8_t val; 254184610Salfred 255188412Sthompsa rue_read_mem(sc, reg, &val, 1); 256184610Salfred return (val); 257184610Salfred} 258184610Salfred 259184610Salfredstatic uint16_t 260188412Sthompsarue_csr_read_2(struct rue_softc *sc, uint16_t reg) 261184610Salfred{ 262184610Salfred uint8_t val[2]; 263184610Salfred 264188412Sthompsa rue_read_mem(sc, reg, &val, 2); 265184610Salfred return (UGETW(val)); 266184610Salfred} 267184610Salfred 268188412Sthompsastatic int 269188412Sthompsarue_csr_write_1(struct rue_softc *sc, uint16_t reg, uint8_t val) 270184610Salfred{ 271188412Sthompsa return (rue_write_mem(sc, reg, &val, 1)); 272184610Salfred} 273184610Salfred 274188412Sthompsastatic int 275188412Sthompsarue_csr_write_2(struct rue_softc *sc, uint16_t reg, uint16_t val) 276184610Salfred{ 277184610Salfred uint8_t temp[2]; 278184610Salfred 279184610Salfred USETW(temp, val); 280188412Sthompsa return (rue_write_mem(sc, reg, &temp, 2)); 281184610Salfred} 282184610Salfred 283188412Sthompsastatic int 284188412Sthompsarue_csr_write_4(struct rue_softc *sc, int reg, uint32_t val) 285184610Salfred{ 286184610Salfred uint8_t temp[4]; 287184610Salfred 288184610Salfred USETDW(temp, val); 289188412Sthompsa return (rue_write_mem(sc, reg, &temp, 4)); 290184610Salfred} 291184610Salfred 292184610Salfredstatic int 293188412Sthompsarue_miibus_readreg(device_t dev, int phy, int reg) 294184610Salfred{ 295184610Salfred struct rue_softc *sc = device_get_softc(dev); 296184610Salfred uint16_t rval; 297184610Salfred uint16_t ruereg; 298188412Sthompsa int locked; 299184610Salfred 300188412Sthompsa if (phy != 0) /* RTL8150 supports PHY == 0, only */ 301184610Salfred return (0); 302184610Salfred 303188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 304188412Sthompsa if (!locked) 305188412Sthompsa RUE_LOCK(sc); 306188412Sthompsa 307184610Salfred switch (reg) { 308184610Salfred case MII_BMCR: 309184610Salfred ruereg = RUE_BMCR; 310184610Salfred break; 311184610Salfred case MII_BMSR: 312184610Salfred ruereg = RUE_BMSR; 313184610Salfred break; 314184610Salfred case MII_ANAR: 315184610Salfred ruereg = RUE_ANAR; 316184610Salfred break; 317184610Salfred case MII_ANER: 318184610Salfred ruereg = RUE_AER; 319184610Salfred break; 320184610Salfred case MII_ANLPAR: 321184610Salfred ruereg = RUE_ANLP; 322184610Salfred break; 323184610Salfred case MII_PHYIDR1: 324184610Salfred case MII_PHYIDR2: 325184610Salfred rval = 0; 326184610Salfred goto done; 327184610Salfred default: 328188412Sthompsa if (RUE_REG_MIN <= reg && reg <= RUE_REG_MAX) { 329188412Sthompsa rval = rue_csr_read_1(sc, reg); 330184610Salfred goto done; 331184610Salfred } 332188412Sthompsa device_printf(sc->sc_ue.ue_dev, "bad phy register\n"); 333184610Salfred rval = 0; 334184610Salfred goto done; 335184610Salfred } 336184610Salfred 337188412Sthompsa rval = rue_csr_read_2(sc, ruereg); 338184610Salfreddone: 339188412Sthompsa if (!locked) 340188412Sthompsa RUE_UNLOCK(sc); 341184610Salfred return (rval); 342184610Salfred} 343184610Salfred 344184610Salfredstatic int 345188412Sthompsarue_miibus_writereg(device_t dev, int phy, int reg, int data) 346184610Salfred{ 347184610Salfred struct rue_softc *sc = device_get_softc(dev); 348184610Salfred uint16_t ruereg; 349188412Sthompsa int locked; 350184610Salfred 351188412Sthompsa if (phy != 0) /* RTL8150 supports PHY == 0, only */ 352184610Salfred return (0); 353184610Salfred 354188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 355188412Sthompsa if (!locked) 356188412Sthompsa RUE_LOCK(sc); 357188412Sthompsa 358184610Salfred switch (reg) { 359184610Salfred case MII_BMCR: 360184610Salfred ruereg = RUE_BMCR; 361184610Salfred break; 362184610Salfred case MII_BMSR: 363184610Salfred ruereg = RUE_BMSR; 364184610Salfred break; 365184610Salfred case MII_ANAR: 366184610Salfred ruereg = RUE_ANAR; 367184610Salfred break; 368184610Salfred case MII_ANER: 369184610Salfred ruereg = RUE_AER; 370184610Salfred break; 371184610Salfred case MII_ANLPAR: 372184610Salfred ruereg = RUE_ANLP; 373184610Salfred break; 374184610Salfred case MII_PHYIDR1: 375184610Salfred case MII_PHYIDR2: 376184610Salfred goto done; 377184610Salfred default: 378188412Sthompsa if (RUE_REG_MIN <= reg && reg <= RUE_REG_MAX) { 379188412Sthompsa rue_csr_write_1(sc, reg, data); 380184610Salfred goto done; 381184610Salfred } 382188412Sthompsa device_printf(sc->sc_ue.ue_dev, " bad phy register\n"); 383184610Salfred goto done; 384184610Salfred } 385188412Sthompsa rue_csr_write_2(sc, ruereg, data); 386184610Salfreddone: 387188412Sthompsa if (!locked) 388188412Sthompsa RUE_UNLOCK(sc); 389184610Salfred return (0); 390184610Salfred} 391184610Salfred 392184610Salfredstatic void 393188412Sthompsarue_miibus_statchg(device_t dev) 394184610Salfred{ 395184610Salfred /* 396184610Salfred * When the code below is enabled the card starts doing weird 397184610Salfred * things after link going from UP to DOWN and back UP. 398184610Salfred * 399184610Salfred * Looks like some of register writes below messes up PHY 400184610Salfred * interface. 401184610Salfred * 402184610Salfred * No visible regressions were found after commenting this code 403184610Salfred * out, so that disable it for good. 404184610Salfred */ 405184610Salfred#if 0 406184610Salfred struct rue_softc *sc = device_get_softc(dev); 407184610Salfred struct mii_data *mii = GET_MII(sc); 408184610Salfred uint16_t bmcr; 409188412Sthompsa int locked; 410184610Salfred 411188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 412188412Sthompsa if (!locked) 413188412Sthompsa RUE_LOCK(sc); 414184610Salfred 415188412Sthompsa RUE_CLRBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE)); 416184610Salfred 417188412Sthompsa bmcr = rue_csr_read_2(sc, RUE_BMCR); 418184610Salfred 419184610Salfred if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) 420184610Salfred bmcr |= RUE_BMCR_SPD_SET; 421184610Salfred else 422184610Salfred bmcr &= ~RUE_BMCR_SPD_SET; 423184610Salfred 424184610Salfred if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) 425184610Salfred bmcr |= RUE_BMCR_DUPLEX; 426184610Salfred else 427184610Salfred bmcr &= ~RUE_BMCR_DUPLEX; 428184610Salfred 429188412Sthompsa rue_csr_write_2(sc, RUE_BMCR, bmcr); 430184610Salfred 431188412Sthompsa RUE_SETBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE)); 432184610Salfred 433188412Sthompsa if (!locked) 434188412Sthompsa RUE_UNLOCK(sc); 435184610Salfred#endif 436184610Salfred} 437184610Salfred 438184610Salfredstatic void 439188412Sthompsarue_setpromisc(struct usb2_ether *ue) 440184610Salfred{ 441188412Sthompsa struct rue_softc *sc = usb2_ether_getsc(ue); 442188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 443184610Salfred 444188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 445184610Salfred 446188412Sthompsa /* If we want promiscuous mode, set the allframes bit. */ 447188412Sthompsa if (ifp->if_flags & IFF_PROMISC) 448188412Sthompsa RUE_SETBIT(sc, RUE_RCR, RUE_RCR_AAP); 449188412Sthompsa else 450188412Sthompsa RUE_CLRBIT(sc, RUE_RCR, RUE_RCR_AAP); 451184610Salfred} 452184610Salfred 453184610Salfred/* 454184610Salfred * Program the 64-bit multicast hash filter. 455184610Salfred */ 456184610Salfredstatic void 457188412Sthompsarue_setmulti(struct usb2_ether *ue) 458184610Salfred{ 459188412Sthompsa struct rue_softc *sc = usb2_ether_getsc(ue); 460188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 461184610Salfred uint16_t rxcfg; 462188412Sthompsa int h = 0; 463188412Sthompsa uint32_t hashes[2] = { 0, 0 }; 464188412Sthompsa struct ifmultiaddr *ifma; 465188412Sthompsa int mcnt = 0; 466184610Salfred 467188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 468184610Salfred 469188412Sthompsa rxcfg = rue_csr_read_2(sc, RUE_RCR); 470188412Sthompsa 471188412Sthompsa if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 472184610Salfred rxcfg |= (RUE_RCR_AAM | RUE_RCR_AAP); 473184610Salfred rxcfg &= ~RUE_RCR_AM; 474188412Sthompsa rue_csr_write_2(sc, RUE_RCR, rxcfg); 475188412Sthompsa rue_csr_write_4(sc, RUE_MAR0, 0xFFFFFFFF); 476188412Sthompsa rue_csr_write_4(sc, RUE_MAR4, 0xFFFFFFFF); 477184610Salfred return; 478184610Salfred } 479184610Salfred 480188412Sthompsa /* first, zot all the existing hash bits */ 481188412Sthompsa rue_csr_write_4(sc, RUE_MAR0, 0); 482188412Sthompsa rue_csr_write_4(sc, RUE_MAR4, 0); 483188412Sthompsa 484188412Sthompsa /* now program new ones */ 485188412Sthompsa IF_ADDR_LOCK(ifp); 486188412Sthompsa TAILQ_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link) 487188412Sthompsa { 488188412Sthompsa if (ifma->ifma_addr->sa_family != AF_LINK) 489188412Sthompsa continue; 490188412Sthompsa h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 491188412Sthompsa ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 492188412Sthompsa if (h < 32) 493188412Sthompsa hashes[0] |= (1 << h); 494188412Sthompsa else 495188412Sthompsa hashes[1] |= (1 << (h - 32)); 496188412Sthompsa mcnt++; 497188412Sthompsa } 498188412Sthompsa IF_ADDR_UNLOCK(ifp); 499188412Sthompsa 500188412Sthompsa if (mcnt) 501184610Salfred rxcfg |= RUE_RCR_AM; 502184610Salfred else 503184610Salfred rxcfg &= ~RUE_RCR_AM; 504184610Salfred 505184610Salfred rxcfg &= ~(RUE_RCR_AAM | RUE_RCR_AAP); 506184610Salfred 507188412Sthompsa rue_csr_write_2(sc, RUE_RCR, rxcfg); 508188412Sthompsa rue_csr_write_4(sc, RUE_MAR0, hashes[0]); 509188412Sthompsa rue_csr_write_4(sc, RUE_MAR4, hashes[1]); 510184610Salfred} 511184610Salfred 512184610Salfredstatic void 513188412Sthompsarue_reset(struct rue_softc *sc) 514184610Salfred{ 515188412Sthompsa int i; 516184610Salfred 517188412Sthompsa rue_csr_write_1(sc, RUE_CR, RUE_CR_SOFT_RST); 518184610Salfred 519188412Sthompsa for (i = 0; i != RUE_TIMEOUT; i++) { 520188412Sthompsa if (usb2_ether_pause(&sc->sc_ue, hz / 1000)) 521188412Sthompsa break; 522188412Sthompsa if (!(rue_csr_read_1(sc, RUE_CR) & RUE_CR_SOFT_RST)) 523188412Sthompsa break; 524188412Sthompsa } 525188412Sthompsa if (i == RUE_TIMEOUT) 526188412Sthompsa device_printf(sc->sc_ue.ue_dev, "reset never completed!\n"); 527184610Salfred 528188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 100); 529188412Sthompsa} 530184610Salfred 531188412Sthompsastatic void 532188412Sthompsarue_attach_post(struct usb2_ether *ue) 533188412Sthompsa{ 534188412Sthompsa struct rue_softc *sc = usb2_ether_getsc(ue); 535184610Salfred 536188412Sthompsa /* reset the adapter */ 537188412Sthompsa rue_reset(sc); 538184610Salfred 539188412Sthompsa /* get station address from the EEPROM */ 540188412Sthompsa rue_read_mem(sc, RUE_EEPROM_IDR0, ue->ue_eaddr, ETHER_ADDR_LEN); 541184610Salfred} 542184610Salfred 543184610Salfred/* 544184610Salfred * Probe for a RTL8150 chip. 545184610Salfred */ 546184610Salfredstatic int 547184610Salfredrue_probe(device_t dev) 548184610Salfred{ 549184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 550184610Salfred 551188412Sthompsa if (uaa->usb2_mode != USB_MODE_HOST) 552184610Salfred return (ENXIO); 553188412Sthompsa if (uaa->info.bConfigIndex != RUE_CONFIG_IDX) 554184610Salfred return (ENXIO); 555188412Sthompsa if (uaa->info.bIfaceIndex != RUE_IFACE_IDX) 556184610Salfred return (ENXIO); 557188412Sthompsa 558184610Salfred return (usb2_lookup_id_by_uaa(rue_devs, sizeof(rue_devs), uaa)); 559184610Salfred} 560184610Salfred 561184610Salfred/* 562184610Salfred * Attach the interface. Allocate softc structures, do ifmedia 563184610Salfred * setup and ethernet/BPF attach. 564184610Salfred */ 565184610Salfredstatic int 566184610Salfredrue_attach(device_t dev) 567184610Salfred{ 568184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 569184610Salfred struct rue_softc *sc = device_get_softc(dev); 570188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 571184610Salfred uint8_t iface_index; 572188412Sthompsa int error; 573184610Salfred 574184610Salfred device_set_usb2_desc(dev); 575188412Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 576184610Salfred 577184610Salfred iface_index = RUE_IFACE_IDX; 578184610Salfred error = usb2_transfer_setup(uaa->device, &iface_index, 579187259Sthompsa sc->sc_xfer, rue_config, RUE_N_TRANSFER, 580184610Salfred sc, &sc->sc_mtx); 581184610Salfred if (error) { 582188412Sthompsa device_printf(dev, "allocating USB transfers failed!\n"); 583184610Salfred goto detach; 584184610Salfred } 585188412Sthompsa 586188412Sthompsa ue->ue_sc = sc; 587188412Sthompsa ue->ue_dev = dev; 588188412Sthompsa ue->ue_udev = uaa->device; 589188412Sthompsa ue->ue_mtx = &sc->sc_mtx; 590188412Sthompsa ue->ue_methods = &rue_ue_methods; 591188412Sthompsa 592188412Sthompsa error = usb2_ether_ifattach(ue); 593184610Salfred if (error) { 594188412Sthompsa device_printf(dev, "could not attach interface\n"); 595184610Salfred goto detach; 596184610Salfred } 597184610Salfred return (0); /* success */ 598184610Salfred 599184610Salfreddetach: 600184610Salfred rue_detach(dev); 601184610Salfred return (ENXIO); /* failure */ 602184610Salfred} 603184610Salfred 604184610Salfredstatic int 605184610Salfredrue_detach(device_t dev) 606184610Salfred{ 607184610Salfred struct rue_softc *sc = device_get_softc(dev); 608188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 609184610Salfred 610187259Sthompsa usb2_transfer_unsetup(sc->sc_xfer, RUE_N_TRANSFER); 611188412Sthompsa usb2_ether_ifdetach(ue); 612184610Salfred mtx_destroy(&sc->sc_mtx); 613184610Salfred 614184610Salfred return (0); 615184610Salfred} 616184610Salfred 617184610Salfredstatic void 618184610Salfredrue_intr_callback(struct usb2_xfer *xfer) 619184610Salfred{ 620184610Salfred struct rue_softc *sc = xfer->priv_sc; 621188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue); 622184610Salfred struct rue_intrpkt pkt; 623184610Salfred 624184610Salfred switch (USB_GET_STATE(xfer)) { 625184610Salfred case USB_ST_TRANSFERRED: 626184610Salfred 627184610Salfred if (ifp && (ifp->if_drv_flags & IFF_DRV_RUNNING) && 628184610Salfred (xfer->actlen >= sizeof(pkt))) { 629184610Salfred 630184610Salfred usb2_copy_out(xfer->frbuffers, 0, &pkt, sizeof(pkt)); 631184610Salfred 632184610Salfred ifp->if_ierrors += pkt.rue_rxlost_cnt; 633184610Salfred ifp->if_ierrors += pkt.rue_crcerr_cnt; 634184610Salfred ifp->if_collisions += pkt.rue_col_cnt; 635184610Salfred } 636188412Sthompsa /* FALLTHROUGH */ 637184610Salfred case USB_ST_SETUP: 638188412Sthompsatr_setup: 639188412Sthompsa xfer->frlengths[0] = xfer->max_data_length; 640188412Sthompsa usb2_start_hardware(xfer); 641184610Salfred return; 642184610Salfred 643184610Salfred default: /* Error */ 644184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 645188412Sthompsa /* try to clear stall first */ 646188412Sthompsa xfer->flags.stall_pipe = 1; 647188412Sthompsa goto tr_setup; 648184610Salfred } 649184610Salfred return; 650184610Salfred } 651184610Salfred} 652184610Salfred 653184610Salfredstatic void 654184610Salfredrue_bulk_read_callback(struct usb2_xfer *xfer) 655184610Salfred{ 656184610Salfred struct rue_softc *sc = xfer->priv_sc; 657188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 658188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 659184610Salfred uint16_t status; 660184610Salfred 661184610Salfred switch (USB_GET_STATE(xfer)) { 662184610Salfred case USB_ST_TRANSFERRED: 663184610Salfred 664184610Salfred if (xfer->actlen < 4) { 665184610Salfred ifp->if_ierrors++; 666184610Salfred goto tr_setup; 667184610Salfred } 668184610Salfred usb2_copy_out(xfer->frbuffers, xfer->actlen - 4, 669184610Salfred &status, sizeof(status)); 670188412Sthompsa xfer->actlen -= 4; 671184610Salfred 672188412Sthompsa /* check recieve packet was valid or not */ 673184610Salfred status = le16toh(status); 674184610Salfred if ((status & RUE_RXSTAT_VALID) == 0) { 675184610Salfred ifp->if_ierrors++; 676184610Salfred goto tr_setup; 677184610Salfred } 678188412Sthompsa usb2_ether_rxbuf(ue, xfer->frbuffers, 0, xfer->actlen); 679188412Sthompsa /* FALLTHROUGH */ 680184610Salfred case USB_ST_SETUP: 681184610Salfredtr_setup: 682188412Sthompsa xfer->frlengths[0] = xfer->max_data_length; 683188412Sthompsa usb2_start_hardware(xfer); 684188412Sthompsa usb2_ether_rxflush(ue); 685184610Salfred return; 686184610Salfred 687184610Salfred default: /* Error */ 688188412Sthompsa DPRINTF("bulk read error, %s\n", 689188412Sthompsa usb2_errstr(xfer->error)); 690188412Sthompsa 691184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 692184610Salfred /* try to clear stall first */ 693188412Sthompsa xfer->flags.stall_pipe = 1; 694188412Sthompsa goto tr_setup; 695184610Salfred } 696184610Salfred return; 697184610Salfred } 698184610Salfred} 699184610Salfred 700184610Salfredstatic void 701184610Salfredrue_bulk_write_callback(struct usb2_xfer *xfer) 702184610Salfred{ 703184610Salfred struct rue_softc *sc = xfer->priv_sc; 704188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue); 705184610Salfred struct mbuf *m; 706188412Sthompsa int temp_len; 707184610Salfred 708184610Salfred switch (USB_GET_STATE(xfer)) { 709184610Salfred case USB_ST_TRANSFERRED: 710184610Salfred DPRINTFN(11, "transfer complete\n"); 711184610Salfred ifp->if_opackets++; 712184610Salfred 713188412Sthompsa /* FALLTHROUGH */ 714184610Salfred case USB_ST_SETUP: 715188412Sthompsatr_setup: 716188412Sthompsa if ((sc->sc_flags & RUE_FLAG_LINK) == 0) { 717184610Salfred /* 718184610Salfred * don't send anything if there is no link ! 719184610Salfred */ 720188412Sthompsa return; 721184610Salfred } 722184610Salfred IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 723184610Salfred 724188412Sthompsa if (m == NULL) 725188412Sthompsa return; 726188412Sthompsa if (m->m_pkthdr.len > MCLBYTES) 727184610Salfred m->m_pkthdr.len = MCLBYTES; 728184610Salfred temp_len = m->m_pkthdr.len; 729184610Salfred 730184610Salfred usb2_m_copy_in(xfer->frbuffers, 0, 731184610Salfred m, 0, m->m_pkthdr.len); 732184610Salfred 733184610Salfred /* 734184610Salfred * This is an undocumented behavior. 735184610Salfred * RTL8150 chip doesn't send frame length smaller than 736184610Salfred * RUE_MIN_FRAMELEN (60) byte packet. 737184610Salfred */ 738184610Salfred if (temp_len < RUE_MIN_FRAMELEN) { 739184610Salfred usb2_bzero(xfer->frbuffers, temp_len, 740184610Salfred RUE_MIN_FRAMELEN - temp_len); 741184610Salfred temp_len = RUE_MIN_FRAMELEN; 742184610Salfred } 743184610Salfred xfer->frlengths[0] = temp_len; 744184610Salfred 745184610Salfred /* 746184610Salfred * if there's a BPF listener, bounce a copy 747184610Salfred * of this frame to him: 748184610Salfred */ 749184610Salfred BPF_MTAP(ifp, m); 750184610Salfred 751184610Salfred m_freem(m); 752184610Salfred 753184610Salfred usb2_start_hardware(xfer); 754184610Salfred 755184610Salfred return; 756184610Salfred 757184610Salfred default: /* Error */ 758184610Salfred DPRINTFN(11, "transfer error, %s\n", 759184610Salfred usb2_errstr(xfer->error)); 760184610Salfred 761188412Sthompsa ifp->if_oerrors++; 762188412Sthompsa 763184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 764184610Salfred /* try to clear stall first */ 765188412Sthompsa xfer->flags.stall_pipe = 1; 766188412Sthompsa goto tr_setup; 767184610Salfred } 768184610Salfred return; 769184610Salfred } 770184610Salfred} 771184610Salfred 772184610Salfredstatic void 773188412Sthompsarue_tick(struct usb2_ether *ue) 774184610Salfred{ 775188412Sthompsa struct rue_softc *sc = usb2_ether_getsc(ue); 776184610Salfred struct mii_data *mii = GET_MII(sc); 777184610Salfred 778188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 779188412Sthompsa 780184610Salfred mii_tick(mii); 781188412Sthompsa if ((sc->sc_flags & RUE_FLAG_LINK) == 0 782188412Sthompsa && mii->mii_media_status & IFM_ACTIVE && 783188412Sthompsa IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 784188412Sthompsa sc->sc_flags |= RUE_FLAG_LINK; 785188412Sthompsa rue_start(ue); 786184610Salfred } 787184610Salfred} 788184610Salfred 789184610Salfredstatic void 790188412Sthompsarue_start(struct usb2_ether *ue) 791184610Salfred{ 792188412Sthompsa struct rue_softc *sc = usb2_ether_getsc(ue); 793184610Salfred 794188412Sthompsa /* 795188412Sthompsa * start the USB transfers, if not already started: 796188412Sthompsa */ 797188412Sthompsa usb2_transfer_start(sc->sc_xfer[RUE_INTR_DT_RD]); 798188412Sthompsa usb2_transfer_start(sc->sc_xfer[RUE_BULK_DT_RD]); 799188412Sthompsa usb2_transfer_start(sc->sc_xfer[RUE_BULK_DT_WR]); 800184610Salfred} 801184610Salfred 802184610Salfredstatic void 803188412Sthompsarue_init(struct usb2_ether *ue) 804184610Salfred{ 805188412Sthompsa struct rue_softc *sc = usb2_ether_getsc(ue); 806188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 807184610Salfred 808188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 809184610Salfred 810184610Salfred /* 811184610Salfred * Cancel pending I/O 812184610Salfred */ 813188412Sthompsa rue_reset(sc); 814184610Salfred 815188412Sthompsa /* Set MAC address */ 816188412Sthompsa rue_write_mem(sc, RUE_IDR0, IF_LLADDR(ifp), ETHER_ADDR_LEN); 817184610Salfred 818188412Sthompsa rue_stop(ue); 819184610Salfred 820184610Salfred /* 821184610Salfred * Set the initial TX and RX configuration. 822184610Salfred */ 823188412Sthompsa rue_csr_write_1(sc, RUE_TCR, RUE_TCR_CONFIG); 824188412Sthompsa rue_csr_write_2(sc, RUE_RCR, RUE_RCR_CONFIG|RUE_RCR_AB); 825184610Salfred 826184610Salfred /* Load the multicast filter */ 827188412Sthompsa rue_setpromisc(ue); 828188412Sthompsa /* Load the multicast filter. */ 829188412Sthompsa rue_setmulti(ue); 830184610Salfred 831184610Salfred /* Enable RX and TX */ 832188412Sthompsa rue_csr_write_1(sc, RUE_CR, (RUE_CR_TE | RUE_CR_RE | RUE_CR_EP3CLREN)); 833184610Salfred 834188412Sthompsa usb2_transfer_set_stall(sc->sc_xfer[RUE_BULK_DT_WR]); 835184610Salfred 836188412Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 837188412Sthompsa rue_start(ue); 838184610Salfred} 839184610Salfred 840184610Salfred/* 841184610Salfred * Set media options. 842184610Salfred */ 843184610Salfredstatic int 844188412Sthompsarue_ifmedia_upd(struct ifnet *ifp) 845184610Salfred{ 846184610Salfred struct rue_softc *sc = ifp->if_softc; 847184610Salfred struct mii_data *mii = GET_MII(sc); 848184610Salfred 849188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 850184610Salfred 851188412Sthompsa sc->sc_flags &= ~RUE_FLAG_LINK; 852184610Salfred if (mii->mii_instance) { 853184610Salfred struct mii_softc *miisc; 854184610Salfred 855188412Sthompsa LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 856184610Salfred mii_phy_reset(miisc); 857184610Salfred } 858184610Salfred mii_mediachg(mii); 859188412Sthompsa return (0); 860184610Salfred} 861184610Salfred 862184610Salfred/* 863184610Salfred * Report current media status. 864184610Salfred */ 865184610Salfredstatic void 866188412Sthompsarue_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 867184610Salfred{ 868184610Salfred struct rue_softc *sc = ifp->if_softc; 869188412Sthompsa struct mii_data *mii = GET_MII(sc); 870184610Salfred 871188412Sthompsa RUE_LOCK(sc); 872188412Sthompsa mii_pollstat(mii); 873188412Sthompsa RUE_UNLOCK(sc); 874188412Sthompsa ifmr->ifm_active = mii->mii_media_active; 875188412Sthompsa ifmr->ifm_status = mii->mii_media_status; 876184610Salfred} 877184610Salfred 878184610Salfredstatic void 879188412Sthompsarue_stop(struct usb2_ether *ue) 880184610Salfred{ 881188412Sthompsa struct rue_softc *sc = usb2_ether_getsc(ue); 882188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 883184610Salfred 884188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 885184610Salfred 886188412Sthompsa ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 887188412Sthompsa sc->sc_flags &= ~RUE_FLAG_LINK; 888184610Salfred 889184610Salfred /* 890184610Salfred * stop all the transfers, if not already stopped: 891184610Salfred */ 892187259Sthompsa usb2_transfer_stop(sc->sc_xfer[RUE_BULK_DT_WR]); 893187259Sthompsa usb2_transfer_stop(sc->sc_xfer[RUE_BULK_DT_RD]); 894187259Sthompsa usb2_transfer_stop(sc->sc_xfer[RUE_INTR_DT_RD]); 895184610Salfred 896188412Sthompsa rue_csr_write_1(sc, RUE_CR, 0x00); 897184610Salfred 898188412Sthompsa rue_reset(sc); 899184610Salfred} 900184610Salfred 901184610Salfred/* 902184610Salfred * Stop all chip I/O so that the kernel's probe routines don't 903184610Salfred * get confused by errant DMAs when rebooting. 904184610Salfred */ 905184610Salfredstatic int 906184610Salfredrue_shutdown(device_t dev) 907184610Salfred{ 908184610Salfred struct rue_softc *sc = device_get_softc(dev); 909184610Salfred 910188412Sthompsa usb2_ether_ifshutdown(&sc->sc_ue); 911184610Salfred 912184610Salfred return (0); 913184610Salfred} 914