if_rue.c revision 212122
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/usb/net/if_rue.c 212122 2010-09-01 23:47:53Z 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 68194677Sthompsa#include <sys/stdint.h> 69194677Sthompsa#include <sys/stddef.h> 70194677Sthompsa#include <sys/param.h> 71194677Sthompsa#include <sys/queue.h> 72194677Sthompsa#include <sys/types.h> 73194677Sthompsa#include <sys/systm.h> 74194677Sthompsa#include <sys/kernel.h> 75194677Sthompsa#include <sys/bus.h> 76194677Sthompsa#include <sys/linker_set.h> 77194677Sthompsa#include <sys/module.h> 78194677Sthompsa#include <sys/lock.h> 79194677Sthompsa#include <sys/mutex.h> 80194677Sthompsa#include <sys/condvar.h> 81194677Sthompsa#include <sys/sysctl.h> 82194677Sthompsa#include <sys/sx.h> 83194677Sthompsa#include <sys/unistd.h> 84194677Sthompsa#include <sys/callout.h> 85194677Sthompsa#include <sys/malloc.h> 86194677Sthompsa#include <sys/priv.h> 87194677Sthompsa 88194677Sthompsa#include <dev/usb/usb.h> 89194677Sthompsa#include <dev/usb/usbdi.h> 90194677Sthompsa#include <dev/usb/usbdi_util.h> 91188746Sthompsa#include "usbdevs.h" 92184610Salfred 93184610Salfred#define USB_DEBUG_VAR rue_debug 94194677Sthompsa#include <dev/usb/usb_debug.h> 95188942Sthompsa#include <dev/usb/usb_process.h> 96184610Salfred 97188942Sthompsa#include <dev/usb/net/usb_ethernet.h> 98188942Sthompsa#include <dev/usb/net/if_ruereg.h> 99184610Salfred 100207077Sthompsa#ifdef USB_DEBUG 101184610Salfredstatic int rue_debug = 0; 102184610Salfred 103192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, rue, CTLFLAG_RW, 0, "USB rue"); 104192502SthompsaSYSCTL_INT(_hw_usb_rue, OID_AUTO, debug, CTLFLAG_RW, 105184610Salfred &rue_debug, 0, "Debug level"); 106184610Salfred#endif 107184610Salfred 108184610Salfred/* 109184610Salfred * Various supported device vendors/products. 110184610Salfred */ 111184610Salfred 112192984Sthompsastatic const struct usb_device_id rue_devs[] = { 113184610Salfred {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX, 0)}, 114184610Salfred {USB_VPI(USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_USBKR100, 0)}, 115209444Sthompsa {USB_VPI(USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01, 0)}, 116184610Salfred}; 117184610Salfred 118184610Salfred/* prototypes */ 119184610Salfred 120184610Salfredstatic device_probe_t rue_probe; 121184610Salfredstatic device_attach_t rue_attach; 122184610Salfredstatic device_detach_t rue_detach; 123184610Salfred 124188412Sthompsastatic miibus_readreg_t rue_miibus_readreg; 125188412Sthompsastatic miibus_writereg_t rue_miibus_writereg; 126188412Sthompsastatic miibus_statchg_t rue_miibus_statchg; 127188412Sthompsa 128193045Sthompsastatic usb_callback_t rue_intr_callback; 129193045Sthompsastatic usb_callback_t rue_bulk_read_callback; 130193045Sthompsastatic usb_callback_t rue_bulk_write_callback; 131184610Salfred 132193045Sthompsastatic uether_fn_t rue_attach_post; 133193045Sthompsastatic uether_fn_t rue_init; 134193045Sthompsastatic uether_fn_t rue_stop; 135193045Sthompsastatic uether_fn_t rue_start; 136193045Sthompsastatic uether_fn_t rue_tick; 137193045Sthompsastatic uether_fn_t rue_setmulti; 138193045Sthompsastatic uether_fn_t rue_setpromisc; 139184610Salfred 140188412Sthompsastatic int rue_read_mem(struct rue_softc *, uint16_t, void *, int); 141188412Sthompsastatic int rue_write_mem(struct rue_softc *, uint16_t, void *, int); 142188412Sthompsastatic uint8_t rue_csr_read_1(struct rue_softc *, uint16_t); 143188412Sthompsastatic uint16_t rue_csr_read_2(struct rue_softc *, uint16_t); 144188412Sthompsastatic int rue_csr_write_1(struct rue_softc *, uint16_t, uint8_t); 145188412Sthompsastatic int rue_csr_write_2(struct rue_softc *, uint16_t, uint16_t); 146188412Sthompsastatic int rue_csr_write_4(struct rue_softc *, int, uint32_t); 147184610Salfred 148188412Sthompsastatic void rue_reset(struct rue_softc *); 149188412Sthompsastatic int rue_ifmedia_upd(struct ifnet *); 150188412Sthompsastatic void rue_ifmedia_sts(struct ifnet *, struct ifmediareq *); 151184610Salfred 152192984Sthompsastatic const struct usb_config rue_config[RUE_N_TRANSFER] = { 153184610Salfred 154187259Sthompsa [RUE_BULK_DT_WR] = { 155184610Salfred .type = UE_BULK, 156184610Salfred .endpoint = UE_ADDR_ANY, 157184610Salfred .direction = UE_DIR_OUT, 158190734Sthompsa .bufsize = MCLBYTES, 159190734Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 160190734Sthompsa .callback = rue_bulk_write_callback, 161190734Sthompsa .timeout = 10000, /* 10 seconds */ 162184610Salfred }, 163184610Salfred 164187259Sthompsa [RUE_BULK_DT_RD] = { 165184610Salfred .type = UE_BULK, 166184610Salfred .endpoint = UE_ADDR_ANY, 167184610Salfred .direction = UE_DIR_IN, 168190734Sthompsa .bufsize = (MCLBYTES + 4), 169190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 170190734Sthompsa .callback = rue_bulk_read_callback, 171190734Sthompsa .timeout = 0, /* no timeout */ 172184610Salfred }, 173184610Salfred 174187259Sthompsa [RUE_INTR_DT_RD] = { 175184610Salfred .type = UE_INTERRUPT, 176184610Salfred .endpoint = UE_ADDR_ANY, 177184610Salfred .direction = UE_DIR_IN, 178190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 179190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 180190734Sthompsa .callback = rue_intr_callback, 181184610Salfred }, 182184610Salfred}; 183184610Salfred 184184610Salfredstatic device_method_t rue_methods[] = { 185184610Salfred /* Device interface */ 186184610Salfred DEVMETHOD(device_probe, rue_probe), 187184610Salfred DEVMETHOD(device_attach, rue_attach), 188184610Salfred DEVMETHOD(device_detach, rue_detach), 189184610Salfred 190184610Salfred /* Bus interface */ 191184610Salfred DEVMETHOD(bus_print_child, bus_generic_print_child), 192184610Salfred DEVMETHOD(bus_driver_added, bus_generic_driver_added), 193184610Salfred 194184610Salfred /* MII interface */ 195188412Sthompsa DEVMETHOD(miibus_readreg, rue_miibus_readreg), 196188412Sthompsa DEVMETHOD(miibus_writereg, rue_miibus_writereg), 197188412Sthompsa DEVMETHOD(miibus_statchg, rue_miibus_statchg), 198184610Salfred 199184610Salfred {0, 0} 200184610Salfred}; 201184610Salfred 202184610Salfredstatic driver_t rue_driver = { 203184610Salfred .name = "rue", 204184610Salfred .methods = rue_methods, 205184610Salfred .size = sizeof(struct rue_softc), 206184610Salfred}; 207184610Salfred 208184610Salfredstatic devclass_t rue_devclass; 209184610Salfred 210189275SthompsaDRIVER_MODULE(rue, uhub, rue_driver, rue_devclass, NULL, 0); 211184610SalfredDRIVER_MODULE(miibus, rue, miibus_driver, miibus_devclass, 0, 0); 212188942SthompsaMODULE_DEPEND(rue, uether, 1, 1, 1); 213188942SthompsaMODULE_DEPEND(rue, usb, 1, 1, 1); 214184610SalfredMODULE_DEPEND(rue, ether, 1, 1, 1); 215184610SalfredMODULE_DEPEND(rue, miibus, 1, 1, 1); 216212122SthompsaMODULE_VERSION(rue, 1); 217184610Salfred 218192984Sthompsastatic const struct usb_ether_methods rue_ue_methods = { 219188412Sthompsa .ue_attach_post = rue_attach_post, 220188412Sthompsa .ue_start = rue_start, 221188412Sthompsa .ue_init = rue_init, 222188412Sthompsa .ue_stop = rue_stop, 223188412Sthompsa .ue_tick = rue_tick, 224188412Sthompsa .ue_setmulti = rue_setmulti, 225188412Sthompsa .ue_setpromisc = rue_setpromisc, 226188412Sthompsa .ue_mii_upd = rue_ifmedia_upd, 227188412Sthompsa .ue_mii_sts = rue_ifmedia_sts, 228188412Sthompsa}; 229184610Salfred 230188412Sthompsa#define RUE_SETBIT(sc, reg, x) \ 231188412Sthompsa rue_csr_write_1(sc, reg, rue_csr_read_1(sc, reg) | (x)) 232184610Salfred 233188412Sthompsa#define RUE_CLRBIT(sc, reg, x) \ 234188412Sthompsa rue_csr_write_1(sc, reg, rue_csr_read_1(sc, reg) & ~(x)) 235184610Salfred 236188412Sthompsastatic int 237188412Sthompsarue_read_mem(struct rue_softc *sc, uint16_t addr, void *buf, int len) 238184610Salfred{ 239192984Sthompsa struct usb_device_request req; 240184610Salfred 241184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 242184610Salfred req.bRequest = UR_SET_ADDRESS; 243184610Salfred USETW(req.wValue, addr); 244184610Salfred USETW(req.wIndex, 0); 245184610Salfred USETW(req.wLength, len); 246184610Salfred 247194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 248184610Salfred} 249184610Salfred 250188412Sthompsastatic int 251188412Sthompsarue_write_mem(struct rue_softc *sc, uint16_t addr, void *buf, int len) 252184610Salfred{ 253192984Sthompsa struct usb_device_request req; 254184610Salfred 255184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 256184610Salfred req.bRequest = UR_SET_ADDRESS; 257184610Salfred USETW(req.wValue, addr); 258184610Salfred USETW(req.wIndex, 0); 259184610Salfred USETW(req.wLength, len); 260184610Salfred 261194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 262184610Salfred} 263184610Salfred 264184610Salfredstatic uint8_t 265188412Sthompsarue_csr_read_1(struct rue_softc *sc, uint16_t reg) 266184610Salfred{ 267184610Salfred uint8_t val; 268184610Salfred 269188412Sthompsa rue_read_mem(sc, reg, &val, 1); 270184610Salfred return (val); 271184610Salfred} 272184610Salfred 273184610Salfredstatic uint16_t 274188412Sthompsarue_csr_read_2(struct rue_softc *sc, uint16_t reg) 275184610Salfred{ 276184610Salfred uint8_t val[2]; 277184610Salfred 278188412Sthompsa rue_read_mem(sc, reg, &val, 2); 279184610Salfred return (UGETW(val)); 280184610Salfred} 281184610Salfred 282188412Sthompsastatic int 283188412Sthompsarue_csr_write_1(struct rue_softc *sc, uint16_t reg, uint8_t val) 284184610Salfred{ 285188412Sthompsa return (rue_write_mem(sc, reg, &val, 1)); 286184610Salfred} 287184610Salfred 288188412Sthompsastatic int 289188412Sthompsarue_csr_write_2(struct rue_softc *sc, uint16_t reg, uint16_t val) 290184610Salfred{ 291184610Salfred uint8_t temp[2]; 292184610Salfred 293184610Salfred USETW(temp, val); 294188412Sthompsa return (rue_write_mem(sc, reg, &temp, 2)); 295184610Salfred} 296184610Salfred 297188412Sthompsastatic int 298188412Sthompsarue_csr_write_4(struct rue_softc *sc, int reg, uint32_t val) 299184610Salfred{ 300184610Salfred uint8_t temp[4]; 301184610Salfred 302184610Salfred USETDW(temp, val); 303188412Sthompsa return (rue_write_mem(sc, reg, &temp, 4)); 304184610Salfred} 305184610Salfred 306184610Salfredstatic int 307188412Sthompsarue_miibus_readreg(device_t dev, int phy, int reg) 308184610Salfred{ 309184610Salfred struct rue_softc *sc = device_get_softc(dev); 310184610Salfred uint16_t rval; 311184610Salfred uint16_t ruereg; 312188412Sthompsa int locked; 313184610Salfred 314188412Sthompsa if (phy != 0) /* RTL8150 supports PHY == 0, only */ 315184610Salfred return (0); 316184610Salfred 317188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 318188412Sthompsa if (!locked) 319188412Sthompsa RUE_LOCK(sc); 320188412Sthompsa 321184610Salfred switch (reg) { 322184610Salfred case MII_BMCR: 323184610Salfred ruereg = RUE_BMCR; 324184610Salfred break; 325184610Salfred case MII_BMSR: 326184610Salfred ruereg = RUE_BMSR; 327184610Salfred break; 328184610Salfred case MII_ANAR: 329184610Salfred ruereg = RUE_ANAR; 330184610Salfred break; 331184610Salfred case MII_ANER: 332184610Salfred ruereg = RUE_AER; 333184610Salfred break; 334184610Salfred case MII_ANLPAR: 335184610Salfred ruereg = RUE_ANLP; 336184610Salfred break; 337184610Salfred case MII_PHYIDR1: 338184610Salfred case MII_PHYIDR2: 339184610Salfred rval = 0; 340184610Salfred goto done; 341184610Salfred default: 342188412Sthompsa if (RUE_REG_MIN <= reg && reg <= RUE_REG_MAX) { 343188412Sthompsa rval = rue_csr_read_1(sc, reg); 344184610Salfred goto done; 345184610Salfred } 346188412Sthompsa device_printf(sc->sc_ue.ue_dev, "bad phy register\n"); 347184610Salfred rval = 0; 348184610Salfred goto done; 349184610Salfred } 350184610Salfred 351188412Sthompsa rval = rue_csr_read_2(sc, ruereg); 352184610Salfreddone: 353188412Sthompsa if (!locked) 354188412Sthompsa RUE_UNLOCK(sc); 355184610Salfred return (rval); 356184610Salfred} 357184610Salfred 358184610Salfredstatic int 359188412Sthompsarue_miibus_writereg(device_t dev, int phy, int reg, int data) 360184610Salfred{ 361184610Salfred struct rue_softc *sc = device_get_softc(dev); 362184610Salfred uint16_t ruereg; 363188412Sthompsa int locked; 364184610Salfred 365188412Sthompsa if (phy != 0) /* RTL8150 supports PHY == 0, only */ 366184610Salfred return (0); 367184610Salfred 368188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 369188412Sthompsa if (!locked) 370188412Sthompsa RUE_LOCK(sc); 371188412Sthompsa 372184610Salfred switch (reg) { 373184610Salfred case MII_BMCR: 374184610Salfred ruereg = RUE_BMCR; 375184610Salfred break; 376184610Salfred case MII_BMSR: 377184610Salfred ruereg = RUE_BMSR; 378184610Salfred break; 379184610Salfred case MII_ANAR: 380184610Salfred ruereg = RUE_ANAR; 381184610Salfred break; 382184610Salfred case MII_ANER: 383184610Salfred ruereg = RUE_AER; 384184610Salfred break; 385184610Salfred case MII_ANLPAR: 386184610Salfred ruereg = RUE_ANLP; 387184610Salfred break; 388184610Salfred case MII_PHYIDR1: 389184610Salfred case MII_PHYIDR2: 390184610Salfred goto done; 391184610Salfred default: 392188412Sthompsa if (RUE_REG_MIN <= reg && reg <= RUE_REG_MAX) { 393188412Sthompsa rue_csr_write_1(sc, reg, data); 394184610Salfred goto done; 395184610Salfred } 396188412Sthompsa device_printf(sc->sc_ue.ue_dev, " bad phy register\n"); 397184610Salfred goto done; 398184610Salfred } 399188412Sthompsa rue_csr_write_2(sc, ruereg, data); 400184610Salfreddone: 401188412Sthompsa if (!locked) 402188412Sthompsa RUE_UNLOCK(sc); 403184610Salfred return (0); 404184610Salfred} 405184610Salfred 406184610Salfredstatic void 407188412Sthompsarue_miibus_statchg(device_t dev) 408184610Salfred{ 409184610Salfred /* 410184610Salfred * When the code below is enabled the card starts doing weird 411184610Salfred * things after link going from UP to DOWN and back UP. 412184610Salfred * 413184610Salfred * Looks like some of register writes below messes up PHY 414184610Salfred * interface. 415184610Salfred * 416184610Salfred * No visible regressions were found after commenting this code 417184610Salfred * out, so that disable it for good. 418184610Salfred */ 419184610Salfred#if 0 420184610Salfred struct rue_softc *sc = device_get_softc(dev); 421184610Salfred struct mii_data *mii = GET_MII(sc); 422184610Salfred uint16_t bmcr; 423188412Sthompsa int locked; 424184610Salfred 425188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 426188412Sthompsa if (!locked) 427188412Sthompsa RUE_LOCK(sc); 428184610Salfred 429188412Sthompsa RUE_CLRBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE)); 430184610Salfred 431188412Sthompsa bmcr = rue_csr_read_2(sc, RUE_BMCR); 432184610Salfred 433184610Salfred if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) 434184610Salfred bmcr |= RUE_BMCR_SPD_SET; 435184610Salfred else 436184610Salfred bmcr &= ~RUE_BMCR_SPD_SET; 437184610Salfred 438184610Salfred if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) 439184610Salfred bmcr |= RUE_BMCR_DUPLEX; 440184610Salfred else 441184610Salfred bmcr &= ~RUE_BMCR_DUPLEX; 442184610Salfred 443188412Sthompsa rue_csr_write_2(sc, RUE_BMCR, bmcr); 444184610Salfred 445188412Sthompsa RUE_SETBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE)); 446184610Salfred 447188412Sthompsa if (!locked) 448188412Sthompsa RUE_UNLOCK(sc); 449184610Salfred#endif 450184610Salfred} 451184610Salfred 452184610Salfredstatic void 453192984Sthompsarue_setpromisc(struct usb_ether *ue) 454184610Salfred{ 455194228Sthompsa struct rue_softc *sc = uether_getsc(ue); 456194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 457184610Salfred 458188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 459184610Salfred 460188412Sthompsa /* If we want promiscuous mode, set the allframes bit. */ 461188412Sthompsa if (ifp->if_flags & IFF_PROMISC) 462188412Sthompsa RUE_SETBIT(sc, RUE_RCR, RUE_RCR_AAP); 463188412Sthompsa else 464188412Sthompsa RUE_CLRBIT(sc, RUE_RCR, RUE_RCR_AAP); 465184610Salfred} 466184610Salfred 467184610Salfred/* 468184610Salfred * Program the 64-bit multicast hash filter. 469184610Salfred */ 470184610Salfredstatic void 471192984Sthompsarue_setmulti(struct usb_ether *ue) 472184610Salfred{ 473194228Sthompsa struct rue_softc *sc = uether_getsc(ue); 474194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 475184610Salfred uint16_t rxcfg; 476188412Sthompsa int h = 0; 477188412Sthompsa uint32_t hashes[2] = { 0, 0 }; 478188412Sthompsa struct ifmultiaddr *ifma; 479188412Sthompsa int mcnt = 0; 480184610Salfred 481188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 482184610Salfred 483188412Sthompsa rxcfg = rue_csr_read_2(sc, RUE_RCR); 484188412Sthompsa 485188412Sthompsa if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 486184610Salfred rxcfg |= (RUE_RCR_AAM | RUE_RCR_AAP); 487184610Salfred rxcfg &= ~RUE_RCR_AM; 488188412Sthompsa rue_csr_write_2(sc, RUE_RCR, rxcfg); 489188412Sthompsa rue_csr_write_4(sc, RUE_MAR0, 0xFFFFFFFF); 490188412Sthompsa rue_csr_write_4(sc, RUE_MAR4, 0xFFFFFFFF); 491184610Salfred return; 492184610Salfred } 493184610Salfred 494188412Sthompsa /* first, zot all the existing hash bits */ 495188412Sthompsa rue_csr_write_4(sc, RUE_MAR0, 0); 496188412Sthompsa rue_csr_write_4(sc, RUE_MAR4, 0); 497188412Sthompsa 498188412Sthompsa /* now program new ones */ 499195049Srwatson if_maddr_rlock(ifp); 500188412Sthompsa TAILQ_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link) 501188412Sthompsa { 502188412Sthompsa if (ifma->ifma_addr->sa_family != AF_LINK) 503188412Sthompsa continue; 504188412Sthompsa h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 505188412Sthompsa ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 506188412Sthompsa if (h < 32) 507188412Sthompsa hashes[0] |= (1 << h); 508188412Sthompsa else 509188412Sthompsa hashes[1] |= (1 << (h - 32)); 510188412Sthompsa mcnt++; 511188412Sthompsa } 512195049Srwatson if_maddr_runlock(ifp); 513188412Sthompsa 514188412Sthompsa if (mcnt) 515184610Salfred rxcfg |= RUE_RCR_AM; 516184610Salfred else 517184610Salfred rxcfg &= ~RUE_RCR_AM; 518184610Salfred 519184610Salfred rxcfg &= ~(RUE_RCR_AAM | RUE_RCR_AAP); 520184610Salfred 521188412Sthompsa rue_csr_write_2(sc, RUE_RCR, rxcfg); 522188412Sthompsa rue_csr_write_4(sc, RUE_MAR0, hashes[0]); 523188412Sthompsa rue_csr_write_4(sc, RUE_MAR4, hashes[1]); 524184610Salfred} 525184610Salfred 526184610Salfredstatic void 527188412Sthompsarue_reset(struct rue_softc *sc) 528184610Salfred{ 529188412Sthompsa int i; 530184610Salfred 531188412Sthompsa rue_csr_write_1(sc, RUE_CR, RUE_CR_SOFT_RST); 532184610Salfred 533188412Sthompsa for (i = 0; i != RUE_TIMEOUT; i++) { 534194228Sthompsa if (uether_pause(&sc->sc_ue, hz / 1000)) 535188412Sthompsa break; 536188412Sthompsa if (!(rue_csr_read_1(sc, RUE_CR) & RUE_CR_SOFT_RST)) 537188412Sthompsa break; 538188412Sthompsa } 539188412Sthompsa if (i == RUE_TIMEOUT) 540199816Sthompsa device_printf(sc->sc_ue.ue_dev, "reset never completed\n"); 541184610Salfred 542194228Sthompsa uether_pause(&sc->sc_ue, hz / 100); 543188412Sthompsa} 544184610Salfred 545188412Sthompsastatic void 546192984Sthompsarue_attach_post(struct usb_ether *ue) 547188412Sthompsa{ 548194228Sthompsa struct rue_softc *sc = uether_getsc(ue); 549184610Salfred 550188412Sthompsa /* reset the adapter */ 551188412Sthompsa rue_reset(sc); 552184610Salfred 553188412Sthompsa /* get station address from the EEPROM */ 554188412Sthompsa rue_read_mem(sc, RUE_EEPROM_IDR0, ue->ue_eaddr, ETHER_ADDR_LEN); 555184610Salfred} 556184610Salfred 557184610Salfred/* 558184610Salfred * Probe for a RTL8150 chip. 559184610Salfred */ 560184610Salfredstatic int 561184610Salfredrue_probe(device_t dev) 562184610Salfred{ 563192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 564184610Salfred 565192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 566184610Salfred return (ENXIO); 567188412Sthompsa if (uaa->info.bConfigIndex != RUE_CONFIG_IDX) 568184610Salfred return (ENXIO); 569188412Sthompsa if (uaa->info.bIfaceIndex != RUE_IFACE_IDX) 570184610Salfred return (ENXIO); 571188412Sthompsa 572194228Sthompsa return (usbd_lookup_id_by_uaa(rue_devs, sizeof(rue_devs), uaa)); 573184610Salfred} 574184610Salfred 575184610Salfred/* 576184610Salfred * Attach the interface. Allocate softc structures, do ifmedia 577184610Salfred * setup and ethernet/BPF attach. 578184610Salfred */ 579184610Salfredstatic int 580184610Salfredrue_attach(device_t dev) 581184610Salfred{ 582192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 583184610Salfred struct rue_softc *sc = device_get_softc(dev); 584192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 585184610Salfred uint8_t iface_index; 586188412Sthompsa int error; 587184610Salfred 588194228Sthompsa device_set_usb_desc(dev); 589188412Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 590184610Salfred 591184610Salfred iface_index = RUE_IFACE_IDX; 592194228Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, 593187259Sthompsa sc->sc_xfer, rue_config, RUE_N_TRANSFER, 594184610Salfred sc, &sc->sc_mtx); 595184610Salfred if (error) { 596199816Sthompsa device_printf(dev, "allocating USB transfers failed\n"); 597184610Salfred goto detach; 598184610Salfred } 599188412Sthompsa 600188412Sthompsa ue->ue_sc = sc; 601188412Sthompsa ue->ue_dev = dev; 602188412Sthompsa ue->ue_udev = uaa->device; 603188412Sthompsa ue->ue_mtx = &sc->sc_mtx; 604188412Sthompsa ue->ue_methods = &rue_ue_methods; 605188412Sthompsa 606194228Sthompsa error = uether_ifattach(ue); 607184610Salfred if (error) { 608188412Sthompsa device_printf(dev, "could not attach interface\n"); 609184610Salfred goto detach; 610184610Salfred } 611184610Salfred return (0); /* success */ 612184610Salfred 613184610Salfreddetach: 614184610Salfred rue_detach(dev); 615184610Salfred return (ENXIO); /* failure */ 616184610Salfred} 617184610Salfred 618184610Salfredstatic int 619184610Salfredrue_detach(device_t dev) 620184610Salfred{ 621184610Salfred struct rue_softc *sc = device_get_softc(dev); 622192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 623184610Salfred 624194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, RUE_N_TRANSFER); 625194228Sthompsa uether_ifdetach(ue); 626184610Salfred mtx_destroy(&sc->sc_mtx); 627184610Salfred 628184610Salfred return (0); 629184610Salfred} 630184610Salfred 631184610Salfredstatic void 632194677Sthompsarue_intr_callback(struct usb_xfer *xfer, usb_error_t error) 633184610Salfred{ 634194677Sthompsa struct rue_softc *sc = usbd_xfer_softc(xfer); 635194228Sthompsa struct ifnet *ifp = uether_getifp(&sc->sc_ue); 636184610Salfred struct rue_intrpkt pkt; 637194677Sthompsa struct usb_page_cache *pc; 638194677Sthompsa int actlen; 639184610Salfred 640194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 641194677Sthompsa 642184610Salfred switch (USB_GET_STATE(xfer)) { 643184610Salfred case USB_ST_TRANSFERRED: 644184610Salfred 645184610Salfred if (ifp && (ifp->if_drv_flags & IFF_DRV_RUNNING) && 646194677Sthompsa actlen >= sizeof(pkt)) { 647184610Salfred 648194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 649194677Sthompsa usbd_copy_out(pc, 0, &pkt, sizeof(pkt)); 650184610Salfred 651184610Salfred ifp->if_ierrors += pkt.rue_rxlost_cnt; 652184610Salfred ifp->if_ierrors += pkt.rue_crcerr_cnt; 653184610Salfred ifp->if_collisions += pkt.rue_col_cnt; 654184610Salfred } 655188412Sthompsa /* FALLTHROUGH */ 656184610Salfred case USB_ST_SETUP: 657188412Sthompsatr_setup: 658194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 659194228Sthompsa usbd_transfer_submit(xfer); 660184610Salfred return; 661184610Salfred 662184610Salfred default: /* Error */ 663194677Sthompsa if (error != USB_ERR_CANCELLED) { 664188412Sthompsa /* try to clear stall first */ 665194677Sthompsa usbd_xfer_set_stall(xfer); 666188412Sthompsa goto tr_setup; 667184610Salfred } 668184610Salfred return; 669184610Salfred } 670184610Salfred} 671184610Salfred 672184610Salfredstatic void 673194677Sthompsarue_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 674184610Salfred{ 675194677Sthompsa struct rue_softc *sc = usbd_xfer_softc(xfer); 676192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 677194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 678194677Sthompsa struct usb_page_cache *pc; 679184610Salfred uint16_t status; 680194677Sthompsa int actlen; 681184610Salfred 682194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 683194677Sthompsa 684184610Salfred switch (USB_GET_STATE(xfer)) { 685184610Salfred case USB_ST_TRANSFERRED: 686184610Salfred 687194677Sthompsa if (actlen < 4) { 688184610Salfred ifp->if_ierrors++; 689184610Salfred goto tr_setup; 690184610Salfred } 691194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 692194677Sthompsa usbd_copy_out(pc, actlen - 4, &status, sizeof(status)); 693194677Sthompsa actlen -= 4; 694184610Salfred 695188412Sthompsa /* check recieve packet was valid or not */ 696184610Salfred status = le16toh(status); 697184610Salfred if ((status & RUE_RXSTAT_VALID) == 0) { 698184610Salfred ifp->if_ierrors++; 699184610Salfred goto tr_setup; 700184610Salfred } 701194677Sthompsa uether_rxbuf(ue, pc, 0, actlen); 702188412Sthompsa /* FALLTHROUGH */ 703184610Salfred case USB_ST_SETUP: 704184610Salfredtr_setup: 705194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 706194228Sthompsa usbd_transfer_submit(xfer); 707194228Sthompsa uether_rxflush(ue); 708184610Salfred return; 709184610Salfred 710184610Salfred default: /* Error */ 711188412Sthompsa DPRINTF("bulk read error, %s\n", 712194677Sthompsa usbd_errstr(error)); 713188412Sthompsa 714194677Sthompsa if (error != USB_ERR_CANCELLED) { 715184610Salfred /* try to clear stall first */ 716194677Sthompsa usbd_xfer_set_stall(xfer); 717188412Sthompsa goto tr_setup; 718184610Salfred } 719184610Salfred return; 720184610Salfred } 721184610Salfred} 722184610Salfred 723184610Salfredstatic void 724194677Sthompsarue_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 725184610Salfred{ 726194677Sthompsa struct rue_softc *sc = usbd_xfer_softc(xfer); 727194228Sthompsa struct ifnet *ifp = uether_getifp(&sc->sc_ue); 728194677Sthompsa struct usb_page_cache *pc; 729184610Salfred struct mbuf *m; 730188412Sthompsa int temp_len; 731184610Salfred 732184610Salfred switch (USB_GET_STATE(xfer)) { 733184610Salfred case USB_ST_TRANSFERRED: 734184610Salfred DPRINTFN(11, "transfer complete\n"); 735184610Salfred ifp->if_opackets++; 736184610Salfred 737188412Sthompsa /* FALLTHROUGH */ 738184610Salfred case USB_ST_SETUP: 739188412Sthompsatr_setup: 740188412Sthompsa if ((sc->sc_flags & RUE_FLAG_LINK) == 0) { 741184610Salfred /* 742184610Salfred * don't send anything if there is no link ! 743184610Salfred */ 744188412Sthompsa return; 745184610Salfred } 746184610Salfred IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 747184610Salfred 748188412Sthompsa if (m == NULL) 749188412Sthompsa return; 750188412Sthompsa if (m->m_pkthdr.len > MCLBYTES) 751184610Salfred m->m_pkthdr.len = MCLBYTES; 752184610Salfred temp_len = m->m_pkthdr.len; 753184610Salfred 754194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 755194677Sthompsa usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); 756184610Salfred 757184610Salfred /* 758184610Salfred * This is an undocumented behavior. 759184610Salfred * RTL8150 chip doesn't send frame length smaller than 760184610Salfred * RUE_MIN_FRAMELEN (60) byte packet. 761184610Salfred */ 762184610Salfred if (temp_len < RUE_MIN_FRAMELEN) { 763194677Sthompsa usbd_frame_zero(pc, temp_len, 764184610Salfred RUE_MIN_FRAMELEN - temp_len); 765184610Salfred temp_len = RUE_MIN_FRAMELEN; 766184610Salfred } 767194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, temp_len); 768184610Salfred 769184610Salfred /* 770184610Salfred * if there's a BPF listener, bounce a copy 771184610Salfred * of this frame to him: 772184610Salfred */ 773184610Salfred BPF_MTAP(ifp, m); 774184610Salfred 775184610Salfred m_freem(m); 776184610Salfred 777194228Sthompsa usbd_transfer_submit(xfer); 778184610Salfred 779184610Salfred return; 780184610Salfred 781184610Salfred default: /* Error */ 782184610Salfred DPRINTFN(11, "transfer error, %s\n", 783194677Sthompsa usbd_errstr(error)); 784184610Salfred 785188412Sthompsa ifp->if_oerrors++; 786188412Sthompsa 787194677Sthompsa if (error != USB_ERR_CANCELLED) { 788184610Salfred /* try to clear stall first */ 789194677Sthompsa usbd_xfer_set_stall(xfer); 790188412Sthompsa goto tr_setup; 791184610Salfred } 792184610Salfred return; 793184610Salfred } 794184610Salfred} 795184610Salfred 796184610Salfredstatic void 797192984Sthompsarue_tick(struct usb_ether *ue) 798184610Salfred{ 799194228Sthompsa struct rue_softc *sc = uether_getsc(ue); 800184610Salfred struct mii_data *mii = GET_MII(sc); 801184610Salfred 802188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 803188412Sthompsa 804184610Salfred mii_tick(mii); 805188412Sthompsa if ((sc->sc_flags & RUE_FLAG_LINK) == 0 806188412Sthompsa && mii->mii_media_status & IFM_ACTIVE && 807188412Sthompsa IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 808188412Sthompsa sc->sc_flags |= RUE_FLAG_LINK; 809188412Sthompsa rue_start(ue); 810184610Salfred } 811184610Salfred} 812184610Salfred 813184610Salfredstatic void 814192984Sthompsarue_start(struct usb_ether *ue) 815184610Salfred{ 816194228Sthompsa struct rue_softc *sc = uether_getsc(ue); 817184610Salfred 818188412Sthompsa /* 819188412Sthompsa * start the USB transfers, if not already started: 820188412Sthompsa */ 821194228Sthompsa usbd_transfer_start(sc->sc_xfer[RUE_INTR_DT_RD]); 822194228Sthompsa usbd_transfer_start(sc->sc_xfer[RUE_BULK_DT_RD]); 823194228Sthompsa usbd_transfer_start(sc->sc_xfer[RUE_BULK_DT_WR]); 824184610Salfred} 825184610Salfred 826184610Salfredstatic void 827192984Sthompsarue_init(struct usb_ether *ue) 828184610Salfred{ 829194228Sthompsa struct rue_softc *sc = uether_getsc(ue); 830194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 831184610Salfred 832188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 833184610Salfred 834184610Salfred /* 835184610Salfred * Cancel pending I/O 836184610Salfred */ 837188412Sthompsa rue_reset(sc); 838184610Salfred 839188412Sthompsa /* Set MAC address */ 840188412Sthompsa rue_write_mem(sc, RUE_IDR0, IF_LLADDR(ifp), ETHER_ADDR_LEN); 841184610Salfred 842188412Sthompsa rue_stop(ue); 843184610Salfred 844184610Salfred /* 845184610Salfred * Set the initial TX and RX configuration. 846184610Salfred */ 847188412Sthompsa rue_csr_write_1(sc, RUE_TCR, RUE_TCR_CONFIG); 848188412Sthompsa rue_csr_write_2(sc, RUE_RCR, RUE_RCR_CONFIG|RUE_RCR_AB); 849184610Salfred 850184610Salfred /* Load the multicast filter */ 851188412Sthompsa rue_setpromisc(ue); 852188412Sthompsa /* Load the multicast filter. */ 853188412Sthompsa rue_setmulti(ue); 854184610Salfred 855184610Salfred /* Enable RX and TX */ 856188412Sthompsa rue_csr_write_1(sc, RUE_CR, (RUE_CR_TE | RUE_CR_RE | RUE_CR_EP3CLREN)); 857184610Salfred 858194677Sthompsa usbd_xfer_set_stall(sc->sc_xfer[RUE_BULK_DT_WR]); 859184610Salfred 860188412Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 861188412Sthompsa rue_start(ue); 862184610Salfred} 863184610Salfred 864184610Salfred/* 865184610Salfred * Set media options. 866184610Salfred */ 867184610Salfredstatic int 868188412Sthompsarue_ifmedia_upd(struct ifnet *ifp) 869184610Salfred{ 870184610Salfred struct rue_softc *sc = ifp->if_softc; 871184610Salfred struct mii_data *mii = GET_MII(sc); 872184610Salfred 873188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 874184610Salfred 875188412Sthompsa sc->sc_flags &= ~RUE_FLAG_LINK; 876184610Salfred if (mii->mii_instance) { 877184610Salfred struct mii_softc *miisc; 878184610Salfred 879188412Sthompsa LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 880184610Salfred mii_phy_reset(miisc); 881184610Salfred } 882184610Salfred mii_mediachg(mii); 883188412Sthompsa return (0); 884184610Salfred} 885184610Salfred 886184610Salfred/* 887184610Salfred * Report current media status. 888184610Salfred */ 889184610Salfredstatic void 890188412Sthompsarue_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 891184610Salfred{ 892184610Salfred struct rue_softc *sc = ifp->if_softc; 893188412Sthompsa struct mii_data *mii = GET_MII(sc); 894184610Salfred 895188412Sthompsa RUE_LOCK(sc); 896188412Sthompsa mii_pollstat(mii); 897188412Sthompsa RUE_UNLOCK(sc); 898188412Sthompsa ifmr->ifm_active = mii->mii_media_active; 899188412Sthompsa ifmr->ifm_status = mii->mii_media_status; 900184610Salfred} 901184610Salfred 902184610Salfredstatic void 903192984Sthompsarue_stop(struct usb_ether *ue) 904184610Salfred{ 905194228Sthompsa struct rue_softc *sc = uether_getsc(ue); 906194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 907184610Salfred 908188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 909184610Salfred 910188412Sthompsa ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 911188412Sthompsa sc->sc_flags &= ~RUE_FLAG_LINK; 912184610Salfred 913184610Salfred /* 914184610Salfred * stop all the transfers, if not already stopped: 915184610Salfred */ 916194228Sthompsa usbd_transfer_stop(sc->sc_xfer[RUE_BULK_DT_WR]); 917194228Sthompsa usbd_transfer_stop(sc->sc_xfer[RUE_BULK_DT_RD]); 918194228Sthompsa usbd_transfer_stop(sc->sc_xfer[RUE_INTR_DT_RD]); 919184610Salfred 920188412Sthompsa rue_csr_write_1(sc, RUE_CR, 0x00); 921184610Salfred 922188412Sthompsa rue_reset(sc); 923184610Salfred} 924