if_rue.c revision 187259
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 187259 2009-01-15 02:35:40Z 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 68184610Salfred/* 69184610Salfred * NOTE: all function names beginning like "rue_cfg_" can only 70184610Salfred * be called from within the config thread function ! 71184610Salfred */ 72184610Salfred 73184610Salfred#include <dev/usb2/include/usb2_devid.h> 74184610Salfred#include <dev/usb2/include/usb2_standard.h> 75184610Salfred#include <dev/usb2/include/usb2_mfunc.h> 76184610Salfred#include <dev/usb2/include/usb2_error.h> 77184610Salfred 78184610Salfred#define usb2_config_td_cc usb2_ether_cc 79184610Salfred#define usb2_config_td_softc rue_softc 80184610Salfred 81184610Salfred#define USB_DEBUG_VAR rue_debug 82184610Salfred 83184610Salfred#include <dev/usb2/core/usb2_core.h> 84184610Salfred#include <dev/usb2/core/usb2_lookup.h> 85184610Salfred#include <dev/usb2/core/usb2_process.h> 86184610Salfred#include <dev/usb2/core/usb2_config_td.h> 87184610Salfred#include <dev/usb2/core/usb2_debug.h> 88184610Salfred#include <dev/usb2/core/usb2_request.h> 89184610Salfred#include <dev/usb2/core/usb2_busdma.h> 90184610Salfred#include <dev/usb2/core/usb2_util.h> 91184610Salfred 92184610Salfred#include <dev/usb2/ethernet/usb2_ethernet.h> 93187192Sthompsa#include <dev/usb2/ethernet/if_ruereg.h> 94184610Salfred 95184610Salfred#if USB_DEBUG 96184610Salfredstatic int rue_debug = 0; 97184610Salfred 98184610SalfredSYSCTL_NODE(_hw_usb2, OID_AUTO, rue, CTLFLAG_RW, 0, "USB rue"); 99184610SalfredSYSCTL_INT(_hw_usb2_rue, OID_AUTO, debug, CTLFLAG_RW, 100184610Salfred &rue_debug, 0, "Debug level"); 101184610Salfred#endif 102184610Salfred 103184610Salfred/* 104184610Salfred * Various supported device vendors/products. 105184610Salfred */ 106184610Salfred 107184610Salfredstatic const struct usb2_device_id rue_devs[] = { 108184610Salfred {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX, 0)}, 109184610Salfred {USB_VPI(USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_USBKR100, 0)}, 110184610Salfred}; 111184610Salfred 112184610Salfred/* prototypes */ 113184610Salfred 114184610Salfredstatic device_probe_t rue_probe; 115184610Salfredstatic device_attach_t rue_attach; 116184610Salfredstatic device_detach_t rue_detach; 117184610Salfredstatic device_shutdown_t rue_shutdown; 118184610Salfred 119184610Salfredstatic usb2_callback_t rue_intr_clear_stall_callback; 120184610Salfredstatic usb2_callback_t rue_intr_callback; 121184610Salfredstatic usb2_callback_t rue_bulk_read_clear_stall_callback; 122184610Salfredstatic usb2_callback_t rue_bulk_read_callback; 123184610Salfredstatic usb2_callback_t rue_bulk_write_clear_stall_callback; 124184610Salfredstatic usb2_callback_t rue_bulk_write_callback; 125184610Salfred 126184610Salfredstatic usb2_config_td_command_t rue_config_copy; 127184610Salfredstatic usb2_config_td_command_t rue_cfg_promisc_upd; 128184610Salfredstatic usb2_config_td_command_t rue_cfg_first_time_setup; 129184610Salfredstatic usb2_config_td_command_t rue_cfg_tick; 130184610Salfredstatic usb2_config_td_command_t rue_cfg_pre_init; 131184610Salfredstatic usb2_config_td_command_t rue_cfg_init; 132184610Salfredstatic usb2_config_td_command_t rue_cfg_ifmedia_upd; 133184610Salfredstatic usb2_config_td_command_t rue_cfg_pre_stop; 134184610Salfredstatic usb2_config_td_command_t rue_cfg_stop; 135184610Salfred 136184610Salfredstatic void rue_cfg_do_request(struct rue_softc *sc, struct usb2_device_request *req, void *data); 137184610Salfredstatic void rue_cfg_read_mem(struct rue_softc *sc, uint16_t addr, void *buf, uint16_t len); 138184610Salfredstatic void rue_cfg_write_mem(struct rue_softc *sc, uint16_t addr, void *buf, uint16_t len); 139184610Salfredstatic uint8_t rue_cfg_csr_read_1(struct rue_softc *sc, uint16_t reg); 140184610Salfredstatic uint16_t rue_cfg_csr_read_2(struct rue_softc *sc, uint16_t reg); 141184610Salfredstatic void rue_cfg_csr_write_1(struct rue_softc *sc, uint16_t reg, uint8_t val); 142184610Salfredstatic void rue_cfg_csr_write_2(struct rue_softc *sc, uint16_t reg, uint16_t val); 143184610Salfredstatic void rue_cfg_csr_write_4(struct rue_softc *sc, int reg, uint32_t val); 144184610Salfred 145184610Salfredstatic miibus_readreg_t rue_cfg_miibus_readreg; 146184610Salfredstatic miibus_writereg_t rue_cfg_miibus_writereg; 147184610Salfredstatic miibus_statchg_t rue_cfg_miibus_statchg; 148184610Salfred 149184610Salfredstatic void rue_cfg_reset(struct rue_softc *sc); 150184610Salfredstatic void rue_start_cb(struct ifnet *ifp); 151184610Salfredstatic void rue_start_transfers(struct rue_softc *sc); 152184610Salfredstatic void rue_init_cb(void *arg); 153184610Salfredstatic int rue_ifmedia_upd_cb(struct ifnet *ifp); 154184610Salfredstatic void rue_ifmedia_sts_cb(struct ifnet *ifp, struct ifmediareq *ifmr); 155184610Salfredstatic int rue_ioctl_cb(struct ifnet *ifp, u_long command, caddr_t data); 156184610Salfredstatic void rue_watchdog(void *arg); 157184610Salfred 158187259Sthompsastatic const struct usb2_config rue_config[RUE_N_TRANSFER] = { 159184610Salfred 160187259Sthompsa [RUE_BULK_DT_WR] = { 161184610Salfred .type = UE_BULK, 162184610Salfred .endpoint = UE_ADDR_ANY, 163184610Salfred .direction = UE_DIR_OUT, 164184610Salfred .mh.bufsize = MCLBYTES, 165184610Salfred .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 166184610Salfred .mh.callback = &rue_bulk_write_callback, 167184610Salfred .mh.timeout = 10000, /* 10 seconds */ 168184610Salfred }, 169184610Salfred 170187259Sthompsa [RUE_BULK_DT_RD] = { 171184610Salfred .type = UE_BULK, 172184610Salfred .endpoint = UE_ADDR_ANY, 173184610Salfred .direction = UE_DIR_IN, 174184610Salfred .mh.bufsize = (MCLBYTES + 4), 175184610Salfred .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 176184610Salfred .mh.callback = &rue_bulk_read_callback, 177184610Salfred .mh.timeout = 0, /* no timeout */ 178184610Salfred }, 179184610Salfred 180187259Sthompsa [RUE_BULK_CS_WR] = { 181184610Salfred .type = UE_CONTROL, 182184610Salfred .endpoint = 0x00, /* Control pipe */ 183184610Salfred .direction = UE_DIR_ANY, 184184610Salfred .mh.bufsize = sizeof(struct usb2_device_request), 185184610Salfred .mh.flags = {}, 186184610Salfred .mh.callback = &rue_bulk_write_clear_stall_callback, 187184610Salfred .mh.timeout = 1000, /* 1 second */ 188184610Salfred .mh.interval = 50, /* 50ms */ 189184610Salfred }, 190184610Salfred 191187259Sthompsa [RUE_BULK_CS_RD] = { 192184610Salfred .type = UE_CONTROL, 193184610Salfred .endpoint = 0x00, /* Control pipe */ 194184610Salfred .direction = UE_DIR_ANY, 195184610Salfred .mh.bufsize = sizeof(struct usb2_device_request), 196184610Salfred .mh.flags = {}, 197184610Salfred .mh.callback = &rue_bulk_read_clear_stall_callback, 198184610Salfred .mh.timeout = 1000, /* 1 second */ 199184610Salfred .mh.interval = 50, /* 50ms */ 200184610Salfred }, 201184610Salfred 202187259Sthompsa [RUE_INTR_DT_RD] = { 203184610Salfred .type = UE_INTERRUPT, 204184610Salfred .endpoint = UE_ADDR_ANY, 205184610Salfred .direction = UE_DIR_IN, 206184610Salfred .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 207184610Salfred .mh.bufsize = 0, /* use wMaxPacketSize */ 208184610Salfred .mh.callback = &rue_intr_callback, 209184610Salfred }, 210184610Salfred 211187259Sthompsa [RUE_INTR_CS_RD] = { 212184610Salfred .type = UE_CONTROL, 213184610Salfred .endpoint = 0x00, /* Control pipe */ 214184610Salfred .direction = UE_DIR_ANY, 215184610Salfred .mh.bufsize = sizeof(struct usb2_device_request), 216184610Salfred .mh.flags = {}, 217184610Salfred .mh.callback = &rue_intr_clear_stall_callback, 218184610Salfred .mh.timeout = 1000, /* 1 second */ 219184610Salfred .mh.interval = 50, /* 50ms */ 220184610Salfred }, 221184610Salfred}; 222184610Salfred 223184610Salfredstatic device_method_t rue_methods[] = { 224184610Salfred /* Device interface */ 225184610Salfred DEVMETHOD(device_probe, rue_probe), 226184610Salfred DEVMETHOD(device_attach, rue_attach), 227184610Salfred DEVMETHOD(device_detach, rue_detach), 228184610Salfred DEVMETHOD(device_shutdown, rue_shutdown), 229184610Salfred 230184610Salfred /* Bus interface */ 231184610Salfred DEVMETHOD(bus_print_child, bus_generic_print_child), 232184610Salfred DEVMETHOD(bus_driver_added, bus_generic_driver_added), 233184610Salfred 234184610Salfred /* MII interface */ 235184610Salfred DEVMETHOD(miibus_readreg, rue_cfg_miibus_readreg), 236184610Salfred DEVMETHOD(miibus_writereg, rue_cfg_miibus_writereg), 237184610Salfred DEVMETHOD(miibus_statchg, rue_cfg_miibus_statchg), 238184610Salfred 239184610Salfred {0, 0} 240184610Salfred}; 241184610Salfred 242184610Salfredstatic driver_t rue_driver = { 243184610Salfred .name = "rue", 244184610Salfred .methods = rue_methods, 245184610Salfred .size = sizeof(struct rue_softc), 246184610Salfred}; 247184610Salfred 248184610Salfredstatic devclass_t rue_devclass; 249184610Salfred 250184610SalfredDRIVER_MODULE(rue, ushub, rue_driver, rue_devclass, NULL, 0); 251184610SalfredDRIVER_MODULE(miibus, rue, miibus_driver, miibus_devclass, 0, 0); 252184610SalfredMODULE_DEPEND(rue, usb2_ethernet, 1, 1, 1); 253184610SalfredMODULE_DEPEND(rue, usb2_core, 1, 1, 1); 254184610SalfredMODULE_DEPEND(rue, ether, 1, 1, 1); 255184610SalfredMODULE_DEPEND(rue, miibus, 1, 1, 1); 256184610Salfred 257184610Salfredstatic void 258184610Salfredrue_cfg_do_request(struct rue_softc *sc, struct usb2_device_request *req, 259184610Salfred void *data) 260184610Salfred{ 261184610Salfred uint16_t length; 262184610Salfred usb2_error_t err; 263184610Salfred 264184610Salfred if (usb2_config_td_is_gone(&sc->sc_config_td)) { 265184610Salfred goto error; 266184610Salfred } 267184610Salfred err = usb2_do_request_flags 268184610Salfred (sc->sc_udev, &sc->sc_mtx, req, data, 0, NULL, 1000); 269184610Salfred 270184610Salfred if (err) { 271184610Salfred 272184610Salfred DPRINTF("device request failed, err=%s " 273184610Salfred "(ignored)\n", usb2_errstr(err)); 274184610Salfred 275184610Salfrederror: 276184610Salfred length = UGETW(req->wLength); 277184610Salfred 278184610Salfred if ((req->bmRequestType & UT_READ) && length) { 279184610Salfred bzero(data, length); 280184610Salfred } 281184610Salfred } 282184610Salfred} 283184610Salfred 284184610Salfred#define RUE_CFG_SETBIT(sc, reg, x) \ 285184610Salfred rue_cfg_csr_write_1(sc, reg, rue_cfg_csr_read_1(sc, reg) | (x)) 286184610Salfred 287184610Salfred#define RUE_CFG_CLRBIT(sc, reg, x) \ 288184610Salfred rue_cfg_csr_write_1(sc, reg, rue_cfg_csr_read_1(sc, reg) & ~(x)) 289184610Salfred 290184610Salfredstatic void 291184610Salfredrue_cfg_read_mem(struct rue_softc *sc, uint16_t addr, void *buf, 292184610Salfred uint16_t len) 293184610Salfred{ 294184610Salfred struct usb2_device_request req; 295184610Salfred 296184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 297184610Salfred req.bRequest = UR_SET_ADDRESS; 298184610Salfred USETW(req.wValue, addr); 299184610Salfred USETW(req.wIndex, 0); 300184610Salfred USETW(req.wLength, len); 301184610Salfred 302184610Salfred rue_cfg_do_request(sc, &req, buf); 303184610Salfred} 304184610Salfred 305184610Salfredstatic void 306184610Salfredrue_cfg_write_mem(struct rue_softc *sc, uint16_t addr, void *buf, 307184610Salfred uint16_t len) 308184610Salfred{ 309184610Salfred struct usb2_device_request req; 310184610Salfred 311184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 312184610Salfred req.bRequest = UR_SET_ADDRESS; 313184610Salfred USETW(req.wValue, addr); 314184610Salfred USETW(req.wIndex, 0); 315184610Salfred USETW(req.wLength, len); 316184610Salfred 317184610Salfred rue_cfg_do_request(sc, &req, buf); 318184610Salfred} 319184610Salfred 320184610Salfredstatic uint8_t 321184610Salfredrue_cfg_csr_read_1(struct rue_softc *sc, uint16_t reg) 322184610Salfred{ 323184610Salfred uint8_t val; 324184610Salfred 325184610Salfred rue_cfg_read_mem(sc, reg, &val, 1); 326184610Salfred return (val); 327184610Salfred} 328184610Salfred 329184610Salfredstatic uint16_t 330184610Salfredrue_cfg_csr_read_2(struct rue_softc *sc, uint16_t reg) 331184610Salfred{ 332184610Salfred uint8_t val[2]; 333184610Salfred 334184610Salfred rue_cfg_read_mem(sc, reg, &val, 2); 335184610Salfred return (UGETW(val)); 336184610Salfred} 337184610Salfred 338184610Salfredstatic void 339184610Salfredrue_cfg_csr_write_1(struct rue_softc *sc, uint16_t reg, uint8_t val) 340184610Salfred{ 341184610Salfred rue_cfg_write_mem(sc, reg, &val, 1); 342184610Salfred} 343184610Salfred 344184610Salfredstatic void 345184610Salfredrue_cfg_csr_write_2(struct rue_softc *sc, uint16_t reg, uint16_t val) 346184610Salfred{ 347184610Salfred uint8_t temp[2]; 348184610Salfred 349184610Salfred USETW(temp, val); 350184610Salfred rue_cfg_write_mem(sc, reg, &temp, 2); 351184610Salfred} 352184610Salfred 353184610Salfredstatic void 354184610Salfredrue_cfg_csr_write_4(struct rue_softc *sc, int reg, uint32_t val) 355184610Salfred{ 356184610Salfred uint8_t temp[4]; 357184610Salfred 358184610Salfred USETDW(temp, val); 359184610Salfred rue_cfg_write_mem(sc, reg, &temp, 4); 360184610Salfred} 361184610Salfred 362184610Salfredstatic int 363184610Salfredrue_cfg_miibus_readreg(device_t dev, int phy, int reg) 364184610Salfred{ 365184610Salfred struct rue_softc *sc = device_get_softc(dev); 366184610Salfred uint16_t rval; 367184610Salfred uint16_t ruereg; 368184610Salfred uint8_t do_unlock; 369184610Salfred 370184610Salfred if (phy != 0) { /* RTL8150 supports PHY == 0, only */ 371184610Salfred return (0); 372184610Salfred } 373184610Salfred /* avoid recursive locking */ 374184610Salfred if (mtx_owned(&sc->sc_mtx)) { 375184610Salfred do_unlock = 0; 376184610Salfred } else { 377184610Salfred mtx_lock(&sc->sc_mtx); 378184610Salfred do_unlock = 1; 379184610Salfred } 380184610Salfred 381184610Salfred switch (reg) { 382184610Salfred case MII_BMCR: 383184610Salfred ruereg = RUE_BMCR; 384184610Salfred break; 385184610Salfred case MII_BMSR: 386184610Salfred ruereg = RUE_BMSR; 387184610Salfred break; 388184610Salfred case MII_ANAR: 389184610Salfred ruereg = RUE_ANAR; 390184610Salfred break; 391184610Salfred case MII_ANER: 392184610Salfred ruereg = RUE_AER; 393184610Salfred break; 394184610Salfred case MII_ANLPAR: 395184610Salfred ruereg = RUE_ANLP; 396184610Salfred break; 397184610Salfred case MII_PHYIDR1: 398184610Salfred case MII_PHYIDR2: 399184610Salfred rval = 0; 400184610Salfred goto done; 401184610Salfred default: 402184610Salfred if ((RUE_REG_MIN <= reg) && (reg <= RUE_REG_MAX)) { 403184610Salfred rval = rue_cfg_csr_read_1(sc, reg); 404184610Salfred goto done; 405184610Salfred } 406184610Salfred printf("rue%d: bad phy register\n", sc->sc_unit); 407184610Salfred rval = 0; 408184610Salfred goto done; 409184610Salfred } 410184610Salfred 411184610Salfred rval = rue_cfg_csr_read_2(sc, ruereg); 412184610Salfreddone: 413184610Salfred if (do_unlock) { 414184610Salfred mtx_unlock(&sc->sc_mtx); 415184610Salfred } 416184610Salfred return (rval); 417184610Salfred} 418184610Salfred 419184610Salfredstatic int 420184610Salfredrue_cfg_miibus_writereg(device_t dev, int phy, int reg, int data) 421184610Salfred{ 422184610Salfred struct rue_softc *sc = device_get_softc(dev); 423184610Salfred uint16_t ruereg; 424184610Salfred uint8_t do_unlock; 425184610Salfred 426184610Salfred if (phy != 0) { /* RTL8150 supports PHY == 0, only */ 427184610Salfred return (0); 428184610Salfred } 429184610Salfred /* avoid recursive locking */ 430184610Salfred if (mtx_owned(&sc->sc_mtx)) { 431184610Salfred do_unlock = 0; 432184610Salfred } else { 433184610Salfred mtx_lock(&sc->sc_mtx); 434184610Salfred do_unlock = 1; 435184610Salfred } 436184610Salfred 437184610Salfred switch (reg) { 438184610Salfred case MII_BMCR: 439184610Salfred ruereg = RUE_BMCR; 440184610Salfred break; 441184610Salfred case MII_BMSR: 442184610Salfred ruereg = RUE_BMSR; 443184610Salfred break; 444184610Salfred case MII_ANAR: 445184610Salfred ruereg = RUE_ANAR; 446184610Salfred break; 447184610Salfred case MII_ANER: 448184610Salfred ruereg = RUE_AER; 449184610Salfred break; 450184610Salfred case MII_ANLPAR: 451184610Salfred ruereg = RUE_ANLP; 452184610Salfred break; 453184610Salfred case MII_PHYIDR1: 454184610Salfred case MII_PHYIDR2: 455184610Salfred goto done; 456184610Salfred default: 457184610Salfred if ((RUE_REG_MIN <= reg) && (reg <= RUE_REG_MAX)) { 458184610Salfred rue_cfg_csr_write_1(sc, reg, data); 459184610Salfred goto done; 460184610Salfred } 461184610Salfred printf("%s: bad phy register\n", 462184610Salfred sc->sc_name); 463184610Salfred goto done; 464184610Salfred } 465184610Salfred rue_cfg_csr_write_2(sc, ruereg, data); 466184610Salfreddone: 467184610Salfred if (do_unlock) { 468184610Salfred mtx_unlock(&sc->sc_mtx); 469184610Salfred } 470184610Salfred return (0); 471184610Salfred} 472184610Salfred 473184610Salfredstatic void 474184610Salfredrue_cfg_miibus_statchg(device_t dev) 475184610Salfred{ 476184610Salfred /* 477184610Salfred * When the code below is enabled the card starts doing weird 478184610Salfred * things after link going from UP to DOWN and back UP. 479184610Salfred * 480184610Salfred * Looks like some of register writes below messes up PHY 481184610Salfred * interface. 482184610Salfred * 483184610Salfred * No visible regressions were found after commenting this code 484184610Salfred * out, so that disable it for good. 485184610Salfred */ 486184610Salfred#if 0 487184610Salfred struct rue_softc *sc = device_get_softc(dev); 488184610Salfred struct mii_data *mii = GET_MII(sc); 489184610Salfred uint16_t bmcr; 490184610Salfred uint8_t do_unlock; 491184610Salfred 492184610Salfred /* avoid recursive locking */ 493184610Salfred if (mtx_owned(&sc->sc_mtx)) { 494184610Salfred do_unlock = 0; 495184610Salfred } else { 496184610Salfred mtx_lock(&sc->sc_mtx); 497184610Salfred do_unlock = 1; 498184610Salfred } 499184610Salfred 500184610Salfred RUE_CFG_CLRBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE)); 501184610Salfred 502184610Salfred bmcr = rue_cfg_csr_read_2(sc, RUE_BMCR); 503184610Salfred 504184610Salfred if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) 505184610Salfred bmcr |= RUE_BMCR_SPD_SET; 506184610Salfred else 507184610Salfred bmcr &= ~RUE_BMCR_SPD_SET; 508184610Salfred 509184610Salfred if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) 510184610Salfred bmcr |= RUE_BMCR_DUPLEX; 511184610Salfred else 512184610Salfred bmcr &= ~RUE_BMCR_DUPLEX; 513184610Salfred 514184610Salfred rue_cfg_csr_write_2(sc, RUE_BMCR, bmcr); 515184610Salfred 516184610Salfred RUE_CFG_SETBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE)); 517184610Salfred 518184610Salfred if (do_unlock) { 519184610Salfred mtx_unlock(&sc->sc_mtx); 520184610Salfred } 521184610Salfred#endif 522184610Salfred} 523184610Salfred 524184610Salfredstatic void 525184610Salfredrue_mchash(struct usb2_config_td_cc *cc, const uint8_t *ptr) 526184610Salfred{ 527184610Salfred uint8_t h; 528184610Salfred 529184610Salfred h = ether_crc32_be(ptr, ETHER_ADDR_LEN) >> 26; 530184610Salfred cc->if_hash[h / 8] |= 1 << (h & 7); 531184610Salfred cc->if_nhash = 1; 532184610Salfred} 533184610Salfred 534184610Salfredstatic void 535184610Salfredrue_config_copy(struct rue_softc *sc, 536184610Salfred struct usb2_config_td_cc *cc, uint16_t refcount) 537184610Salfred{ 538184610Salfred bzero(cc, sizeof(*cc)); 539184610Salfred usb2_ether_cc(sc->sc_ifp, &rue_mchash, cc); 540184610Salfred} 541184610Salfred 542184610Salfred/* 543184610Salfred * Program the 64-bit multicast hash filter. 544184610Salfred */ 545184610Salfredstatic void 546184610Salfredrue_cfg_promisc_upd(struct rue_softc *sc, 547184610Salfred struct usb2_config_td_cc *cc, uint16_t refcount) 548184610Salfred{ 549184610Salfred uint16_t rxcfg; 550184610Salfred 551184610Salfred rxcfg = rue_cfg_csr_read_2(sc, RUE_RCR); 552184610Salfred 553184610Salfred if ((cc->if_flags & IFF_ALLMULTI) || 554184610Salfred (cc->if_flags & IFF_PROMISC)) { 555184610Salfred rxcfg |= (RUE_RCR_AAM | RUE_RCR_AAP); 556184610Salfred rxcfg &= ~RUE_RCR_AM; 557184610Salfred rue_cfg_csr_write_2(sc, RUE_RCR, rxcfg); 558184610Salfred rue_cfg_csr_write_4(sc, RUE_MAR0, 0xFFFFFFFF); 559184610Salfred rue_cfg_csr_write_4(sc, RUE_MAR4, 0xFFFFFFFF); 560184610Salfred return; 561184610Salfred } 562184610Salfred /* first, zero all the existing hash bits */ 563184610Salfred rue_cfg_csr_write_4(sc, RUE_MAR0, 0); 564184610Salfred rue_cfg_csr_write_4(sc, RUE_MAR4, 0); 565184610Salfred 566184610Salfred if (cc->if_nhash) 567184610Salfred rxcfg |= RUE_RCR_AM; 568184610Salfred else 569184610Salfred rxcfg &= ~RUE_RCR_AM; 570184610Salfred 571184610Salfred rxcfg &= ~(RUE_RCR_AAM | RUE_RCR_AAP); 572184610Salfred 573184610Salfred rue_cfg_csr_write_2(sc, RUE_RCR, rxcfg); 574184610Salfred rue_cfg_write_mem(sc, RUE_MAR0, cc->if_hash, 4); 575184610Salfred rue_cfg_write_mem(sc, RUE_MAR4, cc->if_hash + 4, 4); 576184610Salfred} 577184610Salfred 578184610Salfredstatic void 579184610Salfredrue_cfg_reset(struct rue_softc *sc) 580184610Salfred{ 581184610Salfred usb2_error_t err; 582184610Salfred uint16_t to; 583184610Salfred 584184610Salfred rue_cfg_csr_write_1(sc, RUE_CR, RUE_CR_SOFT_RST); 585184610Salfred 586184610Salfred for (to = 0;; to++) { 587184610Salfred 588184610Salfred if (to < RUE_TIMEOUT) { 589184610Salfred 590184610Salfred err = usb2_config_td_sleep(&sc->sc_config_td, hz / 100); 591184610Salfred 592184610Salfred if (err) { 593184610Salfred break; 594184610Salfred } 595184610Salfred if (!(rue_cfg_csr_read_1(sc, RUE_CR) & RUE_CR_SOFT_RST)) { 596184610Salfred break; 597184610Salfred } 598184610Salfred } else { 599184610Salfred printf("%s: reset timeout!\n", 600184610Salfred sc->sc_name); 601184610Salfred break; 602184610Salfred } 603184610Salfred } 604184610Salfred 605184610Salfred err = usb2_config_td_sleep(&sc->sc_config_td, hz / 100); 606184610Salfred} 607184610Salfred 608184610Salfred/* 609184610Salfred * Probe for a RTL8150 chip. 610184610Salfred */ 611184610Salfredstatic int 612184610Salfredrue_probe(device_t dev) 613184610Salfred{ 614184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 615184610Salfred 616184610Salfred if (uaa->usb2_mode != USB_MODE_HOST) { 617184610Salfred return (ENXIO); 618184610Salfred } 619184610Salfred if (uaa->info.bConfigIndex != RUE_CONFIG_IDX) { 620184610Salfred return (ENXIO); 621184610Salfred } 622184610Salfred if (uaa->info.bIfaceIndex != RUE_IFACE_IDX) { 623184610Salfred return (ENXIO); 624184610Salfred } 625184610Salfred return (usb2_lookup_id_by_uaa(rue_devs, sizeof(rue_devs), uaa)); 626184610Salfred} 627184610Salfred 628184610Salfred/* 629184610Salfred * Attach the interface. Allocate softc structures, do ifmedia 630184610Salfred * setup and ethernet/BPF attach. 631184610Salfred */ 632184610Salfredstatic int 633184610Salfredrue_attach(device_t dev) 634184610Salfred{ 635184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 636184610Salfred struct rue_softc *sc = device_get_softc(dev); 637184610Salfred int32_t error; 638184610Salfred uint8_t iface_index; 639184610Salfred 640184610Salfred if (sc == NULL) { 641184610Salfred return (ENOMEM); 642184610Salfred } 643184610Salfred sc->sc_udev = uaa->device; 644184610Salfred sc->sc_dev = dev; 645184610Salfred sc->sc_unit = device_get_unit(dev); 646184610Salfred 647184610Salfred device_set_usb2_desc(dev); 648184610Salfred 649184610Salfred snprintf(sc->sc_name, sizeof(sc->sc_name), "%s", 650184610Salfred device_get_nameunit(dev)); 651184610Salfred 652184610Salfred mtx_init(&sc->sc_mtx, "rue lock", NULL, MTX_DEF | MTX_RECURSE); 653184610Salfred 654186454Sthompsa usb2_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0); 655184610Salfred 656184610Salfred iface_index = RUE_IFACE_IDX; 657184610Salfred error = usb2_transfer_setup(uaa->device, &iface_index, 658187259Sthompsa sc->sc_xfer, rue_config, RUE_N_TRANSFER, 659184610Salfred sc, &sc->sc_mtx); 660184610Salfred if (error) { 661184610Salfred device_printf(dev, "allocating USB " 662184610Salfred "transfers failed!\n"); 663184610Salfred goto detach; 664184610Salfred } 665184610Salfred error = usb2_config_td_setup(&sc->sc_config_td, sc, &sc->sc_mtx, 666184610Salfred NULL, sizeof(struct usb2_config_td_cc), 16); 667184610Salfred if (error) { 668184610Salfred device_printf(dev, "could not setup config " 669184610Salfred "thread!\n"); 670184610Salfred goto detach; 671184610Salfred } 672184610Salfred mtx_lock(&sc->sc_mtx); 673184610Salfred 674184610Salfred sc->sc_flags |= RUE_FLAG_WAIT_LINK; 675184610Salfred 676184610Salfred /* start setup */ 677184610Salfred 678184610Salfred usb2_config_td_queue_command 679184610Salfred (&sc->sc_config_td, NULL, &rue_cfg_first_time_setup, 0, 0); 680184610Salfred 681184610Salfred rue_watchdog(sc); 682186454Sthompsa mtx_unlock(&sc->sc_mtx); 683184610Salfred return (0); /* success */ 684184610Salfred 685184610Salfreddetach: 686184610Salfred rue_detach(dev); 687184610Salfred return (ENXIO); /* failure */ 688184610Salfred} 689184610Salfred 690184610Salfredstatic void 691184610Salfredrue_cfg_first_time_setup(struct rue_softc *sc, 692184610Salfred struct usb2_config_td_cc *cc, uint16_t refcount) 693184610Salfred{ 694184610Salfred struct ifnet *ifp; 695184610Salfred int error; 696184610Salfred uint8_t eaddr[min(ETHER_ADDR_LEN, 6)]; 697184610Salfred 698184610Salfred /* reset the adapter */ 699184610Salfred rue_cfg_reset(sc); 700184610Salfred 701184610Salfred /* get station address from the EEPROM */ 702184610Salfred rue_cfg_read_mem(sc, RUE_EEPROM_IDR0, 703184610Salfred eaddr, ETHER_ADDR_LEN); 704184610Salfred 705184610Salfred mtx_unlock(&sc->sc_mtx); 706184610Salfred 707184610Salfred ifp = if_alloc(IFT_ETHER); 708184610Salfred 709184610Salfred mtx_lock(&sc->sc_mtx); 710184610Salfred 711184610Salfred if (ifp == NULL) { 712184610Salfred printf("%s: could not if_alloc()\n", 713184610Salfred sc->sc_name); 714184610Salfred goto done; 715184610Salfred } 716184610Salfred sc->sc_evilhack = ifp; 717184610Salfred 718184610Salfred ifp->if_softc = sc; 719184610Salfred if_initname(ifp, "rue", sc->sc_unit); 720184610Salfred ifp->if_mtu = ETHERMTU; 721184610Salfred ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 722184610Salfred ifp->if_ioctl = rue_ioctl_cb; 723184610Salfred ifp->if_start = rue_start_cb; 724184610Salfred ifp->if_watchdog = NULL; 725184610Salfred ifp->if_init = rue_init_cb; 726184610Salfred IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 727184610Salfred ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 728184610Salfred IFQ_SET_READY(&ifp->if_snd); 729184610Salfred 730184610Salfred /* 731184610Salfred * XXX need Giant when accessing the device structures ! 732184610Salfred */ 733184610Salfred 734184610Salfred mtx_unlock(&sc->sc_mtx); 735184610Salfred 736184610Salfred mtx_lock(&Giant); 737184610Salfred 738184610Salfred /* MII setup */ 739184610Salfred error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, 740184610Salfred &rue_ifmedia_upd_cb, 741184610Salfred &rue_ifmedia_sts_cb); 742184610Salfred mtx_unlock(&Giant); 743184610Salfred 744184610Salfred mtx_lock(&sc->sc_mtx); 745184610Salfred 746184610Salfred if (error) { 747184610Salfred printf("%s: MII without any PHY!\n", 748184610Salfred sc->sc_name); 749184610Salfred if_free(ifp); 750184610Salfred goto done; 751184610Salfred } 752184610Salfred sc->sc_ifp = ifp; 753184610Salfred 754184610Salfred mtx_unlock(&sc->sc_mtx); 755184610Salfred 756184610Salfred /* 757184610Salfred * Call MI attach routine. 758184610Salfred */ 759184610Salfred 760184610Salfred ether_ifattach(ifp, eaddr); 761184610Salfred 762184610Salfred mtx_lock(&sc->sc_mtx); 763184610Salfred 764184610Salfreddone: 765184610Salfred return; 766184610Salfred} 767184610Salfred 768184610Salfredstatic int 769184610Salfredrue_detach(device_t dev) 770184610Salfred{ 771184610Salfred struct rue_softc *sc = device_get_softc(dev); 772184610Salfred struct ifnet *ifp; 773184610Salfred 774184610Salfred usb2_config_td_drain(&sc->sc_config_td); 775184610Salfred 776184610Salfred mtx_lock(&sc->sc_mtx); 777184610Salfred 778184610Salfred usb2_callout_stop(&sc->sc_watchdog); 779184610Salfred 780184610Salfred rue_cfg_pre_stop(sc, NULL, 0); 781184610Salfred 782184610Salfred ifp = sc->sc_ifp; 783184610Salfred 784184610Salfred mtx_unlock(&sc->sc_mtx); 785184610Salfred 786184610Salfred /* stop all USB transfers first */ 787187259Sthompsa usb2_transfer_unsetup(sc->sc_xfer, RUE_N_TRANSFER); 788184610Salfred 789184610Salfred /* get rid of any late children */ 790184610Salfred bus_generic_detach(dev); 791184610Salfred 792184610Salfred if (ifp) { 793184610Salfred ether_ifdetach(ifp); 794184610Salfred if_free(ifp); 795184610Salfred } 796184610Salfred usb2_config_td_unsetup(&sc->sc_config_td); 797184610Salfred 798184610Salfred usb2_callout_drain(&sc->sc_watchdog); 799184610Salfred 800184610Salfred mtx_destroy(&sc->sc_mtx); 801184610Salfred 802184610Salfred return (0); 803184610Salfred} 804184610Salfred 805184610Salfredstatic void 806184610Salfredrue_intr_clear_stall_callback(struct usb2_xfer *xfer) 807184610Salfred{ 808184610Salfred struct rue_softc *sc = xfer->priv_sc; 809187259Sthompsa struct usb2_xfer *xfer_other = sc->sc_xfer[RUE_INTR_DT_RD]; 810184610Salfred 811184610Salfred if (usb2_clear_stall_callback(xfer, xfer_other)) { 812184610Salfred DPRINTF("stall cleared\n"); 813184610Salfred sc->sc_flags &= ~RUE_FLAG_INTR_STALL; 814184610Salfred usb2_transfer_start(xfer_other); 815184610Salfred } 816184610Salfred} 817184610Salfred 818184610Salfredstatic void 819184610Salfredrue_intr_callback(struct usb2_xfer *xfer) 820184610Salfred{ 821184610Salfred struct rue_softc *sc = xfer->priv_sc; 822184610Salfred struct ifnet *ifp = sc->sc_ifp; 823184610Salfred struct rue_intrpkt pkt; 824184610Salfred 825184610Salfred switch (USB_GET_STATE(xfer)) { 826184610Salfred case USB_ST_TRANSFERRED: 827184610Salfred 828184610Salfred if (ifp && (ifp->if_drv_flags & IFF_DRV_RUNNING) && 829184610Salfred (xfer->actlen >= sizeof(pkt))) { 830184610Salfred 831184610Salfred usb2_copy_out(xfer->frbuffers, 0, &pkt, sizeof(pkt)); 832184610Salfred 833184610Salfred ifp->if_ierrors += pkt.rue_rxlost_cnt; 834184610Salfred ifp->if_ierrors += pkt.rue_crcerr_cnt; 835184610Salfred ifp->if_collisions += pkt.rue_col_cnt; 836184610Salfred } 837184610Salfred case USB_ST_SETUP: 838184610Salfred if (sc->sc_flags & RUE_FLAG_INTR_STALL) { 839187259Sthompsa usb2_transfer_start(sc->sc_xfer[RUE_INTR_CS_RD]); 840184610Salfred } else { 841184610Salfred xfer->frlengths[0] = xfer->max_data_length; 842184610Salfred usb2_start_hardware(xfer); 843184610Salfred } 844184610Salfred return; 845184610Salfred 846184610Salfred default: /* Error */ 847184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 848184610Salfred /* start clear stall */ 849184610Salfred sc->sc_flags |= RUE_FLAG_INTR_STALL; 850187259Sthompsa usb2_transfer_start(sc->sc_xfer[RUE_INTR_CS_RD]); 851184610Salfred } 852184610Salfred return; 853184610Salfred } 854184610Salfred} 855184610Salfred 856184610Salfredstatic void 857184610Salfredrue_bulk_read_clear_stall_callback(struct usb2_xfer *xfer) 858184610Salfred{ 859184610Salfred struct rue_softc *sc = xfer->priv_sc; 860187259Sthompsa struct usb2_xfer *xfer_other = sc->sc_xfer[RUE_BULK_DT_RD]; 861184610Salfred 862184610Salfred if (usb2_clear_stall_callback(xfer, xfer_other)) { 863184610Salfred DPRINTF("stall cleared\n"); 864184610Salfred sc->sc_flags &= ~RUE_FLAG_READ_STALL; 865184610Salfred usb2_transfer_start(xfer_other); 866184610Salfred } 867184610Salfred} 868184610Salfred 869184610Salfredstatic void 870184610Salfredrue_bulk_read_callback(struct usb2_xfer *xfer) 871184610Salfred{ 872184610Salfred struct rue_softc *sc = xfer->priv_sc; 873184610Salfred struct ifnet *ifp = sc->sc_ifp; 874184610Salfred uint16_t status; 875184610Salfred struct mbuf *m = NULL; 876184610Salfred 877184610Salfred switch (USB_GET_STATE(xfer)) { 878184610Salfred case USB_ST_TRANSFERRED: 879184610Salfred 880184610Salfred if (xfer->actlen < 4) { 881184610Salfred ifp->if_ierrors++; 882184610Salfred goto tr_setup; 883184610Salfred } 884184610Salfred usb2_copy_out(xfer->frbuffers, xfer->actlen - 4, 885184610Salfred &status, sizeof(status)); 886184610Salfred 887184610Salfred status = le16toh(status); 888184610Salfred 889184610Salfred /* check recieve packet was valid or not */ 890184610Salfred 891184610Salfred if ((status & RUE_RXSTAT_VALID) == 0) { 892184610Salfred ifp->if_ierrors++; 893184610Salfred goto tr_setup; 894184610Salfred } 895184610Salfred xfer->actlen -= 4; 896184610Salfred 897184610Salfred if (xfer->actlen < sizeof(struct ether_header)) { 898184610Salfred ifp->if_ierrors++; 899184610Salfred goto tr_setup; 900184610Salfred } 901184610Salfred m = usb2_ether_get_mbuf(); 902184610Salfred 903184610Salfred if (m == NULL) { 904184610Salfred ifp->if_ierrors++; 905184610Salfred goto tr_setup; 906184610Salfred } 907184610Salfred xfer->actlen = min(xfer->actlen, m->m_len); 908184610Salfred 909184610Salfred usb2_copy_out(xfer->frbuffers, 0, m->m_data, xfer->actlen); 910184610Salfred 911184610Salfred ifp->if_ipackets++; 912184610Salfred m->m_pkthdr.rcvif = ifp; 913184610Salfred m->m_pkthdr.len = m->m_len = xfer->actlen; 914184610Salfred 915184610Salfred case USB_ST_SETUP: 916184610Salfredtr_setup: 917184610Salfred 918184610Salfred if (sc->sc_flags & RUE_FLAG_READ_STALL) { 919187259Sthompsa usb2_transfer_start(sc->sc_xfer[RUE_BULK_CS_RD]); 920184610Salfred } else { 921184610Salfred xfer->frlengths[0] = xfer->max_data_length; 922184610Salfred usb2_start_hardware(xfer); 923184610Salfred } 924184610Salfred 925184610Salfred /* 926184610Salfred * At the end of a USB callback it is always safe to unlock 927184610Salfred * the private mutex of a device! That is why we do the 928184610Salfred * "if_input" here, and not some lines up! 929184610Salfred */ 930184610Salfred if (m) { 931184610Salfred mtx_unlock(&sc->sc_mtx); 932184610Salfred (ifp->if_input) (ifp, m); 933184610Salfred mtx_lock(&sc->sc_mtx); 934184610Salfred } 935184610Salfred return; 936184610Salfred 937184610Salfred default: /* Error */ 938184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 939184610Salfred /* try to clear stall first */ 940184610Salfred sc->sc_flags |= RUE_FLAG_READ_STALL; 941187259Sthompsa usb2_transfer_start(sc->sc_xfer[RUE_BULK_CS_RD]); 942184610Salfred } 943184610Salfred DPRINTF("bulk read error, %s\n", 944184610Salfred usb2_errstr(xfer->error)); 945184610Salfred return; 946184610Salfred 947184610Salfred } 948184610Salfred} 949184610Salfred 950184610Salfredstatic void 951184610Salfredrue_bulk_write_clear_stall_callback(struct usb2_xfer *xfer) 952184610Salfred{ 953184610Salfred struct rue_softc *sc = xfer->priv_sc; 954187259Sthompsa struct usb2_xfer *xfer_other = sc->sc_xfer[RUE_BULK_DT_WR]; 955184610Salfred 956184610Salfred if (usb2_clear_stall_callback(xfer, xfer_other)) { 957184610Salfred DPRINTF("stall cleared\n"); 958184610Salfred sc->sc_flags &= ~RUE_FLAG_WRITE_STALL; 959184610Salfred usb2_transfer_start(xfer_other); 960184610Salfred } 961184610Salfred} 962184610Salfred 963184610Salfredstatic void 964184610Salfredrue_bulk_write_callback(struct usb2_xfer *xfer) 965184610Salfred{ 966184610Salfred struct rue_softc *sc = xfer->priv_sc; 967184610Salfred struct ifnet *ifp = sc->sc_ifp; 968184610Salfred struct mbuf *m; 969184610Salfred uint32_t temp_len; 970184610Salfred 971184610Salfred switch (USB_GET_STATE(xfer)) { 972184610Salfred case USB_ST_TRANSFERRED: 973184610Salfred DPRINTFN(11, "transfer complete\n"); 974184610Salfred 975184610Salfred ifp->if_opackets++; 976184610Salfred 977184610Salfred case USB_ST_SETUP: 978184610Salfred 979184610Salfred if (sc->sc_flags & RUE_FLAG_WRITE_STALL) { 980187259Sthompsa usb2_transfer_start(sc->sc_xfer[RUE_BULK_CS_WR]); 981184610Salfred goto done; 982184610Salfred } 983184610Salfred if (sc->sc_flags & RUE_FLAG_WAIT_LINK) { 984184610Salfred /* 985184610Salfred * don't send anything if there is no link ! 986184610Salfred */ 987184610Salfred goto done; 988184610Salfred } 989184610Salfred IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 990184610Salfred 991184610Salfred if (m == NULL) { 992184610Salfred goto done; 993184610Salfred } 994184610Salfred if (m->m_pkthdr.len > MCLBYTES) { 995184610Salfred m->m_pkthdr.len = MCLBYTES; 996184610Salfred } 997184610Salfred temp_len = m->m_pkthdr.len; 998184610Salfred 999184610Salfred usb2_m_copy_in(xfer->frbuffers, 0, 1000184610Salfred m, 0, m->m_pkthdr.len); 1001184610Salfred 1002184610Salfred /* 1003184610Salfred * This is an undocumented behavior. 1004184610Salfred * RTL8150 chip doesn't send frame length smaller than 1005184610Salfred * RUE_MIN_FRAMELEN (60) byte packet. 1006184610Salfred */ 1007184610Salfred if (temp_len < RUE_MIN_FRAMELEN) { 1008184610Salfred usb2_bzero(xfer->frbuffers, temp_len, 1009184610Salfred RUE_MIN_FRAMELEN - temp_len); 1010184610Salfred temp_len = RUE_MIN_FRAMELEN; 1011184610Salfred } 1012184610Salfred xfer->frlengths[0] = temp_len; 1013184610Salfred 1014184610Salfred /* 1015184610Salfred * if there's a BPF listener, bounce a copy 1016184610Salfred * of this frame to him: 1017184610Salfred */ 1018184610Salfred BPF_MTAP(ifp, m); 1019184610Salfred 1020184610Salfred m_freem(m); 1021184610Salfred 1022184610Salfred usb2_start_hardware(xfer); 1023184610Salfred 1024184610Salfreddone: 1025184610Salfred return; 1026184610Salfred 1027184610Salfred default: /* Error */ 1028184610Salfred DPRINTFN(11, "transfer error, %s\n", 1029184610Salfred usb2_errstr(xfer->error)); 1030184610Salfred 1031184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 1032184610Salfred /* try to clear stall first */ 1033184610Salfred sc->sc_flags |= RUE_FLAG_WRITE_STALL; 1034187259Sthompsa usb2_transfer_start(sc->sc_xfer[RUE_BULK_CS_WR]); 1035184610Salfred } 1036184610Salfred ifp->if_oerrors++; 1037184610Salfred return; 1038184610Salfred 1039184610Salfred } 1040184610Salfred} 1041184610Salfred 1042184610Salfredstatic void 1043184610Salfredrue_cfg_tick(struct rue_softc *sc, 1044184610Salfred struct usb2_config_td_cc *cc, uint16_t refcount) 1045184610Salfred{ 1046184610Salfred struct ifnet *ifp = sc->sc_ifp; 1047184610Salfred struct mii_data *mii = GET_MII(sc); 1048184610Salfred 1049184610Salfred if ((ifp == NULL) || 1050184610Salfred (mii == NULL)) { 1051184610Salfred /* not ready */ 1052184610Salfred return; 1053184610Salfred } 1054184610Salfred mii_tick(mii); 1055184610Salfred 1056184610Salfred mii_pollstat(mii); 1057184610Salfred 1058184610Salfred if ((sc->sc_flags & RUE_FLAG_WAIT_LINK) && 1059184610Salfred (mii->mii_media_status & IFM_ACTIVE) && 1060184610Salfred (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)) { 1061184610Salfred sc->sc_flags &= ~RUE_FLAG_WAIT_LINK; 1062184610Salfred } 1063184610Salfred sc->sc_media_active = mii->mii_media_active; 1064184610Salfred sc->sc_media_status = mii->mii_media_status; 1065184610Salfred 1066184610Salfred /* start stopped transfers, if any */ 1067184610Salfred 1068184610Salfred rue_start_transfers(sc); 1069184610Salfred} 1070184610Salfred 1071184610Salfredstatic void 1072184610Salfredrue_start_cb(struct ifnet *ifp) 1073184610Salfred{ 1074184610Salfred struct rue_softc *sc = ifp->if_softc; 1075184610Salfred 1076184610Salfred mtx_lock(&sc->sc_mtx); 1077184610Salfred 1078184610Salfred rue_start_transfers(sc); 1079184610Salfred 1080184610Salfred mtx_unlock(&sc->sc_mtx); 1081184610Salfred} 1082184610Salfred 1083184610Salfredstatic void 1084184610Salfredrue_start_transfers(struct rue_softc *sc) 1085184610Salfred{ 1086184610Salfred if ((sc->sc_flags & RUE_FLAG_LL_READY) && 1087184610Salfred (sc->sc_flags & RUE_FLAG_HL_READY)) { 1088184610Salfred 1089184610Salfred /* 1090184610Salfred * start the USB transfers, if not already started: 1091184610Salfred */ 1092187259Sthompsa usb2_transfer_start(sc->sc_xfer[RUE_INTR_DT_RD]); 1093187259Sthompsa usb2_transfer_start(sc->sc_xfer[RUE_BULK_DT_RD]); 1094187259Sthompsa usb2_transfer_start(sc->sc_xfer[RUE_BULK_DT_WR]); 1095184610Salfred } 1096184610Salfred} 1097184610Salfred 1098184610Salfredstatic void 1099184610Salfredrue_init_cb(void *arg) 1100184610Salfred{ 1101184610Salfred struct rue_softc *sc = arg; 1102184610Salfred 1103184610Salfred mtx_lock(&sc->sc_mtx); 1104184610Salfred usb2_config_td_queue_command 1105184610Salfred (&sc->sc_config_td, &rue_cfg_pre_init, 1106184610Salfred &rue_cfg_init, 0, 0); 1107184610Salfred mtx_unlock(&sc->sc_mtx); 1108184610Salfred} 1109184610Salfred 1110184610Salfredstatic void 1111184610Salfredrue_cfg_pre_init(struct rue_softc *sc, 1112184610Salfred struct usb2_config_td_cc *cc, uint16_t refcount) 1113184610Salfred{ 1114184610Salfred struct ifnet *ifp = sc->sc_ifp; 1115184610Salfred 1116184610Salfred /* immediate configuration */ 1117184610Salfred 1118184610Salfred rue_cfg_pre_stop(sc, cc, 0); 1119184610Salfred 1120184610Salfred ifp->if_drv_flags |= IFF_DRV_RUNNING; 1121184610Salfred 1122184610Salfred sc->sc_flags |= RUE_FLAG_HL_READY; 1123184610Salfred} 1124184610Salfred 1125184610Salfredstatic void 1126184610Salfredrue_cfg_init(struct rue_softc *sc, 1127184610Salfred struct usb2_config_td_cc *cc, uint16_t refcount) 1128184610Salfred{ 1129184610Salfred struct mii_data *mii = GET_MII(sc); 1130184610Salfred uint16_t rxcfg; 1131184610Salfred 1132184610Salfred /* 1133184610Salfred * Cancel pending I/O 1134184610Salfred */ 1135184610Salfred 1136184610Salfred rue_cfg_stop(sc, cc, 0); 1137184610Salfred 1138184610Salfred /* set MAC address */ 1139184610Salfred 1140184610Salfred rue_cfg_write_mem(sc, RUE_IDR0, cc->if_lladdr, ETHER_ADDR_LEN); 1141184610Salfred 1142184610Salfred /* 1143184610Salfred * Set the initial TX and RX configuration. 1144184610Salfred */ 1145184610Salfred rue_cfg_csr_write_1(sc, RUE_TCR, RUE_TCR_CONFIG); 1146184610Salfred 1147184610Salfred rxcfg = RUE_RCR_CONFIG; 1148184610Salfred 1149184610Salfred /* Set capture broadcast bit to capture broadcast frames. */ 1150184610Salfred if (cc->if_flags & IFF_BROADCAST) 1151184610Salfred rxcfg |= RUE_RCR_AB; 1152184610Salfred else 1153184610Salfred rxcfg &= ~RUE_RCR_AB; 1154184610Salfred 1155184610Salfred rue_cfg_csr_write_2(sc, RUE_RCR, rxcfg); 1156184610Salfred 1157184610Salfred /* Load the multicast filter */ 1158184610Salfred rue_cfg_promisc_upd(sc, cc, 0); 1159184610Salfred 1160184610Salfred /* Enable RX and TX */ 1161184610Salfred rue_cfg_csr_write_1(sc, RUE_CR, (RUE_CR_TE | RUE_CR_RE | RUE_CR_EP3CLREN)); 1162184610Salfred 1163184610Salfred mii_mediachg(mii); 1164184610Salfred 1165184610Salfred sc->sc_flags |= (RUE_FLAG_READ_STALL | 1166184610Salfred RUE_FLAG_WRITE_STALL | 1167184610Salfred RUE_FLAG_LL_READY); 1168184610Salfred 1169184610Salfred rue_start_transfers(sc); 1170184610Salfred} 1171184610Salfred 1172184610Salfred/* 1173184610Salfred * Set media options. 1174184610Salfred */ 1175184610Salfredstatic int 1176184610Salfredrue_ifmedia_upd_cb(struct ifnet *ifp) 1177184610Salfred{ 1178184610Salfred struct rue_softc *sc = ifp->if_softc; 1179184610Salfred 1180184610Salfred mtx_lock(&sc->sc_mtx); 1181184610Salfred usb2_config_td_queue_command 1182184610Salfred (&sc->sc_config_td, NULL, 1183184610Salfred &rue_cfg_ifmedia_upd, 0, 0); 1184184610Salfred mtx_unlock(&sc->sc_mtx); 1185184610Salfred 1186184610Salfred return (0); 1187184610Salfred} 1188184610Salfred 1189184610Salfredstatic void 1190184610Salfredrue_cfg_ifmedia_upd(struct rue_softc *sc, 1191184610Salfred struct usb2_config_td_cc *cc, uint16_t refcount) 1192184610Salfred{ 1193184610Salfred struct ifnet *ifp = sc->sc_ifp; 1194184610Salfred struct mii_data *mii = GET_MII(sc); 1195184610Salfred 1196184610Salfred if ((ifp == NULL) || 1197184610Salfred (mii == NULL)) { 1198184610Salfred /* not ready */ 1199184610Salfred return; 1200184610Salfred } 1201184610Salfred sc->sc_flags |= RUE_FLAG_WAIT_LINK; 1202184610Salfred 1203184610Salfred if (mii->mii_instance) { 1204184610Salfred struct mii_softc *miisc; 1205184610Salfred 1206184610Salfred LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { 1207184610Salfred mii_phy_reset(miisc); 1208184610Salfred } 1209184610Salfred } 1210184610Salfred mii_mediachg(mii); 1211184610Salfred} 1212184610Salfred 1213184610Salfred/* 1214184610Salfred * Report current media status. 1215184610Salfred */ 1216184610Salfredstatic void 1217184610Salfredrue_ifmedia_sts_cb(struct ifnet *ifp, struct ifmediareq *ifmr) 1218184610Salfred{ 1219184610Salfred struct rue_softc *sc = ifp->if_softc; 1220184610Salfred 1221184610Salfred mtx_lock(&sc->sc_mtx); 1222184610Salfred 1223184610Salfred ifmr->ifm_active = sc->sc_media_active; 1224184610Salfred ifmr->ifm_status = sc->sc_media_status; 1225184610Salfred 1226184610Salfred mtx_unlock(&sc->sc_mtx); 1227184610Salfred} 1228184610Salfred 1229184610Salfredstatic int 1230184610Salfredrue_ioctl_cb(struct ifnet *ifp, u_long command, caddr_t data) 1231184610Salfred{ 1232184610Salfred struct rue_softc *sc = ifp->if_softc; 1233184610Salfred struct mii_data *mii; 1234184610Salfred int error = 0; 1235184610Salfred 1236184610Salfred switch (command) { 1237184610Salfred case SIOCSIFFLAGS: 1238184610Salfred 1239184610Salfred mtx_lock(&sc->sc_mtx); 1240184610Salfred if (ifp->if_flags & IFF_UP) { 1241184610Salfred if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1242184610Salfred usb2_config_td_queue_command 1243184610Salfred (&sc->sc_config_td, &rue_config_copy, 1244184610Salfred &rue_cfg_promisc_upd, 0, 0); 1245184610Salfred } else { 1246184610Salfred usb2_config_td_queue_command 1247184610Salfred (&sc->sc_config_td, &rue_cfg_pre_init, 1248184610Salfred &rue_cfg_init, 0, 0); 1249184610Salfred } 1250184610Salfred } else { 1251184610Salfred if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1252184610Salfred usb2_config_td_queue_command 1253184610Salfred (&sc->sc_config_td, &rue_cfg_pre_stop, 1254184610Salfred &rue_cfg_stop, 0, 0); 1255184610Salfred } 1256184610Salfred } 1257184610Salfred mtx_unlock(&sc->sc_mtx); 1258184610Salfred break; 1259184610Salfred 1260184610Salfred case SIOCADDMULTI: 1261184610Salfred case SIOCDELMULTI: 1262184610Salfred mtx_lock(&sc->sc_mtx); 1263184610Salfred usb2_config_td_queue_command 1264184610Salfred (&sc->sc_config_td, &rue_config_copy, 1265184610Salfred &rue_cfg_promisc_upd, 0, 0); 1266184610Salfred mtx_unlock(&sc->sc_mtx); 1267184610Salfred break; 1268184610Salfred 1269184610Salfred case SIOCGIFMEDIA: 1270184610Salfred case SIOCSIFMEDIA: 1271184610Salfred mii = GET_MII(sc); 1272184610Salfred if (mii == NULL) { 1273184610Salfred error = EINVAL; 1274184610Salfred } else { 1275184610Salfred error = ifmedia_ioctl 1276184610Salfred (ifp, (void *)data, &mii->mii_media, command); 1277184610Salfred } 1278184610Salfred break; 1279184610Salfred 1280184610Salfred default: 1281184610Salfred error = ether_ioctl(ifp, command, data); 1282184610Salfred break; 1283184610Salfred } 1284184610Salfred return (error); 1285184610Salfred} 1286184610Salfred 1287184610Salfredstatic void 1288184610Salfredrue_watchdog(void *arg) 1289184610Salfred{ 1290184610Salfred struct rue_softc *sc = arg; 1291184610Salfred 1292184610Salfred mtx_assert(&sc->sc_mtx, MA_OWNED); 1293184610Salfred 1294184610Salfred usb2_config_td_queue_command 1295184610Salfred (&sc->sc_config_td, NULL, &rue_cfg_tick, 0, 0); 1296184610Salfred 1297184610Salfred usb2_callout_reset(&sc->sc_watchdog, 1298184610Salfred hz, &rue_watchdog, sc); 1299184610Salfred} 1300184610Salfred 1301184610Salfred/* 1302184610Salfred * NOTE: can be called when "ifp" is NULL 1303184610Salfred */ 1304184610Salfredstatic void 1305184610Salfredrue_cfg_pre_stop(struct rue_softc *sc, 1306184610Salfred struct usb2_config_td_cc *cc, uint16_t refcount) 1307184610Salfred{ 1308184610Salfred struct ifnet *ifp = sc->sc_ifp; 1309184610Salfred 1310184610Salfred if (cc) { 1311184610Salfred /* copy the needed configuration */ 1312184610Salfred rue_config_copy(sc, cc, refcount); 1313184610Salfred } 1314184610Salfred /* immediate configuration */ 1315184610Salfred 1316184610Salfred if (ifp) { 1317184610Salfred /* clear flags */ 1318184610Salfred ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1319184610Salfred } 1320184610Salfred sc->sc_flags &= ~(RUE_FLAG_HL_READY | 1321184610Salfred RUE_FLAG_LL_READY); 1322184610Salfred 1323184610Salfred sc->sc_flags |= RUE_FLAG_WAIT_LINK; 1324184610Salfred 1325184610Salfred /* 1326184610Salfred * stop all the transfers, if not already stopped: 1327184610Salfred */ 1328187259Sthompsa usb2_transfer_stop(sc->sc_xfer[RUE_BULK_DT_WR]); 1329187259Sthompsa usb2_transfer_stop(sc->sc_xfer[RUE_BULK_DT_RD]); 1330187259Sthompsa usb2_transfer_stop(sc->sc_xfer[RUE_BULK_CS_WR]); 1331187259Sthompsa usb2_transfer_stop(sc->sc_xfer[RUE_BULK_CS_RD]); 1332187259Sthompsa usb2_transfer_stop(sc->sc_xfer[RUE_INTR_DT_RD]); 1333187259Sthompsa usb2_transfer_stop(sc->sc_xfer[RUE_INTR_CS_RD]); 1334184610Salfred} 1335184610Salfred 1336184610Salfredstatic void 1337184610Salfredrue_cfg_stop(struct rue_softc *sc, 1338184610Salfred struct usb2_config_td_cc *cc, uint16_t refcount) 1339184610Salfred{ 1340184610Salfred rue_cfg_csr_write_1(sc, RUE_CR, 0x00); 1341184610Salfred 1342184610Salfred rue_cfg_reset(sc); 1343184610Salfred} 1344184610Salfred 1345184610Salfred/* 1346184610Salfred * Stop all chip I/O so that the kernel's probe routines don't 1347184610Salfred * get confused by errant DMAs when rebooting. 1348184610Salfred */ 1349184610Salfredstatic int 1350184610Salfredrue_shutdown(device_t dev) 1351184610Salfred{ 1352184610Salfred struct rue_softc *sc = device_get_softc(dev); 1353184610Salfred 1354184610Salfred mtx_lock(&sc->sc_mtx); 1355184610Salfred 1356184610Salfred usb2_config_td_queue_command 1357184610Salfred (&sc->sc_config_td, &rue_cfg_pre_stop, 1358184610Salfred &rue_cfg_stop, 0, 0); 1359184610Salfred 1360184610Salfred mtx_unlock(&sc->sc_mtx); 1361184610Salfred 1362184610Salfred return (0); 1363184610Salfred} 1364