1e1b74f21SKevin Lo /*- 2a24d62b5SKevin Lo * Copyright (c) 2015-2016 Kevin Lo <kevlo@FreeBSD.org> 3e1b74f21SKevin Lo * All rights reserved. 4e1b74f21SKevin Lo * 5e1b74f21SKevin Lo * Redistribution and use in source and binary forms, with or without 6e1b74f21SKevin Lo * modification, are permitted provided that the following conditions 7e1b74f21SKevin Lo * are met: 8e1b74f21SKevin Lo * 1. Redistributions of source code must retain the above copyright 9e1b74f21SKevin Lo * notice, this list of conditions and the following disclaimer. 10e1b74f21SKevin Lo * 2. Redistributions in binary form must reproduce the above copyright 11e1b74f21SKevin Lo * notice, this list of conditions and the following disclaimer in the 12e1b74f21SKevin Lo * documentation and/or other materials provided with the distribution. 13e1b74f21SKevin Lo * 14e1b74f21SKevin Lo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15e1b74f21SKevin Lo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16e1b74f21SKevin Lo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17e1b74f21SKevin Lo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18e1b74f21SKevin Lo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19e1b74f21SKevin Lo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20e1b74f21SKevin Lo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21e1b74f21SKevin Lo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22e1b74f21SKevin Lo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23e1b74f21SKevin Lo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24e1b74f21SKevin Lo * SUCH DAMAGE. 25e1b74f21SKevin Lo */ 26e1b74f21SKevin Lo 27e1b74f21SKevin Lo #include <sys/cdefs.h> 28e1b74f21SKevin Lo __FBSDID("$FreeBSD$"); 29e1b74f21SKevin Lo 30e1b74f21SKevin Lo #include <sys/param.h> 31e1b74f21SKevin Lo #include <sys/systm.h> 32e1b74f21SKevin Lo #include <sys/bus.h> 33e1b74f21SKevin Lo #include <sys/condvar.h> 34e1b74f21SKevin Lo #include <sys/kernel.h> 35e1b74f21SKevin Lo #include <sys/lock.h> 36e1b74f21SKevin Lo #include <sys/module.h> 37e1b74f21SKevin Lo #include <sys/mutex.h> 38e1b74f21SKevin Lo #include <sys/socket.h> 39e1b74f21SKevin Lo #include <sys/sysctl.h> 40e1b74f21SKevin Lo #include <sys/unistd.h> 41e1b74f21SKevin Lo 42e1b74f21SKevin Lo #include <net/if.h> 43e1b74f21SKevin Lo #include <net/if_var.h> 4431c484adSJustin Hibbits #include <net/if_media.h> 4531c484adSJustin Hibbits 4631c484adSJustin Hibbits #include <dev/mii/mii.h> 4731c484adSJustin Hibbits #include <dev/mii/miivar.h> 48e1b74f21SKevin Lo 49e1b74f21SKevin Lo #include <dev/usb/usb.h> 50e1b74f21SKevin Lo #include <dev/usb/usbdi.h> 51e1b74f21SKevin Lo #include <dev/usb/usbdi_util.h> 52e1b74f21SKevin Lo #include "usbdevs.h" 53e1b74f21SKevin Lo 54e1b74f21SKevin Lo #define USB_DEBUG_VAR ure_debug 55e1b74f21SKevin Lo #include <dev/usb/usb_debug.h> 56e1b74f21SKevin Lo #include <dev/usb/usb_process.h> 57e1b74f21SKevin Lo 58e1b74f21SKevin Lo #include <dev/usb/net/usb_ethernet.h> 59e1b74f21SKevin Lo #include <dev/usb/net/if_urereg.h> 60e1b74f21SKevin Lo 6131c484adSJustin Hibbits #include "miibus_if.h" 6231c484adSJustin Hibbits 63e1b74f21SKevin Lo #ifdef USB_DEBUG 64e1b74f21SKevin Lo static int ure_debug = 0; 65e1b74f21SKevin Lo 66e1b74f21SKevin Lo static SYSCTL_NODE(_hw_usb, OID_AUTO, ure, CTLFLAG_RW, 0, "USB ure"); 67e1b74f21SKevin Lo SYSCTL_INT(_hw_usb_ure, OID_AUTO, debug, CTLFLAG_RWTUN, &ure_debug, 0, 68e1b74f21SKevin Lo "Debug level"); 69e1b74f21SKevin Lo #endif 70e1b74f21SKevin Lo 71cef38d45SGanbold Tsagaankhuu #define ETHER_IS_ZERO(addr) \ 72cef38d45SGanbold Tsagaankhuu (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) 73cef38d45SGanbold Tsagaankhuu 74e1b74f21SKevin Lo /* 75e1b74f21SKevin Lo * Various supported device vendors/products. 76e1b74f21SKevin Lo */ 77e1b74f21SKevin Lo static const STRUCT_USB_HOST_ID ure_devs[] = { 78a24d62b5SKevin Lo #define URE_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } 7921d36c96SKevin Lo URE_DEV(LENOVO, RTL8153, 0), 80146ebc76SPoul-Henning Kamp URE_DEV(LENOVO, TBT3LAN, 0), 81afa9b036SGavin Atkinson URE_DEV(LENOVO, ONELINK, 0), 82146ebc76SPoul-Henning Kamp URE_DEV(LENOVO, USBCLAN, 0), 8323242e7aSMichal Meloun URE_DEV(NVIDIA, RTL8153, 0), 84a24d62b5SKevin Lo URE_DEV(REALTEK, RTL8152, URE_FLAG_8152), 85a24d62b5SKevin Lo URE_DEV(REALTEK, RTL8153, 0), 86ccaf7ad4SKevin Lo URE_DEV(TPLINK, RTL8153, 0), 87e1b74f21SKevin Lo #undef URE_DEV 88e1b74f21SKevin Lo }; 89e1b74f21SKevin Lo 90e1b74f21SKevin Lo static device_probe_t ure_probe; 91e1b74f21SKevin Lo static device_attach_t ure_attach; 92e1b74f21SKevin Lo static device_detach_t ure_detach; 93e1b74f21SKevin Lo 94e1b74f21SKevin Lo static usb_callback_t ure_bulk_read_callback; 95e1b74f21SKevin Lo static usb_callback_t ure_bulk_write_callback; 96e1b74f21SKevin Lo 97e1b74f21SKevin Lo static miibus_readreg_t ure_miibus_readreg; 98e1b74f21SKevin Lo static miibus_writereg_t ure_miibus_writereg; 99e1b74f21SKevin Lo static miibus_statchg_t ure_miibus_statchg; 100e1b74f21SKevin Lo 101e1b74f21SKevin Lo static uether_fn_t ure_attach_post; 102e1b74f21SKevin Lo static uether_fn_t ure_init; 103e1b74f21SKevin Lo static uether_fn_t ure_stop; 104e1b74f21SKevin Lo static uether_fn_t ure_start; 105e1b74f21SKevin Lo static uether_fn_t ure_tick; 106a24d62b5SKevin Lo static uether_fn_t ure_rxfilter; 107e1b74f21SKevin Lo 108e1b74f21SKevin Lo static int ure_ctl(struct ure_softc *, uint8_t, uint16_t, uint16_t, 109e1b74f21SKevin Lo void *, int); 110e1b74f21SKevin Lo static int ure_read_mem(struct ure_softc *, uint16_t, uint16_t, void *, 111e1b74f21SKevin Lo int); 112e1b74f21SKevin Lo static int ure_write_mem(struct ure_softc *, uint16_t, uint16_t, void *, 113e1b74f21SKevin Lo int); 114e1b74f21SKevin Lo static uint8_t ure_read_1(struct ure_softc *, uint16_t, uint16_t); 115e1b74f21SKevin Lo static uint16_t ure_read_2(struct ure_softc *, uint16_t, uint16_t); 116e1b74f21SKevin Lo static uint32_t ure_read_4(struct ure_softc *, uint16_t, uint16_t); 117e1b74f21SKevin Lo static int ure_write_1(struct ure_softc *, uint16_t, uint16_t, uint32_t); 118e1b74f21SKevin Lo static int ure_write_2(struct ure_softc *, uint16_t, uint16_t, uint32_t); 119e1b74f21SKevin Lo static int ure_write_4(struct ure_softc *, uint16_t, uint16_t, uint32_t); 120e1b74f21SKevin Lo static uint16_t ure_ocp_reg_read(struct ure_softc *, uint16_t); 121e1b74f21SKevin Lo static void ure_ocp_reg_write(struct ure_softc *, uint16_t, uint16_t); 122e1b74f21SKevin Lo 123e1b74f21SKevin Lo static void ure_read_chipver(struct ure_softc *); 124e1b74f21SKevin Lo static int ure_attach_post_sub(struct usb_ether *); 125e1b74f21SKevin Lo static void ure_reset(struct ure_softc *); 126e1b74f21SKevin Lo static int ure_ifmedia_upd(struct ifnet *); 127e1b74f21SKevin Lo static void ure_ifmedia_sts(struct ifnet *, struct ifmediareq *); 128e1b74f21SKevin Lo static int ure_ioctl(struct ifnet *, u_long, caddr_t); 129e1b74f21SKevin Lo static void ure_rtl8152_init(struct ure_softc *); 130a24d62b5SKevin Lo static void ure_rtl8153_init(struct ure_softc *); 131e1b74f21SKevin Lo static void ure_disable_teredo(struct ure_softc *); 132e1b74f21SKevin Lo static void ure_init_fifo(struct ure_softc *); 133e1b74f21SKevin Lo 134e1b74f21SKevin Lo static const struct usb_config ure_config[URE_N_TRANSFER] = { 135e1b74f21SKevin Lo [URE_BULK_DT_WR] = { 136e1b74f21SKevin Lo .type = UE_BULK, 137e1b74f21SKevin Lo .endpoint = UE_ADDR_ANY, 138e1b74f21SKevin Lo .direction = UE_DIR_OUT, 139e1b74f21SKevin Lo .bufsize = MCLBYTES, 140e1b74f21SKevin Lo .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 141e1b74f21SKevin Lo .callback = ure_bulk_write_callback, 142e1b74f21SKevin Lo .timeout = 10000, /* 10 seconds */ 143e1b74f21SKevin Lo }, 144e1b74f21SKevin Lo [URE_BULK_DT_RD] = { 145e1b74f21SKevin Lo .type = UE_BULK, 146e1b74f21SKevin Lo .endpoint = UE_ADDR_ANY, 147e1b74f21SKevin Lo .direction = UE_DIR_IN, 148a24d62b5SKevin Lo .bufsize = 16384, 149e1b74f21SKevin Lo .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 150e1b74f21SKevin Lo .callback = ure_bulk_read_callback, 151e1b74f21SKevin Lo .timeout = 0, /* no timeout */ 152e1b74f21SKevin Lo }, 153e1b74f21SKevin Lo }; 154e1b74f21SKevin Lo 155e1b74f21SKevin Lo static device_method_t ure_methods[] = { 156e1b74f21SKevin Lo /* Device interface. */ 157e1b74f21SKevin Lo DEVMETHOD(device_probe, ure_probe), 158e1b74f21SKevin Lo DEVMETHOD(device_attach, ure_attach), 159e1b74f21SKevin Lo DEVMETHOD(device_detach, ure_detach), 160e1b74f21SKevin Lo 161e1b74f21SKevin Lo /* MII interface. */ 162e1b74f21SKevin Lo DEVMETHOD(miibus_readreg, ure_miibus_readreg), 163e1b74f21SKevin Lo DEVMETHOD(miibus_writereg, ure_miibus_writereg), 164e1b74f21SKevin Lo DEVMETHOD(miibus_statchg, ure_miibus_statchg), 165e1b74f21SKevin Lo 166e1b74f21SKevin Lo DEVMETHOD_END 167e1b74f21SKevin Lo }; 168e1b74f21SKevin Lo 169e1b74f21SKevin Lo static driver_t ure_driver = { 170e1b74f21SKevin Lo .name = "ure", 171e1b74f21SKevin Lo .methods = ure_methods, 172e1b74f21SKevin Lo .size = sizeof(struct ure_softc), 173e1b74f21SKevin Lo }; 174e1b74f21SKevin Lo 175e1b74f21SKevin Lo static devclass_t ure_devclass; 176e1b74f21SKevin Lo 177e1b74f21SKevin Lo DRIVER_MODULE(ure, uhub, ure_driver, ure_devclass, NULL, NULL); 178e1b74f21SKevin Lo DRIVER_MODULE(miibus, ure, miibus_driver, miibus_devclass, NULL, NULL); 179e1b74f21SKevin Lo MODULE_DEPEND(ure, uether, 1, 1, 1); 180e1b74f21SKevin Lo MODULE_DEPEND(ure, usb, 1, 1, 1); 181e1b74f21SKevin Lo MODULE_DEPEND(ure, ether, 1, 1, 1); 182e1b74f21SKevin Lo MODULE_DEPEND(ure, miibus, 1, 1, 1); 183e1b74f21SKevin Lo MODULE_VERSION(ure, 1); 18472851e85SAllan Jude USB_PNP_HOST_INFO(ure_devs); 185e1b74f21SKevin Lo 186e1b74f21SKevin Lo static const struct usb_ether_methods ure_ue_methods = { 187e1b74f21SKevin Lo .ue_attach_post = ure_attach_post, 188e1b74f21SKevin Lo .ue_attach_post_sub = ure_attach_post_sub, 189e1b74f21SKevin Lo .ue_start = ure_start, 190e1b74f21SKevin Lo .ue_init = ure_init, 191e1b74f21SKevin Lo .ue_stop = ure_stop, 192e1b74f21SKevin Lo .ue_tick = ure_tick, 193a24d62b5SKevin Lo .ue_setmulti = ure_rxfilter, 194a24d62b5SKevin Lo .ue_setpromisc = ure_rxfilter, 195e1b74f21SKevin Lo .ue_mii_upd = ure_ifmedia_upd, 196e1b74f21SKevin Lo .ue_mii_sts = ure_ifmedia_sts, 197e1b74f21SKevin Lo }; 198e1b74f21SKevin Lo 199e1b74f21SKevin Lo static int 200e1b74f21SKevin Lo ure_ctl(struct ure_softc *sc, uint8_t rw, uint16_t val, uint16_t index, 201e1b74f21SKevin Lo void *buf, int len) 202e1b74f21SKevin Lo { 203e1b74f21SKevin Lo struct usb_device_request req; 204e1b74f21SKevin Lo 205e1b74f21SKevin Lo URE_LOCK_ASSERT(sc, MA_OWNED); 206e1b74f21SKevin Lo 207e1b74f21SKevin Lo if (rw == URE_CTL_WRITE) 208e1b74f21SKevin Lo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 209e1b74f21SKevin Lo else 210e1b74f21SKevin Lo req.bmRequestType = UT_READ_VENDOR_DEVICE; 211e1b74f21SKevin Lo req.bRequest = UR_SET_ADDRESS; 212e1b74f21SKevin Lo USETW(req.wValue, val); 213e1b74f21SKevin Lo USETW(req.wIndex, index); 214e1b74f21SKevin Lo USETW(req.wLength, len); 215e1b74f21SKevin Lo 216e1b74f21SKevin Lo return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 217e1b74f21SKevin Lo } 218e1b74f21SKevin Lo 219e1b74f21SKevin Lo static int 220e1b74f21SKevin Lo ure_read_mem(struct ure_softc *sc, uint16_t addr, uint16_t index, 221e1b74f21SKevin Lo void *buf, int len) 222e1b74f21SKevin Lo { 223e1b74f21SKevin Lo 224e1b74f21SKevin Lo return (ure_ctl(sc, URE_CTL_READ, addr, index, buf, len)); 225e1b74f21SKevin Lo } 226e1b74f21SKevin Lo 227e1b74f21SKevin Lo static int 228e1b74f21SKevin Lo ure_write_mem(struct ure_softc *sc, uint16_t addr, uint16_t index, 229e1b74f21SKevin Lo void *buf, int len) 230e1b74f21SKevin Lo { 231e1b74f21SKevin Lo 232e1b74f21SKevin Lo return (ure_ctl(sc, URE_CTL_WRITE, addr, index, buf, len)); 233e1b74f21SKevin Lo } 234e1b74f21SKevin Lo 235e1b74f21SKevin Lo static uint8_t 236e1b74f21SKevin Lo ure_read_1(struct ure_softc *sc, uint16_t reg, uint16_t index) 237e1b74f21SKevin Lo { 238e1b74f21SKevin Lo uint32_t val; 239e1b74f21SKevin Lo uint8_t temp[4]; 240e1b74f21SKevin Lo uint8_t shift; 241e1b74f21SKevin Lo 242e1b74f21SKevin Lo shift = (reg & 3) << 3; 243e1b74f21SKevin Lo reg &= ~3; 244e1b74f21SKevin Lo 245e1b74f21SKevin Lo ure_read_mem(sc, reg, index, &temp, 4); 246e1b74f21SKevin Lo val = UGETDW(temp); 247e1b74f21SKevin Lo val >>= shift; 248e1b74f21SKevin Lo 249e1b74f21SKevin Lo return (val & 0xff); 250e1b74f21SKevin Lo } 251e1b74f21SKevin Lo 252e1b74f21SKevin Lo static uint16_t 253e1b74f21SKevin Lo ure_read_2(struct ure_softc *sc, uint16_t reg, uint16_t index) 254e1b74f21SKevin Lo { 255e1b74f21SKevin Lo uint32_t val; 256e1b74f21SKevin Lo uint8_t temp[4]; 257e1b74f21SKevin Lo uint8_t shift; 258e1b74f21SKevin Lo 259e1b74f21SKevin Lo shift = (reg & 2) << 3; 260e1b74f21SKevin Lo reg &= ~3; 261e1b74f21SKevin Lo 262e1b74f21SKevin Lo ure_read_mem(sc, reg, index, &temp, 4); 263e1b74f21SKevin Lo val = UGETDW(temp); 264e1b74f21SKevin Lo val >>= shift; 265e1b74f21SKevin Lo 266e1b74f21SKevin Lo return (val & 0xffff); 267e1b74f21SKevin Lo } 268e1b74f21SKevin Lo 269e1b74f21SKevin Lo static uint32_t 270e1b74f21SKevin Lo ure_read_4(struct ure_softc *sc, uint16_t reg, uint16_t index) 271e1b74f21SKevin Lo { 272e1b74f21SKevin Lo uint8_t temp[4]; 273e1b74f21SKevin Lo 274e1b74f21SKevin Lo ure_read_mem(sc, reg, index, &temp, 4); 275e1b74f21SKevin Lo return (UGETDW(temp)); 276e1b74f21SKevin Lo } 277e1b74f21SKevin Lo 278e1b74f21SKevin Lo static int 279e1b74f21SKevin Lo ure_write_1(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val) 280e1b74f21SKevin Lo { 281e1b74f21SKevin Lo uint16_t byen; 282e1b74f21SKevin Lo uint8_t temp[4]; 283e1b74f21SKevin Lo uint8_t shift; 284e1b74f21SKevin Lo 285e1b74f21SKevin Lo byen = URE_BYTE_EN_BYTE; 286e1b74f21SKevin Lo shift = reg & 3; 287e1b74f21SKevin Lo val &= 0xff; 288e1b74f21SKevin Lo 289e1b74f21SKevin Lo if (reg & 3) { 290e1b74f21SKevin Lo byen <<= shift; 291e1b74f21SKevin Lo val <<= (shift << 3); 292e1b74f21SKevin Lo reg &= ~3; 293e1b74f21SKevin Lo } 294e1b74f21SKevin Lo 295e1b74f21SKevin Lo USETDW(temp, val); 296e1b74f21SKevin Lo return (ure_write_mem(sc, reg, index | byen, &temp, 4)); 297e1b74f21SKevin Lo } 298e1b74f21SKevin Lo 299e1b74f21SKevin Lo static int 300e1b74f21SKevin Lo ure_write_2(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val) 301e1b74f21SKevin Lo { 302e1b74f21SKevin Lo uint16_t byen; 303e1b74f21SKevin Lo uint8_t temp[4]; 304e1b74f21SKevin Lo uint8_t shift; 305e1b74f21SKevin Lo 306e1b74f21SKevin Lo byen = URE_BYTE_EN_WORD; 307e1b74f21SKevin Lo shift = reg & 2; 308e1b74f21SKevin Lo val &= 0xffff; 309e1b74f21SKevin Lo 310e1b74f21SKevin Lo if (reg & 2) { 311e1b74f21SKevin Lo byen <<= shift; 312e1b74f21SKevin Lo val <<= (shift << 3); 313e1b74f21SKevin Lo reg &= ~3; 314e1b74f21SKevin Lo } 315e1b74f21SKevin Lo 316e1b74f21SKevin Lo USETDW(temp, val); 317e1b74f21SKevin Lo return (ure_write_mem(sc, reg, index | byen, &temp, 4)); 318e1b74f21SKevin Lo } 319e1b74f21SKevin Lo 320e1b74f21SKevin Lo static int 321e1b74f21SKevin Lo ure_write_4(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val) 322e1b74f21SKevin Lo { 323e1b74f21SKevin Lo uint8_t temp[4]; 324e1b74f21SKevin Lo 325e1b74f21SKevin Lo USETDW(temp, val); 326e1b74f21SKevin Lo return (ure_write_mem(sc, reg, index | URE_BYTE_EN_DWORD, &temp, 4)); 327e1b74f21SKevin Lo } 328e1b74f21SKevin Lo 329e1b74f21SKevin Lo static uint16_t 330e1b74f21SKevin Lo ure_ocp_reg_read(struct ure_softc *sc, uint16_t addr) 331e1b74f21SKevin Lo { 332e1b74f21SKevin Lo uint16_t reg; 333e1b74f21SKevin Lo 334e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); 335e1b74f21SKevin Lo reg = (addr & 0x0fff) | 0xb000; 336e1b74f21SKevin Lo 337e1b74f21SKevin Lo return (ure_read_2(sc, reg, URE_MCU_TYPE_PLA)); 338e1b74f21SKevin Lo } 339e1b74f21SKevin Lo 340e1b74f21SKevin Lo static void 341e1b74f21SKevin Lo ure_ocp_reg_write(struct ure_softc *sc, uint16_t addr, uint16_t data) 342e1b74f21SKevin Lo { 343e1b74f21SKevin Lo uint16_t reg; 344e1b74f21SKevin Lo 345e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); 346e1b74f21SKevin Lo reg = (addr & 0x0fff) | 0xb000; 347e1b74f21SKevin Lo 348e1b74f21SKevin Lo ure_write_2(sc, reg, URE_MCU_TYPE_PLA, data); 349e1b74f21SKevin Lo } 350e1b74f21SKevin Lo 351e1b74f21SKevin Lo static int 352e1b74f21SKevin Lo ure_miibus_readreg(device_t dev, int phy, int reg) 353e1b74f21SKevin Lo { 354e1b74f21SKevin Lo struct ure_softc *sc; 355e1b74f21SKevin Lo uint16_t val; 356e1b74f21SKevin Lo int locked; 357e1b74f21SKevin Lo 358e1b74f21SKevin Lo sc = device_get_softc(dev); 359e1b74f21SKevin Lo locked = mtx_owned(&sc->sc_mtx); 360e1b74f21SKevin Lo if (!locked) 361e1b74f21SKevin Lo URE_LOCK(sc); 362e1b74f21SKevin Lo 363a24d62b5SKevin Lo /* Let the rgephy driver read the URE_GMEDIASTAT register. */ 364a24d62b5SKevin Lo if (reg == URE_GMEDIASTAT) { 365a24d62b5SKevin Lo if (!locked) 366a24d62b5SKevin Lo URE_UNLOCK(sc); 367a24d62b5SKevin Lo return (ure_read_1(sc, URE_GMEDIASTAT, URE_MCU_TYPE_PLA)); 368a24d62b5SKevin Lo } 369a24d62b5SKevin Lo 370e1b74f21SKevin Lo val = ure_ocp_reg_read(sc, URE_OCP_BASE_MII + reg * 2); 371e1b74f21SKevin Lo 372e1b74f21SKevin Lo if (!locked) 373e1b74f21SKevin Lo URE_UNLOCK(sc); 374e1b74f21SKevin Lo return (val); 375e1b74f21SKevin Lo } 376e1b74f21SKevin Lo 377e1b74f21SKevin Lo static int 378e1b74f21SKevin Lo ure_miibus_writereg(device_t dev, int phy, int reg, int val) 379e1b74f21SKevin Lo { 380e1b74f21SKevin Lo struct ure_softc *sc; 381e1b74f21SKevin Lo int locked; 382e1b74f21SKevin Lo 383e1b74f21SKevin Lo sc = device_get_softc(dev); 384e1b74f21SKevin Lo if (sc->sc_phyno != phy) 385e1b74f21SKevin Lo return (0); 386e1b74f21SKevin Lo 387e1b74f21SKevin Lo locked = mtx_owned(&sc->sc_mtx); 388e1b74f21SKevin Lo if (!locked) 389e1b74f21SKevin Lo URE_LOCK(sc); 390e1b74f21SKevin Lo 391e1b74f21SKevin Lo ure_ocp_reg_write(sc, URE_OCP_BASE_MII + reg * 2, val); 392e1b74f21SKevin Lo 393e1b74f21SKevin Lo if (!locked) 394e1b74f21SKevin Lo URE_UNLOCK(sc); 395e1b74f21SKevin Lo return (0); 396e1b74f21SKevin Lo } 397e1b74f21SKevin Lo 398e1b74f21SKevin Lo static void 399e1b74f21SKevin Lo ure_miibus_statchg(device_t dev) 400e1b74f21SKevin Lo { 401e1b74f21SKevin Lo struct ure_softc *sc; 402e1b74f21SKevin Lo struct mii_data *mii; 403e1b74f21SKevin Lo struct ifnet *ifp; 404e1b74f21SKevin Lo int locked; 405e1b74f21SKevin Lo 406e1b74f21SKevin Lo sc = device_get_softc(dev); 407e1b74f21SKevin Lo mii = GET_MII(sc); 408e1b74f21SKevin Lo locked = mtx_owned(&sc->sc_mtx); 409e1b74f21SKevin Lo if (!locked) 410e1b74f21SKevin Lo URE_LOCK(sc); 411e1b74f21SKevin Lo 412e1b74f21SKevin Lo ifp = uether_getifp(&sc->sc_ue); 413e1b74f21SKevin Lo if (mii == NULL || ifp == NULL || 414e1b74f21SKevin Lo (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 415e1b74f21SKevin Lo goto done; 416e1b74f21SKevin Lo 417e1b74f21SKevin Lo sc->sc_flags &= ~URE_FLAG_LINK; 418e1b74f21SKevin Lo if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 419e1b74f21SKevin Lo (IFM_ACTIVE | IFM_AVALID)) { 420e1b74f21SKevin Lo switch (IFM_SUBTYPE(mii->mii_media_active)) { 421e1b74f21SKevin Lo case IFM_10_T: 422e1b74f21SKevin Lo case IFM_100_TX: 423e1b74f21SKevin Lo sc->sc_flags |= URE_FLAG_LINK; 424e1b74f21SKevin Lo break; 425a24d62b5SKevin Lo case IFM_1000_T: 426a24d62b5SKevin Lo if ((sc->sc_flags & URE_FLAG_8152) != 0) 427a24d62b5SKevin Lo break; 428a24d62b5SKevin Lo sc->sc_flags |= URE_FLAG_LINK; 429a24d62b5SKevin Lo break; 430e1b74f21SKevin Lo default: 431e1b74f21SKevin Lo break; 432e1b74f21SKevin Lo } 433e1b74f21SKevin Lo } 434e1b74f21SKevin Lo 435e1b74f21SKevin Lo /* Lost link, do nothing. */ 436e1b74f21SKevin Lo if ((sc->sc_flags & URE_FLAG_LINK) == 0) 437e1b74f21SKevin Lo goto done; 438e1b74f21SKevin Lo done: 439e1b74f21SKevin Lo if (!locked) 440e1b74f21SKevin Lo URE_UNLOCK(sc); 441e1b74f21SKevin Lo } 442e1b74f21SKevin Lo 443e1b74f21SKevin Lo /* 444a24d62b5SKevin Lo * Probe for a RTL8152/RTL8153 chip. 445e1b74f21SKevin Lo */ 446e1b74f21SKevin Lo static int 447e1b74f21SKevin Lo ure_probe(device_t dev) 448e1b74f21SKevin Lo { 449e1b74f21SKevin Lo struct usb_attach_arg *uaa; 450e1b74f21SKevin Lo 45174b8d63dSPedro F. Giffuni uaa = device_get_ivars(dev); 452e1b74f21SKevin Lo if (uaa->usb_mode != USB_MODE_HOST) 453e1b74f21SKevin Lo return (ENXIO); 454e1b74f21SKevin Lo if (uaa->info.bConfigIndex != URE_CONFIG_IDX) 455e1b74f21SKevin Lo return (ENXIO); 456e1b74f21SKevin Lo if (uaa->info.bIfaceIndex != URE_IFACE_IDX) 457e1b74f21SKevin Lo return (ENXIO); 458e1b74f21SKevin Lo 459e1b74f21SKevin Lo return (usbd_lookup_id_by_uaa(ure_devs, sizeof(ure_devs), uaa)); 460e1b74f21SKevin Lo } 461e1b74f21SKevin Lo 462e1b74f21SKevin Lo /* 463e1b74f21SKevin Lo * Attach the interface. Allocate softc structures, do ifmedia 464e1b74f21SKevin Lo * setup and ethernet/BPF attach. 465e1b74f21SKevin Lo */ 466e1b74f21SKevin Lo static int 467e1b74f21SKevin Lo ure_attach(device_t dev) 468e1b74f21SKevin Lo { 469e1b74f21SKevin Lo struct usb_attach_arg *uaa = device_get_ivars(dev); 470e1b74f21SKevin Lo struct ure_softc *sc = device_get_softc(dev); 471e1b74f21SKevin Lo struct usb_ether *ue = &sc->sc_ue; 472e1b74f21SKevin Lo uint8_t iface_index; 473e1b74f21SKevin Lo int error; 474e1b74f21SKevin Lo 475a24d62b5SKevin Lo sc->sc_flags = USB_GET_DRIVER_INFO(uaa); 476e1b74f21SKevin Lo device_set_usb_desc(dev); 477e1b74f21SKevin Lo mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 478e1b74f21SKevin Lo 479e1b74f21SKevin Lo iface_index = URE_IFACE_IDX; 480e1b74f21SKevin Lo error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, 481e1b74f21SKevin Lo ure_config, URE_N_TRANSFER, sc, &sc->sc_mtx); 482e1b74f21SKevin Lo if (error != 0) { 483e1b74f21SKevin Lo device_printf(dev, "allocating USB transfers failed\n"); 484e1b74f21SKevin Lo goto detach; 485e1b74f21SKevin Lo } 486e1b74f21SKevin Lo 487e1b74f21SKevin Lo ue->ue_sc = sc; 488e1b74f21SKevin Lo ue->ue_dev = dev; 489e1b74f21SKevin Lo ue->ue_udev = uaa->device; 490e1b74f21SKevin Lo ue->ue_mtx = &sc->sc_mtx; 491e1b74f21SKevin Lo ue->ue_methods = &ure_ue_methods; 492e1b74f21SKevin Lo 493e1b74f21SKevin Lo error = uether_ifattach(ue); 494e1b74f21SKevin Lo if (error != 0) { 495e1b74f21SKevin Lo device_printf(dev, "could not attach interface\n"); 496e1b74f21SKevin Lo goto detach; 497e1b74f21SKevin Lo } 498e1b74f21SKevin Lo return (0); /* success */ 499e1b74f21SKevin Lo 500e1b74f21SKevin Lo detach: 501e1b74f21SKevin Lo ure_detach(dev); 502e1b74f21SKevin Lo return (ENXIO); /* failure */ 503e1b74f21SKevin Lo } 504e1b74f21SKevin Lo 505e1b74f21SKevin Lo static int 506e1b74f21SKevin Lo ure_detach(device_t dev) 507e1b74f21SKevin Lo { 508e1b74f21SKevin Lo struct ure_softc *sc = device_get_softc(dev); 509e1b74f21SKevin Lo struct usb_ether *ue = &sc->sc_ue; 510e1b74f21SKevin Lo 511e1b74f21SKevin Lo usbd_transfer_unsetup(sc->sc_xfer, URE_N_TRANSFER); 512e1b74f21SKevin Lo uether_ifdetach(ue); 513e1b74f21SKevin Lo mtx_destroy(&sc->sc_mtx); 514e1b74f21SKevin Lo 515e1b74f21SKevin Lo return (0); 516e1b74f21SKevin Lo } 517e1b74f21SKevin Lo 518e1b74f21SKevin Lo static void 519e1b74f21SKevin Lo ure_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 520e1b74f21SKevin Lo { 521e1b74f21SKevin Lo struct ure_softc *sc = usbd_xfer_softc(xfer); 522e1b74f21SKevin Lo struct usb_ether *ue = &sc->sc_ue; 523e1b74f21SKevin Lo struct ifnet *ifp = uether_getifp(ue); 524e1b74f21SKevin Lo struct usb_page_cache *pc; 525e1b74f21SKevin Lo struct ure_rxpkt pkt; 526e1b74f21SKevin Lo int actlen, len; 527e1b74f21SKevin Lo 528e1b74f21SKevin Lo usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 529e1b74f21SKevin Lo 530e1b74f21SKevin Lo switch (USB_GET_STATE(xfer)) { 531e1b74f21SKevin Lo case USB_ST_TRANSFERRED: 532e1b74f21SKevin Lo if (actlen < (int)(sizeof(pkt))) { 533e1b74f21SKevin Lo if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 534e1b74f21SKevin Lo goto tr_setup; 535e1b74f21SKevin Lo } 536e1b74f21SKevin Lo pc = usbd_xfer_get_frame(xfer, 0); 537e1b74f21SKevin Lo usbd_copy_out(pc, 0, &pkt, sizeof(pkt)); 538e1b74f21SKevin Lo len = le32toh(pkt.ure_pktlen) & URE_RXPKT_LEN_MASK; 539e1b74f21SKevin Lo len -= ETHER_CRC_LEN; 540e1b74f21SKevin Lo if (actlen < (int)(len + sizeof(pkt))) { 541e1b74f21SKevin Lo if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 542e1b74f21SKevin Lo goto tr_setup; 543e1b74f21SKevin Lo } 544e1b74f21SKevin Lo 545e1b74f21SKevin Lo uether_rxbuf(ue, pc, sizeof(pkt), len); 546e1b74f21SKevin Lo /* FALLTHROUGH */ 547e1b74f21SKevin Lo case USB_ST_SETUP: 548e1b74f21SKevin Lo tr_setup: 549e1b74f21SKevin Lo usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 550e1b74f21SKevin Lo usbd_transfer_submit(xfer); 551e1b74f21SKevin Lo uether_rxflush(ue); 552e1b74f21SKevin Lo return; 553e1b74f21SKevin Lo 554e1b74f21SKevin Lo default: /* Error */ 555e1b74f21SKevin Lo DPRINTF("bulk read error, %s\n", 556e1b74f21SKevin Lo usbd_errstr(error)); 557e1b74f21SKevin Lo 558e1b74f21SKevin Lo if (error != USB_ERR_CANCELLED) { 559e1b74f21SKevin Lo /* try to clear stall first */ 560e1b74f21SKevin Lo usbd_xfer_set_stall(xfer); 561e1b74f21SKevin Lo goto tr_setup; 562e1b74f21SKevin Lo } 563e1b74f21SKevin Lo return; 564e1b74f21SKevin Lo } 565e1b74f21SKevin Lo } 566e1b74f21SKevin Lo 567e1b74f21SKevin Lo static void 568e1b74f21SKevin Lo ure_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 569e1b74f21SKevin Lo { 570e1b74f21SKevin Lo struct ure_softc *sc = usbd_xfer_softc(xfer); 571e1b74f21SKevin Lo struct ifnet *ifp = uether_getifp(&sc->sc_ue); 572e1b74f21SKevin Lo struct usb_page_cache *pc; 573e1b74f21SKevin Lo struct mbuf *m; 574e1b74f21SKevin Lo struct ure_txpkt txpkt; 575e1b74f21SKevin Lo int len, pos; 576e1b74f21SKevin Lo 577e1b74f21SKevin Lo switch (USB_GET_STATE(xfer)) { 578e1b74f21SKevin Lo case USB_ST_TRANSFERRED: 579e1b74f21SKevin Lo DPRINTFN(11, "transfer complete\n"); 580e1b74f21SKevin Lo ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 581e1b74f21SKevin Lo /* FALLTHROUGH */ 582e1b74f21SKevin Lo case USB_ST_SETUP: 583e1b74f21SKevin Lo tr_setup: 584e1b74f21SKevin Lo if ((sc->sc_flags & URE_FLAG_LINK) == 0 || 585e1b74f21SKevin Lo (ifp->if_drv_flags & IFF_DRV_OACTIVE) != 0) { 586e1b74f21SKevin Lo /* 587e1b74f21SKevin Lo * don't send anything if there is no link ! 588e1b74f21SKevin Lo */ 589e1b74f21SKevin Lo return; 590e1b74f21SKevin Lo } 591e1b74f21SKevin Lo IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 592e1b74f21SKevin Lo if (m == NULL) 593e1b74f21SKevin Lo break; 594e1b74f21SKevin Lo pos = 0; 595e1b74f21SKevin Lo len = m->m_pkthdr.len; 596e1b74f21SKevin Lo pc = usbd_xfer_get_frame(xfer, 0); 597e1b74f21SKevin Lo memset(&txpkt, 0, sizeof(txpkt)); 598e1b74f21SKevin Lo txpkt.ure_pktlen = htole32((len & URE_TXPKT_LEN_MASK) | 599e1b74f21SKevin Lo URE_TKPKT_TX_FS | URE_TKPKT_TX_LS); 600e1b74f21SKevin Lo usbd_copy_in(pc, pos, &txpkt, sizeof(txpkt)); 601e1b74f21SKevin Lo pos += sizeof(txpkt); 602e1b74f21SKevin Lo usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len); 603e1b74f21SKevin Lo pos += m->m_pkthdr.len; 604e1b74f21SKevin Lo 605e1b74f21SKevin Lo if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 606e1b74f21SKevin Lo 607e1b74f21SKevin Lo /* 608e1b74f21SKevin Lo * If there's a BPF listener, bounce a copy 609e1b74f21SKevin Lo * of this frame to him. 610e1b74f21SKevin Lo */ 611e1b74f21SKevin Lo BPF_MTAP(ifp, m); 612e1b74f21SKevin Lo 613e1b74f21SKevin Lo m_freem(m); 614e1b74f21SKevin Lo 615e1b74f21SKevin Lo /* Set frame length. */ 616e1b74f21SKevin Lo usbd_xfer_set_frame_len(xfer, 0, pos); 617e1b74f21SKevin Lo 618e1b74f21SKevin Lo usbd_transfer_submit(xfer); 619e1b74f21SKevin Lo ifp->if_drv_flags |= IFF_DRV_OACTIVE; 620e1b74f21SKevin Lo return; 621e1b74f21SKevin Lo default: /* Error */ 622e1b74f21SKevin Lo DPRINTFN(11, "transfer error, %s\n", 623e1b74f21SKevin Lo usbd_errstr(error)); 624e1b74f21SKevin Lo 625e1b74f21SKevin Lo if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 626e1b74f21SKevin Lo ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 627e1b74f21SKevin Lo 628e1b74f21SKevin Lo if (error != USB_ERR_CANCELLED) { 629e1b74f21SKevin Lo /* try to clear stall first */ 630e1b74f21SKevin Lo usbd_xfer_set_stall(xfer); 631e1b74f21SKevin Lo goto tr_setup; 632e1b74f21SKevin Lo } 633e1b74f21SKevin Lo return; 634e1b74f21SKevin Lo } 635e1b74f21SKevin Lo } 636e1b74f21SKevin Lo 637e1b74f21SKevin Lo static void 638e1b74f21SKevin Lo ure_read_chipver(struct ure_softc *sc) 639e1b74f21SKevin Lo { 640e1b74f21SKevin Lo uint16_t ver; 641e1b74f21SKevin Lo 642e1b74f21SKevin Lo ver = ure_read_2(sc, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK; 643e1b74f21SKevin Lo switch (ver) { 644e1b74f21SKevin Lo case 0x4c00: 645e1b74f21SKevin Lo sc->sc_chip |= URE_CHIP_VER_4C00; 646e1b74f21SKevin Lo break; 647e1b74f21SKevin Lo case 0x4c10: 648e1b74f21SKevin Lo sc->sc_chip |= URE_CHIP_VER_4C10; 649e1b74f21SKevin Lo break; 650a24d62b5SKevin Lo case 0x5c00: 651a24d62b5SKevin Lo sc->sc_chip |= URE_CHIP_VER_5C00; 652a24d62b5SKevin Lo break; 653a24d62b5SKevin Lo case 0x5c10: 654a24d62b5SKevin Lo sc->sc_chip |= URE_CHIP_VER_5C10; 655a24d62b5SKevin Lo break; 656a24d62b5SKevin Lo case 0x5c20: 657a24d62b5SKevin Lo sc->sc_chip |= URE_CHIP_VER_5C20; 658a24d62b5SKevin Lo break; 659a24d62b5SKevin Lo case 0x5c30: 660a24d62b5SKevin Lo sc->sc_chip |= URE_CHIP_VER_5C30; 661a24d62b5SKevin Lo break; 662e1b74f21SKevin Lo default: 663e1b74f21SKevin Lo device_printf(sc->sc_ue.ue_dev, 664e1b74f21SKevin Lo "unknown version 0x%04x\n", ver); 665e1b74f21SKevin Lo break; 666e1b74f21SKevin Lo } 667e1b74f21SKevin Lo } 668e1b74f21SKevin Lo 669e1b74f21SKevin Lo static void 670e1b74f21SKevin Lo ure_attach_post(struct usb_ether *ue) 671e1b74f21SKevin Lo { 672e1b74f21SKevin Lo struct ure_softc *sc = uether_getsc(ue); 673e1b74f21SKevin Lo 674e1b74f21SKevin Lo sc->sc_phyno = 0; 675e1b74f21SKevin Lo 676e1b74f21SKevin Lo /* Determine the chip version. */ 677e1b74f21SKevin Lo ure_read_chipver(sc); 678e1b74f21SKevin Lo 679e1b74f21SKevin Lo /* Initialize controller and get station address. */ 680a24d62b5SKevin Lo if (sc->sc_flags & URE_FLAG_8152) 681e1b74f21SKevin Lo ure_rtl8152_init(sc); 682a24d62b5SKevin Lo else 683a24d62b5SKevin Lo ure_rtl8153_init(sc); 684e1b74f21SKevin Lo 685cef38d45SGanbold Tsagaankhuu if ((sc->sc_chip & URE_CHIP_VER_4C00) || 686cef38d45SGanbold Tsagaankhuu (sc->sc_chip & URE_CHIP_VER_4C10)) 687e1b74f21SKevin Lo ure_read_mem(sc, URE_PLA_IDR, URE_MCU_TYPE_PLA, 688e1b74f21SKevin Lo ue->ue_eaddr, 8); 689e1b74f21SKevin Lo else 690e1b74f21SKevin Lo ure_read_mem(sc, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, 691e1b74f21SKevin Lo ue->ue_eaddr, 8); 692cef38d45SGanbold Tsagaankhuu 693cef38d45SGanbold Tsagaankhuu if (ETHER_IS_ZERO(sc->sc_ue.ue_eaddr)) { 694cef38d45SGanbold Tsagaankhuu device_printf(sc->sc_ue.ue_dev, "MAC assigned randomly\n"); 695cef38d45SGanbold Tsagaankhuu arc4rand(sc->sc_ue.ue_eaddr, ETHER_ADDR_LEN, 0); 696cef38d45SGanbold Tsagaankhuu sc->sc_ue.ue_eaddr[0] &= ~0x01; /* unicast */ 697cef38d45SGanbold Tsagaankhuu sc->sc_ue.ue_eaddr[0] |= 0x02; /* locally administered */ 698cef38d45SGanbold Tsagaankhuu } 699e1b74f21SKevin Lo } 700e1b74f21SKevin Lo 701e1b74f21SKevin Lo static int 702e1b74f21SKevin Lo ure_attach_post_sub(struct usb_ether *ue) 703e1b74f21SKevin Lo { 704e1b74f21SKevin Lo struct ure_softc *sc; 705e1b74f21SKevin Lo struct ifnet *ifp; 706e1b74f21SKevin Lo int error; 707e1b74f21SKevin Lo 708e1b74f21SKevin Lo sc = uether_getsc(ue); 709e1b74f21SKevin Lo ifp = ue->ue_ifp; 710e1b74f21SKevin Lo ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 711e1b74f21SKevin Lo ifp->if_start = uether_start; 712e1b74f21SKevin Lo ifp->if_ioctl = ure_ioctl; 713e1b74f21SKevin Lo ifp->if_init = uether_init; 714e1b74f21SKevin Lo IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 715e1b74f21SKevin Lo ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 716e1b74f21SKevin Lo IFQ_SET_READY(&ifp->if_snd); 717e1b74f21SKevin Lo 718e1b74f21SKevin Lo mtx_lock(&Giant); 719e1b74f21SKevin Lo error = mii_attach(ue->ue_dev, &ue->ue_miibus, ifp, 720e1b74f21SKevin Lo uether_ifmedia_upd, ue->ue_methods->ue_mii_sts, 721e1b74f21SKevin Lo BMSR_DEFCAPMASK, sc->sc_phyno, MII_OFFSET_ANY, 0); 722e1b74f21SKevin Lo mtx_unlock(&Giant); 723e1b74f21SKevin Lo 724e1b74f21SKevin Lo return (error); 725e1b74f21SKevin Lo } 726e1b74f21SKevin Lo 727e1b74f21SKevin Lo static void 728e1b74f21SKevin Lo ure_init(struct usb_ether *ue) 729e1b74f21SKevin Lo { 730e1b74f21SKevin Lo struct ure_softc *sc = uether_getsc(ue); 731e1b74f21SKevin Lo struct ifnet *ifp = uether_getifp(ue); 732e1b74f21SKevin Lo 733e1b74f21SKevin Lo URE_LOCK_ASSERT(sc, MA_OWNED); 734e1b74f21SKevin Lo 735e1b74f21SKevin Lo if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 736e1b74f21SKevin Lo return; 737e1b74f21SKevin Lo 738e1b74f21SKevin Lo /* Cancel pending I/O. */ 739e1b74f21SKevin Lo ure_stop(ue); 740e1b74f21SKevin Lo 741e1b74f21SKevin Lo ure_reset(sc); 742e1b74f21SKevin Lo 743e1b74f21SKevin Lo /* Set MAC address. */ 744cef38d45SGanbold Tsagaankhuu ure_write_1(sc, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_CONFIG); 745e1b74f21SKevin Lo ure_write_mem(sc, URE_PLA_IDR, URE_MCU_TYPE_PLA | URE_BYTE_EN_SIX_BYTES, 746e1b74f21SKevin Lo IF_LLADDR(ifp), 8); 747cef38d45SGanbold Tsagaankhuu ure_write_1(sc, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML); 748e1b74f21SKevin Lo 749e1b74f21SKevin Lo /* Reset the packet filter. */ 750e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA, 751e1b74f21SKevin Lo ure_read_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA) & 752e1b74f21SKevin Lo ~URE_FMC_FCR_MCU_EN); 753e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA, 754e1b74f21SKevin Lo ure_read_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA) | 755e1b74f21SKevin Lo URE_FMC_FCR_MCU_EN); 756e1b74f21SKevin Lo 757e1b74f21SKevin Lo /* Enable transmit and receive. */ 758e1b74f21SKevin Lo ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, 759e1b74f21SKevin Lo ure_read_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA) | URE_CR_RE | 760e1b74f21SKevin Lo URE_CR_TE); 761e1b74f21SKevin Lo 762e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, 763e1b74f21SKevin Lo ure_read_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) & 764e1b74f21SKevin Lo ~URE_RXDY_GATED_EN); 765e1b74f21SKevin Lo 766a24d62b5SKevin Lo /* Configure RX filters. */ 767a24d62b5SKevin Lo ure_rxfilter(ue); 768e1b74f21SKevin Lo 769e1b74f21SKevin Lo usbd_xfer_set_stall(sc->sc_xfer[URE_BULK_DT_WR]); 770e1b74f21SKevin Lo 771e1b74f21SKevin Lo /* Indicate we are up and running. */ 772e1b74f21SKevin Lo ifp->if_drv_flags |= IFF_DRV_RUNNING; 773e1b74f21SKevin Lo 774e1b74f21SKevin Lo /* Switch to selected media. */ 775e1b74f21SKevin Lo ure_ifmedia_upd(ifp); 776e1b74f21SKevin Lo } 777e1b74f21SKevin Lo 778e1b74f21SKevin Lo static void 779e1b74f21SKevin Lo ure_tick(struct usb_ether *ue) 780e1b74f21SKevin Lo { 781e1b74f21SKevin Lo struct ure_softc *sc = uether_getsc(ue); 782e1b74f21SKevin Lo struct mii_data *mii = GET_MII(sc); 783e1b74f21SKevin Lo 784e1b74f21SKevin Lo URE_LOCK_ASSERT(sc, MA_OWNED); 785e1b74f21SKevin Lo 786e1b74f21SKevin Lo mii_tick(mii); 787e1b74f21SKevin Lo if ((sc->sc_flags & URE_FLAG_LINK) == 0 788e1b74f21SKevin Lo && mii->mii_media_status & IFM_ACTIVE && 789e1b74f21SKevin Lo IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 790e1b74f21SKevin Lo sc->sc_flags |= URE_FLAG_LINK; 791e1b74f21SKevin Lo ure_start(ue); 792e1b74f21SKevin Lo } 793e1b74f21SKevin Lo } 794e1b74f21SKevin Lo 795*a433f711SGleb Smirnoff static u_int 796*a433f711SGleb Smirnoff ure_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 797*a433f711SGleb Smirnoff { 798*a433f711SGleb Smirnoff uint32_t h, *hashes = arg; 799*a433f711SGleb Smirnoff 800*a433f711SGleb Smirnoff h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; 801*a433f711SGleb Smirnoff if (h < 32) 802*a433f711SGleb Smirnoff hashes[0] |= (1 << h); 803*a433f711SGleb Smirnoff else 804*a433f711SGleb Smirnoff hashes[1] |= (1 << (h - 32)); 805*a433f711SGleb Smirnoff return (1); 806*a433f711SGleb Smirnoff } 807*a433f711SGleb Smirnoff 808e1b74f21SKevin Lo /* 809e1b74f21SKevin Lo * Program the 64-bit multicast hash filter. 810e1b74f21SKevin Lo */ 811e1b74f21SKevin Lo static void 812a24d62b5SKevin Lo ure_rxfilter(struct usb_ether *ue) 813e1b74f21SKevin Lo { 814e1b74f21SKevin Lo struct ure_softc *sc = uether_getsc(ue); 815e1b74f21SKevin Lo struct ifnet *ifp = uether_getifp(ue); 816*a433f711SGleb Smirnoff uint32_t rxmode; 817*a433f711SGleb Smirnoff uint32_t h, hashes[2] = { 0, 0 }; 818e1b74f21SKevin Lo 819e1b74f21SKevin Lo URE_LOCK_ASSERT(sc, MA_OWNED); 820e1b74f21SKevin Lo 821a24d62b5SKevin Lo rxmode = URE_RCR_APM; 822a24d62b5SKevin Lo if (ifp->if_flags & IFF_BROADCAST) 823a24d62b5SKevin Lo rxmode |= URE_RCR_AB; 824e1b74f21SKevin Lo if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { 825e1b74f21SKevin Lo if (ifp->if_flags & IFF_PROMISC) 826e1b74f21SKevin Lo rxmode |= URE_RCR_AAP; 827e1b74f21SKevin Lo rxmode |= URE_RCR_AM; 828e1b74f21SKevin Lo hashes[0] = hashes[1] = 0xffffffff; 829e1b74f21SKevin Lo goto done; 830e1b74f21SKevin Lo } 831e1b74f21SKevin Lo 832a24d62b5SKevin Lo rxmode |= URE_RCR_AM; 833*a433f711SGleb Smirnoff if_foreach_llmaddr(ifp, ure_hash_maddr, &hashes); 834e1b74f21SKevin Lo 835e1b74f21SKevin Lo h = bswap32(hashes[0]); 836e1b74f21SKevin Lo hashes[0] = bswap32(hashes[1]); 837e1b74f21SKevin Lo hashes[1] = h; 838e1b74f21SKevin Lo rxmode |= URE_RCR_AM; 839e1b74f21SKevin Lo 840e1b74f21SKevin Lo done: 841e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_MAR0, URE_MCU_TYPE_PLA, hashes[0]); 842e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_MAR4, URE_MCU_TYPE_PLA, hashes[1]); 843e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); 844e1b74f21SKevin Lo } 845e1b74f21SKevin Lo 846e1b74f21SKevin Lo static void 847e1b74f21SKevin Lo ure_start(struct usb_ether *ue) 848e1b74f21SKevin Lo { 849e1b74f21SKevin Lo struct ure_softc *sc = uether_getsc(ue); 850e1b74f21SKevin Lo 851e1b74f21SKevin Lo /* 852e1b74f21SKevin Lo * start the USB transfers, if not already started: 853e1b74f21SKevin Lo */ 854e1b74f21SKevin Lo usbd_transfer_start(sc->sc_xfer[URE_BULK_DT_RD]); 855e1b74f21SKevin Lo usbd_transfer_start(sc->sc_xfer[URE_BULK_DT_WR]); 856e1b74f21SKevin Lo } 857e1b74f21SKevin Lo 858e1b74f21SKevin Lo static void 859e1b74f21SKevin Lo ure_reset(struct ure_softc *sc) 860e1b74f21SKevin Lo { 861e1b74f21SKevin Lo int i; 862e1b74f21SKevin Lo 863e1b74f21SKevin Lo ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST); 864e1b74f21SKevin Lo 865e1b74f21SKevin Lo for (i = 0; i < URE_TIMEOUT; i++) { 866e1b74f21SKevin Lo if (!(ure_read_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA) & 867e1b74f21SKevin Lo URE_CR_RST)) 868e1b74f21SKevin Lo break; 869e1b74f21SKevin Lo uether_pause(&sc->sc_ue, hz / 100); 870e1b74f21SKevin Lo } 871e1b74f21SKevin Lo if (i == URE_TIMEOUT) 872e1b74f21SKevin Lo device_printf(sc->sc_ue.ue_dev, "reset never completed\n"); 873e1b74f21SKevin Lo } 874e1b74f21SKevin Lo 875e1b74f21SKevin Lo /* 876e1b74f21SKevin Lo * Set media options. 877e1b74f21SKevin Lo */ 878e1b74f21SKevin Lo static int 879e1b74f21SKevin Lo ure_ifmedia_upd(struct ifnet *ifp) 880e1b74f21SKevin Lo { 881e1b74f21SKevin Lo struct ure_softc *sc = ifp->if_softc; 882e1b74f21SKevin Lo struct mii_data *mii = GET_MII(sc); 883e1b74f21SKevin Lo struct mii_softc *miisc; 884e1b74f21SKevin Lo int error; 885e1b74f21SKevin Lo 886e1b74f21SKevin Lo URE_LOCK_ASSERT(sc, MA_OWNED); 887e1b74f21SKevin Lo 888e1b74f21SKevin Lo LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 889e1b74f21SKevin Lo PHY_RESET(miisc); 890e1b74f21SKevin Lo error = mii_mediachg(mii); 891e1b74f21SKevin Lo return (error); 892e1b74f21SKevin Lo } 893e1b74f21SKevin Lo 894e1b74f21SKevin Lo /* 895e1b74f21SKevin Lo * Report current media status. 896e1b74f21SKevin Lo */ 897e1b74f21SKevin Lo static void 898e1b74f21SKevin Lo ure_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 899e1b74f21SKevin Lo { 900e1b74f21SKevin Lo struct ure_softc *sc; 901e1b74f21SKevin Lo struct mii_data *mii; 902e1b74f21SKevin Lo 903e1b74f21SKevin Lo sc = ifp->if_softc; 904e1b74f21SKevin Lo mii = GET_MII(sc); 905e1b74f21SKevin Lo 906e1b74f21SKevin Lo URE_LOCK(sc); 907e1b74f21SKevin Lo mii_pollstat(mii); 908e1b74f21SKevin Lo ifmr->ifm_active = mii->mii_media_active; 909e1b74f21SKevin Lo ifmr->ifm_status = mii->mii_media_status; 910e1b74f21SKevin Lo URE_UNLOCK(sc); 911e1b74f21SKevin Lo } 912e1b74f21SKevin Lo 913e1b74f21SKevin Lo static int 914e1b74f21SKevin Lo ure_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 915e1b74f21SKevin Lo { 916e1b74f21SKevin Lo struct usb_ether *ue = ifp->if_softc; 917e1b74f21SKevin Lo struct ure_softc *sc; 918e1b74f21SKevin Lo struct ifreq *ifr; 919e1b74f21SKevin Lo int error, mask, reinit; 920e1b74f21SKevin Lo 921e1b74f21SKevin Lo sc = uether_getsc(ue); 922e1b74f21SKevin Lo ifr = (struct ifreq *)data; 923e1b74f21SKevin Lo error = 0; 924e1b74f21SKevin Lo reinit = 0; 925e1b74f21SKevin Lo if (cmd == SIOCSIFCAP) { 926e1b74f21SKevin Lo URE_LOCK(sc); 927e1b74f21SKevin Lo mask = ifr->ifr_reqcap ^ ifp->if_capenable; 928e1b74f21SKevin Lo if (reinit > 0 && ifp->if_drv_flags & IFF_DRV_RUNNING) 929e1b74f21SKevin Lo ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 930e1b74f21SKevin Lo else 931e1b74f21SKevin Lo reinit = 0; 932e1b74f21SKevin Lo URE_UNLOCK(sc); 933e1b74f21SKevin Lo if (reinit > 0) 934e1b74f21SKevin Lo uether_init(ue); 935e1b74f21SKevin Lo } else 936e1b74f21SKevin Lo error = uether_ioctl(ifp, cmd, data); 937e1b74f21SKevin Lo 938e1b74f21SKevin Lo return (error); 939e1b74f21SKevin Lo } 940e1b74f21SKevin Lo 941e1b74f21SKevin Lo static void 942e1b74f21SKevin Lo ure_rtl8152_init(struct ure_softc *sc) 943e1b74f21SKevin Lo { 944e1b74f21SKevin Lo uint32_t pwrctrl; 945e1b74f21SKevin Lo 946e1b74f21SKevin Lo /* Disable ALDPS. */ 947e1b74f21SKevin Lo ure_ocp_reg_write(sc, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | 948e1b74f21SKevin Lo URE_DIS_SDSAVE); 949e1b74f21SKevin Lo uether_pause(&sc->sc_ue, hz / 50); 950e1b74f21SKevin Lo 951e1b74f21SKevin Lo if (sc->sc_chip & URE_CHIP_VER_4C00) { 952e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, 953e1b74f21SKevin Lo ure_read_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & 954e1b74f21SKevin Lo ~URE_LED_MODE_MASK); 955e1b74f21SKevin Lo } 956e1b74f21SKevin Lo 957e1b74f21SKevin Lo ure_write_2(sc, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB, 958e1b74f21SKevin Lo ure_read_2(sc, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB) & 959e1b74f21SKevin Lo ~URE_POWER_CUT); 960e1b74f21SKevin Lo ure_write_2(sc, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB, 961e1b74f21SKevin Lo ure_read_2(sc, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB) & 962e1b74f21SKevin Lo ~URE_RESUME_INDICATE); 963e1b74f21SKevin Lo 964e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, 965e1b74f21SKevin Lo ure_read_2(sc, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | 966e1b74f21SKevin Lo URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH); 967e1b74f21SKevin Lo pwrctrl = ure_read_4(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA); 968e1b74f21SKevin Lo pwrctrl &= ~URE_MCU_CLK_RATIO_MASK; 969e1b74f21SKevin Lo pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN; 970e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl); 971e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA, 972e1b74f21SKevin Lo URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK | 973e1b74f21SKevin Lo URE_SPDWN_LINKCHG_MSK); 974e1b74f21SKevin Lo 975e1b74f21SKevin Lo /* Disable Rx aggregation. */ 976e1b74f21SKevin Lo ure_write_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, 977e1b74f21SKevin Lo ure_read_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) | 978e1b74f21SKevin Lo URE_RX_AGG_DISABLE); 979e1b74f21SKevin Lo 980e1b74f21SKevin Lo /* Disable ALDPS. */ 981e1b74f21SKevin Lo ure_ocp_reg_write(sc, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | 982e1b74f21SKevin Lo URE_DIS_SDSAVE); 983e1b74f21SKevin Lo uether_pause(&sc->sc_ue, hz / 50); 984e1b74f21SKevin Lo 985e1b74f21SKevin Lo ure_init_fifo(sc); 986e1b74f21SKevin Lo 987e1b74f21SKevin Lo ure_write_1(sc, URE_USB_TX_AGG, URE_MCU_TYPE_USB, 988e1b74f21SKevin Lo URE_TX_AGG_MAX_THRESHOLD); 989e1b74f21SKevin Lo ure_write_4(sc, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH); 990e1b74f21SKevin Lo ure_write_4(sc, URE_USB_TX_DMA, URE_MCU_TYPE_USB, 991e1b74f21SKevin Lo URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1); 992e1b74f21SKevin Lo } 993e1b74f21SKevin Lo 994e1b74f21SKevin Lo static void 995a24d62b5SKevin Lo ure_rtl8153_init(struct ure_softc *sc) 996a24d62b5SKevin Lo { 997a24d62b5SKevin Lo uint16_t val; 998a24d62b5SKevin Lo uint8_t u1u2[8]; 999a24d62b5SKevin Lo int i; 1000a24d62b5SKevin Lo 1001a24d62b5SKevin Lo /* Disable ALDPS. */ 1002a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_POWER_CFG, 1003a24d62b5SKevin Lo ure_ocp_reg_read(sc, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); 1004a24d62b5SKevin Lo uether_pause(&sc->sc_ue, hz / 50); 1005a24d62b5SKevin Lo 1006a24d62b5SKevin Lo memset(u1u2, 0x00, sizeof(u1u2)); 1007a24d62b5SKevin Lo ure_write_mem(sc, URE_USB_TOLERANCE, 1008a24d62b5SKevin Lo URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); 1009a24d62b5SKevin Lo 1010a24d62b5SKevin Lo for (i = 0; i < URE_TIMEOUT; i++) { 1011a24d62b5SKevin Lo if (ure_read_2(sc, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) & 1012a24d62b5SKevin Lo URE_AUTOLOAD_DONE) 1013a24d62b5SKevin Lo break; 1014a24d62b5SKevin Lo uether_pause(&sc->sc_ue, hz / 100); 1015a24d62b5SKevin Lo } 1016a24d62b5SKevin Lo if (i == URE_TIMEOUT) 1017a24d62b5SKevin Lo device_printf(sc->sc_ue.ue_dev, 1018a24d62b5SKevin Lo "timeout waiting for chip autoload\n"); 1019a24d62b5SKevin Lo 1020a24d62b5SKevin Lo for (i = 0; i < URE_TIMEOUT; i++) { 1021a24d62b5SKevin Lo val = ure_ocp_reg_read(sc, URE_OCP_PHY_STATUS) & 1022a24d62b5SKevin Lo URE_PHY_STAT_MASK; 1023a24d62b5SKevin Lo if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN) 1024a24d62b5SKevin Lo break; 1025a24d62b5SKevin Lo uether_pause(&sc->sc_ue, hz / 100); 1026a24d62b5SKevin Lo } 1027a24d62b5SKevin Lo if (i == URE_TIMEOUT) 1028a24d62b5SKevin Lo device_printf(sc->sc_ue.ue_dev, 1029a24d62b5SKevin Lo "timeout waiting for phy to stabilize\n"); 1030a24d62b5SKevin Lo 1031a24d62b5SKevin Lo ure_write_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, 1032a24d62b5SKevin Lo ure_read_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB) & 1033a24d62b5SKevin Lo ~URE_U2P3_ENABLE); 1034a24d62b5SKevin Lo 1035a24d62b5SKevin Lo if (sc->sc_chip & URE_CHIP_VER_5C10) { 1036a24d62b5SKevin Lo val = ure_read_2(sc, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB); 1037a24d62b5SKevin Lo val &= ~URE_PWD_DN_SCALE_MASK; 1038a24d62b5SKevin Lo val |= URE_PWD_DN_SCALE(96); 1039a24d62b5SKevin Lo ure_write_2(sc, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB, val); 1040a24d62b5SKevin Lo 1041a24d62b5SKevin Lo ure_write_1(sc, URE_USB_USB2PHY, URE_MCU_TYPE_USB, 1042a24d62b5SKevin Lo ure_read_1(sc, URE_USB_USB2PHY, URE_MCU_TYPE_USB) | 1043a24d62b5SKevin Lo URE_USB2PHY_L1 | URE_USB2PHY_SUSPEND); 1044a24d62b5SKevin Lo } else if (sc->sc_chip & URE_CHIP_VER_5C20) { 1045a24d62b5SKevin Lo ure_write_1(sc, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA, 1046a24d62b5SKevin Lo ure_read_1(sc, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA) & 1047a24d62b5SKevin Lo ~URE_ECM_ALDPS); 1048a24d62b5SKevin Lo } 1049a24d62b5SKevin Lo if (sc->sc_chip & (URE_CHIP_VER_5C20 | URE_CHIP_VER_5C30)) { 1050a24d62b5SKevin Lo val = ure_read_1(sc, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB); 1051a24d62b5SKevin Lo if (ure_read_2(sc, URE_USB_BURST_SIZE, URE_MCU_TYPE_USB) == 1052a24d62b5SKevin Lo 0) 1053a24d62b5SKevin Lo val &= ~URE_DYNAMIC_BURST; 1054a24d62b5SKevin Lo else 1055a24d62b5SKevin Lo val |= URE_DYNAMIC_BURST; 1056a24d62b5SKevin Lo ure_write_1(sc, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB, val); 1057a24d62b5SKevin Lo } 1058a24d62b5SKevin Lo 1059a24d62b5SKevin Lo ure_write_1(sc, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB, 1060a24d62b5SKevin Lo ure_read_1(sc, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB) | 1061a24d62b5SKevin Lo URE_EP4_FULL_FC); 1062a24d62b5SKevin Lo 1063a24d62b5SKevin Lo ure_write_2(sc, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB, 1064a24d62b5SKevin Lo ure_read_2(sc, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB) & 1065a24d62b5SKevin Lo ~URE_TIMER11_EN); 1066a24d62b5SKevin Lo 1067a24d62b5SKevin Lo ure_write_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, 1068a24d62b5SKevin Lo ure_read_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & 1069a24d62b5SKevin Lo ~URE_LED_MODE_MASK); 1070a24d62b5SKevin Lo 1071a24d62b5SKevin Lo if ((sc->sc_chip & URE_CHIP_VER_5C10) && 1072a24d62b5SKevin Lo usbd_get_speed(sc->sc_ue.ue_udev) != USB_SPEED_SUPER) 1073a24d62b5SKevin Lo val = URE_LPM_TIMER_500MS; 1074a24d62b5SKevin Lo else 1075a24d62b5SKevin Lo val = URE_LPM_TIMER_500US; 1076a24d62b5SKevin Lo ure_write_1(sc, URE_USB_LPM_CTRL, URE_MCU_TYPE_USB, 1077a24d62b5SKevin Lo val | URE_FIFO_EMPTY_1FB | URE_ROK_EXIT_LPM); 1078a24d62b5SKevin Lo 1079a24d62b5SKevin Lo val = ure_read_2(sc, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB); 1080a24d62b5SKevin Lo val &= ~URE_SEN_VAL_MASK; 1081a24d62b5SKevin Lo val |= URE_SEN_VAL_NORMAL | URE_SEL_RXIDLE; 1082a24d62b5SKevin Lo ure_write_2(sc, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB, val); 1083a24d62b5SKevin Lo 1084a24d62b5SKevin Lo ure_write_2(sc, URE_USB_CONNECT_TIMER, URE_MCU_TYPE_USB, 0x0001); 1085a24d62b5SKevin Lo 1086a24d62b5SKevin Lo ure_write_2(sc, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, 1087a24d62b5SKevin Lo ure_read_2(sc, URE_USB_POWER_CUT, URE_MCU_TYPE_USB) & 1088a24d62b5SKevin Lo ~(URE_PWR_EN | URE_PHASE2_EN)); 1089a24d62b5SKevin Lo ure_write_2(sc, URE_USB_MISC_0, URE_MCU_TYPE_USB, 1090a24d62b5SKevin Lo ure_read_2(sc, URE_USB_MISC_0, URE_MCU_TYPE_USB) & 1091a24d62b5SKevin Lo ~URE_PCUT_STATUS); 1092a24d62b5SKevin Lo 1093a24d62b5SKevin Lo memset(u1u2, 0xff, sizeof(u1u2)); 1094a24d62b5SKevin Lo ure_write_mem(sc, URE_USB_TOLERANCE, 1095a24d62b5SKevin Lo URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); 1096a24d62b5SKevin Lo 1097a24d62b5SKevin Lo ure_write_2(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, 1098a24d62b5SKevin Lo URE_ALDPS_SPDWN_RATIO); 1099a24d62b5SKevin Lo ure_write_2(sc, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA, 1100a24d62b5SKevin Lo URE_EEE_SPDWN_RATIO); 1101a24d62b5SKevin Lo ure_write_2(sc, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA, 1102a24d62b5SKevin Lo URE_PKT_AVAIL_SPDWN_EN | URE_SUSPEND_SPDWN_EN | 1103a24d62b5SKevin Lo URE_U1U2_SPDWN_EN | URE_L1_SPDWN_EN); 1104a24d62b5SKevin Lo ure_write_2(sc, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA, 1105a24d62b5SKevin Lo URE_PWRSAVE_SPDWN_EN | URE_RXDV_SPDWN_EN | URE_TX10MIDLE_EN | 1106a24d62b5SKevin Lo URE_TP100_SPDWN_EN | URE_TP500_SPDWN_EN | URE_TP1000_SPDWN_EN | 1107a24d62b5SKevin Lo URE_EEE_SPDWN_EN); 1108a24d62b5SKevin Lo 1109a24d62b5SKevin Lo val = ure_read_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); 1110a24d62b5SKevin Lo if (!(sc->sc_chip & (URE_CHIP_VER_5C00 | URE_CHIP_VER_5C10))) 1111a24d62b5SKevin Lo val |= URE_U2P3_ENABLE; 1112a24d62b5SKevin Lo else 1113a24d62b5SKevin Lo val &= ~URE_U2P3_ENABLE; 1114a24d62b5SKevin Lo ure_write_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); 1115a24d62b5SKevin Lo 1116a24d62b5SKevin Lo memset(u1u2, 0x00, sizeof(u1u2)); 1117a24d62b5SKevin Lo ure_write_mem(sc, URE_USB_TOLERANCE, 1118a24d62b5SKevin Lo URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); 1119a24d62b5SKevin Lo 1120a24d62b5SKevin Lo /* Disable ALDPS. */ 1121a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_POWER_CFG, 1122a24d62b5SKevin Lo ure_ocp_reg_read(sc, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); 1123a24d62b5SKevin Lo uether_pause(&sc->sc_ue, hz / 50); 1124a24d62b5SKevin Lo 1125a24d62b5SKevin Lo ure_init_fifo(sc); 1126a24d62b5SKevin Lo 1127a24d62b5SKevin Lo /* Disable Rx aggregation. */ 1128a24d62b5SKevin Lo ure_write_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, 1129a24d62b5SKevin Lo ure_read_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) | 1130a24d62b5SKevin Lo URE_RX_AGG_DISABLE); 1131a24d62b5SKevin Lo 1132a24d62b5SKevin Lo val = ure_read_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); 1133a24d62b5SKevin Lo if (!(sc->sc_chip & (URE_CHIP_VER_5C00 | URE_CHIP_VER_5C10))) 1134a24d62b5SKevin Lo val |= URE_U2P3_ENABLE; 1135a24d62b5SKevin Lo else 1136a24d62b5SKevin Lo val &= ~URE_U2P3_ENABLE; 1137a24d62b5SKevin Lo ure_write_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); 1138a24d62b5SKevin Lo 1139a24d62b5SKevin Lo memset(u1u2, 0xff, sizeof(u1u2)); 1140a24d62b5SKevin Lo ure_write_mem(sc, URE_USB_TOLERANCE, 1141a24d62b5SKevin Lo URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); 1142a24d62b5SKevin Lo } 1143a24d62b5SKevin Lo 1144a24d62b5SKevin Lo static void 1145e1b74f21SKevin Lo ure_stop(struct usb_ether *ue) 1146e1b74f21SKevin Lo { 1147e1b74f21SKevin Lo struct ure_softc *sc = uether_getsc(ue); 1148e1b74f21SKevin Lo struct ifnet *ifp = uether_getifp(ue); 1149e1b74f21SKevin Lo 1150e1b74f21SKevin Lo URE_LOCK_ASSERT(sc, MA_OWNED); 1151e1b74f21SKevin Lo 1152e1b74f21SKevin Lo ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1153e1b74f21SKevin Lo sc->sc_flags &= ~URE_FLAG_LINK; 1154e1b74f21SKevin Lo 1155e1b74f21SKevin Lo /* 1156e1b74f21SKevin Lo * stop all the transfers, if not already stopped: 1157e1b74f21SKevin Lo */ 1158e1b74f21SKevin Lo usbd_transfer_stop(sc->sc_xfer[URE_BULK_DT_WR]); 1159e1b74f21SKevin Lo usbd_transfer_stop(sc->sc_xfer[URE_BULK_DT_RD]); 1160e1b74f21SKevin Lo } 1161e1b74f21SKevin Lo 1162e1b74f21SKevin Lo static void 1163e1b74f21SKevin Lo ure_disable_teredo(struct ure_softc *sc) 1164e1b74f21SKevin Lo { 1165e1b74f21SKevin Lo 1166e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA, 1167e1b74f21SKevin Lo ure_read_4(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) & 1168e1b74f21SKevin Lo ~(URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN)); 1169e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA, 1170e1b74f21SKevin Lo URE_WDT6_SET_MODE); 1171e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0); 1172e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0); 1173e1b74f21SKevin Lo } 1174e1b74f21SKevin Lo 1175e1b74f21SKevin Lo static void 1176e1b74f21SKevin Lo ure_init_fifo(struct ure_softc *sc) 1177e1b74f21SKevin Lo { 1178e1b74f21SKevin Lo uint32_t rx_fifo1, rx_fifo2; 1179e1b74f21SKevin Lo int i; 1180e1b74f21SKevin Lo 1181e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, 1182e1b74f21SKevin Lo ure_read_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) | 1183e1b74f21SKevin Lo URE_RXDY_GATED_EN); 1184e1b74f21SKevin Lo 1185e1b74f21SKevin Lo ure_disable_teredo(sc); 1186e1b74f21SKevin Lo 1187e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, 1188e1b74f21SKevin Lo ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA) & 1189e1b74f21SKevin Lo ~URE_RCR_ACPT_ALL); 1190e1b74f21SKevin Lo 1191a24d62b5SKevin Lo if (!(sc->sc_flags & URE_FLAG_8152)) { 1192a24d62b5SKevin Lo if (sc->sc_chip & (URE_CHIP_VER_5C00 | URE_CHIP_VER_5C10 | 1193a24d62b5SKevin Lo URE_CHIP_VER_5C20)) { 1194a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_ADC_CFG, 1195a24d62b5SKevin Lo URE_CKADSEL_L | URE_ADC_EN | URE_EN_EMI_L); 1196a24d62b5SKevin Lo } 1197a24d62b5SKevin Lo if (sc->sc_chip & URE_CHIP_VER_5C00) { 1198a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_EEE_CFG, 1199a24d62b5SKevin Lo ure_ocp_reg_read(sc, URE_OCP_EEE_CFG) & 1200a24d62b5SKevin Lo ~URE_CTAP_SHORT_EN); 1201a24d62b5SKevin Lo } 1202a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_POWER_CFG, 1203a24d62b5SKevin Lo ure_ocp_reg_read(sc, URE_OCP_POWER_CFG) | 1204a24d62b5SKevin Lo URE_EEE_CLKDIV_EN); 1205a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_DOWN_SPEED, 1206a24d62b5SKevin Lo ure_ocp_reg_read(sc, URE_OCP_DOWN_SPEED) | 1207a24d62b5SKevin Lo URE_EN_10M_BGOFF); 1208a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_POWER_CFG, 1209a24d62b5SKevin Lo ure_ocp_reg_read(sc, URE_OCP_POWER_CFG) | 1210a24d62b5SKevin Lo URE_EN_10M_PLLOFF); 1211a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_SRAM_ADDR, URE_SRAM_IMPEDANCE); 1212a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_SRAM_DATA, 0x0b13); 1213a24d62b5SKevin Lo ure_write_2(sc, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, 1214a24d62b5SKevin Lo ure_read_2(sc, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | 1215a24d62b5SKevin Lo URE_PFM_PWM_SWITCH); 1216a24d62b5SKevin Lo 1217a24d62b5SKevin Lo /* Enable LPF corner auto tune. */ 1218a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_SRAM_ADDR, URE_SRAM_LPF_CFG); 1219a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_SRAM_DATA, 0xf70f); 1220a24d62b5SKevin Lo 1221a24d62b5SKevin Lo /* Adjust 10M amplitude. */ 1222a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP1); 1223a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_SRAM_DATA, 0x00af); 1224a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP2); 1225a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_SRAM_DATA, 0x0208); 1226a24d62b5SKevin Lo } 1227a24d62b5SKevin Lo 1228e1b74f21SKevin Lo ure_reset(sc); 1229e1b74f21SKevin Lo 1230e1b74f21SKevin Lo ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, 0); 1231e1b74f21SKevin Lo 1232e1b74f21SKevin Lo ure_write_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, 1233e1b74f21SKevin Lo ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & 1234e1b74f21SKevin Lo ~URE_NOW_IS_OOB); 1235e1b74f21SKevin Lo 1236e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, 1237e1b74f21SKevin Lo ure_read_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) & 1238e1b74f21SKevin Lo ~URE_MCU_BORW_EN); 1239e1b74f21SKevin Lo for (i = 0; i < URE_TIMEOUT; i++) { 1240e1b74f21SKevin Lo if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & 1241e1b74f21SKevin Lo URE_LINK_LIST_READY) 1242e1b74f21SKevin Lo break; 1243e1b74f21SKevin Lo uether_pause(&sc->sc_ue, hz / 100); 1244e1b74f21SKevin Lo } 1245e1b74f21SKevin Lo if (i == URE_TIMEOUT) 1246e1b74f21SKevin Lo device_printf(sc->sc_ue.ue_dev, 1247e1b74f21SKevin Lo "timeout waiting for OOB control\n"); 1248e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, 1249e1b74f21SKevin Lo ure_read_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) | 1250e1b74f21SKevin Lo URE_RE_INIT_LL); 1251e1b74f21SKevin Lo for (i = 0; i < URE_TIMEOUT; i++) { 1252e1b74f21SKevin Lo if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & 1253e1b74f21SKevin Lo URE_LINK_LIST_READY) 1254e1b74f21SKevin Lo break; 1255e1b74f21SKevin Lo uether_pause(&sc->sc_ue, hz / 100); 1256e1b74f21SKevin Lo } 1257e1b74f21SKevin Lo if (i == URE_TIMEOUT) 1258e1b74f21SKevin Lo device_printf(sc->sc_ue.ue_dev, 1259e1b74f21SKevin Lo "timeout waiting for OOB control\n"); 1260e1b74f21SKevin Lo 1261e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA, 1262e1b74f21SKevin Lo ure_read_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA) & 1263e1b74f21SKevin Lo ~URE_CPCR_RX_VLAN); 1264e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_TCR0, URE_MCU_TYPE_PLA, 1265e1b74f21SKevin Lo ure_read_2(sc, URE_PLA_TCR0, URE_MCU_TYPE_PLA) | 1266e1b74f21SKevin Lo URE_TCR0_AUTO_FIFO); 1267e1b74f21SKevin Lo 1268e1b74f21SKevin Lo /* Configure Rx FIFO threshold. */ 1269e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA, 1270e1b74f21SKevin Lo URE_RXFIFO_THR1_NORMAL); 1271e1b74f21SKevin Lo if (usbd_get_speed(sc->sc_ue.ue_udev) == USB_SPEED_FULL) { 1272e1b74f21SKevin Lo rx_fifo1 = URE_RXFIFO_THR2_FULL; 1273e1b74f21SKevin Lo rx_fifo2 = URE_RXFIFO_THR3_FULL; 1274e1b74f21SKevin Lo } else { 1275e1b74f21SKevin Lo rx_fifo1 = URE_RXFIFO_THR2_HIGH; 1276e1b74f21SKevin Lo rx_fifo2 = URE_RXFIFO_THR3_HIGH; 1277e1b74f21SKevin Lo } 1278e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1); 1279e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2); 1280e1b74f21SKevin Lo 1281e1b74f21SKevin Lo /* Configure Tx FIFO threshold. */ 1282e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, 1283e1b74f21SKevin Lo URE_TXFIFO_THR_NORMAL); 1284e1b74f21SKevin Lo } 1285