if_axge.c revision 266490
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: head/sys/dev/usb/net/if_axge.c 266490 2014-05-21 08:09:44Z kevlo $"); 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), 69258331Smarkj /* AXGE_DEV(SITECOMEU, LN032), */ 70258331Smarkj#undef AXGE_DEV 71258331Smarkj}; 72258331Smarkj 73258331Smarkjstatic const struct { 74266490Skevlo uint8_t ctrl; 75266490Skevlo uint8_t timer_l; 76266490Skevlo uint8_t timer_h; 77266490Skevlo uint8_t size; 78266490Skevlo uint8_t ifg; 79266490Skevlo} axge_bulk_size[] = { 80266490Skevlo { 7, 0x4f, 0x00, 0x12, 0xff }, 81266490Skevlo { 7, 0x20, 0x03, 0x16, 0xff }, 82266490Skevlo { 7, 0xae, 0x07, 0x18, 0xff }, 83266490Skevlo { 7, 0xcc, 0x4c, 0x18, 0x08 } 84258331Smarkj}; 85258331Smarkj 86258331Smarkj/* prototypes */ 87258331Smarkj 88258331Smarkjstatic device_probe_t axge_probe; 89258331Smarkjstatic device_attach_t axge_attach; 90258331Smarkjstatic device_detach_t axge_detach; 91258331Smarkj 92258331Smarkjstatic usb_callback_t axge_bulk_read_callback; 93258331Smarkjstatic usb_callback_t axge_bulk_write_callback; 94258331Smarkj 95258331Smarkjstatic miibus_readreg_t axge_miibus_readreg; 96258331Smarkjstatic miibus_writereg_t axge_miibus_writereg; 97258331Smarkjstatic miibus_statchg_t axge_miibus_statchg; 98258331Smarkj 99258331Smarkjstatic uether_fn_t axge_attach_post; 100258331Smarkjstatic uether_fn_t axge_init; 101258331Smarkjstatic uether_fn_t axge_stop; 102258331Smarkjstatic uether_fn_t axge_start; 103258331Smarkjstatic uether_fn_t axge_tick; 104258331Smarkjstatic uether_fn_t axge_setmulti; 105258331Smarkjstatic uether_fn_t axge_setpromisc; 106258331Smarkj 107258331Smarkjstatic int axge_read_mem(struct axge_softc *, uint8_t, uint16_t, 108258331Smarkj uint16_t, void *, int); 109258331Smarkjstatic void axge_write_mem(struct axge_softc *, uint8_t, uint16_t, 110258331Smarkj uint16_t, void *, int); 111266490Skevlostatic uint8_t axge_read_cmd_1(struct axge_softc *, uint8_t, uint16_t, 112266490Skevlo uint16_t); 113258331Smarkjstatic uint16_t axge_read_cmd_2(struct axge_softc *, uint8_t, uint16_t, 114258331Smarkj uint16_t); 115258331Smarkjstatic void axge_write_cmd_1(struct axge_softc *, uint8_t, uint16_t, 116258331Smarkj uint16_t, uint8_t); 117258331Smarkjstatic void axge_write_cmd_2(struct axge_softc *, uint8_t, uint16_t, 118258331Smarkj uint16_t, uint16_t); 119258331Smarkjstatic void axge_chip_init(struct axge_softc *); 120258331Smarkjstatic void axge_reset(struct axge_softc *); 121258331Smarkj 122258331Smarkjstatic int axge_attach_post_sub(struct usb_ether *); 123258331Smarkjstatic int axge_ifmedia_upd(struct ifnet *); 124258331Smarkjstatic void axge_ifmedia_sts(struct ifnet *, struct ifmediareq *); 125258331Smarkjstatic int axge_ioctl(struct ifnet *, u_long, caddr_t); 126258331Smarkjstatic int axge_rx_frame(struct usb_ether *, struct usb_page_cache *, int); 127258331Smarkjstatic int axge_rxeof(struct usb_ether *, struct usb_page_cache *, 128258331Smarkj unsigned int, unsigned int, struct axge_csum_hdr *); 129258331Smarkjstatic void axge_csum_cfg(struct usb_ether *); 130258331Smarkj 131258331Smarkj#define AXGE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 132258331Smarkj 133258331Smarkj#ifdef USB_DEBUG 134258331Smarkjstatic int axge_debug = 0; 135258331Smarkj 136258331Smarkjstatic SYSCTL_NODE(_hw_usb, OID_AUTO, axge, CTLFLAG_RW, 0, "USB axge"); 137258331SmarkjSYSCTL_INT(_hw_usb_axge, OID_AUTO, debug, CTLFLAG_RW, &axge_debug, 0, 138258331Smarkj "Debug level"); 139258331Smarkj#endif 140258331Smarkj 141258331Smarkjstatic const struct usb_config axge_config[AXGE_N_TRANSFER] = { 142258331Smarkj [AXGE_BULK_DT_WR] = { 143258331Smarkj .type = UE_BULK, 144258331Smarkj .endpoint = UE_ADDR_ANY, 145258331Smarkj .direction = UE_DIR_OUT, 146258331Smarkj .frames = 16, 147258331Smarkj .bufsize = 16 * (MCLBYTES + 16), 148258331Smarkj .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 149258331Smarkj .callback = axge_bulk_write_callback, 150258331Smarkj .timeout = 10000, /* 10 seconds */ 151258331Smarkj }, 152258331Smarkj [AXGE_BULK_DT_RD] = { 153258331Smarkj .type = UE_BULK, 154258331Smarkj .endpoint = UE_ADDR_ANY, 155258331Smarkj .direction = UE_DIR_IN, 156258331Smarkj .bufsize = 20480, 157258331Smarkj .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 158258331Smarkj .callback = axge_bulk_read_callback, 159258331Smarkj .timeout = 0, /* no timeout */ 160258331Smarkj }, 161258331Smarkj}; 162258331Smarkj 163258331Smarkjstatic device_method_t axge_methods[] = { 164258331Smarkj /* Device interface. */ 165258331Smarkj DEVMETHOD(device_probe, axge_probe), 166258331Smarkj DEVMETHOD(device_attach, axge_attach), 167258331Smarkj DEVMETHOD(device_detach, axge_detach), 168258331Smarkj 169258331Smarkj /* MII interface. */ 170258331Smarkj DEVMETHOD(miibus_readreg, axge_miibus_readreg), 171258331Smarkj DEVMETHOD(miibus_writereg, axge_miibus_writereg), 172258331Smarkj DEVMETHOD(miibus_statchg, axge_miibus_statchg), 173258331Smarkj 174258331Smarkj DEVMETHOD_END 175258331Smarkj}; 176258331Smarkj 177258331Smarkjstatic driver_t axge_driver = { 178258331Smarkj .name = "axge", 179258331Smarkj .methods = axge_methods, 180258331Smarkj .size = sizeof(struct axge_softc), 181258331Smarkj}; 182258331Smarkj 183258331Smarkjstatic devclass_t axge_devclass; 184258331Smarkj 185258331SmarkjDRIVER_MODULE(axge, uhub, axge_driver, axge_devclass, NULL, NULL); 186258331SmarkjDRIVER_MODULE(miibus, axge, miibus_driver, miibus_devclass, NULL, NULL); 187258331SmarkjMODULE_DEPEND(axge, uether, 1, 1, 1); 188258331SmarkjMODULE_DEPEND(axge, usb, 1, 1, 1); 189258331SmarkjMODULE_DEPEND(axge, ether, 1, 1, 1); 190258331SmarkjMODULE_DEPEND(axge, miibus, 1, 1, 1); 191258331SmarkjMODULE_VERSION(axge, 1); 192258331Smarkj 193258331Smarkjstatic const struct usb_ether_methods axge_ue_methods = { 194258331Smarkj .ue_attach_post = axge_attach_post, 195258331Smarkj .ue_attach_post_sub = axge_attach_post_sub, 196258331Smarkj .ue_start = axge_start, 197258331Smarkj .ue_init = axge_init, 198258331Smarkj .ue_stop = axge_stop, 199258331Smarkj .ue_tick = axge_tick, 200258331Smarkj .ue_setmulti = axge_setmulti, 201258331Smarkj .ue_setpromisc = axge_setpromisc, 202258331Smarkj .ue_mii_upd = axge_ifmedia_upd, 203258331Smarkj .ue_mii_sts = axge_ifmedia_sts, 204258331Smarkj}; 205258331Smarkj 206258331Smarkjstatic int 207258331Smarkjaxge_read_mem(struct axge_softc *sc, uint8_t cmd, uint16_t index, 208258331Smarkj uint16_t val, void *buf, int len) 209258331Smarkj{ 210258331Smarkj struct usb_device_request req; 211258331Smarkj 212258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 213258331Smarkj 214258331Smarkj req.bmRequestType = UT_READ_VENDOR_DEVICE; 215258331Smarkj req.bRequest = cmd; 216258331Smarkj USETW(req.wValue, val); 217258331Smarkj USETW(req.wIndex, index); 218258331Smarkj USETW(req.wLength, len); 219258331Smarkj 220258331Smarkj return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 221258331Smarkj} 222258331Smarkj 223258331Smarkjstatic void 224258331Smarkjaxge_write_mem(struct axge_softc *sc, uint8_t cmd, uint16_t index, 225258331Smarkj uint16_t val, void *buf, int len) 226258331Smarkj{ 227258331Smarkj struct usb_device_request req; 228258331Smarkj 229258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 230258331Smarkj 231258331Smarkj req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 232258331Smarkj req.bRequest = cmd; 233258331Smarkj USETW(req.wValue, val); 234258331Smarkj USETW(req.wIndex, index); 235258331Smarkj USETW(req.wLength, len); 236258331Smarkj 237258331Smarkj if (uether_do_request(&sc->sc_ue, &req, buf, 1000)) { 238258331Smarkj /* Error ignored. */ 239258331Smarkj } 240258331Smarkj} 241258331Smarkj 242266490Skevlostatic uint8_t 243266490Skevloaxge_read_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t index, 244266490Skevlo uint16_t reg) 245266490Skevlo{ 246266490Skevlo uint8_t val; 247266490Skevlo 248266490Skevlo axge_read_mem(sc, cmd, index, reg, &val, 1); 249266490Skevlo return (val); 250266490Skevlo} 251266490Skevlo 252258331Smarkjstatic uint16_t 253258331Smarkjaxge_read_cmd_2(struct axge_softc *sc, uint8_t cmd, uint16_t index, 254258331Smarkj uint16_t reg) 255258331Smarkj{ 256258331Smarkj uint8_t val[2]; 257258331Smarkj 258258331Smarkj axge_read_mem(sc, cmd, index, reg, &val, 2); 259258331Smarkj return (UGETW(val)); 260258331Smarkj} 261258331Smarkj 262258331Smarkjstatic void 263258331Smarkjaxge_write_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t index, 264258331Smarkj uint16_t reg, uint8_t val) 265258331Smarkj{ 266258331Smarkj axge_write_mem(sc, cmd, index, 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 359266490Skevlo link_status = axge_read_cmd_1(sc, AXGE_ACCESS_MAC, 1, AXGE_LINK_STATUS); 360266490Skevlo 361258331Smarkj val = 0; 362258331Smarkj if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 363258331Smarkj val |= AXGE_MEDIUM_FULL_DUPLEX; 364258331Smarkj if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) 365258331Smarkj val |= AXGE_MEDIUM_TXFLOW_CTRLEN; 366258331Smarkj if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) 367258331Smarkj val |= AXGE_MEDIUM_RXFLOW_CTRLEN; 368258331Smarkj } 369266490Skevlo val |= AXGE_MEDIUM_RECEIVE_EN; 370258331Smarkj switch (IFM_SUBTYPE(mii->mii_media_active)) { 371258331Smarkj case IFM_1000_T: 372266490Skevlo val |= AXGE_MEDIUM_GIGAMODE | AXGE_MEDIUM_EN_125MHZ; 373266490Skevlo if (link_status & AXGE_LINK_STATUS_USB_SS) 374266490Skevlo memcpy(tmp, &axge_bulk_size[0], 5); 375266490Skevlo else if (link_status & AXGE_LINK_STATUS_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: 381258331Smarkj val |= AXGE_MEDIUM_PS; 382266490Skevlo if (link_status & 383266490Skevlo (AXGE_LINK_STATUS_USB_SS | AXGE_LINK_STATUS_USB_HS)) 384266490Skevlo memcpy(tmp, &axge_bulk_size[2], 5); 385266490Skevlo else 386266490Skevlo memcpy(tmp, &axge_bulk_size[3], 5); 387266490Skevlo break; 388258331Smarkj case IFM_10_T: 389266490Skevlo memcpy(tmp, &axge_bulk_size[3], 5); 390258331Smarkj break; 391258331Smarkj } 392266490Skevlo /* Rx bulk configuration. */ 393266490Skevlo axge_write_mem(sc, AXGE_ACCESS_MAC, 5, AXGE_RX_BULKIN_QCTRL, tmp, 5); 394258331Smarkj axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_MEDIUM_STATUS_MODE, val); 395258331Smarkjdone: 396258331Smarkj if (!locked) 397258331Smarkj AXGE_UNLOCK(sc); 398258331Smarkj} 399258331Smarkj 400258331Smarkjstatic void 401258331Smarkjaxge_chip_init(struct axge_softc *sc) 402258331Smarkj{ 403258331Smarkj /* Power up ethernet PHY. */ 404258331Smarkj axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_PHYPWR_RSTCTL, 0); 405258331Smarkj axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_PHYPWR_RSTCTL, 406258331Smarkj AXGE_PHYPWR_RSTCTL_IPRL); 407258331Smarkj uether_pause(&sc->sc_ue, hz / 4); 408258331Smarkj axge_write_cmd_1(sc, AXGE_ACCESS_MAC, 1, AXGE_CLK_SELECT, 409258331Smarkj AXGE_CLK_SELECT_ACS | AXGE_CLK_SELECT_BCS); 410258331Smarkj uether_pause(&sc->sc_ue, hz / 10); 411258331Smarkj} 412258331Smarkj 413258331Smarkjstatic void 414258331Smarkjaxge_reset(struct axge_softc *sc) 415258331Smarkj{ 416258331Smarkj struct usb_config_descriptor *cd; 417258331Smarkj usb_error_t err; 418258331Smarkj 419258331Smarkj cd = usbd_get_config_descriptor(sc->sc_ue.ue_udev); 420258331Smarkj 421258331Smarkj err = usbd_req_set_config(sc->sc_ue.ue_udev, &sc->sc_mtx, 422258331Smarkj cd->bConfigurationValue); 423258331Smarkj if (err) 424258331Smarkj DPRINTF("reset failed (ignored)\n"); 425258331Smarkj 426258331Smarkj /* Wait a little while for the chip to get its brains in order. */ 427258331Smarkj uether_pause(&sc->sc_ue, hz / 100); 428258331Smarkj 429258331Smarkj /* Reinitialize controller to achieve full reset. */ 430258331Smarkj axge_chip_init(sc); 431258331Smarkj} 432258331Smarkj 433258331Smarkjstatic void 434258331Smarkjaxge_attach_post(struct usb_ether *ue) 435258331Smarkj{ 436258331Smarkj struct axge_softc *sc; 437258331Smarkj 438258331Smarkj sc = uether_getsc(ue); 439258331Smarkj sc->sc_phyno = 3; 440258331Smarkj 441258331Smarkj /* Initialize controller and get station address. */ 442258331Smarkj axge_chip_init(sc); 443258331Smarkj axge_read_mem(sc, AXGE_ACCESS_MAC, ETHER_ADDR_LEN, AXGE_NODE_ID, 444258331Smarkj ue->ue_eaddr, ETHER_ADDR_LEN); 445258331Smarkj} 446258331Smarkj 447258331Smarkjstatic int 448258331Smarkjaxge_attach_post_sub(struct usb_ether *ue) 449258331Smarkj{ 450258331Smarkj struct axge_softc *sc; 451258331Smarkj struct ifnet *ifp; 452258331Smarkj int error; 453258331Smarkj 454258331Smarkj sc = uether_getsc(ue); 455258331Smarkj ifp = ue->ue_ifp; 456258331Smarkj ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 457258331Smarkj ifp->if_start = uether_start; 458258331Smarkj ifp->if_ioctl = axge_ioctl; 459258331Smarkj ifp->if_init = uether_init; 460258331Smarkj IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 461258331Smarkj ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 462258331Smarkj IFQ_SET_READY(&ifp->if_snd); 463258331Smarkj 464258331Smarkj ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_TXCSUM | IFCAP_RXCSUM; 465258331Smarkj ifp->if_hwassist = AXGE_CSUM_FEATURES; 466258331Smarkj ifp->if_capenable = ifp->if_capabilities; 467258331Smarkj 468258331Smarkj mtx_lock(&Giant); 469258331Smarkj error = mii_attach(ue->ue_dev, &ue->ue_miibus, ifp, 470258331Smarkj uether_ifmedia_upd, ue->ue_methods->ue_mii_sts, 471266490Skevlo BMSR_DEFCAPMASK, sc->sc_phyno, MII_OFFSET_ANY, MIIF_DOPAUSE); 472258331Smarkj mtx_unlock(&Giant); 473258331Smarkj 474258331Smarkj return (error); 475258331Smarkj} 476258331Smarkj 477258331Smarkj/* 478258331Smarkj * Set media options. 479258331Smarkj */ 480258331Smarkjstatic int 481258331Smarkjaxge_ifmedia_upd(struct ifnet *ifp) 482258331Smarkj{ 483258331Smarkj struct axge_softc *sc; 484258331Smarkj struct mii_data *mii; 485258331Smarkj struct mii_softc *miisc; 486258331Smarkj int error; 487258331Smarkj 488258331Smarkj sc = ifp->if_softc; 489258331Smarkj mii = GET_MII(sc); 490258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 491258331Smarkj 492258331Smarkj LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 493258331Smarkj PHY_RESET(miisc); 494258331Smarkj error = mii_mediachg(mii); 495258331Smarkj 496258331Smarkj return (error); 497258331Smarkj} 498258331Smarkj 499258331Smarkj/* 500258331Smarkj * Report current media status. 501258331Smarkj */ 502258331Smarkjstatic void 503258331Smarkjaxge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 504258331Smarkj{ 505258331Smarkj struct axge_softc *sc; 506258331Smarkj struct mii_data *mii; 507258331Smarkj 508258331Smarkj sc = ifp->if_softc; 509258331Smarkj mii = GET_MII(sc); 510258331Smarkj AXGE_LOCK(sc); 511258331Smarkj mii_pollstat(mii); 512258331Smarkj ifmr->ifm_active = mii->mii_media_active; 513258331Smarkj ifmr->ifm_status = mii->mii_media_status; 514258331Smarkj AXGE_UNLOCK(sc); 515258331Smarkj} 516258331Smarkj 517258331Smarkj/* 518258331Smarkj * Probe for a AX88179 chip. 519258331Smarkj */ 520258331Smarkjstatic int 521258331Smarkjaxge_probe(device_t dev) 522258331Smarkj{ 523258331Smarkj struct usb_attach_arg *uaa; 524258331Smarkj 525258331Smarkj uaa = device_get_ivars(dev); 526258331Smarkj if (uaa->usb_mode != USB_MODE_HOST) 527258331Smarkj return (ENXIO); 528258331Smarkj if (uaa->info.bConfigIndex != AXGE_CONFIG_IDX) 529258331Smarkj return (ENXIO); 530258331Smarkj if (uaa->info.bIfaceIndex != AXGE_IFACE_IDX) 531258331Smarkj return (ENXIO); 532258331Smarkj 533258331Smarkj return (usbd_lookup_id_by_uaa(axge_devs, sizeof(axge_devs), uaa)); 534258331Smarkj} 535258331Smarkj 536258331Smarkj/* 537258331Smarkj * Attach the interface. Allocate softc structures, do ifmedia 538258331Smarkj * setup and ethernet/BPF attach. 539258331Smarkj */ 540258331Smarkjstatic int 541258331Smarkjaxge_attach(device_t dev) 542258331Smarkj{ 543258331Smarkj struct usb_attach_arg *uaa; 544258331Smarkj struct axge_softc *sc; 545258331Smarkj struct usb_ether *ue; 546258331Smarkj uint8_t iface_index; 547258331Smarkj int error; 548258331Smarkj 549258331Smarkj uaa = device_get_ivars(dev); 550258331Smarkj sc = device_get_softc(dev); 551258331Smarkj ue = &sc->sc_ue; 552258331Smarkj 553258331Smarkj device_set_usb_desc(dev); 554258331Smarkj mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 555258331Smarkj 556258331Smarkj iface_index = AXGE_IFACE_IDX; 557258331Smarkj error = usbd_transfer_setup(uaa->device, &iface_index, 558258331Smarkj sc->sc_xfer, axge_config, AXGE_N_TRANSFER, sc, &sc->sc_mtx); 559258331Smarkj if (error) { 560258331Smarkj device_printf(dev, "allocating USB transfers failed\n"); 561258331Smarkj goto detach; 562258331Smarkj } 563258331Smarkj 564258331Smarkj ue->ue_sc = sc; 565258331Smarkj ue->ue_dev = dev; 566258331Smarkj ue->ue_udev = uaa->device; 567258331Smarkj ue->ue_mtx = &sc->sc_mtx; 568258331Smarkj ue->ue_methods = &axge_ue_methods; 569258331Smarkj 570258331Smarkj error = uether_ifattach(ue); 571258331Smarkj if (error) { 572258331Smarkj device_printf(dev, "could not attach interface\n"); 573258331Smarkj goto detach; 574258331Smarkj } 575258331Smarkj return (0); /* success */ 576258331Smarkj 577258331Smarkjdetach: 578258331Smarkj axge_detach(dev); 579258331Smarkj return (ENXIO); /* failure */ 580258331Smarkj} 581258331Smarkj 582258331Smarkjstatic int 583258331Smarkjaxge_detach(device_t dev) 584258331Smarkj{ 585258331Smarkj struct axge_softc *sc; 586258331Smarkj struct usb_ether *ue; 587258331Smarkj 588258331Smarkj sc = device_get_softc(dev); 589258331Smarkj ue = &sc->sc_ue; 590258331Smarkj usbd_transfer_unsetup(sc->sc_xfer, AXGE_N_TRANSFER); 591258331Smarkj uether_ifdetach(ue); 592258331Smarkj mtx_destroy(&sc->sc_mtx); 593258331Smarkj 594258331Smarkj return (0); 595258331Smarkj} 596258331Smarkj 597258331Smarkjstatic void 598258331Smarkjaxge_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 599258331Smarkj{ 600258331Smarkj struct axge_softc *sc; 601258331Smarkj struct usb_ether *ue; 602258331Smarkj struct usb_page_cache *pc; 603258331Smarkj int actlen; 604258331Smarkj 605258331Smarkj sc = usbd_xfer_softc(xfer); 606258331Smarkj ue = &sc->sc_ue; 607258331Smarkj usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 608258331Smarkj 609258331Smarkj switch (USB_GET_STATE(xfer)) { 610258331Smarkj case USB_ST_TRANSFERRED: 611258331Smarkj pc = usbd_xfer_get_frame(xfer, 0); 612258331Smarkj axge_rx_frame(ue, pc, actlen); 613258331Smarkj 614258331Smarkj /* FALLTHROUGH */ 615258331Smarkj case USB_ST_SETUP: 616258331Smarkjtr_setup: 617258331Smarkj usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 618258331Smarkj usbd_transfer_submit(xfer); 619258331Smarkj uether_rxflush(ue); 620258331Smarkj return; 621258331Smarkj 622258331Smarkj default: 623258331Smarkj if (error != USB_ERR_CANCELLED) { 624258331Smarkj usbd_xfer_set_stall(xfer); 625258331Smarkj goto tr_setup; 626258331Smarkj } 627258331Smarkj return; 628258331Smarkj 629258331Smarkj } 630258331Smarkj} 631258331Smarkj 632258331Smarkjstatic void 633258331Smarkjaxge_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 634258331Smarkj{ 635258331Smarkj struct axge_softc *sc; 636258331Smarkj struct ifnet *ifp; 637258331Smarkj struct usb_page_cache *pc; 638258331Smarkj struct mbuf *m; 639258331Smarkj uint32_t txhdr; 640258331Smarkj uint32_t txhdr2; 641258331Smarkj int nframes; 642258331Smarkj int frm_len; 643258331Smarkj 644258331Smarkj sc = usbd_xfer_softc(xfer); 645258331Smarkj ifp = uether_getifp(&sc->sc_ue); 646258331Smarkj 647258331Smarkj switch (USB_GET_STATE(xfer)) { 648258331Smarkj case USB_ST_TRANSFERRED: 649258331Smarkj ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 650258331Smarkj /* FALLTHROUGH */ 651258331Smarkj case USB_ST_SETUP: 652258331Smarkjtr_setup: 653258331Smarkj if ((sc->sc_flags & AXGE_FLAG_LINK) == 0 || 654258331Smarkj (ifp->if_drv_flags & IFF_DRV_OACTIVE) != 0) { 655258331Smarkj /* 656258331Smarkj * Don't send anything if there is no link or 657258331Smarkj * controller is busy. 658258331Smarkj */ 659258331Smarkj return; 660258331Smarkj } 661258331Smarkj 662258331Smarkj for (nframes = 0; nframes < 16 && 663258331Smarkj !IFQ_DRV_IS_EMPTY(&ifp->if_snd); nframes++) { 664258331Smarkj IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 665258331Smarkj if (m == NULL) 666258331Smarkj break; 667258331Smarkj usbd_xfer_set_frame_offset(xfer, nframes * MCLBYTES, 668258331Smarkj nframes); 669258331Smarkj frm_len = 0; 670258331Smarkj pc = usbd_xfer_get_frame(xfer, nframes); 671258331Smarkj 672258331Smarkj txhdr = m->m_pkthdr.len; 673258331Smarkj txhdr = htole32(txhdr); 674258331Smarkj usbd_copy_in(pc, 0, &txhdr, sizeof(txhdr)); 675258331Smarkj frm_len += sizeof(txhdr); 676258331Smarkj 677258331Smarkj txhdr2 = 0; 678258331Smarkj if ((m->m_pkthdr.len + sizeof(txhdr) + sizeof(txhdr2)) % 679258331Smarkj usbd_xfer_max_framelen(xfer) == 0) { 680258331Smarkj txhdr2 |= 0x80008000; 681258331Smarkj } 682258331Smarkj txhdr2 = htole32(txhdr2); 683258331Smarkj usbd_copy_in(pc, frm_len, &txhdr2, sizeof(txhdr2)); 684258331Smarkj frm_len += sizeof(txhdr2); 685258331Smarkj 686258331Smarkj /* Next copy in the actual packet. */ 687258331Smarkj usbd_m_copy_in(pc, frm_len, m, 0, m->m_pkthdr.len); 688258331Smarkj frm_len += m->m_pkthdr.len; 689258331Smarkj 690258331Smarkj /* 691258331Smarkj * XXX 692258331Smarkj * Update TX packet counter here. This is not 693258331Smarkj * correct way but it seems that there is no way 694258331Smarkj * to know how many packets are sent at the end 695258331Smarkj * of transfer because controller combines 696258331Smarkj * multiple writes into single one if there is 697258331Smarkj * room in TX buffer of controller. 698258331Smarkj */ 699258331Smarkj ifp->if_opackets++; 700258331Smarkj 701258331Smarkj /* 702258331Smarkj * if there's a BPF listener, bounce a copy 703258331Smarkj * of this frame to him: 704258331Smarkj */ 705258331Smarkj BPF_MTAP(ifp, m); 706258331Smarkj 707258331Smarkj m_freem(m); 708258331Smarkj 709258331Smarkj /* Set frame length. */ 710258331Smarkj usbd_xfer_set_frame_len(xfer, nframes, frm_len); 711258331Smarkj } 712258331Smarkj if (nframes != 0) { 713258331Smarkj usbd_xfer_set_frames(xfer, nframes); 714258331Smarkj usbd_transfer_submit(xfer); 715258331Smarkj ifp->if_drv_flags |= IFF_DRV_OACTIVE; 716258331Smarkj } 717258331Smarkj return; 718258331Smarkj /* NOTREACHED */ 719258331Smarkj default: 720258331Smarkj ifp->if_oerrors++; 721258331Smarkj ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 722258331Smarkj 723258331Smarkj if (error != USB_ERR_CANCELLED) { 724258331Smarkj usbd_xfer_set_stall(xfer); 725258331Smarkj goto tr_setup; 726258331Smarkj } 727258331Smarkj return; 728258331Smarkj 729258331Smarkj } 730258331Smarkj} 731258331Smarkj 732258331Smarkjstatic void 733258331Smarkjaxge_tick(struct usb_ether *ue) 734258331Smarkj{ 735258331Smarkj struct axge_softc *sc; 736258331Smarkj struct mii_data *mii; 737258331Smarkj 738258331Smarkj sc = uether_getsc(ue); 739258331Smarkj mii = GET_MII(sc); 740258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 741258331Smarkj 742258331Smarkj mii_tick(mii); 743258331Smarkj if ((sc->sc_flags & AXGE_FLAG_LINK) == 0) { 744258331Smarkj axge_miibus_statchg(ue->ue_dev); 745258331Smarkj if ((sc->sc_flags & AXGE_FLAG_LINK) != 0) 746258331Smarkj axge_start(ue); 747258331Smarkj } 748258331Smarkj} 749258331Smarkj 750258331Smarkjstatic void 751258331Smarkjaxge_setmulti(struct usb_ether *ue) 752258331Smarkj{ 753258331Smarkj struct axge_softc *sc; 754258331Smarkj struct ifnet *ifp; 755258331Smarkj struct ifmultiaddr *ifma; 756258331Smarkj uint32_t h; 757258331Smarkj uint16_t rxmode; 758258331Smarkj uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 759258331Smarkj 760258331Smarkj sc = uether_getsc(ue); 761258331Smarkj ifp = uether_getifp(ue); 762258331Smarkj h = 0; 763258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 764258331Smarkj 765258331Smarkj rxmode = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RX_CTL); 766258331Smarkj if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { 767258331Smarkj rxmode |= AXGE_RX_CTL_AMALL; 768258331Smarkj axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RX_CTL, rxmode); 769258331Smarkj return; 770258331Smarkj } 771258331Smarkj rxmode &= ~AXGE_RX_CTL_AMALL; 772258331Smarkj 773258331Smarkj if_maddr_rlock(ifp); 774258331Smarkj TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 775258331Smarkj if (ifma->ifma_addr->sa_family != AF_LINK) 776258331Smarkj continue; 777258331Smarkj h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 778258331Smarkj ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 779258331Smarkj hashtbl[h / 8] |= 1 << (h % 8); 780258331Smarkj } 781258331Smarkj if_maddr_runlock(ifp); 782258331Smarkj 783258331Smarkj axge_write_mem(sc, AXGE_ACCESS_MAC, 8, AXGE_MULTI_FILTER_ARRY, 784258331Smarkj (void *)&hashtbl, 8); 785258331Smarkj axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RX_CTL, rxmode); 786258331Smarkj} 787258331Smarkj 788258331Smarkjstatic void 789258331Smarkjaxge_setpromisc(struct usb_ether *ue) 790258331Smarkj{ 791258331Smarkj struct axge_softc *sc; 792258331Smarkj struct ifnet *ifp; 793258331Smarkj uint16_t rxmode; 794258331Smarkj 795258331Smarkj sc = uether_getsc(ue); 796258331Smarkj ifp = uether_getifp(ue); 797258331Smarkj rxmode = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RX_CTL); 798258331Smarkj 799258331Smarkj if (ifp->if_flags & IFF_PROMISC) 800258331Smarkj rxmode |= AXGE_RX_CTL_PRO; 801258331Smarkj else 802258331Smarkj rxmode &= ~AXGE_RX_CTL_PRO; 803258331Smarkj 804258331Smarkj axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RX_CTL, rxmode); 805258331Smarkj axge_setmulti(ue); 806258331Smarkj} 807258331Smarkj 808258331Smarkjstatic void 809258331Smarkjaxge_start(struct usb_ether *ue) 810258331Smarkj{ 811258331Smarkj struct axge_softc *sc; 812258331Smarkj 813258331Smarkj sc = uether_getsc(ue); 814258331Smarkj /* 815258331Smarkj * Start the USB transfers, if not already started. 816258331Smarkj */ 817258331Smarkj usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_RD]); 818258331Smarkj usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_WR]); 819258331Smarkj} 820258331Smarkj 821258331Smarkjstatic void 822258331Smarkjaxge_init(struct usb_ether *ue) 823258331Smarkj{ 824258331Smarkj struct axge_softc *sc; 825258331Smarkj struct ifnet *ifp; 826258331Smarkj uint16_t rxmode; 827258331Smarkj 828258331Smarkj sc = uether_getsc(ue); 829258331Smarkj ifp = uether_getifp(ue); 830258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 831258331Smarkj 832258331Smarkj if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 833258331Smarkj return; 834258331Smarkj 835258331Smarkj /* 836258331Smarkj * Cancel pending I/O and free all RX/TX buffers. 837258331Smarkj */ 838258331Smarkj axge_stop(ue); 839258331Smarkj 840258331Smarkj axge_reset(sc); 841258331Smarkj 842258331Smarkj /* Set MAC address. */ 843258331Smarkj axge_write_mem(sc, AXGE_ACCESS_MAC, ETHER_ADDR_LEN, AXGE_NODE_ID, 844258331Smarkj IF_LLADDR(ifp), ETHER_ADDR_LEN); 845258331Smarkj 846258331Smarkj axge_write_cmd_1(sc, AXGE_ACCESS_MAC, 1, AXGE_PAUSE_WATERLVL_LOW, 0x34); 847258331Smarkj axge_write_cmd_1(sc, AXGE_ACCESS_MAC, 1, AXGE_PAUSE_WATERLVL_HIGH, 848258331Smarkj 0x52); 849258331Smarkj 850258331Smarkj /* Configure TX/RX checksum offloading. */ 851258331Smarkj axge_csum_cfg(ue); 852258331Smarkj 853258331Smarkj /* Configure RX settings. */ 854258331Smarkj rxmode = (AXGE_RX_CTL_IPE | AXGE_RX_CTL_AM | AXGE_RX_CTL_START); 855258331Smarkj 856258331Smarkj /* If we want promiscuous mode, set the allframes bit. */ 857258331Smarkj if (ifp->if_flags & IFF_PROMISC) 858258331Smarkj rxmode |= AXGE_RX_CTL_PRO; 859258331Smarkj 860258331Smarkj if (ifp->if_flags & IFF_BROADCAST) 861258331Smarkj rxmode |= AXGE_RX_CTL_AB; 862258331Smarkj 863258331Smarkj axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RX_CTL, rxmode); 864258331Smarkj 865258331Smarkj /* Load the multicast filter. */ 866258331Smarkj axge_setmulti(ue); 867258331Smarkj 868258331Smarkj usbd_xfer_set_stall(sc->sc_xfer[AXGE_BULK_DT_WR]); 869258331Smarkj 870258331Smarkj ifp->if_drv_flags |= IFF_DRV_RUNNING; 871258331Smarkj /* Switch to selected media. */ 872258331Smarkj axge_ifmedia_upd(ifp); 873258331Smarkj} 874258331Smarkj 875258331Smarkjstatic void 876258331Smarkjaxge_stop(struct usb_ether *ue) 877258331Smarkj{ 878258331Smarkj struct axge_softc *sc; 879258331Smarkj struct ifnet *ifp; 880258331Smarkj 881258331Smarkj sc = uether_getsc(ue); 882258331Smarkj ifp = uether_getifp(ue); 883258331Smarkj 884258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 885258331Smarkj 886258331Smarkj ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 887258331Smarkj sc->sc_flags &= ~AXGE_FLAG_LINK; 888258331Smarkj 889258331Smarkj /* 890258331Smarkj * Stop all the transfers, if not already stopped: 891258331Smarkj */ 892258331Smarkj usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_WR]); 893258331Smarkj usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_RD]); 894258331Smarkj} 895258331Smarkj 896258331Smarkjstatic int 897258331Smarkjaxge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 898258331Smarkj{ 899258331Smarkj struct usb_ether *ue; 900258331Smarkj struct axge_softc *sc; 901258331Smarkj struct ifreq *ifr; 902258331Smarkj int error, mask, reinit; 903258331Smarkj 904258331Smarkj ue = ifp->if_softc; 905258331Smarkj sc = uether_getsc(ue); 906258331Smarkj ifr = (struct ifreq *)data; 907258331Smarkj error = 0; 908258331Smarkj reinit = 0; 909258331Smarkj if (cmd == SIOCSIFCAP) { 910258331Smarkj AXGE_LOCK(sc); 911258331Smarkj mask = ifr->ifr_reqcap ^ ifp->if_capenable; 912258331Smarkj if ((mask & IFCAP_TXCSUM) != 0 && 913258331Smarkj (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { 914258331Smarkj ifp->if_capenable ^= IFCAP_TXCSUM; 915258331Smarkj if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 916258331Smarkj ifp->if_hwassist |= AXGE_CSUM_FEATURES; 917258331Smarkj else 918258331Smarkj ifp->if_hwassist &= ~AXGE_CSUM_FEATURES; 919258331Smarkj reinit++; 920258331Smarkj } 921258331Smarkj if ((mask & IFCAP_RXCSUM) != 0 && 922258331Smarkj (ifp->if_capabilities & IFCAP_RXCSUM) != 0) { 923258331Smarkj ifp->if_capenable ^= IFCAP_RXCSUM; 924258331Smarkj reinit++; 925258331Smarkj } 926258331Smarkj if (reinit > 0 && ifp->if_drv_flags & IFF_DRV_RUNNING) 927258331Smarkj ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 928258331Smarkj else 929258331Smarkj reinit = 0; 930258331Smarkj AXGE_UNLOCK(sc); 931258331Smarkj if (reinit > 0) 932258331Smarkj uether_init(ue); 933258331Smarkj } else 934258331Smarkj error = uether_ioctl(ifp, cmd, data); 935258331Smarkj 936258331Smarkj return (error); 937258331Smarkj} 938258331Smarkj 939258331Smarkjstatic int 940258331Smarkjaxge_rx_frame(struct usb_ether *ue, struct usb_page_cache *pc, int actlen) 941258331Smarkj{ 942258331Smarkj struct axge_csum_hdr csum_hdr; 943258331Smarkj int error, len, pos; 944258331Smarkj int pkt_cnt; 945258331Smarkj uint32_t rxhdr; 946258331Smarkj uint16_t hdr_off; 947258331Smarkj uint16_t pktlen; 948258331Smarkj 949258331Smarkj pos = 0; 950258331Smarkj len = 0; 951258331Smarkj error = 0; 952258331Smarkj 953258331Smarkj usbd_copy_out(pc, actlen - sizeof(rxhdr), &rxhdr, sizeof(rxhdr)); 954258331Smarkj actlen -= sizeof(rxhdr); 955258331Smarkj rxhdr = le32toh(rxhdr); 956258331Smarkj 957258331Smarkj pkt_cnt = (uint16_t)rxhdr; 958258331Smarkj hdr_off = (uint16_t)(rxhdr >> 16); 959258331Smarkj 960258331Smarkj usbd_copy_out(pc, pos + hdr_off, &csum_hdr, sizeof(csum_hdr)); 961258331Smarkj csum_hdr.len = le16toh(csum_hdr.len); 962258331Smarkj csum_hdr.cstatus = le16toh(csum_hdr.cstatus); 963258331Smarkj 964258331Smarkj while (pkt_cnt--) { 965258331Smarkj if (actlen <= sizeof(csum_hdr) + sizeof(struct ether_header)) { 966258331Smarkj error = EINVAL; 967258331Smarkj break; 968258331Smarkj } 969258331Smarkj pktlen = AXGE_CSUM_RXBYTES(csum_hdr.len); 970258331Smarkj 971258331Smarkj if (pkt_cnt == 0) 972258331Smarkj /* Skip the 2-byte IP alignment header. */ 973258331Smarkj axge_rxeof(ue, pc, 2, pktlen - 2, &csum_hdr); 974258331Smarkj } 975258331Smarkj 976258331Smarkj if (error != 0) 977258331Smarkj ue->ue_ifp->if_ierrors++; 978258331Smarkj return (error); 979258331Smarkj} 980258331Smarkj 981258331Smarkjstatic int 982258331Smarkjaxge_rxeof(struct usb_ether *ue, struct usb_page_cache *pc, 983258331Smarkj unsigned int offset, unsigned int len, struct axge_csum_hdr *csum_hdr) 984258331Smarkj{ 985258331Smarkj struct ifnet *ifp; 986258331Smarkj struct mbuf *m; 987258331Smarkj 988258331Smarkj ifp = ue->ue_ifp; 989258331Smarkj if (len < ETHER_HDR_LEN || len > MCLBYTES - ETHER_ALIGN) { 990258331Smarkj ifp->if_ierrors++; 991258331Smarkj return (EINVAL); 992258331Smarkj } 993258331Smarkj 994258331Smarkj m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 995258331Smarkj if (m == NULL) { 996258331Smarkj ifp->if_iqdrops++; 997258331Smarkj return (ENOMEM); 998258331Smarkj } 999258331Smarkj m->m_len = m->m_pkthdr.len = MCLBYTES; 1000258331Smarkj m_adj(m, ETHER_ALIGN); 1001258331Smarkj 1002258331Smarkj usbd_copy_out(pc, offset, mtod(m, uint8_t *), len); 1003258331Smarkj 1004258331Smarkj ifp->if_ipackets++; 1005258331Smarkj m->m_pkthdr.rcvif = ifp; 1006258331Smarkj m->m_pkthdr.len = m->m_len = len; 1007258331Smarkj 1008258331Smarkj if (csum_hdr != NULL && 1009258331Smarkj csum_hdr->cstatus & AXGE_CSUM_HDR_L3_TYPE_IPV4) { 1010258331Smarkj if ((csum_hdr->cstatus & (AXGE_CSUM_HDR_L4_CSUM_ERR | 1011258331Smarkj AXGE_RXHDR_L4CSUM_ERR)) == 0) { 1012258331Smarkj m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED | 1013258331Smarkj CSUM_IP_VALID; 1014258331Smarkj if ((csum_hdr->cstatus & AXGE_CSUM_HDR_L4_TYPE_MASK) == 1015258331Smarkj AXGE_CSUM_HDR_L4_TYPE_TCP || 1016258331Smarkj (csum_hdr->cstatus & AXGE_CSUM_HDR_L4_TYPE_MASK) == 1017258331Smarkj AXGE_CSUM_HDR_L4_TYPE_UDP) { 1018258331Smarkj m->m_pkthdr.csum_flags |= 1019258331Smarkj CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 1020258331Smarkj m->m_pkthdr.csum_data = 0xffff; 1021258331Smarkj } 1022258331Smarkj } 1023258331Smarkj } 1024258331Smarkj 1025258331Smarkj _IF_ENQUEUE(&ue->ue_rxq, m); 1026258331Smarkj return (0); 1027258331Smarkj} 1028258331Smarkj 1029258331Smarkjstatic void 1030258331Smarkjaxge_csum_cfg(struct usb_ether *ue) 1031258331Smarkj{ 1032258331Smarkj struct axge_softc *sc; 1033258331Smarkj struct ifnet *ifp; 1034258331Smarkj uint8_t csum; 1035258331Smarkj 1036258331Smarkj sc = uether_getsc(ue); 1037258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 1038258331Smarkj ifp = uether_getifp(ue); 1039258331Smarkj 1040258331Smarkj csum = 0; 1041258331Smarkj if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 1042258331Smarkj csum |= AXGE_TXCOE_IP | AXGE_TXCOE_TCP | AXGE_TXCOE_UDP; 1043258331Smarkj axge_write_cmd_1(sc, AXGE_ACCESS_MAC, 1, AXGE_TXCOE_CTL, csum); 1044258331Smarkj 1045258331Smarkj csum = 0; 1046258331Smarkj if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 1047258331Smarkj csum |= AXGE_RXCOE_IP | AXGE_RXCOE_TCP | AXGE_RXCOE_UDP | 1048258331Smarkj AXGE_RXCOE_ICMP | AXGE_RXCOE_IGMP; 1049258331Smarkj axge_write_cmd_1(sc, AXGE_ACCESS_MAC, 1, AXGE_RXCOE_CTL, csum); 1050258331Smarkj} 1051