1258331Smarkj/*- 2268226Shselasky * 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$"); 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), 69268226Shselasky AXGE_DEV(DLINK, DUB1312), 70268226Shselasky AXGE_DEV(SITECOMEU, LN032), 71258331Smarkj#undef AXGE_DEV 72258331Smarkj}; 73258331Smarkj 74258331Smarkjstatic const struct { 75268226Shselasky uint8_t ctrl; 76268226Shselasky uint8_t timer_l; 77268226Shselasky uint8_t timer_h; 78268226Shselasky uint8_t size; 79268226Shselasky uint8_t ifg; 80268226Shselasky} axge_bulk_size[] = { 81268226Shselasky { 7, 0x4f, 0x00, 0x12, 0xff }, 82268226Shselasky { 7, 0x20, 0x03, 0x16, 0xff }, 83268226Shselasky { 7, 0xae, 0x07, 0x18, 0xff }, 84268226Shselasky { 7, 0xcc, 0x4c, 0x18, 0x08 } 85258331Smarkj}; 86258331Smarkj 87258331Smarkj/* prototypes */ 88258331Smarkj 89258331Smarkjstatic device_probe_t axge_probe; 90258331Smarkjstatic device_attach_t axge_attach; 91258331Smarkjstatic device_detach_t axge_detach; 92258331Smarkj 93258331Smarkjstatic usb_callback_t axge_bulk_read_callback; 94258331Smarkjstatic usb_callback_t axge_bulk_write_callback; 95258331Smarkj 96258331Smarkjstatic miibus_readreg_t axge_miibus_readreg; 97258331Smarkjstatic miibus_writereg_t axge_miibus_writereg; 98258331Smarkjstatic miibus_statchg_t axge_miibus_statchg; 99258331Smarkj 100258331Smarkjstatic uether_fn_t axge_attach_post; 101258331Smarkjstatic uether_fn_t axge_init; 102258331Smarkjstatic uether_fn_t axge_stop; 103258331Smarkjstatic uether_fn_t axge_start; 104258331Smarkjstatic uether_fn_t axge_tick; 105258331Smarkjstatic uether_fn_t axge_setmulti; 106258331Smarkjstatic uether_fn_t axge_setpromisc; 107258331Smarkj 108258331Smarkjstatic int axge_read_mem(struct axge_softc *, uint8_t, uint16_t, 109258331Smarkj uint16_t, void *, int); 110258331Smarkjstatic void axge_write_mem(struct axge_softc *, uint8_t, uint16_t, 111258331Smarkj uint16_t, void *, int); 112268226Shselaskystatic uint8_t axge_read_cmd_1(struct axge_softc *, uint8_t, 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, 116268226Shselasky 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); 126268226Shselaskystatic void axge_rx_frame(struct usb_ether *, struct usb_page_cache *, int); 127268226Shselaskystatic void axge_rxeof(struct usb_ether *, struct usb_page_cache *, 128268226Shselasky unsigned int, unsigned int, uint32_t); 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, 147268226Shselasky .bufsize = 16 * MCLBYTES, 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 242268226Shselaskystatic uint8_t 243268226Shselaskyaxge_read_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t reg) 244268226Shselasky{ 245268226Shselasky uint8_t val; 246268226Shselasky 247268226Shselasky axge_read_mem(sc, cmd, 1, reg, &val, 1); 248268226Shselasky return (val); 249268226Shselasky} 250268226Shselasky 251258331Smarkjstatic uint16_t 252258331Smarkjaxge_read_cmd_2(struct axge_softc *sc, uint8_t cmd, uint16_t index, 253258331Smarkj uint16_t reg) 254258331Smarkj{ 255258331Smarkj uint8_t val[2]; 256258331Smarkj 257258331Smarkj axge_read_mem(sc, cmd, index, reg, &val, 2); 258258331Smarkj return (UGETW(val)); 259258331Smarkj} 260258331Smarkj 261258331Smarkjstatic void 262268226Shselaskyaxge_write_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t reg, uint8_t val) 263258331Smarkj{ 264268226Shselasky axge_write_mem(sc, cmd, 1, reg, &val, 1); 265258331Smarkj} 266258331Smarkj 267258331Smarkjstatic void 268258331Smarkjaxge_write_cmd_2(struct axge_softc *sc, uint8_t cmd, uint16_t index, 269258331Smarkj uint16_t reg, uint16_t val) 270258331Smarkj{ 271258331Smarkj uint8_t temp[2]; 272258331Smarkj 273258331Smarkj USETW(temp, val); 274258331Smarkj axge_write_mem(sc, cmd, index, reg, &temp, 2); 275258331Smarkj} 276258331Smarkj 277258331Smarkjstatic int 278258331Smarkjaxge_miibus_readreg(device_t dev, int phy, int reg) 279258331Smarkj{ 280258331Smarkj struct axge_softc *sc; 281258331Smarkj uint16_t val; 282258331Smarkj int locked; 283258331Smarkj 284258331Smarkj sc = device_get_softc(dev); 285258331Smarkj locked = mtx_owned(&sc->sc_mtx); 286258331Smarkj if (!locked) 287258331Smarkj AXGE_LOCK(sc); 288258331Smarkj 289258331Smarkj val = axge_read_cmd_2(sc, AXGE_ACCESS_PHY, reg, phy); 290258331Smarkj 291258331Smarkj if (!locked) 292258331Smarkj AXGE_UNLOCK(sc); 293258331Smarkj 294258331Smarkj return (val); 295258331Smarkj} 296258331Smarkj 297258331Smarkjstatic int 298258331Smarkjaxge_miibus_writereg(device_t dev, int phy, int reg, int val) 299258331Smarkj{ 300258331Smarkj struct axge_softc *sc; 301258331Smarkj int locked; 302258331Smarkj 303258331Smarkj sc = device_get_softc(dev); 304258331Smarkj if (sc->sc_phyno != phy) 305258331Smarkj return (0); 306258331Smarkj locked = mtx_owned(&sc->sc_mtx); 307258331Smarkj if (!locked) 308258331Smarkj AXGE_LOCK(sc); 309258331Smarkj 310258331Smarkj axge_write_cmd_2(sc, AXGE_ACCESS_PHY, reg, phy, val); 311258331Smarkj 312258331Smarkj if (!locked) 313258331Smarkj AXGE_UNLOCK(sc); 314258331Smarkj 315258331Smarkj return (0); 316258331Smarkj} 317258331Smarkj 318258331Smarkjstatic void 319258331Smarkjaxge_miibus_statchg(device_t dev) 320258331Smarkj{ 321258331Smarkj struct axge_softc *sc; 322258331Smarkj struct mii_data *mii; 323258331Smarkj struct ifnet *ifp; 324268226Shselasky uint8_t link_status, tmp[5]; 325258331Smarkj uint16_t val; 326258331Smarkj int locked; 327258331Smarkj 328258331Smarkj sc = device_get_softc(dev); 329258331Smarkj mii = GET_MII(sc); 330258331Smarkj locked = mtx_owned(&sc->sc_mtx); 331258331Smarkj if (!locked) 332258331Smarkj AXGE_LOCK(sc); 333258331Smarkj 334258331Smarkj ifp = uether_getifp(&sc->sc_ue); 335258331Smarkj if (mii == NULL || ifp == NULL || 336258331Smarkj (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 337258331Smarkj goto done; 338258331Smarkj 339258331Smarkj sc->sc_flags &= ~AXGE_FLAG_LINK; 340258331Smarkj if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 341258331Smarkj (IFM_ACTIVE | IFM_AVALID)) { 342258331Smarkj switch (IFM_SUBTYPE(mii->mii_media_active)) { 343258331Smarkj case IFM_10_T: 344258331Smarkj case IFM_100_TX: 345258331Smarkj case IFM_1000_T: 346258331Smarkj sc->sc_flags |= AXGE_FLAG_LINK; 347258331Smarkj break; 348258331Smarkj default: 349258331Smarkj break; 350258331Smarkj } 351258331Smarkj } 352258331Smarkj 353258331Smarkj /* Lost link, do nothing. */ 354258331Smarkj if ((sc->sc_flags & AXGE_FLAG_LINK) == 0) 355258331Smarkj goto done; 356258331Smarkj 357268226Shselasky link_status = axge_read_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PLSR); 358268226Shselasky 359258331Smarkj val = 0; 360258331Smarkj if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 361268226Shselasky val |= MSR_FD; 362258331Smarkj if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) 363268226Shselasky val |= MSR_TFC; 364258331Smarkj if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) 365268226Shselasky val |= MSR_RFC; 366258331Smarkj } 367268226Shselasky val |= MSR_RE; 368258331Smarkj switch (IFM_SUBTYPE(mii->mii_media_active)) { 369258331Smarkj case IFM_1000_T: 370268226Shselasky val |= MSR_GM | MSR_EN_125MHZ; 371268226Shselasky if (link_status & PLSR_USB_SS) 372268226Shselasky memcpy(tmp, &axge_bulk_size[0], 5); 373268226Shselasky else if (link_status & PLSR_USB_HS) 374268226Shselasky memcpy(tmp, &axge_bulk_size[1], 5); 375268226Shselasky else 376268226Shselasky memcpy(tmp, &axge_bulk_size[3], 5); 377268226Shselasky break; 378258331Smarkj case IFM_100_TX: 379268226Shselasky val |= MSR_PS; 380268226Shselasky if (link_status & (PLSR_USB_SS | PLSR_USB_HS)) 381268226Shselasky memcpy(tmp, &axge_bulk_size[2], 5); 382268226Shselasky else 383268226Shselasky memcpy(tmp, &axge_bulk_size[3], 5); 384268226Shselasky break; 385258331Smarkj case IFM_10_T: 386268226Shselasky memcpy(tmp, &axge_bulk_size[3], 5); 387258331Smarkj break; 388258331Smarkj } 389268226Shselasky /* Rx bulk configuration. */ 390268226Shselasky axge_write_mem(sc, AXGE_ACCESS_MAC, 5, AXGE_RX_BULKIN_QCTRL, tmp, 5); 391268226Shselasky axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_MSR, val); 392258331Smarkjdone: 393258331Smarkj if (!locked) 394258331Smarkj AXGE_UNLOCK(sc); 395258331Smarkj} 396258331Smarkj 397258331Smarkjstatic void 398258331Smarkjaxge_chip_init(struct axge_softc *sc) 399258331Smarkj{ 400258331Smarkj /* Power up ethernet PHY. */ 401268226Shselasky axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR, 0); 402268226Shselasky axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR, EPPRCR_IPRL); 403258331Smarkj uether_pause(&sc->sc_ue, hz / 4); 404268226Shselasky axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CLK_SELECT, 405258331Smarkj AXGE_CLK_SELECT_ACS | AXGE_CLK_SELECT_BCS); 406258331Smarkj uether_pause(&sc->sc_ue, hz / 10); 407258331Smarkj} 408258331Smarkj 409258331Smarkjstatic void 410258331Smarkjaxge_reset(struct axge_softc *sc) 411258331Smarkj{ 412258331Smarkj struct usb_config_descriptor *cd; 413258331Smarkj usb_error_t err; 414258331Smarkj 415258331Smarkj cd = usbd_get_config_descriptor(sc->sc_ue.ue_udev); 416258331Smarkj 417258331Smarkj err = usbd_req_set_config(sc->sc_ue.ue_udev, &sc->sc_mtx, 418258331Smarkj cd->bConfigurationValue); 419258331Smarkj if (err) 420258331Smarkj DPRINTF("reset failed (ignored)\n"); 421258331Smarkj 422258331Smarkj /* Wait a little while for the chip to get its brains in order. */ 423258331Smarkj uether_pause(&sc->sc_ue, hz / 100); 424258331Smarkj 425258331Smarkj /* Reinitialize controller to achieve full reset. */ 426258331Smarkj axge_chip_init(sc); 427258331Smarkj} 428258331Smarkj 429258331Smarkjstatic void 430258331Smarkjaxge_attach_post(struct usb_ether *ue) 431258331Smarkj{ 432258331Smarkj struct axge_softc *sc; 433258331Smarkj 434258331Smarkj sc = uether_getsc(ue); 435258331Smarkj sc->sc_phyno = 3; 436258331Smarkj 437258331Smarkj /* Initialize controller and get station address. */ 438258331Smarkj axge_chip_init(sc); 439268226Shselasky axge_read_mem(sc, AXGE_ACCESS_MAC, ETHER_ADDR_LEN, AXGE_NIDR, 440258331Smarkj ue->ue_eaddr, ETHER_ADDR_LEN); 441258331Smarkj} 442258331Smarkj 443258331Smarkjstatic int 444258331Smarkjaxge_attach_post_sub(struct usb_ether *ue) 445258331Smarkj{ 446258331Smarkj struct axge_softc *sc; 447258331Smarkj struct ifnet *ifp; 448258331Smarkj int error; 449258331Smarkj 450258331Smarkj sc = uether_getsc(ue); 451258331Smarkj ifp = ue->ue_ifp; 452258331Smarkj ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 453258331Smarkj ifp->if_start = uether_start; 454258331Smarkj ifp->if_ioctl = axge_ioctl; 455258331Smarkj ifp->if_init = uether_init; 456258331Smarkj IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 457258331Smarkj ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 458258331Smarkj IFQ_SET_READY(&ifp->if_snd); 459258331Smarkj 460258331Smarkj ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_TXCSUM | IFCAP_RXCSUM; 461258331Smarkj ifp->if_hwassist = AXGE_CSUM_FEATURES; 462258331Smarkj ifp->if_capenable = ifp->if_capabilities; 463258331Smarkj 464258331Smarkj mtx_lock(&Giant); 465258331Smarkj error = mii_attach(ue->ue_dev, &ue->ue_miibus, ifp, 466258331Smarkj uether_ifmedia_upd, ue->ue_methods->ue_mii_sts, 467268226Shselasky BMSR_DEFCAPMASK, sc->sc_phyno, MII_OFFSET_ANY, MIIF_DOPAUSE); 468258331Smarkj mtx_unlock(&Giant); 469258331Smarkj 470258331Smarkj return (error); 471258331Smarkj} 472258331Smarkj 473258331Smarkj/* 474258331Smarkj * Set media options. 475258331Smarkj */ 476258331Smarkjstatic int 477258331Smarkjaxge_ifmedia_upd(struct ifnet *ifp) 478258331Smarkj{ 479258331Smarkj struct axge_softc *sc; 480258331Smarkj struct mii_data *mii; 481258331Smarkj struct mii_softc *miisc; 482258331Smarkj int error; 483258331Smarkj 484258331Smarkj sc = ifp->if_softc; 485258331Smarkj mii = GET_MII(sc); 486258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 487258331Smarkj 488258331Smarkj LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 489258331Smarkj PHY_RESET(miisc); 490258331Smarkj error = mii_mediachg(mii); 491258331Smarkj 492258331Smarkj return (error); 493258331Smarkj} 494258331Smarkj 495258331Smarkj/* 496258331Smarkj * Report current media status. 497258331Smarkj */ 498258331Smarkjstatic void 499258331Smarkjaxge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 500258331Smarkj{ 501258331Smarkj struct axge_softc *sc; 502258331Smarkj struct mii_data *mii; 503258331Smarkj 504258331Smarkj sc = ifp->if_softc; 505258331Smarkj mii = GET_MII(sc); 506258331Smarkj AXGE_LOCK(sc); 507258331Smarkj mii_pollstat(mii); 508258331Smarkj ifmr->ifm_active = mii->mii_media_active; 509258331Smarkj ifmr->ifm_status = mii->mii_media_status; 510258331Smarkj AXGE_UNLOCK(sc); 511258331Smarkj} 512258331Smarkj 513258331Smarkj/* 514258331Smarkj * Probe for a AX88179 chip. 515258331Smarkj */ 516258331Smarkjstatic int 517258331Smarkjaxge_probe(device_t dev) 518258331Smarkj{ 519258331Smarkj struct usb_attach_arg *uaa; 520258331Smarkj 521258331Smarkj uaa = device_get_ivars(dev); 522258331Smarkj if (uaa->usb_mode != USB_MODE_HOST) 523258331Smarkj return (ENXIO); 524258331Smarkj if (uaa->info.bConfigIndex != AXGE_CONFIG_IDX) 525258331Smarkj return (ENXIO); 526258331Smarkj if (uaa->info.bIfaceIndex != AXGE_IFACE_IDX) 527258331Smarkj return (ENXIO); 528258331Smarkj 529258331Smarkj return (usbd_lookup_id_by_uaa(axge_devs, sizeof(axge_devs), uaa)); 530258331Smarkj} 531258331Smarkj 532258331Smarkj/* 533258331Smarkj * Attach the interface. Allocate softc structures, do ifmedia 534258331Smarkj * setup and ethernet/BPF attach. 535258331Smarkj */ 536258331Smarkjstatic int 537258331Smarkjaxge_attach(device_t dev) 538258331Smarkj{ 539258331Smarkj struct usb_attach_arg *uaa; 540258331Smarkj struct axge_softc *sc; 541258331Smarkj struct usb_ether *ue; 542258331Smarkj uint8_t iface_index; 543258331Smarkj int error; 544258331Smarkj 545258331Smarkj uaa = device_get_ivars(dev); 546258331Smarkj sc = device_get_softc(dev); 547258331Smarkj ue = &sc->sc_ue; 548258331Smarkj 549258331Smarkj device_set_usb_desc(dev); 550258331Smarkj mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 551258331Smarkj 552258331Smarkj iface_index = AXGE_IFACE_IDX; 553258331Smarkj error = usbd_transfer_setup(uaa->device, &iface_index, 554258331Smarkj sc->sc_xfer, axge_config, AXGE_N_TRANSFER, sc, &sc->sc_mtx); 555258331Smarkj if (error) { 556258331Smarkj device_printf(dev, "allocating USB transfers failed\n"); 557258331Smarkj goto detach; 558258331Smarkj } 559258331Smarkj 560258331Smarkj ue->ue_sc = sc; 561258331Smarkj ue->ue_dev = dev; 562258331Smarkj ue->ue_udev = uaa->device; 563258331Smarkj ue->ue_mtx = &sc->sc_mtx; 564258331Smarkj ue->ue_methods = &axge_ue_methods; 565258331Smarkj 566258331Smarkj error = uether_ifattach(ue); 567258331Smarkj if (error) { 568258331Smarkj device_printf(dev, "could not attach interface\n"); 569258331Smarkj goto detach; 570258331Smarkj } 571258331Smarkj return (0); /* success */ 572258331Smarkj 573258331Smarkjdetach: 574258331Smarkj axge_detach(dev); 575258331Smarkj return (ENXIO); /* failure */ 576258331Smarkj} 577258331Smarkj 578258331Smarkjstatic int 579258331Smarkjaxge_detach(device_t dev) 580258331Smarkj{ 581258331Smarkj struct axge_softc *sc; 582258331Smarkj struct usb_ether *ue; 583258331Smarkj 584258331Smarkj sc = device_get_softc(dev); 585258331Smarkj ue = &sc->sc_ue; 586258331Smarkj usbd_transfer_unsetup(sc->sc_xfer, AXGE_N_TRANSFER); 587258331Smarkj uether_ifdetach(ue); 588258331Smarkj mtx_destroy(&sc->sc_mtx); 589258331Smarkj 590258331Smarkj return (0); 591258331Smarkj} 592258331Smarkj 593258331Smarkjstatic void 594258331Smarkjaxge_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 595258331Smarkj{ 596258331Smarkj struct axge_softc *sc; 597258331Smarkj struct usb_ether *ue; 598258331Smarkj struct usb_page_cache *pc; 599258331Smarkj int actlen; 600258331Smarkj 601258331Smarkj sc = usbd_xfer_softc(xfer); 602258331Smarkj ue = &sc->sc_ue; 603258331Smarkj usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 604258331Smarkj 605258331Smarkj switch (USB_GET_STATE(xfer)) { 606258331Smarkj case USB_ST_TRANSFERRED: 607258331Smarkj pc = usbd_xfer_get_frame(xfer, 0); 608258331Smarkj axge_rx_frame(ue, pc, actlen); 609258331Smarkj 610258331Smarkj /* FALLTHROUGH */ 611258331Smarkj case USB_ST_SETUP: 612258331Smarkjtr_setup: 613258331Smarkj usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 614258331Smarkj usbd_transfer_submit(xfer); 615258331Smarkj uether_rxflush(ue); 616258331Smarkj return; 617258331Smarkj 618258331Smarkj default: 619258331Smarkj if (error != USB_ERR_CANCELLED) { 620258331Smarkj usbd_xfer_set_stall(xfer); 621258331Smarkj goto tr_setup; 622258331Smarkj } 623258331Smarkj return; 624258331Smarkj 625258331Smarkj } 626258331Smarkj} 627258331Smarkj 628258331Smarkjstatic void 629258331Smarkjaxge_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 630258331Smarkj{ 631258331Smarkj struct axge_softc *sc; 632258331Smarkj struct ifnet *ifp; 633258331Smarkj struct usb_page_cache *pc; 634258331Smarkj struct mbuf *m; 635258331Smarkj uint32_t txhdr; 636268226Shselasky int nframes, pos; 637258331Smarkj 638258331Smarkj sc = usbd_xfer_softc(xfer); 639258331Smarkj ifp = uether_getifp(&sc->sc_ue); 640258331Smarkj 641258331Smarkj switch (USB_GET_STATE(xfer)) { 642258331Smarkj case USB_ST_TRANSFERRED: 643258331Smarkj ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 644258331Smarkj /* FALLTHROUGH */ 645258331Smarkj case USB_ST_SETUP: 646258331Smarkjtr_setup: 647258331Smarkj if ((sc->sc_flags & AXGE_FLAG_LINK) == 0 || 648258331Smarkj (ifp->if_drv_flags & IFF_DRV_OACTIVE) != 0) { 649258331Smarkj /* 650258331Smarkj * Don't send anything if there is no link or 651258331Smarkj * controller is busy. 652258331Smarkj */ 653258331Smarkj return; 654258331Smarkj } 655258331Smarkj 656258331Smarkj for (nframes = 0; nframes < 16 && 657258331Smarkj !IFQ_DRV_IS_EMPTY(&ifp->if_snd); nframes++) { 658258331Smarkj IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 659258331Smarkj if (m == NULL) 660258331Smarkj break; 661258331Smarkj usbd_xfer_set_frame_offset(xfer, nframes * MCLBYTES, 662258331Smarkj nframes); 663268226Shselasky pos = 0; 664258331Smarkj pc = usbd_xfer_get_frame(xfer, nframes); 665268226Shselasky txhdr = htole32(m->m_pkthdr.len); 666268226Shselasky usbd_copy_in(pc, 0, &txhdr, sizeof(txhdr)); 667268226Shselasky txhdr = 0; 668258331Smarkj txhdr = htole32(txhdr); 669268226Shselasky usbd_copy_in(pc, 4, &txhdr, sizeof(txhdr)); 670268226Shselasky pos += 8; 671268226Shselasky usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len); 672268226Shselasky pos += m->m_pkthdr.len; 673268226Shselasky if ((pos % usbd_xfer_max_framelen(xfer)) == 0) 674268226Shselasky txhdr |= 0x80008000; 675258331Smarkj 676258331Smarkj /* 677258331Smarkj * XXX 678258331Smarkj * Update TX packet counter here. This is not 679258331Smarkj * correct way but it seems that there is no way 680258331Smarkj * to know how many packets are sent at the end 681258331Smarkj * of transfer because controller combines 682258331Smarkj * multiple writes into single one if there is 683258331Smarkj * room in TX buffer of controller. 684258331Smarkj */ 685258331Smarkj ifp->if_opackets++; 686258331Smarkj 687258331Smarkj /* 688258331Smarkj * if there's a BPF listener, bounce a copy 689258331Smarkj * of this frame to him: 690258331Smarkj */ 691258331Smarkj BPF_MTAP(ifp, m); 692258331Smarkj 693258331Smarkj m_freem(m); 694258331Smarkj 695258331Smarkj /* Set frame length. */ 696268226Shselasky usbd_xfer_set_frame_len(xfer, nframes, pos); 697258331Smarkj } 698258331Smarkj if (nframes != 0) { 699258331Smarkj usbd_xfer_set_frames(xfer, nframes); 700258331Smarkj usbd_transfer_submit(xfer); 701258331Smarkj ifp->if_drv_flags |= IFF_DRV_OACTIVE; 702258331Smarkj } 703258331Smarkj return; 704258331Smarkj /* NOTREACHED */ 705258331Smarkj default: 706258331Smarkj ifp->if_oerrors++; 707258331Smarkj ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 708258331Smarkj 709258331Smarkj if (error != USB_ERR_CANCELLED) { 710258331Smarkj usbd_xfer_set_stall(xfer); 711258331Smarkj goto tr_setup; 712258331Smarkj } 713258331Smarkj return; 714258331Smarkj 715258331Smarkj } 716258331Smarkj} 717258331Smarkj 718258331Smarkjstatic void 719258331Smarkjaxge_tick(struct usb_ether *ue) 720258331Smarkj{ 721258331Smarkj struct axge_softc *sc; 722258331Smarkj struct mii_data *mii; 723258331Smarkj 724258331Smarkj sc = uether_getsc(ue); 725258331Smarkj mii = GET_MII(sc); 726258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 727258331Smarkj 728258331Smarkj mii_tick(mii); 729258331Smarkj if ((sc->sc_flags & AXGE_FLAG_LINK) == 0) { 730258331Smarkj axge_miibus_statchg(ue->ue_dev); 731258331Smarkj if ((sc->sc_flags & AXGE_FLAG_LINK) != 0) 732258331Smarkj axge_start(ue); 733258331Smarkj } 734258331Smarkj} 735258331Smarkj 736258331Smarkjstatic void 737258331Smarkjaxge_setmulti(struct usb_ether *ue) 738258331Smarkj{ 739258331Smarkj struct axge_softc *sc; 740258331Smarkj struct ifnet *ifp; 741258331Smarkj struct ifmultiaddr *ifma; 742258331Smarkj uint32_t h; 743258331Smarkj uint16_t rxmode; 744258331Smarkj uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 745258331Smarkj 746258331Smarkj sc = uether_getsc(ue); 747258331Smarkj ifp = uether_getifp(ue); 748258331Smarkj h = 0; 749258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 750258331Smarkj 751268226Shselasky rxmode = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR); 752258331Smarkj if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { 753268226Shselasky rxmode |= RCR_AMALL; 754268226Shselasky axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); 755258331Smarkj return; 756258331Smarkj } 757268226Shselasky rxmode &= ~RCR_AMALL; 758258331Smarkj 759258331Smarkj if_maddr_rlock(ifp); 760258331Smarkj TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 761258331Smarkj if (ifma->ifma_addr->sa_family != AF_LINK) 762258331Smarkj continue; 763258331Smarkj h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 764258331Smarkj ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 765258331Smarkj hashtbl[h / 8] |= 1 << (h % 8); 766258331Smarkj } 767258331Smarkj if_maddr_runlock(ifp); 768258331Smarkj 769268226Shselasky axge_write_mem(sc, AXGE_ACCESS_MAC, 8, AXGE_MFA, (void *)&hashtbl, 8); 770268226Shselasky axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); 771258331Smarkj} 772258331Smarkj 773258331Smarkjstatic void 774258331Smarkjaxge_setpromisc(struct usb_ether *ue) 775258331Smarkj{ 776258331Smarkj struct axge_softc *sc; 777258331Smarkj struct ifnet *ifp; 778258331Smarkj uint16_t rxmode; 779258331Smarkj 780258331Smarkj sc = uether_getsc(ue); 781258331Smarkj ifp = uether_getifp(ue); 782268226Shselasky rxmode = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR); 783258331Smarkj 784258331Smarkj if (ifp->if_flags & IFF_PROMISC) 785268226Shselasky rxmode |= RCR_PRO; 786258331Smarkj else 787268226Shselasky rxmode &= ~RCR_PRO; 788258331Smarkj 789268226Shselasky axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); 790258331Smarkj axge_setmulti(ue); 791258331Smarkj} 792258331Smarkj 793258331Smarkjstatic void 794258331Smarkjaxge_start(struct usb_ether *ue) 795258331Smarkj{ 796258331Smarkj struct axge_softc *sc; 797258331Smarkj 798258331Smarkj sc = uether_getsc(ue); 799258331Smarkj /* 800258331Smarkj * Start the USB transfers, if not already started. 801258331Smarkj */ 802258331Smarkj usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_RD]); 803258331Smarkj usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_WR]); 804258331Smarkj} 805258331Smarkj 806258331Smarkjstatic void 807258331Smarkjaxge_init(struct usb_ether *ue) 808258331Smarkj{ 809258331Smarkj struct axge_softc *sc; 810258331Smarkj struct ifnet *ifp; 811258331Smarkj uint16_t rxmode; 812258331Smarkj 813258331Smarkj sc = uether_getsc(ue); 814258331Smarkj ifp = uether_getifp(ue); 815258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 816258331Smarkj 817258331Smarkj if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 818258331Smarkj return; 819258331Smarkj 820258331Smarkj /* 821258331Smarkj * Cancel pending I/O and free all RX/TX buffers. 822258331Smarkj */ 823258331Smarkj axge_stop(ue); 824258331Smarkj 825258331Smarkj axge_reset(sc); 826258331Smarkj 827258331Smarkj /* Set MAC address. */ 828268226Shselasky axge_write_mem(sc, AXGE_ACCESS_MAC, ETHER_ADDR_LEN, AXGE_NIDR, 829258331Smarkj IF_LLADDR(ifp), ETHER_ADDR_LEN); 830258331Smarkj 831268226Shselasky axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PWLLR, 0x34); 832268226Shselasky axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PWLHR, 0x52); 833258331Smarkj 834258331Smarkj /* Configure TX/RX checksum offloading. */ 835258331Smarkj axge_csum_cfg(ue); 836258331Smarkj 837258331Smarkj /* Configure RX settings. */ 838268226Shselasky rxmode = (RCR_AM | RCR_SO | RCR_DROP_CRCE); 839268226Shselasky if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 840268226Shselasky rxmode |= RCR_IPE; 841258331Smarkj 842258331Smarkj /* If we want promiscuous mode, set the allframes bit. */ 843258331Smarkj if (ifp->if_flags & IFF_PROMISC) 844268226Shselasky rxmode |= RCR_PRO; 845258331Smarkj 846258331Smarkj if (ifp->if_flags & IFF_BROADCAST) 847268226Shselasky rxmode |= RCR_AB; 848258331Smarkj 849268226Shselasky axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); 850258331Smarkj 851268226Shselasky axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_MMSR, 852268226Shselasky MMSR_PME_TYPE | MMSR_PME_POL | MMSR_RWMP); 853268226Shselasky 854258331Smarkj /* Load the multicast filter. */ 855258331Smarkj axge_setmulti(ue); 856258331Smarkj 857258331Smarkj usbd_xfer_set_stall(sc->sc_xfer[AXGE_BULK_DT_WR]); 858258331Smarkj 859258331Smarkj ifp->if_drv_flags |= IFF_DRV_RUNNING; 860258331Smarkj /* Switch to selected media. */ 861258331Smarkj axge_ifmedia_upd(ifp); 862258331Smarkj} 863258331Smarkj 864258331Smarkjstatic void 865258331Smarkjaxge_stop(struct usb_ether *ue) 866258331Smarkj{ 867258331Smarkj struct axge_softc *sc; 868258331Smarkj struct ifnet *ifp; 869258331Smarkj 870258331Smarkj sc = uether_getsc(ue); 871258331Smarkj ifp = uether_getifp(ue); 872258331Smarkj 873258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 874258331Smarkj 875258331Smarkj ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 876258331Smarkj sc->sc_flags &= ~AXGE_FLAG_LINK; 877258331Smarkj 878258331Smarkj /* 879258331Smarkj * Stop all the transfers, if not already stopped: 880258331Smarkj */ 881258331Smarkj usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_WR]); 882258331Smarkj usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_RD]); 883258331Smarkj} 884258331Smarkj 885258331Smarkjstatic int 886258331Smarkjaxge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 887258331Smarkj{ 888258331Smarkj struct usb_ether *ue; 889258331Smarkj struct axge_softc *sc; 890258331Smarkj struct ifreq *ifr; 891258331Smarkj int error, mask, reinit; 892258331Smarkj 893258331Smarkj ue = ifp->if_softc; 894258331Smarkj sc = uether_getsc(ue); 895258331Smarkj ifr = (struct ifreq *)data; 896258331Smarkj error = 0; 897258331Smarkj reinit = 0; 898258331Smarkj if (cmd == SIOCSIFCAP) { 899258331Smarkj AXGE_LOCK(sc); 900258331Smarkj mask = ifr->ifr_reqcap ^ ifp->if_capenable; 901258331Smarkj if ((mask & IFCAP_TXCSUM) != 0 && 902258331Smarkj (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { 903258331Smarkj ifp->if_capenable ^= IFCAP_TXCSUM; 904258331Smarkj if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 905258331Smarkj ifp->if_hwassist |= AXGE_CSUM_FEATURES; 906258331Smarkj else 907258331Smarkj ifp->if_hwassist &= ~AXGE_CSUM_FEATURES; 908258331Smarkj reinit++; 909258331Smarkj } 910258331Smarkj if ((mask & IFCAP_RXCSUM) != 0 && 911258331Smarkj (ifp->if_capabilities & IFCAP_RXCSUM) != 0) { 912258331Smarkj ifp->if_capenable ^= IFCAP_RXCSUM; 913258331Smarkj reinit++; 914258331Smarkj } 915258331Smarkj if (reinit > 0 && ifp->if_drv_flags & IFF_DRV_RUNNING) 916258331Smarkj ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 917258331Smarkj else 918258331Smarkj reinit = 0; 919258331Smarkj AXGE_UNLOCK(sc); 920258331Smarkj if (reinit > 0) 921258331Smarkj uether_init(ue); 922258331Smarkj } else 923258331Smarkj error = uether_ioctl(ifp, cmd, data); 924258331Smarkj 925258331Smarkj return (error); 926258331Smarkj} 927258331Smarkj 928268226Shselaskystatic void 929258331Smarkjaxge_rx_frame(struct usb_ether *ue, struct usb_page_cache *pc, int actlen) 930258331Smarkj{ 931268226Shselasky uint32_t pos; 932268226Shselasky uint32_t pkt_cnt; 933258331Smarkj uint32_t rxhdr; 934268226Shselasky uint32_t pkt_hdr; 935268226Shselasky uint32_t hdr_off; 936268226Shselasky uint32_t pktlen; 937258331Smarkj 938268226Shselasky /* verify we have enough data */ 939268226Shselasky if (actlen < (int)sizeof(rxhdr)) 940268226Shselasky return; 941268226Shselasky 942258331Smarkj pos = 0; 943258331Smarkj 944258331Smarkj usbd_copy_out(pc, actlen - sizeof(rxhdr), &rxhdr, sizeof(rxhdr)); 945258331Smarkj rxhdr = le32toh(rxhdr); 946258331Smarkj 947258331Smarkj pkt_cnt = (uint16_t)rxhdr; 948258331Smarkj hdr_off = (uint16_t)(rxhdr >> 16); 949258331Smarkj 950258331Smarkj while (pkt_cnt--) { 951268226Shselasky /* verify the header offset */ 952268226Shselasky if ((int)(hdr_off + sizeof(pkt_hdr)) > actlen) { 953268226Shselasky DPRINTF("End of packet headers\n"); 954258331Smarkj break; 955258331Smarkj } 956268226Shselasky if ((int)pos >= actlen) { 957268226Shselasky DPRINTF("Data position reached end\n"); 958268226Shselasky break; 959268226Shselasky } 960268226Shselasky usbd_copy_out(pc, hdr_off, &pkt_hdr, sizeof(pkt_hdr)); 961258331Smarkj 962268226Shselasky pkt_hdr = le32toh(pkt_hdr); 963268226Shselasky pktlen = (pkt_hdr >> 16) & 0x1fff; 964268226Shselasky if (pkt_hdr & (AXGE_RXHDR_CRC_ERR | AXGE_RXHDR_DROP_ERR)) { 965268226Shselasky DPRINTF("Dropped a packet\n"); 966268226Shselasky ue->ue_ifp->if_ierrors++; 967268226Shselasky } 968268226Shselasky if (pktlen >= 2 && (int)(pos + pktlen) <= actlen) { 969268226Shselasky axge_rxeof(ue, pc, pos + 2, pktlen - 2, pkt_hdr); 970268226Shselasky } else { 971268226Shselasky DPRINTF("Invalid packet pos=%d len=%d\n", 972268226Shselasky (int)pos, (int)pktlen); 973268226Shselasky } 974268226Shselasky pos += (pktlen + 7) & ~7; 975268226Shselasky hdr_off += sizeof(pkt_hdr); 976258331Smarkj } 977258331Smarkj} 978258331Smarkj 979268226Shselaskystatic void 980258331Smarkjaxge_rxeof(struct usb_ether *ue, struct usb_page_cache *pc, 981268226Shselasky unsigned int offset, unsigned int len, uint32_t pkt_hdr) 982258331Smarkj{ 983258331Smarkj struct ifnet *ifp; 984258331Smarkj struct mbuf *m; 985258331Smarkj 986258331Smarkj ifp = ue->ue_ifp; 987258331Smarkj if (len < ETHER_HDR_LEN || len > MCLBYTES - ETHER_ALIGN) { 988258331Smarkj ifp->if_ierrors++; 989268226Shselasky return; 990258331Smarkj } 991258331Smarkj 992258331Smarkj m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 993258331Smarkj if (m == NULL) { 994258331Smarkj ifp->if_iqdrops++; 995268226Shselasky return; 996258331Smarkj } 997268226Shselasky m->m_pkthdr.rcvif = ifp; 998268226Shselasky m->m_len = m->m_pkthdr.len = len + ETHER_ALIGN; 999258331Smarkj m_adj(m, ETHER_ALIGN); 1000258331Smarkj 1001258331Smarkj usbd_copy_out(pc, offset, mtod(m, uint8_t *), len); 1002258331Smarkj 1003258331Smarkj ifp->if_ipackets++; 1004268226Shselasky#if 0 1005268226Shselasky if ((pkt_hdr & (AXGE_RXHDR_L4CSUM_ERR | AXGE_RXHDR_L3CSUM_ERR)) == 0) { 1006268226Shselasky if ((pkt_hdr & AXGE_RXHDR_L4_TYPE_MASK) == 1007268226Shselasky AXGE_RXHDR_L4_TYPE_TCP || 1008268226Shselasky (pkt_hdr & AXGE_RXHDR_L4_TYPE_MASK) == 1009268226Shselasky AXGE_RXHDR_L4_TYPE_UDP) { 1010268226Shselasky m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | 1011268226Shselasky CSUM_PSEUDO_HDR | CSUM_IP_CHECKED | CSUM_IP_VALID; 1012268226Shselasky m->m_pkthdr.csum_data = 0xffff; 1013258331Smarkj } 1014258331Smarkj } 1015268226Shselasky#endif 1016258331Smarkj _IF_ENQUEUE(&ue->ue_rxq, m); 1017258331Smarkj} 1018258331Smarkj 1019258331Smarkjstatic void 1020258331Smarkjaxge_csum_cfg(struct usb_ether *ue) 1021258331Smarkj{ 1022258331Smarkj struct axge_softc *sc; 1023258331Smarkj struct ifnet *ifp; 1024258331Smarkj uint8_t csum; 1025258331Smarkj 1026258331Smarkj sc = uether_getsc(ue); 1027258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 1028258331Smarkj ifp = uether_getifp(ue); 1029258331Smarkj 1030258331Smarkj csum = 0; 1031258331Smarkj if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 1032268226Shselasky csum |= CTCR_IP | CTCR_TCP | CTCR_UDP; 1033268226Shselasky axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CTCR, csum); 1034258331Smarkj 1035258331Smarkj csum = 0; 1036258331Smarkj if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 1037268226Shselasky csum |= CRCR_IP | CRCR_TCP | CRCR_UDP; 1038268226Shselasky axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CRCR, csum); 1039258331Smarkj} 1040