if_axe.c revision 192984
1184610Salfred/*- 2184610Salfred * Copyright (c) 1997, 1998, 1999, 2000-2003 3184610Salfred * Bill Paul <wpaul@windriver.com>. All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 1. Redistributions of source code must retain the above copyright 9184610Salfred * notice, this list of conditions and the following disclaimer. 10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer in the 12184610Salfred * documentation and/or other materials provided with the distribution. 13184610Salfred * 3. All advertising materials mentioning features or use of this software 14184610Salfred * must display the following acknowledgement: 15184610Salfred * This product includes software developed by Bill Paul. 16184610Salfred * 4. Neither the name of the author nor the names of any co-contributors 17184610Salfred * may be used to endorse or promote products derived from this software 18184610Salfred * without specific prior written permission. 19184610Salfred * 20184610Salfred * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30184610Salfred * THE POSSIBILITY OF SUCH DAMAGE. 31184610Salfred */ 32184610Salfred 33184610Salfred#include <sys/cdefs.h> 34184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_axe.c 192984 2009-05-28 17:36:36Z thompsa $"); 35184610Salfred 36184610Salfred/* 37188412Sthompsa * ASIX Electronics AX88172/AX88178/AX88778 USB 2.0 ethernet driver. 38188412Sthompsa * Used in the LinkSys USB200M and various other adapters. 39184610Salfred * 40184610Salfred * Manuals available from: 41184610Salfred * http://www.asix.com.tw/datasheet/mac/Ax88172.PDF 42184610Salfred * Note: you need the manual for the AX88170 chip (USB 1.x ethernet 43184610Salfred * controller) to find the definitions for the RX control register. 44184610Salfred * http://www.asix.com.tw/datasheet/mac/Ax88170.PDF 45184610Salfred * 46184610Salfred * Written by Bill Paul <wpaul@windriver.com> 47184610Salfred * Senior Engineer 48184610Salfred * Wind River Systems 49184610Salfred */ 50184610Salfred 51184610Salfred/* 52184610Salfred * The AX88172 provides USB ethernet supports at 10 and 100Mbps. 53184610Salfred * It uses an external PHY (reference designs use a RealTek chip), 54184610Salfred * and has a 64-bit multicast hash filter. There is some information 55184610Salfred * missing from the manual which one needs to know in order to make 56184610Salfred * the chip function: 57184610Salfred * 58184610Salfred * - You must set bit 7 in the RX control register, otherwise the 59184610Salfred * chip won't receive any packets. 60184610Salfred * - You must initialize all 3 IPG registers, or you won't be able 61184610Salfred * to send any packets. 62184610Salfred * 63184610Salfred * Note that this device appears to only support loading the station 64184610Salfred * address via autload from the EEPROM (i.e. there's no way to manaully 65184610Salfred * set it). 66184610Salfred * 67184610Salfred * (Adam Weinberger wanted me to name this driver if_gir.c.) 68184610Salfred */ 69184610Salfred 70184610Salfred/* 71184610Salfred * Ax88178 and Ax88772 support backported from the OpenBSD driver. 72184610Salfred * 2007/02/12, J.R. Oldroyd, fbsd@opal.com 73184610Salfred * 74184610Salfred * Manual here: 75184610Salfred * http://www.asix.com.tw/FrootAttach/datasheet/AX88178_datasheet_Rev10.pdf 76184610Salfred * http://www.asix.com.tw/FrootAttach/datasheet/AX88772_datasheet_Rev10.pdf 77184610Salfred */ 78184610Salfred 79188746Sthompsa#include "usbdevs.h" 80188942Sthompsa#include <dev/usb/usb.h> 81188942Sthompsa#include <dev/usb/usb_mfunc.h> 82188942Sthompsa#include <dev/usb/usb_error.h> 83184610Salfred 84184610Salfred#define USB_DEBUG_VAR axe_debug 85184610Salfred 86188942Sthompsa#include <dev/usb/usb_core.h> 87188942Sthompsa#include <dev/usb/usb_lookup.h> 88188942Sthompsa#include <dev/usb/usb_process.h> 89188942Sthompsa#include <dev/usb/usb_debug.h> 90188942Sthompsa#include <dev/usb/usb_request.h> 91188942Sthompsa#include <dev/usb/usb_busdma.h> 92188942Sthompsa#include <dev/usb/usb_util.h> 93184610Salfred 94188942Sthompsa#include <dev/usb/net/usb_ethernet.h> 95188942Sthompsa#include <dev/usb/net/if_axereg.h> 96184610Salfred 97188412Sthompsa/* 98188412Sthompsa * AXE_178_MAX_FRAME_BURST 99188412Sthompsa * max frame burst size for Ax88178 and Ax88772 100188412Sthompsa * 0 2048 bytes 101188412Sthompsa * 1 4096 bytes 102188412Sthompsa * 2 8192 bytes 103188412Sthompsa * 3 16384 bytes 104188412Sthompsa * use the largest your system can handle without USB stalling. 105188412Sthompsa * 106188412Sthompsa * NB: 88772 parts appear to generate lots of input errors with 107188412Sthompsa * a 2K rx buffer and 8K is only slightly faster than 4K on an 108188412Sthompsa * EHCI port on a T42 so change at your own risk. 109188412Sthompsa */ 110188412Sthompsa#define AXE_178_MAX_FRAME_BURST 1 111184610Salfred 112184610Salfred#if USB_DEBUG 113184610Salfredstatic int axe_debug = 0; 114184610Salfred 115192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, axe, CTLFLAG_RW, 0, "USB axe"); 116192502SthompsaSYSCTL_INT(_hw_usb_axe, OID_AUTO, debug, CTLFLAG_RW, &axe_debug, 0, 117184610Salfred "Debug level"); 118184610Salfred#endif 119184610Salfred 120184610Salfred/* 121184610Salfred * Various supported device vendors/products. 122184610Salfred */ 123192984Sthompsastatic const struct usb_device_id axe_devs[] = { 124184610Salfred {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UF200, 0)}, 125184610Salfred {USB_VPI(USB_VENDOR_ACERCM, USB_PRODUCT_ACERCM_EP1427X2, 0)}, 126184610Salfred {USB_VPI(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_ETHERNET, AXE_FLAG_772)}, 127184610Salfred {USB_VPI(USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88172, 0)}, 128184610Salfred {USB_VPI(USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178, AXE_FLAG_178)}, 129184610Salfred {USB_VPI(USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772, AXE_FLAG_772)}, 130184610Salfred {USB_VPI(USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC210T, 0)}, 131184610Salfred {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D5055, AXE_FLAG_178)}, 132184610Salfred {USB_VPI(USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB2AR, 0)}, 133184610Salfred {USB_VPI(USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_USB200MV2, AXE_FLAG_772)}, 134184610Salfred {USB_VPI(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB2_TX, 0)}, 135184610Salfred {USB_VPI(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100, 0)}, 136184610Salfred {USB_VPI(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100B1, AXE_FLAG_772)}, 137184610Salfred {USB_VPI(USB_VENDOR_GOODWAY, USB_PRODUCT_GOODWAY_GWUSB2E, 0)}, 138184610Salfred {USB_VPI(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETGUS2, AXE_FLAG_178)}, 139184610Salfred {USB_VPI(USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_PRX1, 0)}, 140184610Salfred {USB_VPI(USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_USB200M, 0)}, 141184610Salfred {USB_VPI(USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_USB1000, AXE_FLAG_178)}, 142184610Salfred {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2KTX, 0)}, 143184610Salfred {USB_VPI(USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA120, 0)}, 144184610Salfred {USB_VPI(USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01PLUS, AXE_FLAG_772)}, 145184610Salfred {USB_VPI(USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GU1000T, AXE_FLAG_178)}, 146184610Salfred {USB_VPI(USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_LN029, 0)}, 147184610Salfred {USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN028, AXE_FLAG_178)}, 148184610Salfred {USB_VPI(USB_VENDOR_SYSTEMTALKS, USB_PRODUCT_SYSTEMTALKS_SGCX2UL, 0)}, 149184610Salfred}; 150184610Salfred 151184610Salfredstatic device_probe_t axe_probe; 152184610Salfredstatic device_attach_t axe_attach; 153184610Salfredstatic device_detach_t axe_detach; 154184610Salfred 155184610Salfredstatic usb2_callback_t axe_intr_callback; 156184610Salfredstatic usb2_callback_t axe_bulk_read_callback; 157184610Salfredstatic usb2_callback_t axe_bulk_write_callback; 158184610Salfred 159188412Sthompsastatic miibus_readreg_t axe_miibus_readreg; 160188412Sthompsastatic miibus_writereg_t axe_miibus_writereg; 161188412Sthompsastatic miibus_statchg_t axe_miibus_statchg; 162184610Salfred 163188412Sthompsastatic usb2_ether_fn_t axe_attach_post; 164188412Sthompsastatic usb2_ether_fn_t axe_init; 165188412Sthompsastatic usb2_ether_fn_t axe_stop; 166188412Sthompsastatic usb2_ether_fn_t axe_start; 167188412Sthompsastatic usb2_ether_fn_t axe_tick; 168188412Sthompsastatic usb2_ether_fn_t axe_setmulti; 169188412Sthompsastatic usb2_ether_fn_t axe_setpromisc; 170184610Salfred 171188412Sthompsastatic int axe_ifmedia_upd(struct ifnet *); 172188412Sthompsastatic void axe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 173188412Sthompsastatic int axe_cmd(struct axe_softc *, int, int, int, void *); 174188412Sthompsastatic void axe_ax88178_init(struct axe_softc *); 175188412Sthompsastatic void axe_ax88772_init(struct axe_softc *); 176186730Salfredstatic int axe_get_phyno(struct axe_softc *, int); 177184610Salfred 178192984Sthompsastatic const struct usb_config axe_config[AXE_N_TRANSFER] = { 179184610Salfred 180187259Sthompsa [AXE_BULK_DT_WR] = { 181184610Salfred .type = UE_BULK, 182184610Salfred .endpoint = UE_ADDR_ANY, 183184610Salfred .direction = UE_DIR_OUT, 184190734Sthompsa .bufsize = AXE_BULK_BUF_SIZE, 185190734Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 186190734Sthompsa .callback = axe_bulk_write_callback, 187190734Sthompsa .timeout = 10000, /* 10 seconds */ 188184610Salfred }, 189184610Salfred 190187259Sthompsa [AXE_BULK_DT_RD] = { 191184610Salfred .type = UE_BULK, 192184610Salfred .endpoint = UE_ADDR_ANY, 193184610Salfred .direction = UE_DIR_IN, 194184610Salfred#if (MCLBYTES < 2048) 195184610Salfred#error "(MCLBYTES < 2048)" 196184610Salfred#endif 197190734Sthompsa .bufsize = MCLBYTES, 198190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 199190734Sthompsa .callback = axe_bulk_read_callback, 200190734Sthompsa .timeout = 0, /* no timeout */ 201184610Salfred }, 202184610Salfred 203187259Sthompsa [AXE_INTR_DT_RD] = { 204184610Salfred .type = UE_INTERRUPT, 205184610Salfred .endpoint = UE_ADDR_ANY, 206184610Salfred .direction = UE_DIR_IN, 207190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 208190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 209190734Sthompsa .callback = axe_intr_callback, 210184610Salfred }, 211184610Salfred}; 212184610Salfred 213184610Salfredstatic device_method_t axe_methods[] = { 214184610Salfred /* Device interface */ 215184610Salfred DEVMETHOD(device_probe, axe_probe), 216184610Salfred DEVMETHOD(device_attach, axe_attach), 217184610Salfred DEVMETHOD(device_detach, axe_detach), 218184610Salfred 219184610Salfred /* bus interface */ 220184610Salfred DEVMETHOD(bus_print_child, bus_generic_print_child), 221184610Salfred DEVMETHOD(bus_driver_added, bus_generic_driver_added), 222184610Salfred 223184610Salfred /* MII interface */ 224188412Sthompsa DEVMETHOD(miibus_readreg, axe_miibus_readreg), 225188412Sthompsa DEVMETHOD(miibus_writereg, axe_miibus_writereg), 226188412Sthompsa DEVMETHOD(miibus_statchg, axe_miibus_statchg), 227184610Salfred 228184610Salfred {0, 0} 229184610Salfred}; 230184610Salfred 231184610Salfredstatic driver_t axe_driver = { 232184610Salfred .name = "axe", 233184610Salfred .methods = axe_methods, 234184610Salfred .size = sizeof(struct axe_softc), 235184610Salfred}; 236184610Salfred 237184610Salfredstatic devclass_t axe_devclass; 238184610Salfred 239189275SthompsaDRIVER_MODULE(axe, uhub, axe_driver, axe_devclass, NULL, 0); 240184610SalfredDRIVER_MODULE(miibus, axe, miibus_driver, miibus_devclass, 0, 0); 241188942SthompsaMODULE_DEPEND(axe, uether, 1, 1, 1); 242188942SthompsaMODULE_DEPEND(axe, usb, 1, 1, 1); 243188412SthompsaMODULE_DEPEND(axe, ether, 1, 1, 1); 244188412SthompsaMODULE_DEPEND(axe, miibus, 1, 1, 1); 245184610Salfred 246192984Sthompsastatic const struct usb_ether_methods axe_ue_methods = { 247188412Sthompsa .ue_attach_post = axe_attach_post, 248188412Sthompsa .ue_start = axe_start, 249188412Sthompsa .ue_init = axe_init, 250188412Sthompsa .ue_stop = axe_stop, 251188412Sthompsa .ue_tick = axe_tick, 252188412Sthompsa .ue_setmulti = axe_setmulti, 253188412Sthompsa .ue_setpromisc = axe_setpromisc, 254188412Sthompsa .ue_mii_upd = axe_ifmedia_upd, 255188412Sthompsa .ue_mii_sts = axe_ifmedia_sts, 256188412Sthompsa}; 257188412Sthompsa 258188412Sthompsastatic int 259188412Sthompsaaxe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf) 260184610Salfred{ 261192984Sthompsa struct usb_device_request req; 262184610Salfred usb2_error_t err; 263184610Salfred 264188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 265188412Sthompsa 266184610Salfred req.bmRequestType = (AXE_CMD_IS_WRITE(cmd) ? 267184610Salfred UT_WRITE_VENDOR_DEVICE : 268184610Salfred UT_READ_VENDOR_DEVICE); 269184610Salfred req.bRequest = AXE_CMD_CMD(cmd); 270184610Salfred USETW(req.wValue, val); 271184610Salfred USETW(req.wIndex, index); 272188412Sthompsa USETW(req.wLength, AXE_CMD_LEN(cmd)); 273184610Salfred 274188412Sthompsa err = usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000); 275184610Salfred 276188412Sthompsa return (err); 277184610Salfred} 278184610Salfred 279184610Salfredstatic int 280188412Sthompsaaxe_miibus_readreg(device_t dev, int phy, int reg) 281184610Salfred{ 282184610Salfred struct axe_softc *sc = device_get_softc(dev); 283184610Salfred uint16_t val; 284188412Sthompsa int locked; 285184610Salfred 286188412Sthompsa if (sc->sc_phyno != phy) 287188412Sthompsa return (0); 288184610Salfred 289188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 290188412Sthompsa if (!locked) 291188412Sthompsa AXE_LOCK(sc); 292186730Salfred 293188412Sthompsa axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); 294188412Sthompsa axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, &val); 295188412Sthompsa axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); 296184610Salfred 297184610Salfred val = le16toh(val); 298186730Salfred if ((sc->sc_flags & AXE_FLAG_772) != 0 && reg == MII_BMSR) { 299186730Salfred /* 300186730Salfred * BMSR of AX88772 indicates that it supports extended 301186730Salfred * capability but the extended status register is 302186730Salfred * revered for embedded ethernet PHY. So clear the 303186730Salfred * extended capability bit of BMSR. 304186730Salfred */ 305186730Salfred val &= ~BMSR_EXTCAP; 306186730Salfred } 307184610Salfred 308188412Sthompsa if (!locked) 309188412Sthompsa AXE_UNLOCK(sc); 310184610Salfred return (val); 311184610Salfred} 312184610Salfred 313184610Salfredstatic int 314188412Sthompsaaxe_miibus_writereg(device_t dev, int phy, int reg, int val) 315184610Salfred{ 316184610Salfred struct axe_softc *sc = device_get_softc(dev); 317188412Sthompsa int locked; 318184610Salfred 319189522Sthompsa val = htole32(val); 320184610Salfred 321186730Salfred if (sc->sc_phyno != phy) 322188412Sthompsa return (0); 323186730Salfred 324188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 325188412Sthompsa if (!locked) 326188412Sthompsa AXE_LOCK(sc); 327184610Salfred 328188412Sthompsa axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); 329188412Sthompsa axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, &val); 330188412Sthompsa axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); 331188412Sthompsa 332188412Sthompsa if (!locked) 333188412Sthompsa AXE_UNLOCK(sc); 334184610Salfred return (0); 335184610Salfred} 336184610Salfred 337184610Salfredstatic void 338188412Sthompsaaxe_miibus_statchg(device_t dev) 339184610Salfred{ 340184610Salfred struct axe_softc *sc = device_get_softc(dev); 341184610Salfred struct mii_data *mii = GET_MII(sc); 342188553Sthompsa struct ifnet *ifp; 343184610Salfred uint16_t val; 344188412Sthompsa int err, locked; 345184610Salfred 346188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 347188412Sthompsa if (!locked) 348188412Sthompsa AXE_LOCK(sc); 349184610Salfred 350188553Sthompsa ifp = usb2_ether_getifp(&sc->sc_ue); 351188553Sthompsa if (mii == NULL || ifp == NULL || 352188553Sthompsa (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 353188553Sthompsa goto done; 354188553Sthompsa 355188553Sthompsa sc->sc_flags &= ~AXE_FLAG_LINK; 356188553Sthompsa if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 357188553Sthompsa (IFM_ACTIVE | IFM_AVALID)) { 358188553Sthompsa switch (IFM_SUBTYPE(mii->mii_media_active)) { 359188553Sthompsa case IFM_10_T: 360188553Sthompsa case IFM_100_TX: 361188553Sthompsa sc->sc_flags |= AXE_FLAG_LINK; 362188553Sthompsa break; 363188553Sthompsa case IFM_1000_T: 364188553Sthompsa if ((sc->sc_flags & AXE_FLAG_178) == 0) 365188553Sthompsa break; 366188553Sthompsa sc->sc_flags |= AXE_FLAG_LINK; 367188553Sthompsa break; 368188553Sthompsa default: 369188553Sthompsa break; 370188553Sthompsa } 371188553Sthompsa } 372188553Sthompsa 373188553Sthompsa /* Lost link, do nothing. */ 374188553Sthompsa if ((sc->sc_flags & AXE_FLAG_LINK) == 0) 375188553Sthompsa goto done; 376188553Sthompsa 377188553Sthompsa val = 0; 378188553Sthompsa if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) 379188553Sthompsa val |= AXE_MEDIA_FULL_DUPLEX; 380186730Salfred if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) { 381186730Salfred val |= AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC; 382188553Sthompsa if ((sc->sc_flags & AXE_FLAG_178) != 0) 383188553Sthompsa val |= AXE_178_MEDIA_ENCK; 384184610Salfred switch (IFM_SUBTYPE(mii->mii_media_active)) { 385184610Salfred case IFM_1000_T: 386184610Salfred val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK; 387184610Salfred break; 388184610Salfred case IFM_100_TX: 389184610Salfred val |= AXE_178_MEDIA_100TX; 390184610Salfred break; 391184610Salfred case IFM_10_T: 392184610Salfred /* doesn't need to be handled */ 393184610Salfred break; 394184610Salfred } 395184610Salfred } 396188412Sthompsa err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL); 397188412Sthompsa if (err) 398188412Sthompsa device_printf(dev, "media change failed, error %d\n", err); 399188553Sthompsadone: 400188412Sthompsa if (!locked) 401188412Sthompsa AXE_UNLOCK(sc); 402184610Salfred} 403184610Salfred 404184610Salfred/* 405184610Salfred * Set media options. 406184610Salfred */ 407184610Salfredstatic int 408188412Sthompsaaxe_ifmedia_upd(struct ifnet *ifp) 409184610Salfred{ 410184610Salfred struct axe_softc *sc = ifp->if_softc; 411184610Salfred struct mii_data *mii = GET_MII(sc); 412188553Sthompsa int error; 413184610Salfred 414188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 415184610Salfred 416184610Salfred if (mii->mii_instance) { 417184610Salfred struct mii_softc *miisc; 418184610Salfred 419188412Sthompsa LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 420184610Salfred mii_phy_reset(miisc); 421184610Salfred } 422188553Sthompsa error = mii_mediachg(mii); 423188553Sthompsa return (error); 424184610Salfred} 425184610Salfred 426184610Salfred/* 427184610Salfred * Report current media status. 428184610Salfred */ 429184610Salfredstatic void 430188412Sthompsaaxe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 431184610Salfred{ 432184610Salfred struct axe_softc *sc = ifp->if_softc; 433188412Sthompsa struct mii_data *mii = GET_MII(sc); 434184610Salfred 435188412Sthompsa AXE_LOCK(sc); 436188412Sthompsa mii_pollstat(mii); 437188412Sthompsa AXE_UNLOCK(sc); 438188412Sthompsa ifmr->ifm_active = mii->mii_media_active; 439188412Sthompsa ifmr->ifm_status = mii->mii_media_status; 440184610Salfred} 441184610Salfred 442184610Salfredstatic void 443192984Sthompsaaxe_setmulti(struct usb_ether *ue) 444184610Salfred{ 445188412Sthompsa struct axe_softc *sc = usb2_ether_getsc(ue); 446188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 447188412Sthompsa struct ifmultiaddr *ifma; 448188412Sthompsa uint32_t h = 0; 449184610Salfred uint16_t rxmode; 450188412Sthompsa uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 451184610Salfred 452188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 453184610Salfred 454188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, &rxmode); 455184610Salfred rxmode = le16toh(rxmode); 456184610Salfred 457188412Sthompsa if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { 458184610Salfred rxmode |= AXE_RXCMD_ALLMULTI; 459188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 460184610Salfred return; 461184610Salfred } 462184610Salfred rxmode &= ~AXE_RXCMD_ALLMULTI; 463184610Salfred 464188412Sthompsa IF_ADDR_LOCK(ifp); 465188412Sthompsa TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 466188412Sthompsa { 467188412Sthompsa if (ifma->ifma_addr->sa_family != AF_LINK) 468188412Sthompsa continue; 469188412Sthompsa h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 470188412Sthompsa ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 471188412Sthompsa hashtbl[h / 8] |= 1 << (h % 8); 472188412Sthompsa } 473188412Sthompsa IF_ADDR_UNLOCK(ifp); 474184610Salfred 475188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, (void *)&hashtbl); 476188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 477184610Salfred} 478184610Salfred 479186730Salfredstatic int 480186730Salfredaxe_get_phyno(struct axe_softc *sc, int sel) 481186730Salfred{ 482188412Sthompsa int phyno; 483186730Salfred 484186730Salfred switch (AXE_PHY_TYPE(sc->sc_phyaddrs[sel])) { 485186730Salfred case PHY_TYPE_100_HOME: 486186730Salfred case PHY_TYPE_GIG: 487188412Sthompsa phyno = AXE_PHY_NO(sc->sc_phyaddrs[sel]); 488186730Salfred break; 489186730Salfred case PHY_TYPE_SPECIAL: 490186730Salfred /* FALLTHROUGH */ 491186730Salfred case PHY_TYPE_RSVD: 492186730Salfred /* FALLTHROUGH */ 493186730Salfred case PHY_TYPE_NON_SUP: 494186730Salfred /* FALLTHROUGH */ 495186730Salfred default: 496186730Salfred phyno = -1; 497186730Salfred break; 498186730Salfred } 499186730Salfred 500186730Salfred return (phyno); 501186730Salfred} 502186730Salfred 503184610Salfredstatic void 504188412Sthompsaaxe_ax88178_init(struct axe_softc *sc) 505184610Salfred{ 506188412Sthompsa int gpio0 = 0, phymode = 0; 507184610Salfred uint16_t eeprom; 508184610Salfred 509188412Sthompsa axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL); 510184610Salfred /* XXX magic */ 511188412Sthompsa axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom); 512184610Salfred eeprom = le16toh(eeprom); 513188412Sthompsa axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL); 514184610Salfred 515184610Salfred /* if EEPROM is invalid we have to use to GPIO0 */ 516184610Salfred if (eeprom == 0xffff) { 517184610Salfred phymode = 0; 518184610Salfred gpio0 = 1; 519184610Salfred } else { 520188412Sthompsa phymode = eeprom & 7; 521184610Salfred gpio0 = (eeprom & 0x80) ? 0 : 1; 522184610Salfred } 523184610Salfred 524188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x008c, NULL); 525188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 16); 526184610Salfred 527184610Salfred if ((eeprom >> 8) != 0x01) { 528188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL); 529188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 32); 530184610Salfred 531188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x001c, NULL); 532188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 3); 533184610Salfred 534188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL); 535188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 32); 536184610Salfred } else { 537188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x0004, NULL); 538188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 32); 539184610Salfred 540188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x000c, NULL); 541188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 32); 542184610Salfred } 543184610Salfred 544184610Salfred /* soft reset */ 545188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); 546188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 4); 547184610Salfred 548188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 549184610Salfred AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL); 550188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 4); 551186730Salfred /* Enable MII/GMII/RGMII interface to work with external PHY. */ 552188412Sthompsa axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL); 553188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 4); 554184610Salfred 555188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); 556184610Salfred} 557184610Salfred 558184610Salfredstatic void 559188412Sthompsaaxe_ax88772_init(struct axe_softc *sc) 560184610Salfred{ 561188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL); 562188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 16); 563184610Salfred 564186730Salfred if (sc->sc_phyno == AXE_772_PHY_NO_EPHY) { 565184610Salfred /* ask for the embedded PHY */ 566188412Sthompsa axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x01, NULL); 567188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 64); 568184610Salfred 569184610Salfred /* power down and reset state, pin reset state */ 570188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 571184610Salfred AXE_SW_RESET_CLEAR, NULL); 572188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 16); 573184610Salfred 574184610Salfred /* power down/reset state, pin operating state */ 575188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 576184610Salfred AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); 577188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 4); 578184610Salfred 579184610Salfred /* power up, reset */ 580188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL); 581184610Salfred 582184610Salfred /* power up, operating */ 583188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 584184610Salfred AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL); 585184610Salfred } else { 586184610Salfred /* ask for external PHY */ 587188412Sthompsa axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x00, NULL); 588188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 64); 589184610Salfred 590184610Salfred /* power down internal PHY */ 591188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 592184610Salfred AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); 593184610Salfred } 594184610Salfred 595188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 4); 596188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); 597184610Salfred} 598184610Salfred 599184610Salfredstatic void 600188412Sthompsaaxe_reset(struct axe_softc *sc) 601184610Salfred{ 602192984Sthompsa struct usb_config_descriptor *cd; 603188412Sthompsa usb2_error_t err; 604184610Salfred 605188412Sthompsa cd = usb2_get_config_descriptor(sc->sc_ue.ue_udev); 606184610Salfred 607188412Sthompsa err = usb2_req_set_config(sc->sc_ue.ue_udev, &sc->sc_mtx, 608188412Sthompsa cd->bConfigurationValue); 609188412Sthompsa if (err) 610188412Sthompsa DPRINTF("reset failed (ignored)\n"); 611188412Sthompsa 612188412Sthompsa /* Wait a little while for the chip to get its brains in order. */ 613188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 100); 614188412Sthompsa} 615188412Sthompsa 616188412Sthompsastatic void 617192984Sthompsaaxe_attach_post(struct usb_ether *ue) 618188412Sthompsa{ 619188412Sthompsa struct axe_softc *sc = usb2_ether_getsc(ue); 620188412Sthompsa 621184610Salfred /* 622184610Salfred * Load PHY indexes first. Needed by axe_xxx_init(). 623184610Salfred */ 624188412Sthompsa axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, sc->sc_phyaddrs); 625186730Salfred#if 1 626188412Sthompsa device_printf(sc->sc_ue.ue_dev, "PHYADDR 0x%02x:0x%02x\n", 627186730Salfred sc->sc_phyaddrs[0], sc->sc_phyaddrs[1]); 628186730Salfred#endif 629186730Salfred sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI); 630186730Salfred if (sc->sc_phyno == -1) 631186730Salfred sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC); 632186730Salfred if (sc->sc_phyno == -1) { 633188412Sthompsa device_printf(sc->sc_ue.ue_dev, 634188412Sthompsa "no valid PHY address found, assuming PHY address 0\n"); 635186730Salfred sc->sc_phyno = 0; 636186730Salfred } 637184610Salfred 638188412Sthompsa if (sc->sc_flags & AXE_FLAG_178) 639188412Sthompsa axe_ax88178_init(sc); 640188412Sthompsa else if (sc->sc_flags & AXE_FLAG_772) 641188412Sthompsa axe_ax88772_init(sc); 642188412Sthompsa 643184610Salfred /* 644184610Salfred * Get station address. 645184610Salfred */ 646184610Salfred if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) 647188412Sthompsa axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, ue->ue_eaddr); 648184610Salfred else 649188412Sthompsa axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, ue->ue_eaddr); 650184610Salfred 651184610Salfred /* 652184610Salfred * Fetch IPG values. 653184610Salfred */ 654188412Sthompsa axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->sc_ipgs); 655188412Sthompsa} 656184610Salfred 657188412Sthompsa/* 658188412Sthompsa * Probe for a AX88172 chip. 659188412Sthompsa */ 660188412Sthompsastatic int 661188412Sthompsaaxe_probe(device_t dev) 662188412Sthompsa{ 663192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 664184610Salfred 665192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 666188412Sthompsa return (ENXIO); 667188412Sthompsa if (uaa->info.bConfigIndex != AXE_CONFIG_IDX) 668188412Sthompsa return (ENXIO); 669188412Sthompsa if (uaa->info.bIfaceIndex != AXE_IFACE_IDX) 670188412Sthompsa return (ENXIO); 671184610Salfred 672188412Sthompsa return (usb2_lookup_id_by_uaa(axe_devs, sizeof(axe_devs), uaa)); 673188412Sthompsa} 674184610Salfred 675188412Sthompsa/* 676188412Sthompsa * Attach the interface. Allocate softc structures, do ifmedia 677188412Sthompsa * setup and ethernet/BPF attach. 678188412Sthompsa */ 679188412Sthompsastatic int 680188412Sthompsaaxe_attach(device_t dev) 681188412Sthompsa{ 682192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 683188412Sthompsa struct axe_softc *sc = device_get_softc(dev); 684192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 685188412Sthompsa uint8_t iface_index; 686188412Sthompsa int error; 687184610Salfred 688188412Sthompsa sc->sc_flags = USB_GET_DRIVER_INFO(uaa); 689184610Salfred 690188412Sthompsa device_set_usb2_desc(dev); 691184610Salfred 692188412Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 693184610Salfred 694188412Sthompsa iface_index = AXE_IFACE_IDX; 695188412Sthompsa error = usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, 696188412Sthompsa axe_config, AXE_N_TRANSFER, sc, &sc->sc_mtx); 697188412Sthompsa if (error) { 698188412Sthompsa device_printf(dev, "allocating USB transfers failed!\n"); 699188412Sthompsa goto detach; 700188412Sthompsa } 701184610Salfred 702188412Sthompsa ue->ue_sc = sc; 703188412Sthompsa ue->ue_dev = dev; 704188412Sthompsa ue->ue_udev = uaa->device; 705188412Sthompsa ue->ue_mtx = &sc->sc_mtx; 706188412Sthompsa ue->ue_methods = &axe_ue_methods; 707184610Salfred 708188412Sthompsa error = usb2_ether_ifattach(ue); 709184610Salfred if (error) { 710188412Sthompsa device_printf(dev, "could not attach interface\n"); 711188412Sthompsa goto detach; 712184610Salfred } 713188412Sthompsa return (0); /* success */ 714184610Salfred 715188412Sthompsadetach: 716188412Sthompsa axe_detach(dev); 717188412Sthompsa return (ENXIO); /* failure */ 718184610Salfred} 719184610Salfred 720184610Salfredstatic int 721184610Salfredaxe_detach(device_t dev) 722184610Salfred{ 723184610Salfred struct axe_softc *sc = device_get_softc(dev); 724192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 725184610Salfred 726187259Sthompsa usb2_transfer_unsetup(sc->sc_xfer, AXE_N_TRANSFER); 727188412Sthompsa usb2_ether_ifdetach(ue); 728184610Salfred mtx_destroy(&sc->sc_mtx); 729184610Salfred 730184610Salfred return (0); 731184610Salfred} 732184610Salfred 733184610Salfredstatic void 734192984Sthompsaaxe_intr_callback(struct usb_xfer *xfer) 735184610Salfred{ 736184610Salfred switch (USB_GET_STATE(xfer)) { 737184610Salfred case USB_ST_TRANSFERRED: 738184610Salfred case USB_ST_SETUP: 739188412Sthompsatr_setup: 740188412Sthompsa xfer->frlengths[0] = xfer->max_data_length; 741188412Sthompsa usb2_start_hardware(xfer); 742184610Salfred return; 743184610Salfred 744184610Salfred default: /* Error */ 745184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 746188412Sthompsa /* try to clear stall first */ 747188412Sthompsa xfer->flags.stall_pipe = 1; 748188412Sthompsa goto tr_setup; 749184610Salfred } 750184610Salfred return; 751184610Salfred } 752184610Salfred} 753184610Salfred 754184610Salfred#if (AXE_BULK_BUF_SIZE >= 0x10000) 755184610Salfred#error "Please update axe_bulk_read_callback()!" 756184610Salfred#endif 757184610Salfred 758184610Salfredstatic void 759192984Sthompsaaxe_bulk_read_callback(struct usb_xfer *xfer) 760184610Salfred{ 761184610Salfred struct axe_softc *sc = xfer->priv_sc; 762192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 763188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 764184610Salfred struct axe_sframe_hdr hdr; 765188412Sthompsa int error, pos, len, adjust; 766184610Salfred 767184610Salfred switch (USB_GET_STATE(xfer)) { 768184610Salfred case USB_ST_TRANSFERRED: 769184610Salfred pos = 0; 770184610Salfred while (1) { 771184610Salfred if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) { 772184610Salfred if (xfer->actlen < sizeof(hdr)) { 773184610Salfred /* too little data */ 774184610Salfred break; 775184610Salfred } 776184610Salfred usb2_copy_out(xfer->frbuffers, pos, &hdr, sizeof(hdr)); 777184610Salfred 778184610Salfred if ((hdr.len ^ hdr.ilen) != 0xFFFF) { 779184610Salfred /* we lost sync */ 780184610Salfred break; 781184610Salfred } 782184610Salfred xfer->actlen -= sizeof(hdr); 783184610Salfred pos += sizeof(hdr); 784184610Salfred 785184610Salfred len = le16toh(hdr.len); 786184610Salfred if (len > xfer->actlen) { 787184610Salfred /* invalid length */ 788184610Salfred break; 789184610Salfred } 790184610Salfred adjust = (len & 1); 791184610Salfred 792184610Salfred } else { 793184610Salfred len = xfer->actlen; 794184610Salfred adjust = 0; 795184610Salfred } 796188412Sthompsa error = usb2_ether_rxbuf(ue, xfer->frbuffers, pos, len); 797188412Sthompsa if (error) 798184610Salfred break; 799184610Salfred 800184610Salfred pos += len; 801184610Salfred xfer->actlen -= len; 802184610Salfred 803184610Salfred if (xfer->actlen <= adjust) { 804184610Salfred /* we are finished */ 805184610Salfred goto tr_setup; 806184610Salfred } 807184610Salfred pos += adjust; 808184610Salfred xfer->actlen -= adjust; 809184610Salfred } 810184610Salfred 811184610Salfred /* count an error */ 812184610Salfred ifp->if_ierrors++; 813184610Salfred 814188412Sthompsa /* FALLTHROUGH */ 815184610Salfred case USB_ST_SETUP: 816184610Salfredtr_setup: 817188412Sthompsa xfer->frlengths[0] = xfer->max_data_length; 818188412Sthompsa usb2_start_hardware(xfer); 819188412Sthompsa usb2_ether_rxflush(ue); 820184610Salfred return; 821184610Salfred 822184610Salfred default: /* Error */ 823188412Sthompsa DPRINTF("bulk read error, %s\n", 824188412Sthompsa usb2_errstr(xfer->error)); 825188412Sthompsa 826184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 827184610Salfred /* try to clear stall first */ 828188412Sthompsa xfer->flags.stall_pipe = 1; 829188412Sthompsa goto tr_setup; 830184610Salfred } 831184610Salfred return; 832184610Salfred 833184610Salfred } 834184610Salfred} 835184610Salfred 836184610Salfred#if ((AXE_BULK_BUF_SIZE >= 0x10000) || (AXE_BULK_BUF_SIZE < (MCLBYTES+4))) 837184610Salfred#error "Please update axe_bulk_write_callback()!" 838184610Salfred#endif 839184610Salfred 840184610Salfredstatic void 841192984Sthompsaaxe_bulk_write_callback(struct usb_xfer *xfer) 842184610Salfred{ 843184610Salfred struct axe_softc *sc = xfer->priv_sc; 844184610Salfred struct axe_sframe_hdr hdr; 845188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue); 846184610Salfred struct mbuf *m; 847188412Sthompsa int pos; 848184610Salfred 849184610Salfred switch (USB_GET_STATE(xfer)) { 850184610Salfred case USB_ST_TRANSFERRED: 851184610Salfred DPRINTFN(11, "transfer complete\n"); 852184610Salfred ifp->if_opackets++; 853188412Sthompsa /* FALLTHROUGH */ 854184610Salfred case USB_ST_SETUP: 855188412Sthompsatr_setup: 856186730Salfred if ((sc->sc_flags & AXE_FLAG_LINK) == 0) { 857184610Salfred /* 858184610Salfred * don't send anything if there is no link ! 859184610Salfred */ 860188412Sthompsa return; 861184610Salfred } 862184610Salfred pos = 0; 863184610Salfred 864184610Salfred while (1) { 865184610Salfred 866184610Salfred IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 867184610Salfred 868184610Salfred if (m == NULL) { 869184610Salfred if (pos > 0) 870184610Salfred break; /* send out data */ 871188412Sthompsa return; 872184610Salfred } 873184610Salfred if (m->m_pkthdr.len > MCLBYTES) { 874184610Salfred m->m_pkthdr.len = MCLBYTES; 875184610Salfred } 876184610Salfred if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) { 877184610Salfred 878184610Salfred hdr.len = htole16(m->m_pkthdr.len); 879184610Salfred hdr.ilen = ~hdr.len; 880184610Salfred 881184610Salfred usb2_copy_in(xfer->frbuffers, pos, &hdr, sizeof(hdr)); 882184610Salfred 883184610Salfred pos += sizeof(hdr); 884184610Salfred 885184610Salfred /* 886184610Salfred * NOTE: Some drivers force a short packet 887184610Salfred * by appending a dummy header with zero 888184610Salfred * length at then end of the USB transfer. 889184610Salfred * This driver uses the 890184610Salfred * USB_FORCE_SHORT_XFER flag instead. 891184610Salfred */ 892184610Salfred } 893184610Salfred usb2_m_copy_in(xfer->frbuffers, pos, 894184610Salfred m, 0, m->m_pkthdr.len); 895184610Salfred 896184610Salfred pos += m->m_pkthdr.len; 897184610Salfred 898184610Salfred /* 899188412Sthompsa * if there's a BPF listener, bounce a copy 900188412Sthompsa * of this frame to him: 901188412Sthompsa */ 902184610Salfred BPF_MTAP(ifp, m); 903184610Salfred 904184610Salfred m_freem(m); 905184610Salfred 906184610Salfred if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) { 907184610Salfred if (pos > (AXE_BULK_BUF_SIZE - MCLBYTES - sizeof(hdr))) { 908184610Salfred /* send out frame(s) */ 909184610Salfred break; 910184610Salfred } 911184610Salfred } else { 912184610Salfred /* send out frame */ 913184610Salfred break; 914184610Salfred } 915184610Salfred } 916184610Salfred 917184610Salfred xfer->frlengths[0] = pos; 918184610Salfred usb2_start_hardware(xfer); 919184610Salfred return; 920184610Salfred 921184610Salfred default: /* Error */ 922184610Salfred DPRINTFN(11, "transfer error, %s\n", 923184610Salfred usb2_errstr(xfer->error)); 924184610Salfred 925188412Sthompsa ifp->if_oerrors++; 926188412Sthompsa 927184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 928184610Salfred /* try to clear stall first */ 929188412Sthompsa xfer->flags.stall_pipe = 1; 930188412Sthompsa goto tr_setup; 931184610Salfred } 932184610Salfred return; 933184610Salfred 934184610Salfred } 935184610Salfred} 936184610Salfred 937184610Salfredstatic void 938192984Sthompsaaxe_tick(struct usb_ether *ue) 939184610Salfred{ 940188412Sthompsa struct axe_softc *sc = usb2_ether_getsc(ue); 941184610Salfred struct mii_data *mii = GET_MII(sc); 942184610Salfred 943188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 944188412Sthompsa 945184610Salfred mii_tick(mii); 946188553Sthompsa if ((sc->sc_flags & AXE_FLAG_LINK) == 0) { 947188553Sthompsa axe_miibus_statchg(ue->ue_dev); 948188553Sthompsa if ((sc->sc_flags & AXE_FLAG_LINK) != 0) 949188553Sthompsa axe_start(ue); 950186730Salfred } 951184610Salfred} 952184610Salfred 953184610Salfredstatic void 954192984Sthompsaaxe_start(struct usb_ether *ue) 955184610Salfred{ 956188412Sthompsa struct axe_softc *sc = usb2_ether_getsc(ue); 957184610Salfred 958188412Sthompsa /* 959188412Sthompsa * start the USB transfers, if not already started: 960188412Sthompsa */ 961188412Sthompsa usb2_transfer_start(sc->sc_xfer[AXE_INTR_DT_RD]); 962188412Sthompsa usb2_transfer_start(sc->sc_xfer[AXE_BULK_DT_RD]); 963188412Sthompsa usb2_transfer_start(sc->sc_xfer[AXE_BULK_DT_WR]); 964184610Salfred} 965184610Salfred 966184610Salfredstatic void 967192984Sthompsaaxe_init(struct usb_ether *ue) 968184610Salfred{ 969188412Sthompsa struct axe_softc *sc = usb2_ether_getsc(ue); 970188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 971184610Salfred uint16_t rxmode; 972184610Salfred 973188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 974184610Salfred 975188412Sthompsa /* Cancel pending I/O */ 976188412Sthompsa axe_stop(ue); 977184610Salfred 978188412Sthompsa#ifdef notdef 979184610Salfred /* Set MAC address */ 980188412Sthompsa axe_mac(sc, IF_LLADDR(ifp), 1); 981184610Salfred#endif 982184610Salfred 983184610Salfred /* Set transmitter IPG values */ 984184610Salfred if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) { 985188412Sthompsa axe_cmd(sc, AXE_178_CMD_WRITE_IPG012, sc->sc_ipgs[2], 986184610Salfred (sc->sc_ipgs[1] << 8) | (sc->sc_ipgs[0]), NULL); 987184610Salfred } else { 988188412Sthompsa axe_cmd(sc, AXE_172_CMD_WRITE_IPG0, 0, sc->sc_ipgs[0], NULL); 989188412Sthompsa axe_cmd(sc, AXE_172_CMD_WRITE_IPG1, 0, sc->sc_ipgs[1], NULL); 990188412Sthompsa axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->sc_ipgs[2], NULL); 991184610Salfred } 992184610Salfred 993184610Salfred /* Enable receiver, set RX mode */ 994184610Salfred rxmode = (AXE_RXCMD_MULTICAST | AXE_RXCMD_ENABLE); 995184610Salfred if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) { 996184610Salfred rxmode |= AXE_178_RXCMD_MFB_2048; /* chip default */ 997184610Salfred } else { 998184610Salfred rxmode |= AXE_172_RXCMD_UNICAST; 999184610Salfred } 1000184610Salfred 1001184610Salfred /* If we want promiscuous mode, set the allframes bit. */ 1002188412Sthompsa if (ifp->if_flags & IFF_PROMISC) 1003184610Salfred rxmode |= AXE_RXCMD_PROMISC; 1004188412Sthompsa 1005188412Sthompsa if (ifp->if_flags & IFF_BROADCAST) 1006184610Salfred rxmode |= AXE_RXCMD_BROADCAST; 1007184610Salfred 1008188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 1009188412Sthompsa 1010184610Salfred /* Load the multicast filter. */ 1011188412Sthompsa axe_setmulti(ue); 1012184610Salfred 1013188412Sthompsa usb2_transfer_set_stall(sc->sc_xfer[AXE_BULK_DT_WR]); 1014184610Salfred 1015188412Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 1016188412Sthompsa axe_start(ue); 1017184610Salfred} 1018184610Salfred 1019184610Salfredstatic void 1020192984Sthompsaaxe_setpromisc(struct usb_ether *ue) 1021184610Salfred{ 1022188412Sthompsa struct axe_softc *sc = usb2_ether_getsc(ue); 1023188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 1024184610Salfred uint16_t rxmode; 1025184610Salfred 1026188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, &rxmode); 1027184610Salfred 1028184610Salfred rxmode = le16toh(rxmode); 1029184610Salfred 1030188412Sthompsa if (ifp->if_flags & IFF_PROMISC) { 1031184610Salfred rxmode |= AXE_RXCMD_PROMISC; 1032184610Salfred } else { 1033184610Salfred rxmode &= ~AXE_RXCMD_PROMISC; 1034184610Salfred } 1035184610Salfred 1036188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 1037184610Salfred 1038188412Sthompsa axe_setmulti(ue); 1039184610Salfred} 1040184610Salfred 1041184610Salfredstatic void 1042192984Sthompsaaxe_stop(struct usb_ether *ue) 1043184610Salfred{ 1044188412Sthompsa struct axe_softc *sc = usb2_ether_getsc(ue); 1045188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 1046184610Salfred 1047188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 1048184610Salfred 1049188412Sthompsa ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1050186730Salfred sc->sc_flags &= ~AXE_FLAG_LINK; 1051184610Salfred 1052184610Salfred /* 1053184610Salfred * stop all the transfers, if not already stopped: 1054184610Salfred */ 1055187259Sthompsa usb2_transfer_stop(sc->sc_xfer[AXE_BULK_DT_WR]); 1056187259Sthompsa usb2_transfer_stop(sc->sc_xfer[AXE_BULK_DT_RD]); 1057187259Sthompsa usb2_transfer_stop(sc->sc_xfer[AXE_INTR_DT_RD]); 1058184610Salfred 1059188412Sthompsa axe_reset(sc); 1060184610Salfred} 1061