if_axe.c revision 212980
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 212980 2010-09-21 22:42:14Z sanpei $"); 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 79194677Sthompsa#include <sys/stdint.h> 80194677Sthompsa#include <sys/stddef.h> 81194677Sthompsa#include <sys/param.h> 82194677Sthompsa#include <sys/queue.h> 83194677Sthompsa#include <sys/types.h> 84194677Sthompsa#include <sys/systm.h> 85194677Sthompsa#include <sys/kernel.h> 86194677Sthompsa#include <sys/bus.h> 87194677Sthompsa#include <sys/linker_set.h> 88194677Sthompsa#include <sys/module.h> 89194677Sthompsa#include <sys/lock.h> 90194677Sthompsa#include <sys/mutex.h> 91194677Sthompsa#include <sys/condvar.h> 92194677Sthompsa#include <sys/sysctl.h> 93194677Sthompsa#include <sys/sx.h> 94194677Sthompsa#include <sys/unistd.h> 95194677Sthompsa#include <sys/callout.h> 96194677Sthompsa#include <sys/malloc.h> 97194677Sthompsa#include <sys/priv.h> 98194677Sthompsa 99194677Sthompsa#include <dev/usb/usb.h> 100194677Sthompsa#include <dev/usb/usbdi.h> 101194677Sthompsa#include <dev/usb/usbdi_util.h> 102188746Sthompsa#include "usbdevs.h" 103184610Salfred 104184610Salfred#define USB_DEBUG_VAR axe_debug 105194677Sthompsa#include <dev/usb/usb_debug.h> 106188942Sthompsa#include <dev/usb/usb_process.h> 107184610Salfred 108188942Sthompsa#include <dev/usb/net/usb_ethernet.h> 109188942Sthompsa#include <dev/usb/net/if_axereg.h> 110184610Salfred 111188412Sthompsa/* 112188412Sthompsa * AXE_178_MAX_FRAME_BURST 113188412Sthompsa * max frame burst size for Ax88178 and Ax88772 114188412Sthompsa * 0 2048 bytes 115188412Sthompsa * 1 4096 bytes 116188412Sthompsa * 2 8192 bytes 117188412Sthompsa * 3 16384 bytes 118188412Sthompsa * use the largest your system can handle without USB stalling. 119188412Sthompsa * 120188412Sthompsa * NB: 88772 parts appear to generate lots of input errors with 121188412Sthompsa * a 2K rx buffer and 8K is only slightly faster than 4K on an 122188412Sthompsa * EHCI port on a T42 so change at your own risk. 123188412Sthompsa */ 124188412Sthompsa#define AXE_178_MAX_FRAME_BURST 1 125184610Salfred 126207077Sthompsa#ifdef USB_DEBUG 127184610Salfredstatic int axe_debug = 0; 128184610Salfred 129192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, axe, CTLFLAG_RW, 0, "USB axe"); 130192502SthompsaSYSCTL_INT(_hw_usb_axe, OID_AUTO, debug, CTLFLAG_RW, &axe_debug, 0, 131184610Salfred "Debug level"); 132184610Salfred#endif 133184610Salfred 134184610Salfred/* 135184610Salfred * Various supported device vendors/products. 136184610Salfred */ 137192984Sthompsastatic const struct usb_device_id axe_devs[] = { 138201028Sthompsa#define AXE_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } 139201028Sthompsa AXE_DEV(ABOCOM, UF200, 0), 140201028Sthompsa AXE_DEV(ACERCM, EP1427X2, 0), 141201028Sthompsa AXE_DEV(APPLE, ETHERNET, AXE_FLAG_772), 142201028Sthompsa AXE_DEV(ASIX, AX88172, 0), 143201028Sthompsa AXE_DEV(ASIX, AX88178, AXE_FLAG_178), 144201028Sthompsa AXE_DEV(ASIX, AX88772, AXE_FLAG_772), 145201028Sthompsa AXE_DEV(ASIX, AX88772A, AXE_FLAG_772), 146201028Sthompsa AXE_DEV(ATEN, UC210T, 0), 147201028Sthompsa AXE_DEV(BELKIN, F5D5055, AXE_FLAG_178), 148201028Sthompsa AXE_DEV(BILLIONTON, USB2AR, 0), 149201028Sthompsa AXE_DEV(CISCOLINKSYS, USB200MV2, AXE_FLAG_772), 150201028Sthompsa AXE_DEV(COREGA, FETHER_USB2_TX, 0), 151201028Sthompsa AXE_DEV(DLINK, DUBE100, 0), 152201028Sthompsa AXE_DEV(DLINK, DUBE100B1, AXE_FLAG_772), 153201028Sthompsa AXE_DEV(GOODWAY, GWUSB2E, 0), 154201028Sthompsa AXE_DEV(IODATA, ETGUS2, AXE_FLAG_178), 155201028Sthompsa AXE_DEV(JVC, MP_PRX1, 0), 156201028Sthompsa AXE_DEV(LINKSYS2, USB200M, 0), 157201028Sthompsa AXE_DEV(LINKSYS4, USB1000, AXE_FLAG_178), 158212980Ssanpei AXE_DEV(LOGITEC, LAN_GTJU2A, AXE_FLAG_178), 159201028Sthompsa AXE_DEV(MELCO, LUAU2KTX, 0), 160212980Ssanpei AXE_DEV(MELCO, LUA3U2AGT, AXE_FLAG_178), 161201028Sthompsa AXE_DEV(NETGEAR, FA120, 0), 162201028Sthompsa AXE_DEV(OQO, ETHER01PLUS, AXE_FLAG_772), 163201028Sthompsa AXE_DEV(PLANEX3, GU1000T, AXE_FLAG_178), 164201028Sthompsa AXE_DEV(SITECOM, LN029, 0), 165201028Sthompsa AXE_DEV(SITECOMEU, LN028, AXE_FLAG_178), 166201028Sthompsa AXE_DEV(SYSTEMTALKS, SGCX2UL, 0), 167201028Sthompsa#undef AXE_DEV 168184610Salfred}; 169184610Salfred 170184610Salfredstatic device_probe_t axe_probe; 171184610Salfredstatic device_attach_t axe_attach; 172184610Salfredstatic device_detach_t axe_detach; 173184610Salfred 174193045Sthompsastatic usb_callback_t axe_intr_callback; 175193045Sthompsastatic usb_callback_t axe_bulk_read_callback; 176193045Sthompsastatic usb_callback_t axe_bulk_write_callback; 177184610Salfred 178188412Sthompsastatic miibus_readreg_t axe_miibus_readreg; 179188412Sthompsastatic miibus_writereg_t axe_miibus_writereg; 180188412Sthompsastatic miibus_statchg_t axe_miibus_statchg; 181184610Salfred 182193045Sthompsastatic uether_fn_t axe_attach_post; 183193045Sthompsastatic uether_fn_t axe_init; 184193045Sthompsastatic uether_fn_t axe_stop; 185193045Sthompsastatic uether_fn_t axe_start; 186193045Sthompsastatic uether_fn_t axe_tick; 187193045Sthompsastatic uether_fn_t axe_setmulti; 188193045Sthompsastatic uether_fn_t axe_setpromisc; 189184610Salfred 190188412Sthompsastatic int axe_ifmedia_upd(struct ifnet *); 191188412Sthompsastatic void axe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 192188412Sthompsastatic int axe_cmd(struct axe_softc *, int, int, int, void *); 193188412Sthompsastatic void axe_ax88178_init(struct axe_softc *); 194188412Sthompsastatic void axe_ax88772_init(struct axe_softc *); 195186730Salfredstatic int axe_get_phyno(struct axe_softc *, int); 196184610Salfred 197192984Sthompsastatic const struct usb_config axe_config[AXE_N_TRANSFER] = { 198184610Salfred 199187259Sthompsa [AXE_BULK_DT_WR] = { 200184610Salfred .type = UE_BULK, 201184610Salfred .endpoint = UE_ADDR_ANY, 202184610Salfred .direction = UE_DIR_OUT, 203190734Sthompsa .bufsize = AXE_BULK_BUF_SIZE, 204190734Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 205190734Sthompsa .callback = axe_bulk_write_callback, 206190734Sthompsa .timeout = 10000, /* 10 seconds */ 207184610Salfred }, 208184610Salfred 209187259Sthompsa [AXE_BULK_DT_RD] = { 210184610Salfred .type = UE_BULK, 211184610Salfred .endpoint = UE_ADDR_ANY, 212184610Salfred .direction = UE_DIR_IN, 213197566Sthompsa .bufsize = 16384, /* bytes */ 214190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 215190734Sthompsa .callback = axe_bulk_read_callback, 216190734Sthompsa .timeout = 0, /* no timeout */ 217184610Salfred }, 218184610Salfred 219187259Sthompsa [AXE_INTR_DT_RD] = { 220184610Salfred .type = UE_INTERRUPT, 221184610Salfred .endpoint = UE_ADDR_ANY, 222184610Salfred .direction = UE_DIR_IN, 223190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 224190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 225190734Sthompsa .callback = axe_intr_callback, 226184610Salfred }, 227184610Salfred}; 228184610Salfred 229184610Salfredstatic device_method_t axe_methods[] = { 230184610Salfred /* Device interface */ 231184610Salfred DEVMETHOD(device_probe, axe_probe), 232184610Salfred DEVMETHOD(device_attach, axe_attach), 233184610Salfred DEVMETHOD(device_detach, axe_detach), 234184610Salfred 235184610Salfred /* bus interface */ 236184610Salfred DEVMETHOD(bus_print_child, bus_generic_print_child), 237184610Salfred DEVMETHOD(bus_driver_added, bus_generic_driver_added), 238184610Salfred 239184610Salfred /* MII interface */ 240188412Sthompsa DEVMETHOD(miibus_readreg, axe_miibus_readreg), 241188412Sthompsa DEVMETHOD(miibus_writereg, axe_miibus_writereg), 242188412Sthompsa DEVMETHOD(miibus_statchg, axe_miibus_statchg), 243184610Salfred 244184610Salfred {0, 0} 245184610Salfred}; 246184610Salfred 247184610Salfredstatic driver_t axe_driver = { 248184610Salfred .name = "axe", 249184610Salfred .methods = axe_methods, 250184610Salfred .size = sizeof(struct axe_softc), 251184610Salfred}; 252184610Salfred 253184610Salfredstatic devclass_t axe_devclass; 254184610Salfred 255189275SthompsaDRIVER_MODULE(axe, uhub, axe_driver, axe_devclass, NULL, 0); 256184610SalfredDRIVER_MODULE(miibus, axe, miibus_driver, miibus_devclass, 0, 0); 257188942SthompsaMODULE_DEPEND(axe, uether, 1, 1, 1); 258188942SthompsaMODULE_DEPEND(axe, usb, 1, 1, 1); 259188412SthompsaMODULE_DEPEND(axe, ether, 1, 1, 1); 260188412SthompsaMODULE_DEPEND(axe, miibus, 1, 1, 1); 261212122SthompsaMODULE_VERSION(axe, 1); 262184610Salfred 263192984Sthompsastatic const struct usb_ether_methods axe_ue_methods = { 264188412Sthompsa .ue_attach_post = axe_attach_post, 265188412Sthompsa .ue_start = axe_start, 266188412Sthompsa .ue_init = axe_init, 267188412Sthompsa .ue_stop = axe_stop, 268188412Sthompsa .ue_tick = axe_tick, 269188412Sthompsa .ue_setmulti = axe_setmulti, 270188412Sthompsa .ue_setpromisc = axe_setpromisc, 271188412Sthompsa .ue_mii_upd = axe_ifmedia_upd, 272188412Sthompsa .ue_mii_sts = axe_ifmedia_sts, 273188412Sthompsa}; 274188412Sthompsa 275188412Sthompsastatic int 276188412Sthompsaaxe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf) 277184610Salfred{ 278192984Sthompsa struct usb_device_request req; 279193045Sthompsa usb_error_t err; 280184610Salfred 281188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 282188412Sthompsa 283184610Salfred req.bmRequestType = (AXE_CMD_IS_WRITE(cmd) ? 284184610Salfred UT_WRITE_VENDOR_DEVICE : 285184610Salfred UT_READ_VENDOR_DEVICE); 286184610Salfred req.bRequest = AXE_CMD_CMD(cmd); 287184610Salfred USETW(req.wValue, val); 288184610Salfred USETW(req.wIndex, index); 289188412Sthompsa USETW(req.wLength, AXE_CMD_LEN(cmd)); 290184610Salfred 291194228Sthompsa err = uether_do_request(&sc->sc_ue, &req, buf, 1000); 292184610Salfred 293188412Sthompsa return (err); 294184610Salfred} 295184610Salfred 296184610Salfredstatic int 297188412Sthompsaaxe_miibus_readreg(device_t dev, int phy, int reg) 298184610Salfred{ 299184610Salfred struct axe_softc *sc = device_get_softc(dev); 300184610Salfred uint16_t val; 301188412Sthompsa int locked; 302184610Salfred 303188412Sthompsa if (sc->sc_phyno != phy) 304188412Sthompsa return (0); 305184610Salfred 306188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 307188412Sthompsa if (!locked) 308188412Sthompsa AXE_LOCK(sc); 309186730Salfred 310188412Sthompsa axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); 311188412Sthompsa axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, &val); 312188412Sthompsa axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); 313184610Salfred 314184610Salfred val = le16toh(val); 315186730Salfred if ((sc->sc_flags & AXE_FLAG_772) != 0 && reg == MII_BMSR) { 316186730Salfred /* 317186730Salfred * BMSR of AX88772 indicates that it supports extended 318186730Salfred * capability but the extended status register is 319186730Salfred * revered for embedded ethernet PHY. So clear the 320186730Salfred * extended capability bit of BMSR. 321186730Salfred */ 322186730Salfred val &= ~BMSR_EXTCAP; 323186730Salfred } 324184610Salfred 325188412Sthompsa if (!locked) 326188412Sthompsa AXE_UNLOCK(sc); 327184610Salfred return (val); 328184610Salfred} 329184610Salfred 330184610Salfredstatic int 331188412Sthompsaaxe_miibus_writereg(device_t dev, int phy, int reg, int val) 332184610Salfred{ 333184610Salfred struct axe_softc *sc = device_get_softc(dev); 334188412Sthompsa int locked; 335184610Salfred 336189522Sthompsa val = htole32(val); 337184610Salfred 338186730Salfred if (sc->sc_phyno != phy) 339188412Sthompsa return (0); 340186730Salfred 341188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 342188412Sthompsa if (!locked) 343188412Sthompsa AXE_LOCK(sc); 344184610Salfred 345188412Sthompsa axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); 346188412Sthompsa axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, &val); 347188412Sthompsa axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); 348188412Sthompsa 349188412Sthompsa if (!locked) 350188412Sthompsa AXE_UNLOCK(sc); 351184610Salfred return (0); 352184610Salfred} 353184610Salfred 354184610Salfredstatic void 355188412Sthompsaaxe_miibus_statchg(device_t dev) 356184610Salfred{ 357184610Salfred struct axe_softc *sc = device_get_softc(dev); 358184610Salfred struct mii_data *mii = GET_MII(sc); 359188553Sthompsa struct ifnet *ifp; 360184610Salfred uint16_t val; 361188412Sthompsa int err, locked; 362184610Salfred 363188412Sthompsa locked = mtx_owned(&sc->sc_mtx); 364188412Sthompsa if (!locked) 365188412Sthompsa AXE_LOCK(sc); 366184610Salfred 367194228Sthompsa ifp = uether_getifp(&sc->sc_ue); 368188553Sthompsa if (mii == NULL || ifp == NULL || 369188553Sthompsa (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 370188553Sthompsa goto done; 371188553Sthompsa 372188553Sthompsa sc->sc_flags &= ~AXE_FLAG_LINK; 373188553Sthompsa if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 374188553Sthompsa (IFM_ACTIVE | IFM_AVALID)) { 375188553Sthompsa switch (IFM_SUBTYPE(mii->mii_media_active)) { 376188553Sthompsa case IFM_10_T: 377188553Sthompsa case IFM_100_TX: 378188553Sthompsa sc->sc_flags |= AXE_FLAG_LINK; 379188553Sthompsa break; 380188553Sthompsa case IFM_1000_T: 381188553Sthompsa if ((sc->sc_flags & AXE_FLAG_178) == 0) 382188553Sthompsa break; 383188553Sthompsa sc->sc_flags |= AXE_FLAG_LINK; 384188553Sthompsa break; 385188553Sthompsa default: 386188553Sthompsa break; 387188553Sthompsa } 388188553Sthompsa } 389188553Sthompsa 390188553Sthompsa /* Lost link, do nothing. */ 391188553Sthompsa if ((sc->sc_flags & AXE_FLAG_LINK) == 0) 392188553Sthompsa goto done; 393188553Sthompsa 394188553Sthompsa val = 0; 395188553Sthompsa if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) 396188553Sthompsa val |= AXE_MEDIA_FULL_DUPLEX; 397186730Salfred if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) { 398186730Salfred val |= AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC; 399188553Sthompsa if ((sc->sc_flags & AXE_FLAG_178) != 0) 400188553Sthompsa val |= AXE_178_MEDIA_ENCK; 401184610Salfred switch (IFM_SUBTYPE(mii->mii_media_active)) { 402184610Salfred case IFM_1000_T: 403184610Salfred val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK; 404184610Salfred break; 405184610Salfred case IFM_100_TX: 406184610Salfred val |= AXE_178_MEDIA_100TX; 407184610Salfred break; 408184610Salfred case IFM_10_T: 409184610Salfred /* doesn't need to be handled */ 410184610Salfred break; 411184610Salfred } 412184610Salfred } 413188412Sthompsa err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL); 414188412Sthompsa if (err) 415188412Sthompsa device_printf(dev, "media change failed, error %d\n", err); 416188553Sthompsadone: 417188412Sthompsa if (!locked) 418188412Sthompsa AXE_UNLOCK(sc); 419184610Salfred} 420184610Salfred 421184610Salfred/* 422184610Salfred * Set media options. 423184610Salfred */ 424184610Salfredstatic int 425188412Sthompsaaxe_ifmedia_upd(struct ifnet *ifp) 426184610Salfred{ 427184610Salfred struct axe_softc *sc = ifp->if_softc; 428184610Salfred struct mii_data *mii = GET_MII(sc); 429188553Sthompsa int error; 430184610Salfred 431188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 432184610Salfred 433184610Salfred if (mii->mii_instance) { 434184610Salfred struct mii_softc *miisc; 435184610Salfred 436188412Sthompsa LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 437184610Salfred mii_phy_reset(miisc); 438184610Salfred } 439188553Sthompsa error = mii_mediachg(mii); 440188553Sthompsa return (error); 441184610Salfred} 442184610Salfred 443184610Salfred/* 444184610Salfred * Report current media status. 445184610Salfred */ 446184610Salfredstatic void 447188412Sthompsaaxe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 448184610Salfred{ 449184610Salfred struct axe_softc *sc = ifp->if_softc; 450188412Sthompsa struct mii_data *mii = GET_MII(sc); 451184610Salfred 452188412Sthompsa AXE_LOCK(sc); 453188412Sthompsa mii_pollstat(mii); 454188412Sthompsa AXE_UNLOCK(sc); 455188412Sthompsa ifmr->ifm_active = mii->mii_media_active; 456188412Sthompsa ifmr->ifm_status = mii->mii_media_status; 457184610Salfred} 458184610Salfred 459184610Salfredstatic void 460192984Sthompsaaxe_setmulti(struct usb_ether *ue) 461184610Salfred{ 462194228Sthompsa struct axe_softc *sc = uether_getsc(ue); 463194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 464188412Sthompsa struct ifmultiaddr *ifma; 465188412Sthompsa uint32_t h = 0; 466184610Salfred uint16_t rxmode; 467188412Sthompsa uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 468184610Salfred 469188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 470184610Salfred 471188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, &rxmode); 472184610Salfred rxmode = le16toh(rxmode); 473184610Salfred 474188412Sthompsa if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { 475184610Salfred rxmode |= AXE_RXCMD_ALLMULTI; 476188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 477184610Salfred return; 478184610Salfred } 479184610Salfred rxmode &= ~AXE_RXCMD_ALLMULTI; 480184610Salfred 481195049Srwatson if_maddr_rlock(ifp); 482188412Sthompsa TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 483188412Sthompsa { 484188412Sthompsa if (ifma->ifma_addr->sa_family != AF_LINK) 485188412Sthompsa continue; 486188412Sthompsa h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 487188412Sthompsa ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 488188412Sthompsa hashtbl[h / 8] |= 1 << (h % 8); 489188412Sthompsa } 490195049Srwatson if_maddr_runlock(ifp); 491184610Salfred 492188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, (void *)&hashtbl); 493188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 494184610Salfred} 495184610Salfred 496186730Salfredstatic int 497186730Salfredaxe_get_phyno(struct axe_softc *sc, int sel) 498186730Salfred{ 499188412Sthompsa int phyno; 500186730Salfred 501186730Salfred switch (AXE_PHY_TYPE(sc->sc_phyaddrs[sel])) { 502186730Salfred case PHY_TYPE_100_HOME: 503186730Salfred case PHY_TYPE_GIG: 504188412Sthompsa phyno = AXE_PHY_NO(sc->sc_phyaddrs[sel]); 505186730Salfred break; 506186730Salfred case PHY_TYPE_SPECIAL: 507186730Salfred /* FALLTHROUGH */ 508186730Salfred case PHY_TYPE_RSVD: 509186730Salfred /* FALLTHROUGH */ 510186730Salfred case PHY_TYPE_NON_SUP: 511186730Salfred /* FALLTHROUGH */ 512186730Salfred default: 513186730Salfred phyno = -1; 514186730Salfred break; 515186730Salfred } 516186730Salfred 517186730Salfred return (phyno); 518186730Salfred} 519186730Salfred 520212130Sthompsa#define AXE_GPIO_WRITE(x, y) do { \ 521212130Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, (x), NULL); \ 522212130Sthompsa uether_pause(ue, (y)); \ 523212130Sthompsa} while (0) 524212130Sthompsa 525184610Salfredstatic void 526188412Sthompsaaxe_ax88178_init(struct axe_softc *sc) 527184610Salfred{ 528212130Sthompsa struct usb_ether *ue; 529212130Sthompsa int gpio0, phymode; 530212130Sthompsa uint16_t eeprom, val; 531184610Salfred 532212130Sthompsa ue = &sc->sc_ue; 533188412Sthompsa axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL); 534184610Salfred /* XXX magic */ 535188412Sthompsa axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom); 536184610Salfred eeprom = le16toh(eeprom); 537188412Sthompsa axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL); 538184610Salfred 539184610Salfred /* if EEPROM is invalid we have to use to GPIO0 */ 540184610Salfred if (eeprom == 0xffff) { 541212130Sthompsa phymode = AXE_PHY_MODE_MARVELL; 542184610Salfred gpio0 = 1; 543184610Salfred } else { 544212130Sthompsa phymode = eeprom & 0x7f; 545184610Salfred gpio0 = (eeprom & 0x80) ? 0 : 1; 546184610Salfred } 547184610Salfred 548212130Sthompsa if (bootverbose) 549212130Sthompsa device_printf(sc->sc_ue.ue_dev, "EEPROM data : 0x%04x\n", 550212130Sthompsa eeprom); 551212130Sthompsa /* Program GPIOs depending on PHY hardware. */ 552212130Sthompsa switch (phymode) { 553212130Sthompsa case AXE_PHY_MODE_MARVELL: 554212130Sthompsa if (gpio0 == 1) { 555212130Sthompsa AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0_EN, 556212130Sthompsa hz / 32); 557212130Sthompsa AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, 558212130Sthompsa hz / 32); 559212130Sthompsa AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2_EN, hz / 4); 560212130Sthompsa AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, 561212130Sthompsa hz / 32); 562212130Sthompsa } else 563212130Sthompsa AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | 564212130Sthompsa AXE_GPIO1_EN, hz / 32); 565212130Sthompsa break; 566212130Sthompsa case AXE_PHY_MODE_CICADA: 567212130Sthompsa if (gpio0 == 1) 568212130Sthompsa AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0 | 569212130Sthompsa AXE_GPIO0_EN, hz / 32); 570212130Sthompsa else 571212130Sthompsa AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | 572212130Sthompsa AXE_GPIO1_EN, hz / 32); 573212130Sthompsa break; 574212130Sthompsa case AXE_PHY_MODE_AGERE: 575212130Sthompsa AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | 576212130Sthompsa AXE_GPIO1_EN, hz / 32); 577212130Sthompsa AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | 578212130Sthompsa AXE_GPIO2_EN, hz / 32); 579212130Sthompsa AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2_EN, hz / 4); 580212130Sthompsa AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | 581212130Sthompsa AXE_GPIO2_EN, hz / 32); 582212130Sthompsa break; 583212130Sthompsa case AXE_PHY_MODE_REALTEK_8211CL: 584212130Sthompsa case AXE_PHY_MODE_REALTEK_8211BN: 585212130Sthompsa case AXE_PHY_MODE_REALTEK_8251CL: 586212130Sthompsa val = gpio0 == 1 ? AXE_GPIO0 | AXE_GPIO0_EN : 587212130Sthompsa AXE_GPIO1 | AXE_GPIO1_EN; 588212130Sthompsa AXE_GPIO_WRITE(val, hz / 32); 589212130Sthompsa AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); 590212130Sthompsa AXE_GPIO_WRITE(val | AXE_GPIO2_EN, hz / 4); 591212130Sthompsa AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); 592212130Sthompsa if (phymode == AXE_PHY_MODE_REALTEK_8211CL) { 593212130Sthompsa axe_miibus_writereg(ue->ue_dev, sc->sc_phyno, 594212130Sthompsa 0x1F, 0x0005); 595212130Sthompsa axe_miibus_writereg(ue->ue_dev, sc->sc_phyno, 596212130Sthompsa 0x0C, 0x0000); 597212130Sthompsa val = axe_miibus_readreg(ue->ue_dev, sc->sc_phyno, 598212130Sthompsa 0x0001); 599212130Sthompsa axe_miibus_writereg(ue->ue_dev, sc->sc_phyno, 600212130Sthompsa 0x01, val | 0x0080); 601212130Sthompsa axe_miibus_writereg(ue->ue_dev, sc->sc_phyno, 602212130Sthompsa 0x1F, 0x0000); 603212130Sthompsa } 604212130Sthompsa break; 605212130Sthompsa default: 606212130Sthompsa /* Unknown PHY model or no need to program GPIOs. */ 607212130Sthompsa break; 608184610Salfred } 609184610Salfred 610184610Salfred /* soft reset */ 611188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); 612212130Sthompsa uether_pause(ue, hz / 4); 613184610Salfred 614188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 615184610Salfred AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL); 616212130Sthompsa uether_pause(ue, hz / 4); 617186730Salfred /* Enable MII/GMII/RGMII interface to work with external PHY. */ 618188412Sthompsa axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL); 619212130Sthompsa uether_pause(ue, hz / 4); 620184610Salfred 621188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); 622184610Salfred} 623212130Sthompsa#undef AXE_GPIO_WRITE 624184610Salfred 625184610Salfredstatic void 626188412Sthompsaaxe_ax88772_init(struct axe_softc *sc) 627184610Salfred{ 628188412Sthompsa axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL); 629194228Sthompsa uether_pause(&sc->sc_ue, hz / 16); 630184610Salfred 631186730Salfred if (sc->sc_phyno == AXE_772_PHY_NO_EPHY) { 632184610Salfred /* ask for the embedded PHY */ 633188412Sthompsa axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x01, NULL); 634194228Sthompsa uether_pause(&sc->sc_ue, hz / 64); 635184610Salfred 636184610Salfred /* power down and reset state, pin reset state */ 637188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 638184610Salfred AXE_SW_RESET_CLEAR, NULL); 639194228Sthompsa uether_pause(&sc->sc_ue, hz / 16); 640184610Salfred 641184610Salfred /* power down/reset state, pin operating state */ 642188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 643184610Salfred AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); 644194228Sthompsa uether_pause(&sc->sc_ue, hz / 4); 645184610Salfred 646184610Salfred /* power up, reset */ 647188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL); 648184610Salfred 649184610Salfred /* power up, operating */ 650188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 651184610Salfred AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL); 652184610Salfred } else { 653184610Salfred /* ask for external PHY */ 654188412Sthompsa axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x00, NULL); 655194228Sthompsa uether_pause(&sc->sc_ue, hz / 64); 656184610Salfred 657184610Salfred /* power down internal PHY */ 658188412Sthompsa axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, 659184610Salfred AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); 660184610Salfred } 661184610Salfred 662194228Sthompsa uether_pause(&sc->sc_ue, hz / 4); 663188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); 664184610Salfred} 665184610Salfred 666184610Salfredstatic void 667188412Sthompsaaxe_reset(struct axe_softc *sc) 668184610Salfred{ 669192984Sthompsa struct usb_config_descriptor *cd; 670193045Sthompsa usb_error_t err; 671184610Salfred 672194228Sthompsa cd = usbd_get_config_descriptor(sc->sc_ue.ue_udev); 673184610Salfred 674194228Sthompsa err = usbd_req_set_config(sc->sc_ue.ue_udev, &sc->sc_mtx, 675188412Sthompsa cd->bConfigurationValue); 676188412Sthompsa if (err) 677188412Sthompsa DPRINTF("reset failed (ignored)\n"); 678188412Sthompsa 679188412Sthompsa /* Wait a little while for the chip to get its brains in order. */ 680194228Sthompsa uether_pause(&sc->sc_ue, hz / 100); 681188412Sthompsa} 682188412Sthompsa 683188412Sthompsastatic void 684192984Sthompsaaxe_attach_post(struct usb_ether *ue) 685188412Sthompsa{ 686194228Sthompsa struct axe_softc *sc = uether_getsc(ue); 687188412Sthompsa 688184610Salfred /* 689184610Salfred * Load PHY indexes first. Needed by axe_xxx_init(). 690184610Salfred */ 691188412Sthompsa axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, sc->sc_phyaddrs); 692212130Sthompsa if (bootverbose) 693212130Sthompsa device_printf(sc->sc_ue.ue_dev, "PHYADDR 0x%02x:0x%02x\n", 694212130Sthompsa sc->sc_phyaddrs[0], sc->sc_phyaddrs[1]); 695186730Salfred sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI); 696186730Salfred if (sc->sc_phyno == -1) 697186730Salfred sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC); 698186730Salfred if (sc->sc_phyno == -1) { 699188412Sthompsa device_printf(sc->sc_ue.ue_dev, 700188412Sthompsa "no valid PHY address found, assuming PHY address 0\n"); 701186730Salfred sc->sc_phyno = 0; 702186730Salfred } 703184610Salfred 704188412Sthompsa if (sc->sc_flags & AXE_FLAG_178) 705188412Sthompsa axe_ax88178_init(sc); 706188412Sthompsa else if (sc->sc_flags & AXE_FLAG_772) 707188412Sthompsa axe_ax88772_init(sc); 708188412Sthompsa 709184610Salfred /* 710184610Salfred * Get station address. 711184610Salfred */ 712184610Salfred if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) 713188412Sthompsa axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, ue->ue_eaddr); 714184610Salfred else 715188412Sthompsa axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, ue->ue_eaddr); 716184610Salfred 717184610Salfred /* 718184610Salfred * Fetch IPG values. 719184610Salfred */ 720188412Sthompsa axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->sc_ipgs); 721188412Sthompsa} 722184610Salfred 723188412Sthompsa/* 724188412Sthompsa * Probe for a AX88172 chip. 725188412Sthompsa */ 726188412Sthompsastatic int 727188412Sthompsaaxe_probe(device_t dev) 728188412Sthompsa{ 729192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 730184610Salfred 731192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 732188412Sthompsa return (ENXIO); 733188412Sthompsa if (uaa->info.bConfigIndex != AXE_CONFIG_IDX) 734188412Sthompsa return (ENXIO); 735188412Sthompsa if (uaa->info.bIfaceIndex != AXE_IFACE_IDX) 736188412Sthompsa return (ENXIO); 737184610Salfred 738194228Sthompsa return (usbd_lookup_id_by_uaa(axe_devs, sizeof(axe_devs), uaa)); 739188412Sthompsa} 740184610Salfred 741188412Sthompsa/* 742188412Sthompsa * Attach the interface. Allocate softc structures, do ifmedia 743188412Sthompsa * setup and ethernet/BPF attach. 744188412Sthompsa */ 745188412Sthompsastatic int 746188412Sthompsaaxe_attach(device_t dev) 747188412Sthompsa{ 748192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 749188412Sthompsa struct axe_softc *sc = device_get_softc(dev); 750192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 751188412Sthompsa uint8_t iface_index; 752188412Sthompsa int error; 753184610Salfred 754188412Sthompsa sc->sc_flags = USB_GET_DRIVER_INFO(uaa); 755184610Salfred 756194228Sthompsa device_set_usb_desc(dev); 757184610Salfred 758188412Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 759184610Salfred 760188412Sthompsa iface_index = AXE_IFACE_IDX; 761194228Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, 762188412Sthompsa axe_config, AXE_N_TRANSFER, sc, &sc->sc_mtx); 763188412Sthompsa if (error) { 764199816Sthompsa device_printf(dev, "allocating USB transfers failed\n"); 765188412Sthompsa goto detach; 766188412Sthompsa } 767184610Salfred 768188412Sthompsa ue->ue_sc = sc; 769188412Sthompsa ue->ue_dev = dev; 770188412Sthompsa ue->ue_udev = uaa->device; 771188412Sthompsa ue->ue_mtx = &sc->sc_mtx; 772188412Sthompsa ue->ue_methods = &axe_ue_methods; 773184610Salfred 774194228Sthompsa error = uether_ifattach(ue); 775184610Salfred if (error) { 776188412Sthompsa device_printf(dev, "could not attach interface\n"); 777188412Sthompsa goto detach; 778184610Salfred } 779188412Sthompsa return (0); /* success */ 780184610Salfred 781188412Sthompsadetach: 782188412Sthompsa axe_detach(dev); 783188412Sthompsa return (ENXIO); /* failure */ 784184610Salfred} 785184610Salfred 786184610Salfredstatic int 787184610Salfredaxe_detach(device_t dev) 788184610Salfred{ 789184610Salfred struct axe_softc *sc = device_get_softc(dev); 790192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 791184610Salfred 792194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, AXE_N_TRANSFER); 793194228Sthompsa uether_ifdetach(ue); 794184610Salfred mtx_destroy(&sc->sc_mtx); 795184610Salfred 796184610Salfred return (0); 797184610Salfred} 798184610Salfred 799184610Salfredstatic void 800194677Sthompsaaxe_intr_callback(struct usb_xfer *xfer, usb_error_t error) 801184610Salfred{ 802184610Salfred switch (USB_GET_STATE(xfer)) { 803184610Salfred case USB_ST_TRANSFERRED: 804184610Salfred case USB_ST_SETUP: 805188412Sthompsatr_setup: 806194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 807194228Sthompsa usbd_transfer_submit(xfer); 808184610Salfred return; 809184610Salfred 810184610Salfred default: /* Error */ 811194677Sthompsa if (error != USB_ERR_CANCELLED) { 812188412Sthompsa /* try to clear stall first */ 813194677Sthompsa usbd_xfer_set_stall(xfer); 814188412Sthompsa goto tr_setup; 815184610Salfred } 816184610Salfred return; 817184610Salfred } 818184610Salfred} 819184610Salfred 820184610Salfred#if (AXE_BULK_BUF_SIZE >= 0x10000) 821184610Salfred#error "Please update axe_bulk_read_callback()!" 822184610Salfred#endif 823184610Salfred 824184610Salfredstatic void 825194677Sthompsaaxe_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 826184610Salfred{ 827194677Sthompsa struct axe_softc *sc = usbd_xfer_softc(xfer); 828192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 829194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 830184610Salfred struct axe_sframe_hdr hdr; 831194677Sthompsa struct usb_page_cache *pc; 832197566Sthompsa int err, pos, len; 833194677Sthompsa int actlen; 834184610Salfred 835194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 836194677Sthompsa 837184610Salfred switch (USB_GET_STATE(xfer)) { 838184610Salfred case USB_ST_TRANSFERRED: 839184610Salfred pos = 0; 840197566Sthompsa len = 0; 841197566Sthompsa err = 0; 842197566Sthompsa 843194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 844197566Sthompsa if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) { 845197566Sthompsa while (pos < actlen) { 846197566Sthompsa if ((pos + sizeof(hdr)) > actlen) { 847184610Salfred /* too little data */ 848197566Sthompsa err = EINVAL; 849184610Salfred break; 850184610Salfred } 851194677Sthompsa usbd_copy_out(pc, pos, &hdr, sizeof(hdr)); 852184610Salfred 853184610Salfred if ((hdr.len ^ hdr.ilen) != 0xFFFF) { 854184610Salfred /* we lost sync */ 855197566Sthompsa err = EINVAL; 856184610Salfred break; 857184610Salfred } 858184610Salfred pos += sizeof(hdr); 859184610Salfred 860184610Salfred len = le16toh(hdr.len); 861197566Sthompsa if ((pos + len) > actlen) { 862184610Salfred /* invalid length */ 863197566Sthompsa err = EINVAL; 864184610Salfred break; 865184610Salfred } 866197566Sthompsa err = uether_rxbuf(ue, pc, pos, len); 867184610Salfred 868197566Sthompsa pos += len + (len % 2); 869184610Salfred } 870197566Sthompsa } else { 871197566Sthompsa err = uether_rxbuf(ue, pc, 0, actlen); 872184610Salfred } 873184610Salfred 874197566Sthompsa if (err != 0) 875197566Sthompsa ifp->if_ierrors++; 876184610Salfred 877188412Sthompsa /* FALLTHROUGH */ 878184610Salfred case USB_ST_SETUP: 879184610Salfredtr_setup: 880194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 881194228Sthompsa usbd_transfer_submit(xfer); 882194228Sthompsa uether_rxflush(ue); 883184610Salfred return; 884184610Salfred 885184610Salfred default: /* Error */ 886194677Sthompsa DPRINTF("bulk read error, %s\n", usbd_errstr(error)); 887188412Sthompsa 888194677Sthompsa if (error != USB_ERR_CANCELLED) { 889184610Salfred /* try to clear stall first */ 890194677Sthompsa usbd_xfer_set_stall(xfer); 891188412Sthompsa goto tr_setup; 892184610Salfred } 893184610Salfred return; 894184610Salfred 895184610Salfred } 896184610Salfred} 897184610Salfred 898184610Salfred#if ((AXE_BULK_BUF_SIZE >= 0x10000) || (AXE_BULK_BUF_SIZE < (MCLBYTES+4))) 899184610Salfred#error "Please update axe_bulk_write_callback()!" 900184610Salfred#endif 901184610Salfred 902184610Salfredstatic void 903194677Sthompsaaxe_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 904184610Salfred{ 905194677Sthompsa struct axe_softc *sc = usbd_xfer_softc(xfer); 906184610Salfred struct axe_sframe_hdr hdr; 907194228Sthompsa struct ifnet *ifp = uether_getifp(&sc->sc_ue); 908194677Sthompsa struct usb_page_cache *pc; 909184610Salfred struct mbuf *m; 910188412Sthompsa int pos; 911184610Salfred 912184610Salfred switch (USB_GET_STATE(xfer)) { 913184610Salfred case USB_ST_TRANSFERRED: 914184610Salfred DPRINTFN(11, "transfer complete\n"); 915184610Salfred ifp->if_opackets++; 916188412Sthompsa /* FALLTHROUGH */ 917184610Salfred case USB_ST_SETUP: 918188412Sthompsatr_setup: 919186730Salfred if ((sc->sc_flags & AXE_FLAG_LINK) == 0) { 920184610Salfred /* 921184610Salfred * don't send anything if there is no link ! 922184610Salfred */ 923188412Sthompsa return; 924184610Salfred } 925184610Salfred pos = 0; 926194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 927184610Salfred 928184610Salfred while (1) { 929184610Salfred 930184610Salfred IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 931184610Salfred 932184610Salfred if (m == NULL) { 933184610Salfred if (pos > 0) 934184610Salfred break; /* send out data */ 935188412Sthompsa return; 936184610Salfred } 937184610Salfred if (m->m_pkthdr.len > MCLBYTES) { 938184610Salfred m->m_pkthdr.len = MCLBYTES; 939184610Salfred } 940184610Salfred if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) { 941184610Salfred 942184610Salfred hdr.len = htole16(m->m_pkthdr.len); 943184610Salfred hdr.ilen = ~hdr.len; 944184610Salfred 945194677Sthompsa usbd_copy_in(pc, pos, &hdr, sizeof(hdr)); 946184610Salfred 947184610Salfred pos += sizeof(hdr); 948184610Salfred 949184610Salfred /* 950184610Salfred * NOTE: Some drivers force a short packet 951184610Salfred * by appending a dummy header with zero 952184610Salfred * length at then end of the USB transfer. 953184610Salfred * This driver uses the 954184610Salfred * USB_FORCE_SHORT_XFER flag instead. 955184610Salfred */ 956184610Salfred } 957194677Sthompsa usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len); 958184610Salfred pos += m->m_pkthdr.len; 959184610Salfred 960184610Salfred /* 961188412Sthompsa * if there's a BPF listener, bounce a copy 962188412Sthompsa * of this frame to him: 963188412Sthompsa */ 964184610Salfred BPF_MTAP(ifp, m); 965184610Salfred 966184610Salfred m_freem(m); 967184610Salfred 968184610Salfred if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) { 969184610Salfred if (pos > (AXE_BULK_BUF_SIZE - MCLBYTES - sizeof(hdr))) { 970184610Salfred /* send out frame(s) */ 971184610Salfred break; 972184610Salfred } 973184610Salfred } else { 974184610Salfred /* send out frame */ 975184610Salfred break; 976184610Salfred } 977184610Salfred } 978184610Salfred 979194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, pos); 980194228Sthompsa usbd_transfer_submit(xfer); 981184610Salfred return; 982184610Salfred 983184610Salfred default: /* Error */ 984184610Salfred DPRINTFN(11, "transfer error, %s\n", 985194677Sthompsa usbd_errstr(error)); 986184610Salfred 987188412Sthompsa ifp->if_oerrors++; 988188412Sthompsa 989194677Sthompsa if (error != USB_ERR_CANCELLED) { 990184610Salfred /* try to clear stall first */ 991194677Sthompsa usbd_xfer_set_stall(xfer); 992188412Sthompsa goto tr_setup; 993184610Salfred } 994184610Salfred return; 995184610Salfred 996184610Salfred } 997184610Salfred} 998184610Salfred 999184610Salfredstatic void 1000192984Sthompsaaxe_tick(struct usb_ether *ue) 1001184610Salfred{ 1002194228Sthompsa struct axe_softc *sc = uether_getsc(ue); 1003184610Salfred struct mii_data *mii = GET_MII(sc); 1004184610Salfred 1005188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 1006188412Sthompsa 1007184610Salfred mii_tick(mii); 1008188553Sthompsa if ((sc->sc_flags & AXE_FLAG_LINK) == 0) { 1009188553Sthompsa axe_miibus_statchg(ue->ue_dev); 1010188553Sthompsa if ((sc->sc_flags & AXE_FLAG_LINK) != 0) 1011188553Sthompsa axe_start(ue); 1012186730Salfred } 1013184610Salfred} 1014184610Salfred 1015184610Salfredstatic void 1016192984Sthompsaaxe_start(struct usb_ether *ue) 1017184610Salfred{ 1018194228Sthompsa struct axe_softc *sc = uether_getsc(ue); 1019184610Salfred 1020188412Sthompsa /* 1021188412Sthompsa * start the USB transfers, if not already started: 1022188412Sthompsa */ 1023194228Sthompsa usbd_transfer_start(sc->sc_xfer[AXE_INTR_DT_RD]); 1024194228Sthompsa usbd_transfer_start(sc->sc_xfer[AXE_BULK_DT_RD]); 1025194228Sthompsa usbd_transfer_start(sc->sc_xfer[AXE_BULK_DT_WR]); 1026184610Salfred} 1027184610Salfred 1028184610Salfredstatic void 1029192984Sthompsaaxe_init(struct usb_ether *ue) 1030184610Salfred{ 1031194228Sthompsa struct axe_softc *sc = uether_getsc(ue); 1032194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 1033184610Salfred uint16_t rxmode; 1034184610Salfred 1035188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 1036184610Salfred 1037188412Sthompsa /* Cancel pending I/O */ 1038188412Sthompsa axe_stop(ue); 1039184610Salfred 1040197567Sthompsa /* Set MAC address. */ 1041197567Sthompsa if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) 1042197567Sthompsa axe_cmd(sc, AXE_178_CMD_WRITE_NODEID, 0, 0, IF_LLADDR(ifp)); 1043197567Sthompsa else 1044197567Sthompsa axe_cmd(sc, AXE_172_CMD_WRITE_NODEID, 0, 0, IF_LLADDR(ifp)); 1045184610Salfred 1046184610Salfred /* Set transmitter IPG values */ 1047184610Salfred if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) { 1048188412Sthompsa axe_cmd(sc, AXE_178_CMD_WRITE_IPG012, sc->sc_ipgs[2], 1049184610Salfred (sc->sc_ipgs[1] << 8) | (sc->sc_ipgs[0]), NULL); 1050184610Salfred } else { 1051188412Sthompsa axe_cmd(sc, AXE_172_CMD_WRITE_IPG0, 0, sc->sc_ipgs[0], NULL); 1052188412Sthompsa axe_cmd(sc, AXE_172_CMD_WRITE_IPG1, 0, sc->sc_ipgs[1], NULL); 1053188412Sthompsa axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->sc_ipgs[2], NULL); 1054184610Salfred } 1055184610Salfred 1056184610Salfred /* Enable receiver, set RX mode */ 1057184610Salfred rxmode = (AXE_RXCMD_MULTICAST | AXE_RXCMD_ENABLE); 1058184610Salfred if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) { 1059197566Sthompsa#if 0 1060184610Salfred rxmode |= AXE_178_RXCMD_MFB_2048; /* chip default */ 1061197566Sthompsa#else 1062197566Sthompsa /* 1063197566Sthompsa * Default Rx buffer size is too small to get 1064197566Sthompsa * maximum performance. 1065197566Sthompsa */ 1066197566Sthompsa rxmode |= AXE_178_RXCMD_MFB_16384; 1067197566Sthompsa#endif 1068184610Salfred } else { 1069184610Salfred rxmode |= AXE_172_RXCMD_UNICAST; 1070184610Salfred } 1071184610Salfred 1072184610Salfred /* If we want promiscuous mode, set the allframes bit. */ 1073188412Sthompsa if (ifp->if_flags & IFF_PROMISC) 1074184610Salfred rxmode |= AXE_RXCMD_PROMISC; 1075188412Sthompsa 1076188412Sthompsa if (ifp->if_flags & IFF_BROADCAST) 1077184610Salfred rxmode |= AXE_RXCMD_BROADCAST; 1078184610Salfred 1079188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 1080188412Sthompsa 1081184610Salfred /* Load the multicast filter. */ 1082188412Sthompsa axe_setmulti(ue); 1083184610Salfred 1084194677Sthompsa usbd_xfer_set_stall(sc->sc_xfer[AXE_BULK_DT_WR]); 1085184610Salfred 1086188412Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 1087188412Sthompsa axe_start(ue); 1088184610Salfred} 1089184610Salfred 1090184610Salfredstatic void 1091192984Sthompsaaxe_setpromisc(struct usb_ether *ue) 1092184610Salfred{ 1093194228Sthompsa struct axe_softc *sc = uether_getsc(ue); 1094194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 1095184610Salfred uint16_t rxmode; 1096184610Salfred 1097188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, &rxmode); 1098184610Salfred 1099184610Salfred rxmode = le16toh(rxmode); 1100184610Salfred 1101188412Sthompsa if (ifp->if_flags & IFF_PROMISC) { 1102184610Salfred rxmode |= AXE_RXCMD_PROMISC; 1103184610Salfred } else { 1104184610Salfred rxmode &= ~AXE_RXCMD_PROMISC; 1105184610Salfred } 1106184610Salfred 1107188412Sthompsa axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); 1108184610Salfred 1109188412Sthompsa axe_setmulti(ue); 1110184610Salfred} 1111184610Salfred 1112184610Salfredstatic void 1113192984Sthompsaaxe_stop(struct usb_ether *ue) 1114184610Salfred{ 1115194228Sthompsa struct axe_softc *sc = uether_getsc(ue); 1116194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 1117184610Salfred 1118188412Sthompsa AXE_LOCK_ASSERT(sc, MA_OWNED); 1119184610Salfred 1120188412Sthompsa ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1121186730Salfred sc->sc_flags &= ~AXE_FLAG_LINK; 1122184610Salfred 1123184610Salfred /* 1124184610Salfred * stop all the transfers, if not already stopped: 1125184610Salfred */ 1126194228Sthompsa usbd_transfer_stop(sc->sc_xfer[AXE_BULK_DT_WR]); 1127194228Sthompsa usbd_transfer_stop(sc->sc_xfer[AXE_BULK_DT_RD]); 1128194228Sthompsa usbd_transfer_stop(sc->sc_xfer[AXE_INTR_DT_RD]); 1129184610Salfred 1130188412Sthompsa axe_reset(sc); 1131184610Salfred} 1132