if_rue.c revision 192502
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 192502 2009-05-21 01:48:42Z 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" 69188942Sthompsa#include <dev/usb/usb.h> 70188942Sthompsa#include <dev/usb/usb_mfunc.h> 71188942Sthompsa#include <dev/usb/usb_error.h> 72184610Salfred 73184610Salfred#define USB_DEBUG_VAR rue_debug 74184610Salfred 75188942Sthompsa#include <dev/usb/usb_core.h> 76188942Sthompsa#include <dev/usb/usb_lookup.h> 77188942Sthompsa#include <dev/usb/usb_process.h> 78188942Sthompsa#include <dev/usb/usb_debug.h> 79188942Sthompsa#include <dev/usb/usb_request.h> 80188942Sthompsa#include <dev/usb/usb_busdma.h> 81188942Sthompsa#include <dev/usb/usb_util.h> 82184610Salfred 83188942Sthompsa#include <dev/usb/net/usb_ethernet.h> 84188942Sthompsa#include <dev/usb/net/if_ruereg.h> 85184610Salfred 86184610Salfred#if USB_DEBUG 87184610Salfredstatic int rue_debug = 0; 88184610Salfred 89192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, rue, CTLFLAG_RW, 0, "USB rue"); 90192502SthompsaSYSCTL_INT(_hw_usb_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; 108184610Salfred 109188412Sthompsastatic miibus_readreg_t rue_miibus_readreg; 110188412Sthompsastatic miibus_writereg_t rue_miibus_writereg; 111188412Sthompsastatic miibus_statchg_t rue_miibus_statchg; 112188412Sthompsa 113184610Salfredstatic usb2_callback_t rue_intr_callback; 114184610Salfredstatic usb2_callback_t rue_bulk_read_callback; 115184610Salfredstatic usb2_callback_t rue_bulk_write_callback; 116184610Salfred 117188412Sthompsastatic usb2_ether_fn_t rue_attach_post; 118188412Sthompsastatic usb2_ether_fn_t rue_init; 119188412Sthompsastatic usb2_ether_fn_t rue_stop; 120188412Sthompsastatic usb2_ether_fn_t rue_start; 121188412Sthompsastatic usb2_ether_fn_t rue_tick; 122188412Sthompsastatic usb2_ether_fn_t rue_setmulti; 123188412Sthompsastatic usb2_ether_fn_t rue_setpromisc; 124184610Salfred 125188412Sthompsastatic int rue_read_mem(struct rue_softc *, uint16_t, void *, int); 126188412Sthompsastatic int rue_write_mem(struct rue_softc *, uint16_t, void *, int); 127188412Sthompsastatic uint8_t rue_csr_read_1(struct rue_softc *, uint16_t); 128188412Sthompsastatic uint16_t rue_csr_read_2(struct rue_softc *, uint16_t); 129188412Sthompsastatic int rue_csr_write_1(struct rue_softc *, uint16_t, uint8_t); 130188412Sthompsastatic int rue_csr_write_2(struct rue_softc *, uint16_t, uint16_t); 131188412Sthompsastatic int rue_csr_write_4(struct rue_softc *, int, uint32_t); 132184610Salfred 133188412Sthompsastatic void rue_reset(struct rue_softc *); 134188412Sthompsastatic int rue_ifmedia_upd(struct ifnet *); 135188412Sthompsastatic void rue_ifmedia_sts(struct ifnet *, struct ifmediareq *); 136184610Salfred 137187259Sthompsastatic const struct usb2_config rue_config[RUE_N_TRANSFER] = { 138184610Salfred 139187259Sthompsa [RUE_BULK_DT_WR] = { 140184610Salfred .type = UE_BULK, 141184610Salfred .endpoint = UE_ADDR_ANY, 142184610Salfred .direction = UE_DIR_OUT, 143190734Sthompsa .bufsize = MCLBYTES, 144190734Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 145190734Sthompsa .callback = rue_bulk_write_callback, 146190734Sthompsa .timeout = 10000, /* 10 seconds */ 147184610Salfred }, 148184610Salfred 149187259Sthompsa [RUE_BULK_DT_RD] = { 150184610Salfred .type = UE_BULK, 151184610Salfred .endpoint = UE_ADDR_ANY, 152184610Salfred .direction = UE_DIR_IN, 153190734Sthompsa .bufsize = (MCLBYTES + 4), 154190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 155190734Sthompsa .callback = rue_bulk_read_callback, 156190734Sthompsa .timeout = 0, /* no timeout */ 157184610Salfred }, 158184610Salfred 159187259Sthompsa [RUE_INTR_DT_RD] = { 160184610Salfred .type = UE_INTERRUPT, 161184610Salfred .endpoint = UE_ADDR_ANY, 162184610Salfred .direction = UE_DIR_IN, 163190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 164190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 165190734Sthompsa .callback = rue_intr_callback, 166184610Salfred }, 167184610Salfred}; 168184610Salfred 169184610Salfredstatic device_method_t rue_methods[] = { 170184610Salfred /* Device interface */ 171184610Salfred DEVMETHOD(device_probe, rue_probe), 172184610Salfred DEVMETHOD(device_attach, rue_attach), 173184610Salfred DEVMETHOD(device_detach, rue_detach), 174184610Salfred 175184610Salfred /* Bus interface */ 176184610Salfred DEVMETHOD(bus_print_child, bus_generic_print_child), 177184610Salfred DEVMETHOD(bus_driver_added, bus_generic_driver_added), 178184610Salfred 179184610Salfred /* MII interface */ 180188412Sthompsa DEVMETHOD(miibus_readreg, rue_miibus_readreg), 181188412Sthompsa DEVMETHOD(miibus_writereg, rue_miibus_writereg), 182188412Sthompsa DEVMETHOD(miibus_statchg, rue_miibus_statchg), 183184610Salfred 184184610Salfred {0, 0} 185184610Salfred}; 186184610Salfred 187184610Salfredstatic driver_t rue_driver = { 188184610Salfred .name = "rue", 189184610Salfred .methods = rue_methods, 190184610Salfred .size = sizeof(struct rue_softc), 191184610Salfred}; 192184610Salfred 193184610Salfredstatic devclass_t rue_devclass; 194184610Salfred 195189275SthompsaDRIVER_MODULE(rue, uhub, rue_driver, rue_devclass, NULL, 0); 196184610SalfredDRIVER_MODULE(miibus, rue, miibus_driver, miibus_devclass, 0, 0); 197188942SthompsaMODULE_DEPEND(rue, uether, 1, 1, 1); 198188942SthompsaMODULE_DEPEND(rue, usb, 1, 1, 1); 199184610SalfredMODULE_DEPEND(rue, ether, 1, 1, 1); 200184610SalfredMODULE_DEPEND(rue, miibus, 1, 1, 1); 201184610Salfred 202188412Sthompsastatic const struct usb2_ether_methods rue_ue_methods = { 203188412Sthompsa .ue_attach_post = rue_attach_post, 204188412Sthompsa .ue_start = rue_start, 205188412Sthompsa .ue_init = rue_init, 206188412Sthompsa .ue_stop = rue_stop, 207188412Sthompsa .ue_tick = rue_tick, 208188412Sthompsa .ue_setmulti = rue_setmulti, 209188412Sthompsa .ue_setpromisc = rue_setpromisc, 210188412Sthompsa .ue_mii_upd = rue_ifmedia_upd, 211188412Sthompsa .ue_mii_sts = rue_ifmedia_sts, 212188412Sthompsa}; 213184610Salfred 214188412Sthompsa#define RUE_SETBIT(sc, reg, x) \ 215188412Sthompsa rue_csr_write_1(sc, reg, rue_csr_read_1(sc, reg) | (x)) 216184610Salfred 217188412Sthompsa#define RUE_CLRBIT(sc, reg, x) \ 218188412Sthompsa rue_csr_write_1(sc, reg, rue_csr_read_1(sc, reg) & ~(x)) 219184610Salfred 220188412Sthompsastatic int 221188412Sthompsarue_read_mem(struct rue_softc *sc, uint16_t addr, void *buf, int len) 222184610Salfred{ 223184610Salfred struct usb2_device_request req; 224184610Salfred 225184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 226184610Salfred req.bRequest = UR_SET_ADDRESS; 227184610Salfred USETW(req.wValue, addr); 228184610Salfred USETW(req.wIndex, 0); 229184610Salfred USETW(req.wLength, len); 230184610Salfred 231188412Sthompsa return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000)); 232184610Salfred} 233184610Salfred 234188412Sthompsastatic int 235188412Sthompsarue_write_mem(struct rue_softc *sc, uint16_t addr, void *buf, int len) 236184610Salfred{ 237184610Salfred struct usb2_device_request req; 238184610Salfred 239184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 240184610Salfred req.bRequest = UR_SET_ADDRESS; 241184610Salfred USETW(req.wValue, addr); 242184610Salfred USETW(req.wIndex, 0); 243184610Salfred USETW(req.wLength, len); 244184610Salfred 245188412Sthompsa return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000)); 246184610Salfred} 247184610Salfred 248184610Salfredstatic uint8_t 249188412Sthompsarue_csr_read_1(struct rue_softc *sc, uint16_t reg) 250184610Salfred{ 251184610Salfred uint8_t val; 252184610Salfred 253188412Sthompsa rue_read_mem(sc, reg, &val, 1); 254184610Salfred return (val); 255184610Salfred} 256184610Salfred 257184610Salfredstatic uint16_t 258188412Sthompsarue_csr_read_2(struct rue_softc *sc, uint16_t reg) 259184610Salfred{ 260184610Salfred uint8_t val[2]; 261184610Salfred 262188412Sthompsa rue_read_mem(sc, reg, &val, 2); 263184610Salfred return (UGETW(val)); 264184610Salfred} 265184610Salfred 266188412Sthompsastatic int 267188412Sthompsarue_csr_write_1(struct rue_softc *sc, uint16_t reg, uint8_t val) 268184610Salfred{ 269188412Sthompsa return (rue_write_mem(sc, reg, &val, 1)); 270184610Salfred} 271184610Salfred 272188412Sthompsastatic int 273188412Sthompsarue_csr_write_2(struct rue_softc *sc, uint16_t reg, uint16_t val) 274184610Salfred{ 275184610Salfred uint8_t temp[2]; 276184610Salfred 277184610Salfred USETW(temp, val); 278188412Sthompsa return (rue_write_mem(sc, reg, &temp, 2)); 279184610Salfred} 280184610Salfred 281188412Sthompsastatic int 282188412Sthompsarue_csr_write_4(struct rue_softc *sc, int reg, uint32_t val) 283184610Salfred{ 284184610Salfred uint8_t temp[4]; 285184610Salfred 286184610Salfred USETDW(temp, val); 287188412Sthompsa return (rue_write_mem(sc, reg, &temp, 4)); 288184610Salfred} 289184610Salfred 290184610Salfredstatic int 291188412Sthompsarue_miibus_readreg(device_t dev, int phy, int reg) 292184610Salfred{ 293184610Salfred struct rue_softc *sc = device_get_softc(dev); 294184610Salfred uint16_t rval; 295184610Salfred uint16_t ruereg; 296188412Sthompsa int locked; 297184610Salfred 298188412Sthompsa if (phy != 0) /* RTL8150 supports PHY == 0, only */ 299184610Salfred return (0); 300184610Salfred 301188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 302188412Sthompsa if (!locked) 303188412Sthompsa RUE_LOCK(sc); 304188412Sthompsa 305184610Salfred switch (reg) { 306184610Salfred case MII_BMCR: 307184610Salfred ruereg = RUE_BMCR; 308184610Salfred break; 309184610Salfred case MII_BMSR: 310184610Salfred ruereg = RUE_BMSR; 311184610Salfred break; 312184610Salfred case MII_ANAR: 313184610Salfred ruereg = RUE_ANAR; 314184610Salfred break; 315184610Salfred case MII_ANER: 316184610Salfred ruereg = RUE_AER; 317184610Salfred break; 318184610Salfred case MII_ANLPAR: 319184610Salfred ruereg = RUE_ANLP; 320184610Salfred break; 321184610Salfred case MII_PHYIDR1: 322184610Salfred case MII_PHYIDR2: 323184610Salfred rval = 0; 324184610Salfred goto done; 325184610Salfred default: 326188412Sthompsa if (RUE_REG_MIN <= reg && reg <= RUE_REG_MAX) { 327188412Sthompsa rval = rue_csr_read_1(sc, reg); 328184610Salfred goto done; 329184610Salfred } 330188412Sthompsa device_printf(sc->sc_ue.ue_dev, "bad phy register\n"); 331184610Salfred rval = 0; 332184610Salfred goto done; 333184610Salfred } 334184610Salfred 335188412Sthompsa rval = rue_csr_read_2(sc, ruereg); 336184610Salfreddone: 337188412Sthompsa if (!locked) 338188412Sthompsa RUE_UNLOCK(sc); 339184610Salfred return (rval); 340184610Salfred} 341184610Salfred 342184610Salfredstatic int 343188412Sthompsarue_miibus_writereg(device_t dev, int phy, int reg, int data) 344184610Salfred{ 345184610Salfred struct rue_softc *sc = device_get_softc(dev); 346184610Salfred uint16_t ruereg; 347188412Sthompsa int locked; 348184610Salfred 349188412Sthompsa if (phy != 0) /* RTL8150 supports PHY == 0, only */ 350184610Salfred return (0); 351184610Salfred 352188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 353188412Sthompsa if (!locked) 354188412Sthompsa RUE_LOCK(sc); 355188412Sthompsa 356184610Salfred switch (reg) { 357184610Salfred case MII_BMCR: 358184610Salfred ruereg = RUE_BMCR; 359184610Salfred break; 360184610Salfred case MII_BMSR: 361184610Salfred ruereg = RUE_BMSR; 362184610Salfred break; 363184610Salfred case MII_ANAR: 364184610Salfred ruereg = RUE_ANAR; 365184610Salfred break; 366184610Salfred case MII_ANER: 367184610Salfred ruereg = RUE_AER; 368184610Salfred break; 369184610Salfred case MII_ANLPAR: 370184610Salfred ruereg = RUE_ANLP; 371184610Salfred break; 372184610Salfred case MII_PHYIDR1: 373184610Salfred case MII_PHYIDR2: 374184610Salfred goto done; 375184610Salfred default: 376188412Sthompsa if (RUE_REG_MIN <= reg && reg <= RUE_REG_MAX) { 377188412Sthompsa rue_csr_write_1(sc, reg, data); 378184610Salfred goto done; 379184610Salfred } 380188412Sthompsa device_printf(sc->sc_ue.ue_dev, " bad phy register\n"); 381184610Salfred goto done; 382184610Salfred } 383188412Sthompsa rue_csr_write_2(sc, ruereg, data); 384184610Salfreddone: 385188412Sthompsa if (!locked) 386188412Sthompsa RUE_UNLOCK(sc); 387184610Salfred return (0); 388184610Salfred} 389184610Salfred 390184610Salfredstatic void 391188412Sthompsarue_miibus_statchg(device_t dev) 392184610Salfred{ 393184610Salfred /* 394184610Salfred * When the code below is enabled the card starts doing weird 395184610Salfred * things after link going from UP to DOWN and back UP. 396184610Salfred * 397184610Salfred * Looks like some of register writes below messes up PHY 398184610Salfred * interface. 399184610Salfred * 400184610Salfred * No visible regressions were found after commenting this code 401184610Salfred * out, so that disable it for good. 402184610Salfred */ 403184610Salfred#if 0 404184610Salfred struct rue_softc *sc = device_get_softc(dev); 405184610Salfred struct mii_data *mii = GET_MII(sc); 406184610Salfred uint16_t bmcr; 407188412Sthompsa int locked; 408184610Salfred 409188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 410188412Sthompsa if (!locked) 411188412Sthompsa RUE_LOCK(sc); 412184610Salfred 413188412Sthompsa RUE_CLRBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE)); 414184610Salfred 415188412Sthompsa bmcr = rue_csr_read_2(sc, RUE_BMCR); 416184610Salfred 417184610Salfred if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) 418184610Salfred bmcr |= RUE_BMCR_SPD_SET; 419184610Salfred else 420184610Salfred bmcr &= ~RUE_BMCR_SPD_SET; 421184610Salfred 422184610Salfred if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) 423184610Salfred bmcr |= RUE_BMCR_DUPLEX; 424184610Salfred else 425184610Salfred bmcr &= ~RUE_BMCR_DUPLEX; 426184610Salfred 427188412Sthompsa rue_csr_write_2(sc, RUE_BMCR, bmcr); 428184610Salfred 429188412Sthompsa RUE_SETBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE)); 430184610Salfred 431188412Sthompsa if (!locked) 432188412Sthompsa RUE_UNLOCK(sc); 433184610Salfred#endif 434184610Salfred} 435184610Salfred 436184610Salfredstatic void 437188412Sthompsarue_setpromisc(struct usb2_ether *ue) 438184610Salfred{ 439188412Sthompsa struct rue_softc *sc = usb2_ether_getsc(ue); 440188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 441184610Salfred 442188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 443184610Salfred 444188412Sthompsa /* If we want promiscuous mode, set the allframes bit. */ 445188412Sthompsa if (ifp->if_flags & IFF_PROMISC) 446188412Sthompsa RUE_SETBIT(sc, RUE_RCR, RUE_RCR_AAP); 447188412Sthompsa else 448188412Sthompsa RUE_CLRBIT(sc, RUE_RCR, RUE_RCR_AAP); 449184610Salfred} 450184610Salfred 451184610Salfred/* 452184610Salfred * Program the 64-bit multicast hash filter. 453184610Salfred */ 454184610Salfredstatic void 455188412Sthompsarue_setmulti(struct usb2_ether *ue) 456184610Salfred{ 457188412Sthompsa struct rue_softc *sc = usb2_ether_getsc(ue); 458188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 459184610Salfred uint16_t rxcfg; 460188412Sthompsa int h = 0; 461188412Sthompsa uint32_t hashes[2] = { 0, 0 }; 462188412Sthompsa struct ifmultiaddr *ifma; 463188412Sthompsa int mcnt = 0; 464184610Salfred 465188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 466184610Salfred 467188412Sthompsa rxcfg = rue_csr_read_2(sc, RUE_RCR); 468188412Sthompsa 469188412Sthompsa if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 470184610Salfred rxcfg |= (RUE_RCR_AAM | RUE_RCR_AAP); 471184610Salfred rxcfg &= ~RUE_RCR_AM; 472188412Sthompsa rue_csr_write_2(sc, RUE_RCR, rxcfg); 473188412Sthompsa rue_csr_write_4(sc, RUE_MAR0, 0xFFFFFFFF); 474188412Sthompsa rue_csr_write_4(sc, RUE_MAR4, 0xFFFFFFFF); 475184610Salfred return; 476184610Salfred } 477184610Salfred 478188412Sthompsa /* first, zot all the existing hash bits */ 479188412Sthompsa rue_csr_write_4(sc, RUE_MAR0, 0); 480188412Sthompsa rue_csr_write_4(sc, RUE_MAR4, 0); 481188412Sthompsa 482188412Sthompsa /* now program new ones */ 483188412Sthompsa IF_ADDR_LOCK(ifp); 484188412Sthompsa TAILQ_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link) 485188412Sthompsa { 486188412Sthompsa if (ifma->ifma_addr->sa_family != AF_LINK) 487188412Sthompsa continue; 488188412Sthompsa h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 489188412Sthompsa ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 490188412Sthompsa if (h < 32) 491188412Sthompsa hashes[0] |= (1 << h); 492188412Sthompsa else 493188412Sthompsa hashes[1] |= (1 << (h - 32)); 494188412Sthompsa mcnt++; 495188412Sthompsa } 496188412Sthompsa IF_ADDR_UNLOCK(ifp); 497188412Sthompsa 498188412Sthompsa if (mcnt) 499184610Salfred rxcfg |= RUE_RCR_AM; 500184610Salfred else 501184610Salfred rxcfg &= ~RUE_RCR_AM; 502184610Salfred 503184610Salfred rxcfg &= ~(RUE_RCR_AAM | RUE_RCR_AAP); 504184610Salfred 505188412Sthompsa rue_csr_write_2(sc, RUE_RCR, rxcfg); 506188412Sthompsa rue_csr_write_4(sc, RUE_MAR0, hashes[0]); 507188412Sthompsa rue_csr_write_4(sc, RUE_MAR4, hashes[1]); 508184610Salfred} 509184610Salfred 510184610Salfredstatic void 511188412Sthompsarue_reset(struct rue_softc *sc) 512184610Salfred{ 513188412Sthompsa int i; 514184610Salfred 515188412Sthompsa rue_csr_write_1(sc, RUE_CR, RUE_CR_SOFT_RST); 516184610Salfred 517188412Sthompsa for (i = 0; i != RUE_TIMEOUT; i++) { 518188412Sthompsa if (usb2_ether_pause(&sc->sc_ue, hz / 1000)) 519188412Sthompsa break; 520188412Sthompsa if (!(rue_csr_read_1(sc, RUE_CR) & RUE_CR_SOFT_RST)) 521188412Sthompsa break; 522188412Sthompsa } 523188412Sthompsa if (i == RUE_TIMEOUT) 524188412Sthompsa device_printf(sc->sc_ue.ue_dev, "reset never completed!\n"); 525184610Salfred 526188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 100); 527188412Sthompsa} 528184610Salfred 529188412Sthompsastatic void 530188412Sthompsarue_attach_post(struct usb2_ether *ue) 531188412Sthompsa{ 532188412Sthompsa struct rue_softc *sc = usb2_ether_getsc(ue); 533184610Salfred 534188412Sthompsa /* reset the adapter */ 535188412Sthompsa rue_reset(sc); 536184610Salfred 537188412Sthompsa /* get station address from the EEPROM */ 538188412Sthompsa rue_read_mem(sc, RUE_EEPROM_IDR0, ue->ue_eaddr, ETHER_ADDR_LEN); 539184610Salfred} 540184610Salfred 541184610Salfred/* 542184610Salfred * Probe for a RTL8150 chip. 543184610Salfred */ 544184610Salfredstatic int 545184610Salfredrue_probe(device_t dev) 546184610Salfred{ 547184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 548184610Salfred 549192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 550184610Salfred return (ENXIO); 551188412Sthompsa if (uaa->info.bConfigIndex != RUE_CONFIG_IDX) 552184610Salfred return (ENXIO); 553188412Sthompsa if (uaa->info.bIfaceIndex != RUE_IFACE_IDX) 554184610Salfred return (ENXIO); 555188412Sthompsa 556184610Salfred return (usb2_lookup_id_by_uaa(rue_devs, sizeof(rue_devs), uaa)); 557184610Salfred} 558184610Salfred 559184610Salfred/* 560184610Salfred * Attach the interface. Allocate softc structures, do ifmedia 561184610Salfred * setup and ethernet/BPF attach. 562184610Salfred */ 563184610Salfredstatic int 564184610Salfredrue_attach(device_t dev) 565184610Salfred{ 566184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 567184610Salfred struct rue_softc *sc = device_get_softc(dev); 568188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 569184610Salfred uint8_t iface_index; 570188412Sthompsa int error; 571184610Salfred 572184610Salfred device_set_usb2_desc(dev); 573188412Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 574184610Salfred 575184610Salfred iface_index = RUE_IFACE_IDX; 576184610Salfred error = usb2_transfer_setup(uaa->device, &iface_index, 577187259Sthompsa sc->sc_xfer, rue_config, RUE_N_TRANSFER, 578184610Salfred sc, &sc->sc_mtx); 579184610Salfred if (error) { 580188412Sthompsa device_printf(dev, "allocating USB transfers failed!\n"); 581184610Salfred goto detach; 582184610Salfred } 583188412Sthompsa 584188412Sthompsa ue->ue_sc = sc; 585188412Sthompsa ue->ue_dev = dev; 586188412Sthompsa ue->ue_udev = uaa->device; 587188412Sthompsa ue->ue_mtx = &sc->sc_mtx; 588188412Sthompsa ue->ue_methods = &rue_ue_methods; 589188412Sthompsa 590188412Sthompsa error = usb2_ether_ifattach(ue); 591184610Salfred if (error) { 592188412Sthompsa device_printf(dev, "could not attach interface\n"); 593184610Salfred goto detach; 594184610Salfred } 595184610Salfred return (0); /* success */ 596184610Salfred 597184610Salfreddetach: 598184610Salfred rue_detach(dev); 599184610Salfred return (ENXIO); /* failure */ 600184610Salfred} 601184610Salfred 602184610Salfredstatic int 603184610Salfredrue_detach(device_t dev) 604184610Salfred{ 605184610Salfred struct rue_softc *sc = device_get_softc(dev); 606188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 607184610Salfred 608187259Sthompsa usb2_transfer_unsetup(sc->sc_xfer, RUE_N_TRANSFER); 609188412Sthompsa usb2_ether_ifdetach(ue); 610184610Salfred mtx_destroy(&sc->sc_mtx); 611184610Salfred 612184610Salfred return (0); 613184610Salfred} 614184610Salfred 615184610Salfredstatic void 616184610Salfredrue_intr_callback(struct usb2_xfer *xfer) 617184610Salfred{ 618184610Salfred struct rue_softc *sc = xfer->priv_sc; 619188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue); 620184610Salfred struct rue_intrpkt pkt; 621184610Salfred 622184610Salfred switch (USB_GET_STATE(xfer)) { 623184610Salfred case USB_ST_TRANSFERRED: 624184610Salfred 625184610Salfred if (ifp && (ifp->if_drv_flags & IFF_DRV_RUNNING) && 626184610Salfred (xfer->actlen >= sizeof(pkt))) { 627184610Salfred 628184610Salfred usb2_copy_out(xfer->frbuffers, 0, &pkt, sizeof(pkt)); 629184610Salfred 630184610Salfred ifp->if_ierrors += pkt.rue_rxlost_cnt; 631184610Salfred ifp->if_ierrors += pkt.rue_crcerr_cnt; 632184610Salfred ifp->if_collisions += pkt.rue_col_cnt; 633184610Salfred } 634188412Sthompsa /* FALLTHROUGH */ 635184610Salfred case USB_ST_SETUP: 636188412Sthompsatr_setup: 637188412Sthompsa xfer->frlengths[0] = xfer->max_data_length; 638188412Sthompsa usb2_start_hardware(xfer); 639184610Salfred return; 640184610Salfred 641184610Salfred default: /* Error */ 642184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 643188412Sthompsa /* try to clear stall first */ 644188412Sthompsa xfer->flags.stall_pipe = 1; 645188412Sthompsa goto tr_setup; 646184610Salfred } 647184610Salfred return; 648184610Salfred } 649184610Salfred} 650184610Salfred 651184610Salfredstatic void 652184610Salfredrue_bulk_read_callback(struct usb2_xfer *xfer) 653184610Salfred{ 654184610Salfred struct rue_softc *sc = xfer->priv_sc; 655188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 656188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 657184610Salfred uint16_t status; 658184610Salfred 659184610Salfred switch (USB_GET_STATE(xfer)) { 660184610Salfred case USB_ST_TRANSFERRED: 661184610Salfred 662184610Salfred if (xfer->actlen < 4) { 663184610Salfred ifp->if_ierrors++; 664184610Salfred goto tr_setup; 665184610Salfred } 666184610Salfred usb2_copy_out(xfer->frbuffers, xfer->actlen - 4, 667184610Salfred &status, sizeof(status)); 668188412Sthompsa xfer->actlen -= 4; 669184610Salfred 670188412Sthompsa /* check recieve packet was valid or not */ 671184610Salfred status = le16toh(status); 672184610Salfred if ((status & RUE_RXSTAT_VALID) == 0) { 673184610Salfred ifp->if_ierrors++; 674184610Salfred goto tr_setup; 675184610Salfred } 676188412Sthompsa usb2_ether_rxbuf(ue, xfer->frbuffers, 0, xfer->actlen); 677188412Sthompsa /* FALLTHROUGH */ 678184610Salfred case USB_ST_SETUP: 679184610Salfredtr_setup: 680188412Sthompsa xfer->frlengths[0] = xfer->max_data_length; 681188412Sthompsa usb2_start_hardware(xfer); 682188412Sthompsa usb2_ether_rxflush(ue); 683184610Salfred return; 684184610Salfred 685184610Salfred default: /* Error */ 686188412Sthompsa DPRINTF("bulk read error, %s\n", 687188412Sthompsa usb2_errstr(xfer->error)); 688188412Sthompsa 689184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 690184610Salfred /* try to clear stall first */ 691188412Sthompsa xfer->flags.stall_pipe = 1; 692188412Sthompsa goto tr_setup; 693184610Salfred } 694184610Salfred return; 695184610Salfred } 696184610Salfred} 697184610Salfred 698184610Salfredstatic void 699184610Salfredrue_bulk_write_callback(struct usb2_xfer *xfer) 700184610Salfred{ 701184610Salfred struct rue_softc *sc = xfer->priv_sc; 702188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue); 703184610Salfred struct mbuf *m; 704188412Sthompsa int temp_len; 705184610Salfred 706184610Salfred switch (USB_GET_STATE(xfer)) { 707184610Salfred case USB_ST_TRANSFERRED: 708184610Salfred DPRINTFN(11, "transfer complete\n"); 709184610Salfred ifp->if_opackets++; 710184610Salfred 711188412Sthompsa /* FALLTHROUGH */ 712184610Salfred case USB_ST_SETUP: 713188412Sthompsatr_setup: 714188412Sthompsa if ((sc->sc_flags & RUE_FLAG_LINK) == 0) { 715184610Salfred /* 716184610Salfred * don't send anything if there is no link ! 717184610Salfred */ 718188412Sthompsa return; 719184610Salfred } 720184610Salfred IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 721184610Salfred 722188412Sthompsa if (m == NULL) 723188412Sthompsa return; 724188412Sthompsa if (m->m_pkthdr.len > MCLBYTES) 725184610Salfred m->m_pkthdr.len = MCLBYTES; 726184610Salfred temp_len = m->m_pkthdr.len; 727184610Salfred 728184610Salfred usb2_m_copy_in(xfer->frbuffers, 0, 729184610Salfred m, 0, m->m_pkthdr.len); 730184610Salfred 731184610Salfred /* 732184610Salfred * This is an undocumented behavior. 733184610Salfred * RTL8150 chip doesn't send frame length smaller than 734184610Salfred * RUE_MIN_FRAMELEN (60) byte packet. 735184610Salfred */ 736184610Salfred if (temp_len < RUE_MIN_FRAMELEN) { 737184610Salfred usb2_bzero(xfer->frbuffers, temp_len, 738184610Salfred RUE_MIN_FRAMELEN - temp_len); 739184610Salfred temp_len = RUE_MIN_FRAMELEN; 740184610Salfred } 741184610Salfred xfer->frlengths[0] = temp_len; 742184610Salfred 743184610Salfred /* 744184610Salfred * if there's a BPF listener, bounce a copy 745184610Salfred * of this frame to him: 746184610Salfred */ 747184610Salfred BPF_MTAP(ifp, m); 748184610Salfred 749184610Salfred m_freem(m); 750184610Salfred 751184610Salfred usb2_start_hardware(xfer); 752184610Salfred 753184610Salfred return; 754184610Salfred 755184610Salfred default: /* Error */ 756184610Salfred DPRINTFN(11, "transfer error, %s\n", 757184610Salfred usb2_errstr(xfer->error)); 758184610Salfred 759188412Sthompsa ifp->if_oerrors++; 760188412Sthompsa 761184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 762184610Salfred /* try to clear stall first */ 763188412Sthompsa xfer->flags.stall_pipe = 1; 764188412Sthompsa goto tr_setup; 765184610Salfred } 766184610Salfred return; 767184610Salfred } 768184610Salfred} 769184610Salfred 770184610Salfredstatic void 771188412Sthompsarue_tick(struct usb2_ether *ue) 772184610Salfred{ 773188412Sthompsa struct rue_softc *sc = usb2_ether_getsc(ue); 774184610Salfred struct mii_data *mii = GET_MII(sc); 775184610Salfred 776188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 777188412Sthompsa 778184610Salfred mii_tick(mii); 779188412Sthompsa if ((sc->sc_flags & RUE_FLAG_LINK) == 0 780188412Sthompsa && mii->mii_media_status & IFM_ACTIVE && 781188412Sthompsa IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 782188412Sthompsa sc->sc_flags |= RUE_FLAG_LINK; 783188412Sthompsa rue_start(ue); 784184610Salfred } 785184610Salfred} 786184610Salfred 787184610Salfredstatic void 788188412Sthompsarue_start(struct usb2_ether *ue) 789184610Salfred{ 790188412Sthompsa struct rue_softc *sc = usb2_ether_getsc(ue); 791184610Salfred 792188412Sthompsa /* 793188412Sthompsa * start the USB transfers, if not already started: 794188412Sthompsa */ 795188412Sthompsa usb2_transfer_start(sc->sc_xfer[RUE_INTR_DT_RD]); 796188412Sthompsa usb2_transfer_start(sc->sc_xfer[RUE_BULK_DT_RD]); 797188412Sthompsa usb2_transfer_start(sc->sc_xfer[RUE_BULK_DT_WR]); 798184610Salfred} 799184610Salfred 800184610Salfredstatic void 801188412Sthompsarue_init(struct usb2_ether *ue) 802184610Salfred{ 803188412Sthompsa struct rue_softc *sc = usb2_ether_getsc(ue); 804188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 805184610Salfred 806188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 807184610Salfred 808184610Salfred /* 809184610Salfred * Cancel pending I/O 810184610Salfred */ 811188412Sthompsa rue_reset(sc); 812184610Salfred 813188412Sthompsa /* Set MAC address */ 814188412Sthompsa rue_write_mem(sc, RUE_IDR0, IF_LLADDR(ifp), ETHER_ADDR_LEN); 815184610Salfred 816188412Sthompsa rue_stop(ue); 817184610Salfred 818184610Salfred /* 819184610Salfred * Set the initial TX and RX configuration. 820184610Salfred */ 821188412Sthompsa rue_csr_write_1(sc, RUE_TCR, RUE_TCR_CONFIG); 822188412Sthompsa rue_csr_write_2(sc, RUE_RCR, RUE_RCR_CONFIG|RUE_RCR_AB); 823184610Salfred 824184610Salfred /* Load the multicast filter */ 825188412Sthompsa rue_setpromisc(ue); 826188412Sthompsa /* Load the multicast filter. */ 827188412Sthompsa rue_setmulti(ue); 828184610Salfred 829184610Salfred /* Enable RX and TX */ 830188412Sthompsa rue_csr_write_1(sc, RUE_CR, (RUE_CR_TE | RUE_CR_RE | RUE_CR_EP3CLREN)); 831184610Salfred 832188412Sthompsa usb2_transfer_set_stall(sc->sc_xfer[RUE_BULK_DT_WR]); 833184610Salfred 834188412Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 835188412Sthompsa rue_start(ue); 836184610Salfred} 837184610Salfred 838184610Salfred/* 839184610Salfred * Set media options. 840184610Salfred */ 841184610Salfredstatic int 842188412Sthompsarue_ifmedia_upd(struct ifnet *ifp) 843184610Salfred{ 844184610Salfred struct rue_softc *sc = ifp->if_softc; 845184610Salfred struct mii_data *mii = GET_MII(sc); 846184610Salfred 847188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 848184610Salfred 849188412Sthompsa sc->sc_flags &= ~RUE_FLAG_LINK; 850184610Salfred if (mii->mii_instance) { 851184610Salfred struct mii_softc *miisc; 852184610Salfred 853188412Sthompsa LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 854184610Salfred mii_phy_reset(miisc); 855184610Salfred } 856184610Salfred mii_mediachg(mii); 857188412Sthompsa return (0); 858184610Salfred} 859184610Salfred 860184610Salfred/* 861184610Salfred * Report current media status. 862184610Salfred */ 863184610Salfredstatic void 864188412Sthompsarue_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 865184610Salfred{ 866184610Salfred struct rue_softc *sc = ifp->if_softc; 867188412Sthompsa struct mii_data *mii = GET_MII(sc); 868184610Salfred 869188412Sthompsa RUE_LOCK(sc); 870188412Sthompsa mii_pollstat(mii); 871188412Sthompsa RUE_UNLOCK(sc); 872188412Sthompsa ifmr->ifm_active = mii->mii_media_active; 873188412Sthompsa ifmr->ifm_status = mii->mii_media_status; 874184610Salfred} 875184610Salfred 876184610Salfredstatic void 877188412Sthompsarue_stop(struct usb2_ether *ue) 878184610Salfred{ 879188412Sthompsa struct rue_softc *sc = usb2_ether_getsc(ue); 880188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 881184610Salfred 882188412Sthompsa RUE_LOCK_ASSERT(sc, MA_OWNED); 883184610Salfred 884188412Sthompsa ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 885188412Sthompsa sc->sc_flags &= ~RUE_FLAG_LINK; 886184610Salfred 887184610Salfred /* 888184610Salfred * stop all the transfers, if not already stopped: 889184610Salfred */ 890187259Sthompsa usb2_transfer_stop(sc->sc_xfer[RUE_BULK_DT_WR]); 891187259Sthompsa usb2_transfer_stop(sc->sc_xfer[RUE_BULK_DT_RD]); 892187259Sthompsa usb2_transfer_stop(sc->sc_xfer[RUE_INTR_DT_RD]); 893184610Salfred 894188412Sthompsa rue_csr_write_1(sc, RUE_CR, 0x00); 895184610Salfred 896188412Sthompsa rue_reset(sc); 897184610Salfred} 898