if_axe.c revision 190734
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 190734 2009-04-05 18:20:38Z 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 115184610SalfredSYSCTL_NODE(_hw_usb2, OID_AUTO, axe, CTLFLAG_RW, 0, "USB axe"); 116184610SalfredSYSCTL_INT(_hw_usb2_axe, OID_AUTO, debug, CTLFLAG_RW, &axe_debug, 0, 117184610Salfred "Debug level"); 118184610Salfred#endif 119184610Salfred 120184610Salfred/* 121184610Salfred * Various supported device vendors/products. 122184610Salfred */ 123184610Salfredstatic const struct usb2_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; 154184610Salfredstatic device_shutdown_t axe_shutdown; 155184610Salfred 156184610Salfredstatic usb2_callback_t axe_intr_callback; 157184610Salfredstatic usb2_callback_t axe_bulk_read_callback; 158184610Salfredstatic usb2_callback_t axe_bulk_write_callback; 159184610Salfred 160188412Sthompsastatic miibus_readreg_t axe_miibus_readreg; 161188412Sthompsastatic miibus_writereg_t axe_miibus_writereg; 162188412Sthompsastatic miibus_statchg_t axe_miibus_statchg; 163184610Salfred 164188412Sthompsastatic usb2_ether_fn_t axe_attach_post; 165188412Sthompsastatic usb2_ether_fn_t axe_init; 166188412Sthompsastatic usb2_ether_fn_t axe_stop; 167188412Sthompsastatic usb2_ether_fn_t axe_start; 168188412Sthompsastatic usb2_ether_fn_t axe_tick; 169188412Sthompsastatic usb2_ether_fn_t axe_setmulti; 170188412Sthompsastatic usb2_ether_fn_t axe_setpromisc; 171184610Salfred 172188412Sthompsastatic int axe_ifmedia_upd(struct ifnet *); 173188412Sthompsastatic void axe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 174188412Sthompsastatic int axe_cmd(struct axe_softc *, int, int, int, void *); 175188412Sthompsastatic void axe_ax88178_init(struct axe_softc *); 176188412Sthompsastatic void axe_ax88772_init(struct axe_softc *); 177186730Salfredstatic int axe_get_phyno(struct axe_softc *, int); 178184610Salfred 179187259Sthompsastatic const struct usb2_config axe_config[AXE_N_TRANSFER] = { 180184610Salfred 181187259Sthompsa [AXE_BULK_DT_WR] = { 182184610Salfred .type = UE_BULK, 183184610Salfred .endpoint = UE_ADDR_ANY, 184184610Salfred .direction = UE_DIR_OUT, 185190734Sthompsa .bufsize = AXE_BULK_BUF_SIZE, 186190734Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 187190734Sthompsa .callback = axe_bulk_write_callback, 188190734Sthompsa .timeout = 10000, /* 10 seconds */ 189184610Salfred }, 190184610Salfred 191187259Sthompsa [AXE_BULK_DT_RD] = { 192184610Salfred .type = UE_BULK, 193184610Salfred .endpoint = UE_ADDR_ANY, 194184610Salfred .direction = UE_DIR_IN, 195184610Salfred#if (MCLBYTES < 2048) 196184610Salfred#error "(MCLBYTES < 2048)" 197184610Salfred#endif 198190734Sthompsa .bufsize = MCLBYTES, 199190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 200190734Sthompsa .callback = axe_bulk_read_callback, 201190734Sthompsa .timeout = 0, /* no timeout */ 202184610Salfred }, 203184610Salfred 204187259Sthompsa [AXE_INTR_DT_RD] = { 205184610Salfred .type = UE_INTERRUPT, 206184610Salfred .endpoint = UE_ADDR_ANY, 207184610Salfred .direction = UE_DIR_IN, 208190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 209190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 210190734Sthompsa .callback = axe_intr_callback, 211184610Salfred }, 212184610Salfred}; 213184610Salfred 214184610Salfredstatic device_method_t axe_methods[] = { 215184610Salfred /* Device interface */ 216184610Salfred DEVMETHOD(device_probe, axe_probe), 217184610Salfred DEVMETHOD(device_attach, axe_attach), 218184610Salfred DEVMETHOD(device_detach, axe_detach), 219184610Salfred DEVMETHOD(device_shutdown, axe_shutdown), 220184610Salfred 221184610Salfred /* bus interface */ 222184610Salfred DEVMETHOD(bus_print_child, bus_generic_print_child), 223184610Salfred DEVMETHOD(bus_driver_added, bus_generic_driver_added), 224184610Salfred 225184610Salfred /* MII interface */ 226188412Sthompsa DEVMETHOD(miibus_readreg, axe_miibus_readreg), 227188412Sthompsa DEVMETHOD(miibus_writereg, axe_miibus_writereg), 228188412Sthompsa DEVMETHOD(miibus_statchg, axe_miibus_statchg), 229184610Salfred 230184610Salfred {0, 0} 231184610Salfred}; 232184610Salfred 233184610Salfredstatic driver_t axe_driver = { 234184610Salfred .name = "axe", 235184610Salfred .methods = axe_methods, 236184610Salfred .size = sizeof(struct axe_softc), 237184610Salfred}; 238184610Salfred 239184610Salfredstatic devclass_t axe_devclass; 240184610Salfred 241189275SthompsaDRIVER_MODULE(axe, uhub, axe_driver, axe_devclass, NULL, 0); 242184610SalfredDRIVER_MODULE(miibus, axe, miibus_driver, miibus_devclass, 0, 0); 243188942SthompsaMODULE_DEPEND(axe, uether, 1, 1, 1); 244188942SthompsaMODULE_DEPEND(axe, usb, 1, 1, 1); 245188412SthompsaMODULE_DEPEND(axe, ether, 1, 1, 1); 246188412SthompsaMODULE_DEPEND(axe, miibus, 1, 1, 1); 247184610Salfred 248188412Sthompsastatic const struct usb2_ether_methods axe_ue_methods = { 249188412Sthompsa .ue_attach_post = axe_attach_post, 250188412Sthompsa .ue_start = axe_start, 251188412Sthompsa .ue_init = axe_init, 252188412Sthompsa .ue_stop = axe_stop, 253188412Sthompsa .ue_tick = axe_tick, 254188412Sthompsa .ue_setmulti = axe_setmulti, 255188412Sthompsa .ue_setpromisc = axe_setpromisc, 256188412Sthompsa .ue_mii_upd = axe_ifmedia_upd, 257188412Sthompsa .ue_mii_sts = axe_ifmedia_sts, 258188412Sthompsa}; 259188412Sthompsa 260188412Sthompsastatic int 261188412Sthompsaaxe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf) 262184610Salfred{ 263184610Salfred struct usb2_device_request req; 264184610Salfred usb2_error_t err; 265184610Salfred 266188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 267188412Sthompsa 268184610Salfred req.bmRequestType = (AXE_CMD_IS_WRITE(cmd) ? 269184610Salfred UT_WRITE_VENDOR_DEVICE : 270184610Salfred UT_READ_VENDOR_DEVICE); 271184610Salfred req.bRequest = AXE_CMD_CMD(cmd); 272184610Salfred USETW(req.wValue, val); 273184610Salfred USETW(req.wIndex, index); 274188412Sthompsa USETW(req.wLength, AXE_CMD_LEN(cmd)); 275184610Salfred 276188412Sthompsa err = usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000); 277184610Salfred 278188412Sthompsa return (err); 279184610Salfred} 280184610Salfred 281184610Salfredstatic int 282188412Sthompsaaxe_miibus_readreg(device_t dev, int phy, int reg) 283184610Salfred{ 284184610Salfred struct axe_softc *sc = device_get_softc(dev); 285184610Salfred uint16_t val; 286188412Sthompsa int locked; 287184610Salfred 288188412Sthompsa if (sc->sc_phyno != phy) 289188412Sthompsa return (0); 290184610Salfred 291188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 292188412Sthompsa if (!locked) 293188412Sthompsa AXE_LOCK(sc); 294186730Salfred 295188412Sthompsa axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); 296188412Sthompsa axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, &val); 297188412Sthompsa axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); 298184610Salfred 299184610Salfred val = le16toh(val); 300186730Salfred if ((sc->sc_flags & AXE_FLAG_772) != 0 && reg == MII_BMSR) { 301186730Salfred /* 302186730Salfred * BMSR of AX88772 indicates that it supports extended 303186730Salfred * capability but the extended status register is 304186730Salfred * revered for embedded ethernet PHY. So clear the 305186730Salfred * extended capability bit of BMSR. 306186730Salfred */ 307186730Salfred val &= ~BMSR_EXTCAP; 308186730Salfred } 309184610Salfred 310188412Sthompsa if (!locked) 311188412Sthompsa AXE_UNLOCK(sc); 312184610Salfred return (val); 313184610Salfred} 314184610Salfred 315184610Salfredstatic int 316188412Sthompsaaxe_miibus_writereg(device_t dev, int phy, int reg, int val) 317184610Salfred{ 318184610Salfred struct axe_softc *sc = device_get_softc(dev); 319188412Sthompsa int locked; 320184610Salfred 321189522Sthompsa val = htole32(val); 322184610Salfred 323186730Salfred if (sc->sc_phyno != phy) 324188412Sthompsa return (0); 325186730Salfred 326188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 327188412Sthompsa if (!locked) 328188412Sthompsa AXE_LOCK(sc); 329184610Salfred 330188412Sthompsa axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); 331188412Sthompsa axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, &val); 332188412Sthompsa axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); 333188412Sthompsa 334188412Sthompsa if (!locked) 335188412Sthompsa AXE_UNLOCK(sc); 336184610Salfred return (0); 337184610Salfred} 338184610Salfred 339184610Salfredstatic void 340188412Sthompsaaxe_miibus_statchg(device_t dev) 341184610Salfred{ 342184610Salfred struct axe_softc *sc = device_get_softc(dev); 343184610Salfred struct mii_data *mii = GET_MII(sc); 344188553Sthompsa struct ifnet *ifp; 345184610Salfred uint16_t val; 346188412Sthompsa int err, locked; 347184610Salfred 348188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 349188412Sthompsa if (!locked) 350188412Sthompsa AXE_LOCK(sc); 351184610Salfred 352188553Sthompsa ifp = usb2_ether_getifp(&sc->sc_ue); 353188553Sthompsa if (mii == NULL || ifp == NULL || 354188553Sthompsa (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 355188553Sthompsa goto done; 356188553Sthompsa 357188553Sthompsa sc->sc_flags &= ~AXE_FLAG_LINK; 358188553Sthompsa if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 359188553Sthompsa (IFM_ACTIVE | IFM_AVALID)) { 360188553Sthompsa switch (IFM_SUBTYPE(mii->mii_media_active)) { 361188553Sthompsa case IFM_10_T: 362188553Sthompsa case IFM_100_TX: 363188553Sthompsa sc->sc_flags |= AXE_FLAG_LINK; 364188553Sthompsa break; 365188553Sthompsa case IFM_1000_T: 366188553Sthompsa if ((sc->sc_flags & AXE_FLAG_178) == 0) 367188553Sthompsa break; 368188553Sthompsa sc->sc_flags |= AXE_FLAG_LINK; 369188553Sthompsa break; 370188553Sthompsa default: 371188553Sthompsa break; 372188553Sthompsa } 373188553Sthompsa } 374188553Sthompsa 375188553Sthompsa /* Lost link, do nothing. */ 376188553Sthompsa if ((sc->sc_flags & AXE_FLAG_LINK) == 0) 377188553Sthompsa goto done; 378188553Sthompsa 379188553Sthompsa val = 0; 380188553Sthompsa if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) 381188553Sthompsa val |= AXE_MEDIA_FULL_DUPLEX; 382186730Salfred if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) { 383186730Salfred val |= AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC; 384188553Sthompsa if ((sc->sc_flags & AXE_FLAG_178) != 0) 385188553Sthompsa val |= AXE_178_MEDIA_ENCK; 386184610Salfred switch (IFM_SUBTYPE(mii->mii_media_active)) { 387184610Salfred case IFM_1000_T: 388184610Salfred val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK; 389184610Salfred break; 390184610Salfred case IFM_100_TX: 391184610Salfred val |= AXE_178_MEDIA_100TX; 392184610Salfred break; 393184610Salfred case IFM_10_T: 394184610Salfred /* doesn't need to be handled */ 395184610Salfred break; 396184610Salfred } 397184610Salfred } 398188412Sthompsa err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL); 399188412Sthompsa if (err) 400188412Sthompsa device_printf(dev, "media change failed, error %d\n", err); 401188553Sthompsadone: 402188412Sthompsa if (!locked) 403188412Sthompsa AXE_UNLOCK(sc); 404184610Salfred} 405184610Salfred 406184610Salfred/* 407184610Salfred * Set media options. 408184610Salfred */ 409184610Salfredstatic int 410188412Sthompsaaxe_ifmedia_upd(struct ifnet *ifp) 411184610Salfred{ 412184610Salfred struct axe_softc *sc = ifp->if_softc; 413184610Salfred struct mii_data *mii = GET_MII(sc); 414188553Sthompsa int error; 415184610Salfred 416188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 417184610Salfred 418184610Salfred if (mii->mii_instance) { 419184610Salfred struct mii_softc *miisc; 420184610Salfred 421188412Sthompsa LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 422184610Salfred mii_phy_reset(miisc); 423184610Salfred } 424188553Sthompsa error = mii_mediachg(mii); 425188553Sthompsa return (error); 426184610Salfred} 427184610Salfred 428184610Salfred/* 429184610Salfred * Report current media status. 430184610Salfred */ 431184610Salfredstatic void 432188412Sthompsaaxe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 433184610Salfred{ 434184610Salfred struct axe_softc *sc = ifp->if_softc; 435188412Sthompsa struct mii_data *mii = GET_MII(sc); 436184610Salfred 437188412Sthompsa AXE_LOCK(sc); 438188412Sthompsa mii_pollstat(mii); 439188412Sthompsa AXE_UNLOCK(sc); 440188412Sthompsa ifmr->ifm_active = mii->mii_media_active; 441188412Sthompsa ifmr->ifm_status = mii->mii_media_status; 442184610Salfred} 443184610Salfred 444184610Salfredstatic void 445188412Sthompsaaxe_setmulti(struct usb2_ether *ue) 446184610Salfred{ 447188412Sthompsa struct axe_softc *sc = usb2_ether_getsc(ue); 448188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 449188412Sthompsa struct ifmultiaddr *ifma; 450188412Sthompsa uint32_t h = 0; 451184610Salfred uint16_t rxmode; 452188412Sthompsa uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 453184610Salfred 454188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 455184610Salfred 456188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, &rxmode); 457184610Salfred rxmode = le16toh(rxmode); 458184610Salfred 459188412Sthompsa if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { 460184610Salfred rxmode |= AXE_RXCMD_ALLMULTI; 461188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 462184610Salfred return; 463184610Salfred } 464184610Salfred rxmode &= ~AXE_RXCMD_ALLMULTI; 465184610Salfred 466188412Sthompsa IF_ADDR_LOCK(ifp); 467188412Sthompsa TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 468188412Sthompsa { 469188412Sthompsa if (ifma->ifma_addr->sa_family != AF_LINK) 470188412Sthompsa continue; 471188412Sthompsa h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 472188412Sthompsa ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 473188412Sthompsa hashtbl[h / 8] |= 1 << (h % 8); 474188412Sthompsa } 475188412Sthompsa IF_ADDR_UNLOCK(ifp); 476184610Salfred 477188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, (void *)&hashtbl); 478188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 479184610Salfred} 480184610Salfred 481186730Salfredstatic int 482186730Salfredaxe_get_phyno(struct axe_softc *sc, int sel) 483186730Salfred{ 484188412Sthompsa int phyno; 485186730Salfred 486186730Salfred switch (AXE_PHY_TYPE(sc->sc_phyaddrs[sel])) { 487186730Salfred case PHY_TYPE_100_HOME: 488186730Salfred case PHY_TYPE_GIG: 489188412Sthompsa phyno = AXE_PHY_NO(sc->sc_phyaddrs[sel]); 490186730Salfred break; 491186730Salfred case PHY_TYPE_SPECIAL: 492186730Salfred /* FALLTHROUGH */ 493186730Salfred case PHY_TYPE_RSVD: 494186730Salfred /* FALLTHROUGH */ 495186730Salfred case PHY_TYPE_NON_SUP: 496186730Salfred /* FALLTHROUGH */ 497186730Salfred default: 498186730Salfred phyno = -1; 499186730Salfred break; 500186730Salfred } 501186730Salfred 502186730Salfred return (phyno); 503186730Salfred} 504186730Salfred 505184610Salfredstatic void 506188412Sthompsaaxe_ax88178_init(struct axe_softc *sc) 507184610Salfred{ 508188412Sthompsa int gpio0 = 0, phymode = 0; 509184610Salfred uint16_t eeprom; 510184610Salfred 511188412Sthompsa axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL); 512184610Salfred /* XXX magic */ 513188412Sthompsa axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom); 514184610Salfred eeprom = le16toh(eeprom); 515188412Sthompsa axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL); 516184610Salfred 517184610Salfred /* if EEPROM is invalid we have to use to GPIO0 */ 518184610Salfred if (eeprom == 0xffff) { 519184610Salfred phymode = 0; 520184610Salfred gpio0 = 1; 521184610Salfred } else { 522188412Sthompsa phymode = eeprom & 7; 523184610Salfred gpio0 = (eeprom & 0x80) ? 0 : 1; 524184610Salfred } 525184610Salfred 526188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x008c, NULL); 527188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 16); 528184610Salfred 529184610Salfred if ((eeprom >> 8) != 0x01) { 530188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL); 531188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 32); 532184610Salfred 533188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x001c, NULL); 534188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 3); 535184610Salfred 536188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL); 537188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 32); 538184610Salfred } else { 539188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x0004, NULL); 540188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 32); 541184610Salfred 542188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x000c, NULL); 543188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 32); 544184610Salfred } 545184610Salfred 546184610Salfred /* soft reset */ 547188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); 548188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 4); 549184610Salfred 550188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 551184610Salfred AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL); 552188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 4); 553186730Salfred /* Enable MII/GMII/RGMII interface to work with external PHY. */ 554188412Sthompsa axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL); 555188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 4); 556184610Salfred 557188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); 558184610Salfred} 559184610Salfred 560184610Salfredstatic void 561188412Sthompsaaxe_ax88772_init(struct axe_softc *sc) 562184610Salfred{ 563188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL); 564188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 16); 565184610Salfred 566186730Salfred if (sc->sc_phyno == AXE_772_PHY_NO_EPHY) { 567184610Salfred /* ask for the embedded PHY */ 568188412Sthompsa axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x01, NULL); 569188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 64); 570184610Salfred 571184610Salfred /* power down and reset state, pin reset state */ 572188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 573184610Salfred AXE_SW_RESET_CLEAR, NULL); 574188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 16); 575184610Salfred 576184610Salfred /* power down/reset state, pin operating state */ 577188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 578184610Salfred AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); 579188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 4); 580184610Salfred 581184610Salfred /* power up, reset */ 582188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL); 583184610Salfred 584184610Salfred /* power up, operating */ 585188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 586184610Salfred AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL); 587184610Salfred } else { 588184610Salfred /* ask for external PHY */ 589188412Sthompsa axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x00, NULL); 590188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 64); 591184610Salfred 592184610Salfred /* power down internal PHY */ 593188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 594184610Salfred AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); 595184610Salfred } 596184610Salfred 597188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 4); 598188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); 599184610Salfred} 600184610Salfred 601184610Salfredstatic void 602188412Sthompsaaxe_reset(struct axe_softc *sc) 603184610Salfred{ 604188412Sthompsa struct usb2_config_descriptor *cd; 605188412Sthompsa usb2_error_t err; 606184610Salfred 607188412Sthompsa cd = usb2_get_config_descriptor(sc->sc_ue.ue_udev); 608184610Salfred 609188412Sthompsa err = usb2_req_set_config(sc->sc_ue.ue_udev, &sc->sc_mtx, 610188412Sthompsa cd->bConfigurationValue); 611188412Sthompsa if (err) 612188412Sthompsa DPRINTF("reset failed (ignored)\n"); 613188412Sthompsa 614188412Sthompsa /* Wait a little while for the chip to get its brains in order. */ 615188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 100); 616188412Sthompsa} 617188412Sthompsa 618188412Sthompsastatic void 619188412Sthompsaaxe_attach_post(struct usb2_ether *ue) 620188412Sthompsa{ 621188412Sthompsa struct axe_softc *sc = usb2_ether_getsc(ue); 622188412Sthompsa 623184610Salfred /* 624184610Salfred * Load PHY indexes first. Needed by axe_xxx_init(). 625184610Salfred */ 626188412Sthompsa axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, sc->sc_phyaddrs); 627186730Salfred#if 1 628188412Sthompsa device_printf(sc->sc_ue.ue_dev, "PHYADDR 0x%02x:0x%02x\n", 629186730Salfred sc->sc_phyaddrs[0], sc->sc_phyaddrs[1]); 630186730Salfred#endif 631186730Salfred sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI); 632186730Salfred if (sc->sc_phyno == -1) 633186730Salfred sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC); 634186730Salfred if (sc->sc_phyno == -1) { 635188412Sthompsa device_printf(sc->sc_ue.ue_dev, 636188412Sthompsa "no valid PHY address found, assuming PHY address 0\n"); 637186730Salfred sc->sc_phyno = 0; 638186730Salfred } 639184610Salfred 640188412Sthompsa if (sc->sc_flags & AXE_FLAG_178) 641188412Sthompsa axe_ax88178_init(sc); 642188412Sthompsa else if (sc->sc_flags & AXE_FLAG_772) 643188412Sthompsa axe_ax88772_init(sc); 644188412Sthompsa 645184610Salfred /* 646184610Salfred * Get station address. 647184610Salfred */ 648184610Salfred if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) 649188412Sthompsa axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, ue->ue_eaddr); 650184610Salfred else 651188412Sthompsa axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, ue->ue_eaddr); 652184610Salfred 653184610Salfred /* 654184610Salfred * Fetch IPG values. 655184610Salfred */ 656188412Sthompsa axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->sc_ipgs); 657188412Sthompsa} 658184610Salfred 659188412Sthompsa/* 660188412Sthompsa * Probe for a AX88172 chip. 661188412Sthompsa */ 662188412Sthompsastatic int 663188412Sthompsaaxe_probe(device_t dev) 664188412Sthompsa{ 665188412Sthompsa struct usb2_attach_arg *uaa = device_get_ivars(dev); 666184610Salfred 667188412Sthompsa if (uaa->usb2_mode != USB_MODE_HOST) 668188412Sthompsa return (ENXIO); 669188412Sthompsa if (uaa->info.bConfigIndex != AXE_CONFIG_IDX) 670188412Sthompsa return (ENXIO); 671188412Sthompsa if (uaa->info.bIfaceIndex != AXE_IFACE_IDX) 672188412Sthompsa return (ENXIO); 673184610Salfred 674188412Sthompsa return (usb2_lookup_id_by_uaa(axe_devs, sizeof(axe_devs), uaa)); 675188412Sthompsa} 676184610Salfred 677188412Sthompsa/* 678188412Sthompsa * Attach the interface. Allocate softc structures, do ifmedia 679188412Sthompsa * setup and ethernet/BPF attach. 680188412Sthompsa */ 681188412Sthompsastatic int 682188412Sthompsaaxe_attach(device_t dev) 683188412Sthompsa{ 684188412Sthompsa struct usb2_attach_arg *uaa = device_get_ivars(dev); 685188412Sthompsa struct axe_softc *sc = device_get_softc(dev); 686188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 687188412Sthompsa uint8_t iface_index; 688188412Sthompsa int error; 689184610Salfred 690188412Sthompsa sc->sc_flags = USB_GET_DRIVER_INFO(uaa); 691184610Salfred 692188412Sthompsa device_set_usb2_desc(dev); 693184610Salfred 694188412Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 695184610Salfred 696188412Sthompsa iface_index = AXE_IFACE_IDX; 697188412Sthompsa error = usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, 698188412Sthompsa axe_config, AXE_N_TRANSFER, sc, &sc->sc_mtx); 699188412Sthompsa if (error) { 700188412Sthompsa device_printf(dev, "allocating USB transfers failed!\n"); 701188412Sthompsa goto detach; 702188412Sthompsa } 703184610Salfred 704188412Sthompsa ue->ue_sc = sc; 705188412Sthompsa ue->ue_dev = dev; 706188412Sthompsa ue->ue_udev = uaa->device; 707188412Sthompsa ue->ue_mtx = &sc->sc_mtx; 708188412Sthompsa ue->ue_methods = &axe_ue_methods; 709184610Salfred 710188412Sthompsa error = usb2_ether_ifattach(ue); 711184610Salfred if (error) { 712188412Sthompsa device_printf(dev, "could not attach interface\n"); 713188412Sthompsa goto detach; 714184610Salfred } 715188412Sthompsa return (0); /* success */ 716184610Salfred 717188412Sthompsadetach: 718188412Sthompsa axe_detach(dev); 719188412Sthompsa return (ENXIO); /* failure */ 720184610Salfred} 721184610Salfred 722184610Salfredstatic int 723184610Salfredaxe_detach(device_t dev) 724184610Salfred{ 725184610Salfred struct axe_softc *sc = device_get_softc(dev); 726188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 727184610Salfred 728187259Sthompsa usb2_transfer_unsetup(sc->sc_xfer, AXE_N_TRANSFER); 729188412Sthompsa usb2_ether_ifdetach(ue); 730184610Salfred mtx_destroy(&sc->sc_mtx); 731184610Salfred 732184610Salfred return (0); 733184610Salfred} 734184610Salfred 735184610Salfredstatic void 736184610Salfredaxe_intr_callback(struct usb2_xfer *xfer) 737184610Salfred{ 738184610Salfred switch (USB_GET_STATE(xfer)) { 739184610Salfred case USB_ST_TRANSFERRED: 740184610Salfred case USB_ST_SETUP: 741188412Sthompsatr_setup: 742188412Sthompsa xfer->frlengths[0] = xfer->max_data_length; 743188412Sthompsa usb2_start_hardware(xfer); 744184610Salfred return; 745184610Salfred 746184610Salfred default: /* Error */ 747184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 748188412Sthompsa /* try to clear stall first */ 749188412Sthompsa xfer->flags.stall_pipe = 1; 750188412Sthompsa goto tr_setup; 751184610Salfred } 752184610Salfred return; 753184610Salfred } 754184610Salfred} 755184610Salfred 756184610Salfred#if (AXE_BULK_BUF_SIZE >= 0x10000) 757184610Salfred#error "Please update axe_bulk_read_callback()!" 758184610Salfred#endif 759184610Salfred 760184610Salfredstatic void 761184610Salfredaxe_bulk_read_callback(struct usb2_xfer *xfer) 762184610Salfred{ 763184610Salfred struct axe_softc *sc = xfer->priv_sc; 764188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 765188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 766184610Salfred struct axe_sframe_hdr hdr; 767188412Sthompsa int error, pos, len, adjust; 768184610Salfred 769184610Salfred switch (USB_GET_STATE(xfer)) { 770184610Salfred case USB_ST_TRANSFERRED: 771184610Salfred pos = 0; 772184610Salfred while (1) { 773184610Salfred if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) { 774184610Salfred if (xfer->actlen < sizeof(hdr)) { 775184610Salfred /* too little data */ 776184610Salfred break; 777184610Salfred } 778184610Salfred usb2_copy_out(xfer->frbuffers, pos, &hdr, sizeof(hdr)); 779184610Salfred 780184610Salfred if ((hdr.len ^ hdr.ilen) != 0xFFFF) { 781184610Salfred /* we lost sync */ 782184610Salfred break; 783184610Salfred } 784184610Salfred xfer->actlen -= sizeof(hdr); 785184610Salfred pos += sizeof(hdr); 786184610Salfred 787184610Salfred len = le16toh(hdr.len); 788184610Salfred if (len > xfer->actlen) { 789184610Salfred /* invalid length */ 790184610Salfred break; 791184610Salfred } 792184610Salfred adjust = (len & 1); 793184610Salfred 794184610Salfred } else { 795184610Salfred len = xfer->actlen; 796184610Salfred adjust = 0; 797184610Salfred } 798188412Sthompsa error = usb2_ether_rxbuf(ue, xfer->frbuffers, pos, len); 799188412Sthompsa if (error) 800184610Salfred break; 801184610Salfred 802184610Salfred pos += len; 803184610Salfred xfer->actlen -= len; 804184610Salfred 805184610Salfred if (xfer->actlen <= adjust) { 806184610Salfred /* we are finished */ 807184610Salfred goto tr_setup; 808184610Salfred } 809184610Salfred pos += adjust; 810184610Salfred xfer->actlen -= adjust; 811184610Salfred } 812184610Salfred 813184610Salfred /* count an error */ 814184610Salfred ifp->if_ierrors++; 815184610Salfred 816188412Sthompsa /* FALLTHROUGH */ 817184610Salfred case USB_ST_SETUP: 818184610Salfredtr_setup: 819188412Sthompsa xfer->frlengths[0] = xfer->max_data_length; 820188412Sthompsa usb2_start_hardware(xfer); 821188412Sthompsa usb2_ether_rxflush(ue); 822184610Salfred return; 823184610Salfred 824184610Salfred default: /* Error */ 825188412Sthompsa DPRINTF("bulk read error, %s\n", 826188412Sthompsa usb2_errstr(xfer->error)); 827188412Sthompsa 828184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 829184610Salfred /* try to clear stall first */ 830188412Sthompsa xfer->flags.stall_pipe = 1; 831188412Sthompsa goto tr_setup; 832184610Salfred } 833184610Salfred return; 834184610Salfred 835184610Salfred } 836184610Salfred} 837184610Salfred 838184610Salfred#if ((AXE_BULK_BUF_SIZE >= 0x10000) || (AXE_BULK_BUF_SIZE < (MCLBYTES+4))) 839184610Salfred#error "Please update axe_bulk_write_callback()!" 840184610Salfred#endif 841184610Salfred 842184610Salfredstatic void 843184610Salfredaxe_bulk_write_callback(struct usb2_xfer *xfer) 844184610Salfred{ 845184610Salfred struct axe_softc *sc = xfer->priv_sc; 846184610Salfred struct axe_sframe_hdr hdr; 847188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue); 848184610Salfred struct mbuf *m; 849188412Sthompsa int pos; 850184610Salfred 851184610Salfred switch (USB_GET_STATE(xfer)) { 852184610Salfred case USB_ST_TRANSFERRED: 853184610Salfred DPRINTFN(11, "transfer complete\n"); 854184610Salfred ifp->if_opackets++; 855188412Sthompsa /* FALLTHROUGH */ 856184610Salfred case USB_ST_SETUP: 857188412Sthompsatr_setup: 858186730Salfred if ((sc->sc_flags & AXE_FLAG_LINK) == 0) { 859184610Salfred /* 860184610Salfred * don't send anything if there is no link ! 861184610Salfred */ 862188412Sthompsa return; 863184610Salfred } 864184610Salfred pos = 0; 865184610Salfred 866184610Salfred while (1) { 867184610Salfred 868184610Salfred IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 869184610Salfred 870184610Salfred if (m == NULL) { 871184610Salfred if (pos > 0) 872184610Salfred break; /* send out data */ 873188412Sthompsa return; 874184610Salfred } 875184610Salfred if (m->m_pkthdr.len > MCLBYTES) { 876184610Salfred m->m_pkthdr.len = MCLBYTES; 877184610Salfred } 878184610Salfred if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) { 879184610Salfred 880184610Salfred hdr.len = htole16(m->m_pkthdr.len); 881184610Salfred hdr.ilen = ~hdr.len; 882184610Salfred 883184610Salfred usb2_copy_in(xfer->frbuffers, pos, &hdr, sizeof(hdr)); 884184610Salfred 885184610Salfred pos += sizeof(hdr); 886184610Salfred 887184610Salfred /* 888184610Salfred * NOTE: Some drivers force a short packet 889184610Salfred * by appending a dummy header with zero 890184610Salfred * length at then end of the USB transfer. 891184610Salfred * This driver uses the 892184610Salfred * USB_FORCE_SHORT_XFER flag instead. 893184610Salfred */ 894184610Salfred } 895184610Salfred usb2_m_copy_in(xfer->frbuffers, pos, 896184610Salfred m, 0, m->m_pkthdr.len); 897184610Salfred 898184610Salfred pos += m->m_pkthdr.len; 899184610Salfred 900184610Salfred /* 901188412Sthompsa * if there's a BPF listener, bounce a copy 902188412Sthompsa * of this frame to him: 903188412Sthompsa */ 904184610Salfred BPF_MTAP(ifp, m); 905184610Salfred 906184610Salfred m_freem(m); 907184610Salfred 908184610Salfred if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) { 909184610Salfred if (pos > (AXE_BULK_BUF_SIZE - MCLBYTES - sizeof(hdr))) { 910184610Salfred /* send out frame(s) */ 911184610Salfred break; 912184610Salfred } 913184610Salfred } else { 914184610Salfred /* send out frame */ 915184610Salfred break; 916184610Salfred } 917184610Salfred } 918184610Salfred 919184610Salfred xfer->frlengths[0] = pos; 920184610Salfred usb2_start_hardware(xfer); 921184610Salfred return; 922184610Salfred 923184610Salfred default: /* Error */ 924184610Salfred DPRINTFN(11, "transfer error, %s\n", 925184610Salfred usb2_errstr(xfer->error)); 926184610Salfred 927188412Sthompsa ifp->if_oerrors++; 928188412Sthompsa 929184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 930184610Salfred /* try to clear stall first */ 931188412Sthompsa xfer->flags.stall_pipe = 1; 932188412Sthompsa goto tr_setup; 933184610Salfred } 934184610Salfred return; 935184610Salfred 936184610Salfred } 937184610Salfred} 938184610Salfred 939184610Salfredstatic void 940188412Sthompsaaxe_tick(struct usb2_ether *ue) 941184610Salfred{ 942188412Sthompsa struct axe_softc *sc = usb2_ether_getsc(ue); 943184610Salfred struct mii_data *mii = GET_MII(sc); 944184610Salfred 945188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 946188412Sthompsa 947184610Salfred mii_tick(mii); 948188553Sthompsa if ((sc->sc_flags & AXE_FLAG_LINK) == 0) { 949188553Sthompsa axe_miibus_statchg(ue->ue_dev); 950188553Sthompsa if ((sc->sc_flags & AXE_FLAG_LINK) != 0) 951188553Sthompsa axe_start(ue); 952186730Salfred } 953184610Salfred} 954184610Salfred 955184610Salfredstatic void 956188412Sthompsaaxe_start(struct usb2_ether *ue) 957184610Salfred{ 958188412Sthompsa struct axe_softc *sc = usb2_ether_getsc(ue); 959184610Salfred 960188412Sthompsa /* 961188412Sthompsa * start the USB transfers, if not already started: 962188412Sthompsa */ 963188412Sthompsa usb2_transfer_start(sc->sc_xfer[AXE_INTR_DT_RD]); 964188412Sthompsa usb2_transfer_start(sc->sc_xfer[AXE_BULK_DT_RD]); 965188412Sthompsa usb2_transfer_start(sc->sc_xfer[AXE_BULK_DT_WR]); 966184610Salfred} 967184610Salfred 968184610Salfredstatic void 969188412Sthompsaaxe_init(struct usb2_ether *ue) 970184610Salfred{ 971188412Sthompsa struct axe_softc *sc = usb2_ether_getsc(ue); 972188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 973184610Salfred uint16_t rxmode; 974184610Salfred 975188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 976184610Salfred 977188412Sthompsa /* Cancel pending I/O */ 978188412Sthompsa axe_stop(ue); 979184610Salfred 980188412Sthompsa#ifdef notdef 981184610Salfred /* Set MAC address */ 982188412Sthompsa axe_mac(sc, IF_LLADDR(ifp), 1); 983184610Salfred#endif 984184610Salfred 985184610Salfred /* Set transmitter IPG values */ 986184610Salfred if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) { 987188412Sthompsa axe_cmd(sc, AXE_178_CMD_WRITE_IPG012, sc->sc_ipgs[2], 988184610Salfred (sc->sc_ipgs[1] << 8) | (sc->sc_ipgs[0]), NULL); 989184610Salfred } else { 990188412Sthompsa axe_cmd(sc, AXE_172_CMD_WRITE_IPG0, 0, sc->sc_ipgs[0], NULL); 991188412Sthompsa axe_cmd(sc, AXE_172_CMD_WRITE_IPG1, 0, sc->sc_ipgs[1], NULL); 992188412Sthompsa axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->sc_ipgs[2], NULL); 993184610Salfred } 994184610Salfred 995184610Salfred /* Enable receiver, set RX mode */ 996184610Salfred rxmode = (AXE_RXCMD_MULTICAST | AXE_RXCMD_ENABLE); 997184610Salfred if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) { 998184610Salfred rxmode |= AXE_178_RXCMD_MFB_2048; /* chip default */ 999184610Salfred } else { 1000184610Salfred rxmode |= AXE_172_RXCMD_UNICAST; 1001184610Salfred } 1002184610Salfred 1003184610Salfred /* If we want promiscuous mode, set the allframes bit. */ 1004188412Sthompsa if (ifp->if_flags & IFF_PROMISC) 1005184610Salfred rxmode |= AXE_RXCMD_PROMISC; 1006188412Sthompsa 1007188412Sthompsa if (ifp->if_flags & IFF_BROADCAST) 1008184610Salfred rxmode |= AXE_RXCMD_BROADCAST; 1009184610Salfred 1010188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 1011188412Sthompsa 1012184610Salfred /* Load the multicast filter. */ 1013188412Sthompsa axe_setmulti(ue); 1014184610Salfred 1015188412Sthompsa usb2_transfer_set_stall(sc->sc_xfer[AXE_BULK_DT_WR]); 1016184610Salfred 1017188412Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 1018188412Sthompsa axe_start(ue); 1019184610Salfred} 1020184610Salfred 1021184610Salfredstatic void 1022188412Sthompsaaxe_setpromisc(struct usb2_ether *ue) 1023184610Salfred{ 1024188412Sthompsa struct axe_softc *sc = usb2_ether_getsc(ue); 1025188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 1026184610Salfred uint16_t rxmode; 1027184610Salfred 1028188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, &rxmode); 1029184610Salfred 1030184610Salfred rxmode = le16toh(rxmode); 1031184610Salfred 1032188412Sthompsa if (ifp->if_flags & IFF_PROMISC) { 1033184610Salfred rxmode |= AXE_RXCMD_PROMISC; 1034184610Salfred } else { 1035184610Salfred rxmode &= ~AXE_RXCMD_PROMISC; 1036184610Salfred } 1037184610Salfred 1038188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 1039184610Salfred 1040188412Sthompsa axe_setmulti(ue); 1041184610Salfred} 1042184610Salfred 1043184610Salfredstatic void 1044188412Sthompsaaxe_stop(struct usb2_ether *ue) 1045184610Salfred{ 1046188412Sthompsa struct axe_softc *sc = usb2_ether_getsc(ue); 1047188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 1048184610Salfred 1049188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 1050184610Salfred 1051188412Sthompsa ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1052186730Salfred sc->sc_flags &= ~AXE_FLAG_LINK; 1053184610Salfred 1054184610Salfred /* 1055184610Salfred * stop all the transfers, if not already stopped: 1056184610Salfred */ 1057187259Sthompsa usb2_transfer_stop(sc->sc_xfer[AXE_BULK_DT_WR]); 1058187259Sthompsa usb2_transfer_stop(sc->sc_xfer[AXE_BULK_DT_RD]); 1059187259Sthompsa usb2_transfer_stop(sc->sc_xfer[AXE_INTR_DT_RD]); 1060184610Salfred 1061188412Sthompsa axe_reset(sc); 1062184610Salfred} 1063184610Salfred 1064184610Salfred/* 1065184610Salfred * Stop all chip I/O so that the kernel's probe routines don't 1066184610Salfred * get confused by errant DMAs when rebooting. 1067184610Salfred */ 1068184610Salfredstatic int 1069184610Salfredaxe_shutdown(device_t dev) 1070184610Salfred{ 1071184610Salfred struct axe_softc *sc = device_get_softc(dev); 1072184610Salfred 1073188412Sthompsa usb2_ether_ifshutdown(&sc->sc_ue); 1074184610Salfred 1075184610Salfred return (0); 1076184610Salfred} 1077