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/param.h> 28e1b74f21SKevin Lo #include <sys/systm.h> 29e1b74f21SKevin Lo #include <sys/bus.h> 30e1b74f21SKevin Lo #include <sys/condvar.h> 31e1b74f21SKevin Lo #include <sys/kernel.h> 32e1b74f21SKevin Lo #include <sys/lock.h> 33e1b74f21SKevin Lo #include <sys/module.h> 34e1b74f21SKevin Lo #include <sys/mutex.h> 357d5522e1SJohn-Mark Gurney #include <sys/sbuf.h> 36e1b74f21SKevin Lo #include <sys/socket.h> 37e1b74f21SKevin Lo #include <sys/sysctl.h> 38e1b74f21SKevin Lo #include <sys/unistd.h> 39e1b74f21SKevin Lo 40e1b74f21SKevin Lo #include <net/if.h> 41e1b74f21SKevin Lo #include <net/if_var.h> 4231c484adSJustin Hibbits #include <net/if_media.h> 4331c484adSJustin Hibbits 447d5522e1SJohn-Mark Gurney /* needed for checksum offload */ 457d5522e1SJohn-Mark Gurney #include <netinet/in.h> 467d5522e1SJohn-Mark Gurney #include <netinet/ip.h> 477d5522e1SJohn-Mark Gurney 4831c484adSJustin Hibbits #include <dev/mii/mii.h> 4931c484adSJustin Hibbits #include <dev/mii/miivar.h> 50e1b74f21SKevin Lo 51e1b74f21SKevin Lo #include <dev/usb/usb.h> 52e1b74f21SKevin Lo #include <dev/usb/usbdi.h> 53e1b74f21SKevin Lo #include <dev/usb/usbdi_util.h> 54e1b74f21SKevin Lo #include "usbdevs.h" 55e1b74f21SKevin Lo 56e1b74f21SKevin Lo #define USB_DEBUG_VAR ure_debug 57e1b74f21SKevin Lo #include <dev/usb/usb_debug.h> 58e1b74f21SKevin Lo #include <dev/usb/usb_process.h> 59e1b74f21SKevin Lo 60e1b74f21SKevin Lo #include <dev/usb/net/usb_ethernet.h> 61e1b74f21SKevin Lo #include <dev/usb/net/if_urereg.h> 62e1b74f21SKevin Lo 6331c484adSJustin Hibbits #include "miibus_if.h" 6431c484adSJustin Hibbits 657d5522e1SJohn-Mark Gurney #include "opt_inet6.h" 667d5522e1SJohn-Mark Gurney 67e1b74f21SKevin Lo #ifdef USB_DEBUG 68e1b74f21SKevin Lo static int ure_debug = 0; 69e1b74f21SKevin Lo 70f8d2b1f3SPawel Biernacki static SYSCTL_NODE(_hw_usb, OID_AUTO, ure, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 71f8d2b1f3SPawel Biernacki "USB ure"); 72e1b74f21SKevin Lo SYSCTL_INT(_hw_usb_ure, OID_AUTO, debug, CTLFLAG_RWTUN, &ure_debug, 0, 73e1b74f21SKevin Lo "Debug level"); 74e1b74f21SKevin Lo #endif 75e1b74f21SKevin Lo 767d5522e1SJohn-Mark Gurney #ifdef USB_DEBUG_VAR 777d5522e1SJohn-Mark Gurney #ifdef USB_DEBUG 787d5522e1SJohn-Mark Gurney #define DEVPRINTFN(n,dev,fmt,...) do { \ 797d5522e1SJohn-Mark Gurney if ((USB_DEBUG_VAR) >= (n)) { \ 807d5522e1SJohn-Mark Gurney device_printf((dev), "%s: " fmt, \ 817d5522e1SJohn-Mark Gurney __FUNCTION__ ,##__VA_ARGS__); \ 827d5522e1SJohn-Mark Gurney } \ 837d5522e1SJohn-Mark Gurney } while (0) 847d5522e1SJohn-Mark Gurney #define DEVPRINTF(...) DEVPRINTFN(1, __VA_ARGS__) 857d5522e1SJohn-Mark Gurney #else 867d5522e1SJohn-Mark Gurney #define DEVPRINTF(...) do { } while (0) 877d5522e1SJohn-Mark Gurney #define DEVPRINTFN(...) do { } while (0) 887d5522e1SJohn-Mark Gurney #endif 897d5522e1SJohn-Mark Gurney #endif 907d5522e1SJohn-Mark Gurney 91e1b74f21SKevin Lo /* 92e1b74f21SKevin Lo * Various supported device vendors/products. 93e1b74f21SKevin Lo */ 94e1b74f21SKevin Lo static const STRUCT_USB_HOST_ID ure_devs[] = { 95dab84426SHans Petter Selasky #define URE_DEV(v,p,i) { \ 96dab84426SHans Petter Selasky USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i), \ 97dab84426SHans Petter Selasky USB_IFACE_CLASS(UICLASS_VENDOR), \ 98dab84426SHans Petter Selasky USB_IFACE_SUBCLASS(UISUBCLASS_VENDOR) } 99*dc273058SFUKAUMI Naoki URE_DEV(ELECOM, EDCQUA3C, 0), 100d4cf41a9SHans Petter Selasky URE_DEV(LENOVO, RTL8153, URE_FLAG_8153), 101a8261b70SHans Petter Selasky URE_DEV(LENOVO, TBT3LANGEN2, 0), 102afa9b036SGavin Atkinson URE_DEV(LENOVO, ONELINK, 0), 10331937f7eSPoul-Henning Kamp URE_DEV(LENOVO, RTL8153_04, URE_FLAG_8153), 104a1bb5bdbSAlexander Motin URE_DEV(LENOVO, ONELINKPLUS, URE_FLAG_8153), 105146ebc76SPoul-Henning Kamp URE_DEV(LENOVO, USBCLAN, 0), 106a8261b70SHans Petter Selasky URE_DEV(LENOVO, USBCLANGEN2, 0), 10753a03e31SJoerg Pulz URE_DEV(LENOVO, USBCLANHYBRID, 0), 108e5b9b5eeSAndrew Turner URE_DEV(MICROSOFT, WINDEVETH, 0), 109d4cf41a9SHans Petter Selasky URE_DEV(NVIDIA, RTL8153, URE_FLAG_8153), 110a24d62b5SKevin Lo URE_DEV(REALTEK, RTL8152, URE_FLAG_8152), 111d4cf41a9SHans Petter Selasky URE_DEV(REALTEK, RTL8153, URE_FLAG_8153), 112d4cf41a9SHans Petter Selasky URE_DEV(TPLINK, RTL8153, URE_FLAG_8153), 113d4cf41a9SHans Petter Selasky URE_DEV(REALTEK, RTL8156, URE_FLAG_8156), 114e1b74f21SKevin Lo #undef URE_DEV 115e1b74f21SKevin Lo }; 116e1b74f21SKevin Lo 117e1b74f21SKevin Lo static device_probe_t ure_probe; 118e1b74f21SKevin Lo static device_attach_t ure_attach; 119e1b74f21SKevin Lo static device_detach_t ure_detach; 120e1b74f21SKevin Lo 121e1b74f21SKevin Lo static usb_callback_t ure_bulk_read_callback; 122e1b74f21SKevin Lo static usb_callback_t ure_bulk_write_callback; 123e1b74f21SKevin Lo 124e1b74f21SKevin Lo static miibus_readreg_t ure_miibus_readreg; 125e1b74f21SKevin Lo static miibus_writereg_t ure_miibus_writereg; 126e1b74f21SKevin Lo static miibus_statchg_t ure_miibus_statchg; 127e1b74f21SKevin Lo 128e1b74f21SKevin Lo static uether_fn_t ure_attach_post; 129e1b74f21SKevin Lo static uether_fn_t ure_init; 130e1b74f21SKevin Lo static uether_fn_t ure_stop; 131e1b74f21SKevin Lo static uether_fn_t ure_start; 132e1b74f21SKevin Lo static uether_fn_t ure_tick; 133a24d62b5SKevin Lo static uether_fn_t ure_rxfilter; 134e1b74f21SKevin Lo 135e1b74f21SKevin Lo static int ure_ctl(struct ure_softc *, uint8_t, uint16_t, uint16_t, 136e1b74f21SKevin Lo void *, int); 137e1b74f21SKevin Lo static int ure_read_mem(struct ure_softc *, uint16_t, uint16_t, void *, 138e1b74f21SKevin Lo int); 139e1b74f21SKevin Lo static int ure_write_mem(struct ure_softc *, uint16_t, uint16_t, void *, 140e1b74f21SKevin Lo int); 141e1b74f21SKevin Lo static uint8_t ure_read_1(struct ure_softc *, uint16_t, uint16_t); 142e1b74f21SKevin Lo static uint16_t ure_read_2(struct ure_softc *, uint16_t, uint16_t); 143e1b74f21SKevin Lo static uint32_t ure_read_4(struct ure_softc *, uint16_t, uint16_t); 144e1b74f21SKevin Lo static int ure_write_1(struct ure_softc *, uint16_t, uint16_t, uint32_t); 145e1b74f21SKevin Lo static int ure_write_2(struct ure_softc *, uint16_t, uint16_t, uint32_t); 146e1b74f21SKevin Lo static int ure_write_4(struct ure_softc *, uint16_t, uint16_t, uint32_t); 147e1b74f21SKevin Lo static uint16_t ure_ocp_reg_read(struct ure_softc *, uint16_t); 148e1b74f21SKevin Lo static void ure_ocp_reg_write(struct ure_softc *, uint16_t, uint16_t); 149d4cf41a9SHans Petter Selasky static void ure_sram_write(struct ure_softc *, uint16_t, uint16_t); 150e1b74f21SKevin Lo 1517d5522e1SJohn-Mark Gurney static int ure_sysctl_chipver(SYSCTL_HANDLER_ARGS); 1527d5522e1SJohn-Mark Gurney 153e1b74f21SKevin Lo static void ure_read_chipver(struct ure_softc *); 154e1b74f21SKevin Lo static int ure_attach_post_sub(struct usb_ether *); 155e1b74f21SKevin Lo static void ure_reset(struct ure_softc *); 156935b194dSJustin Hibbits static int ure_ifmedia_upd(if_t); 157935b194dSJustin Hibbits static void ure_ifmedia_sts(if_t, struct ifmediareq *); 158d4cf41a9SHans Petter Selasky static void ure_add_media_types(struct ure_softc *); 159d4cf41a9SHans Petter Selasky static void ure_link_state(struct ure_softc *sc); 160d4cf41a9SHans Petter Selasky static int ure_get_link_status(struct ure_softc *); 161935b194dSJustin Hibbits static int ure_ioctl(if_t, u_long, caddr_t); 162e1b74f21SKevin Lo static void ure_rtl8152_init(struct ure_softc *); 163d4cf41a9SHans Petter Selasky static void ure_rtl8152_nic_reset(struct ure_softc *); 164a24d62b5SKevin Lo static void ure_rtl8153_init(struct ure_softc *); 165d4cf41a9SHans Petter Selasky static void ure_rtl8153b_init(struct ure_softc *); 166d4cf41a9SHans Petter Selasky static void ure_rtl8153b_nic_reset(struct ure_softc *); 167e1b74f21SKevin Lo static void ure_disable_teredo(struct ure_softc *); 168d4cf41a9SHans Petter Selasky static void ure_enable_aldps(struct ure_softc *, bool); 169d4cf41a9SHans Petter Selasky static uint16_t ure_phy_status(struct ure_softc *, uint16_t); 1707d5522e1SJohn-Mark Gurney static void ure_rxcsum(int capenb, struct ure_rxpkt *rp, struct mbuf *m); 1717d5522e1SJohn-Mark Gurney static int ure_txcsum(struct mbuf *m, int caps, uint32_t *regout); 172e1b74f21SKevin Lo 173e1b74f21SKevin Lo static device_method_t ure_methods[] = { 174e1b74f21SKevin Lo /* Device interface. */ 175e1b74f21SKevin Lo DEVMETHOD(device_probe, ure_probe), 176e1b74f21SKevin Lo DEVMETHOD(device_attach, ure_attach), 177e1b74f21SKevin Lo DEVMETHOD(device_detach, ure_detach), 178e1b74f21SKevin Lo 179e1b74f21SKevin Lo /* MII interface. */ 180e1b74f21SKevin Lo DEVMETHOD(miibus_readreg, ure_miibus_readreg), 181e1b74f21SKevin Lo DEVMETHOD(miibus_writereg, ure_miibus_writereg), 182e1b74f21SKevin Lo DEVMETHOD(miibus_statchg, ure_miibus_statchg), 183e1b74f21SKevin Lo 184e1b74f21SKevin Lo DEVMETHOD_END 185e1b74f21SKevin Lo }; 186e1b74f21SKevin Lo 187e1b74f21SKevin Lo static driver_t ure_driver = { 188e1b74f21SKevin Lo .name = "ure", 189e1b74f21SKevin Lo .methods = ure_methods, 190e1b74f21SKevin Lo .size = sizeof(struct ure_softc), 191e1b74f21SKevin Lo }; 192e1b74f21SKevin Lo 193bc9372d7SJohn Baldwin DRIVER_MODULE(ure, uhub, ure_driver, NULL, NULL); 1943e38757dSJohn Baldwin DRIVER_MODULE(miibus, ure, miibus_driver, NULL, NULL); 195e1b74f21SKevin Lo MODULE_DEPEND(ure, uether, 1, 1, 1); 196e1b74f21SKevin Lo MODULE_DEPEND(ure, usb, 1, 1, 1); 197e1b74f21SKevin Lo MODULE_DEPEND(ure, ether, 1, 1, 1); 198e1b74f21SKevin Lo MODULE_DEPEND(ure, miibus, 1, 1, 1); 199e1b74f21SKevin Lo MODULE_VERSION(ure, 1); 20072851e85SAllan Jude USB_PNP_HOST_INFO(ure_devs); 201e1b74f21SKevin Lo 202e1b74f21SKevin Lo static const struct usb_ether_methods ure_ue_methods = { 203e1b74f21SKevin Lo .ue_attach_post = ure_attach_post, 204e1b74f21SKevin Lo .ue_attach_post_sub = ure_attach_post_sub, 205e1b74f21SKevin Lo .ue_start = ure_start, 206e1b74f21SKevin Lo .ue_init = ure_init, 207e1b74f21SKevin Lo .ue_stop = ure_stop, 208e1b74f21SKevin Lo .ue_tick = ure_tick, 209a24d62b5SKevin Lo .ue_setmulti = ure_rxfilter, 210a24d62b5SKevin Lo .ue_setpromisc = ure_rxfilter, 211e1b74f21SKevin Lo .ue_mii_upd = ure_ifmedia_upd, 212e1b74f21SKevin Lo .ue_mii_sts = ure_ifmedia_sts, 213e1b74f21SKevin Lo }; 214e1b74f21SKevin Lo 215d4cf41a9SHans Petter Selasky #define URE_SETBIT_1(sc, reg, index, x) \ 216d4cf41a9SHans Petter Selasky ure_write_1(sc, reg, index, ure_read_1(sc, reg, index) | (x)) 217d4cf41a9SHans Petter Selasky #define URE_SETBIT_2(sc, reg, index, x) \ 218d4cf41a9SHans Petter Selasky ure_write_2(sc, reg, index, ure_read_2(sc, reg, index) | (x)) 219d4cf41a9SHans Petter Selasky #define URE_SETBIT_4(sc, reg, index, x) \ 220d4cf41a9SHans Petter Selasky ure_write_4(sc, reg, index, ure_read_4(sc, reg, index) | (x)) 221d4cf41a9SHans Petter Selasky 222d4cf41a9SHans Petter Selasky #define URE_CLRBIT_1(sc, reg, index, x) \ 223d4cf41a9SHans Petter Selasky ure_write_1(sc, reg, index, ure_read_1(sc, reg, index) & ~(x)) 224d4cf41a9SHans Petter Selasky #define URE_CLRBIT_2(sc, reg, index, x) \ 225d4cf41a9SHans Petter Selasky ure_write_2(sc, reg, index, ure_read_2(sc, reg, index) & ~(x)) 226d4cf41a9SHans Petter Selasky #define URE_CLRBIT_4(sc, reg, index, x) \ 227d4cf41a9SHans Petter Selasky ure_write_4(sc, reg, index, ure_read_4(sc, reg, index) & ~(x)) 228d4cf41a9SHans Petter Selasky 229e1b74f21SKevin Lo static int 230e1b74f21SKevin Lo ure_ctl(struct ure_softc *sc, uint8_t rw, uint16_t val, uint16_t index, 231e1b74f21SKevin Lo void *buf, int len) 232e1b74f21SKevin Lo { 233e1b74f21SKevin Lo struct usb_device_request req; 234e1b74f21SKevin Lo 235e1b74f21SKevin Lo URE_LOCK_ASSERT(sc, MA_OWNED); 236e1b74f21SKevin Lo 237e1b74f21SKevin Lo if (rw == URE_CTL_WRITE) 238e1b74f21SKevin Lo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 239e1b74f21SKevin Lo else 240e1b74f21SKevin Lo req.bmRequestType = UT_READ_VENDOR_DEVICE; 241e1b74f21SKevin Lo req.bRequest = UR_SET_ADDRESS; 242e1b74f21SKevin Lo USETW(req.wValue, val); 243e1b74f21SKevin Lo USETW(req.wIndex, index); 244e1b74f21SKevin Lo USETW(req.wLength, len); 245e1b74f21SKevin Lo 246e1b74f21SKevin Lo return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 247e1b74f21SKevin Lo } 248e1b74f21SKevin Lo 249e1b74f21SKevin Lo static int 250e1b74f21SKevin Lo ure_read_mem(struct ure_softc *sc, uint16_t addr, uint16_t index, 251e1b74f21SKevin Lo void *buf, int len) 252e1b74f21SKevin Lo { 253e1b74f21SKevin Lo 254e1b74f21SKevin Lo return (ure_ctl(sc, URE_CTL_READ, addr, index, buf, len)); 255e1b74f21SKevin Lo } 256e1b74f21SKevin Lo 257e1b74f21SKevin Lo static int 258e1b74f21SKevin Lo ure_write_mem(struct ure_softc *sc, uint16_t addr, uint16_t index, 259e1b74f21SKevin Lo void *buf, int len) 260e1b74f21SKevin Lo { 261e1b74f21SKevin Lo 262e1b74f21SKevin Lo return (ure_ctl(sc, URE_CTL_WRITE, addr, index, buf, len)); 263e1b74f21SKevin Lo } 264e1b74f21SKevin Lo 265e1b74f21SKevin Lo static uint8_t 266e1b74f21SKevin Lo ure_read_1(struct ure_softc *sc, uint16_t reg, uint16_t index) 267e1b74f21SKevin Lo { 268e1b74f21SKevin Lo uint32_t val; 269e1b74f21SKevin Lo uint8_t temp[4]; 270e1b74f21SKevin Lo uint8_t shift; 271e1b74f21SKevin Lo 272e1b74f21SKevin Lo shift = (reg & 3) << 3; 273e1b74f21SKevin Lo reg &= ~3; 274e1b74f21SKevin Lo 275e1b74f21SKevin Lo ure_read_mem(sc, reg, index, &temp, 4); 276e1b74f21SKevin Lo val = UGETDW(temp); 277e1b74f21SKevin Lo val >>= shift; 278e1b74f21SKevin Lo 279e1b74f21SKevin Lo return (val & 0xff); 280e1b74f21SKevin Lo } 281e1b74f21SKevin Lo 282e1b74f21SKevin Lo static uint16_t 283e1b74f21SKevin Lo ure_read_2(struct ure_softc *sc, uint16_t reg, uint16_t index) 284e1b74f21SKevin Lo { 285e1b74f21SKevin Lo uint32_t val; 286e1b74f21SKevin Lo uint8_t temp[4]; 287e1b74f21SKevin Lo uint8_t shift; 288e1b74f21SKevin Lo 289e1b74f21SKevin Lo shift = (reg & 2) << 3; 290e1b74f21SKevin Lo reg &= ~3; 291e1b74f21SKevin Lo 292e1b74f21SKevin Lo ure_read_mem(sc, reg, index, &temp, 4); 293e1b74f21SKevin Lo val = UGETDW(temp); 294e1b74f21SKevin Lo val >>= shift; 295e1b74f21SKevin Lo 296e1b74f21SKevin Lo return (val & 0xffff); 297e1b74f21SKevin Lo } 298e1b74f21SKevin Lo 299e1b74f21SKevin Lo static uint32_t 300e1b74f21SKevin Lo ure_read_4(struct ure_softc *sc, uint16_t reg, uint16_t index) 301e1b74f21SKevin Lo { 302e1b74f21SKevin Lo uint8_t temp[4]; 303e1b74f21SKevin Lo 304e1b74f21SKevin Lo ure_read_mem(sc, reg, index, &temp, 4); 305e1b74f21SKevin Lo return (UGETDW(temp)); 306e1b74f21SKevin Lo } 307e1b74f21SKevin Lo 308e1b74f21SKevin Lo static int 309e1b74f21SKevin Lo ure_write_1(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val) 310e1b74f21SKevin Lo { 311e1b74f21SKevin Lo uint16_t byen; 312e1b74f21SKevin Lo uint8_t temp[4]; 313e1b74f21SKevin Lo uint8_t shift; 314e1b74f21SKevin Lo 315e1b74f21SKevin Lo byen = URE_BYTE_EN_BYTE; 316e1b74f21SKevin Lo shift = reg & 3; 317e1b74f21SKevin Lo val &= 0xff; 318e1b74f21SKevin Lo 319e1b74f21SKevin Lo if (reg & 3) { 320e1b74f21SKevin Lo byen <<= shift; 321e1b74f21SKevin Lo val <<= (shift << 3); 322e1b74f21SKevin Lo reg &= ~3; 323e1b74f21SKevin Lo } 324e1b74f21SKevin Lo 325e1b74f21SKevin Lo USETDW(temp, val); 326e1b74f21SKevin Lo return (ure_write_mem(sc, reg, index | byen, &temp, 4)); 327e1b74f21SKevin Lo } 328e1b74f21SKevin Lo 329e1b74f21SKevin Lo static int 330e1b74f21SKevin Lo ure_write_2(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val) 331e1b74f21SKevin Lo { 332e1b74f21SKevin Lo uint16_t byen; 333e1b74f21SKevin Lo uint8_t temp[4]; 334e1b74f21SKevin Lo uint8_t shift; 335e1b74f21SKevin Lo 336e1b74f21SKevin Lo byen = URE_BYTE_EN_WORD; 337e1b74f21SKevin Lo shift = reg & 2; 338e1b74f21SKevin Lo val &= 0xffff; 339e1b74f21SKevin Lo 340e1b74f21SKevin Lo if (reg & 2) { 341e1b74f21SKevin Lo byen <<= shift; 342e1b74f21SKevin Lo val <<= (shift << 3); 343e1b74f21SKevin Lo reg &= ~3; 344e1b74f21SKevin Lo } 345e1b74f21SKevin Lo 346e1b74f21SKevin Lo USETDW(temp, val); 347e1b74f21SKevin Lo return (ure_write_mem(sc, reg, index | byen, &temp, 4)); 348e1b74f21SKevin Lo } 349e1b74f21SKevin Lo 350e1b74f21SKevin Lo static int 351e1b74f21SKevin Lo ure_write_4(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val) 352e1b74f21SKevin Lo { 353e1b74f21SKevin Lo uint8_t temp[4]; 354e1b74f21SKevin Lo 355e1b74f21SKevin Lo USETDW(temp, val); 356e1b74f21SKevin Lo return (ure_write_mem(sc, reg, index | URE_BYTE_EN_DWORD, &temp, 4)); 357e1b74f21SKevin Lo } 358e1b74f21SKevin Lo 359e1b74f21SKevin Lo static uint16_t 360e1b74f21SKevin Lo ure_ocp_reg_read(struct ure_softc *sc, uint16_t addr) 361e1b74f21SKevin Lo { 362e1b74f21SKevin Lo uint16_t reg; 363e1b74f21SKevin Lo 364e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); 365e1b74f21SKevin Lo reg = (addr & 0x0fff) | 0xb000; 366e1b74f21SKevin Lo 367e1b74f21SKevin Lo return (ure_read_2(sc, reg, URE_MCU_TYPE_PLA)); 368e1b74f21SKevin Lo } 369e1b74f21SKevin Lo 370e1b74f21SKevin Lo static void 371e1b74f21SKevin Lo ure_ocp_reg_write(struct ure_softc *sc, uint16_t addr, uint16_t data) 372e1b74f21SKevin Lo { 373e1b74f21SKevin Lo uint16_t reg; 374e1b74f21SKevin Lo 375e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); 376e1b74f21SKevin Lo reg = (addr & 0x0fff) | 0xb000; 377e1b74f21SKevin Lo 378e1b74f21SKevin Lo ure_write_2(sc, reg, URE_MCU_TYPE_PLA, data); 379e1b74f21SKevin Lo } 380e1b74f21SKevin Lo 381d4cf41a9SHans Petter Selasky static void 382d4cf41a9SHans Petter Selasky ure_sram_write(struct ure_softc *sc, uint16_t addr, uint16_t data) 383d4cf41a9SHans Petter Selasky { 384d4cf41a9SHans Petter Selasky ure_ocp_reg_write(sc, URE_OCP_SRAM_ADDR, addr); 385d4cf41a9SHans Petter Selasky ure_ocp_reg_write(sc, URE_OCP_SRAM_DATA, data); 386d4cf41a9SHans Petter Selasky } 387d4cf41a9SHans Petter Selasky 388e1b74f21SKevin Lo static int 389e1b74f21SKevin Lo ure_miibus_readreg(device_t dev, int phy, int reg) 390e1b74f21SKevin Lo { 391e1b74f21SKevin Lo struct ure_softc *sc; 392e1b74f21SKevin Lo uint16_t val; 393e1b74f21SKevin Lo int locked; 394e1b74f21SKevin Lo 395e1b74f21SKevin Lo sc = device_get_softc(dev); 396e1b74f21SKevin Lo locked = mtx_owned(&sc->sc_mtx); 397e1b74f21SKevin Lo if (!locked) 398e1b74f21SKevin Lo URE_LOCK(sc); 399e1b74f21SKevin Lo 400a24d62b5SKevin Lo /* Let the rgephy driver read the URE_GMEDIASTAT register. */ 401a24d62b5SKevin Lo if (reg == URE_GMEDIASTAT) { 402a24d62b5SKevin Lo if (!locked) 403a24d62b5SKevin Lo URE_UNLOCK(sc); 404a24d62b5SKevin Lo return (ure_read_1(sc, URE_GMEDIASTAT, URE_MCU_TYPE_PLA)); 405a24d62b5SKevin Lo } 406a24d62b5SKevin Lo 407e1b74f21SKevin Lo val = ure_ocp_reg_read(sc, URE_OCP_BASE_MII + reg * 2); 408e1b74f21SKevin Lo 409e1b74f21SKevin Lo if (!locked) 410e1b74f21SKevin Lo URE_UNLOCK(sc); 411e1b74f21SKevin Lo return (val); 412e1b74f21SKevin Lo } 413e1b74f21SKevin Lo 414e1b74f21SKevin Lo static int 415e1b74f21SKevin Lo ure_miibus_writereg(device_t dev, int phy, int reg, int val) 416e1b74f21SKevin Lo { 417e1b74f21SKevin Lo struct ure_softc *sc; 418e1b74f21SKevin Lo int locked; 419e1b74f21SKevin Lo 420e1b74f21SKevin Lo sc = device_get_softc(dev); 421e1b74f21SKevin Lo if (sc->sc_phyno != phy) 422e1b74f21SKevin Lo return (0); 423e1b74f21SKevin Lo 424e1b74f21SKevin Lo locked = mtx_owned(&sc->sc_mtx); 425e1b74f21SKevin Lo if (!locked) 426e1b74f21SKevin Lo URE_LOCK(sc); 427e1b74f21SKevin Lo 428e1b74f21SKevin Lo ure_ocp_reg_write(sc, URE_OCP_BASE_MII + reg * 2, val); 429e1b74f21SKevin Lo 430e1b74f21SKevin Lo if (!locked) 431e1b74f21SKevin Lo URE_UNLOCK(sc); 432e1b74f21SKevin Lo return (0); 433e1b74f21SKevin Lo } 434e1b74f21SKevin Lo 435e1b74f21SKevin Lo static void 436e1b74f21SKevin Lo ure_miibus_statchg(device_t dev) 437e1b74f21SKevin Lo { 438e1b74f21SKevin Lo struct ure_softc *sc; 439e1b74f21SKevin Lo struct mii_data *mii; 440935b194dSJustin Hibbits if_t ifp; 441e1b74f21SKevin Lo int locked; 442e1b74f21SKevin Lo 443e1b74f21SKevin Lo sc = device_get_softc(dev); 444e1b74f21SKevin Lo mii = GET_MII(sc); 445e1b74f21SKevin Lo locked = mtx_owned(&sc->sc_mtx); 446e1b74f21SKevin Lo if (!locked) 447e1b74f21SKevin Lo URE_LOCK(sc); 448e1b74f21SKevin Lo 449e1b74f21SKevin Lo ifp = uether_getifp(&sc->sc_ue); 450e1b74f21SKevin Lo if (mii == NULL || ifp == NULL || 451935b194dSJustin Hibbits (if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) 452e1b74f21SKevin Lo goto done; 453e1b74f21SKevin Lo 454e1b74f21SKevin Lo sc->sc_flags &= ~URE_FLAG_LINK; 455e1b74f21SKevin Lo if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 456e1b74f21SKevin Lo (IFM_ACTIVE | IFM_AVALID)) { 457e1b74f21SKevin Lo switch (IFM_SUBTYPE(mii->mii_media_active)) { 458e1b74f21SKevin Lo case IFM_10_T: 459e1b74f21SKevin Lo case IFM_100_TX: 460e1b74f21SKevin Lo sc->sc_flags |= URE_FLAG_LINK; 4617d5522e1SJohn-Mark Gurney sc->sc_rxstarted = 0; 462e1b74f21SKevin Lo break; 463a24d62b5SKevin Lo case IFM_1000_T: 464a24d62b5SKevin Lo if ((sc->sc_flags & URE_FLAG_8152) != 0) 465a24d62b5SKevin Lo break; 466a24d62b5SKevin Lo sc->sc_flags |= URE_FLAG_LINK; 4677d5522e1SJohn-Mark Gurney sc->sc_rxstarted = 0; 468a24d62b5SKevin Lo break; 469e1b74f21SKevin Lo default: 470e1b74f21SKevin Lo break; 471e1b74f21SKevin Lo } 472e1b74f21SKevin Lo } 473e1b74f21SKevin Lo 474e1b74f21SKevin Lo /* Lost link, do nothing. */ 475e1b74f21SKevin Lo if ((sc->sc_flags & URE_FLAG_LINK) == 0) 476e1b74f21SKevin Lo goto done; 477e1b74f21SKevin Lo done: 478e1b74f21SKevin Lo if (!locked) 479e1b74f21SKevin Lo URE_UNLOCK(sc); 480e1b74f21SKevin Lo } 481e1b74f21SKevin Lo 482e1b74f21SKevin Lo /* 4836ea4d95fSLi-Wen Hsu * Probe for a RTL8152/RTL8153/RTL8156 chip. 484e1b74f21SKevin Lo */ 485e1b74f21SKevin Lo static int 486e1b74f21SKevin Lo ure_probe(device_t dev) 487e1b74f21SKevin Lo { 488e1b74f21SKevin Lo struct usb_attach_arg *uaa; 489e1b74f21SKevin Lo 49074b8d63dSPedro F. Giffuni uaa = device_get_ivars(dev); 491e1b74f21SKevin Lo if (uaa->usb_mode != USB_MODE_HOST) 492e1b74f21SKevin Lo return (ENXIO); 493e1b74f21SKevin Lo if (uaa->info.bIfaceIndex != URE_IFACE_IDX) 494e1b74f21SKevin Lo return (ENXIO); 495e1b74f21SKevin Lo 496e1b74f21SKevin Lo return (usbd_lookup_id_by_uaa(ure_devs, sizeof(ure_devs), uaa)); 497e1b74f21SKevin Lo } 498e1b74f21SKevin Lo 499e1b74f21SKevin Lo /* 500e1b74f21SKevin Lo * Attach the interface. Allocate softc structures, do ifmedia 501e1b74f21SKevin Lo * setup and ethernet/BPF attach. 502e1b74f21SKevin Lo */ 503e1b74f21SKevin Lo static int 504e1b74f21SKevin Lo ure_attach(device_t dev) 505e1b74f21SKevin Lo { 506e1b74f21SKevin Lo struct usb_attach_arg *uaa = device_get_ivars(dev); 507e1b74f21SKevin Lo struct ure_softc *sc = device_get_softc(dev); 508e1b74f21SKevin Lo struct usb_ether *ue = &sc->sc_ue; 509d4cf41a9SHans Petter Selasky struct usb_config ure_config_rx[URE_MAX_RX]; 510d4cf41a9SHans Petter Selasky struct usb_config ure_config_tx[URE_MAX_TX]; 511e1b74f21SKevin Lo uint8_t iface_index; 512e1b74f21SKevin Lo int error; 513d4cf41a9SHans Petter Selasky int i; 514e1b74f21SKevin Lo 515a24d62b5SKevin Lo sc->sc_flags = USB_GET_DRIVER_INFO(uaa); 516e1b74f21SKevin Lo device_set_usb_desc(dev); 517e1b74f21SKevin Lo mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 518e1b74f21SKevin Lo 519e1b74f21SKevin Lo iface_index = URE_IFACE_IDX; 520d4cf41a9SHans Petter Selasky 521d4cf41a9SHans Petter Selasky if (sc->sc_flags & (URE_FLAG_8153 | URE_FLAG_8153B)) 522d4cf41a9SHans Petter Selasky sc->sc_rxbufsz = URE_8153_RX_BUFSZ; 523d4cf41a9SHans Petter Selasky else if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) 524d4cf41a9SHans Petter Selasky sc->sc_rxbufsz = URE_8156_RX_BUFSZ; 525d4cf41a9SHans Petter Selasky else 526d4cf41a9SHans Petter Selasky sc->sc_rxbufsz = URE_8152_RX_BUFSZ; 527d4cf41a9SHans Petter Selasky 528d4cf41a9SHans Petter Selasky for (i = 0; i < URE_MAX_RX; i++) { 529d4cf41a9SHans Petter Selasky ure_config_rx[i] = (struct usb_config) { 530d4cf41a9SHans Petter Selasky .type = UE_BULK, 531d4cf41a9SHans Petter Selasky .endpoint = UE_ADDR_ANY, 532d4cf41a9SHans Petter Selasky .direction = UE_DIR_IN, 533d4cf41a9SHans Petter Selasky .bufsize = sc->sc_rxbufsz, 534d4cf41a9SHans Petter Selasky .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 535d4cf41a9SHans Petter Selasky .callback = ure_bulk_read_callback, 536d4cf41a9SHans Petter Selasky .timeout = 0, /* no timeout */ 537d4cf41a9SHans Petter Selasky }; 538d4cf41a9SHans Petter Selasky } 5397d5522e1SJohn-Mark Gurney error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_rx_xfer, 540d4cf41a9SHans Petter Selasky ure_config_rx, URE_MAX_RX, sc, &sc->sc_mtx); 541e1b74f21SKevin Lo if (error != 0) { 5427d5522e1SJohn-Mark Gurney device_printf(dev, "allocating USB RX transfers failed\n"); 543e1b74f21SKevin Lo goto detach; 544e1b74f21SKevin Lo } 545e1b74f21SKevin Lo 546d4cf41a9SHans Petter Selasky for (i = 0; i < URE_MAX_TX; i++) { 547d4cf41a9SHans Petter Selasky ure_config_tx[i] = (struct usb_config) { 548d4cf41a9SHans Petter Selasky .type = UE_BULK, 549d4cf41a9SHans Petter Selasky .endpoint = UE_ADDR_ANY, 550d4cf41a9SHans Petter Selasky .direction = UE_DIR_OUT, 551d4cf41a9SHans Petter Selasky .bufsize = URE_TX_BUFSZ, 552d4cf41a9SHans Petter Selasky .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 553d4cf41a9SHans Petter Selasky .callback = ure_bulk_write_callback, 554d4cf41a9SHans Petter Selasky .timeout = 10000, /* 10 seconds */ 555d4cf41a9SHans Petter Selasky }; 556d4cf41a9SHans Petter Selasky } 5577d5522e1SJohn-Mark Gurney error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_tx_xfer, 558d4cf41a9SHans Petter Selasky ure_config_tx, URE_MAX_TX, sc, &sc->sc_mtx); 5597d5522e1SJohn-Mark Gurney if (error != 0) { 560d4cf41a9SHans Petter Selasky usbd_transfer_unsetup(sc->sc_rx_xfer, URE_MAX_RX); 5617d5522e1SJohn-Mark Gurney device_printf(dev, "allocating USB TX transfers failed\n"); 5627d5522e1SJohn-Mark Gurney goto detach; 5637d5522e1SJohn-Mark Gurney } 5647d5522e1SJohn-Mark Gurney 565e1b74f21SKevin Lo ue->ue_sc = sc; 566e1b74f21SKevin Lo ue->ue_dev = dev; 567e1b74f21SKevin Lo ue->ue_udev = uaa->device; 568e1b74f21SKevin Lo ue->ue_mtx = &sc->sc_mtx; 569e1b74f21SKevin Lo ue->ue_methods = &ure_ue_methods; 570e1b74f21SKevin Lo 571e1b74f21SKevin Lo error = uether_ifattach(ue); 572e1b74f21SKevin Lo if (error != 0) { 573e1b74f21SKevin Lo device_printf(dev, "could not attach interface\n"); 574e1b74f21SKevin Lo goto detach; 575e1b74f21SKevin Lo } 576e1b74f21SKevin Lo return (0); /* success */ 577e1b74f21SKevin Lo 578e1b74f21SKevin Lo detach: 579e1b74f21SKevin Lo ure_detach(dev); 580e1b74f21SKevin Lo return (ENXIO); /* failure */ 581e1b74f21SKevin Lo } 582e1b74f21SKevin Lo 583e1b74f21SKevin Lo static int 584e1b74f21SKevin Lo ure_detach(device_t dev) 585e1b74f21SKevin Lo { 586e1b74f21SKevin Lo struct ure_softc *sc = device_get_softc(dev); 587e1b74f21SKevin Lo struct usb_ether *ue = &sc->sc_ue; 588e1b74f21SKevin Lo 589d4cf41a9SHans Petter Selasky usbd_transfer_unsetup(sc->sc_tx_xfer, URE_MAX_TX); 590d4cf41a9SHans Petter Selasky usbd_transfer_unsetup(sc->sc_rx_xfer, URE_MAX_RX); 591e1b74f21SKevin Lo uether_ifdetach(ue); 592e1b74f21SKevin Lo mtx_destroy(&sc->sc_mtx); 593e1b74f21SKevin Lo 594e1b74f21SKevin Lo return (0); 595e1b74f21SKevin Lo } 596e1b74f21SKevin Lo 5977d5522e1SJohn-Mark Gurney /* 5987d5522e1SJohn-Mark Gurney * Copy from USB buffers to a new mbuf chain with pkt header. 5997d5522e1SJohn-Mark Gurney * 6007d5522e1SJohn-Mark Gurney * This will use m_getm2 to get a mbuf chain w/ properly sized mbuf 6017d5522e1SJohn-Mark Gurney * clusters as necessary. 6027d5522e1SJohn-Mark Gurney */ 6037d5522e1SJohn-Mark Gurney static struct mbuf * 6047d5522e1SJohn-Mark Gurney ure_makembuf(struct usb_page_cache *pc, usb_frlength_t offset, 6057d5522e1SJohn-Mark Gurney usb_frlength_t len) 6067d5522e1SJohn-Mark Gurney { 6077d5522e1SJohn-Mark Gurney struct usb_page_search_res; 6087d5522e1SJohn-Mark Gurney struct mbuf *m, *mb; 6097d5522e1SJohn-Mark Gurney usb_frlength_t tlen; 6107d5522e1SJohn-Mark Gurney 6117d5522e1SJohn-Mark Gurney m = m_getm2(NULL, len + ETHER_ALIGN, M_NOWAIT, MT_DATA, M_PKTHDR); 6127d5522e1SJohn-Mark Gurney if (m == NULL) 6137d5522e1SJohn-Mark Gurney return (m); 6147d5522e1SJohn-Mark Gurney 6157d5522e1SJohn-Mark Gurney /* uether_newbuf does this. */ 6167d5522e1SJohn-Mark Gurney m_adj(m, ETHER_ALIGN); 6177d5522e1SJohn-Mark Gurney 6187d5522e1SJohn-Mark Gurney m->m_pkthdr.len = len; 6197d5522e1SJohn-Mark Gurney 6207d5522e1SJohn-Mark Gurney for (mb = m; len > 0; mb = mb->m_next) { 6217d5522e1SJohn-Mark Gurney tlen = MIN(len, M_TRAILINGSPACE(mb)); 6227d5522e1SJohn-Mark Gurney 6237d5522e1SJohn-Mark Gurney usbd_copy_out(pc, offset, mtod(mb, uint8_t *), tlen); 6247d5522e1SJohn-Mark Gurney mb->m_len = tlen; 6257d5522e1SJohn-Mark Gurney 6267d5522e1SJohn-Mark Gurney offset += tlen; 6277d5522e1SJohn-Mark Gurney len -= tlen; 6287d5522e1SJohn-Mark Gurney } 6297d5522e1SJohn-Mark Gurney 6307d5522e1SJohn-Mark Gurney return (m); 6317d5522e1SJohn-Mark Gurney } 6327d5522e1SJohn-Mark Gurney 633e1b74f21SKevin Lo static void 634e1b74f21SKevin Lo ure_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 635e1b74f21SKevin Lo { 636e1b74f21SKevin Lo struct ure_softc *sc = usbd_xfer_softc(xfer); 637e1b74f21SKevin Lo struct usb_ether *ue = &sc->sc_ue; 638935b194dSJustin Hibbits if_t ifp = uether_getifp(ue); 639e1b74f21SKevin Lo struct usb_page_cache *pc; 6407d5522e1SJohn-Mark Gurney struct mbuf *m; 641e1b74f21SKevin Lo struct ure_rxpkt pkt; 6427d5522e1SJohn-Mark Gurney int actlen, off, len; 6437d5522e1SJohn-Mark Gurney int caps; 6447d5522e1SJohn-Mark Gurney uint32_t pktcsum; 645e1b74f21SKevin Lo 646e1b74f21SKevin Lo usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 647e1b74f21SKevin Lo 648e1b74f21SKevin Lo switch (USB_GET_STATE(xfer)) { 649e1b74f21SKevin Lo case USB_ST_TRANSFERRED: 6507d5522e1SJohn-Mark Gurney off = 0; 6517d5522e1SJohn-Mark Gurney pc = usbd_xfer_get_frame(xfer, 0); 6527d5522e1SJohn-Mark Gurney caps = if_getcapenable(ifp); 6537d5522e1SJohn-Mark Gurney DEVPRINTFN(13, sc->sc_ue.ue_dev, "rcb start\n"); 6547d5522e1SJohn-Mark Gurney while (actlen > 0) { 655e1b74f21SKevin Lo if (actlen < (int)(sizeof(pkt))) { 656e1b74f21SKevin Lo if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 657e1b74f21SKevin Lo goto tr_setup; 658e1b74f21SKevin Lo } 6597d5522e1SJohn-Mark Gurney usbd_copy_out(pc, off, &pkt, sizeof(pkt)); 6607d5522e1SJohn-Mark Gurney 6617d5522e1SJohn-Mark Gurney off += sizeof(pkt); 6627d5522e1SJohn-Mark Gurney actlen -= sizeof(pkt); 6637d5522e1SJohn-Mark Gurney 664e1b74f21SKevin Lo len = le32toh(pkt.ure_pktlen) & URE_RXPKT_LEN_MASK; 6657d5522e1SJohn-Mark Gurney 6667d5522e1SJohn-Mark Gurney DEVPRINTFN(13, sc->sc_ue.ue_dev, 6677d5522e1SJohn-Mark Gurney "rxpkt: %#x, %#x, %#x, %#x, %#x, %#x\n", 6687d5522e1SJohn-Mark Gurney pkt.ure_pktlen, pkt.ure_csum, pkt.ure_misc, 6697d5522e1SJohn-Mark Gurney pkt.ure_rsvd2, pkt.ure_rsvd3, pkt.ure_rsvd4); 6707d5522e1SJohn-Mark Gurney DEVPRINTFN(13, sc->sc_ue.ue_dev, "len: %d\n", len); 6717d5522e1SJohn-Mark Gurney 6727d5522e1SJohn-Mark Gurney if (len >= URE_RXPKT_LEN_MASK) { 6737d5522e1SJohn-Mark Gurney /* 6747d5522e1SJohn-Mark Gurney * drop the rest of this segment. With out 6757d5522e1SJohn-Mark Gurney * more information, we cannot know where next 6767d5522e1SJohn-Mark Gurney * packet starts. Blindly continuing would 6777d5522e1SJohn-Mark Gurney * cause a packet in packet attack, allowing 6787d5522e1SJohn-Mark Gurney * one VLAN to inject packets w/o a VLAN tag, 6797d5522e1SJohn-Mark Gurney * or injecting packets into other VLANs. 6807d5522e1SJohn-Mark Gurney */ 681e1b74f21SKevin Lo if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 682e1b74f21SKevin Lo goto tr_setup; 683e1b74f21SKevin Lo } 684e1b74f21SKevin Lo 6857d5522e1SJohn-Mark Gurney if (actlen < len) { 6867d5522e1SJohn-Mark Gurney if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 6877d5522e1SJohn-Mark Gurney goto tr_setup; 6887d5522e1SJohn-Mark Gurney } 6897d5522e1SJohn-Mark Gurney 6907d0368eeSHans Petter Selasky if (len >= (ETHER_HDR_LEN + ETHER_CRC_LEN)) 6917d5522e1SJohn-Mark Gurney m = ure_makembuf(pc, off, len - ETHER_CRC_LEN); 6927d5522e1SJohn-Mark Gurney else 6937d5522e1SJohn-Mark Gurney m = NULL; 6947d5522e1SJohn-Mark Gurney if (m == NULL) { 6957d5522e1SJohn-Mark Gurney if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 6967d5522e1SJohn-Mark Gurney } else { 6977d5522e1SJohn-Mark Gurney /* make mbuf and queue */ 6987d5522e1SJohn-Mark Gurney pktcsum = le32toh(pkt.ure_csum); 6997d5522e1SJohn-Mark Gurney if (caps & IFCAP_VLAN_HWTAGGING && 7007d5522e1SJohn-Mark Gurney pktcsum & URE_RXPKT_RX_VLAN_TAG) { 7017d5522e1SJohn-Mark Gurney m->m_pkthdr.ether_vtag = 7027d5522e1SJohn-Mark Gurney bswap16(pktcsum & 7037d5522e1SJohn-Mark Gurney URE_RXPKT_VLAN_MASK); 7047d5522e1SJohn-Mark Gurney m->m_flags |= M_VLANTAG; 7057d5522e1SJohn-Mark Gurney } 7067d5522e1SJohn-Mark Gurney 7077d5522e1SJohn-Mark Gurney /* set the necessary flags for rx checksum */ 7087d5522e1SJohn-Mark Gurney ure_rxcsum(caps, &pkt, m); 7097d5522e1SJohn-Mark Gurney 7107d5522e1SJohn-Mark Gurney uether_rxmbuf(ue, m, len - ETHER_CRC_LEN); 7117d5522e1SJohn-Mark Gurney } 7127d5522e1SJohn-Mark Gurney 7137d5522e1SJohn-Mark Gurney off += roundup(len, URE_RXPKT_ALIGN); 7147d5522e1SJohn-Mark Gurney actlen -= roundup(len, URE_RXPKT_ALIGN); 7157d5522e1SJohn-Mark Gurney } 7167d5522e1SJohn-Mark Gurney DEVPRINTFN(13, sc->sc_ue.ue_dev, "rcb end\n"); 7177d5522e1SJohn-Mark Gurney 718e1b74f21SKevin Lo /* FALLTHROUGH */ 719e1b74f21SKevin Lo case USB_ST_SETUP: 720e1b74f21SKevin Lo tr_setup: 721e1b74f21SKevin Lo usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 722e1b74f21SKevin Lo usbd_transfer_submit(xfer); 723e1b74f21SKevin Lo uether_rxflush(ue); 724e1b74f21SKevin Lo return; 725e1b74f21SKevin Lo 726e1b74f21SKevin Lo default: /* Error */ 727e1b74f21SKevin Lo DPRINTF("bulk read error, %s\n", 728e1b74f21SKevin Lo usbd_errstr(error)); 729e1b74f21SKevin Lo 730e1b74f21SKevin Lo if (error != USB_ERR_CANCELLED) { 731e1b74f21SKevin Lo /* try to clear stall first */ 732e1b74f21SKevin Lo usbd_xfer_set_stall(xfer); 733e1b74f21SKevin Lo goto tr_setup; 734e1b74f21SKevin Lo } 735e1b74f21SKevin Lo return; 736e1b74f21SKevin Lo } 737e1b74f21SKevin Lo } 738e1b74f21SKevin Lo 739e1b74f21SKevin Lo static void 740e1b74f21SKevin Lo ure_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 741e1b74f21SKevin Lo { 742e1b74f21SKevin Lo struct ure_softc *sc = usbd_xfer_softc(xfer); 743935b194dSJustin Hibbits if_t ifp = uether_getifp(&sc->sc_ue); 744e1b74f21SKevin Lo struct usb_page_cache *pc; 745e1b74f21SKevin Lo struct mbuf *m; 746e1b74f21SKevin Lo struct ure_txpkt txpkt; 7477d5522e1SJohn-Mark Gurney uint32_t regtmp; 748e1b74f21SKevin Lo int len, pos; 7497d5522e1SJohn-Mark Gurney int rem; 7507d5522e1SJohn-Mark Gurney int caps; 751e1b74f21SKevin Lo 752e1b74f21SKevin Lo switch (USB_GET_STATE(xfer)) { 753e1b74f21SKevin Lo case USB_ST_TRANSFERRED: 754e1b74f21SKevin Lo DPRINTFN(11, "transfer complete\n"); 755935b194dSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 7567d5522e1SJohn-Mark Gurney 757e1b74f21SKevin Lo /* FALLTHROUGH */ 758e1b74f21SKevin Lo case USB_ST_SETUP: 759e1b74f21SKevin Lo tr_setup: 7607d5522e1SJohn-Mark Gurney if ((sc->sc_flags & URE_FLAG_LINK) == 0) { 7617d5522e1SJohn-Mark Gurney /* don't send anything if there is no link! */ 7627d5522e1SJohn-Mark Gurney break; 763e1b74f21SKevin Lo } 7647d5522e1SJohn-Mark Gurney 7657d5522e1SJohn-Mark Gurney pc = usbd_xfer_get_frame(xfer, 0); 7667d5522e1SJohn-Mark Gurney caps = if_getcapenable(ifp); 7677d5522e1SJohn-Mark Gurney 7687d5522e1SJohn-Mark Gurney pos = 0; 769d4cf41a9SHans Petter Selasky rem = URE_TX_BUFSZ; 7707d5522e1SJohn-Mark Gurney while (rem > sizeof(txpkt)) { 771935b194dSJustin Hibbits m = if_dequeue(ifp); 772e1b74f21SKevin Lo if (m == NULL) 773e1b74f21SKevin Lo break; 7747d5522e1SJohn-Mark Gurney 7757d5522e1SJohn-Mark Gurney /* 7767d5522e1SJohn-Mark Gurney * make sure we don't ever send too large of a 7777d5522e1SJohn-Mark Gurney * packet 7787d5522e1SJohn-Mark Gurney */ 779e1b74f21SKevin Lo len = m->m_pkthdr.len; 7807d5522e1SJohn-Mark Gurney if ((len & URE_TXPKT_LEN_MASK) != len) { 7817d5522e1SJohn-Mark Gurney device_printf(sc->sc_ue.ue_dev, 7827d5522e1SJohn-Mark Gurney "pkt len too large: %#x", len); 7837d5522e1SJohn-Mark Gurney pkterror: 7847d5522e1SJohn-Mark Gurney if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 7857d5522e1SJohn-Mark Gurney m_freem(m); 7867d5522e1SJohn-Mark Gurney continue; 7877d5522e1SJohn-Mark Gurney } 7887d5522e1SJohn-Mark Gurney 7897d5522e1SJohn-Mark Gurney if (sizeof(txpkt) + 7907d5522e1SJohn-Mark Gurney roundup(len, URE_TXPKT_ALIGN) > rem) { 7917d5522e1SJohn-Mark Gurney /* out of space */ 792935b194dSJustin Hibbits if_sendq_prepend(ifp, m); 7937d5522e1SJohn-Mark Gurney m = NULL; 7947d5522e1SJohn-Mark Gurney break; 7957d5522e1SJohn-Mark Gurney } 7967d5522e1SJohn-Mark Gurney 7977d5522e1SJohn-Mark Gurney txpkt = (struct ure_txpkt){}; 798e1b74f21SKevin Lo txpkt.ure_pktlen = htole32((len & URE_TXPKT_LEN_MASK) | 799e1b74f21SKevin Lo URE_TKPKT_TX_FS | URE_TKPKT_TX_LS); 8007d5522e1SJohn-Mark Gurney if (m->m_flags & M_VLANTAG) { 8017d5522e1SJohn-Mark Gurney txpkt.ure_csum = htole32( 8027d5522e1SJohn-Mark Gurney bswap16(m->m_pkthdr.ether_vtag & 8037d5522e1SJohn-Mark Gurney URE_TXPKT_VLAN_MASK) | URE_TXPKT_VLAN); 8047d5522e1SJohn-Mark Gurney } 8057d5522e1SJohn-Mark Gurney if (ure_txcsum(m, caps, ®tmp)) { 8067d5522e1SJohn-Mark Gurney device_printf(sc->sc_ue.ue_dev, 8077d5522e1SJohn-Mark Gurney "pkt l4 off too large"); 8087d5522e1SJohn-Mark Gurney goto pkterror; 8097d5522e1SJohn-Mark Gurney } 8107d5522e1SJohn-Mark Gurney txpkt.ure_csum |= htole32(regtmp); 8117d5522e1SJohn-Mark Gurney 8127d5522e1SJohn-Mark Gurney DEVPRINTFN(13, sc->sc_ue.ue_dev, 8137d5522e1SJohn-Mark Gurney "txpkt: mbflg: %#x, %#x, %#x\n", 8147d5522e1SJohn-Mark Gurney m->m_pkthdr.csum_flags, le32toh(txpkt.ure_pktlen), 8157d5522e1SJohn-Mark Gurney le32toh(txpkt.ure_csum)); 8167d5522e1SJohn-Mark Gurney 817e1b74f21SKevin Lo usbd_copy_in(pc, pos, &txpkt, sizeof(txpkt)); 8187d5522e1SJohn-Mark Gurney 819e1b74f21SKevin Lo pos += sizeof(txpkt); 8207d5522e1SJohn-Mark Gurney rem -= sizeof(txpkt); 8217d5522e1SJohn-Mark Gurney 8227d5522e1SJohn-Mark Gurney usbd_m_copy_in(pc, pos, m, 0, len); 8237d5522e1SJohn-Mark Gurney 8247d5522e1SJohn-Mark Gurney pos += roundup(len, URE_TXPKT_ALIGN); 8257d5522e1SJohn-Mark Gurney rem -= roundup(len, URE_TXPKT_ALIGN); 826e1b74f21SKevin Lo 827e1b74f21SKevin Lo if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 828e1b74f21SKevin Lo 829e1b74f21SKevin Lo /* 830e1b74f21SKevin Lo * If there's a BPF listener, bounce a copy 831e1b74f21SKevin Lo * of this frame to him. 832e1b74f21SKevin Lo */ 833e1b74f21SKevin Lo BPF_MTAP(ifp, m); 834e1b74f21SKevin Lo 835e1b74f21SKevin Lo m_freem(m); 8367d5522e1SJohn-Mark Gurney } 8377d5522e1SJohn-Mark Gurney 8387d5522e1SJohn-Mark Gurney /* no packets to send */ 8397d5522e1SJohn-Mark Gurney if (pos == 0) 8407d5522e1SJohn-Mark Gurney break; 841e1b74f21SKevin Lo 842e1b74f21SKevin Lo /* Set frame length. */ 843e1b74f21SKevin Lo usbd_xfer_set_frame_len(xfer, 0, pos); 844e1b74f21SKevin Lo 845e1b74f21SKevin Lo usbd_transfer_submit(xfer); 8467d5522e1SJohn-Mark Gurney 847e1b74f21SKevin Lo return; 8487d5522e1SJohn-Mark Gurney 849e1b74f21SKevin Lo default: /* Error */ 850e1b74f21SKevin Lo DPRINTFN(11, "transfer error, %s\n", 851e1b74f21SKevin Lo usbd_errstr(error)); 852e1b74f21SKevin Lo 853e1b74f21SKevin Lo if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 854935b194dSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 855e1b74f21SKevin Lo 8567d5522e1SJohn-Mark Gurney if (error == USB_ERR_TIMEOUT) { 8577d5522e1SJohn-Mark Gurney DEVPRINTFN(12, sc->sc_ue.ue_dev, 8587d5522e1SJohn-Mark Gurney "pkt tx timeout\n"); 8597d5522e1SJohn-Mark Gurney } 8607d5522e1SJohn-Mark Gurney 861e1b74f21SKevin Lo if (error != USB_ERR_CANCELLED) { 862e1b74f21SKevin Lo /* try to clear stall first */ 863e1b74f21SKevin Lo usbd_xfer_set_stall(xfer); 864e1b74f21SKevin Lo goto tr_setup; 865e1b74f21SKevin Lo } 866e1b74f21SKevin Lo } 867e1b74f21SKevin Lo } 868e1b74f21SKevin Lo 869e1b74f21SKevin Lo static void 870e1b74f21SKevin Lo ure_read_chipver(struct ure_softc *sc) 871e1b74f21SKevin Lo { 872e1b74f21SKevin Lo uint16_t ver; 873e1b74f21SKevin Lo 874e1b74f21SKevin Lo ver = ure_read_2(sc, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK; 8757d5522e1SJohn-Mark Gurney sc->sc_ver = ver; 876e1b74f21SKevin Lo switch (ver) { 877e1b74f21SKevin Lo case 0x4c00: 878e1b74f21SKevin Lo sc->sc_chip |= URE_CHIP_VER_4C00; 879d4cf41a9SHans Petter Selasky sc->sc_flags = URE_FLAG_8152; 880e1b74f21SKevin Lo break; 881e1b74f21SKevin Lo case 0x4c10: 882e1b74f21SKevin Lo sc->sc_chip |= URE_CHIP_VER_4C10; 883d4cf41a9SHans Petter Selasky sc->sc_flags = URE_FLAG_8152; 884e1b74f21SKevin Lo break; 885a24d62b5SKevin Lo case 0x5c00: 886a24d62b5SKevin Lo sc->sc_chip |= URE_CHIP_VER_5C00; 887d4cf41a9SHans Petter Selasky sc->sc_flags = URE_FLAG_8153; 888a24d62b5SKevin Lo break; 889a24d62b5SKevin Lo case 0x5c10: 890a24d62b5SKevin Lo sc->sc_chip |= URE_CHIP_VER_5C10; 891d4cf41a9SHans Petter Selasky sc->sc_flags = URE_FLAG_8153; 892a24d62b5SKevin Lo break; 893a24d62b5SKevin Lo case 0x5c20: 894a24d62b5SKevin Lo sc->sc_chip |= URE_CHIP_VER_5C20; 895d4cf41a9SHans Petter Selasky sc->sc_flags = URE_FLAG_8153; 896a24d62b5SKevin Lo break; 897a24d62b5SKevin Lo case 0x5c30: 898a24d62b5SKevin Lo sc->sc_chip |= URE_CHIP_VER_5C30; 899d4cf41a9SHans Petter Selasky sc->sc_flags = URE_FLAG_8153; 900d4cf41a9SHans Petter Selasky break; 901d4cf41a9SHans Petter Selasky case 0x6000: 902d4cf41a9SHans Petter Selasky sc->sc_flags = URE_FLAG_8153B; 903d4cf41a9SHans Petter Selasky sc->sc_chip |= URE_CHIP_VER_6000; 904d4cf41a9SHans Petter Selasky break; 905d4cf41a9SHans Petter Selasky case 0x6010: 906d4cf41a9SHans Petter Selasky sc->sc_flags = URE_FLAG_8153B; 907d4cf41a9SHans Petter Selasky sc->sc_chip |= URE_CHIP_VER_6010; 908d4cf41a9SHans Petter Selasky break; 909d4cf41a9SHans Petter Selasky case 0x7020: 910d4cf41a9SHans Petter Selasky sc->sc_flags = URE_FLAG_8156; 911d4cf41a9SHans Petter Selasky sc->sc_chip |= URE_CHIP_VER_7020; 912d4cf41a9SHans Petter Selasky break; 913d4cf41a9SHans Petter Selasky case 0x7030: 914d4cf41a9SHans Petter Selasky sc->sc_flags = URE_FLAG_8156; 915d4cf41a9SHans Petter Selasky sc->sc_chip |= URE_CHIP_VER_7030; 916d4cf41a9SHans Petter Selasky break; 917d4cf41a9SHans Petter Selasky case 0x7400: 918d4cf41a9SHans Petter Selasky sc->sc_flags = URE_FLAG_8156B; 919d4cf41a9SHans Petter Selasky sc->sc_chip |= URE_CHIP_VER_7400; 920d4cf41a9SHans Petter Selasky break; 921d4cf41a9SHans Petter Selasky case 0x7410: 922d4cf41a9SHans Petter Selasky sc->sc_flags = URE_FLAG_8156B; 923d4cf41a9SHans Petter Selasky sc->sc_chip |= URE_CHIP_VER_7410; 924a24d62b5SKevin Lo break; 925e1b74f21SKevin Lo default: 926e1b74f21SKevin Lo device_printf(sc->sc_ue.ue_dev, 927e1b74f21SKevin Lo "unknown version 0x%04x\n", ver); 928e1b74f21SKevin Lo break; 929e1b74f21SKevin Lo } 930e1b74f21SKevin Lo } 931e1b74f21SKevin Lo 9327d5522e1SJohn-Mark Gurney static int 9337d5522e1SJohn-Mark Gurney ure_sysctl_chipver(SYSCTL_HANDLER_ARGS) 9347d5522e1SJohn-Mark Gurney { 9357d5522e1SJohn-Mark Gurney struct sbuf sb; 9367d5522e1SJohn-Mark Gurney struct ure_softc *sc = arg1; 9377d5522e1SJohn-Mark Gurney int error; 9387d5522e1SJohn-Mark Gurney 9397d5522e1SJohn-Mark Gurney sbuf_new_for_sysctl(&sb, NULL, 0, req); 9407d5522e1SJohn-Mark Gurney 9417d5522e1SJohn-Mark Gurney sbuf_printf(&sb, "%04x", sc->sc_ver); 9427d5522e1SJohn-Mark Gurney 9437d5522e1SJohn-Mark Gurney error = sbuf_finish(&sb); 9447d5522e1SJohn-Mark Gurney sbuf_delete(&sb); 9457d5522e1SJohn-Mark Gurney 9467d5522e1SJohn-Mark Gurney return (error); 9477d5522e1SJohn-Mark Gurney } 9487d5522e1SJohn-Mark Gurney 949e1b74f21SKevin Lo static void 950e1b74f21SKevin Lo ure_attach_post(struct usb_ether *ue) 951e1b74f21SKevin Lo { 952e1b74f21SKevin Lo struct ure_softc *sc = uether_getsc(ue); 953e1b74f21SKevin Lo 9547d5522e1SJohn-Mark Gurney sc->sc_rxstarted = 0; 955e1b74f21SKevin Lo sc->sc_phyno = 0; 956e1b74f21SKevin Lo 957e1b74f21SKevin Lo /* Determine the chip version. */ 958e1b74f21SKevin Lo ure_read_chipver(sc); 959e1b74f21SKevin Lo 960e1b74f21SKevin Lo /* Initialize controller and get station address. */ 961a24d62b5SKevin Lo if (sc->sc_flags & URE_FLAG_8152) 962e1b74f21SKevin Lo ure_rtl8152_init(sc); 963d4cf41a9SHans Petter Selasky else if (sc->sc_flags & (URE_FLAG_8153B | URE_FLAG_8156 | URE_FLAG_8156B)) 964d4cf41a9SHans Petter Selasky ure_rtl8153b_init(sc); 965a24d62b5SKevin Lo else 966a24d62b5SKevin Lo ure_rtl8153_init(sc); 967e1b74f21SKevin Lo 968cef38d45SGanbold Tsagaankhuu if ((sc->sc_chip & URE_CHIP_VER_4C00) || 969cef38d45SGanbold Tsagaankhuu (sc->sc_chip & URE_CHIP_VER_4C10)) 970e1b74f21SKevin Lo ure_read_mem(sc, URE_PLA_IDR, URE_MCU_TYPE_PLA, 971e1b74f21SKevin Lo ue->ue_eaddr, 8); 972e1b74f21SKevin Lo else 973e1b74f21SKevin Lo ure_read_mem(sc, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, 974e1b74f21SKevin Lo ue->ue_eaddr, 8); 975cef38d45SGanbold Tsagaankhuu 976cef38d45SGanbold Tsagaankhuu if (ETHER_IS_ZERO(sc->sc_ue.ue_eaddr)) { 977cef38d45SGanbold Tsagaankhuu device_printf(sc->sc_ue.ue_dev, "MAC assigned randomly\n"); 978cef38d45SGanbold Tsagaankhuu arc4rand(sc->sc_ue.ue_eaddr, ETHER_ADDR_LEN, 0); 979cef38d45SGanbold Tsagaankhuu sc->sc_ue.ue_eaddr[0] &= ~0x01; /* unicast */ 980cef38d45SGanbold Tsagaankhuu sc->sc_ue.ue_eaddr[0] |= 0x02; /* locally administered */ 981cef38d45SGanbold Tsagaankhuu } 982e1b74f21SKevin Lo } 983e1b74f21SKevin Lo 984e1b74f21SKevin Lo static int 985e1b74f21SKevin Lo ure_attach_post_sub(struct usb_ether *ue) 986e1b74f21SKevin Lo { 987412bbd08SHans Petter Selasky struct sysctl_ctx_list *sctx; 988412bbd08SHans Petter Selasky struct sysctl_oid *soid; 989e1b74f21SKevin Lo struct ure_softc *sc; 990935b194dSJustin Hibbits if_t ifp; 991e1b74f21SKevin Lo int error; 992e1b74f21SKevin Lo 993e1b74f21SKevin Lo sc = uether_getsc(ue); 994e1b74f21SKevin Lo ifp = ue->ue_ifp; 995935b194dSJustin Hibbits if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 996935b194dSJustin Hibbits if_setstartfn(ifp, uether_start); 997935b194dSJustin Hibbits if_setioctlfn(ifp, ure_ioctl); 998935b194dSJustin Hibbits if_setinitfn(ifp, uether_init); 9997d5522e1SJohn-Mark Gurney /* 10007d5522e1SJohn-Mark Gurney * Try to keep two transfers full at a time. 10017d5522e1SJohn-Mark Gurney * ~(TRANSFER_SIZE / 80 bytes/pkt * 2 buffers in flight) 10027d5522e1SJohn-Mark Gurney */ 1003935b194dSJustin Hibbits if_setsendqlen(ifp, 512); 1004935b194dSJustin Hibbits if_setsendqready(ifp); 1005e1b74f21SKevin Lo 10067d5522e1SJohn-Mark Gurney if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0); 10077d5522e1SJohn-Mark Gurney if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWTAGGING, 0); 10087d5522e1SJohn-Mark Gurney if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWCSUM|IFCAP_HWCSUM, 0); 10097d5522e1SJohn-Mark Gurney if_sethwassist(ifp, CSUM_IP|CSUM_IP_UDP|CSUM_IP_TCP); 10107d5522e1SJohn-Mark Gurney #ifdef INET6 10117d5522e1SJohn-Mark Gurney if_setcapabilitiesbit(ifp, IFCAP_HWCSUM_IPV6, 0); 10127d5522e1SJohn-Mark Gurney #endif 10137d5522e1SJohn-Mark Gurney if_setcapenable(ifp, if_getcapabilities(ifp)); 10147d5522e1SJohn-Mark Gurney 1015d4cf41a9SHans Petter Selasky if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) { 1016d4cf41a9SHans Petter Selasky ifmedia_init(&sc->sc_ifmedia, IFM_IMASK, ure_ifmedia_upd, 1017d4cf41a9SHans Petter Selasky ure_ifmedia_sts); 1018d4cf41a9SHans Petter Selasky ure_add_media_types(sc); 1019d4cf41a9SHans Petter Selasky ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL); 1020d4cf41a9SHans Petter Selasky ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO); 1021d4cf41a9SHans Petter Selasky sc->sc_ifmedia.ifm_media = IFM_ETHER | IFM_AUTO; 1022d4cf41a9SHans Petter Selasky error = 0; 1023d4cf41a9SHans Petter Selasky } else { 1024c6df6f53SWarner Losh bus_topo_lock(); 1025e1b74f21SKevin Lo error = mii_attach(ue->ue_dev, &ue->ue_miibus, ifp, 1026e1b74f21SKevin Lo uether_ifmedia_upd, ue->ue_methods->ue_mii_sts, 1027e1b74f21SKevin Lo BMSR_DEFCAPMASK, sc->sc_phyno, MII_OFFSET_ANY, 0); 1028c6df6f53SWarner Losh bus_topo_unlock(); 1029d4cf41a9SHans Petter Selasky } 1030e1b74f21SKevin Lo 1031412bbd08SHans Petter Selasky sctx = device_get_sysctl_ctx(sc->sc_ue.ue_dev); 1032412bbd08SHans Petter Selasky soid = device_get_sysctl_tree(sc->sc_ue.ue_dev); 1033412bbd08SHans Petter Selasky SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "chipver", 1034412bbd08SHans Petter Selasky CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 1035412bbd08SHans Petter Selasky ure_sysctl_chipver, "A", 1036412bbd08SHans Petter Selasky "Return string with chip version."); 1037412bbd08SHans Petter Selasky 1038e1b74f21SKevin Lo return (error); 1039e1b74f21SKevin Lo } 1040e1b74f21SKevin Lo 1041e1b74f21SKevin Lo static void 1042e1b74f21SKevin Lo ure_init(struct usb_ether *ue) 1043e1b74f21SKevin Lo { 1044e1b74f21SKevin Lo struct ure_softc *sc = uether_getsc(ue); 1045935b194dSJustin Hibbits if_t ifp = uether_getifp(ue); 10467d5522e1SJohn-Mark Gurney uint16_t cpcr; 1047d4cf41a9SHans Petter Selasky uint32_t reg; 1048e1b74f21SKevin Lo 1049e1b74f21SKevin Lo URE_LOCK_ASSERT(sc, MA_OWNED); 1050e1b74f21SKevin Lo 1051935b194dSJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) 1052e1b74f21SKevin Lo return; 1053e1b74f21SKevin Lo 1054e1b74f21SKevin Lo /* Cancel pending I/O. */ 1055e1b74f21SKevin Lo ure_stop(ue); 1056e1b74f21SKevin Lo 1057d4cf41a9SHans Petter Selasky if (sc->sc_flags & (URE_FLAG_8153B | URE_FLAG_8156 | URE_FLAG_8156B)) 1058d4cf41a9SHans Petter Selasky ure_rtl8153b_nic_reset(sc); 1059d4cf41a9SHans Petter Selasky else 1060e1b74f21SKevin Lo ure_reset(sc); 1061e1b74f21SKevin Lo 1062e1b74f21SKevin Lo /* Set MAC address. */ 1063cef38d45SGanbold Tsagaankhuu ure_write_1(sc, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_CONFIG); 1064e1b74f21SKevin Lo ure_write_mem(sc, URE_PLA_IDR, URE_MCU_TYPE_PLA | URE_BYTE_EN_SIX_BYTES, 1065935b194dSJustin Hibbits if_getlladdr(ifp), 8); 1066cef38d45SGanbold Tsagaankhuu ure_write_1(sc, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML); 1067e1b74f21SKevin Lo 1068d4cf41a9SHans Petter Selasky /* Set RX EARLY timeout and size */ 1069d4cf41a9SHans Petter Selasky if (sc->sc_flags & URE_FLAG_8153) { 1070d4cf41a9SHans Petter Selasky switch (usbd_get_speed(sc->sc_ue.ue_udev)) { 1071d4cf41a9SHans Petter Selasky case USB_SPEED_SUPER: 1072d4cf41a9SHans Petter Selasky reg = URE_COALESCE_SUPER / 8; 1073d4cf41a9SHans Petter Selasky break; 1074d4cf41a9SHans Petter Selasky case USB_SPEED_HIGH: 1075d4cf41a9SHans Petter Selasky reg = URE_COALESCE_HIGH / 8; 1076d4cf41a9SHans Petter Selasky break; 1077d4cf41a9SHans Petter Selasky default: 1078d4cf41a9SHans Petter Selasky reg = URE_COALESCE_SLOW / 8; 1079d4cf41a9SHans Petter Selasky break; 1080d4cf41a9SHans Petter Selasky } 1081d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_USB_RX_EARLY_AGG, URE_MCU_TYPE_USB, reg); 1082d4cf41a9SHans Petter Selasky reg = URE_8153_RX_BUFSZ - (URE_FRAMELEN(if_getmtu(ifp)) + 1083d4cf41a9SHans Petter Selasky sizeof(struct ure_rxpkt) + URE_RXPKT_ALIGN); 1084d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_USB_RX_EARLY_SIZE, URE_MCU_TYPE_USB, reg / 4); 1085d4cf41a9SHans Petter Selasky } else if (sc->sc_flags & URE_FLAG_8153B) { 1086d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_USB_RX_EARLY_AGG, URE_MCU_TYPE_USB, 158); 1087d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_USB_RX_EXTRA_AGG_TMR, URE_MCU_TYPE_USB, 1875); 1088d4cf41a9SHans Petter Selasky reg = URE_8153_RX_BUFSZ - (URE_FRAMELEN(if_getmtu(ifp)) + 1089d4cf41a9SHans Petter Selasky sizeof(struct ure_rxpkt) + URE_RXPKT_ALIGN); 1090d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_USB_RX_EARLY_SIZE, URE_MCU_TYPE_USB, reg / 8); 1091d4cf41a9SHans Petter Selasky ure_write_1(sc, URE_USB_UPT_RXDMA_OWN, URE_MCU_TYPE_USB, 1092d4cf41a9SHans Petter Selasky URE_OWN_UPDATE | URE_OWN_CLEAR); 1093d4cf41a9SHans Petter Selasky } else if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) { 1094d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_USB_RX_EARLY_AGG, URE_MCU_TYPE_USB, 80); 1095d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_USB_RX_EXTRA_AGG_TMR, URE_MCU_TYPE_USB, 1875); 1096d4cf41a9SHans Petter Selasky reg = URE_8156_RX_BUFSZ - (URE_FRAMELEN(if_getmtu(ifp)) + 1097d4cf41a9SHans Petter Selasky sizeof(struct ure_rxpkt) + URE_RXPKT_ALIGN); 1098d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_USB_RX_EARLY_SIZE, URE_MCU_TYPE_USB, reg / 8); 1099d4cf41a9SHans Petter Selasky ure_write_1(sc, URE_USB_UPT_RXDMA_OWN, URE_MCU_TYPE_USB, 1100d4cf41a9SHans Petter Selasky URE_OWN_UPDATE | URE_OWN_CLEAR); 1101d4cf41a9SHans Petter Selasky } 1102d4cf41a9SHans Petter Selasky 1103d4cf41a9SHans Petter Selasky if (sc->sc_flags & URE_FLAG_8156B) { 1104d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_FW_TASK, URE_MCU_TYPE_USB, URE_FC_PATCH_TASK); 1105d4cf41a9SHans Petter Selasky uether_pause(&sc->sc_ue, hz / 500); 1106d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_USB_FW_TASK, URE_MCU_TYPE_USB, URE_FC_PATCH_TASK); 1107d4cf41a9SHans Petter Selasky } 1108d4cf41a9SHans Petter Selasky 1109e1b74f21SKevin Lo /* Reset the packet filter. */ 1110d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA, URE_FMC_FCR_MCU_EN); 1111d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA, URE_FMC_FCR_MCU_EN); 1112e1b74f21SKevin Lo 11137d5522e1SJohn-Mark Gurney /* Enable RX VLANs if enabled */ 11147d5522e1SJohn-Mark Gurney cpcr = ure_read_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA); 11157d5522e1SJohn-Mark Gurney if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) { 11167d5522e1SJohn-Mark Gurney DEVPRINTFN(12, sc->sc_ue.ue_dev, "enabled hw vlan tag\n"); 11177d5522e1SJohn-Mark Gurney cpcr |= URE_CPCR_RX_VLAN; 11187d5522e1SJohn-Mark Gurney } else { 11197d5522e1SJohn-Mark Gurney DEVPRINTFN(12, sc->sc_ue.ue_dev, "disabled hw vlan tag\n"); 11207d5522e1SJohn-Mark Gurney cpcr &= ~URE_CPCR_RX_VLAN; 11217d5522e1SJohn-Mark Gurney } 11227d5522e1SJohn-Mark Gurney ure_write_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA, cpcr); 11237d5522e1SJohn-Mark Gurney 1124e1b74f21SKevin Lo /* Enable transmit and receive. */ 1125d4cf41a9SHans Petter Selasky URE_SETBIT_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RE | URE_CR_TE); 1126e1b74f21SKevin Lo 1127d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, URE_RXDY_GATED_EN); 1128e1b74f21SKevin Lo 1129a24d62b5SKevin Lo /* Configure RX filters. */ 1130a24d62b5SKevin Lo ure_rxfilter(ue); 1131e1b74f21SKevin Lo 11327d5522e1SJohn-Mark Gurney usbd_xfer_set_stall(sc->sc_tx_xfer[0]); 1133e1b74f21SKevin Lo 1134e1b74f21SKevin Lo /* Indicate we are up and running. */ 1135935b194dSJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 1136e1b74f21SKevin Lo 1137e1b74f21SKevin Lo /* Switch to selected media. */ 1138e1b74f21SKevin Lo ure_ifmedia_upd(ifp); 1139e1b74f21SKevin Lo } 1140e1b74f21SKevin Lo 1141e1b74f21SKevin Lo static void 1142e1b74f21SKevin Lo ure_tick(struct usb_ether *ue) 1143e1b74f21SKevin Lo { 1144e1b74f21SKevin Lo struct ure_softc *sc = uether_getsc(ue); 1145935b194dSJustin Hibbits if_t ifp = uether_getifp(ue); 1146d4cf41a9SHans Petter Selasky struct mii_data *mii; 1147e1b74f21SKevin Lo 1148e1b74f21SKevin Lo URE_LOCK_ASSERT(sc, MA_OWNED); 1149e1b74f21SKevin Lo 11507d5522e1SJohn-Mark Gurney (void)ifp; 1151d4cf41a9SHans Petter Selasky for (int i = 0; i < URE_MAX_RX; i++) 11527d5522e1SJohn-Mark Gurney DEVPRINTFN(13, sc->sc_ue.ue_dev, 11537d5522e1SJohn-Mark Gurney "rx[%d] = %d\n", i, USB_GET_STATE(sc->sc_rx_xfer[i])); 11547d5522e1SJohn-Mark Gurney 1155d4cf41a9SHans Petter Selasky for (int i = 0; i < URE_MAX_TX; i++) 11567d5522e1SJohn-Mark Gurney DEVPRINTFN(13, sc->sc_ue.ue_dev, 11577d5522e1SJohn-Mark Gurney "tx[%d] = %d\n", i, USB_GET_STATE(sc->sc_tx_xfer[i])); 11587d5522e1SJohn-Mark Gurney 1159d4cf41a9SHans Petter Selasky if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) { 1160d4cf41a9SHans Petter Selasky ure_link_state(sc); 1161d4cf41a9SHans Petter Selasky } else { 1162d4cf41a9SHans Petter Selasky mii = GET_MII(sc); 1163e1b74f21SKevin Lo mii_tick(mii); 1164e1b74f21SKevin Lo if ((sc->sc_flags & URE_FLAG_LINK) == 0 1165e1b74f21SKevin Lo && mii->mii_media_status & IFM_ACTIVE && 1166e1b74f21SKevin Lo IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 1167e1b74f21SKevin Lo sc->sc_flags |= URE_FLAG_LINK; 11687d5522e1SJohn-Mark Gurney sc->sc_rxstarted = 0; 1169e1b74f21SKevin Lo ure_start(ue); 1170e1b74f21SKevin Lo } 1171e1b74f21SKevin Lo } 1172d4cf41a9SHans Petter Selasky } 1173e1b74f21SKevin Lo 1174a433f711SGleb Smirnoff static u_int 1175a433f711SGleb Smirnoff ure_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 1176a433f711SGleb Smirnoff { 1177a433f711SGleb Smirnoff uint32_t h, *hashes = arg; 1178a433f711SGleb Smirnoff 1179a433f711SGleb Smirnoff h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; 1180a433f711SGleb Smirnoff if (h < 32) 1181a433f711SGleb Smirnoff hashes[0] |= (1 << h); 1182a433f711SGleb Smirnoff else 1183a433f711SGleb Smirnoff hashes[1] |= (1 << (h - 32)); 1184a433f711SGleb Smirnoff return (1); 1185a433f711SGleb Smirnoff } 1186a433f711SGleb Smirnoff 1187e1b74f21SKevin Lo /* 1188e1b74f21SKevin Lo * Program the 64-bit multicast hash filter. 1189e1b74f21SKevin Lo */ 1190e1b74f21SKevin Lo static void 1191a24d62b5SKevin Lo ure_rxfilter(struct usb_ether *ue) 1192e1b74f21SKevin Lo { 1193e1b74f21SKevin Lo struct ure_softc *sc = uether_getsc(ue); 1194935b194dSJustin Hibbits if_t ifp = uether_getifp(ue); 1195a433f711SGleb Smirnoff uint32_t rxmode; 1196a433f711SGleb Smirnoff uint32_t h, hashes[2] = { 0, 0 }; 1197e1b74f21SKevin Lo 1198e1b74f21SKevin Lo URE_LOCK_ASSERT(sc, MA_OWNED); 1199e1b74f21SKevin Lo 12000b39e344SJohn-Mark Gurney rxmode = ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA); 12010b39e344SJohn-Mark Gurney rxmode &= ~(URE_RCR_AAP | URE_RCR_AM); 12020b39e344SJohn-Mark Gurney rxmode |= URE_RCR_APM; /* accept physical match packets */ 12030b39e344SJohn-Mark Gurney rxmode |= URE_RCR_AB; /* always accept broadcasts */ 1204935b194dSJustin Hibbits if (if_getflags(ifp) & (IFF_ALLMULTI | IFF_PROMISC)) { 1205935b194dSJustin Hibbits if (if_getflags(ifp) & IFF_PROMISC) 1206e1b74f21SKevin Lo rxmode |= URE_RCR_AAP; 1207e1b74f21SKevin Lo rxmode |= URE_RCR_AM; 1208e1b74f21SKevin Lo hashes[0] = hashes[1] = 0xffffffff; 1209e1b74f21SKevin Lo goto done; 1210e1b74f21SKevin Lo } 1211e1b74f21SKevin Lo 12127d5522e1SJohn-Mark Gurney /* calculate multicast masks */ 1213a433f711SGleb Smirnoff if_foreach_llmaddr(ifp, ure_hash_maddr, &hashes); 1214e1b74f21SKevin Lo 1215e1b74f21SKevin Lo h = bswap32(hashes[0]); 1216e1b74f21SKevin Lo hashes[0] = bswap32(hashes[1]); 1217e1b74f21SKevin Lo hashes[1] = h; 12187d5522e1SJohn-Mark Gurney rxmode |= URE_RCR_AM; /* accept multicast packets */ 1219e1b74f21SKevin Lo 1220e1b74f21SKevin Lo done: 12217d5522e1SJohn-Mark Gurney DEVPRINTFN(14, ue->ue_dev, "rxfilt: RCR: %#x\n", 12227d5522e1SJohn-Mark Gurney ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA)); 1223e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_MAR0, URE_MCU_TYPE_PLA, hashes[0]); 1224e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_MAR4, URE_MCU_TYPE_PLA, hashes[1]); 1225e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); 1226e1b74f21SKevin Lo } 1227e1b74f21SKevin Lo 1228e1b74f21SKevin Lo static void 1229e1b74f21SKevin Lo ure_start(struct usb_ether *ue) 1230e1b74f21SKevin Lo { 1231e1b74f21SKevin Lo struct ure_softc *sc = uether_getsc(ue); 12326e5baec3SHans Petter Selasky unsigned i; 12337d5522e1SJohn-Mark Gurney 12347d5522e1SJohn-Mark Gurney URE_LOCK_ASSERT(sc, MA_OWNED); 12357d5522e1SJohn-Mark Gurney 12367d5522e1SJohn-Mark Gurney if (!sc->sc_rxstarted) { 12377d5522e1SJohn-Mark Gurney sc->sc_rxstarted = 1; 1238d4cf41a9SHans Petter Selasky for (i = 0; i != URE_MAX_RX; i++) 12397d5522e1SJohn-Mark Gurney usbd_transfer_start(sc->sc_rx_xfer[i]); 12407d5522e1SJohn-Mark Gurney } 1241e1b74f21SKevin Lo 1242d4cf41a9SHans Petter Selasky for (i = 0; i != URE_MAX_TX; i++) 12436e5baec3SHans Petter Selasky usbd_transfer_start(sc->sc_tx_xfer[i]); 1244e1b74f21SKevin Lo } 1245e1b74f21SKevin Lo 1246e1b74f21SKevin Lo static void 1247e1b74f21SKevin Lo ure_reset(struct ure_softc *sc) 1248e1b74f21SKevin Lo { 1249e1b74f21SKevin Lo int i; 1250e1b74f21SKevin Lo 1251e1b74f21SKevin Lo ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST); 1252e1b74f21SKevin Lo 1253e1b74f21SKevin Lo for (i = 0; i < URE_TIMEOUT; i++) { 1254e1b74f21SKevin Lo if (!(ure_read_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA) & 1255e1b74f21SKevin Lo URE_CR_RST)) 1256e1b74f21SKevin Lo break; 1257e1b74f21SKevin Lo uether_pause(&sc->sc_ue, hz / 100); 1258e1b74f21SKevin Lo } 1259e1b74f21SKevin Lo if (i == URE_TIMEOUT) 1260e1b74f21SKevin Lo device_printf(sc->sc_ue.ue_dev, "reset never completed\n"); 1261e1b74f21SKevin Lo } 1262e1b74f21SKevin Lo 1263e1b74f21SKevin Lo /* 1264e1b74f21SKevin Lo * Set media options. 1265e1b74f21SKevin Lo */ 1266e1b74f21SKevin Lo static int 1267935b194dSJustin Hibbits ure_ifmedia_upd(if_t ifp) 1268e1b74f21SKevin Lo { 1269935b194dSJustin Hibbits struct ure_softc *sc = if_getsoftc(ifp); 1270d4cf41a9SHans Petter Selasky struct ifmedia *ifm; 1271d4cf41a9SHans Petter Selasky struct mii_data *mii; 1272e1b74f21SKevin Lo struct mii_softc *miisc; 1273d4cf41a9SHans Petter Selasky int gig; 1274d4cf41a9SHans Petter Selasky int reg; 1275d4cf41a9SHans Petter Selasky int anar; 1276d4cf41a9SHans Petter Selasky int locked; 1277e1b74f21SKevin Lo int error; 1278e1b74f21SKevin Lo 1279d4cf41a9SHans Petter Selasky if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) { 1280d4cf41a9SHans Petter Selasky ifm = &sc->sc_ifmedia; 1281d4cf41a9SHans Petter Selasky if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1282d4cf41a9SHans Petter Selasky return (EINVAL); 1283e1b74f21SKevin Lo 1284d4cf41a9SHans Petter Selasky locked = mtx_owned(&sc->sc_mtx); 1285d4cf41a9SHans Petter Selasky if (!locked) 1286d4cf41a9SHans Petter Selasky URE_LOCK(sc); 1287d4cf41a9SHans Petter Selasky reg = ure_ocp_reg_read(sc, 0xa5d4); 1288d4cf41a9SHans Petter Selasky reg &= ~URE_ADV_2500TFDX; 1289d4cf41a9SHans Petter Selasky 1290d4cf41a9SHans Petter Selasky anar = gig = 0; 1291d4cf41a9SHans Petter Selasky switch (IFM_SUBTYPE(ifm->ifm_media)) { 1292d4cf41a9SHans Petter Selasky case IFM_AUTO: 1293d4cf41a9SHans Petter Selasky anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10; 1294d4cf41a9SHans Petter Selasky gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX; 1295d4cf41a9SHans Petter Selasky reg |= URE_ADV_2500TFDX; 1296d4cf41a9SHans Petter Selasky break; 1297d4cf41a9SHans Petter Selasky case IFM_2500_T: 1298d4cf41a9SHans Petter Selasky anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10; 1299d4cf41a9SHans Petter Selasky gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX; 1300d4cf41a9SHans Petter Selasky reg |= URE_ADV_2500TFDX; 1301935b194dSJustin Hibbits if_setbaudrate(ifp, IF_Mbps(2500)); 1302d4cf41a9SHans Petter Selasky break; 1303d4cf41a9SHans Petter Selasky case IFM_1000_T: 1304d4cf41a9SHans Petter Selasky anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10; 1305d4cf41a9SHans Petter Selasky gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX; 1306935b194dSJustin Hibbits if_setbaudrate(ifp, IF_Gbps(1)); 1307d4cf41a9SHans Petter Selasky break; 1308d4cf41a9SHans Petter Selasky case IFM_100_TX: 1309d4cf41a9SHans Petter Selasky anar |= ANAR_TX | ANAR_TX_FD; 1310935b194dSJustin Hibbits if_setbaudrate(ifp, IF_Mbps(100)); 1311d4cf41a9SHans Petter Selasky break; 1312d4cf41a9SHans Petter Selasky case IFM_10_T: 1313d4cf41a9SHans Petter Selasky anar |= ANAR_10 | ANAR_10_FD; 1314935b194dSJustin Hibbits if_setbaudrate(ifp, IF_Mbps(10)); 1315d4cf41a9SHans Petter Selasky break; 1316d4cf41a9SHans Petter Selasky default: 1317d4cf41a9SHans Petter Selasky device_printf(sc->sc_ue.ue_dev, "unsupported media type\n"); 1318d4cf41a9SHans Petter Selasky if (!locked) 1319d4cf41a9SHans Petter Selasky URE_UNLOCK(sc); 1320d4cf41a9SHans Petter Selasky return (EINVAL); 1321d4cf41a9SHans Petter Selasky } 1322d4cf41a9SHans Petter Selasky 1323d4cf41a9SHans Petter Selasky ure_ocp_reg_write(sc, URE_OCP_BASE_MII + MII_ANAR * 2, 1324d4cf41a9SHans Petter Selasky anar | ANAR_PAUSE_ASYM | ANAR_FC); 1325d4cf41a9SHans Petter Selasky ure_ocp_reg_write(sc, URE_OCP_BASE_MII + MII_100T2CR * 2, gig); 1326d4cf41a9SHans Petter Selasky ure_ocp_reg_write(sc, 0xa5d4, reg); 1327d4cf41a9SHans Petter Selasky ure_ocp_reg_write(sc, URE_OCP_BASE_MII + MII_BMCR, 1328d4cf41a9SHans Petter Selasky BMCR_AUTOEN | BMCR_STARTNEG); 1329d4cf41a9SHans Petter Selasky if (!locked) 1330d4cf41a9SHans Petter Selasky URE_UNLOCK(sc); 1331d4cf41a9SHans Petter Selasky return (0); 1332d4cf41a9SHans Petter Selasky } 1333d4cf41a9SHans Petter Selasky 1334d4cf41a9SHans Petter Selasky mii = GET_MII(sc); 1335d4cf41a9SHans Petter Selasky 1336d4cf41a9SHans Petter Selasky URE_LOCK_ASSERT(sc, MA_OWNED); 1337e1b74f21SKevin Lo LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 1338e1b74f21SKevin Lo PHY_RESET(miisc); 1339e1b74f21SKevin Lo error = mii_mediachg(mii); 1340e1b74f21SKevin Lo return (error); 1341e1b74f21SKevin Lo } 1342e1b74f21SKevin Lo 1343e1b74f21SKevin Lo /* 1344e1b74f21SKevin Lo * Report current media status. 1345e1b74f21SKevin Lo */ 1346e1b74f21SKevin Lo static void 1347935b194dSJustin Hibbits ure_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) 1348e1b74f21SKevin Lo { 1349e1b74f21SKevin Lo struct ure_softc *sc; 1350e1b74f21SKevin Lo struct mii_data *mii; 1351d4cf41a9SHans Petter Selasky uint16_t status; 1352e1b74f21SKevin Lo 1353935b194dSJustin Hibbits sc = if_getsoftc(ifp); 1354d4cf41a9SHans Petter Selasky if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) { 1355d4cf41a9SHans Petter Selasky URE_LOCK(sc); 1356d4cf41a9SHans Petter Selasky ifmr->ifm_status = IFM_AVALID; 1357d4cf41a9SHans Petter Selasky if (ure_get_link_status(sc)) { 1358d4cf41a9SHans Petter Selasky ifmr->ifm_status |= IFM_ACTIVE; 1359d4cf41a9SHans Petter Selasky status = ure_read_2(sc, URE_PLA_PHYSTATUS, 1360d4cf41a9SHans Petter Selasky URE_MCU_TYPE_PLA); 1361d4cf41a9SHans Petter Selasky if ((status & URE_PHYSTATUS_FDX) || 1362d4cf41a9SHans Petter Selasky (status & URE_PHYSTATUS_2500MBPS)) 1363d4cf41a9SHans Petter Selasky ifmr->ifm_active |= IFM_FDX; 1364d4cf41a9SHans Petter Selasky else 1365d4cf41a9SHans Petter Selasky ifmr->ifm_active |= IFM_HDX; 1366d4cf41a9SHans Petter Selasky if (status & URE_PHYSTATUS_10MBPS) 1367d4cf41a9SHans Petter Selasky ifmr->ifm_active |= IFM_10_T; 1368d4cf41a9SHans Petter Selasky else if (status & URE_PHYSTATUS_100MBPS) 1369d4cf41a9SHans Petter Selasky ifmr->ifm_active |= IFM_100_TX; 1370d4cf41a9SHans Petter Selasky else if (status & URE_PHYSTATUS_1000MBPS) 1371d4cf41a9SHans Petter Selasky ifmr->ifm_active |= IFM_1000_T; 1372d4cf41a9SHans Petter Selasky else if (status & URE_PHYSTATUS_2500MBPS) 1373d4cf41a9SHans Petter Selasky ifmr->ifm_active |= IFM_2500_T; 1374d4cf41a9SHans Petter Selasky } 1375d4cf41a9SHans Petter Selasky URE_UNLOCK(sc); 1376d4cf41a9SHans Petter Selasky return; 1377d4cf41a9SHans Petter Selasky } 1378d4cf41a9SHans Petter Selasky 1379e1b74f21SKevin Lo mii = GET_MII(sc); 1380e1b74f21SKevin Lo 1381e1b74f21SKevin Lo URE_LOCK(sc); 1382e1b74f21SKevin Lo mii_pollstat(mii); 1383e1b74f21SKevin Lo ifmr->ifm_active = mii->mii_media_active; 1384e1b74f21SKevin Lo ifmr->ifm_status = mii->mii_media_status; 1385e1b74f21SKevin Lo URE_UNLOCK(sc); 1386e1b74f21SKevin Lo } 1387e1b74f21SKevin Lo 1388d4cf41a9SHans Petter Selasky static void 1389d4cf41a9SHans Petter Selasky ure_add_media_types(struct ure_softc *sc) 1390d4cf41a9SHans Petter Selasky { 1391d4cf41a9SHans Petter Selasky ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0, NULL); 1392d4cf41a9SHans Petter Selasky ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL); 1393d4cf41a9SHans Petter Selasky ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_100_TX, 0, NULL); 1394d4cf41a9SHans Petter Selasky ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL); 1395d4cf41a9SHans Petter Selasky ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); 1396d4cf41a9SHans Petter Selasky ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_2500_T | IFM_FDX, 0, NULL); 1397d4cf41a9SHans Petter Selasky } 1398d4cf41a9SHans Petter Selasky 1399d4cf41a9SHans Petter Selasky static void 1400d4cf41a9SHans Petter Selasky ure_link_state(struct ure_softc *sc) 1401d4cf41a9SHans Petter Selasky { 1402935b194dSJustin Hibbits if_t ifp = uether_getifp(&sc->sc_ue); 1403d4cf41a9SHans Petter Selasky 1404d4cf41a9SHans Petter Selasky if (ure_get_link_status(sc)) { 1405935b194dSJustin Hibbits if (if_getlinkstate(ifp) != LINK_STATE_UP) { 1406d4cf41a9SHans Petter Selasky if_link_state_change(ifp, LINK_STATE_UP); 1407d4cf41a9SHans Petter Selasky /* Enable transmit and receive. */ 1408d4cf41a9SHans Petter Selasky URE_SETBIT_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RE | URE_CR_TE); 1409d4cf41a9SHans Petter Selasky 1410d4cf41a9SHans Petter Selasky if (ure_read_2(sc, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA) & 1411d4cf41a9SHans Petter Selasky URE_PHYSTATUS_2500MBPS) 1412d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA, 0x40); 1413d4cf41a9SHans Petter Selasky else 1414d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA, 0x40); 1415d4cf41a9SHans Petter Selasky } 1416d4cf41a9SHans Petter Selasky } else { 1417935b194dSJustin Hibbits if (if_getlinkstate(ifp) != LINK_STATE_DOWN) { 1418d4cf41a9SHans Petter Selasky if_link_state_change(ifp, LINK_STATE_DOWN); 1419d4cf41a9SHans Petter Selasky } 1420d4cf41a9SHans Petter Selasky } 1421d4cf41a9SHans Petter Selasky } 1422d4cf41a9SHans Petter Selasky 1423d4cf41a9SHans Petter Selasky static int 1424d4cf41a9SHans Petter Selasky ure_get_link_status(struct ure_softc *sc) 1425d4cf41a9SHans Petter Selasky { 1426d4cf41a9SHans Petter Selasky if (ure_read_2(sc, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA) & 1427d4cf41a9SHans Petter Selasky URE_PHYSTATUS_LINK) { 1428d4cf41a9SHans Petter Selasky sc->sc_flags |= URE_FLAG_LINK; 1429d4cf41a9SHans Petter Selasky return (1); 1430d4cf41a9SHans Petter Selasky } else { 1431d4cf41a9SHans Petter Selasky sc->sc_flags &= ~URE_FLAG_LINK; 1432d4cf41a9SHans Petter Selasky return (0); 1433d4cf41a9SHans Petter Selasky } 1434d4cf41a9SHans Petter Selasky } 1435d4cf41a9SHans Petter Selasky 1436e1b74f21SKevin Lo static int 1437935b194dSJustin Hibbits ure_ioctl(if_t ifp, u_long cmd, caddr_t data) 1438e1b74f21SKevin Lo { 1439935b194dSJustin Hibbits struct usb_ether *ue = if_getsoftc(ifp); 1440e1b74f21SKevin Lo struct ure_softc *sc; 1441e1b74f21SKevin Lo struct ifreq *ifr; 1442e1b74f21SKevin Lo int error, mask, reinit; 1443e1b74f21SKevin Lo 1444e1b74f21SKevin Lo sc = uether_getsc(ue); 1445e1b74f21SKevin Lo ifr = (struct ifreq *)data; 1446e1b74f21SKevin Lo error = 0; 1447e1b74f21SKevin Lo reinit = 0; 14487d5522e1SJohn-Mark Gurney switch (cmd) { 14497d5522e1SJohn-Mark Gurney case SIOCSIFCAP: 1450e1b74f21SKevin Lo URE_LOCK(sc); 1451935b194dSJustin Hibbits mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); 14527d5522e1SJohn-Mark Gurney if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && 1453935b194dSJustin Hibbits (if_getcapabilities(ifp) & IFCAP_VLAN_HWTAGGING) != 0) { 1454935b194dSJustin Hibbits if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING); 14557d5522e1SJohn-Mark Gurney reinit++; 14567d5522e1SJohn-Mark Gurney } 14577d5522e1SJohn-Mark Gurney if ((mask & IFCAP_TXCSUM) != 0 && 1458935b194dSJustin Hibbits (if_getcapabilities(ifp) & IFCAP_TXCSUM) != 0) { 1459935b194dSJustin Hibbits if_togglecapenable(ifp, IFCAP_TXCSUM); 14607d5522e1SJohn-Mark Gurney } 14617d5522e1SJohn-Mark Gurney if ((mask & IFCAP_RXCSUM) != 0 && 1462935b194dSJustin Hibbits (if_getcapabilities(ifp) & IFCAP_RXCSUM) != 0) { 1463935b194dSJustin Hibbits if_togglecapenable(ifp, IFCAP_RXCSUM); 14647d5522e1SJohn-Mark Gurney } 14657d5522e1SJohn-Mark Gurney if ((mask & IFCAP_TXCSUM_IPV6) != 0 && 1466935b194dSJustin Hibbits (if_getcapabilities(ifp) & IFCAP_TXCSUM_IPV6) != 0) { 1467935b194dSJustin Hibbits if_togglecapenable(ifp, IFCAP_TXCSUM_IPV6); 14687d5522e1SJohn-Mark Gurney } 14697d5522e1SJohn-Mark Gurney if ((mask & IFCAP_RXCSUM_IPV6) != 0 && 1470935b194dSJustin Hibbits (if_getcapabilities(ifp) & IFCAP_RXCSUM_IPV6) != 0) { 1471935b194dSJustin Hibbits if_togglecapenable(ifp, IFCAP_RXCSUM_IPV6); 14727d5522e1SJohn-Mark Gurney } 1473935b194dSJustin Hibbits if (reinit > 0 && if_getdrvflags(ifp) & IFF_DRV_RUNNING) 1474935b194dSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 1475e1b74f21SKevin Lo else 1476e1b74f21SKevin Lo reinit = 0; 1477e1b74f21SKevin Lo URE_UNLOCK(sc); 1478e1b74f21SKevin Lo if (reinit > 0) 1479e1b74f21SKevin Lo uether_init(ue); 14807d5522e1SJohn-Mark Gurney break; 14817d5522e1SJohn-Mark Gurney 14827d5522e1SJohn-Mark Gurney case SIOCSIFMTU: 14837d5522e1SJohn-Mark Gurney /* 14847d5522e1SJohn-Mark Gurney * in testing large MTUs "crashes" the device, it 14857d5522e1SJohn-Mark Gurney * leaves the device w/ a broken state where link 14867d5522e1SJohn-Mark Gurney * is in a bad state. 14877d5522e1SJohn-Mark Gurney */ 14887d5522e1SJohn-Mark Gurney if (ifr->ifr_mtu < ETHERMIN || 14897d5522e1SJohn-Mark Gurney ifr->ifr_mtu > (4096 - ETHER_HDR_LEN - 14907d5522e1SJohn-Mark Gurney ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN)) { 14917d5522e1SJohn-Mark Gurney error = EINVAL; 14927d5522e1SJohn-Mark Gurney break; 14937d5522e1SJohn-Mark Gurney } 14947d5522e1SJohn-Mark Gurney URE_LOCK(sc); 14957d5522e1SJohn-Mark Gurney if (if_getmtu(ifp) != ifr->ifr_mtu) 14967d5522e1SJohn-Mark Gurney if_setmtu(ifp, ifr->ifr_mtu); 14977d5522e1SJohn-Mark Gurney URE_UNLOCK(sc); 14987d5522e1SJohn-Mark Gurney break; 14997d5522e1SJohn-Mark Gurney 1500d4cf41a9SHans Petter Selasky case SIOCGIFMEDIA: 1501d4cf41a9SHans Petter Selasky case SIOCSIFMEDIA: 1502d4cf41a9SHans Petter Selasky if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) 1503d4cf41a9SHans Petter Selasky error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd); 1504d4cf41a9SHans Petter Selasky else 1505d4cf41a9SHans Petter Selasky error = uether_ioctl(ifp, cmd, data); 1506d4cf41a9SHans Petter Selasky break; 1507d4cf41a9SHans Petter Selasky 15087d5522e1SJohn-Mark Gurney default: 1509e1b74f21SKevin Lo error = uether_ioctl(ifp, cmd, data); 1510d4cf41a9SHans Petter Selasky break; 15117d5522e1SJohn-Mark Gurney } 1512e1b74f21SKevin Lo 1513e1b74f21SKevin Lo return (error); 1514e1b74f21SKevin Lo } 1515e1b74f21SKevin Lo 1516e1b74f21SKevin Lo static void 1517e1b74f21SKevin Lo ure_rtl8152_init(struct ure_softc *sc) 1518e1b74f21SKevin Lo { 1519e1b74f21SKevin Lo uint32_t pwrctrl; 1520e1b74f21SKevin Lo 1521d4cf41a9SHans Petter Selasky ure_enable_aldps(sc, false); 1522e1b74f21SKevin Lo 1523e1b74f21SKevin Lo if (sc->sc_chip & URE_CHIP_VER_4C00) { 1524d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, URE_LED_MODE_MASK); 1525e1b74f21SKevin Lo } 1526e1b74f21SKevin Lo 1527d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB, URE_POWER_CUT); 1528e1b74f21SKevin Lo 1529d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB, URE_RESUME_INDICATE); 1530d4cf41a9SHans Petter Selasky 1531d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH); 1532d4cf41a9SHans Petter Selasky 1533e1b74f21SKevin Lo pwrctrl = ure_read_4(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA); 1534e1b74f21SKevin Lo pwrctrl &= ~URE_MCU_CLK_RATIO_MASK; 1535e1b74f21SKevin Lo pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN; 1536e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl); 1537e1b74f21SKevin Lo ure_write_2(sc, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA, 1538e1b74f21SKevin Lo URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK | 1539e1b74f21SKevin Lo URE_SPDWN_LINKCHG_MSK); 1540e1b74f21SKevin Lo 15417d5522e1SJohn-Mark Gurney /* Enable Rx aggregation. */ 1542d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, URE_RX_AGG_DISABLE | URE_RX_ZERO_EN); 1543e1b74f21SKevin Lo 1544d4cf41a9SHans Petter Selasky ure_enable_aldps(sc, false); 1545e1b74f21SKevin Lo 1546d4cf41a9SHans Petter Selasky ure_rtl8152_nic_reset(sc); 1547e1b74f21SKevin Lo 1548e1b74f21SKevin Lo ure_write_1(sc, URE_USB_TX_AGG, URE_MCU_TYPE_USB, 1549e1b74f21SKevin Lo URE_TX_AGG_MAX_THRESHOLD); 1550e1b74f21SKevin Lo ure_write_4(sc, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH); 1551e1b74f21SKevin Lo ure_write_4(sc, URE_USB_TX_DMA, URE_MCU_TYPE_USB, 1552e1b74f21SKevin Lo URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1); 1553e1b74f21SKevin Lo } 1554e1b74f21SKevin Lo 1555e1b74f21SKevin Lo static void 1556a24d62b5SKevin Lo ure_rtl8153_init(struct ure_softc *sc) 1557a24d62b5SKevin Lo { 1558a24d62b5SKevin Lo uint16_t val; 1559a24d62b5SKevin Lo uint8_t u1u2[8]; 1560a24d62b5SKevin Lo int i; 1561a24d62b5SKevin Lo 1562d4cf41a9SHans Petter Selasky ure_enable_aldps(sc, false); 1563a24d62b5SKevin Lo 1564a24d62b5SKevin Lo memset(u1u2, 0x00, sizeof(u1u2)); 1565a24d62b5SKevin Lo ure_write_mem(sc, URE_USB_TOLERANCE, 1566a24d62b5SKevin Lo URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); 1567a24d62b5SKevin Lo 1568a24d62b5SKevin Lo for (i = 0; i < URE_TIMEOUT; i++) { 1569a24d62b5SKevin Lo if (ure_read_2(sc, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) & 1570a24d62b5SKevin Lo URE_AUTOLOAD_DONE) 1571a24d62b5SKevin Lo break; 1572a24d62b5SKevin Lo uether_pause(&sc->sc_ue, hz / 100); 1573a24d62b5SKevin Lo } 1574a24d62b5SKevin Lo if (i == URE_TIMEOUT) 1575a24d62b5SKevin Lo device_printf(sc->sc_ue.ue_dev, 1576a24d62b5SKevin Lo "timeout waiting for chip autoload\n"); 1577a24d62b5SKevin Lo 1578a24d62b5SKevin Lo for (i = 0; i < URE_TIMEOUT; i++) { 1579a24d62b5SKevin Lo val = ure_ocp_reg_read(sc, URE_OCP_PHY_STATUS) & 1580a24d62b5SKevin Lo URE_PHY_STAT_MASK; 1581a24d62b5SKevin Lo if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN) 1582a24d62b5SKevin Lo break; 1583a24d62b5SKevin Lo uether_pause(&sc->sc_ue, hz / 100); 1584a24d62b5SKevin Lo } 1585a24d62b5SKevin Lo if (i == URE_TIMEOUT) 1586a24d62b5SKevin Lo device_printf(sc->sc_ue.ue_dev, 1587a24d62b5SKevin Lo "timeout waiting for phy to stabilize\n"); 1588a24d62b5SKevin Lo 1589d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, URE_U2P3_ENABLE); 1590a24d62b5SKevin Lo 1591a24d62b5SKevin Lo if (sc->sc_chip & URE_CHIP_VER_5C10) { 1592a24d62b5SKevin Lo val = ure_read_2(sc, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB); 1593a24d62b5SKevin Lo val &= ~URE_PWD_DN_SCALE_MASK; 1594a24d62b5SKevin Lo val |= URE_PWD_DN_SCALE(96); 1595a24d62b5SKevin Lo ure_write_2(sc, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB, val); 1596a24d62b5SKevin Lo 1597d4cf41a9SHans Petter Selasky URE_SETBIT_1(sc, URE_USB_USB2PHY, URE_MCU_TYPE_USB, URE_USB2PHY_L1 | URE_USB2PHY_SUSPEND); 1598d4cf41a9SHans Petter Selasky } else if (sc->sc_chip & URE_CHIP_VER_5C20) 1599d4cf41a9SHans Petter Selasky URE_CLRBIT_1(sc, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA, URE_ECM_ALDPS); 1600d4cf41a9SHans Petter Selasky 1601a24d62b5SKevin Lo if (sc->sc_chip & (URE_CHIP_VER_5C20 | URE_CHIP_VER_5C30)) { 1602a24d62b5SKevin Lo val = ure_read_1(sc, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB); 1603a24d62b5SKevin Lo if (ure_read_2(sc, URE_USB_BURST_SIZE, URE_MCU_TYPE_USB) == 1604a24d62b5SKevin Lo 0) 1605a24d62b5SKevin Lo val &= ~URE_DYNAMIC_BURST; 1606a24d62b5SKevin Lo else 1607a24d62b5SKevin Lo val |= URE_DYNAMIC_BURST; 1608a24d62b5SKevin Lo ure_write_1(sc, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB, val); 1609a24d62b5SKevin Lo } 1610a24d62b5SKevin Lo 1611d4cf41a9SHans Petter Selasky URE_SETBIT_1(sc, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB, URE_EP4_FULL_FC); 1612a24d62b5SKevin Lo 1613d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB, URE_TIMER11_EN); 1614a24d62b5SKevin Lo 1615d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, URE_LED_MODE_MASK); 1616a24d62b5SKevin Lo 1617a24d62b5SKevin Lo if ((sc->sc_chip & URE_CHIP_VER_5C10) && 1618a24d62b5SKevin Lo usbd_get_speed(sc->sc_ue.ue_udev) != USB_SPEED_SUPER) 1619a24d62b5SKevin Lo val = URE_LPM_TIMER_500MS; 1620a24d62b5SKevin Lo else 1621a24d62b5SKevin Lo val = URE_LPM_TIMER_500US; 1622a24d62b5SKevin Lo ure_write_1(sc, URE_USB_LPM_CTRL, URE_MCU_TYPE_USB, 1623a24d62b5SKevin Lo val | URE_FIFO_EMPTY_1FB | URE_ROK_EXIT_LPM); 1624a24d62b5SKevin Lo 1625a24d62b5SKevin Lo val = ure_read_2(sc, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB); 1626a24d62b5SKevin Lo val &= ~URE_SEN_VAL_MASK; 1627a24d62b5SKevin Lo val |= URE_SEN_VAL_NORMAL | URE_SEL_RXIDLE; 1628a24d62b5SKevin Lo ure_write_2(sc, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB, val); 1629a24d62b5SKevin Lo 1630a24d62b5SKevin Lo ure_write_2(sc, URE_USB_CONNECT_TIMER, URE_MCU_TYPE_USB, 0x0001); 1631a24d62b5SKevin Lo 1632d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, URE_PWR_EN | URE_PHASE2_EN); 1633d4cf41a9SHans Petter Selasky 1634d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_MISC_0, URE_MCU_TYPE_USB, URE_PCUT_STATUS); 1635a24d62b5SKevin Lo 1636a24d62b5SKevin Lo memset(u1u2, 0xff, sizeof(u1u2)); 1637a24d62b5SKevin Lo ure_write_mem(sc, URE_USB_TOLERANCE, 1638a24d62b5SKevin Lo URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); 1639a24d62b5SKevin Lo 1640a24d62b5SKevin Lo ure_write_2(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, 1641a24d62b5SKevin Lo URE_ALDPS_SPDWN_RATIO); 1642a24d62b5SKevin Lo ure_write_2(sc, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA, 1643a24d62b5SKevin Lo URE_EEE_SPDWN_RATIO); 1644a24d62b5SKevin Lo ure_write_2(sc, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA, 1645a24d62b5SKevin Lo URE_PKT_AVAIL_SPDWN_EN | URE_SUSPEND_SPDWN_EN | 1646a24d62b5SKevin Lo URE_U1U2_SPDWN_EN | URE_L1_SPDWN_EN); 1647a24d62b5SKevin Lo ure_write_2(sc, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA, 1648a24d62b5SKevin Lo URE_PWRSAVE_SPDWN_EN | URE_RXDV_SPDWN_EN | URE_TX10MIDLE_EN | 1649a24d62b5SKevin Lo URE_TP100_SPDWN_EN | URE_TP500_SPDWN_EN | URE_TP1000_SPDWN_EN | 1650a24d62b5SKevin Lo URE_EEE_SPDWN_EN); 1651a24d62b5SKevin Lo 1652a24d62b5SKevin Lo val = ure_read_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); 1653a24d62b5SKevin Lo if (!(sc->sc_chip & (URE_CHIP_VER_5C00 | URE_CHIP_VER_5C10))) 1654a24d62b5SKevin Lo val |= URE_U2P3_ENABLE; 1655a24d62b5SKevin Lo else 1656a24d62b5SKevin Lo val &= ~URE_U2P3_ENABLE; 1657a24d62b5SKevin Lo ure_write_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); 1658a24d62b5SKevin Lo 1659a24d62b5SKevin Lo memset(u1u2, 0x00, sizeof(u1u2)); 1660a24d62b5SKevin Lo ure_write_mem(sc, URE_USB_TOLERANCE, 1661a24d62b5SKevin Lo URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); 1662a24d62b5SKevin Lo 1663d4cf41a9SHans Petter Selasky ure_enable_aldps(sc, false); 1664a24d62b5SKevin Lo 1665a24d62b5SKevin Lo if (sc->sc_chip & (URE_CHIP_VER_5C00 | URE_CHIP_VER_5C10 | 1666a24d62b5SKevin Lo URE_CHIP_VER_5C20)) { 1667a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_ADC_CFG, 1668a24d62b5SKevin Lo URE_CKADSEL_L | URE_ADC_EN | URE_EN_EMI_L); 1669a24d62b5SKevin Lo } 1670a24d62b5SKevin Lo if (sc->sc_chip & URE_CHIP_VER_5C00) { 1671a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_EEE_CFG, 1672a24d62b5SKevin Lo ure_ocp_reg_read(sc, URE_OCP_EEE_CFG) & 1673a24d62b5SKevin Lo ~URE_CTAP_SHORT_EN); 1674a24d62b5SKevin Lo } 1675a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_POWER_CFG, 1676a24d62b5SKevin Lo ure_ocp_reg_read(sc, URE_OCP_POWER_CFG) | 1677a24d62b5SKevin Lo URE_EEE_CLKDIV_EN); 1678a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_DOWN_SPEED, 1679a24d62b5SKevin Lo ure_ocp_reg_read(sc, URE_OCP_DOWN_SPEED) | 1680a24d62b5SKevin Lo URE_EN_10M_BGOFF); 1681a24d62b5SKevin Lo ure_ocp_reg_write(sc, URE_OCP_POWER_CFG, 1682a24d62b5SKevin Lo ure_ocp_reg_read(sc, URE_OCP_POWER_CFG) | 1683a24d62b5SKevin Lo URE_EN_10M_PLLOFF); 1684d4cf41a9SHans Petter Selasky ure_sram_write(sc, URE_SRAM_IMPEDANCE, 0x0b13); 1685d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, URE_PFM_PWM_SWITCH); 1686a24d62b5SKevin Lo 1687a24d62b5SKevin Lo /* Enable LPF corner auto tune. */ 1688d4cf41a9SHans Petter Selasky ure_sram_write(sc, URE_SRAM_LPF_CFG, 0xf70f); 1689a24d62b5SKevin Lo 1690a24d62b5SKevin Lo /* Adjust 10M amplitude. */ 1691d4cf41a9SHans Petter Selasky ure_sram_write(sc, URE_SRAM_10M_AMP1, 0x00af); 1692d4cf41a9SHans Petter Selasky ure_sram_write(sc, URE_SRAM_10M_AMP2, 0x0208); 1693d4cf41a9SHans Petter Selasky 1694d4cf41a9SHans Petter Selasky ure_rtl8152_nic_reset(sc); 1695d4cf41a9SHans Petter Selasky 1696d4cf41a9SHans Petter Selasky /* Enable Rx aggregation. */ 1697d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, URE_RX_AGG_DISABLE | URE_RX_ZERO_EN); 1698d4cf41a9SHans Petter Selasky 1699d4cf41a9SHans Petter Selasky val = ure_read_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); 1700d4cf41a9SHans Petter Selasky if (!(sc->sc_chip & (URE_CHIP_VER_5C00 | URE_CHIP_VER_5C10))) 1701d4cf41a9SHans Petter Selasky val |= URE_U2P3_ENABLE; 1702d4cf41a9SHans Petter Selasky else 1703d4cf41a9SHans Petter Selasky val &= ~URE_U2P3_ENABLE; 1704d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); 1705d4cf41a9SHans Petter Selasky 1706d4cf41a9SHans Petter Selasky memset(u1u2, 0xff, sizeof(u1u2)); 1707d4cf41a9SHans Petter Selasky ure_write_mem(sc, URE_USB_TOLERANCE, 1708d4cf41a9SHans Petter Selasky URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); 1709a24d62b5SKevin Lo } 1710a24d62b5SKevin Lo 1711d4cf41a9SHans Petter Selasky static void 1712d4cf41a9SHans Petter Selasky ure_rtl8153b_init(struct ure_softc *sc) 1713d4cf41a9SHans Petter Selasky { 1714d4cf41a9SHans Petter Selasky uint16_t val; 1715d4cf41a9SHans Petter Selasky int i; 1716d4cf41a9SHans Petter Selasky 1717d4cf41a9SHans Petter Selasky if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) { 1718d4cf41a9SHans Petter Selasky URE_CLRBIT_1(sc, 0xd26b, URE_MCU_TYPE_USB, 0x01); 1719d4cf41a9SHans Petter Selasky ure_write_2(sc, 0xd32a, URE_MCU_TYPE_USB, 0); 1720d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, 0xcfee, URE_MCU_TYPE_USB, 0x0020); 1721d4cf41a9SHans Petter Selasky } 1722d4cf41a9SHans Petter Selasky 1723d4cf41a9SHans Petter Selasky if (sc->sc_flags & URE_FLAG_8156B) { 1724d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, 0xb460, URE_MCU_TYPE_USB, 0x08); 1725d4cf41a9SHans Petter Selasky } 1726d4cf41a9SHans Petter Selasky 1727d4cf41a9SHans Petter Selasky ure_enable_aldps(sc, false); 1728d4cf41a9SHans Petter Selasky 1729d4cf41a9SHans Petter Selasky /* Disable U1U2 */ 1730d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_LPM_CONFIG, URE_MCU_TYPE_USB, URE_LPM_U1U2_EN); 1731d4cf41a9SHans Petter Selasky 1732d4cf41a9SHans Petter Selasky /* Wait loading flash */ 1733d4cf41a9SHans Petter Selasky if (sc->sc_chip == URE_CHIP_VER_7410) { 1734d4cf41a9SHans Petter Selasky if ((ure_read_2(sc, 0xd3ae, URE_MCU_TYPE_PLA) & 0x0002) && 1735d4cf41a9SHans Petter Selasky !(ure_read_2(sc, 0xd284, URE_MCU_TYPE_USB) & 0x0020)) { 1736d4cf41a9SHans Petter Selasky for (i=0; i < 100; i++) { 1737d4cf41a9SHans Petter Selasky if (ure_read_2(sc, 0xd284, URE_MCU_TYPE_USB) & 0x0004) 1738d4cf41a9SHans Petter Selasky break; 1739d4cf41a9SHans Petter Selasky uether_pause(&sc->sc_ue, hz / 1000); 1740d4cf41a9SHans Petter Selasky } 1741d4cf41a9SHans Petter Selasky } 1742d4cf41a9SHans Petter Selasky } 1743d4cf41a9SHans Petter Selasky 1744d4cf41a9SHans Petter Selasky for (i = 0; i < URE_TIMEOUT; i++) { 1745d4cf41a9SHans Petter Selasky if (ure_read_2(sc, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) & 1746d4cf41a9SHans Petter Selasky URE_AUTOLOAD_DONE) 1747d4cf41a9SHans Petter Selasky break; 1748d4cf41a9SHans Petter Selasky uether_pause(&sc->sc_ue, hz / 100); 1749d4cf41a9SHans Petter Selasky } 1750d4cf41a9SHans Petter Selasky if (i == URE_TIMEOUT) 1751d4cf41a9SHans Petter Selasky device_printf(sc->sc_ue.ue_dev, 1752d4cf41a9SHans Petter Selasky "timeout waiting for chip autoload\n"); 1753d4cf41a9SHans Petter Selasky 1754d4cf41a9SHans Petter Selasky val = ure_phy_status(sc, 0); 1755d4cf41a9SHans Petter Selasky if ((val == URE_PHY_STAT_EXT_INIT) & 1756d4cf41a9SHans Petter Selasky (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B))) { 1757d4cf41a9SHans Petter Selasky ure_ocp_reg_write(sc, 0xa468, 1758d4cf41a9SHans Petter Selasky ure_ocp_reg_read(sc, 0xa468) & ~0x0a); 1759d4cf41a9SHans Petter Selasky if (sc->sc_flags & URE_FLAG_8156B) 1760d4cf41a9SHans Petter Selasky ure_ocp_reg_write(sc, 0xa466, 1761d4cf41a9SHans Petter Selasky ure_ocp_reg_read(sc, 0xa466) & ~0x01); 1762d4cf41a9SHans Petter Selasky } 1763d4cf41a9SHans Petter Selasky 1764d4cf41a9SHans Petter Selasky val = ure_ocp_reg_read(sc, URE_OCP_BASE_MII + MII_BMCR); 1765d4cf41a9SHans Petter Selasky if (val & BMCR_PDOWN) { 1766d4cf41a9SHans Petter Selasky val &= ~BMCR_PDOWN; 1767d4cf41a9SHans Petter Selasky ure_ocp_reg_write(sc, URE_OCP_BASE_MII + MII_BMCR, val); 1768d4cf41a9SHans Petter Selasky } 1769d4cf41a9SHans Petter Selasky 1770d4cf41a9SHans Petter Selasky ure_phy_status(sc, URE_PHY_STAT_LAN_ON); 1771d4cf41a9SHans Petter Selasky 1772d4cf41a9SHans Petter Selasky /* Disable U2P3 */ 1773d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, URE_U2P3_ENABLE); 1774d4cf41a9SHans Petter Selasky 1775d4cf41a9SHans Petter Selasky /* MSC timer, 32760 ms. */ 1776d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_USB_MSC_TIMER, URE_MCU_TYPE_USB, 0x0fff); 1777d4cf41a9SHans Petter Selasky 1778d4cf41a9SHans Petter Selasky /* U1/U2/L1 idle timer, 500 us. */ 1779d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_USB_U1U2_TIMER, URE_MCU_TYPE_USB, 500); 1780d4cf41a9SHans Petter Selasky 1781d4cf41a9SHans Petter Selasky /* Disable power cut */ 1782d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, URE_PWR_EN); 1783d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_MISC_0, URE_MCU_TYPE_USB, URE_PCUT_STATUS); 1784d4cf41a9SHans Petter Selasky 1785d4cf41a9SHans Petter Selasky /* Disable ups */ 1786d4cf41a9SHans Petter Selasky URE_CLRBIT_1(sc, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, URE_UPS_EN | URE_USP_PREWAKE); 1787d4cf41a9SHans Petter Selasky URE_CLRBIT_1(sc, 0xcfff, URE_MCU_TYPE_USB, 0x01); 1788d4cf41a9SHans Petter Selasky 1789d4cf41a9SHans Petter Selasky /* Disable queue wake */ 1790d4cf41a9SHans Petter Selasky URE_CLRBIT_1(sc, URE_PLA_INDICATE_FALG, URE_MCU_TYPE_USB, URE_UPCOMING_RUNTIME_D3); 1791d4cf41a9SHans Petter Selasky URE_CLRBIT_1(sc, URE_PLA_SUSPEND_FLAG, URE_MCU_TYPE_USB, URE_LINK_CHG_EVENT); 1792d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_PLA_EXTRA_STATUS, URE_MCU_TYPE_USB, URE_LINK_CHANGE_FLAG); 1793d4cf41a9SHans Petter Selasky 1794d4cf41a9SHans Petter Selasky /* Disable runtime suspend */ 1795d4cf41a9SHans Petter Selasky ure_write_1(sc, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_CONFIG); 1796d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_PLA_CONFIG34, URE_MCU_TYPE_USB, URE_LINK_OFF_WAKE_EN); 1797d4cf41a9SHans Petter Selasky ure_write_1(sc, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML); 1798d4cf41a9SHans Petter Selasky 1799d4cf41a9SHans Petter Selasky /* Enable U1U2 */ 1800d4cf41a9SHans Petter Selasky if (usbd_get_speed(sc->sc_ue.ue_udev) == USB_SPEED_SUPER) 1801d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_USB_LPM_CONFIG, URE_MCU_TYPE_USB, URE_LPM_U1U2_EN); 1802d4cf41a9SHans Petter Selasky 1803d4cf41a9SHans Petter Selasky if (sc->sc_flags & URE_FLAG_8156B) { 1804d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, 0xc010, URE_MCU_TYPE_PLA, 0x0800); 1805d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, 0xe854, URE_MCU_TYPE_PLA, 0x0001); 1806d4cf41a9SHans Petter Selasky 1807d4cf41a9SHans Petter Selasky /* enable fc timer and set timer to 600 ms. */ 1808d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_USB_FC_TIMER, URE_MCU_TYPE_USB, URE_CTRL_TIMER_EN | (600 / 8)); 1809d4cf41a9SHans Petter Selasky 1810d4cf41a9SHans Petter Selasky if (!(ure_read_1(sc, 0xdc6b, URE_MCU_TYPE_PLA) & 0x80)) { 1811d4cf41a9SHans Petter Selasky val = ure_read_2(sc, URE_USB_FW_CTRL, URE_MCU_TYPE_USB); 1812d4cf41a9SHans Petter Selasky val |= URE_FLOW_CTRL_PATCH_OPT | 0x0100; 1813d4cf41a9SHans Petter Selasky val &= ~0x08; 1814d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_USB_FW_CTRL, URE_MCU_TYPE_USB, val); 1815d4cf41a9SHans Petter Selasky } 1816d4cf41a9SHans Petter Selasky 1817d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_USB_FW_TASK, URE_MCU_TYPE_USB, URE_FC_PATCH_TASK); 1818d4cf41a9SHans Petter Selasky } 1819d4cf41a9SHans Petter Selasky 1820d4cf41a9SHans Petter Selasky val = ure_read_2(sc, URE_PLA_EXTRA_STATUS, URE_MCU_TYPE_PLA); 1821d4cf41a9SHans Petter Selasky if (ure_get_link_status(sc)) 1822d4cf41a9SHans Petter Selasky val |= URE_CUR_LINK_OK; 1823d4cf41a9SHans Petter Selasky else 1824d4cf41a9SHans Petter Selasky val &= ~URE_CUR_LINK_OK; 1825d4cf41a9SHans Petter Selasky val |= URE_POLL_LINK_CHG; 1826d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_PLA_EXTRA_STATUS, URE_MCU_TYPE_PLA, val); 1827d4cf41a9SHans Petter Selasky 1828d4cf41a9SHans Petter Selasky /* MAC clock speed down */ 1829d4cf41a9SHans Petter Selasky if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) { 1830d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, 0x0403); 1831d4cf41a9SHans Petter Selasky val = ure_read_2(sc, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA); 1832d4cf41a9SHans Petter Selasky val &= ~0xff; 1833d4cf41a9SHans Petter Selasky val |= URE_MAC_CLK_SPDWN_EN | 0x03; 1834d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA, val); 1835d4cf41a9SHans Petter Selasky } else { 1836d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_USB, URE_MAC_CLK_SPDWN_EN); 1837d4cf41a9SHans Petter Selasky } 1838d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA, URE_PLA_MCU_SPDWN_EN); 1839d4cf41a9SHans Petter Selasky 1840d4cf41a9SHans Petter Selasky /* Enable Rx aggregation. */ 1841d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, URE_RX_AGG_DISABLE | URE_RX_ZERO_EN); 1842d4cf41a9SHans Petter Selasky 1843d4cf41a9SHans Petter Selasky if (sc->sc_flags & URE_FLAG_8156) 1844d4cf41a9SHans Petter Selasky URE_SETBIT_1(sc, 0xd4b4, URE_MCU_TYPE_USB, 0x02); 1845d4cf41a9SHans Petter Selasky 1846d4cf41a9SHans Petter Selasky /* Reset tally */ 1847d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_PLA_RSTTALLY, URE_MCU_TYPE_USB, URE_TALLY_RESET); 1848d4cf41a9SHans Petter Selasky } 1849d4cf41a9SHans Petter Selasky 1850d4cf41a9SHans Petter Selasky static void 1851d4cf41a9SHans Petter Selasky ure_rtl8153b_nic_reset(struct ure_softc *sc) 1852d4cf41a9SHans Petter Selasky { 1853935b194dSJustin Hibbits if_t ifp = uether_getifp(&sc->sc_ue); 1854d4cf41a9SHans Petter Selasky uint16_t val; 1855d4cf41a9SHans Petter Selasky int i; 1856d4cf41a9SHans Petter Selasky 1857d4cf41a9SHans Petter Selasky /* Disable U1U2 */ 1858d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_LPM_CONFIG, URE_MCU_TYPE_USB, URE_LPM_U1U2_EN); 1859d4cf41a9SHans Petter Selasky 1860d4cf41a9SHans Petter Selasky /* Disable U2P3 */ 1861d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, URE_U2P3_ENABLE); 1862d4cf41a9SHans Petter Selasky 1863d4cf41a9SHans Petter Selasky ure_enable_aldps(sc, false); 1864d4cf41a9SHans Petter Selasky 1865d4cf41a9SHans Petter Selasky /* Enable rxdy_gated */ 1866d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, URE_RXDY_GATED_EN); 1867d4cf41a9SHans Petter Selasky 1868d4cf41a9SHans Petter Selasky /* Disable teredo */ 1869d4cf41a9SHans Petter Selasky ure_disable_teredo(sc); 1870d4cf41a9SHans Petter Selasky 1871d4cf41a9SHans Petter Selasky DEVPRINTFN(14, sc->sc_ue.ue_dev, "rtl8153b_nic_reset: RCR: %#x\n", ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA)); 1872d4cf41a9SHans Petter Selasky URE_CLRBIT_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, URE_RCR_ACPT_ALL); 1873d4cf41a9SHans Petter Selasky 1874d4cf41a9SHans Petter Selasky ure_reset(sc); 1875d4cf41a9SHans Petter Selasky 1876d4cf41a9SHans Petter Selasky /* Reset BMU */ 1877d4cf41a9SHans Petter Selasky URE_CLRBIT_1(sc, URE_USB_BMU_RESET, URE_MCU_TYPE_USB, URE_BMU_RESET_EP_IN | URE_BMU_RESET_EP_OUT); 1878d4cf41a9SHans Petter Selasky URE_SETBIT_1(sc, URE_USB_BMU_RESET, URE_MCU_TYPE_USB, URE_BMU_RESET_EP_IN | URE_BMU_RESET_EP_OUT); 1879d4cf41a9SHans Petter Selasky 1880d4cf41a9SHans Petter Selasky URE_CLRBIT_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, URE_NOW_IS_OOB); 1881d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, URE_MCU_BORW_EN); 1882d4cf41a9SHans Petter Selasky if (sc->sc_flags & URE_FLAG_8153B) { 1883d4cf41a9SHans Petter Selasky for (i = 0; i < URE_TIMEOUT; i++) { 1884d4cf41a9SHans Petter Selasky if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & 1885d4cf41a9SHans Petter Selasky URE_LINK_LIST_READY) 1886d4cf41a9SHans Petter Selasky break; 1887d4cf41a9SHans Petter Selasky uether_pause(&sc->sc_ue, hz / 100); 1888d4cf41a9SHans Petter Selasky } 1889d4cf41a9SHans Petter Selasky if (i == URE_TIMEOUT) 1890d4cf41a9SHans Petter Selasky device_printf(sc->sc_ue.ue_dev, 1891d4cf41a9SHans Petter Selasky "timeout waiting for OOB control\n"); 1892d4cf41a9SHans Petter Selasky 1893d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, URE_RE_INIT_LL); 1894d4cf41a9SHans Petter Selasky for (i = 0; i < URE_TIMEOUT; i++) { 1895d4cf41a9SHans Petter Selasky if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & 1896d4cf41a9SHans Petter Selasky URE_LINK_LIST_READY) 1897d4cf41a9SHans Petter Selasky break; 1898d4cf41a9SHans Petter Selasky uether_pause(&sc->sc_ue, hz / 100); 1899d4cf41a9SHans Petter Selasky } 1900d4cf41a9SHans Petter Selasky if (i == URE_TIMEOUT) 1901d4cf41a9SHans Petter Selasky device_printf(sc->sc_ue.ue_dev, 1902d4cf41a9SHans Petter Selasky "timeout waiting for OOB control\n"); 1903d4cf41a9SHans Petter Selasky } 1904d4cf41a9SHans Petter Selasky 1905d4cf41a9SHans Petter Selasky /* Configure rxvlan */ 1906d4cf41a9SHans Petter Selasky val = ure_read_2(sc, 0xc012, URE_MCU_TYPE_PLA); 1907d4cf41a9SHans Petter Selasky val &= ~0x00c0; 1908935b194dSJustin Hibbits if (if_getcapabilities(ifp) & IFCAP_VLAN_HWTAGGING) 1909d4cf41a9SHans Petter Selasky val |= 0x00c0; 1910d4cf41a9SHans Petter Selasky ure_write_2(sc, 0xc012, URE_MCU_TYPE_PLA, val); 1911d4cf41a9SHans Petter Selasky 1912d4cf41a9SHans Petter Selasky val = if_getmtu(ifp); 1913d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_PLA_RMS, URE_MCU_TYPE_PLA, URE_FRAMELEN(val)); 1914d4cf41a9SHans Petter Selasky ure_write_1(sc, URE_PLA_MTPS, URE_MCU_TYPE_PLA, URE_MTPS_JUMBO); 1915d4cf41a9SHans Petter Selasky 1916d4cf41a9SHans Petter Selasky if (sc->sc_flags & URE_FLAG_8153B) { 1917d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_PLA_TCR0, URE_MCU_TYPE_PLA, URE_TCR0_AUTO_FIFO); 1918d4cf41a9SHans Petter Selasky ure_reset(sc); 1919d4cf41a9SHans Petter Selasky } 1920d4cf41a9SHans Petter Selasky 1921d4cf41a9SHans Petter Selasky /* Configure fc parameter */ 1922d4cf41a9SHans Petter Selasky if (sc->sc_flags & URE_FLAG_8156) { 1923d4cf41a9SHans Petter Selasky ure_write_2(sc, 0xc0a6, URE_MCU_TYPE_PLA, 0x0400); 1924d4cf41a9SHans Petter Selasky ure_write_2(sc, 0xc0aa, URE_MCU_TYPE_PLA, 0x0800); 1925d4cf41a9SHans Petter Selasky } else if (sc->sc_flags & URE_FLAG_8156B) { 1926d4cf41a9SHans Petter Selasky ure_write_2(sc, 0xc0a6, URE_MCU_TYPE_PLA, 0x0200); 1927d4cf41a9SHans Petter Selasky ure_write_2(sc, 0xc0aa, URE_MCU_TYPE_PLA, 0x0400); 1928d4cf41a9SHans Petter Selasky } 1929d4cf41a9SHans Petter Selasky 1930d4cf41a9SHans Petter Selasky /* Configure Rx FIFO threshold. */ 1931d4cf41a9SHans Petter Selasky if (sc->sc_flags & URE_FLAG_8153B) { 1932d4cf41a9SHans Petter Selasky ure_write_4(sc, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA, URE_RXFIFO_THR1_NORMAL); 1933d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, URE_RXFIFO_THR2_NORMAL); 1934d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, URE_RXFIFO_THR3_NORMAL); 1935d4cf41a9SHans Petter Selasky ure_write_4(sc, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_B); 1936d4cf41a9SHans Petter Selasky } else { 1937d4cf41a9SHans Petter Selasky ure_write_2(sc, 0xc0a2, URE_MCU_TYPE_PLA, 1938d4cf41a9SHans Petter Selasky (ure_read_2(sc, 0xc0a2, URE_MCU_TYPE_PLA) & ~0xfff) | 0x08); 1939d4cf41a9SHans Petter Selasky ure_write_4(sc, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, 0x00600400); 1940d4cf41a9SHans Petter Selasky } 1941d4cf41a9SHans Petter Selasky 1942d4cf41a9SHans Petter Selasky /* Configure Tx FIFO threshold. */ 1943d4cf41a9SHans Petter Selasky if (sc->sc_flags & URE_FLAG_8153B) { 1944d4cf41a9SHans Petter Selasky ure_write_4(sc, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, URE_TXFIFO_THR_NORMAL2); 1945d4cf41a9SHans Petter Selasky } else if (sc->sc_flags & URE_FLAG_8156) { 1946d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, URE_TXFIFO_THR_NORMAL2); 1947d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, 0xd4b4, URE_MCU_TYPE_USB, 0x0002); 1948d4cf41a9SHans Petter Selasky } else if (sc->sc_flags & URE_FLAG_8156B) { 1949d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, 0x0008); 1950d4cf41a9SHans Petter Selasky ure_write_2(sc, 0xe61a, URE_MCU_TYPE_PLA, 1951d4cf41a9SHans Petter Selasky (URE_FRAMELEN(val) + 0x100) / 16 ); 1952d4cf41a9SHans Petter Selasky } 1953d4cf41a9SHans Petter Selasky 1954d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA, URE_PLA_MCU_SPDWN_EN); 1955d4cf41a9SHans Petter Selasky 1956d4cf41a9SHans Petter Selasky if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) 1957d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, 0xd32a, URE_MCU_TYPE_USB, 0x300); 1958d4cf41a9SHans Petter Selasky 1959d4cf41a9SHans Petter Selasky ure_enable_aldps(sc, true); 1960d4cf41a9SHans Petter Selasky 1961d4cf41a9SHans Petter Selasky if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) { 1962d4cf41a9SHans Petter Selasky /* Enable U2P3 */ 1963d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, URE_U2P3_ENABLE); 1964d4cf41a9SHans Petter Selasky } 1965d4cf41a9SHans Petter Selasky 1966d4cf41a9SHans Petter Selasky /* Enable U1U2 */ 1967d4cf41a9SHans Petter Selasky if (usbd_get_speed(sc->sc_ue.ue_udev) == USB_SPEED_SUPER) 1968d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_USB_LPM_CONFIG, URE_MCU_TYPE_USB, URE_LPM_U1U2_EN); 1969d4cf41a9SHans Petter Selasky } 1970d4cf41a9SHans Petter Selasky 1971d4cf41a9SHans Petter Selasky static void 1972d4cf41a9SHans Petter Selasky ure_stop(struct usb_ether *ue) 1973d4cf41a9SHans Petter Selasky { 1974d4cf41a9SHans Petter Selasky struct ure_softc *sc = uether_getsc(ue); 1975935b194dSJustin Hibbits if_t ifp = uether_getifp(ue); 1976d4cf41a9SHans Petter Selasky 1977d4cf41a9SHans Petter Selasky URE_LOCK_ASSERT(sc, MA_OWNED); 1978d4cf41a9SHans Petter Selasky 1979935b194dSJustin Hibbits if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)); 1980d4cf41a9SHans Petter Selasky sc->sc_flags &= ~URE_FLAG_LINK; 1981d4cf41a9SHans Petter Selasky sc->sc_rxstarted = 0; 1982d4cf41a9SHans Petter Selasky 1983d4cf41a9SHans Petter Selasky /* 1984d4cf41a9SHans Petter Selasky * stop all the transfers, if not already stopped: 1985d4cf41a9SHans Petter Selasky */ 1986d4cf41a9SHans Petter Selasky for (int i = 0; i < URE_MAX_RX; i++) 1987d4cf41a9SHans Petter Selasky usbd_transfer_stop(sc->sc_rx_xfer[i]); 1988d4cf41a9SHans Petter Selasky for (int i = 0; i < URE_MAX_TX; i++) 1989d4cf41a9SHans Petter Selasky usbd_transfer_stop(sc->sc_tx_xfer[i]); 1990d4cf41a9SHans Petter Selasky } 1991d4cf41a9SHans Petter Selasky 1992d4cf41a9SHans Petter Selasky static void 1993d4cf41a9SHans Petter Selasky ure_disable_teredo(struct ure_softc *sc) 1994d4cf41a9SHans Petter Selasky { 1995d4cf41a9SHans Petter Selasky 1996d4cf41a9SHans Petter Selasky if (sc->sc_flags & (URE_FLAG_8153B | URE_FLAG_8156 | URE_FLAG_8156B)) 1997d4cf41a9SHans Petter Selasky ure_write_1(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA, 0xff); 1998d4cf41a9SHans Petter Selasky else { 1999d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA, 2000d4cf41a9SHans Petter Selasky (URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN)); 2001d4cf41a9SHans Petter Selasky } 2002d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA, URE_WDT6_SET_MODE); 2003d4cf41a9SHans Petter Selasky ure_write_2(sc, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0); 2004d4cf41a9SHans Petter Selasky ure_write_4(sc, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0); 2005d4cf41a9SHans Petter Selasky } 2006d4cf41a9SHans Petter Selasky 2007d4cf41a9SHans Petter Selasky static void 2008d4cf41a9SHans Petter Selasky ure_enable_aldps(struct ure_softc *sc, bool enable) 2009d4cf41a9SHans Petter Selasky { 2010d4cf41a9SHans Petter Selasky int i; 2011d4cf41a9SHans Petter Selasky 2012d4cf41a9SHans Petter Selasky if (enable) { 2013d4cf41a9SHans Petter Selasky ure_ocp_reg_write(sc, URE_OCP_POWER_CFG, 2014d4cf41a9SHans Petter Selasky ure_ocp_reg_read(sc, URE_OCP_POWER_CFG) | URE_EN_ALDPS); 2015d4cf41a9SHans Petter Selasky } else { 2016d4cf41a9SHans Petter Selasky ure_ocp_reg_write(sc, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | 2017d4cf41a9SHans Petter Selasky URE_DIS_SDSAVE); 2018d4cf41a9SHans Petter Selasky for (i = 0; i < 20; i++) { 2019d4cf41a9SHans Petter Selasky uether_pause(&sc->sc_ue, hz / 1000); 2020d4cf41a9SHans Petter Selasky if (ure_ocp_reg_read(sc, 0xe000) & 0x0100) 2021d4cf41a9SHans Petter Selasky break; 2022d4cf41a9SHans Petter Selasky } 2023d4cf41a9SHans Petter Selasky } 2024d4cf41a9SHans Petter Selasky } 2025d4cf41a9SHans Petter Selasky 2026d4cf41a9SHans Petter Selasky static uint16_t 2027d4cf41a9SHans Petter Selasky ure_phy_status(struct ure_softc *sc, uint16_t desired) 2028d4cf41a9SHans Petter Selasky { 2029d4cf41a9SHans Petter Selasky uint16_t val; 2030d4cf41a9SHans Petter Selasky int i; 2031d4cf41a9SHans Petter Selasky 2032d4cf41a9SHans Petter Selasky for (i = 0; i < URE_TIMEOUT; i++) { 2033d4cf41a9SHans Petter Selasky val = ure_ocp_reg_read(sc, URE_OCP_PHY_STATUS) & 2034d4cf41a9SHans Petter Selasky URE_PHY_STAT_MASK; 2035d4cf41a9SHans Petter Selasky if (desired) { 2036d4cf41a9SHans Petter Selasky if (val == desired) 2037d4cf41a9SHans Petter Selasky break; 2038d4cf41a9SHans Petter Selasky } else { 2039d4cf41a9SHans Petter Selasky if (val == URE_PHY_STAT_LAN_ON || 2040d4cf41a9SHans Petter Selasky val == URE_PHY_STAT_PWRDN || 2041d4cf41a9SHans Petter Selasky val == URE_PHY_STAT_EXT_INIT) 2042d4cf41a9SHans Petter Selasky break; 2043d4cf41a9SHans Petter Selasky } 2044d4cf41a9SHans Petter Selasky uether_pause(&sc->sc_ue, hz / 100); 2045d4cf41a9SHans Petter Selasky } 2046d4cf41a9SHans Petter Selasky if (i == URE_TIMEOUT) 2047d4cf41a9SHans Petter Selasky device_printf(sc->sc_ue.ue_dev, 2048d4cf41a9SHans Petter Selasky "timeout waiting for phy to stabilize\n"); 2049d4cf41a9SHans Petter Selasky 2050d4cf41a9SHans Petter Selasky return (val); 2051d4cf41a9SHans Petter Selasky } 2052d4cf41a9SHans Petter Selasky 2053d4cf41a9SHans Petter Selasky static void 2054d4cf41a9SHans Petter Selasky ure_rtl8152_nic_reset(struct ure_softc *sc) 2055d4cf41a9SHans Petter Selasky { 2056d4cf41a9SHans Petter Selasky uint32_t rx_fifo1, rx_fifo2; 2057d4cf41a9SHans Petter Selasky int i; 2058d4cf41a9SHans Petter Selasky 2059d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, URE_RXDY_GATED_EN); 2060d4cf41a9SHans Petter Selasky 2061d4cf41a9SHans Petter Selasky ure_disable_teredo(sc); 2062d4cf41a9SHans Petter Selasky 2063d4cf41a9SHans Petter Selasky DEVPRINTFN(14, sc->sc_ue.ue_dev, "rtl8152_nic_reset: RCR: %#x\n", ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA)); 2064d4cf41a9SHans Petter Selasky URE_CLRBIT_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, URE_RCR_ACPT_ALL); 2065d4cf41a9SHans Petter Selasky 2066e1b74f21SKevin Lo ure_reset(sc); 2067e1b74f21SKevin Lo 2068e1b74f21SKevin Lo ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, 0); 2069e1b74f21SKevin Lo 2070d4cf41a9SHans Petter Selasky URE_CLRBIT_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, URE_NOW_IS_OOB); 2071e1b74f21SKevin Lo 2072d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, URE_MCU_BORW_EN); 2073e1b74f21SKevin Lo for (i = 0; i < URE_TIMEOUT; i++) { 2074e1b74f21SKevin Lo if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & 2075e1b74f21SKevin Lo URE_LINK_LIST_READY) 2076e1b74f21SKevin Lo break; 2077e1b74f21SKevin Lo uether_pause(&sc->sc_ue, hz / 100); 2078e1b74f21SKevin Lo } 2079e1b74f21SKevin Lo if (i == URE_TIMEOUT) 2080e1b74f21SKevin Lo device_printf(sc->sc_ue.ue_dev, 2081e1b74f21SKevin Lo "timeout waiting for OOB control\n"); 2082d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, URE_RE_INIT_LL); 2083e1b74f21SKevin Lo for (i = 0; i < URE_TIMEOUT; i++) { 2084e1b74f21SKevin Lo if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & 2085e1b74f21SKevin Lo URE_LINK_LIST_READY) 2086e1b74f21SKevin Lo break; 2087e1b74f21SKevin Lo uether_pause(&sc->sc_ue, hz / 100); 2088e1b74f21SKevin Lo } 2089e1b74f21SKevin Lo if (i == URE_TIMEOUT) 2090e1b74f21SKevin Lo device_printf(sc->sc_ue.ue_dev, 2091e1b74f21SKevin Lo "timeout waiting for OOB control\n"); 2092e1b74f21SKevin Lo 2093d4cf41a9SHans Petter Selasky URE_CLRBIT_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA, URE_CPCR_RX_VLAN); 2094d4cf41a9SHans Petter Selasky 2095d4cf41a9SHans Petter Selasky URE_SETBIT_2(sc, URE_PLA_TCR0, URE_MCU_TYPE_PLA, URE_TCR0_AUTO_FIFO); 2096e1b74f21SKevin Lo 2097e1b74f21SKevin Lo /* Configure Rx FIFO threshold. */ 2098e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA, 2099e1b74f21SKevin Lo URE_RXFIFO_THR1_NORMAL); 2100e1b74f21SKevin Lo if (usbd_get_speed(sc->sc_ue.ue_udev) == USB_SPEED_FULL) { 2101e1b74f21SKevin Lo rx_fifo1 = URE_RXFIFO_THR2_FULL; 2102e1b74f21SKevin Lo rx_fifo2 = URE_RXFIFO_THR3_FULL; 2103e1b74f21SKevin Lo } else { 2104e1b74f21SKevin Lo rx_fifo1 = URE_RXFIFO_THR2_HIGH; 2105e1b74f21SKevin Lo rx_fifo2 = URE_RXFIFO_THR3_HIGH; 2106e1b74f21SKevin Lo } 2107e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1); 2108e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2); 2109e1b74f21SKevin Lo 2110e1b74f21SKevin Lo /* Configure Tx FIFO threshold. */ 2111e1b74f21SKevin Lo ure_write_4(sc, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, 2112e1b74f21SKevin Lo URE_TXFIFO_THR_NORMAL); 2113e1b74f21SKevin Lo } 21147d5522e1SJohn-Mark Gurney 21157d5522e1SJohn-Mark Gurney /* 21167d5522e1SJohn-Mark Gurney * Update mbuf for rx checksum from hardware 21177d5522e1SJohn-Mark Gurney */ 21187d5522e1SJohn-Mark Gurney static void 21197d5522e1SJohn-Mark Gurney ure_rxcsum(int capenb, struct ure_rxpkt *rp, struct mbuf *m) 21207d5522e1SJohn-Mark Gurney { 21217d5522e1SJohn-Mark Gurney int flags; 21227d5522e1SJohn-Mark Gurney uint32_t csum, misc; 21237d5522e1SJohn-Mark Gurney int tcp, udp; 21247d5522e1SJohn-Mark Gurney 21257d5522e1SJohn-Mark Gurney m->m_pkthdr.csum_flags = 0; 21267d5522e1SJohn-Mark Gurney 21277d5522e1SJohn-Mark Gurney if (!(capenb & IFCAP_RXCSUM)) 21287d5522e1SJohn-Mark Gurney return; 21297d5522e1SJohn-Mark Gurney 21307d5522e1SJohn-Mark Gurney csum = le32toh(rp->ure_csum); 21317d5522e1SJohn-Mark Gurney misc = le32toh(rp->ure_misc); 21327d5522e1SJohn-Mark Gurney 21337d5522e1SJohn-Mark Gurney tcp = udp = 0; 21347d5522e1SJohn-Mark Gurney 21357d5522e1SJohn-Mark Gurney flags = 0; 21367d5522e1SJohn-Mark Gurney if (csum & URE_RXPKT_IPV4_CS) 21377d5522e1SJohn-Mark Gurney flags |= CSUM_IP_CHECKED; 21387d5522e1SJohn-Mark Gurney else if (csum & URE_RXPKT_IPV6_CS) 21397d5522e1SJohn-Mark Gurney flags = 0; 21407d5522e1SJohn-Mark Gurney 21417d5522e1SJohn-Mark Gurney tcp = rp->ure_csum & URE_RXPKT_TCP_CS; 21427d5522e1SJohn-Mark Gurney udp = rp->ure_csum & URE_RXPKT_UDP_CS; 21437d5522e1SJohn-Mark Gurney 21447d5522e1SJohn-Mark Gurney if (__predict_true((flags & CSUM_IP_CHECKED) && 21457d5522e1SJohn-Mark Gurney !(misc & URE_RXPKT_IP_F))) { 21467d5522e1SJohn-Mark Gurney flags |= CSUM_IP_VALID; 21477d5522e1SJohn-Mark Gurney } 21487d5522e1SJohn-Mark Gurney if (__predict_true( 21497d5522e1SJohn-Mark Gurney (tcp && !(misc & URE_RXPKT_TCP_F)) || 21507d5522e1SJohn-Mark Gurney (udp && !(misc & URE_RXPKT_UDP_F)))) { 21517d5522e1SJohn-Mark Gurney flags |= CSUM_DATA_VALID|CSUM_PSEUDO_HDR; 21527d5522e1SJohn-Mark Gurney m->m_pkthdr.csum_data = 0xFFFF; 21537d5522e1SJohn-Mark Gurney } 21547d5522e1SJohn-Mark Gurney 21557d5522e1SJohn-Mark Gurney m->m_pkthdr.csum_flags = flags; 21567d5522e1SJohn-Mark Gurney } 21577d5522e1SJohn-Mark Gurney 21587d5522e1SJohn-Mark Gurney /* 21597d5522e1SJohn-Mark Gurney * If the L4 checksum offset is larger than 0x7ff (2047), return failure. 21607d5522e1SJohn-Mark Gurney * We currently restrict MTU such that it can't happen, and even if we 21617d5522e1SJohn-Mark Gurney * did have a large enough MTU, only a very specially crafted IPv6 packet 21627d5522e1SJohn-Mark Gurney * with MANY headers could possibly come close. 21637d5522e1SJohn-Mark Gurney * 21647d5522e1SJohn-Mark Gurney * Returns 0 for success, and 1 if the packet cannot be checksummed and 21657d5522e1SJohn-Mark Gurney * should be dropped. 21667d5522e1SJohn-Mark Gurney */ 21677d5522e1SJohn-Mark Gurney static int 21687d5522e1SJohn-Mark Gurney ure_txcsum(struct mbuf *m, int caps, uint32_t *regout) 21697d5522e1SJohn-Mark Gurney { 21707d5522e1SJohn-Mark Gurney struct ip ip; 21717d5522e1SJohn-Mark Gurney struct ether_header *eh; 21727d5522e1SJohn-Mark Gurney int flags; 21737d5522e1SJohn-Mark Gurney uint32_t data; 21747d5522e1SJohn-Mark Gurney uint32_t reg; 21757d5522e1SJohn-Mark Gurney int l3off, l4off; 21767d5522e1SJohn-Mark Gurney uint16_t type; 21777d5522e1SJohn-Mark Gurney 21787d5522e1SJohn-Mark Gurney *regout = 0; 21797d5522e1SJohn-Mark Gurney flags = m->m_pkthdr.csum_flags; 21807d5522e1SJohn-Mark Gurney if (flags == 0) 21817d5522e1SJohn-Mark Gurney return (0); 21827d5522e1SJohn-Mark Gurney 21837d5522e1SJohn-Mark Gurney if (__predict_true(m->m_len >= (int)sizeof(*eh))) { 21847d5522e1SJohn-Mark Gurney eh = mtod(m, struct ether_header *); 21857d5522e1SJohn-Mark Gurney type = eh->ether_type; 21867d5522e1SJohn-Mark Gurney } else 21877d5522e1SJohn-Mark Gurney m_copydata(m, offsetof(struct ether_header, ether_type), 21887d5522e1SJohn-Mark Gurney sizeof(type), (caddr_t)&type); 21897d5522e1SJohn-Mark Gurney 21907d5522e1SJohn-Mark Gurney switch (type = htons(type)) { 21917d5522e1SJohn-Mark Gurney case ETHERTYPE_IP: 21927d5522e1SJohn-Mark Gurney case ETHERTYPE_IPV6: 21937d5522e1SJohn-Mark Gurney l3off = ETHER_HDR_LEN; 21947d5522e1SJohn-Mark Gurney break; 21957d5522e1SJohn-Mark Gurney case ETHERTYPE_VLAN: 21967d5522e1SJohn-Mark Gurney /* XXX - what about QinQ? */ 21977d5522e1SJohn-Mark Gurney l3off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 21987d5522e1SJohn-Mark Gurney break; 21997d5522e1SJohn-Mark Gurney default: 22007d5522e1SJohn-Mark Gurney return (0); 22017d5522e1SJohn-Mark Gurney } 22027d5522e1SJohn-Mark Gurney 22037d5522e1SJohn-Mark Gurney reg = 0; 22047d5522e1SJohn-Mark Gurney 22057d5522e1SJohn-Mark Gurney if (flags & CSUM_IP) 22067d5522e1SJohn-Mark Gurney reg |= URE_TXPKT_IPV4_CS; 22077d5522e1SJohn-Mark Gurney 22087d5522e1SJohn-Mark Gurney data = m->m_pkthdr.csum_data; 22097d5522e1SJohn-Mark Gurney if (flags & (CSUM_IP_TCP | CSUM_IP_UDP)) { 22107d5522e1SJohn-Mark Gurney m_copydata(m, l3off, sizeof ip, (caddr_t)&ip); 22117d5522e1SJohn-Mark Gurney l4off = l3off + (ip.ip_hl << 2) + data; 22127d5522e1SJohn-Mark Gurney if (__predict_false(l4off > URE_L4_OFFSET_MAX)) 22137d5522e1SJohn-Mark Gurney return (1); 22147d5522e1SJohn-Mark Gurney 22157d5522e1SJohn-Mark Gurney reg |= URE_TXPKT_IPV4_CS; 22167d5522e1SJohn-Mark Gurney if (flags & CSUM_IP_TCP) 22177d5522e1SJohn-Mark Gurney reg |= URE_TXPKT_TCP_CS; 22187d5522e1SJohn-Mark Gurney else if (flags & CSUM_IP_UDP) 22197d5522e1SJohn-Mark Gurney reg |= URE_TXPKT_UDP_CS; 22207d5522e1SJohn-Mark Gurney reg |= l4off << URE_L4_OFFSET_SHIFT; 22217d5522e1SJohn-Mark Gurney } 22227d5522e1SJohn-Mark Gurney #ifdef INET6 22237d5522e1SJohn-Mark Gurney else if (flags & (CSUM_IP6_TCP | CSUM_IP6_UDP)) { 22247d5522e1SJohn-Mark Gurney l4off = l3off + data; 22257d5522e1SJohn-Mark Gurney if (__predict_false(l4off > URE_L4_OFFSET_MAX)) 22267d5522e1SJohn-Mark Gurney return (1); 22277d5522e1SJohn-Mark Gurney 22287d5522e1SJohn-Mark Gurney reg |= URE_TXPKT_IPV6_CS; 22297d5522e1SJohn-Mark Gurney if (flags & CSUM_IP6_TCP) 22307d5522e1SJohn-Mark Gurney reg |= URE_TXPKT_TCP_CS; 22317d5522e1SJohn-Mark Gurney else if (flags & CSUM_IP6_UDP) 22327d5522e1SJohn-Mark Gurney reg |= URE_TXPKT_UDP_CS; 22337d5522e1SJohn-Mark Gurney reg |= l4off << URE_L4_OFFSET_SHIFT; 22347d5522e1SJohn-Mark Gurney } 22357d5522e1SJohn-Mark Gurney #endif 22367d5522e1SJohn-Mark Gurney *regout = reg; 22377d5522e1SJohn-Mark Gurney return 0; 22387d5522e1SJohn-Mark Gurney } 2239