1258331Smarkj/*- 2266991Skevlo * 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), 69266991Skevlo AXGE_DEV(DLINK, DUB1312), 70266991Skevlo AXGE_DEV(SITECOMEU, LN032), 71258331Smarkj#undef AXGE_DEV 72258331Smarkj}; 73258331Smarkj 74258331Smarkjstatic const struct { 75266991Skevlo uint8_t ctrl; 76266991Skevlo uint8_t timer_l; 77266991Skevlo uint8_t timer_h; 78266991Skevlo uint8_t size; 79266991Skevlo uint8_t ifg; 80268737Shselasky} __packed axge_bulk_size[] = { 81266991Skevlo { 7, 0x4f, 0x00, 0x12, 0xff }, 82266991Skevlo { 7, 0x20, 0x03, 0x16, 0xff }, 83266991Skevlo { 7, 0xae, 0x07, 0x18, 0xff }, 84266991Skevlo { 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); 112266991Skevlostatic 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, 116266991Skevlo 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); 126268219Shselaskystatic void axge_rx_frame(struct usb_ether *, struct usb_page_cache *, int); 127268219Shselaskystatic void axge_rxeof(struct usb_ether *, struct usb_page_cache *, 128266991Skevlo 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, 147266991Skevlo .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, 156268737Shselasky .bufsize = 65536, 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 242266991Skevlostatic uint8_t 243266991Skevloaxge_read_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t reg) 244266991Skevlo{ 245266991Skevlo uint8_t val; 246266991Skevlo 247266991Skevlo axge_read_mem(sc, cmd, 1, reg, &val, 1); 248266991Skevlo return (val); 249266991Skevlo} 250266991Skevlo 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 262266991Skevloaxge_write_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t reg, uint8_t val) 263258331Smarkj{ 264266991Skevlo 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; 324266991Skevlo 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 357266991Skevlo link_status = axge_read_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PLSR); 358266991Skevlo 359258331Smarkj val = 0; 360258331Smarkj if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 361266991Skevlo val |= MSR_FD; 362258331Smarkj if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) 363266991Skevlo val |= MSR_TFC; 364258331Smarkj if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) 365266991Skevlo val |= MSR_RFC; 366258331Smarkj } 367266991Skevlo val |= MSR_RE; 368258331Smarkj switch (IFM_SUBTYPE(mii->mii_media_active)) { 369258331Smarkj case IFM_1000_T: 370266991Skevlo val |= MSR_GM | MSR_EN_125MHZ; 371266991Skevlo if (link_status & PLSR_USB_SS) 372266991Skevlo memcpy(tmp, &axge_bulk_size[0], 5); 373266991Skevlo else if (link_status & PLSR_USB_HS) 374266991Skevlo memcpy(tmp, &axge_bulk_size[1], 5); 375266991Skevlo else 376266991Skevlo memcpy(tmp, &axge_bulk_size[3], 5); 377266991Skevlo break; 378258331Smarkj case IFM_100_TX: 379266991Skevlo val |= MSR_PS; 380266991Skevlo if (link_status & (PLSR_USB_SS | PLSR_USB_HS)) 381266991Skevlo memcpy(tmp, &axge_bulk_size[2], 5); 382266991Skevlo else 383266991Skevlo memcpy(tmp, &axge_bulk_size[3], 5); 384266991Skevlo break; 385258331Smarkj case IFM_10_T: 386266991Skevlo memcpy(tmp, &axge_bulk_size[3], 5); 387258331Smarkj break; 388258331Smarkj } 389266991Skevlo /* Rx bulk configuration. */ 390266991Skevlo axge_write_mem(sc, AXGE_ACCESS_MAC, 5, AXGE_RX_BULKIN_QCTRL, tmp, 5); 391266991Skevlo 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. */ 401266991Skevlo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR, 0); 402266991Skevlo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR, EPPRCR_IPRL); 403258331Smarkj uether_pause(&sc->sc_ue, hz / 4); 404266991Skevlo 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); 439266991Skevlo 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, 467266991Skevlo 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); 608268219Shselasky 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); 616268737Shselasky break; 617258331Smarkj 618258331Smarkj default: 619258331Smarkj if (error != USB_ERR_CANCELLED) { 620258331Smarkj usbd_xfer_set_stall(xfer); 621258331Smarkj goto tr_setup; 622258331Smarkj } 623268737Shselasky break; 624258331Smarkj } 625258331Smarkj} 626258331Smarkj 627258331Smarkjstatic void 628258331Smarkjaxge_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 629258331Smarkj{ 630258331Smarkj struct axge_softc *sc; 631258331Smarkj struct ifnet *ifp; 632258331Smarkj struct usb_page_cache *pc; 633258331Smarkj struct mbuf *m; 634258331Smarkj uint32_t txhdr; 635266991Skevlo int nframes, pos; 636258331Smarkj 637258331Smarkj sc = usbd_xfer_softc(xfer); 638258331Smarkj ifp = uether_getifp(&sc->sc_ue); 639258331Smarkj 640258331Smarkj switch (USB_GET_STATE(xfer)) { 641258331Smarkj case USB_ST_TRANSFERRED: 642258331Smarkj ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 643258331Smarkj /* FALLTHROUGH */ 644258331Smarkj case USB_ST_SETUP: 645258331Smarkjtr_setup: 646258331Smarkj if ((sc->sc_flags & AXGE_FLAG_LINK) == 0 || 647258331Smarkj (ifp->if_drv_flags & IFF_DRV_OACTIVE) != 0) { 648258331Smarkj /* 649258331Smarkj * Don't send anything if there is no link or 650258331Smarkj * controller is busy. 651258331Smarkj */ 652258331Smarkj return; 653258331Smarkj } 654258331Smarkj 655258331Smarkj for (nframes = 0; nframes < 16 && 656258331Smarkj !IFQ_DRV_IS_EMPTY(&ifp->if_snd); nframes++) { 657258331Smarkj IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 658258331Smarkj if (m == NULL) 659258331Smarkj break; 660258331Smarkj usbd_xfer_set_frame_offset(xfer, nframes * MCLBYTES, 661258331Smarkj nframes); 662266991Skevlo pos = 0; 663258331Smarkj pc = usbd_xfer_get_frame(xfer, nframes); 664266991Skevlo txhdr = htole32(m->m_pkthdr.len); 665266991Skevlo usbd_copy_in(pc, 0, &txhdr, sizeof(txhdr)); 666266991Skevlo txhdr = 0; 667258331Smarkj txhdr = htole32(txhdr); 668266991Skevlo usbd_copy_in(pc, 4, &txhdr, sizeof(txhdr)); 669266991Skevlo pos += 8; 670266991Skevlo usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len); 671266991Skevlo pos += m->m_pkthdr.len; 672266991Skevlo if ((pos % usbd_xfer_max_framelen(xfer)) == 0) 673266991Skevlo txhdr |= 0x80008000; 674258331Smarkj 675258331Smarkj /* 676258331Smarkj * XXX 677258331Smarkj * Update TX packet counter here. This is not 678258331Smarkj * correct way but it seems that there is no way 679258331Smarkj * to know how many packets are sent at the end 680258331Smarkj * of transfer because controller combines 681258331Smarkj * multiple writes into single one if there is 682258331Smarkj * room in TX buffer of controller. 683258331Smarkj */ 684258331Smarkj ifp->if_opackets++; 685258331Smarkj 686258331Smarkj /* 687258331Smarkj * if there's a BPF listener, bounce a copy 688258331Smarkj * of this frame to him: 689258331Smarkj */ 690258331Smarkj BPF_MTAP(ifp, m); 691258331Smarkj 692258331Smarkj m_freem(m); 693258331Smarkj 694258331Smarkj /* Set frame length. */ 695266991Skevlo usbd_xfer_set_frame_len(xfer, nframes, pos); 696258331Smarkj } 697258331Smarkj if (nframes != 0) { 698258331Smarkj usbd_xfer_set_frames(xfer, nframes); 699258331Smarkj usbd_transfer_submit(xfer); 700258331Smarkj ifp->if_drv_flags |= IFF_DRV_OACTIVE; 701258331Smarkj } 702258331Smarkj return; 703258331Smarkj /* NOTREACHED */ 704258331Smarkj default: 705258331Smarkj ifp->if_oerrors++; 706258331Smarkj ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 707258331Smarkj 708258331Smarkj if (error != USB_ERR_CANCELLED) { 709258331Smarkj usbd_xfer_set_stall(xfer); 710258331Smarkj goto tr_setup; 711258331Smarkj } 712258331Smarkj return; 713258331Smarkj 714258331Smarkj } 715258331Smarkj} 716258331Smarkj 717258331Smarkjstatic void 718258331Smarkjaxge_tick(struct usb_ether *ue) 719258331Smarkj{ 720258331Smarkj struct axge_softc *sc; 721258331Smarkj struct mii_data *mii; 722258331Smarkj 723258331Smarkj sc = uether_getsc(ue); 724258331Smarkj mii = GET_MII(sc); 725258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 726258331Smarkj 727258331Smarkj mii_tick(mii); 728258331Smarkj if ((sc->sc_flags & AXGE_FLAG_LINK) == 0) { 729258331Smarkj axge_miibus_statchg(ue->ue_dev); 730258331Smarkj if ((sc->sc_flags & AXGE_FLAG_LINK) != 0) 731258331Smarkj axge_start(ue); 732258331Smarkj } 733258331Smarkj} 734258331Smarkj 735258331Smarkjstatic void 736258331Smarkjaxge_setmulti(struct usb_ether *ue) 737258331Smarkj{ 738258331Smarkj struct axge_softc *sc; 739258331Smarkj struct ifnet *ifp; 740258331Smarkj struct ifmultiaddr *ifma; 741258331Smarkj uint32_t h; 742258331Smarkj uint16_t rxmode; 743258331Smarkj uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 744258331Smarkj 745258331Smarkj sc = uether_getsc(ue); 746258331Smarkj ifp = uether_getifp(ue); 747258331Smarkj h = 0; 748258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 749258331Smarkj 750266991Skevlo rxmode = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR); 751258331Smarkj if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { 752266991Skevlo rxmode |= RCR_AMALL; 753266991Skevlo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); 754258331Smarkj return; 755258331Smarkj } 756266991Skevlo rxmode &= ~RCR_AMALL; 757258331Smarkj 758258331Smarkj if_maddr_rlock(ifp); 759258331Smarkj TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 760258331Smarkj if (ifma->ifma_addr->sa_family != AF_LINK) 761258331Smarkj continue; 762258331Smarkj h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 763258331Smarkj ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 764258331Smarkj hashtbl[h / 8] |= 1 << (h % 8); 765258331Smarkj } 766258331Smarkj if_maddr_runlock(ifp); 767258331Smarkj 768266991Skevlo axge_write_mem(sc, AXGE_ACCESS_MAC, 8, AXGE_MFA, (void *)&hashtbl, 8); 769266991Skevlo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); 770258331Smarkj} 771258331Smarkj 772258331Smarkjstatic void 773258331Smarkjaxge_setpromisc(struct usb_ether *ue) 774258331Smarkj{ 775258331Smarkj struct axge_softc *sc; 776258331Smarkj struct ifnet *ifp; 777258331Smarkj uint16_t rxmode; 778258331Smarkj 779258331Smarkj sc = uether_getsc(ue); 780258331Smarkj ifp = uether_getifp(ue); 781266991Skevlo rxmode = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR); 782258331Smarkj 783258331Smarkj if (ifp->if_flags & IFF_PROMISC) 784266991Skevlo rxmode |= RCR_PRO; 785258331Smarkj else 786266991Skevlo rxmode &= ~RCR_PRO; 787258331Smarkj 788266991Skevlo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); 789258331Smarkj axge_setmulti(ue); 790258331Smarkj} 791258331Smarkj 792258331Smarkjstatic void 793258331Smarkjaxge_start(struct usb_ether *ue) 794258331Smarkj{ 795258331Smarkj struct axge_softc *sc; 796258331Smarkj 797258331Smarkj sc = uether_getsc(ue); 798258331Smarkj /* 799258331Smarkj * Start the USB transfers, if not already started. 800258331Smarkj */ 801258331Smarkj usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_RD]); 802258331Smarkj usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_WR]); 803258331Smarkj} 804258331Smarkj 805258331Smarkjstatic void 806258331Smarkjaxge_init(struct usb_ether *ue) 807258331Smarkj{ 808258331Smarkj struct axge_softc *sc; 809258331Smarkj struct ifnet *ifp; 810258331Smarkj uint16_t rxmode; 811258331Smarkj 812258331Smarkj sc = uether_getsc(ue); 813258331Smarkj ifp = uether_getifp(ue); 814258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 815258331Smarkj 816258331Smarkj if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 817258331Smarkj return; 818258331Smarkj 819258331Smarkj /* 820258331Smarkj * Cancel pending I/O and free all RX/TX buffers. 821258331Smarkj */ 822258331Smarkj axge_stop(ue); 823258331Smarkj 824258331Smarkj axge_reset(sc); 825258331Smarkj 826258331Smarkj /* Set MAC address. */ 827266991Skevlo axge_write_mem(sc, AXGE_ACCESS_MAC, ETHER_ADDR_LEN, AXGE_NIDR, 828258331Smarkj IF_LLADDR(ifp), ETHER_ADDR_LEN); 829258331Smarkj 830266991Skevlo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PWLLR, 0x34); 831266991Skevlo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PWLHR, 0x52); 832258331Smarkj 833258331Smarkj /* Configure TX/RX checksum offloading. */ 834258331Smarkj axge_csum_cfg(ue); 835258331Smarkj 836258331Smarkj /* Configure RX settings. */ 837266991Skevlo rxmode = (RCR_AM | RCR_SO | RCR_DROP_CRCE); 838266991Skevlo if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 839266991Skevlo rxmode |= RCR_IPE; 840258331Smarkj 841258331Smarkj /* If we want promiscuous mode, set the allframes bit. */ 842258331Smarkj if (ifp->if_flags & IFF_PROMISC) 843266991Skevlo rxmode |= RCR_PRO; 844258331Smarkj 845258331Smarkj if (ifp->if_flags & IFF_BROADCAST) 846266991Skevlo rxmode |= RCR_AB; 847258331Smarkj 848266991Skevlo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); 849258331Smarkj 850266991Skevlo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_MMSR, 851266991Skevlo MMSR_PME_TYPE | MMSR_PME_POL | MMSR_RWMP); 852266991Skevlo 853258331Smarkj /* Load the multicast filter. */ 854258331Smarkj axge_setmulti(ue); 855258331Smarkj 856258331Smarkj usbd_xfer_set_stall(sc->sc_xfer[AXGE_BULK_DT_WR]); 857258331Smarkj 858258331Smarkj ifp->if_drv_flags |= IFF_DRV_RUNNING; 859258331Smarkj /* Switch to selected media. */ 860258331Smarkj axge_ifmedia_upd(ifp); 861258331Smarkj} 862258331Smarkj 863258331Smarkjstatic void 864258331Smarkjaxge_stop(struct usb_ether *ue) 865258331Smarkj{ 866258331Smarkj struct axge_softc *sc; 867258331Smarkj struct ifnet *ifp; 868258331Smarkj 869258331Smarkj sc = uether_getsc(ue); 870258331Smarkj ifp = uether_getifp(ue); 871258331Smarkj 872258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 873258331Smarkj 874258331Smarkj ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 875258331Smarkj sc->sc_flags &= ~AXGE_FLAG_LINK; 876258331Smarkj 877258331Smarkj /* 878258331Smarkj * Stop all the transfers, if not already stopped: 879258331Smarkj */ 880258331Smarkj usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_WR]); 881258331Smarkj usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_RD]); 882258331Smarkj} 883258331Smarkj 884258331Smarkjstatic int 885258331Smarkjaxge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 886258331Smarkj{ 887258331Smarkj struct usb_ether *ue; 888258331Smarkj struct axge_softc *sc; 889258331Smarkj struct ifreq *ifr; 890258331Smarkj int error, mask, reinit; 891258331Smarkj 892258331Smarkj ue = ifp->if_softc; 893258331Smarkj sc = uether_getsc(ue); 894258331Smarkj ifr = (struct ifreq *)data; 895258331Smarkj error = 0; 896258331Smarkj reinit = 0; 897258331Smarkj if (cmd == SIOCSIFCAP) { 898258331Smarkj AXGE_LOCK(sc); 899258331Smarkj mask = ifr->ifr_reqcap ^ ifp->if_capenable; 900258331Smarkj if ((mask & IFCAP_TXCSUM) != 0 && 901258331Smarkj (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { 902258331Smarkj ifp->if_capenable ^= IFCAP_TXCSUM; 903258331Smarkj if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 904258331Smarkj ifp->if_hwassist |= AXGE_CSUM_FEATURES; 905258331Smarkj else 906258331Smarkj ifp->if_hwassist &= ~AXGE_CSUM_FEATURES; 907258331Smarkj reinit++; 908258331Smarkj } 909258331Smarkj if ((mask & IFCAP_RXCSUM) != 0 && 910258331Smarkj (ifp->if_capabilities & IFCAP_RXCSUM) != 0) { 911258331Smarkj ifp->if_capenable ^= IFCAP_RXCSUM; 912258331Smarkj reinit++; 913258331Smarkj } 914258331Smarkj if (reinit > 0 && ifp->if_drv_flags & IFF_DRV_RUNNING) 915258331Smarkj ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 916258331Smarkj else 917258331Smarkj reinit = 0; 918258331Smarkj AXGE_UNLOCK(sc); 919258331Smarkj if (reinit > 0) 920258331Smarkj uether_init(ue); 921258331Smarkj } else 922258331Smarkj error = uether_ioctl(ifp, cmd, data); 923258331Smarkj 924258331Smarkj return (error); 925258331Smarkj} 926258331Smarkj 927268219Shselaskystatic void 928258331Smarkjaxge_rx_frame(struct usb_ether *ue, struct usb_page_cache *pc, int actlen) 929258331Smarkj{ 930268219Shselasky uint32_t pos; 931268219Shselasky uint32_t pkt_cnt; 932268219Shselasky uint32_t rxhdr; 933268219Shselasky uint32_t pkt_hdr; 934268219Shselasky uint32_t hdr_off; 935268219Shselasky uint32_t pktlen; 936258331Smarkj 937268219Shselasky /* verify we have enough data */ 938268219Shselasky if (actlen < (int)sizeof(rxhdr)) 939268219Shselasky return; 940268219Shselasky 941258331Smarkj pos = 0; 942258331Smarkj 943258331Smarkj usbd_copy_out(pc, actlen - sizeof(rxhdr), &rxhdr, sizeof(rxhdr)); 944258331Smarkj rxhdr = le32toh(rxhdr); 945258331Smarkj 946258331Smarkj pkt_cnt = (uint16_t)rxhdr; 947258331Smarkj hdr_off = (uint16_t)(rxhdr >> 16); 948258331Smarkj 949268219Shselasky while (pkt_cnt--) { 950268219Shselasky /* verify the header offset */ 951268219Shselasky if ((int)(hdr_off + sizeof(pkt_hdr)) > actlen) { 952268219Shselasky DPRINTF("End of packet headers\n"); 953258331Smarkj break; 954258331Smarkj } 955268219Shselasky if ((int)pos >= actlen) { 956268219Shselasky DPRINTF("Data position reached end\n"); 957268219Shselasky break; 958268219Shselasky } 959268219Shselasky usbd_copy_out(pc, hdr_off, &pkt_hdr, sizeof(pkt_hdr)); 960268219Shselasky 961266991Skevlo pkt_hdr = le32toh(pkt_hdr); 962266991Skevlo pktlen = (pkt_hdr >> 16) & 0x1fff; 963268219Shselasky if (pkt_hdr & (AXGE_RXHDR_CRC_ERR | AXGE_RXHDR_DROP_ERR)) { 964268219Shselasky DPRINTF("Dropped a packet\n"); 965266991Skevlo ue->ue_ifp->if_ierrors++; 966268219Shselasky } 967268737Shselasky if (pktlen >= 6 && (int)(pos + pktlen) <= actlen) { 968268737Shselasky axge_rxeof(ue, pc, pos + 2, pktlen - 6, pkt_hdr); 969268219Shselasky } else { 970268219Shselasky DPRINTF("Invalid packet pos=%d len=%d\n", 971268219Shselasky (int)pos, (int)pktlen); 972268219Shselasky } 973268219Shselasky pos += (pktlen + 7) & ~7; 974268219Shselasky hdr_off += sizeof(pkt_hdr); 975258331Smarkj } 976258331Smarkj} 977258331Smarkj 978268219Shselaskystatic void 979258331Smarkjaxge_rxeof(struct usb_ether *ue, struct usb_page_cache *pc, 980266991Skevlo unsigned int offset, unsigned int len, uint32_t pkt_hdr) 981258331Smarkj{ 982258331Smarkj struct ifnet *ifp; 983258331Smarkj struct mbuf *m; 984258331Smarkj 985258331Smarkj ifp = ue->ue_ifp; 986258331Smarkj if (len < ETHER_HDR_LEN || len > MCLBYTES - ETHER_ALIGN) { 987258331Smarkj ifp->if_ierrors++; 988268219Shselasky return; 989258331Smarkj } 990258331Smarkj 991258331Smarkj m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 992258331Smarkj if (m == NULL) { 993258331Smarkj ifp->if_iqdrops++; 994268219Shselasky return; 995258331Smarkj } 996268219Shselasky m->m_pkthdr.rcvif = ifp; 997268219Shselasky m->m_len = m->m_pkthdr.len = len + ETHER_ALIGN; 998258331Smarkj m_adj(m, ETHER_ALIGN); 999258331Smarkj 1000258331Smarkj usbd_copy_out(pc, offset, mtod(m, uint8_t *), len); 1001258331Smarkj 1002258331Smarkj ifp->if_ipackets++; 1003268737Shselasky 1004266991Skevlo if ((pkt_hdr & (AXGE_RXHDR_L4CSUM_ERR | AXGE_RXHDR_L3CSUM_ERR)) == 0) { 1005266991Skevlo if ((pkt_hdr & AXGE_RXHDR_L4_TYPE_MASK) == 1006266991Skevlo AXGE_RXHDR_L4_TYPE_TCP || 1007266991Skevlo (pkt_hdr & AXGE_RXHDR_L4_TYPE_MASK) == 1008266991Skevlo AXGE_RXHDR_L4_TYPE_UDP) { 1009266991Skevlo m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | 1010268219Shselasky CSUM_PSEUDO_HDR | CSUM_IP_CHECKED | CSUM_IP_VALID; 1011266991Skevlo m->m_pkthdr.csum_data = 0xffff; 1012258331Smarkj } 1013258331Smarkj } 1014268737Shselasky 1015258331Smarkj _IF_ENQUEUE(&ue->ue_rxq, m); 1016258331Smarkj} 1017258331Smarkj 1018258331Smarkjstatic void 1019258331Smarkjaxge_csum_cfg(struct usb_ether *ue) 1020258331Smarkj{ 1021258331Smarkj struct axge_softc *sc; 1022258331Smarkj struct ifnet *ifp; 1023258331Smarkj uint8_t csum; 1024258331Smarkj 1025258331Smarkj sc = uether_getsc(ue); 1026258331Smarkj AXGE_LOCK_ASSERT(sc, MA_OWNED); 1027258331Smarkj ifp = uether_getifp(ue); 1028258331Smarkj 1029258331Smarkj csum = 0; 1030258331Smarkj if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 1031266991Skevlo csum |= CTCR_IP | CTCR_TCP | CTCR_UDP; 1032266991Skevlo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CTCR, csum); 1033258331Smarkj 1034258331Smarkj csum = 0; 1035258331Smarkj if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 1036266991Skevlo csum |= CRCR_IP | CRCR_TCP | CRCR_UDP; 1037266991Skevlo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CRCR, csum); 1038258331Smarkj} 1039