1291557Skevlo/*- 2291557Skevlo * Copyright (c) 2015 Kevin Lo <kevlo@FreeBSD.org> 3291557Skevlo * All rights reserved. 4291557Skevlo * 5291557Skevlo * Redistribution and use in source and binary forms, with or without 6291557Skevlo * modification, are permitted provided that the following conditions 7291557Skevlo * are met: 8291557Skevlo * 1. Redistributions of source code must retain the above copyright 9291557Skevlo * notice, this list of conditions and the following disclaimer. 10291557Skevlo * 2. Redistributions in binary form must reproduce the above copyright 11291557Skevlo * notice, this list of conditions and the following disclaimer in the 12291557Skevlo * documentation and/or other materials provided with the distribution. 13291557Skevlo * 14291557Skevlo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15291557Skevlo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16291557Skevlo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17291557Skevlo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18291557Skevlo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19291557Skevlo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20291557Skevlo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21291557Skevlo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22291557Skevlo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23291557Skevlo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24291557Skevlo * SUCH DAMAGE. 25291557Skevlo */ 26291557Skevlo 27291557Skevlo#include <sys/cdefs.h> 28291557Skevlo__FBSDID("$FreeBSD: stable/11/sys/dev/usb/net/if_ure.c 365738 2020-09-15 00:22:30Z jmg $"); 29291557Skevlo 30291557Skevlo#include <sys/param.h> 31291557Skevlo#include <sys/systm.h> 32291557Skevlo#include <sys/bus.h> 33291557Skevlo#include <sys/condvar.h> 34291557Skevlo#include <sys/kernel.h> 35291557Skevlo#include <sys/lock.h> 36291557Skevlo#include <sys/module.h> 37291557Skevlo#include <sys/mutex.h> 38291557Skevlo#include <sys/socket.h> 39291557Skevlo#include <sys/sysctl.h> 40291557Skevlo#include <sys/unistd.h> 41291557Skevlo 42291557Skevlo#include <net/if.h> 43291557Skevlo#include <net/if_var.h> 44291557Skevlo 45291557Skevlo#include <dev/usb/usb.h> 46291557Skevlo#include <dev/usb/usbdi.h> 47291557Skevlo#include <dev/usb/usbdi_util.h> 48291557Skevlo#include "usbdevs.h" 49291557Skevlo 50291557Skevlo#define USB_DEBUG_VAR ure_debug 51291557Skevlo#include <dev/usb/usb_debug.h> 52291557Skevlo#include <dev/usb/usb_process.h> 53291557Skevlo 54291557Skevlo#include <dev/usb/net/usb_ethernet.h> 55291557Skevlo#include <dev/usb/net/if_urereg.h> 56291557Skevlo 57291557Skevlo#ifdef USB_DEBUG 58291557Skevlostatic int ure_debug = 0; 59291557Skevlo 60291557Skevlostatic SYSCTL_NODE(_hw_usb, OID_AUTO, ure, CTLFLAG_RW, 0, "USB ure"); 61291557SkevloSYSCTL_INT(_hw_usb_ure, OID_AUTO, debug, CTLFLAG_RWTUN, &ure_debug, 0, 62291557Skevlo "Debug level"); 63291557Skevlo#endif 64291557Skevlo 65291557Skevlo/* 66291557Skevlo * Various supported device vendors/products. 67291557Skevlo */ 68291557Skevlostatic const STRUCT_USB_HOST_ID ure_devs[] = { 69291557Skevlo#define URE_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 70291557Skevlo URE_DEV(REALTEK, RTL8152), 71291557Skevlo#undef URE_DEV 72291557Skevlo}; 73291557Skevlo 74291557Skevlostatic device_probe_t ure_probe; 75291557Skevlostatic device_attach_t ure_attach; 76291557Skevlostatic device_detach_t ure_detach; 77291557Skevlo 78291557Skevlostatic usb_callback_t ure_bulk_read_callback; 79291557Skevlostatic usb_callback_t ure_bulk_write_callback; 80291557Skevlo 81291557Skevlostatic miibus_readreg_t ure_miibus_readreg; 82291557Skevlostatic miibus_writereg_t ure_miibus_writereg; 83291557Skevlostatic miibus_statchg_t ure_miibus_statchg; 84291557Skevlo 85291557Skevlostatic uether_fn_t ure_attach_post; 86291557Skevlostatic uether_fn_t ure_init; 87291557Skevlostatic uether_fn_t ure_stop; 88291557Skevlostatic uether_fn_t ure_start; 89291557Skevlostatic uether_fn_t ure_tick; 90291557Skevlostatic uether_fn_t ure_setmulti; 91291557Skevlostatic uether_fn_t ure_setpromisc; 92291557Skevlo 93291557Skevlostatic int ure_ctl(struct ure_softc *, uint8_t, uint16_t, uint16_t, 94291557Skevlo void *, int); 95291557Skevlostatic int ure_read_mem(struct ure_softc *, uint16_t, uint16_t, void *, 96291557Skevlo int); 97291557Skevlostatic int ure_write_mem(struct ure_softc *, uint16_t, uint16_t, void *, 98291557Skevlo int); 99291557Skevlostatic uint8_t ure_read_1(struct ure_softc *, uint16_t, uint16_t); 100291557Skevlostatic uint16_t ure_read_2(struct ure_softc *, uint16_t, uint16_t); 101291557Skevlostatic uint32_t ure_read_4(struct ure_softc *, uint16_t, uint16_t); 102291557Skevlostatic int ure_write_1(struct ure_softc *, uint16_t, uint16_t, uint32_t); 103291557Skevlostatic int ure_write_2(struct ure_softc *, uint16_t, uint16_t, uint32_t); 104291557Skevlostatic int ure_write_4(struct ure_softc *, uint16_t, uint16_t, uint32_t); 105291557Skevlostatic uint16_t ure_ocp_reg_read(struct ure_softc *, uint16_t); 106291557Skevlostatic void ure_ocp_reg_write(struct ure_softc *, uint16_t, uint16_t); 107291557Skevlo 108291557Skevlostatic void ure_read_chipver(struct ure_softc *); 109291557Skevlostatic int ure_attach_post_sub(struct usb_ether *); 110291557Skevlostatic void ure_reset(struct ure_softc *); 111291557Skevlostatic int ure_ifmedia_upd(struct ifnet *); 112291557Skevlostatic void ure_ifmedia_sts(struct ifnet *, struct ifmediareq *); 113291557Skevlostatic int ure_ioctl(struct ifnet *, u_long, caddr_t); 114291557Skevlostatic void ure_rtl8152_init(struct ure_softc *); 115291557Skevlostatic void ure_disable_teredo(struct ure_softc *); 116291557Skevlostatic void ure_init_fifo(struct ure_softc *); 117291557Skevlo 118291557Skevlostatic const struct usb_config ure_config[URE_N_TRANSFER] = { 119291557Skevlo [URE_BULK_DT_WR] = { 120291557Skevlo .type = UE_BULK, 121291557Skevlo .endpoint = UE_ADDR_ANY, 122291557Skevlo .direction = UE_DIR_OUT, 123291557Skevlo .bufsize = MCLBYTES, 124291557Skevlo .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 125291557Skevlo .callback = ure_bulk_write_callback, 126291557Skevlo .timeout = 10000, /* 10 seconds */ 127291557Skevlo }, 128291557Skevlo [URE_BULK_DT_RD] = { 129291557Skevlo .type = UE_BULK, 130291557Skevlo .endpoint = UE_ADDR_ANY, 131291557Skevlo .direction = UE_DIR_IN, 132291557Skevlo .bufsize = MCLBYTES, 133291557Skevlo .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 134291557Skevlo .callback = ure_bulk_read_callback, 135291557Skevlo .timeout = 0, /* no timeout */ 136291557Skevlo }, 137291557Skevlo}; 138291557Skevlo 139291557Skevlostatic device_method_t ure_methods[] = { 140291557Skevlo /* Device interface. */ 141291557Skevlo DEVMETHOD(device_probe, ure_probe), 142291557Skevlo DEVMETHOD(device_attach, ure_attach), 143291557Skevlo DEVMETHOD(device_detach, ure_detach), 144291557Skevlo 145291557Skevlo /* MII interface. */ 146291557Skevlo DEVMETHOD(miibus_readreg, ure_miibus_readreg), 147291557Skevlo DEVMETHOD(miibus_writereg, ure_miibus_writereg), 148291557Skevlo DEVMETHOD(miibus_statchg, ure_miibus_statchg), 149291557Skevlo 150291557Skevlo DEVMETHOD_END 151291557Skevlo}; 152291557Skevlo 153291557Skevlostatic driver_t ure_driver = { 154291557Skevlo .name = "ure", 155291557Skevlo .methods = ure_methods, 156291557Skevlo .size = sizeof(struct ure_softc), 157291557Skevlo}; 158291557Skevlo 159291557Skevlostatic devclass_t ure_devclass; 160291557Skevlo 161291557SkevloDRIVER_MODULE(ure, uhub, ure_driver, ure_devclass, NULL, NULL); 162291557SkevloDRIVER_MODULE(miibus, ure, miibus_driver, miibus_devclass, NULL, NULL); 163291557SkevloMODULE_DEPEND(ure, uether, 1, 1, 1); 164291557SkevloMODULE_DEPEND(ure, usb, 1, 1, 1); 165291557SkevloMODULE_DEPEND(ure, ether, 1, 1, 1); 166291557SkevloMODULE_DEPEND(ure, miibus, 1, 1, 1); 167291557SkevloMODULE_VERSION(ure, 1); 168291557Skevlo 169291557Skevlostatic const struct usb_ether_methods ure_ue_methods = { 170291557Skevlo .ue_attach_post = ure_attach_post, 171291557Skevlo .ue_attach_post_sub = ure_attach_post_sub, 172291557Skevlo .ue_start = ure_start, 173291557Skevlo .ue_init = ure_init, 174291557Skevlo .ue_stop = ure_stop, 175291557Skevlo .ue_tick = ure_tick, 176291557Skevlo .ue_setmulti = ure_setmulti, 177291557Skevlo .ue_setpromisc = ure_setpromisc, 178291557Skevlo .ue_mii_upd = ure_ifmedia_upd, 179291557Skevlo .ue_mii_sts = ure_ifmedia_sts, 180291557Skevlo}; 181291557Skevlo 182291557Skevlostatic int 183291557Skevloure_ctl(struct ure_softc *sc, uint8_t rw, uint16_t val, uint16_t index, 184291557Skevlo void *buf, int len) 185291557Skevlo{ 186291557Skevlo struct usb_device_request req; 187291557Skevlo 188291557Skevlo URE_LOCK_ASSERT(sc, MA_OWNED); 189291557Skevlo 190291557Skevlo if (rw == URE_CTL_WRITE) 191291557Skevlo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 192291557Skevlo else 193291557Skevlo req.bmRequestType = UT_READ_VENDOR_DEVICE; 194291557Skevlo req.bRequest = UR_SET_ADDRESS; 195291557Skevlo USETW(req.wValue, val); 196291557Skevlo USETW(req.wIndex, index); 197291557Skevlo USETW(req.wLength, len); 198291557Skevlo 199291557Skevlo return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 200291557Skevlo} 201291557Skevlo 202291557Skevlostatic int 203291557Skevloure_read_mem(struct ure_softc *sc, uint16_t addr, uint16_t index, 204291557Skevlo void *buf, int len) 205291557Skevlo{ 206291557Skevlo 207291557Skevlo return (ure_ctl(sc, URE_CTL_READ, addr, index, buf, len)); 208291557Skevlo} 209291557Skevlo 210291557Skevlostatic int 211291557Skevloure_write_mem(struct ure_softc *sc, uint16_t addr, uint16_t index, 212291557Skevlo void *buf, int len) 213291557Skevlo{ 214291557Skevlo 215291557Skevlo return (ure_ctl(sc, URE_CTL_WRITE, addr, index, buf, len)); 216291557Skevlo} 217291557Skevlo 218291557Skevlostatic uint8_t 219291557Skevloure_read_1(struct ure_softc *sc, uint16_t reg, uint16_t index) 220291557Skevlo{ 221291557Skevlo uint32_t val; 222291557Skevlo uint8_t temp[4]; 223291557Skevlo uint8_t shift; 224291557Skevlo 225291557Skevlo shift = (reg & 3) << 3; 226291557Skevlo reg &= ~3; 227291557Skevlo 228291557Skevlo ure_read_mem(sc, reg, index, &temp, 4); 229291557Skevlo val = UGETDW(temp); 230291557Skevlo val >>= shift; 231291557Skevlo 232291557Skevlo return (val & 0xff); 233291557Skevlo} 234291557Skevlo 235291557Skevlostatic uint16_t 236291557Skevloure_read_2(struct ure_softc *sc, uint16_t reg, uint16_t index) 237291557Skevlo{ 238291557Skevlo uint32_t val; 239291557Skevlo uint8_t temp[4]; 240291557Skevlo uint8_t shift; 241291557Skevlo 242291557Skevlo shift = (reg & 2) << 3; 243291557Skevlo reg &= ~3; 244291557Skevlo 245291557Skevlo ure_read_mem(sc, reg, index, &temp, 4); 246291557Skevlo val = UGETDW(temp); 247291557Skevlo val >>= shift; 248291557Skevlo 249291557Skevlo return (val & 0xffff); 250291557Skevlo} 251291557Skevlo 252291557Skevlostatic uint32_t 253291557Skevloure_read_4(struct ure_softc *sc, uint16_t reg, uint16_t index) 254291557Skevlo{ 255291557Skevlo uint8_t temp[4]; 256291557Skevlo 257291557Skevlo ure_read_mem(sc, reg, index, &temp, 4); 258291557Skevlo return (UGETDW(temp)); 259291557Skevlo} 260291557Skevlo 261291557Skevlostatic int 262291557Skevloure_write_1(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val) 263291557Skevlo{ 264291557Skevlo uint16_t byen; 265291557Skevlo uint8_t temp[4]; 266291557Skevlo uint8_t shift; 267291557Skevlo 268291557Skevlo byen = URE_BYTE_EN_BYTE; 269291557Skevlo shift = reg & 3; 270291557Skevlo val &= 0xff; 271291557Skevlo 272291557Skevlo if (reg & 3) { 273291557Skevlo byen <<= shift; 274291557Skevlo val <<= (shift << 3); 275291557Skevlo reg &= ~3; 276291557Skevlo } 277291557Skevlo 278291557Skevlo USETDW(temp, val); 279291557Skevlo return (ure_write_mem(sc, reg, index | byen, &temp, 4)); 280291557Skevlo} 281291557Skevlo 282291557Skevlostatic int 283291557Skevloure_write_2(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val) 284291557Skevlo{ 285291557Skevlo uint16_t byen; 286291557Skevlo uint8_t temp[4]; 287291557Skevlo uint8_t shift; 288291557Skevlo 289291557Skevlo byen = URE_BYTE_EN_WORD; 290291557Skevlo shift = reg & 2; 291291557Skevlo val &= 0xffff; 292291557Skevlo 293291557Skevlo if (reg & 2) { 294291557Skevlo byen <<= shift; 295291557Skevlo val <<= (shift << 3); 296291557Skevlo reg &= ~3; 297291557Skevlo } 298291557Skevlo 299291557Skevlo USETDW(temp, val); 300291557Skevlo return (ure_write_mem(sc, reg, index | byen, &temp, 4)); 301291557Skevlo} 302291557Skevlo 303291557Skevlostatic int 304291557Skevloure_write_4(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val) 305291557Skevlo{ 306291557Skevlo uint8_t temp[4]; 307291557Skevlo 308291557Skevlo USETDW(temp, val); 309291557Skevlo return (ure_write_mem(sc, reg, index | URE_BYTE_EN_DWORD, &temp, 4)); 310291557Skevlo} 311291557Skevlo 312291557Skevlostatic uint16_t 313291557Skevloure_ocp_reg_read(struct ure_softc *sc, uint16_t addr) 314291557Skevlo{ 315291557Skevlo uint16_t reg; 316291557Skevlo 317291557Skevlo ure_write_2(sc, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); 318291557Skevlo reg = (addr & 0x0fff) | 0xb000; 319291557Skevlo 320291557Skevlo return (ure_read_2(sc, reg, URE_MCU_TYPE_PLA)); 321291557Skevlo} 322291557Skevlo 323291557Skevlostatic void 324291557Skevloure_ocp_reg_write(struct ure_softc *sc, uint16_t addr, uint16_t data) 325291557Skevlo{ 326291557Skevlo uint16_t reg; 327291557Skevlo 328291557Skevlo ure_write_2(sc, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); 329291557Skevlo reg = (addr & 0x0fff) | 0xb000; 330291557Skevlo 331291557Skevlo ure_write_2(sc, reg, URE_MCU_TYPE_PLA, data); 332291557Skevlo} 333291557Skevlo 334291557Skevlostatic int 335291557Skevloure_miibus_readreg(device_t dev, int phy, int reg) 336291557Skevlo{ 337291557Skevlo struct ure_softc *sc; 338291557Skevlo uint16_t val; 339291557Skevlo int locked; 340291557Skevlo 341291557Skevlo sc = device_get_softc(dev); 342291557Skevlo locked = mtx_owned(&sc->sc_mtx); 343291557Skevlo if (!locked) 344291557Skevlo URE_LOCK(sc); 345291557Skevlo 346291557Skevlo val = ure_ocp_reg_read(sc, URE_OCP_BASE_MII + reg * 2); 347291557Skevlo 348291557Skevlo if (!locked) 349291557Skevlo URE_UNLOCK(sc); 350291557Skevlo return (val); 351291557Skevlo} 352291557Skevlo 353291557Skevlostatic int 354291557Skevloure_miibus_writereg(device_t dev, int phy, int reg, int val) 355291557Skevlo{ 356291557Skevlo struct ure_softc *sc; 357291557Skevlo int locked; 358291557Skevlo 359291557Skevlo sc = device_get_softc(dev); 360291557Skevlo if (sc->sc_phyno != phy) 361291557Skevlo return (0); 362291557Skevlo 363291557Skevlo locked = mtx_owned(&sc->sc_mtx); 364291557Skevlo if (!locked) 365291557Skevlo URE_LOCK(sc); 366291557Skevlo 367291557Skevlo ure_ocp_reg_write(sc, URE_OCP_BASE_MII + reg * 2, val); 368291557Skevlo 369291557Skevlo if (!locked) 370291557Skevlo URE_UNLOCK(sc); 371291557Skevlo return (0); 372291557Skevlo} 373291557Skevlo 374291557Skevlostatic void 375291557Skevloure_miibus_statchg(device_t dev) 376291557Skevlo{ 377291557Skevlo struct ure_softc *sc; 378291557Skevlo struct mii_data *mii; 379291557Skevlo struct ifnet *ifp; 380291557Skevlo int locked; 381291557Skevlo 382291557Skevlo sc = device_get_softc(dev); 383291557Skevlo mii = GET_MII(sc); 384291557Skevlo locked = mtx_owned(&sc->sc_mtx); 385291557Skevlo if (!locked) 386291557Skevlo URE_LOCK(sc); 387291557Skevlo 388291557Skevlo ifp = uether_getifp(&sc->sc_ue); 389291557Skevlo if (mii == NULL || ifp == NULL || 390291557Skevlo (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 391291557Skevlo goto done; 392291557Skevlo 393291557Skevlo sc->sc_flags &= ~URE_FLAG_LINK; 394291557Skevlo if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 395291557Skevlo (IFM_ACTIVE | IFM_AVALID)) { 396291557Skevlo switch (IFM_SUBTYPE(mii->mii_media_active)) { 397291557Skevlo case IFM_10_T: 398291557Skevlo case IFM_100_TX: 399291557Skevlo sc->sc_flags |= URE_FLAG_LINK; 400291557Skevlo break; 401291557Skevlo default: 402291557Skevlo break; 403291557Skevlo } 404291557Skevlo } 405291557Skevlo 406291557Skevlo /* Lost link, do nothing. */ 407291557Skevlo if ((sc->sc_flags & URE_FLAG_LINK) == 0) 408291557Skevlo goto done; 409291557Skevlodone: 410291557Skevlo if (!locked) 411291557Skevlo URE_UNLOCK(sc); 412291557Skevlo} 413291557Skevlo 414291557Skevlo/* 415291557Skevlo * Probe for a RTL8152 chip. 416291557Skevlo */ 417291557Skevlostatic int 418291557Skevloure_probe(device_t dev) 419291557Skevlo{ 420291557Skevlo struct usb_attach_arg *uaa; 421291557Skevlo 422297793Spfg uaa = device_get_ivars(dev); 423291557Skevlo if (uaa->usb_mode != USB_MODE_HOST) 424291557Skevlo return (ENXIO); 425291557Skevlo if (uaa->info.bConfigIndex != URE_CONFIG_IDX) 426291557Skevlo return (ENXIO); 427291557Skevlo if (uaa->info.bIfaceIndex != URE_IFACE_IDX) 428291557Skevlo return (ENXIO); 429291557Skevlo 430291557Skevlo return (usbd_lookup_id_by_uaa(ure_devs, sizeof(ure_devs), uaa)); 431291557Skevlo} 432291557Skevlo 433291557Skevlo/* 434291557Skevlo * Attach the interface. Allocate softc structures, do ifmedia 435291557Skevlo * setup and ethernet/BPF attach. 436291557Skevlo */ 437291557Skevlostatic int 438291557Skevloure_attach(device_t dev) 439291557Skevlo{ 440291557Skevlo struct usb_attach_arg *uaa = device_get_ivars(dev); 441291557Skevlo struct ure_softc *sc = device_get_softc(dev); 442291557Skevlo struct usb_ether *ue = &sc->sc_ue; 443291557Skevlo uint8_t iface_index; 444291557Skevlo int error; 445291557Skevlo 446291557Skevlo device_set_usb_desc(dev); 447291557Skevlo mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 448291557Skevlo 449291557Skevlo iface_index = URE_IFACE_IDX; 450291557Skevlo error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, 451291557Skevlo ure_config, URE_N_TRANSFER, sc, &sc->sc_mtx); 452291557Skevlo if (error != 0) { 453291557Skevlo device_printf(dev, "allocating USB transfers failed\n"); 454291557Skevlo goto detach; 455291557Skevlo } 456291557Skevlo 457291557Skevlo ue->ue_sc = sc; 458291557Skevlo ue->ue_dev = dev; 459291557Skevlo ue->ue_udev = uaa->device; 460291557Skevlo ue->ue_mtx = &sc->sc_mtx; 461291557Skevlo ue->ue_methods = &ure_ue_methods; 462291557Skevlo 463291557Skevlo error = uether_ifattach(ue); 464291557Skevlo if (error != 0) { 465291557Skevlo device_printf(dev, "could not attach interface\n"); 466291557Skevlo goto detach; 467291557Skevlo } 468291557Skevlo return (0); /* success */ 469291557Skevlo 470291557Skevlodetach: 471291557Skevlo ure_detach(dev); 472291557Skevlo return (ENXIO); /* failure */ 473291557Skevlo} 474291557Skevlo 475291557Skevlostatic int 476291557Skevloure_detach(device_t dev) 477291557Skevlo{ 478291557Skevlo struct ure_softc *sc = device_get_softc(dev); 479291557Skevlo struct usb_ether *ue = &sc->sc_ue; 480291557Skevlo 481291557Skevlo usbd_transfer_unsetup(sc->sc_xfer, URE_N_TRANSFER); 482291557Skevlo uether_ifdetach(ue); 483291557Skevlo mtx_destroy(&sc->sc_mtx); 484291557Skevlo 485291557Skevlo return (0); 486291557Skevlo} 487291557Skevlo 488291557Skevlostatic void 489291557Skevloure_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 490291557Skevlo{ 491291557Skevlo struct ure_softc *sc = usbd_xfer_softc(xfer); 492291557Skevlo struct usb_ether *ue = &sc->sc_ue; 493291557Skevlo struct ifnet *ifp = uether_getifp(ue); 494291557Skevlo struct usb_page_cache *pc; 495291557Skevlo struct ure_rxpkt pkt; 496291557Skevlo int actlen, len; 497291557Skevlo 498291557Skevlo usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 499291557Skevlo 500291557Skevlo switch (USB_GET_STATE(xfer)) { 501291557Skevlo case USB_ST_TRANSFERRED: 502291557Skevlo if (actlen < (int)(sizeof(pkt))) { 503291557Skevlo if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 504291557Skevlo goto tr_setup; 505291557Skevlo } 506291557Skevlo pc = usbd_xfer_get_frame(xfer, 0); 507291557Skevlo usbd_copy_out(pc, 0, &pkt, sizeof(pkt)); 508291557Skevlo len = le32toh(pkt.ure_pktlen) & URE_RXPKT_LEN_MASK; 509291557Skevlo len -= ETHER_CRC_LEN; 510291557Skevlo if (actlen < (int)(len + sizeof(pkt))) { 511291557Skevlo if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 512291557Skevlo goto tr_setup; 513291557Skevlo } 514291557Skevlo 515291557Skevlo uether_rxbuf(ue, pc, sizeof(pkt), len); 516291557Skevlo /* FALLTHROUGH */ 517291557Skevlo case USB_ST_SETUP: 518291557Skevlotr_setup: 519291557Skevlo usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 520291557Skevlo usbd_transfer_submit(xfer); 521291557Skevlo uether_rxflush(ue); 522291557Skevlo return; 523291557Skevlo 524291557Skevlo default: /* Error */ 525291557Skevlo DPRINTF("bulk read error, %s\n", 526291557Skevlo usbd_errstr(error)); 527291557Skevlo 528291557Skevlo if (error != USB_ERR_CANCELLED) { 529291557Skevlo /* try to clear stall first */ 530291557Skevlo usbd_xfer_set_stall(xfer); 531291557Skevlo goto tr_setup; 532291557Skevlo } 533291557Skevlo return; 534291557Skevlo } 535291557Skevlo} 536291557Skevlo 537291557Skevlostatic void 538291557Skevloure_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 539291557Skevlo{ 540291557Skevlo struct ure_softc *sc = usbd_xfer_softc(xfer); 541291557Skevlo struct ifnet *ifp = uether_getifp(&sc->sc_ue); 542291557Skevlo struct usb_page_cache *pc; 543291557Skevlo struct mbuf *m; 544291557Skevlo struct ure_txpkt txpkt; 545291557Skevlo int len, pos; 546291557Skevlo 547291557Skevlo switch (USB_GET_STATE(xfer)) { 548291557Skevlo case USB_ST_TRANSFERRED: 549291557Skevlo DPRINTFN(11, "transfer complete\n"); 550291557Skevlo ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 551291557Skevlo /* FALLTHROUGH */ 552291557Skevlo case USB_ST_SETUP: 553291557Skevlotr_setup: 554291557Skevlo if ((sc->sc_flags & URE_FLAG_LINK) == 0 || 555291557Skevlo (ifp->if_drv_flags & IFF_DRV_OACTIVE) != 0) { 556291557Skevlo /* 557291557Skevlo * don't send anything if there is no link ! 558291557Skevlo */ 559291557Skevlo return; 560291557Skevlo } 561291557Skevlo IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 562291557Skevlo if (m == NULL) 563291557Skevlo break; 564291557Skevlo pos = 0; 565291557Skevlo len = m->m_pkthdr.len; 566291557Skevlo pc = usbd_xfer_get_frame(xfer, 0); 567291557Skevlo memset(&txpkt, 0, sizeof(txpkt)); 568291557Skevlo txpkt.ure_pktlen = htole32((len & URE_TXPKT_LEN_MASK) | 569291557Skevlo URE_TKPKT_TX_FS | URE_TKPKT_TX_LS); 570291557Skevlo usbd_copy_in(pc, pos, &txpkt, sizeof(txpkt)); 571291557Skevlo pos += sizeof(txpkt); 572291557Skevlo usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len); 573291557Skevlo pos += m->m_pkthdr.len; 574291557Skevlo 575291557Skevlo if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 576291557Skevlo 577291557Skevlo /* 578291557Skevlo * If there's a BPF listener, bounce a copy 579291557Skevlo * of this frame to him. 580291557Skevlo */ 581291557Skevlo BPF_MTAP(ifp, m); 582291557Skevlo 583291557Skevlo m_freem(m); 584291557Skevlo 585291557Skevlo /* Set frame length. */ 586291557Skevlo usbd_xfer_set_frame_len(xfer, 0, pos); 587291557Skevlo 588291557Skevlo usbd_transfer_submit(xfer); 589291557Skevlo ifp->if_drv_flags |= IFF_DRV_OACTIVE; 590291557Skevlo return; 591291557Skevlo default: /* Error */ 592291557Skevlo DPRINTFN(11, "transfer error, %s\n", 593291557Skevlo usbd_errstr(error)); 594291557Skevlo 595291557Skevlo if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 596291557Skevlo ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 597291557Skevlo 598291557Skevlo if (error != USB_ERR_CANCELLED) { 599291557Skevlo /* try to clear stall first */ 600291557Skevlo usbd_xfer_set_stall(xfer); 601291557Skevlo goto tr_setup; 602291557Skevlo } 603291557Skevlo return; 604291557Skevlo } 605291557Skevlo} 606291557Skevlo 607291557Skevlostatic void 608291557Skevloure_read_chipver(struct ure_softc *sc) 609291557Skevlo{ 610291557Skevlo uint16_t ver; 611291557Skevlo 612291557Skevlo ver = ure_read_2(sc, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK; 613291557Skevlo switch (ver) { 614291557Skevlo case 0x4c00: 615291557Skevlo sc->sc_chip |= URE_CHIP_VER_4C00; 616291557Skevlo break; 617291557Skevlo case 0x4c10: 618291557Skevlo sc->sc_chip |= URE_CHIP_VER_4C10; 619291557Skevlo break; 620291557Skevlo default: 621291557Skevlo device_printf(sc->sc_ue.ue_dev, 622291557Skevlo "unknown version 0x%04x\n", ver); 623291557Skevlo break; 624291557Skevlo } 625291557Skevlo} 626291557Skevlo 627291557Skevlostatic void 628291557Skevloure_attach_post(struct usb_ether *ue) 629291557Skevlo{ 630291557Skevlo struct ure_softc *sc = uether_getsc(ue); 631291557Skevlo 632291557Skevlo sc->sc_phyno = 0; 633291557Skevlo 634291557Skevlo /* Determine the chip version. */ 635291557Skevlo ure_read_chipver(sc); 636291557Skevlo 637291557Skevlo /* Initialize controller and get station address. */ 638291557Skevlo ure_rtl8152_init(sc); 639291557Skevlo 640291557Skevlo if (sc->sc_chip & URE_CHIP_VER_4C00) 641291557Skevlo ure_read_mem(sc, URE_PLA_IDR, URE_MCU_TYPE_PLA, 642291557Skevlo ue->ue_eaddr, 8); 643291557Skevlo else 644291557Skevlo ure_read_mem(sc, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, 645291557Skevlo ue->ue_eaddr, 8); 646291557Skevlo} 647291557Skevlo 648291557Skevlostatic int 649291557Skevloure_attach_post_sub(struct usb_ether *ue) 650291557Skevlo{ 651291557Skevlo struct ure_softc *sc; 652291557Skevlo struct ifnet *ifp; 653291557Skevlo int error; 654291557Skevlo 655291557Skevlo sc = uether_getsc(ue); 656291557Skevlo ifp = ue->ue_ifp; 657291557Skevlo ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 658291557Skevlo ifp->if_start = uether_start; 659291557Skevlo ifp->if_ioctl = ure_ioctl; 660291557Skevlo ifp->if_init = uether_init; 661291557Skevlo IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 662291557Skevlo ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 663291557Skevlo IFQ_SET_READY(&ifp->if_snd); 664291557Skevlo 665291557Skevlo mtx_lock(&Giant); 666291557Skevlo error = mii_attach(ue->ue_dev, &ue->ue_miibus, ifp, 667291557Skevlo uether_ifmedia_upd, ue->ue_methods->ue_mii_sts, 668291557Skevlo BMSR_DEFCAPMASK, sc->sc_phyno, MII_OFFSET_ANY, 0); 669291557Skevlo mtx_unlock(&Giant); 670291557Skevlo 671291557Skevlo return (error); 672291557Skevlo} 673291557Skevlo 674291557Skevlostatic void 675291557Skevloure_init(struct usb_ether *ue) 676291557Skevlo{ 677291557Skevlo struct ure_softc *sc = uether_getsc(ue); 678291557Skevlo struct ifnet *ifp = uether_getifp(ue); 679291557Skevlo uint32_t rxmode; 680291557Skevlo 681291557Skevlo URE_LOCK_ASSERT(sc, MA_OWNED); 682291557Skevlo 683291557Skevlo if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 684291557Skevlo return; 685291557Skevlo 686291557Skevlo /* Cancel pending I/O. */ 687291557Skevlo ure_stop(ue); 688291557Skevlo 689291557Skevlo ure_reset(sc); 690291557Skevlo 691291557Skevlo /* Set MAC address. */ 692291557Skevlo ure_write_mem(sc, URE_PLA_IDR, URE_MCU_TYPE_PLA | URE_BYTE_EN_SIX_BYTES, 693291557Skevlo IF_LLADDR(ifp), 8); 694291557Skevlo 695291557Skevlo /* Reset the packet filter. */ 696291557Skevlo ure_write_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA, 697291557Skevlo ure_read_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA) & 698291557Skevlo ~URE_FMC_FCR_MCU_EN); 699291557Skevlo ure_write_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA, 700291557Skevlo ure_read_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA) | 701291557Skevlo URE_FMC_FCR_MCU_EN); 702291557Skevlo 703291557Skevlo /* Enable transmit and receive. */ 704291557Skevlo ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, 705291557Skevlo ure_read_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA) | URE_CR_RE | 706291557Skevlo URE_CR_TE); 707291557Skevlo 708291557Skevlo ure_write_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, 709291557Skevlo ure_read_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) & 710291557Skevlo ~URE_RXDY_GATED_EN); 711291557Skevlo 712291557Skevlo /* Set Rx mode. */ 713365738Sjmg rxmode = ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA); 714365738Sjmg rxmode &= ~URE_RCR_ACPT_ALL; 715365738Sjmg rxmode |= URE_RCR_APM; 716291557Skevlo 717291557Skevlo /* If we want promiscuous mode, set the allframes bit. */ 718291557Skevlo if (ifp->if_flags & IFF_PROMISC) 719291557Skevlo rxmode |= URE_RCR_AAP; 720291557Skevlo 721291557Skevlo if (ifp->if_flags & IFF_BROADCAST) 722291557Skevlo rxmode |= URE_RCR_AB; 723291557Skevlo 724291557Skevlo ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); 725291557Skevlo 726291557Skevlo /* Load the multicast filter. */ 727291557Skevlo ure_setmulti(ue); 728291557Skevlo 729291557Skevlo usbd_xfer_set_stall(sc->sc_xfer[URE_BULK_DT_WR]); 730291557Skevlo 731291557Skevlo /* Indicate we are up and running. */ 732291557Skevlo ifp->if_drv_flags |= IFF_DRV_RUNNING; 733291557Skevlo 734291557Skevlo /* Switch to selected media. */ 735291557Skevlo ure_ifmedia_upd(ifp); 736291557Skevlo} 737291557Skevlo 738291557Skevlostatic void 739291557Skevloure_tick(struct usb_ether *ue) 740291557Skevlo{ 741291557Skevlo struct ure_softc *sc = uether_getsc(ue); 742291557Skevlo struct mii_data *mii = GET_MII(sc); 743291557Skevlo 744291557Skevlo URE_LOCK_ASSERT(sc, MA_OWNED); 745291557Skevlo 746291557Skevlo mii_tick(mii); 747291557Skevlo if ((sc->sc_flags & URE_FLAG_LINK) == 0 748291557Skevlo && mii->mii_media_status & IFM_ACTIVE && 749291557Skevlo IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 750291557Skevlo sc->sc_flags |= URE_FLAG_LINK; 751291557Skevlo ure_start(ue); 752291557Skevlo } 753291557Skevlo} 754291557Skevlo 755291557Skevlostatic void 756291557Skevloure_setpromisc(struct usb_ether *ue) 757291557Skevlo{ 758291557Skevlo struct ure_softc *sc = uether_getsc(ue); 759291557Skevlo struct ifnet *ifp = uether_getifp(ue); 760291557Skevlo uint32_t rxmode; 761291557Skevlo 762291557Skevlo rxmode = ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA); 763291557Skevlo 764291557Skevlo if (ifp->if_flags & IFF_PROMISC) 765291557Skevlo rxmode |= URE_RCR_AAP; 766291557Skevlo else 767291557Skevlo rxmode &= ~URE_RCR_AAP; 768291557Skevlo 769291557Skevlo ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); 770291557Skevlo 771291557Skevlo ure_setmulti(ue); 772291557Skevlo} 773291557Skevlo 774291557Skevlo/* 775291557Skevlo * Program the 64-bit multicast hash filter. 776291557Skevlo */ 777291557Skevlostatic void 778291557Skevloure_setmulti(struct usb_ether *ue) 779291557Skevlo{ 780291557Skevlo struct ure_softc *sc = uether_getsc(ue); 781291557Skevlo struct ifnet *ifp = uether_getifp(ue); 782291557Skevlo struct ifmultiaddr *ifma; 783291557Skevlo uint32_t h, rxmode; 784291557Skevlo uint32_t hashes[2] = { 0, 0 }; 785291557Skevlo 786291557Skevlo URE_LOCK_ASSERT(sc, MA_OWNED); 787291557Skevlo 788291557Skevlo rxmode = ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA); 789291557Skevlo if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { 790291557Skevlo if (ifp->if_flags & IFF_PROMISC) 791291557Skevlo rxmode |= URE_RCR_AAP; 792291557Skevlo rxmode |= URE_RCR_AM; 793291557Skevlo hashes[0] = hashes[1] = 0xffffffff; 794291557Skevlo goto done; 795291557Skevlo } 796291557Skevlo 797291557Skevlo if_maddr_rlock(ifp); 798291557Skevlo TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 799291557Skevlo if (ifma->ifma_addr->sa_family != AF_LINK) 800291557Skevlo continue; 801291557Skevlo h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 802291557Skevlo ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 803291557Skevlo if (h < 32) 804291557Skevlo hashes[0] |= (1 << h); 805291557Skevlo else 806291557Skevlo hashes[1] |= (1 << (h - 32)); 807291557Skevlo } 808291557Skevlo if_maddr_runlock(ifp); 809291557Skevlo 810291557Skevlo h = bswap32(hashes[0]); 811291557Skevlo hashes[0] = bswap32(hashes[1]); 812291557Skevlo hashes[1] = h; 813291557Skevlo rxmode |= URE_RCR_AM; 814291557Skevlo 815291557Skevlodone: 816291557Skevlo ure_write_4(sc, URE_PLA_MAR0, URE_MCU_TYPE_PLA, hashes[0]); 817291557Skevlo ure_write_4(sc, URE_PLA_MAR4, URE_MCU_TYPE_PLA, hashes[1]); 818291557Skevlo ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); 819291557Skevlo} 820291557Skevlo 821291557Skevlostatic void 822291557Skevloure_start(struct usb_ether *ue) 823291557Skevlo{ 824291557Skevlo struct ure_softc *sc = uether_getsc(ue); 825291557Skevlo 826291557Skevlo /* 827291557Skevlo * start the USB transfers, if not already started: 828291557Skevlo */ 829291557Skevlo usbd_transfer_start(sc->sc_xfer[URE_BULK_DT_RD]); 830291557Skevlo usbd_transfer_start(sc->sc_xfer[URE_BULK_DT_WR]); 831291557Skevlo} 832291557Skevlo 833291557Skevlostatic void 834291557Skevloure_reset(struct ure_softc *sc) 835291557Skevlo{ 836291557Skevlo int i; 837291557Skevlo 838291557Skevlo ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST); 839291557Skevlo 840291557Skevlo for (i = 0; i < URE_TIMEOUT; i++) { 841291557Skevlo if (!(ure_read_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA) & 842291557Skevlo URE_CR_RST)) 843291557Skevlo break; 844291557Skevlo uether_pause(&sc->sc_ue, hz / 100); 845291557Skevlo } 846291557Skevlo if (i == URE_TIMEOUT) 847291557Skevlo device_printf(sc->sc_ue.ue_dev, "reset never completed\n"); 848291557Skevlo} 849291557Skevlo 850291557Skevlo/* 851291557Skevlo * Set media options. 852291557Skevlo */ 853291557Skevlostatic int 854291557Skevloure_ifmedia_upd(struct ifnet *ifp) 855291557Skevlo{ 856291557Skevlo struct ure_softc *sc = ifp->if_softc; 857291557Skevlo struct mii_data *mii = GET_MII(sc); 858291557Skevlo struct mii_softc *miisc; 859291557Skevlo int error; 860291557Skevlo 861291557Skevlo URE_LOCK_ASSERT(sc, MA_OWNED); 862291557Skevlo 863291557Skevlo LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 864291557Skevlo PHY_RESET(miisc); 865291557Skevlo error = mii_mediachg(mii); 866291557Skevlo return (error); 867291557Skevlo} 868291557Skevlo 869291557Skevlo/* 870291557Skevlo * Report current media status. 871291557Skevlo */ 872291557Skevlostatic void 873291557Skevloure_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 874291557Skevlo{ 875291557Skevlo struct ure_softc *sc; 876291557Skevlo struct mii_data *mii; 877291557Skevlo 878291557Skevlo sc = ifp->if_softc; 879291557Skevlo mii = GET_MII(sc); 880291557Skevlo 881291557Skevlo URE_LOCK(sc); 882291557Skevlo mii_pollstat(mii); 883291557Skevlo ifmr->ifm_active = mii->mii_media_active; 884291557Skevlo ifmr->ifm_status = mii->mii_media_status; 885291557Skevlo URE_UNLOCK(sc); 886291557Skevlo} 887291557Skevlo 888291557Skevlostatic int 889291557Skevloure_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 890291557Skevlo{ 891291557Skevlo struct usb_ether *ue = ifp->if_softc; 892291557Skevlo struct ure_softc *sc; 893291557Skevlo struct ifreq *ifr; 894291557Skevlo int error, mask, reinit; 895291557Skevlo 896291557Skevlo sc = uether_getsc(ue); 897291557Skevlo ifr = (struct ifreq *)data; 898291557Skevlo error = 0; 899291557Skevlo reinit = 0; 900291557Skevlo if (cmd == SIOCSIFCAP) { 901291557Skevlo URE_LOCK(sc); 902291557Skevlo mask = ifr->ifr_reqcap ^ ifp->if_capenable; 903291557Skevlo if (reinit > 0 && ifp->if_drv_flags & IFF_DRV_RUNNING) 904291557Skevlo ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 905291557Skevlo else 906291557Skevlo reinit = 0; 907291557Skevlo URE_UNLOCK(sc); 908291557Skevlo if (reinit > 0) 909291557Skevlo uether_init(ue); 910291557Skevlo } else 911291557Skevlo error = uether_ioctl(ifp, cmd, data); 912291557Skevlo 913291557Skevlo return (error); 914291557Skevlo} 915291557Skevlo 916291557Skevlostatic void 917291557Skevloure_rtl8152_init(struct ure_softc *sc) 918291557Skevlo{ 919291557Skevlo uint32_t pwrctrl; 920291557Skevlo 921291557Skevlo /* Disable ALDPS. */ 922291557Skevlo ure_ocp_reg_write(sc, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | 923291557Skevlo URE_DIS_SDSAVE); 924291557Skevlo uether_pause(&sc->sc_ue, hz / 50); 925291557Skevlo 926291557Skevlo if (sc->sc_chip & URE_CHIP_VER_4C00) { 927291557Skevlo ure_write_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, 928291557Skevlo ure_read_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & 929291557Skevlo ~URE_LED_MODE_MASK); 930291557Skevlo } 931291557Skevlo 932291557Skevlo ure_write_2(sc, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB, 933291557Skevlo ure_read_2(sc, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB) & 934291557Skevlo ~URE_POWER_CUT); 935291557Skevlo ure_write_2(sc, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB, 936291557Skevlo ure_read_2(sc, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB) & 937291557Skevlo ~URE_RESUME_INDICATE); 938291557Skevlo 939291557Skevlo ure_write_2(sc, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, 940291557Skevlo ure_read_2(sc, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | 941291557Skevlo URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH); 942291557Skevlo pwrctrl = ure_read_4(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA); 943291557Skevlo pwrctrl &= ~URE_MCU_CLK_RATIO_MASK; 944291557Skevlo pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN; 945291557Skevlo ure_write_4(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl); 946291557Skevlo ure_write_2(sc, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA, 947291557Skevlo URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK | 948291557Skevlo URE_SPDWN_LINKCHG_MSK); 949291557Skevlo 950291557Skevlo /* Disable Rx aggregation. */ 951291557Skevlo ure_write_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, 952291557Skevlo ure_read_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) | 953291557Skevlo URE_RX_AGG_DISABLE); 954291557Skevlo 955291557Skevlo /* Disable ALDPS. */ 956291557Skevlo ure_ocp_reg_write(sc, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | 957291557Skevlo URE_DIS_SDSAVE); 958291557Skevlo uether_pause(&sc->sc_ue, hz / 50); 959291557Skevlo 960291557Skevlo ure_init_fifo(sc); 961291557Skevlo 962291557Skevlo ure_write_1(sc, URE_USB_TX_AGG, URE_MCU_TYPE_USB, 963291557Skevlo URE_TX_AGG_MAX_THRESHOLD); 964291557Skevlo ure_write_4(sc, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH); 965291557Skevlo ure_write_4(sc, URE_USB_TX_DMA, URE_MCU_TYPE_USB, 966291557Skevlo URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1); 967291557Skevlo} 968291557Skevlo 969291557Skevlostatic void 970291557Skevloure_stop(struct usb_ether *ue) 971291557Skevlo{ 972291557Skevlo struct ure_softc *sc = uether_getsc(ue); 973291557Skevlo struct ifnet *ifp = uether_getifp(ue); 974291557Skevlo 975291557Skevlo URE_LOCK_ASSERT(sc, MA_OWNED); 976291557Skevlo 977291557Skevlo ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 978291557Skevlo sc->sc_flags &= ~URE_FLAG_LINK; 979291557Skevlo 980291557Skevlo /* 981291557Skevlo * stop all the transfers, if not already stopped: 982291557Skevlo */ 983291557Skevlo usbd_transfer_stop(sc->sc_xfer[URE_BULK_DT_WR]); 984291557Skevlo usbd_transfer_stop(sc->sc_xfer[URE_BULK_DT_RD]); 985291557Skevlo} 986291557Skevlo 987291557Skevlostatic void 988291557Skevloure_disable_teredo(struct ure_softc *sc) 989291557Skevlo{ 990291557Skevlo 991291557Skevlo ure_write_4(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA, 992291557Skevlo ure_read_4(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) & 993291557Skevlo ~(URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN)); 994291557Skevlo ure_write_2(sc, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA, 995291557Skevlo URE_WDT6_SET_MODE); 996291557Skevlo ure_write_2(sc, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0); 997291557Skevlo ure_write_4(sc, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0); 998291557Skevlo} 999291557Skevlo 1000291557Skevlostatic void 1001291557Skevloure_init_fifo(struct ure_softc *sc) 1002291557Skevlo{ 1003291557Skevlo uint32_t rx_fifo1, rx_fifo2; 1004291557Skevlo int i; 1005291557Skevlo 1006291557Skevlo ure_write_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, 1007291557Skevlo ure_read_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) | 1008291557Skevlo URE_RXDY_GATED_EN); 1009291557Skevlo 1010291557Skevlo ure_disable_teredo(sc); 1011291557Skevlo 1012291557Skevlo ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, 1013291557Skevlo ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA) & 1014291557Skevlo ~URE_RCR_ACPT_ALL); 1015291557Skevlo 1016291557Skevlo ure_reset(sc); 1017291557Skevlo 1018291557Skevlo ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, 0); 1019291557Skevlo 1020291557Skevlo ure_write_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, 1021291557Skevlo ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & 1022291557Skevlo ~URE_NOW_IS_OOB); 1023291557Skevlo 1024291557Skevlo ure_write_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, 1025291557Skevlo ure_read_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) & 1026291557Skevlo ~URE_MCU_BORW_EN); 1027291557Skevlo for (i = 0; i < URE_TIMEOUT; i++) { 1028291557Skevlo if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & 1029291557Skevlo URE_LINK_LIST_READY) 1030291557Skevlo break; 1031291557Skevlo uether_pause(&sc->sc_ue, hz / 100); 1032291557Skevlo } 1033291557Skevlo if (i == URE_TIMEOUT) 1034291557Skevlo device_printf(sc->sc_ue.ue_dev, 1035291557Skevlo "timeout waiting for OOB control\n"); 1036291557Skevlo ure_write_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, 1037291557Skevlo ure_read_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) | 1038291557Skevlo URE_RE_INIT_LL); 1039291557Skevlo for (i = 0; i < URE_TIMEOUT; i++) { 1040291557Skevlo if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & 1041291557Skevlo URE_LINK_LIST_READY) 1042291557Skevlo break; 1043291557Skevlo uether_pause(&sc->sc_ue, hz / 100); 1044291557Skevlo } 1045291557Skevlo if (i == URE_TIMEOUT) 1046291557Skevlo device_printf(sc->sc_ue.ue_dev, 1047291557Skevlo "timeout waiting for OOB control\n"); 1048291557Skevlo 1049291557Skevlo ure_write_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA, 1050291557Skevlo ure_read_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA) & 1051291557Skevlo ~URE_CPCR_RX_VLAN); 1052291557Skevlo ure_write_2(sc, URE_PLA_TCR0, URE_MCU_TYPE_PLA, 1053291557Skevlo ure_read_2(sc, URE_PLA_TCR0, URE_MCU_TYPE_PLA) | 1054291557Skevlo URE_TCR0_AUTO_FIFO); 1055291557Skevlo 1056291557Skevlo /* Configure Rx FIFO threshold. */ 1057291557Skevlo ure_write_4(sc, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA, 1058291557Skevlo URE_RXFIFO_THR1_NORMAL); 1059291557Skevlo if (usbd_get_speed(sc->sc_ue.ue_udev) == USB_SPEED_FULL) { 1060291557Skevlo rx_fifo1 = URE_RXFIFO_THR2_FULL; 1061291557Skevlo rx_fifo2 = URE_RXFIFO_THR3_FULL; 1062291557Skevlo } else { 1063291557Skevlo rx_fifo1 = URE_RXFIFO_THR2_HIGH; 1064291557Skevlo rx_fifo2 = URE_RXFIFO_THR3_HIGH; 1065291557Skevlo } 1066291557Skevlo ure_write_4(sc, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1); 1067291557Skevlo ure_write_4(sc, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2); 1068291557Skevlo 1069291557Skevlo /* Configure Tx FIFO threshold. */ 1070291557Skevlo ure_write_4(sc, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, 1071291557Skevlo URE_TXFIFO_THR_NORMAL); 1072291557Skevlo} 1073