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