1258331Smarkj/*- 2266490Skevlo * Copyright (c) 2013-2014 Kevin Lo 3258331Smarkj * All rights reserved. 4258331Smarkj * 5258331Smarkj * Redistribution and use in source and binary forms, with or without 6258331Smarkj * modification, are permitted provided that the following conditions 7258331Smarkj * are met: 8258331Smarkj * 1. Redistributions of source code must retain the above copyright 9258331Smarkj * notice, this list of conditions and the following disclaimer. 10258331Smarkj * 2. Redistributions in binary form must reproduce the above copyright 11258331Smarkj * notice, this list of conditions and the following disclaimer in the 12258331Smarkj * documentation and/or other materials provided with the distribution. 13258331Smarkj * 14258331Smarkj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15258331Smarkj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16258331Smarkj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17258331Smarkj * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18258331Smarkj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19258331Smarkj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20258331Smarkj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21258331Smarkj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22258331Smarkj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23258331Smarkj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24258331Smarkj * SUCH DAMAGE. 25258331Smarkj */ 26258331Smarkj 27258331Smarkj#include <sys/cdefs.h> 28258331Smarkj__FBSDID("$FreeBSD: releng/11.0/sys/dev/usb/net/if_axge.c 292080 2015-12-11 05:28:00Z imp $"); 29258331Smarkj 30258331Smarkj/* 31258331Smarkj * ASIX Electronics AX88178A/AX88179 USB 2.0/3.0 gigabit ethernet driver. 32258331Smarkj */ 33258331Smarkj 34258331Smarkj#include <sys/param.h> 35258331Smarkj#include <sys/systm.h> 36258331Smarkj#include <sys/bus.h> 37258331Smarkj#include <sys/condvar.h> 38258331Smarkj#include <sys/kernel.h> 39258331Smarkj#include <sys/lock.h> 40258331Smarkj#include <sys/module.h> 41258331Smarkj#include <sys/mutex.h> 42258331Smarkj#include <sys/socket.h> 43258331Smarkj#include <sys/sysctl.h> 44258331Smarkj#include <sys/unistd.h> 45258331Smarkj 46258331Smarkj#include <net/if.h> 47258331Smarkj#include <net/if_var.h> 48258331Smarkj 49258331Smarkj#include <dev/usb/usb.h> 50258331Smarkj#include <dev/usb/usbdi.h> 51258331Smarkj#include <dev/usb/usbdi_util.h> 52258331Smarkj#include "usbdevs.h" 53258331Smarkj 54258331Smarkj#define USB_DEBUG_VAR axge_debug 55258331Smarkj#include <dev/usb/usb_debug.h> 56258331Smarkj#include <dev/usb/usb_process.h> 57258331Smarkj 58258331Smarkj#include <dev/usb/net/usb_ethernet.h> 59258331Smarkj#include <dev/usb/net/if_axgereg.h> 60258331Smarkj 61258331Smarkj/* 62258331Smarkj * Various supported device vendors/products. 63258331Smarkj */ 64258331Smarkj 65258331Smarkjstatic const STRUCT_USB_HOST_ID axge_devs[] = { 66258331Smarkj#define AXGE_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 67258331Smarkj AXGE_DEV(ASIX, AX88178A), 68258331Smarkj AXGE_DEV(ASIX, AX88179), 69266738Skevlo AXGE_DEV(DLINK, DUB1312), 70281183Skevlo AXGE_DEV(LENOVO, GIGALAN), 71266738Skevlo AXGE_DEV(SITECOMEU, LN032), 72258331Smarkj#undef AXGE_DEV 73258331Smarkj}; 74258331Smarkj 75258331Smarkjstatic const struct { 76266490Skevlo uint8_t ctrl; 77266490Skevlo uint8_t timer_l; 78266490Skevlo uint8_t timer_h; 79266490Skevlo uint8_t size; 80266490Skevlo uint8_t ifg; 81268582Shselasky} __packed axge_bulk_size[] = { 82266490Skevlo { 7, 0x4f, 0x00, 0x12, 0xff }, 83266490Skevlo { 7, 0x20, 0x03, 0x16, 0xff }, 84266490Skevlo { 7, 0xae, 0x07, 0x18, 0xff }, 85266490Skevlo { 7, 0xcc, 0x4c, 0x18, 0x08 } 86258331Smarkj}; 87258331Smarkj 88258331Smarkj/* prototypes */ 89258331Smarkj 90258331Smarkjstatic device_probe_t axge_probe; 91258331Smarkjstatic device_attach_t axge_attach; 92258331Smarkjstatic device_detach_t axge_detach; 93258331Smarkj 94258331Smarkjstatic usb_callback_t axge_bulk_read_callback; 95258331Smarkjstatic usb_callback_t axge_bulk_write_callback; 96258331Smarkj 97258331Smarkjstatic miibus_readreg_t axge_miibus_readreg; 98258331Smarkjstatic miibus_writereg_t axge_miibus_writereg; 99258331Smarkjstatic miibus_statchg_t axge_miibus_statchg; 100258331Smarkj 101258331Smarkjstatic uether_fn_t axge_attach_post; 102258331Smarkjstatic uether_fn_t axge_init; 103258331Smarkjstatic uether_fn_t axge_stop; 104258331Smarkjstatic uether_fn_t axge_start; 105258331Smarkjstatic uether_fn_t axge_tick; 106258331Smarkjstatic uether_fn_t axge_setmulti; 107258331Smarkjstatic uether_fn_t axge_setpromisc; 108258331Smarkj 109258331Smarkjstatic int axge_read_mem(struct axge_softc *, uint8_t, uint16_t, 110258331Smarkj uint16_t, void *, int); 111258331Smarkjstatic void axge_write_mem(struct axge_softc *, uint8_t, uint16_t, 112258331Smarkj uint16_t, void *, int); 113266738Skevlostatic uint8_t axge_read_cmd_1(struct axge_softc *, uint8_t, uint16_t); 114258331Smarkjstatic uint16_t axge_read_cmd_2(struct axge_softc *, uint8_t, uint16_t, 115258331Smarkj uint16_t); 116258331Smarkjstatic void axge_write_cmd_1(struct axge_softc *, uint8_t, uint16_t, 117266738Skevlo uint8_t); 118258331Smarkjstatic void axge_write_cmd_2(struct axge_softc *, uint8_t, uint16_t, 119258331Smarkj uint16_t, uint16_t); 120258331Smarkjstatic void axge_chip_init(struct axge_softc *); 121258331Smarkjstatic void axge_reset(struct axge_softc *); 122258331Smarkj 123258331Smarkjstatic int axge_attach_post_sub(struct usb_ether *); 124258331Smarkjstatic int axge_ifmedia_upd(struct ifnet *); 125258331Smarkjstatic void axge_ifmedia_sts(struct ifnet *, struct ifmediareq *); 126258331Smarkjstatic int axge_ioctl(struct ifnet *, u_long, caddr_t); 127268209Shselaskystatic void axge_rx_frame(struct usb_ether *, struct usb_page_cache *, int); 128268209Shselaskystatic void axge_rxeof(struct usb_ether *, struct usb_page_cache *, 129266738Skevlo unsigned int, unsigned int, uint32_t); 130258331Smarkjstatic void axge_csum_cfg(struct usb_ether *); 131258331Smarkj 132258331Smarkj#define AXGE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 133258331Smarkj 134258331Smarkj#ifdef USB_DEBUG 135258331Smarkjstatic int axge_debug = 0; 136258331Smarkj 137258331Smarkjstatic SYSCTL_NODE(_hw_usb, OID_AUTO, axge, CTLFLAG_RW, 0, "USB axge"); 138276701ShselaskySYSCTL_INT(_hw_usb_axge, OID_AUTO, debug, CTLFLAG_RWTUN, &axge_debug, 0, 139258331Smarkj "Debug level"); 140258331Smarkj#endif 141258331Smarkj 142258331Smarkjstatic const struct usb_config axge_config[AXGE_N_TRANSFER] = { 143258331Smarkj [AXGE_BULK_DT_WR] = { 144258331Smarkj .type = UE_BULK, 145258331Smarkj .endpoint = UE_ADDR_ANY, 146258331Smarkj .direction = UE_DIR_OUT, 147258331Smarkj .frames = 16, 148266738Skevlo .bufsize = 16 * MCLBYTES, 149258331Smarkj .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 150258331Smarkj .callback = axge_bulk_write_callback, 151258331Smarkj .timeout = 10000, /* 10 seconds */ 152258331Smarkj }, 153258331Smarkj [AXGE_BULK_DT_RD] = { 154258331Smarkj .type = UE_BULK, 155258331Smarkj .endpoint = UE_ADDR_ANY, 156258331Smarkj .direction = UE_DIR_IN, 157268582Shselasky .bufsize = 65536, 158258331Smarkj .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 159258331Smarkj .callback = axge_bulk_read_callback, 160258331Smarkj .timeout = 0, /* no timeout */ 161258331Smarkj }, 162258331Smarkj}; 163258331Smarkj 164258331Smarkjstatic device_method_t axge_methods[] = { 165258331Smarkj /* Device interface. */ 166258331Smarkj DEVMETHOD(device_probe, axge_probe), 167258331Smarkj DEVMETHOD(device_attach, axge_attach), 168258331Smarkj DEVMETHOD(device_detach, axge_detach), 169258331Smarkj 170258331Smarkj /* MII interface. */ 171258331Smarkj DEVMETHOD(miibus_readreg, axge_miibus_readreg), 172258331Smarkj DEVMETHOD(miibus_writereg, axge_miibus_writereg), 173258331Smarkj DEVMETHOD(miibus_statchg, axge_miibus_statchg), 174258331Smarkj 175258331Smarkj DEVMETHOD_END 176258331Smarkj}; 177258331Smarkj 178258331Smarkjstatic driver_t axge_driver = { 179258331Smarkj .name = "axge", 180258331Smarkj .methods = axge_methods, 181258331Smarkj .size = sizeof(struct axge_softc), 182258331Smarkj}; 183258331Smarkj 184258331Smarkjstatic devclass_t axge_devclass; 185258331Smarkj 186258331SmarkjDRIVER_MODULE(axge, uhub, axge_driver, axge_devclass, NULL, NULL); 187258331SmarkjDRIVER_MODULE(miibus, axge, miibus_driver, miibus_devclass, NULL, NULL); 188258331SmarkjMODULE_DEPEND(axge, uether, 1, 1, 1); 189258331SmarkjMODULE_DEPEND(axge, usb, 1, 1, 1); 190258331SmarkjMODULE_DEPEND(axge, ether, 1, 1, 1); 191258331SmarkjMODULE_DEPEND(axge, miibus, 1, 1, 1); 192258331SmarkjMODULE_VERSION(axge, 1); 193292080SimpUSB_PNP_HOST_INFO(axge_devs); 194258331Smarkj 195258331Smarkjstatic const struct usb_ether_methods axge_ue_methods = { 196258331Smarkj .ue_attach_post = axge_attach_post, 197258331Smarkj .ue_attach_post_sub = axge_attach_post_sub, 198258331Smarkj .ue_start = axge_start, 199258331Smarkj .ue_init = axge_init, 200258331Smarkj .ue_stop = axge_stop, 201258331Smarkj .ue_tick = axge_tick, 202258331Smarkj .ue_setmulti = axge_setmulti, 203258331Smarkj .ue_setpromisc = axge_setpromisc, 204258331Smarkj .ue_mii_upd = axge_ifmedia_upd, 205258331Smarkj .ue_mii_sts = axge_ifmedia_sts, 206258331Smarkj}; 207258331Smarkj 208258331Smarkjstatic int 209258331Smarkjaxge_read_mem(struct axge_softc *sc, uint8_t cmd, uint16_t index, 210258331Smarkj uint16_t val, void *buf, int len) 211258331Smarkj{ 212258331Smarkj struct usb_device_request req; 213258331Smarkj 214258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 215258331Smarkj 216258331Smarkj req.bmRequestType = UT_READ_VENDOR_DEVICE; 217258331Smarkj req.bRequest = cmd; 218258331Smarkj USETW(req.wValue, val); 219258331Smarkj USETW(req.wIndex, index); 220258331Smarkj USETW(req.wLength, len); 221258331Smarkj 222258331Smarkj return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 223258331Smarkj} 224258331Smarkj 225258331Smarkjstatic void 226258331Smarkjaxge_write_mem(struct axge_softc *sc, uint8_t cmd, uint16_t index, 227258331Smarkj uint16_t val, void *buf, int len) 228258331Smarkj{ 229258331Smarkj struct usb_device_request req; 230258331Smarkj 231258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 232258331Smarkj 233258331Smarkj req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 234258331Smarkj req.bRequest = cmd; 235258331Smarkj USETW(req.wValue, val); 236258331Smarkj USETW(req.wIndex, index); 237258331Smarkj USETW(req.wLength, len); 238258331Smarkj 239258331Smarkj if (uether_do_request(&sc->sc_ue, &req, buf, 1000)) { 240258331Smarkj /* Error ignored. */ 241258331Smarkj } 242258331Smarkj} 243258331Smarkj 244266490Skevlostatic uint8_t 245266738Skevloaxge_read_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t reg) 246266490Skevlo{ 247266490Skevlo uint8_t val; 248266490Skevlo 249266738Skevlo axge_read_mem(sc, cmd, 1, reg, &val, 1); 250266490Skevlo return (val); 251266490Skevlo} 252266490Skevlo 253258331Smarkjstatic uint16_t 254258331Smarkjaxge_read_cmd_2(struct axge_softc *sc, uint8_t cmd, uint16_t index, 255258331Smarkj uint16_t reg) 256258331Smarkj{ 257258331Smarkj uint8_t val[2]; 258258331Smarkj 259258331Smarkj axge_read_mem(sc, cmd, index, reg, &val, 2); 260258331Smarkj return (UGETW(val)); 261258331Smarkj} 262258331Smarkj 263258331Smarkjstatic void 264266738Skevloaxge_write_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t reg, uint8_t val) 265258331Smarkj{ 266266738Skevlo axge_write_mem(sc, cmd, 1, reg, &val, 1); 267258331Smarkj} 268258331Smarkj 269258331Smarkjstatic void 270258331Smarkjaxge_write_cmd_2(struct axge_softc *sc, uint8_t cmd, uint16_t index, 271258331Smarkj uint16_t reg, uint16_t val) 272258331Smarkj{ 273258331Smarkj uint8_t temp[2]; 274258331Smarkj 275258331Smarkj USETW(temp, val); 276258331Smarkj axge_write_mem(sc, cmd, index, reg, &temp, 2); 277258331Smarkj} 278258331Smarkj 279258331Smarkjstatic int 280258331Smarkjaxge_miibus_readreg(device_t dev, int phy, int reg) 281258331Smarkj{ 282258331Smarkj struct axge_softc *sc; 283258331Smarkj uint16_t val; 284258331Smarkj int locked; 285258331Smarkj 286258331Smarkj sc = device_get_softc(dev); 287258331Smarkj locked = mtx_owned(&sc->sc_mtx); 288258331Smarkj if (!locked) 289258331Smarkj AXGE_LOCK(sc); 290258331Smarkj 291258331Smarkj val = axge_read_cmd_2(sc, AXGE_ACCESS_PHY, reg, phy); 292258331Smarkj 293258331Smarkj if (!locked) 294258331Smarkj AXGE_UNLOCK(sc); 295258331Smarkj 296258331Smarkj return (val); 297258331Smarkj} 298258331Smarkj 299258331Smarkjstatic int 300258331Smarkjaxge_miibus_writereg(device_t dev, int phy, int reg, int val) 301258331Smarkj{ 302258331Smarkj struct axge_softc *sc; 303258331Smarkj int locked; 304258331Smarkj 305258331Smarkj sc = device_get_softc(dev); 306258331Smarkj if (sc->sc_phyno != phy) 307258331Smarkj return (0); 308258331Smarkj locked = mtx_owned(&sc->sc_mtx); 309258331Smarkj if (!locked) 310258331Smarkj AXGE_LOCK(sc); 311258331Smarkj 312258331Smarkj axge_write_cmd_2(sc, AXGE_ACCESS_PHY, reg, phy, val); 313258331Smarkj 314258331Smarkj if (!locked) 315258331Smarkj AXGE_UNLOCK(sc); 316258331Smarkj 317258331Smarkj return (0); 318258331Smarkj} 319258331Smarkj 320258331Smarkjstatic void 321258331Smarkjaxge_miibus_statchg(device_t dev) 322258331Smarkj{ 323258331Smarkj struct axge_softc *sc; 324258331Smarkj struct mii_data *mii; 325258331Smarkj struct ifnet *ifp; 326266490Skevlo uint8_t link_status, tmp[5]; 327258331Smarkj uint16_t val; 328258331Smarkj int locked; 329258331Smarkj 330258331Smarkj sc = device_get_softc(dev); 331258331Smarkj mii = GET_MII(sc); 332258331Smarkj locked = mtx_owned(&sc->sc_mtx); 333258331Smarkj if (!locked) 334258331Smarkj AXGE_LOCK(sc); 335258331Smarkj 336258331Smarkj ifp = uether_getifp(&sc->sc_ue); 337258331Smarkj if (mii == NULL || ifp == NULL || 338258331Smarkj (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 339258331Smarkj goto done; 340258331Smarkj 341258331Smarkj sc->sc_flags &= ~AXGE_FLAG_LINK; 342258331Smarkj if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 343258331Smarkj (IFM_ACTIVE | IFM_AVALID)) { 344258331Smarkj switch (IFM_SUBTYPE(mii->mii_media_active)) { 345258331Smarkj case IFM_10_T: 346258331Smarkj case IFM_100_TX: 347258331Smarkj case IFM_1000_T: 348258331Smarkj sc->sc_flags |= AXGE_FLAG_LINK; 349258331Smarkj break; 350258331Smarkj default: 351258331Smarkj break; 352258331Smarkj } 353258331Smarkj } 354258331Smarkj 355258331Smarkj /* Lost link, do nothing. */ 356258331Smarkj if ((sc->sc_flags & AXGE_FLAG_LINK) == 0) 357258331Smarkj goto done; 358258331Smarkj 359266738Skevlo link_status = axge_read_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PLSR); 360266490Skevlo 361258331Smarkj val = 0; 362258331Smarkj if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 363266738Skevlo val |= MSR_FD; 364258331Smarkj if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) 365266738Skevlo val |= MSR_TFC; 366258331Smarkj if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) 367266738Skevlo val |= MSR_RFC; 368258331Smarkj } 369266738Skevlo val |= MSR_RE; 370258331Smarkj switch (IFM_SUBTYPE(mii->mii_media_active)) { 371258331Smarkj case IFM_1000_T: 372266738Skevlo val |= MSR_GM | MSR_EN_125MHZ; 373266738Skevlo if (link_status & PLSR_USB_SS) 374266490Skevlo memcpy(tmp, &axge_bulk_size[0], 5); 375266738Skevlo else if (link_status & PLSR_USB_HS) 376266490Skevlo memcpy(tmp, &axge_bulk_size[1], 5); 377266490Skevlo else 378266490Skevlo memcpy(tmp, &axge_bulk_size[3], 5); 379266490Skevlo break; 380258331Smarkj case IFM_100_TX: 381266738Skevlo val |= MSR_PS; 382266738Skevlo if (link_status & (PLSR_USB_SS | PLSR_USB_HS)) 383266490Skevlo memcpy(tmp, &axge_bulk_size[2], 5); 384266490Skevlo else 385266490Skevlo memcpy(tmp, &axge_bulk_size[3], 5); 386266490Skevlo break; 387258331Smarkj case IFM_10_T: 388266490Skevlo memcpy(tmp, &axge_bulk_size[3], 5); 389258331Smarkj break; 390258331Smarkj } 391266490Skevlo /* Rx bulk configuration. */ 392266490Skevlo axge_write_mem(sc, AXGE_ACCESS_MAC, 5, AXGE_RX_BULKIN_QCTRL, tmp, 5); 393266738Skevlo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_MSR, val); 394258331Smarkjdone: 395258331Smarkj if (!locked) 396258331Smarkj AXGE_UNLOCK(sc); 397258331Smarkj} 398258331Smarkj 399258331Smarkjstatic void 400258331Smarkjaxge_chip_init(struct axge_softc *sc) 401258331Smarkj{ 402258331Smarkj /* Power up ethernet PHY. */ 403266738Skevlo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR, 0); 404266738Skevlo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR, EPPRCR_IPRL); 405258331Smarkj uether_pause(&sc->sc_ue, hz / 4); 406266738Skevlo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CLK_SELECT, 407258331Smarkj AXGE_CLK_SELECT_ACS | AXGE_CLK_SELECT_BCS); 408258331Smarkj uether_pause(&sc->sc_ue, hz / 10); 409258331Smarkj} 410258331Smarkj 411258331Smarkjstatic void 412258331Smarkjaxge_reset(struct axge_softc *sc) 413258331Smarkj{ 414258331Smarkj struct usb_config_descriptor *cd; 415258331Smarkj usb_error_t err; 416258331Smarkj 417258331Smarkj cd = usbd_get_config_descriptor(sc->sc_ue.ue_udev); 418258331Smarkj 419258331Smarkj err = usbd_req_set_config(sc->sc_ue.ue_udev, &sc->sc_mtx, 420258331Smarkj cd->bConfigurationValue); 421258331Smarkj if (err) 422258331Smarkj DPRINTF("reset failed (ignored)\n"); 423258331Smarkj 424258331Smarkj /* Wait a little while for the chip to get its brains in order. */ 425258331Smarkj uether_pause(&sc->sc_ue, hz / 100); 426258331Smarkj 427258331Smarkj /* Reinitialize controller to achieve full reset. */ 428258331Smarkj axge_chip_init(sc); 429258331Smarkj} 430258331Smarkj 431258331Smarkjstatic void 432258331Smarkjaxge_attach_post(struct usb_ether *ue) 433258331Smarkj{ 434258331Smarkj struct axge_softc *sc; 435258331Smarkj 436258331Smarkj sc = uether_getsc(ue); 437258331Smarkj sc->sc_phyno = 3; 438258331Smarkj 439258331Smarkj /* Initialize controller and get station address. */ 440258331Smarkj axge_chip_init(sc); 441266738Skevlo axge_read_mem(sc, AXGE_ACCESS_MAC, ETHER_ADDR_LEN, AXGE_NIDR, 442258331Smarkj ue->ue_eaddr, ETHER_ADDR_LEN); 443258331Smarkj} 444258331Smarkj 445258331Smarkjstatic int 446258331Smarkjaxge_attach_post_sub(struct usb_ether *ue) 447258331Smarkj{ 448258331Smarkj struct axge_softc *sc; 449258331Smarkj struct ifnet *ifp; 450258331Smarkj int error; 451258331Smarkj 452258331Smarkj sc = uether_getsc(ue); 453258331Smarkj ifp = ue->ue_ifp; 454258331Smarkj ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 455258331Smarkj ifp->if_start = uether_start; 456258331Smarkj ifp->if_ioctl = axge_ioctl; 457258331Smarkj ifp->if_init = uether_init; 458258331Smarkj IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 459258331Smarkj ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 460258331Smarkj IFQ_SET_READY(&ifp->if_snd); 461258331Smarkj 462258331Smarkj ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_TXCSUM | IFCAP_RXCSUM; 463258331Smarkj ifp->if_hwassist = AXGE_CSUM_FEATURES; 464258331Smarkj ifp->if_capenable = ifp->if_capabilities; 465258331Smarkj 466258331Smarkj mtx_lock(&Giant); 467258331Smarkj error = mii_attach(ue->ue_dev, &ue->ue_miibus, ifp, 468258331Smarkj uether_ifmedia_upd, ue->ue_methods->ue_mii_sts, 469266490Skevlo BMSR_DEFCAPMASK, sc->sc_phyno, MII_OFFSET_ANY, MIIF_DOPAUSE); 470258331Smarkj mtx_unlock(&Giant); 471258331Smarkj 472258331Smarkj return (error); 473258331Smarkj} 474258331Smarkj 475258331Smarkj/* 476258331Smarkj * Set media options. 477258331Smarkj */ 478258331Smarkjstatic int 479258331Smarkjaxge_ifmedia_upd(struct ifnet *ifp) 480258331Smarkj{ 481258331Smarkj struct axge_softc *sc; 482258331Smarkj struct mii_data *mii; 483258331Smarkj struct mii_softc *miisc; 484258331Smarkj int error; 485258331Smarkj 486258331Smarkj sc = ifp->if_softc; 487258331Smarkj mii = GET_MII(sc); 488258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 489258331Smarkj 490258331Smarkj LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 491258331Smarkj PHY_RESET(miisc); 492258331Smarkj error = mii_mediachg(mii); 493258331Smarkj 494258331Smarkj return (error); 495258331Smarkj} 496258331Smarkj 497258331Smarkj/* 498258331Smarkj * Report current media status. 499258331Smarkj */ 500258331Smarkjstatic void 501258331Smarkjaxge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 502258331Smarkj{ 503258331Smarkj struct axge_softc *sc; 504258331Smarkj struct mii_data *mii; 505258331Smarkj 506258331Smarkj sc = ifp->if_softc; 507258331Smarkj mii = GET_MII(sc); 508258331Smarkj AXGE_LOCK(sc); 509258331Smarkj mii_pollstat(mii); 510258331Smarkj ifmr->ifm_active = mii->mii_media_active; 511258331Smarkj ifmr->ifm_status = mii->mii_media_status; 512258331Smarkj AXGE_UNLOCK(sc); 513258331Smarkj} 514258331Smarkj 515258331Smarkj/* 516258331Smarkj * Probe for a AX88179 chip. 517258331Smarkj */ 518258331Smarkjstatic int 519258331Smarkjaxge_probe(device_t dev) 520258331Smarkj{ 521258331Smarkj struct usb_attach_arg *uaa; 522258331Smarkj 523258331Smarkj uaa = device_get_ivars(dev); 524258331Smarkj if (uaa->usb_mode != USB_MODE_HOST) 525258331Smarkj return (ENXIO); 526258331Smarkj if (uaa->info.bConfigIndex != AXGE_CONFIG_IDX) 527258331Smarkj return (ENXIO); 528258331Smarkj if (uaa->info.bIfaceIndex != AXGE_IFACE_IDX) 529258331Smarkj return (ENXIO); 530258331Smarkj 531258331Smarkj return (usbd_lookup_id_by_uaa(axge_devs, sizeof(axge_devs), uaa)); 532258331Smarkj} 533258331Smarkj 534258331Smarkj/* 535258331Smarkj * Attach the interface. Allocate softc structures, do ifmedia 536258331Smarkj * setup and ethernet/BPF attach. 537258331Smarkj */ 538258331Smarkjstatic int 539258331Smarkjaxge_attach(device_t dev) 540258331Smarkj{ 541258331Smarkj struct usb_attach_arg *uaa; 542258331Smarkj struct axge_softc *sc; 543258331Smarkj struct usb_ether *ue; 544258331Smarkj uint8_t iface_index; 545258331Smarkj int error; 546258331Smarkj 547258331Smarkj uaa = device_get_ivars(dev); 548258331Smarkj sc = device_get_softc(dev); 549258331Smarkj ue = &sc->sc_ue; 550258331Smarkj 551258331Smarkj device_set_usb_desc(dev); 552258331Smarkj mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 553258331Smarkj 554258331Smarkj iface_index = AXGE_IFACE_IDX; 555258331Smarkj error = usbd_transfer_setup(uaa->device, &iface_index, 556258331Smarkj sc->sc_xfer, axge_config, AXGE_N_TRANSFER, sc, &sc->sc_mtx); 557258331Smarkj if (error) { 558258331Smarkj device_printf(dev, "allocating USB transfers failed\n"); 559258331Smarkj goto detach; 560258331Smarkj } 561258331Smarkj 562258331Smarkj ue->ue_sc = sc; 563258331Smarkj ue->ue_dev = dev; 564258331Smarkj ue->ue_udev = uaa->device; 565258331Smarkj ue->ue_mtx = &sc->sc_mtx; 566258331Smarkj ue->ue_methods = &axge_ue_methods; 567258331Smarkj 568258331Smarkj error = uether_ifattach(ue); 569258331Smarkj if (error) { 570258331Smarkj device_printf(dev, "could not attach interface\n"); 571258331Smarkj goto detach; 572258331Smarkj } 573258331Smarkj return (0); /* success */ 574258331Smarkj 575258331Smarkjdetach: 576258331Smarkj axge_detach(dev); 577258331Smarkj return (ENXIO); /* failure */ 578258331Smarkj} 579258331Smarkj 580258331Smarkjstatic int 581258331Smarkjaxge_detach(device_t dev) 582258331Smarkj{ 583258331Smarkj struct axge_softc *sc; 584258331Smarkj struct usb_ether *ue; 585258331Smarkj 586258331Smarkj sc = device_get_softc(dev); 587258331Smarkj ue = &sc->sc_ue; 588258331Smarkj usbd_transfer_unsetup(sc->sc_xfer, AXGE_N_TRANSFER); 589258331Smarkj uether_ifdetach(ue); 590258331Smarkj mtx_destroy(&sc->sc_mtx); 591258331Smarkj 592258331Smarkj return (0); 593258331Smarkj} 594258331Smarkj 595258331Smarkjstatic void 596258331Smarkjaxge_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 597258331Smarkj{ 598258331Smarkj struct axge_softc *sc; 599258331Smarkj struct usb_ether *ue; 600258331Smarkj struct usb_page_cache *pc; 601258331Smarkj int actlen; 602258331Smarkj 603258331Smarkj sc = usbd_xfer_softc(xfer); 604258331Smarkj ue = &sc->sc_ue; 605258331Smarkj usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 606258331Smarkj 607258331Smarkj switch (USB_GET_STATE(xfer)) { 608258331Smarkj case USB_ST_TRANSFERRED: 609258331Smarkj pc = usbd_xfer_get_frame(xfer, 0); 610268209Shselasky axge_rx_frame(ue, pc, actlen); 611258331Smarkj 612258331Smarkj /* FALLTHROUGH */ 613258331Smarkj case USB_ST_SETUP: 614258331Smarkjtr_setup: 615258331Smarkj usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 616258331Smarkj usbd_transfer_submit(xfer); 617258331Smarkj uether_rxflush(ue); 618268582Shselasky break; 619258331Smarkj 620258331Smarkj default: 621258331Smarkj if (error != USB_ERR_CANCELLED) { 622258331Smarkj usbd_xfer_set_stall(xfer); 623258331Smarkj goto tr_setup; 624258331Smarkj } 625268582Shselasky break; 626258331Smarkj } 627258331Smarkj} 628258331Smarkj 629258331Smarkjstatic void 630258331Smarkjaxge_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 631258331Smarkj{ 632258331Smarkj struct axge_softc *sc; 633258331Smarkj struct ifnet *ifp; 634258331Smarkj struct usb_page_cache *pc; 635258331Smarkj struct mbuf *m; 636258331Smarkj uint32_t txhdr; 637266738Skevlo int nframes, pos; 638258331Smarkj 639258331Smarkj sc = usbd_xfer_softc(xfer); 640258331Smarkj ifp = uether_getifp(&sc->sc_ue); 641258331Smarkj 642258331Smarkj switch (USB_GET_STATE(xfer)) { 643258331Smarkj case USB_ST_TRANSFERRED: 644258331Smarkj ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 645258331Smarkj /* FALLTHROUGH */ 646258331Smarkj case USB_ST_SETUP: 647258331Smarkjtr_setup: 648258331Smarkj if ((sc->sc_flags & AXGE_FLAG_LINK) == 0 || 649258331Smarkj (ifp->if_drv_flags & IFF_DRV_OACTIVE) != 0) { 650258331Smarkj /* 651258331Smarkj * Don't send anything if there is no link or 652258331Smarkj * controller is busy. 653258331Smarkj */ 654258331Smarkj return; 655258331Smarkj } 656258331Smarkj 657258331Smarkj for (nframes = 0; nframes < 16 && 658258331Smarkj !IFQ_DRV_IS_EMPTY(&ifp->if_snd); nframes++) { 659258331Smarkj IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 660258331Smarkj if (m == NULL) 661258331Smarkj break; 662258331Smarkj usbd_xfer_set_frame_offset(xfer, nframes * MCLBYTES, 663258331Smarkj nframes); 664266738Skevlo pos = 0; 665258331Smarkj pc = usbd_xfer_get_frame(xfer, nframes); 666266738Skevlo txhdr = htole32(m->m_pkthdr.len); 667266738Skevlo usbd_copy_in(pc, 0, &txhdr, sizeof(txhdr)); 668266738Skevlo txhdr = 0; 669258331Smarkj txhdr = htole32(txhdr); 670266738Skevlo usbd_copy_in(pc, 4, &txhdr, sizeof(txhdr)); 671266738Skevlo pos += 8; 672266738Skevlo usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len); 673266738Skevlo pos += m->m_pkthdr.len; 674266738Skevlo if ((pos % usbd_xfer_max_framelen(xfer)) == 0) 675266738Skevlo txhdr |= 0x80008000; 676258331Smarkj 677258331Smarkj /* 678258331Smarkj * XXX 679258331Smarkj * Update TX packet counter here. This is not 680258331Smarkj * correct way but it seems that there is no way 681258331Smarkj * to know how many packets are sent at the end 682258331Smarkj * of transfer because controller combines 683258331Smarkj * multiple writes into single one if there is 684258331Smarkj * room in TX buffer of controller. 685258331Smarkj */ 686271832Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 687258331Smarkj 688258331Smarkj /* 689258331Smarkj * if there's a BPF listener, bounce a copy 690258331Smarkj * of this frame to him: 691258331Smarkj */ 692258331Smarkj BPF_MTAP(ifp, m); 693258331Smarkj 694258331Smarkj m_freem(m); 695258331Smarkj 696258331Smarkj /* Set frame length. */ 697266738Skevlo usbd_xfer_set_frame_len(xfer, nframes, pos); 698258331Smarkj } 699258331Smarkj if (nframes != 0) { 700258331Smarkj usbd_xfer_set_frames(xfer, nframes); 701258331Smarkj usbd_transfer_submit(xfer); 702258331Smarkj ifp->if_drv_flags |= IFF_DRV_OACTIVE; 703258331Smarkj } 704258331Smarkj return; 705258331Smarkj /* NOTREACHED */ 706258331Smarkj default: 707271832Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 708258331Smarkj ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 709258331Smarkj 710258331Smarkj if (error != USB_ERR_CANCELLED) { 711258331Smarkj usbd_xfer_set_stall(xfer); 712258331Smarkj goto tr_setup; 713258331Smarkj } 714258331Smarkj return; 715258331Smarkj 716258331Smarkj } 717258331Smarkj} 718258331Smarkj 719258331Smarkjstatic void 720258331Smarkjaxge_tick(struct usb_ether *ue) 721258331Smarkj{ 722258331Smarkj struct axge_softc *sc; 723258331Smarkj struct mii_data *mii; 724258331Smarkj 725258331Smarkj sc = uether_getsc(ue); 726258331Smarkj mii = GET_MII(sc); 727258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 728258331Smarkj 729258331Smarkj mii_tick(mii); 730258331Smarkj if ((sc->sc_flags & AXGE_FLAG_LINK) == 0) { 731258331Smarkj axge_miibus_statchg(ue->ue_dev); 732258331Smarkj if ((sc->sc_flags & AXGE_FLAG_LINK) != 0) 733258331Smarkj axge_start(ue); 734258331Smarkj } 735258331Smarkj} 736258331Smarkj 737258331Smarkjstatic void 738258331Smarkjaxge_setmulti(struct usb_ether *ue) 739258331Smarkj{ 740258331Smarkj struct axge_softc *sc; 741258331Smarkj struct ifnet *ifp; 742258331Smarkj struct ifmultiaddr *ifma; 743258331Smarkj uint32_t h; 744258331Smarkj uint16_t rxmode; 745258331Smarkj uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 746258331Smarkj 747258331Smarkj sc = uether_getsc(ue); 748258331Smarkj ifp = uether_getifp(ue); 749258331Smarkj h = 0; 750258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 751258331Smarkj 752266738Skevlo rxmode = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR); 753258331Smarkj if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { 754266738Skevlo rxmode |= RCR_AMALL; 755266738Skevlo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); 756258331Smarkj return; 757258331Smarkj } 758266738Skevlo rxmode &= ~RCR_AMALL; 759258331Smarkj 760258331Smarkj if_maddr_rlock(ifp); 761258331Smarkj TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 762258331Smarkj if (ifma->ifma_addr->sa_family != AF_LINK) 763258331Smarkj continue; 764258331Smarkj h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 765258331Smarkj ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 766258331Smarkj hashtbl[h / 8] |= 1 << (h % 8); 767258331Smarkj } 768258331Smarkj if_maddr_runlock(ifp); 769258331Smarkj 770266738Skevlo axge_write_mem(sc, AXGE_ACCESS_MAC, 8, AXGE_MFA, (void *)&hashtbl, 8); 771266738Skevlo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); 772258331Smarkj} 773258331Smarkj 774258331Smarkjstatic void 775258331Smarkjaxge_setpromisc(struct usb_ether *ue) 776258331Smarkj{ 777258331Smarkj struct axge_softc *sc; 778258331Smarkj struct ifnet *ifp; 779258331Smarkj uint16_t rxmode; 780258331Smarkj 781258331Smarkj sc = uether_getsc(ue); 782258331Smarkj ifp = uether_getifp(ue); 783266738Skevlo rxmode = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR); 784258331Smarkj 785258331Smarkj if (ifp->if_flags & IFF_PROMISC) 786266738Skevlo rxmode |= RCR_PRO; 787258331Smarkj else 788266738Skevlo rxmode &= ~RCR_PRO; 789258331Smarkj 790266738Skevlo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); 791258331Smarkj axge_setmulti(ue); 792258331Smarkj} 793258331Smarkj 794258331Smarkjstatic void 795258331Smarkjaxge_start(struct usb_ether *ue) 796258331Smarkj{ 797258331Smarkj struct axge_softc *sc; 798258331Smarkj 799258331Smarkj sc = uether_getsc(ue); 800258331Smarkj /* 801258331Smarkj * Start the USB transfers, if not already started. 802258331Smarkj */ 803258331Smarkj usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_RD]); 804258331Smarkj usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_WR]); 805258331Smarkj} 806258331Smarkj 807258331Smarkjstatic void 808258331Smarkjaxge_init(struct usb_ether *ue) 809258331Smarkj{ 810258331Smarkj struct axge_softc *sc; 811258331Smarkj struct ifnet *ifp; 812258331Smarkj uint16_t rxmode; 813258331Smarkj 814258331Smarkj sc = uether_getsc(ue); 815258331Smarkj ifp = uether_getifp(ue); 816258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 817258331Smarkj 818258331Smarkj if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 819258331Smarkj return; 820258331Smarkj 821258331Smarkj /* 822258331Smarkj * Cancel pending I/O and free all RX/TX buffers. 823258331Smarkj */ 824258331Smarkj axge_stop(ue); 825258331Smarkj 826258331Smarkj axge_reset(sc); 827258331Smarkj 828258331Smarkj /* Set MAC address. */ 829266738Skevlo axge_write_mem(sc, AXGE_ACCESS_MAC, ETHER_ADDR_LEN, AXGE_NIDR, 830258331Smarkj IF_LLADDR(ifp), ETHER_ADDR_LEN); 831258331Smarkj 832266738Skevlo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PWLLR, 0x34); 833266738Skevlo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PWLHR, 0x52); 834258331Smarkj 835258331Smarkj /* Configure TX/RX checksum offloading. */ 836258331Smarkj axge_csum_cfg(ue); 837258331Smarkj 838258331Smarkj /* Configure RX settings. */ 839266738Skevlo rxmode = (RCR_AM | RCR_SO | RCR_DROP_CRCE); 840266738Skevlo if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 841266738Skevlo rxmode |= RCR_IPE; 842258331Smarkj 843258331Smarkj /* If we want promiscuous mode, set the allframes bit. */ 844258331Smarkj if (ifp->if_flags & IFF_PROMISC) 845266738Skevlo rxmode |= RCR_PRO; 846258331Smarkj 847258331Smarkj if (ifp->if_flags & IFF_BROADCAST) 848266738Skevlo rxmode |= RCR_AB; 849258331Smarkj 850266738Skevlo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); 851258331Smarkj 852266738Skevlo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_MMSR, 853266738Skevlo MMSR_PME_TYPE | MMSR_PME_POL | MMSR_RWMP); 854266738Skevlo 855258331Smarkj /* Load the multicast filter. */ 856258331Smarkj axge_setmulti(ue); 857258331Smarkj 858258331Smarkj usbd_xfer_set_stall(sc->sc_xfer[AXGE_BULK_DT_WR]); 859258331Smarkj 860258331Smarkj ifp->if_drv_flags |= IFF_DRV_RUNNING; 861258331Smarkj /* Switch to selected media. */ 862258331Smarkj axge_ifmedia_upd(ifp); 863258331Smarkj} 864258331Smarkj 865258331Smarkjstatic void 866258331Smarkjaxge_stop(struct usb_ether *ue) 867258331Smarkj{ 868258331Smarkj struct axge_softc *sc; 869258331Smarkj struct ifnet *ifp; 870258331Smarkj 871258331Smarkj sc = uether_getsc(ue); 872258331Smarkj ifp = uether_getifp(ue); 873258331Smarkj 874258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 875258331Smarkj 876258331Smarkj ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 877258331Smarkj sc->sc_flags &= ~AXGE_FLAG_LINK; 878258331Smarkj 879258331Smarkj /* 880258331Smarkj * Stop all the transfers, if not already stopped: 881258331Smarkj */ 882258331Smarkj usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_WR]); 883258331Smarkj usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_RD]); 884258331Smarkj} 885258331Smarkj 886258331Smarkjstatic int 887258331Smarkjaxge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 888258331Smarkj{ 889258331Smarkj struct usb_ether *ue; 890258331Smarkj struct axge_softc *sc; 891258331Smarkj struct ifreq *ifr; 892258331Smarkj int error, mask, reinit; 893258331Smarkj 894258331Smarkj ue = ifp->if_softc; 895258331Smarkj sc = uether_getsc(ue); 896258331Smarkj ifr = (struct ifreq *)data; 897258331Smarkj error = 0; 898258331Smarkj reinit = 0; 899258331Smarkj if (cmd == SIOCSIFCAP) { 900258331Smarkj AXGE_LOCK(sc); 901258331Smarkj mask = ifr->ifr_reqcap ^ ifp->if_capenable; 902258331Smarkj if ((mask & IFCAP_TXCSUM) != 0 && 903258331Smarkj (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { 904258331Smarkj ifp->if_capenable ^= IFCAP_TXCSUM; 905258331Smarkj if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 906258331Smarkj ifp->if_hwassist |= AXGE_CSUM_FEATURES; 907258331Smarkj else 908258331Smarkj ifp->if_hwassist &= ~AXGE_CSUM_FEATURES; 909258331Smarkj reinit++; 910258331Smarkj } 911258331Smarkj if ((mask & IFCAP_RXCSUM) != 0 && 912258331Smarkj (ifp->if_capabilities & IFCAP_RXCSUM) != 0) { 913258331Smarkj ifp->if_capenable ^= IFCAP_RXCSUM; 914258331Smarkj reinit++; 915258331Smarkj } 916258331Smarkj if (reinit > 0 && ifp->if_drv_flags & IFF_DRV_RUNNING) 917258331Smarkj ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 918258331Smarkj else 919258331Smarkj reinit = 0; 920258331Smarkj AXGE_UNLOCK(sc); 921258331Smarkj if (reinit > 0) 922258331Smarkj uether_init(ue); 923258331Smarkj } else 924258331Smarkj error = uether_ioctl(ifp, cmd, data); 925258331Smarkj 926258331Smarkj return (error); 927258331Smarkj} 928258331Smarkj 929268209Shselaskystatic void 930258331Smarkjaxge_rx_frame(struct usb_ether *ue, struct usb_page_cache *pc, int actlen) 931258331Smarkj{ 932268209Shselasky uint32_t pos; 933268209Shselasky uint32_t pkt_cnt; 934267955Shselasky uint32_t rxhdr; 935267955Shselasky uint32_t pkt_hdr; 936267955Shselasky uint32_t hdr_off; 937267955Shselasky uint32_t pktlen; 938258331Smarkj 939267955Shselasky /* verify we have enough data */ 940267955Shselasky if (actlen < (int)sizeof(rxhdr)) 941268209Shselasky return; 942267955Shselasky 943258331Smarkj pos = 0; 944258331Smarkj 945258331Smarkj usbd_copy_out(pc, actlen - sizeof(rxhdr), &rxhdr, sizeof(rxhdr)); 946258331Smarkj rxhdr = le32toh(rxhdr); 947258331Smarkj 948258331Smarkj pkt_cnt = (uint16_t)rxhdr; 949258331Smarkj hdr_off = (uint16_t)(rxhdr >> 16); 950258331Smarkj 951268209Shselasky while (pkt_cnt--) { 952267955Shselasky /* verify the header offset */ 953267955Shselasky if ((int)(hdr_off + sizeof(pkt_hdr)) > actlen) { 954268209Shselasky DPRINTF("End of packet headers\n"); 955258331Smarkj break; 956258331Smarkj } 957268209Shselasky if ((int)pos >= actlen) { 958268209Shselasky DPRINTF("Data position reached end\n"); 959268209Shselasky break; 960268209Shselasky } 961267955Shselasky usbd_copy_out(pc, hdr_off, &pkt_hdr, sizeof(pkt_hdr)); 962267955Shselasky 963266738Skevlo pkt_hdr = le32toh(pkt_hdr); 964266738Skevlo pktlen = (pkt_hdr >> 16) & 0x1fff; 965268209Shselasky if (pkt_hdr & (AXGE_RXHDR_CRC_ERR | AXGE_RXHDR_DROP_ERR)) { 966268209Shselasky DPRINTF("Dropped a packet\n"); 967271832Sglebius if_inc_counter(ue->ue_ifp, IFCOUNTER_IERRORS, 1); 968267955Shselasky } 969268582Shselasky if (pktlen >= 6 && (int)(pos + pktlen) <= actlen) { 970268582Shselasky axge_rxeof(ue, pc, pos + 2, pktlen - 6, pkt_hdr); 971268209Shselasky } else { 972268209Shselasky DPRINTF("Invalid packet pos=%d len=%d\n", 973268209Shselasky (int)pos, (int)pktlen); 974268209Shselasky } 975267955Shselasky pos += (pktlen + 7) & ~7; 976267955Shselasky hdr_off += sizeof(pkt_hdr); 977258331Smarkj } 978258331Smarkj} 979258331Smarkj 980268209Shselaskystatic void 981258331Smarkjaxge_rxeof(struct usb_ether *ue, struct usb_page_cache *pc, 982266738Skevlo unsigned int offset, unsigned int len, uint32_t pkt_hdr) 983258331Smarkj{ 984258331Smarkj struct ifnet *ifp; 985258331Smarkj struct mbuf *m; 986258331Smarkj 987258331Smarkj ifp = ue->ue_ifp; 988258331Smarkj if (len < ETHER_HDR_LEN || len > MCLBYTES - ETHER_ALIGN) { 989271832Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 990268209Shselasky return; 991258331Smarkj } 992258331Smarkj 993258331Smarkj m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 994258331Smarkj if (m == NULL) { 995271832Sglebius if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 996268209Shselasky return; 997258331Smarkj } 998268209Shselasky m->m_pkthdr.rcvif = ifp; 999268209Shselasky m->m_len = m->m_pkthdr.len = len + ETHER_ALIGN; 1000258331Smarkj m_adj(m, ETHER_ALIGN); 1001258331Smarkj 1002258331Smarkj usbd_copy_out(pc, offset, mtod(m, uint8_t *), len); 1003258331Smarkj 1004271832Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 1005268582Shselasky 1006266738Skevlo if ((pkt_hdr & (AXGE_RXHDR_L4CSUM_ERR | AXGE_RXHDR_L3CSUM_ERR)) == 0) { 1007266738Skevlo if ((pkt_hdr & AXGE_RXHDR_L4_TYPE_MASK) == 1008266738Skevlo AXGE_RXHDR_L4_TYPE_TCP || 1009266738Skevlo (pkt_hdr & AXGE_RXHDR_L4_TYPE_MASK) == 1010266738Skevlo AXGE_RXHDR_L4_TYPE_UDP) { 1011266738Skevlo m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | 1012268209Shselasky CSUM_PSEUDO_HDR | CSUM_IP_CHECKED | CSUM_IP_VALID; 1013266738Skevlo m->m_pkthdr.csum_data = 0xffff; 1014258331Smarkj } 1015258331Smarkj } 1016268582Shselasky 1017258331Smarkj _IF_ENQUEUE(&ue->ue_rxq, m); 1018258331Smarkj} 1019258331Smarkj 1020258331Smarkjstatic void 1021258331Smarkjaxge_csum_cfg(struct usb_ether *ue) 1022258331Smarkj{ 1023258331Smarkj struct axge_softc *sc; 1024258331Smarkj struct ifnet *ifp; 1025258331Smarkj uint8_t csum; 1026258331Smarkj 1027258331Smarkj sc = uether_getsc(ue); 1028258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 1029258331Smarkj ifp = uether_getifp(ue); 1030258331Smarkj 1031258331Smarkj csum = 0; 1032258331Smarkj if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 1033266738Skevlo csum |= CTCR_IP | CTCR_TCP | CTCR_UDP; 1034266738Skevlo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CTCR, csum); 1035258331Smarkj 1036258331Smarkj csum = 0; 1037258331Smarkj if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 1038266738Skevlo csum |= CRCR_IP | CRCR_TCP | CRCR_UDP; 1039266738Skevlo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CRCR, csum); 1040258331Smarkj} 1041