if_axe.c revision 188412
1202375Srdivacky/*- 2202375Srdivacky * Copyright (c) 1997, 1998, 1999, 2000-2003 3202375Srdivacky * Bill Paul <wpaul@windriver.com>. All rights reserved. 4202375Srdivacky * 5202375Srdivacky * Redistribution and use in source and binary forms, with or without 6202375Srdivacky * modification, are permitted provided that the following conditions 7202375Srdivacky * are met: 8202375Srdivacky * 1. Redistributions of source code must retain the above copyright 9202375Srdivacky * notice, this list of conditions and the following disclaimer. 10202375Srdivacky * 2. Redistributions in binary form must reproduce the above copyright 11202375Srdivacky * notice, this list of conditions and the following disclaimer in the 12202375Srdivacky * documentation and/or other materials provided with the distribution. 13202375Srdivacky * 3. All advertising materials mentioning features or use of this software 14202375Srdivacky * must display the following acknowledgement: 15249423Sdim * This product includes software developed by Bill Paul. 16249423Sdim * 4. Neither the name of the author nor the names of any co-contributors 17218893Sdim * may be used to endorse or promote products derived from this software 18249423Sdim * without specific prior written permission. 19202375Srdivacky * 20202375Srdivacky * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21202375Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22202375Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23202375Srdivacky * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24202375Srdivacky * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25202375Srdivacky * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26202375Srdivacky * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27202375Srdivacky * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28202375Srdivacky * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29202375Srdivacky * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30251662Sdim * THE POSSIBILITY OF SUCH DAMAGE. 31226633Sdim */ 32226633Sdim 33251662Sdim#include <sys/cdefs.h> 34218893Sdim__FBSDID("$FreeBSD: head/sys/dev/usb2/ethernet/if_axe2.c 188412 2009-02-09 22:02:38Z thompsa $"); 35218893Sdim 36218893Sdim/* 37218893Sdim * ASIX Electronics AX88172/AX88178/AX88778 USB 2.0 ethernet driver. 38218893Sdim * Used in the LinkSys USB200M and various other adapters. 39218893Sdim * 40218893Sdim * Manuals available from: 41218893Sdim * http://www.asix.com.tw/datasheet/mac/Ax88172.PDF 42251662Sdim * Note: you need the manual for the AX88170 chip (USB 1.x ethernet 43202375Srdivacky * controller) to find the definitions for the RX control register. 44202375Srdivacky * http://www.asix.com.tw/datasheet/mac/Ax88170.PDF 45202375Srdivacky * 46202375Srdivacky * Written by Bill Paul <wpaul@windriver.com> 47202375Srdivacky * Senior Engineer 48218893Sdim * Wind River Systems 49202375Srdivacky */ 50202375Srdivacky 51202375Srdivacky/* 52202375Srdivacky * The AX88172 provides USB ethernet supports at 10 and 100Mbps. 53202375Srdivacky * It uses an external PHY (reference designs use a RealTek chip), 54218893Sdim * and has a 64-bit multicast hash filter. There is some information 55218893Sdim * missing from the manual which one needs to know in order to make 56202375Srdivacky * the chip function: 57251662Sdim * 58218893Sdim * - You must set bit 7 in the RX control register, otherwise the 59218893Sdim * chip won't receive any packets. 60218893Sdim * - You must initialize all 3 IPG registers, or you won't be able 61218893Sdim * to send any packets. 62218893Sdim * 63218893Sdim * Note that this device appears to only support loading the station 64251662Sdim * address via autload from the EEPROM (i.e. there's no way to manaully 65202375Srdivacky * set it). 66202375Srdivacky * 67202375Srdivacky * (Adam Weinberger wanted me to name this driver if_gir.c.) 68202375Srdivacky */ 69202375Srdivacky 70202375Srdivacky/* 71202375Srdivacky * Ax88178 and Ax88772 support backported from the OpenBSD driver. 72202375Srdivacky * 2007/02/12, J.R. Oldroyd, fbsd@opal.com 73202375Srdivacky * 74202375Srdivacky * Manual here: 75202375Srdivacky * http://www.asix.com.tw/FrootAttach/datasheet/AX88178_datasheet_Rev10.pdf 76251662Sdim * http://www.asix.com.tw/FrootAttach/datasheet/AX88772_datasheet_Rev10.pdf 77202375Srdivacky */ 78251662Sdim 79202375Srdivacky#include <dev/usb2/include/usb2_devid.h> 80202375Srdivacky#include <dev/usb2/include/usb2_standard.h> 81202375Srdivacky#include <dev/usb2/include/usb2_mfunc.h> 82202375Srdivacky#include <dev/usb2/include/usb2_error.h> 83221345Sdim 84202375Srdivacky#define USB_DEBUG_VAR axe_debug 85202375Srdivacky 86202375Srdivacky#include <dev/usb2/core/usb2_core.h> 87202375Srdivacky#include <dev/usb2/core/usb2_lookup.h> 88202375Srdivacky#include <dev/usb2/core/usb2_process.h> 89251662Sdim#include <dev/usb2/core/usb2_debug.h> 90202375Srdivacky#include <dev/usb2/core/usb2_request.h> 91221345Sdim#include <dev/usb2/core/usb2_busdma.h> 92202375Srdivacky#include <dev/usb2/core/usb2_util.h> 93202375Srdivacky 94202375Srdivacky#include <dev/usb2/ethernet/usb2_ethernet.h> 95202375Srdivacky#include <dev/usb2/ethernet/if_axereg.h> 96202375Srdivacky 97251662Sdim/* 98202375Srdivacky * AXE_178_MAX_FRAME_BURST 99202375Srdivacky * max frame burst size for Ax88178 and Ax88772 100202375Srdivacky * 0 2048 bytes 101202375Srdivacky * 1 4096 bytes 102202375Srdivacky * 2 8192 bytes 103202375Srdivacky * 3 16384 bytes 104202375Srdivacky * use the largest your system can handle without USB stalling. 105202375Srdivacky * 106202375Srdivacky * NB: 88772 parts appear to generate lots of input errors with 107202375Srdivacky * a 2K rx buffer and 8K is only slightly faster than 4K on an 108202375Srdivacky * EHCI port on a T42 so change at your own risk. 109202375Srdivacky */ 110202375Srdivacky#define AXE_178_MAX_FRAME_BURST 1 111202375Srdivacky 112251662Sdim#if USB_DEBUG 113223017Sdimstatic int axe_debug = 0; 114223017Sdim 115223017SdimSYSCTL_NODE(_hw_usb2, OID_AUTO, axe, CTLFLAG_RW, 0, "USB axe"); 116223017SdimSYSCTL_INT(_hw_usb2_axe, OID_AUTO, debug, CTLFLAG_RW, &axe_debug, 0, 117223017Sdim "Debug level"); 118223017Sdim#endif 119223017Sdim 120218893Sdim/* 121218893Sdim * Various supported device vendors/products. 122218893Sdim */ 123218893Sdimstatic const struct usb2_device_id axe_devs[] = { 124218893Sdim {USB_VPI(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UF200, 0)}, 125218893Sdim {USB_VPI(USB_VENDOR_ACERCM, USB_PRODUCT_ACERCM_EP1427X2, 0)}, 126223017Sdim {USB_VPI(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_ETHERNET, AXE_FLAG_772)}, 127218893Sdim {USB_VPI(USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88172, 0)}, 128202375Srdivacky {USB_VPI(USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178, AXE_FLAG_178)}, 129202375Srdivacky {USB_VPI(USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772, AXE_FLAG_772)}, 130202375Srdivacky {USB_VPI(USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC210T, 0)}, 131202375Srdivacky {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D5055, AXE_FLAG_178)}, 132251662Sdim {USB_VPI(USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB2AR, 0)}, 133251662Sdim {USB_VPI(USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_USB200MV2, AXE_FLAG_772)}, 134202375Srdivacky {USB_VPI(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB2_TX, 0)}, 135202375Srdivacky {USB_VPI(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100, 0)}, 136202375Srdivacky {USB_VPI(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100B1, AXE_FLAG_772)}, 137202375Srdivacky {USB_VPI(USB_VENDOR_GOODWAY, USB_PRODUCT_GOODWAY_GWUSB2E, 0)}, 138202375Srdivacky {USB_VPI(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETGUS2, AXE_FLAG_178)}, 139202375Srdivacky {USB_VPI(USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_PRX1, 0)}, 140202375Srdivacky {USB_VPI(USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_USB200M, 0)}, 141202375Srdivacky {USB_VPI(USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_USB1000, AXE_FLAG_178)}, 142202375Srdivacky {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2KTX, 0)}, 143251662Sdim {USB_VPI(USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA120, 0)}, 144218893Sdim {USB_VPI(USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01PLUS, AXE_FLAG_772)}, 145251662Sdim {USB_VPI(USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GU1000T, AXE_FLAG_178)}, 146202375Srdivacky {USB_VPI(USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_LN029, 0)}, 147202375Srdivacky {USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN028, AXE_FLAG_178)}, 148202375Srdivacky {USB_VPI(USB_VENDOR_SYSTEMTALKS, USB_PRODUCT_SYSTEMTALKS_SGCX2UL, 0)}, 149202375Srdivacky}; 150202375Srdivacky 151202375Srdivackystatic device_probe_t axe_probe; 152202375Srdivackystatic device_attach_t axe_attach; 153218893Sdimstatic device_detach_t axe_detach; 154251662Sdimstatic device_shutdown_t axe_shutdown; 155202375Srdivacky 156202375Srdivackystatic usb2_callback_t axe_intr_callback; 157202375Srdivackystatic usb2_callback_t axe_bulk_read_callback; 158202375Srdivackystatic usb2_callback_t axe_bulk_write_callback; 159202375Srdivacky 160251662Sdimstatic miibus_readreg_t axe_miibus_readreg; 161202375Srdivackystatic miibus_writereg_t axe_miibus_writereg; 162202375Srdivackystatic miibus_statchg_t axe_miibus_statchg; 163202375Srdivacky 164202375Srdivackystatic usb2_ether_fn_t axe_attach_post; 165251662Sdimstatic usb2_ether_fn_t axe_init; 166202375Srdivackystatic usb2_ether_fn_t axe_stop; 167202375Srdivackystatic usb2_ether_fn_t axe_start; 168202375Srdivackystatic usb2_ether_fn_t axe_tick; 169202375Srdivackystatic usb2_ether_fn_t axe_setmulti; 170202375Srdivackystatic usb2_ether_fn_t axe_setpromisc; 171202375Srdivacky 172202375Srdivackystatic int axe_ifmedia_upd(struct ifnet *); 173202375Srdivackystatic void axe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 174251662Sdimstatic int axe_cmd(struct axe_softc *, int, int, int, void *); 175202375Srdivackystatic void axe_ax88178_init(struct axe_softc *); 176202375Srdivackystatic void axe_ax88772_init(struct axe_softc *); 177202375Srdivackystatic int axe_get_phyno(struct axe_softc *, int); 178202375Srdivacky 179202375Srdivackystatic const struct usb2_config axe_config[AXE_N_TRANSFER] = { 180202375Srdivacky 181202375Srdivacky [AXE_BULK_DT_WR] = { 182202375Srdivacky .type = UE_BULK, 183202375Srdivacky .endpoint = UE_ADDR_ANY, 184202375Srdivacky .direction = UE_DIR_OUT, 185202375Srdivacky .mh.bufsize = AXE_BULK_BUF_SIZE, 186202375Srdivacky .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 187202375Srdivacky .mh.callback = axe_bulk_write_callback, 188202375Srdivacky .mh.timeout = 10000, /* 10 seconds */ 189251662Sdim }, 190202375Srdivacky 191202375Srdivacky [AXE_BULK_DT_RD] = { 192202375Srdivacky .type = UE_BULK, 193202375Srdivacky .endpoint = UE_ADDR_ANY, 194202375Srdivacky .direction = UE_DIR_IN, 195202375Srdivacky#if (MCLBYTES < 2048) 196202375Srdivacky#error "(MCLBYTES < 2048)" 197202375Srdivacky#endif 198251662Sdim .mh.bufsize = MCLBYTES, 199202375Srdivacky .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 200202375Srdivacky .mh.callback = axe_bulk_read_callback, 201202375Srdivacky .mh.timeout = 0, /* no timeout */ 202251662Sdim }, 203202375Srdivacky 204202375Srdivacky [AXE_INTR_DT_RD] = { 205202375Srdivacky .type = UE_INTERRUPT, 206202375Srdivacky .endpoint = UE_ADDR_ANY, 207221345Sdim .direction = UE_DIR_IN, 208202375Srdivacky .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 209202375Srdivacky .mh.bufsize = 0, /* use wMaxPacketSize */ 210251662Sdim .mh.callback = axe_intr_callback, 211202375Srdivacky }, 212202375Srdivacky}; 213202375Srdivacky 214202375Srdivackystatic device_method_t axe_methods[] = { 215202375Srdivacky /* Device interface */ 216202375Srdivacky DEVMETHOD(device_probe, axe_probe), 217251662Sdim DEVMETHOD(device_attach, axe_attach), 218202375Srdivacky DEVMETHOD(device_detach, axe_detach), 219202375Srdivacky DEVMETHOD(device_shutdown, axe_shutdown), 220202375Srdivacky 221202375Srdivacky /* bus interface */ 222202375Srdivacky DEVMETHOD(bus_print_child, bus_generic_print_child), 223251662Sdim DEVMETHOD(bus_driver_added, bus_generic_driver_added), 224202375Srdivacky 225202375Srdivacky /* MII interface */ 226202375Srdivacky DEVMETHOD(miibus_readreg, axe_miibus_readreg), 227202375Srdivacky DEVMETHOD(miibus_writereg, axe_miibus_writereg), 228202375Srdivacky DEVMETHOD(miibus_statchg, axe_miibus_statchg), 229251662Sdim 230202375Srdivacky {0, 0} 231251662Sdim}; 232226633Sdim 233218893Sdimstatic driver_t axe_driver = { 234223017Sdim .name = "axe", 235218893Sdim .methods = axe_methods, 236202375Srdivacky .size = sizeof(struct axe_softc), 237202375Srdivacky}; 238202375Srdivacky 239202375Srdivackystatic devclass_t axe_devclass; 240202375Srdivacky 241202375SrdivackyDRIVER_MODULE(axe, ushub, axe_driver, axe_devclass, NULL, 0); 242202375SrdivackyDRIVER_MODULE(miibus, axe, miibus_driver, miibus_devclass, 0, 0); 243202375SrdivackyMODULE_DEPEND(axe, usb2_ethernet, 1, 1, 1); 244221345SdimMODULE_DEPEND(axe, usb2_core, 1, 1, 1); 245202375SrdivackyMODULE_DEPEND(axe, ether, 1, 1, 1); 246202375SrdivackyMODULE_DEPEND(axe, miibus, 1, 1, 1); 247202375Srdivacky 248202375Srdivackystatic const struct usb2_ether_methods axe_ue_methods = { 249251662Sdim .ue_attach_post = axe_attach_post, 250202375Srdivacky .ue_start = axe_start, 251202375Srdivacky .ue_init = axe_init, 252202375Srdivacky .ue_stop = axe_stop, 253251662Sdim .ue_tick = axe_tick, 254202375Srdivacky .ue_setmulti = axe_setmulti, 255202375Srdivacky .ue_setpromisc = axe_setpromisc, 256202375Srdivacky .ue_mii_upd = axe_ifmedia_upd, 257202375Srdivacky .ue_mii_sts = axe_ifmedia_sts, 258202375Srdivacky}; 259202375Srdivacky 260210299Sedstatic int 261210299Sedaxe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf) 262210299Sed{ 263202375Srdivacky struct usb2_device_request req; 264202375Srdivacky usb2_error_t err; 265202375Srdivacky 266202375Srdivacky AXE_LOCK_ASSERT(sc, MA_OWNED); 267202375Srdivacky 268202375Srdivacky req.bmRequestType = (AXE_CMD_IS_WRITE(cmd) ? 269251662Sdim UT_WRITE_VENDOR_DEVICE : 270202375Srdivacky UT_READ_VENDOR_DEVICE); 271202375Srdivacky req.bRequest = AXE_CMD_CMD(cmd); 272202375Srdivacky USETW(req.wValue, val); 273251662Sdim USETW(req.wIndex, index); 274202375Srdivacky USETW(req.wLength, AXE_CMD_LEN(cmd)); 275202375Srdivacky 276202375Srdivacky err = usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000); 277202375Srdivacky 278202375Srdivacky return (err); 279202375Srdivacky} 280202375Srdivacky 281202375Srdivackystatic int 282202375Srdivackyaxe_miibus_readreg(device_t dev, int phy, int reg) 283251662Sdim{ 284202375Srdivacky struct axe_softc *sc = device_get_softc(dev); 285202375Srdivacky uint16_t val; 286202375Srdivacky int locked; 287202375Srdivacky 288202375Srdivacky if (sc->sc_phyno != phy) 289226633Sdim return (0); 290226633Sdim 291226633Sdim locked = mtx_owned(&sc->sc_mtx); 292226633Sdim if (!locked) 293226633Sdim AXE_LOCK(sc); 294226633Sdim 295202375Srdivacky axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); 296202375Srdivacky axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, &val); 297202375Srdivacky axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); 298202375Srdivacky 299202375Srdivacky val = le16toh(val); 300202375Srdivacky if ((sc->sc_flags & AXE_FLAG_772) != 0 && reg == MII_BMSR) { 301202375Srdivacky /* 302204792Srdivacky * BMSR of AX88772 indicates that it supports extended 303251662Sdim * capability but the extended status register is 304202375Srdivacky * revered for embedded ethernet PHY. So clear the 305202375Srdivacky * extended capability bit of BMSR. 306202375Srdivacky */ 307202375Srdivacky val &= ~BMSR_EXTCAP; 308202375Srdivacky } 309251662Sdim 310202375Srdivacky if (!locked) 311202375Srdivacky AXE_UNLOCK(sc); 312202375Srdivacky return (val); 313251662Sdim} 314202375Srdivacky 315202375Srdivackystatic int 316251662Sdimaxe_miibus_writereg(device_t dev, int phy, int reg, int val) 317202375Srdivacky{ 318202375Srdivacky struct axe_softc *sc = device_get_softc(dev); 319202375Srdivacky int locked; 320202375Srdivacky 321202375Srdivacky val = htole16(val); 322251662Sdim 323251662Sdim if (sc->sc_phyno != phy) 324202375Srdivacky return (0); 325202375Srdivacky 326202375Srdivacky locked = mtx_owned(&sc->sc_mtx); 327204792Srdivacky if (!locked) 328202375Srdivacky AXE_LOCK(sc); 329202375Srdivacky 330251662Sdim axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); 331202375Srdivacky axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, &val); 332202375Srdivacky axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); 333202375Srdivacky 334202375Srdivacky if (!locked) 335251662Sdim AXE_UNLOCK(sc); 336202375Srdivacky return (0); 337251662Sdim} 338202375Srdivacky 339202375Srdivackystatic void 340202375Srdivackyaxe_miibus_statchg(device_t dev) 341202375Srdivacky{ 342202375Srdivacky struct axe_softc *sc = device_get_softc(dev); 343202375Srdivacky struct mii_data *mii = GET_MII(sc); 344202375Srdivacky uint16_t val; 345251662Sdim int err, locked; 346202375Srdivacky 347202375Srdivacky locked = mtx_owned(&sc->sc_mtx); 348202375Srdivacky if (!locked) 349221345Sdim AXE_LOCK(sc); 350202375Srdivacky 351251662Sdim val = (mii->mii_media_active & IFM_GMASK) == IFM_FDX ? 352202375Srdivacky AXE_MEDIA_FULL_DUPLEX : 0; 353202375Srdivacky if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) { 354251662Sdim val |= AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC; 355202375Srdivacky 356202375Srdivacky switch (IFM_SUBTYPE(mii->mii_media_active)) { 357202375Srdivacky case IFM_1000_T: 358202375Srdivacky val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK; 359202375Srdivacky break; 360202375Srdivacky case IFM_100_TX: 361202375Srdivacky val |= AXE_178_MEDIA_100TX; 362251662Sdim break; 363202375Srdivacky case IFM_10_T: 364202375Srdivacky /* doesn't need to be handled */ 365202375Srdivacky break; 366202375Srdivacky } 367202375Srdivacky } 368202375Srdivacky err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL); 369202375Srdivacky if (err) 370202375Srdivacky device_printf(dev, "media change failed, error %d\n", err); 371202375Srdivacky 372202375Srdivacky if (!locked) 373251662Sdim AXE_UNLOCK(sc); 374202375Srdivacky} 375202375Srdivacky 376202375Srdivacky/* 377202375Srdivacky * Set media options. 378202375Srdivacky */ 379202375Srdivackystatic int 380251662Sdimaxe_ifmedia_upd(struct ifnet *ifp) 381223017Sdim{ 382223017Sdim struct axe_softc *sc = ifp->if_softc; 383223017Sdim struct mii_data *mii = GET_MII(sc); 384202375Srdivacky 385202375Srdivacky AXE_LOCK_ASSERT(sc, MA_OWNED); 386202375Srdivacky 387202375Srdivacky sc->sc_flags &= ~AXE_FLAG_LINK; 388202375Srdivacky if (mii->mii_instance) { 389202375Srdivacky struct mii_softc *miisc; 390202375Srdivacky 391202375Srdivacky LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 392202375Srdivacky mii_phy_reset(miisc); 393202375Srdivacky } 394202375Srdivacky mii_mediachg(mii); 395202375Srdivacky return (0); 396202375Srdivacky} 397202375Srdivacky 398251662Sdim/* 399202375Srdivacky * Report current media status. 400202375Srdivacky */ 401202375Srdivackystatic void 402202375Srdivackyaxe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 403202375Srdivacky{ 404226633Sdim struct axe_softc *sc = ifp->if_softc; 405218893Sdim struct mii_data *mii = GET_MII(sc); 406251662Sdim 407202375Srdivacky AXE_LOCK(sc); 408202375Srdivacky mii_pollstat(mii); 409202375Srdivacky AXE_UNLOCK(sc); 410202375Srdivacky ifmr->ifm_active = mii->mii_media_active; 411202375Srdivacky ifmr->ifm_status = mii->mii_media_status; 412204642Srdivacky} 413202375Srdivacky 414202375Srdivackystatic void 415202375Srdivackyaxe_setmulti(struct usb2_ether *ue) 416202375Srdivacky{ 417251662Sdim struct axe_softc *sc = usb2_ether_getsc(ue); 418202375Srdivacky struct ifnet *ifp = usb2_ether_getifp(ue); 419202375Srdivacky struct ifmultiaddr *ifma; 420202375Srdivacky uint32_t h = 0; 421202375Srdivacky uint16_t rxmode; 422251662Sdim uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 423218893Sdim 424218893Sdim AXE_LOCK_ASSERT(sc, MA_OWNED); 425218893Sdim 426218893Sdim axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, &rxmode); 427218893Sdim rxmode = le16toh(rxmode); 428218893Sdim 429218893Sdim if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { 430202375Srdivacky rxmode |= AXE_RXCMD_ALLMULTI; 431202375Srdivacky axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 432202375Srdivacky return; 433202375Srdivacky } 434202375Srdivacky rxmode &= ~AXE_RXCMD_ALLMULTI; 435202375Srdivacky 436202375Srdivacky IF_ADDR_LOCK(ifp); 437202375Srdivacky TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 438202375Srdivacky { 439202375Srdivacky if (ifma->ifma_addr->sa_family != AF_LINK) 440202375Srdivacky continue; 441202375Srdivacky h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 442202375Srdivacky ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 443202375Srdivacky hashtbl[h / 8] |= 1 << (h % 8); 444202375Srdivacky } 445251662Sdim IF_ADDR_UNLOCK(ifp); 446218893Sdim 447218893Sdim axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, (void *)&hashtbl); 448218893Sdim axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 449218893Sdim} 450218893Sdim 451218893Sdimstatic int 452202375Srdivackyaxe_get_phyno(struct axe_softc *sc, int sel) 453202375Srdivacky{ 454202375Srdivacky int phyno; 455202375Srdivacky 456202375Srdivacky switch (AXE_PHY_TYPE(sc->sc_phyaddrs[sel])) { 457221345Sdim case PHY_TYPE_100_HOME: 458202375Srdivacky case PHY_TYPE_GIG: 459202375Srdivacky phyno = AXE_PHY_NO(sc->sc_phyaddrs[sel]); 460202375Srdivacky break; 461202375Srdivacky case PHY_TYPE_SPECIAL: 462202375Srdivacky /* FALLTHROUGH */ 463202375Srdivacky case PHY_TYPE_RSVD: 464202375Srdivacky /* FALLTHROUGH */ 465202375Srdivacky case PHY_TYPE_NON_SUP: 466202375Srdivacky /* FALLTHROUGH */ 467202375Srdivacky default: 468202375Srdivacky phyno = -1; 469202375Srdivacky break; 470202375Srdivacky } 471202375Srdivacky 472202375Srdivacky return (phyno); 473202375Srdivacky} 474202375Srdivacky 475202375Srdivackystatic void 476202375Srdivackyaxe_ax88178_init(struct axe_softc *sc) 477202375Srdivacky{ 478202375Srdivacky int gpio0 = 0, phymode = 0; 479202375Srdivacky uint16_t eeprom; 480202375Srdivacky 481202375Srdivacky axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL); 482202375Srdivacky /* XXX magic */ 483223017Sdim axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom); 484223017Sdim eeprom = le16toh(eeprom); 485223017Sdim axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL); 486223017Sdim 487223017Sdim /* if EEPROM is invalid we have to use to GPIO0 */ 488223017Sdim if (eeprom == 0xffff) { 489251662Sdim phymode = 0; 490218893Sdim gpio0 = 1; 491218893Sdim } else { 492218893Sdim phymode = eeprom & 7; 493218893Sdim gpio0 = (eeprom & 0x80) ? 0 : 1; 494218893Sdim } 495223017Sdim 496218893Sdim axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x008c, NULL); 497218893Sdim usb2_ether_pause(&sc->sc_ue, hz / 16); 498251662Sdim 499202375Srdivacky if ((eeprom >> 8) != 0x01) { 500223017Sdim axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL); 501223017Sdim usb2_ether_pause(&sc->sc_ue, hz / 32); 502223017Sdim 503223017Sdim axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x001c, NULL); 504202375Srdivacky usb2_ether_pause(&sc->sc_ue, hz / 3); 505202375Srdivacky 506202375Srdivacky axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL); 507202375Srdivacky usb2_ether_pause(&sc->sc_ue, hz / 32); 508202375Srdivacky } else { 509202375Srdivacky axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x0004, NULL); 510202375Srdivacky usb2_ether_pause(&sc->sc_ue, hz / 32); 511202375Srdivacky 512202375Srdivacky axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x000c, NULL); 513202375Srdivacky usb2_ether_pause(&sc->sc_ue, hz / 32); 514202375Srdivacky } 515202375Srdivacky 516251662Sdim /* soft reset */ 517202375Srdivacky axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); 518202375Srdivacky usb2_ether_pause(&sc->sc_ue, hz / 4); 519202375Srdivacky 520202375Srdivacky axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 521202375Srdivacky AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL); 522202375Srdivacky usb2_ether_pause(&sc->sc_ue, hz / 4); 523202375Srdivacky /* Enable MII/GMII/RGMII interface to work with external PHY. */ 524202375Srdivacky axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL); 525202375Srdivacky usb2_ether_pause(&sc->sc_ue, hz / 4); 526202375Srdivacky 527202375Srdivacky axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); 528202375Srdivacky} 529202375Srdivacky 530251662Sdimstatic void 531202375Srdivackyaxe_ax88772_init(struct axe_softc *sc) 532202375Srdivacky{ 533202375Srdivacky axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL); 534202375Srdivacky usb2_ether_pause(&sc->sc_ue, hz / 16); 535251662Sdim 536202375Srdivacky if (sc->sc_phyno == AXE_772_PHY_NO_EPHY) { 537202375Srdivacky /* ask for the embedded PHY */ 538202375Srdivacky axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x01, NULL); 539251662Sdim usb2_ether_pause(&sc->sc_ue, hz / 64); 540202375Srdivacky 541202375Srdivacky /* power down and reset state, pin reset state */ 542202375Srdivacky axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 543202375Srdivacky AXE_SW_RESET_CLEAR, NULL); 544202375Srdivacky usb2_ether_pause(&sc->sc_ue, hz / 16); 545202375Srdivacky 546202375Srdivacky /* power down/reset state, pin operating state */ 547202375Srdivacky axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 548202375Srdivacky AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); 549202375Srdivacky usb2_ether_pause(&sc->sc_ue, hz / 4); 550251662Sdim 551202375Srdivacky /* power up, reset */ 552202375Srdivacky axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL); 553202375Srdivacky 554202375Srdivacky /* power up, operating */ 555202375Srdivacky axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 556202375Srdivacky AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL); 557202375Srdivacky } else { 558202375Srdivacky /* ask for external PHY */ 559202375Srdivacky axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x00, NULL); 560251662Sdim usb2_ether_pause(&sc->sc_ue, hz / 64); 561202375Srdivacky 562202375Srdivacky /* power down internal PHY */ 563251662Sdim axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 564202375Srdivacky AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); 565202375Srdivacky } 566202375Srdivacky 567202375Srdivacky usb2_ether_pause(&sc->sc_ue, hz / 4); 568202375Srdivacky axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); 569202375Srdivacky} 570202375Srdivacky 571202375Srdivackystatic void 572202375Srdivackyaxe_reset(struct axe_softc *sc) 573251662Sdim{ 574202375Srdivacky struct usb2_config_descriptor *cd; 575202375Srdivacky usb2_error_t err; 576202375Srdivacky 577202375Srdivacky cd = usb2_get_config_descriptor(sc->sc_ue.ue_udev); 578251662Sdim 579226633Sdim err = usb2_req_set_config(sc->sc_ue.ue_udev, &sc->sc_mtx, 580202375Srdivacky cd->bConfigurationValue); 581251662Sdim if (err) 582202375Srdivacky DPRINTF("reset failed (ignored)\n"); 583202375Srdivacky 584202375Srdivacky /* Wait a little while for the chip to get its brains in order. */ 585202375Srdivacky usb2_ether_pause(&sc->sc_ue, hz / 100); 586202375Srdivacky} 587202375Srdivacky 588202375Srdivackystatic void 589202375Srdivackyaxe_attach_post(struct usb2_ether *ue) 590202375Srdivacky{ 591202375Srdivacky struct axe_softc *sc = usb2_ether_getsc(ue); 592202375Srdivacky 593202375Srdivacky /* 594202375Srdivacky * Load PHY indexes first. Needed by axe_xxx_init(). 595202375Srdivacky */ 596202375Srdivacky axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, sc->sc_phyaddrs); 597202375Srdivacky#if 1 598202375Srdivacky device_printf(sc->sc_ue.ue_dev, "PHYADDR 0x%02x:0x%02x\n", 599202375Srdivacky sc->sc_phyaddrs[0], sc->sc_phyaddrs[1]); 600202375Srdivacky#endif 601202375Srdivacky sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI); 602202375Srdivacky if (sc->sc_phyno == -1) 603202375Srdivacky sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC); 604202375Srdivacky if (sc->sc_phyno == -1) { 605202375Srdivacky device_printf(sc->sc_ue.ue_dev, 606202375Srdivacky "no valid PHY address found, assuming PHY address 0\n"); 607202375Srdivacky sc->sc_phyno = 0; 608202375Srdivacky } 609202375Srdivacky 610202375Srdivacky if (sc->sc_flags & AXE_FLAG_178) 611202375Srdivacky axe_ax88178_init(sc); 612202375Srdivacky else if (sc->sc_flags & AXE_FLAG_772) 613202375Srdivacky axe_ax88772_init(sc); 614202375Srdivacky 615202375Srdivacky /* 616202375Srdivacky * Get station address. 617202375Srdivacky */ 618202375Srdivacky if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) 619202375Srdivacky axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, ue->ue_eaddr); 620202375Srdivacky else 621202375Srdivacky axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, ue->ue_eaddr); 622251662Sdim 623202375Srdivacky /* 624202375Srdivacky * Fetch IPG values. 625202375Srdivacky */ 626202375Srdivacky axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->sc_ipgs); 627202375Srdivacky} 628202375Srdivacky 629251662Sdim/* 630202375Srdivacky * Probe for a AX88172 chip. 631202375Srdivacky */ 632251662Sdimstatic int 633202375Srdivackyaxe_probe(device_t dev) 634202375Srdivacky{ 635251662Sdim struct usb2_attach_arg *uaa = device_get_ivars(dev); 636202375Srdivacky 637202375Srdivacky if (uaa->usb2_mode != USB_MODE_HOST) 638202375Srdivacky return (ENXIO); 639202375Srdivacky if (uaa->info.bConfigIndex != AXE_CONFIG_IDX) 640202375Srdivacky return (ENXIO); 641202375Srdivacky if (uaa->info.bIfaceIndex != AXE_IFACE_IDX) 642202375Srdivacky return (ENXIO); 643202375Srdivacky 644202375Srdivacky return (usb2_lookup_id_by_uaa(axe_devs, sizeof(axe_devs), uaa)); 645251662Sdim} 646202375Srdivacky 647202375Srdivacky/* 648202375Srdivacky * Attach the interface. Allocate softc structures, do ifmedia 649202375Srdivacky * setup and ethernet/BPF attach. 650202375Srdivacky */ 651251662Sdimstatic int 652251662Sdimaxe_attach(device_t dev) 653202375Srdivacky{ 654202375Srdivacky struct usb2_attach_arg *uaa = device_get_ivars(dev); 655202375Srdivacky struct axe_softc *sc = device_get_softc(dev); 656251662Sdim struct usb2_ether *ue = &sc->sc_ue; 657202375Srdivacky uint8_t iface_index; 658202375Srdivacky int error; 659202375Srdivacky 660202375Srdivacky sc->sc_flags = USB_GET_DRIVER_INFO(uaa); 661202375Srdivacky 662202375Srdivacky device_set_usb2_desc(dev); 663251662Sdim 664202375Srdivacky mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 665202375Srdivacky 666202375Srdivacky iface_index = AXE_IFACE_IDX; 667202375Srdivacky error = usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, 668202375Srdivacky axe_config, AXE_N_TRANSFER, sc, &sc->sc_mtx); 669251662Sdim if (error) { 670202375Srdivacky device_printf(dev, "allocating USB transfers failed!\n"); 671202375Srdivacky goto detach; 672202375Srdivacky } 673202375Srdivacky 674202375Srdivacky ue->ue_sc = sc; 675251662Sdim ue->ue_dev = dev; 676202375Srdivacky ue->ue_udev = uaa->device; 677202375Srdivacky ue->ue_mtx = &sc->sc_mtx; 678202375Srdivacky ue->ue_methods = &axe_ue_methods; 679202375Srdivacky 680251662Sdim error = usb2_ether_ifattach(ue); 681202375Srdivacky if (error) { 682202375Srdivacky device_printf(dev, "could not attach interface\n"); 683202375Srdivacky goto detach; 684251662Sdim } 685202375Srdivacky return (0); /* success */ 686202375Srdivacky 687202375Srdivackydetach: 688251662Sdim axe_detach(dev); 689263508Sdim return (ENXIO); /* failure */ 690263508Sdim} 691263508Sdim 692263508Sdimstatic int 693251662Sdimaxe_detach(device_t dev) 694202375Srdivacky{ 695202375Srdivacky struct axe_softc *sc = device_get_softc(dev); 696202375Srdivacky struct usb2_ether *ue = &sc->sc_ue; 697251662Sdim 698202375Srdivacky usb2_transfer_unsetup(sc->sc_xfer, AXE_N_TRANSFER); 699202375Srdivacky usb2_ether_ifdetach(ue); 700202375Srdivacky mtx_destroy(&sc->sc_mtx); 701251662Sdim 702202375Srdivacky return (0); 703202375Srdivacky} 704202375Srdivacky 705202375Srdivackystatic void 706226633Sdimaxe_intr_callback(struct usb2_xfer *xfer) 707251662Sdim{ 708202375Srdivacky switch (USB_GET_STATE(xfer)) { 709251662Sdim case USB_ST_TRANSFERRED: 710202375Srdivacky case USB_ST_SETUP: 711202375Srdivackytr_setup: 712202375Srdivacky xfer->frlengths[0] = xfer->max_data_length; 713251662Sdim usb2_start_hardware(xfer); 714202375Srdivacky return; 715221345Sdim 716221345Sdim default: /* Error */ 717202375Srdivacky if (xfer->error != USB_ERR_CANCELLED) { 718202375Srdivacky /* try to clear stall first */ 719251662Sdim xfer->flags.stall_pipe = 1; 720202375Srdivacky goto tr_setup; 721202375Srdivacky } 722202375Srdivacky return; 723251662Sdim } 724202375Srdivacky} 725202375Srdivacky 726202375Srdivacky#if (AXE_BULK_BUF_SIZE >= 0x10000) 727202375Srdivacky#error "Please update axe_bulk_read_callback()!" 728202375Srdivacky#endif 729202375Srdivacky 730202375Srdivackystatic void 731202375Srdivackyaxe_bulk_read_callback(struct usb2_xfer *xfer) 732202375Srdivacky{ 733202375Srdivacky struct axe_softc *sc = xfer->priv_sc; 734202375Srdivacky struct usb2_ether *ue = &sc->sc_ue; 735202375Srdivacky struct ifnet *ifp = usb2_ether_getifp(ue); 736202375Srdivacky struct axe_sframe_hdr hdr; 737251662Sdim int error, pos, len, adjust; 738202375Srdivacky 739202375Srdivacky switch (USB_GET_STATE(xfer)) { 740202375Srdivacky case USB_ST_TRANSFERRED: 741202375Srdivacky pos = 0; 742202375Srdivacky while (1) { 743202375Srdivacky if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) { 744202375Srdivacky if (xfer->actlen < sizeof(hdr)) { 745202375Srdivacky /* too little data */ 746202375Srdivacky break; 747251662Sdim } 748202375Srdivacky usb2_copy_out(xfer->frbuffers, pos, &hdr, sizeof(hdr)); 749202375Srdivacky 750202375Srdivacky if ((hdr.len ^ hdr.ilen) != 0xFFFF) { 751202375Srdivacky /* we lost sync */ 752202375Srdivacky break; 753202375Srdivacky } 754202375Srdivacky xfer->actlen -= sizeof(hdr); 755202375Srdivacky pos += sizeof(hdr); 756202375Srdivacky 757251662Sdim len = le16toh(hdr.len); 758202375Srdivacky if (len > xfer->actlen) { 759202375Srdivacky /* invalid length */ 760202375Srdivacky break; 761202375Srdivacky } 762202375Srdivacky adjust = (len & 1); 763202375Srdivacky 764202375Srdivacky } else { 765202375Srdivacky len = xfer->actlen; 766251662Sdim adjust = 0; 767202375Srdivacky } 768202375Srdivacky error = usb2_ether_rxbuf(ue, xfer->frbuffers, pos, len); 769202375Srdivacky if (error) 770202375Srdivacky break; 771202375Srdivacky 772251662Sdim pos += len; 773263508Sdim xfer->actlen -= len; 774202375Srdivacky 775202375Srdivacky if (xfer->actlen <= adjust) { 776202375Srdivacky /* we are finished */ 777251662Sdim goto tr_setup; 778202375Srdivacky } 779202375Srdivacky pos += adjust; 780202375Srdivacky xfer->actlen -= adjust; 781251662Sdim } 782202375Srdivacky 783202375Srdivacky /* count an error */ 784202375Srdivacky ifp->if_ierrors++; 785202375Srdivacky 786202375Srdivacky /* FALLTHROUGH */ 787202375Srdivacky case USB_ST_SETUP: 788202375Srdivackytr_setup: 789202375Srdivacky xfer->frlengths[0] = xfer->max_data_length; 790202375Srdivacky usb2_start_hardware(xfer); 791202375Srdivacky usb2_ether_rxflush(ue); 792202375Srdivacky return; 793263508Sdim 794202375Srdivacky default: /* Error */ 795202375Srdivacky DPRINTF("bulk read error, %s\n", 796202375Srdivacky usb2_errstr(xfer->error)); 797202375Srdivacky 798202375Srdivacky if (xfer->error != USB_ERR_CANCELLED) { 799202375Srdivacky /* try to clear stall first */ 800202375Srdivacky xfer->flags.stall_pipe = 1; 801202375Srdivacky goto tr_setup; 802202375Srdivacky } 803202375Srdivacky return; 804202375Srdivacky 805202375Srdivacky } 806202375Srdivacky} 807202375Srdivacky 808202375Srdivacky#if ((AXE_BULK_BUF_SIZE >= 0x10000) || (AXE_BULK_BUF_SIZE < (MCLBYTES+4))) 809202375Srdivacky#error "Please update axe_bulk_write_callback()!" 810202375Srdivacky#endif 811202375Srdivacky 812202375Srdivackystatic void 813202375Srdivackyaxe_bulk_write_callback(struct usb2_xfer *xfer) 814202375Srdivacky{ 815202375Srdivacky struct axe_softc *sc = xfer->priv_sc; 816202375Srdivacky struct axe_sframe_hdr hdr; 817202375Srdivacky struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue); 818202375Srdivacky struct mbuf *m; 819251662Sdim int pos; 820202375Srdivacky 821202375Srdivacky switch (USB_GET_STATE(xfer)) { 822202375Srdivacky case USB_ST_TRANSFERRED: 823202375Srdivacky DPRINTFN(11, "transfer complete\n"); 824202375Srdivacky ifp->if_opackets++; 825202375Srdivacky /* FALLTHROUGH */ 826202375Srdivacky case USB_ST_SETUP: 827202375Srdivackytr_setup: 828202375Srdivacky if ((sc->sc_flags & AXE_FLAG_LINK) == 0) { 829202375Srdivacky /* 830202375Srdivacky * don't send anything if there is no link ! 831202375Srdivacky */ 832202375Srdivacky return; 833202375Srdivacky } 834202375Srdivacky pos = 0; 835202375Srdivacky 836202375Srdivacky while (1) { 837202375Srdivacky 838202375Srdivacky IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 839202375Srdivacky 840221345Sdim if (m == NULL) { 841202375Srdivacky if (pos > 0) 842221345Sdim break; /* send out data */ 843202375Srdivacky return; 844202375Srdivacky } 845202375Srdivacky if (m->m_pkthdr.len > MCLBYTES) { 846221345Sdim m->m_pkthdr.len = MCLBYTES; 847221345Sdim } 848251662Sdim if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) { 849202375Srdivacky 850202375Srdivacky hdr.len = htole16(m->m_pkthdr.len); 851221345Sdim hdr.ilen = ~hdr.len; 852202375Srdivacky 853202375Srdivacky usb2_copy_in(xfer->frbuffers, pos, &hdr, sizeof(hdr)); 854202375Srdivacky 855202375Srdivacky pos += sizeof(hdr); 856251662Sdim 857202375Srdivacky /* 858202375Srdivacky * NOTE: Some drivers force a short packet 859202375Srdivacky * by appending a dummy header with zero 860221345Sdim * length at then end of the USB transfer. 861202375Srdivacky * This driver uses the 862202375Srdivacky * USB_FORCE_SHORT_XFER flag instead. 863202375Srdivacky */ 864202375Srdivacky } 865202375Srdivacky usb2_m_copy_in(xfer->frbuffers, pos, 866202375Srdivacky m, 0, m->m_pkthdr.len); 867202375Srdivacky 868202375Srdivacky pos += m->m_pkthdr.len; 869202375Srdivacky 870202375Srdivacky /* 871202375Srdivacky * if there's a BPF listener, bounce a copy 872202375Srdivacky * of this frame to him: 873202375Srdivacky */ 874202375Srdivacky BPF_MTAP(ifp, m); 875202375Srdivacky 876202375Srdivacky m_freem(m); 877202375Srdivacky 878202375Srdivacky if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) { 879202375Srdivacky if (pos > (AXE_BULK_BUF_SIZE - MCLBYTES - sizeof(hdr))) { 880202375Srdivacky /* send out frame(s) */ 881202375Srdivacky break; 882202375Srdivacky } 883202375Srdivacky } else { 884202375Srdivacky /* send out frame */ 885202375Srdivacky break; 886202375Srdivacky } 887202375Srdivacky } 888202375Srdivacky 889202375Srdivacky xfer->frlengths[0] = pos; 890202375Srdivacky usb2_start_hardware(xfer); 891202375Srdivacky return; 892202375Srdivacky 893202375Srdivacky default: /* Error */ 894202375Srdivacky DPRINTFN(11, "transfer error, %s\n", 895202375Srdivacky usb2_errstr(xfer->error)); 896204642Srdivacky 897202375Srdivacky ifp->if_oerrors++; 898202375Srdivacky 899202375Srdivacky if (xfer->error != USB_ERR_CANCELLED) { 900251662Sdim /* try to clear stall first */ 901202375Srdivacky xfer->flags.stall_pipe = 1; 902202375Srdivacky goto tr_setup; 903 } 904 return; 905 906 } 907} 908 909static void 910axe_tick(struct usb2_ether *ue) 911{ 912 struct axe_softc *sc = usb2_ether_getsc(ue); 913 struct mii_data *mii = GET_MII(sc); 914 915 AXE_LOCK_ASSERT(sc, MA_OWNED); 916 917 mii_tick(mii); 918 if ((sc->sc_flags & AXE_FLAG_LINK) == 0 919 && mii->mii_media_status & IFM_ACTIVE && 920 IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 921 sc->sc_flags |= AXE_FLAG_LINK; 922 axe_start(ue); 923 } 924} 925 926static void 927axe_start(struct usb2_ether *ue) 928{ 929 struct axe_softc *sc = usb2_ether_getsc(ue); 930 931 /* 932 * start the USB transfers, if not already started: 933 */ 934 usb2_transfer_start(sc->sc_xfer[AXE_INTR_DT_RD]); 935 usb2_transfer_start(sc->sc_xfer[AXE_BULK_DT_RD]); 936 usb2_transfer_start(sc->sc_xfer[AXE_BULK_DT_WR]); 937} 938 939static void 940axe_init(struct usb2_ether *ue) 941{ 942 struct axe_softc *sc = usb2_ether_getsc(ue); 943 struct ifnet *ifp = usb2_ether_getifp(ue); 944 uint16_t rxmode; 945 946 AXE_LOCK_ASSERT(sc, MA_OWNED); 947 948 /* Cancel pending I/O */ 949 axe_stop(ue); 950 951#ifdef notdef 952 /* Set MAC address */ 953 axe_mac(sc, IF_LLADDR(ifp), 1); 954#endif 955 956 /* Set transmitter IPG values */ 957 if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) { 958 axe_cmd(sc, AXE_178_CMD_WRITE_IPG012, sc->sc_ipgs[2], 959 (sc->sc_ipgs[1] << 8) | (sc->sc_ipgs[0]), NULL); 960 } else { 961 axe_cmd(sc, AXE_172_CMD_WRITE_IPG0, 0, sc->sc_ipgs[0], NULL); 962 axe_cmd(sc, AXE_172_CMD_WRITE_IPG1, 0, sc->sc_ipgs[1], NULL); 963 axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->sc_ipgs[2], NULL); 964 } 965 966 /* Enable receiver, set RX mode */ 967 rxmode = (AXE_RXCMD_MULTICAST | AXE_RXCMD_ENABLE); 968 if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) { 969 rxmode |= AXE_178_RXCMD_MFB_2048; /* chip default */ 970 } else { 971 rxmode |= AXE_172_RXCMD_UNICAST; 972 } 973 974 /* If we want promiscuous mode, set the allframes bit. */ 975 if (ifp->if_flags & IFF_PROMISC) 976 rxmode |= AXE_RXCMD_PROMISC; 977 978 if (ifp->if_flags & IFF_BROADCAST) 979 rxmode |= AXE_RXCMD_BROADCAST; 980 981 axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 982 983 /* Load the multicast filter. */ 984 axe_setmulti(ue); 985 986 usb2_transfer_set_stall(sc->sc_xfer[AXE_BULK_DT_WR]); 987 988 ifp->if_drv_flags |= IFF_DRV_RUNNING; 989 axe_start(ue); 990} 991 992static void 993axe_setpromisc(struct usb2_ether *ue) 994{ 995 struct axe_softc *sc = usb2_ether_getsc(ue); 996 struct ifnet *ifp = usb2_ether_getifp(ue); 997 uint16_t rxmode; 998 999 axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, &rxmode); 1000 1001 rxmode = le16toh(rxmode); 1002 1003 if (ifp->if_flags & IFF_PROMISC) { 1004 rxmode |= AXE_RXCMD_PROMISC; 1005 } else { 1006 rxmode &= ~AXE_RXCMD_PROMISC; 1007 } 1008 1009 axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 1010 1011 axe_setmulti(ue); 1012} 1013 1014static void 1015axe_stop(struct usb2_ether *ue) 1016{ 1017 struct axe_softc *sc = usb2_ether_getsc(ue); 1018 struct ifnet *ifp = usb2_ether_getifp(ue); 1019 1020 AXE_LOCK_ASSERT(sc, MA_OWNED); 1021 1022 ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1023 sc->sc_flags &= ~AXE_FLAG_LINK; 1024 1025 /* 1026 * stop all the transfers, if not already stopped: 1027 */ 1028 usb2_transfer_stop(sc->sc_xfer[AXE_BULK_DT_WR]); 1029 usb2_transfer_stop(sc->sc_xfer[AXE_BULK_DT_RD]); 1030 usb2_transfer_stop(sc->sc_xfer[AXE_INTR_DT_RD]); 1031 1032 axe_reset(sc); 1033} 1034 1035/* 1036 * Stop all chip I/O so that the kernel's probe routines don't 1037 * get confused by errant DMAs when rebooting. 1038 */ 1039static int 1040axe_shutdown(device_t dev) 1041{ 1042 struct axe_softc *sc = device_get_softc(dev); 1043 1044 usb2_ether_ifshutdown(&sc->sc_ue); 1045 1046 return (0); 1047} 1048