LCOV - code coverage report
Current view: top level - dev/usb - if_axe.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 706 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 30 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_axe.c,v 1.138 2017/01/22 10:17:39 dlg Exp $        */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2005, 2006, 2007 Jonathan Gray <jsg@openbsd.org>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : /*
      20             :  * Copyright (c) 1997, 1998, 1999, 2000-2003
      21             :  *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
      22             :  *
      23             :  * Redistribution and use in source and binary forms, with or without
      24             :  * modification, are permitted provided that the following conditions
      25             :  * are met:
      26             :  * 1. Redistributions of source code must retain the above copyright
      27             :  *    notice, this list of conditions and the following disclaimer.
      28             :  * 2. Redistributions in binary form must reproduce the above copyright
      29             :  *    notice, this list of conditions and the following disclaimer in the
      30             :  *    documentation and/or other materials provided with the distribution.
      31             :  * 3. All advertising materials mentioning features or use of this software
      32             :  *    must display the following acknowledgement:
      33             :  *      This product includes software developed by Bill Paul.
      34             :  * 4. Neither the name of the author nor the names of any co-contributors
      35             :  *    may be used to endorse or promote products derived from this software
      36             :  *    without specific prior written permission.
      37             :  *
      38             :  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
      39             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      40             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      41             :  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
      42             :  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      43             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      44             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      45             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      46             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      47             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
      48             :  * THE POSSIBILITY OF SUCH DAMAGE.
      49             :  */
      50             : 
      51             : /*
      52             :  * ASIX Electronics AX88172 USB 2.0 ethernet driver. Used in the
      53             :  * LinkSys USB200M and various other adapters.
      54             :  *
      55             :  * Manuals available from:
      56             :  * http://www.asix.com.tw/datasheet/mac/Ax88172.PDF
      57             :  * Note: you need the manual for the AX88170 chip (USB 1.x ethernet
      58             :  * controller) to find the definitions for the RX control register.
      59             :  * http://www.asix.com.tw/datasheet/mac/Ax88170.PDF
      60             :  *
      61             :  * Written by Bill Paul <wpaul@windriver.com>
      62             :  * Senior Engineer
      63             :  * Wind River Systems
      64             :  */
      65             : 
      66             : /*
      67             :  * The AX88172 provides USB ethernet supports at 10 and 100Mbps.
      68             :  * It uses an external PHY (reference designs use a Realtek chip),
      69             :  * and has a 64-bit multicast hash filter. There is some information
      70             :  * missing from the manual which one needs to know in order to make
      71             :  * the chip function:
      72             :  *
      73             :  * - You must set bit 7 in the RX control register, otherwise the
      74             :  *   chip won't receive any packets.
      75             :  * - You must initialize all 3 IPG registers, or you won't be able
      76             :  *   to send any packets.
      77             :  *
      78             :  * Note that this device appears to only support loading the station
      79             :  * address via autoload from the EEPROM (i.e. there's no way to manually
      80             :  * set it).
      81             :  *
      82             :  * (Adam Weinberger wanted me to name this driver if_gir.c.)
      83             :  */
      84             : 
      85             : /*
      86             :  * Ported to OpenBSD 3/28/2004 by Greg Taleck <taleck@oz.net>
      87             :  * with bits and pieces from the aue and url drivers.
      88             :  */
      89             : 
      90             : #include "bpfilter.h"
      91             : 
      92             : #include <sys/param.h>
      93             : #include <sys/systm.h>
      94             : #include <sys/sockio.h>
      95             : #include <sys/rwlock.h>
      96             : #include <sys/mbuf.h>
      97             : #include <sys/kernel.h>
      98             : #include <sys/socket.h>
      99             : 
     100             : #include <sys/device.h>
     101             : 
     102             : #include <machine/bus.h>
     103             : 
     104             : #include <net/if.h>
     105             : #include <net/if_media.h>
     106             : 
     107             : #if NBPFILTER > 0
     108             : #include <net/bpf.h>
     109             : #endif
     110             : 
     111             : #include <netinet/in.h>
     112             : #include <netinet/if_ether.h>
     113             : 
     114             : #include <dev/mii/mii.h>
     115             : #include <dev/mii/miivar.h>
     116             : 
     117             : #include <dev/usb/usb.h>
     118             : #include <dev/usb/usbdi.h>
     119             : #include <dev/usb/usbdi_util.h>
     120             : #include <dev/usb/usbdivar.h>
     121             : #include <dev/usb/usbdevs.h>
     122             : 
     123             : #include <dev/usb/if_axereg.h>
     124             : 
     125             : #ifdef AXE_DEBUG
     126             : #define DPRINTF(x)      do { if (axedebug) printf x; } while (0)
     127             : #define DPRINTFN(n,x)   do { if (axedebug >= (n)) printf x; } while (0)
     128             : int     axedebug = 0;
     129             : #else
     130             : #define DPRINTF(x)
     131             : #define DPRINTFN(n,x)
     132             : #endif
     133             : 
     134             : /*
     135             :  * Various supported device vendors/products.
     136             :  */
     137             : const struct axe_type axe_devs[] = {
     138             :         { { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UF200}, 0 },
     139             :         { { USB_VENDOR_ACERCM, USB_PRODUCT_ACERCM_EP1427X2}, 0 },
     140             :         { { USB_VENDOR_APPLE, USB_PRODUCT_APPLE_ETHERNET }, AX772 },
     141             :         { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88172}, 0 },
     142             :         { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772}, AX772 },
     143             :         { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772A}, AX772 },
     144             :         { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B}, AX772 | AX772B },
     145             :         { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B_1}, AX772 | AX772B },
     146             :         { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178}, AX178 },
     147             :         { { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC210T}, 0 },
     148             :         { { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D5055 }, AX178 },
     149             :         { { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB2AR}, 0},
     150             :         { { USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_USB200MV2}, AX772 },
     151             :         { { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB2_TX }, 0},
     152             :         { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100}, 0 },
     153             :         { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100B1 }, AX772 },
     154             :         { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100C1 }, AX772 | AX772B },
     155             :         { { USB_VENDOR_GOODWAY, USB_PRODUCT_GOODWAY_GWUSB2E}, 0 },
     156             :         { { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETGUS2 }, AX178 },
     157             :         { { USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_PRX1}, 0 },
     158             :         { { USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_ETHERNET }, AX772 | AX772B },
     159             :         { { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_HG20F9}, AX772 | AX772B },
     160             :         { { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_USB200M}, 0 },
     161             :         { { USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_USB1000 }, AX178 },
     162             :         { { USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LAN_GTJU2}, AX178 },
     163             :         { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2GT}, AX178 },
     164             :         { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2KTX}, 0 },
     165             :         { { USB_VENDOR_MSI, USB_PRODUCT_MSI_AX88772A}, AX772 },
     166             :         { { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA120}, 0 },
     167             :         { { USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01PLUS }, AX772 },
     168             :         { { USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GU1000T }, AX178 },
     169             :         { { USB_VENDOR_SYSTEMTALKS, USB_PRODUCT_SYSTEMTALKS_SGCX2UL}, 0 },
     170             :         { { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_LN029}, 0 },
     171             :         { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN028 }, AX178 }
     172             : };
     173             : 
     174             : #define axe_lookup(v, p) ((struct axe_type *)usb_lookup(axe_devs, v, p))
     175             : 
     176             : int axe_match(struct device *, void *, void *);
     177             : void axe_attach(struct device *, struct device *, void *);
     178             : int axe_detach(struct device *, int);
     179             : 
     180             : struct cfdriver axe_cd = {
     181             :         NULL, "axe", DV_IFNET
     182             : };
     183             : 
     184             : const struct cfattach axe_ca = {
     185             :         sizeof(struct axe_softc), axe_match, axe_attach, axe_detach
     186             : };
     187             : 
     188             : int axe_tx_list_init(struct axe_softc *);
     189             : int axe_rx_list_init(struct axe_softc *);
     190             : struct mbuf *axe_newbuf(void);
     191             : int axe_encap(struct axe_softc *, struct mbuf *, int);
     192             : void axe_rxeof(struct usbd_xfer *, void *, usbd_status);
     193             : void axe_txeof(struct usbd_xfer *, void *, usbd_status);
     194             : void axe_tick(void *);
     195             : void axe_tick_task(void *);
     196             : void axe_start(struct ifnet *);
     197             : int axe_ioctl(struct ifnet *, u_long, caddr_t);
     198             : void axe_init(void *);
     199             : void axe_stop(struct axe_softc *);
     200             : void axe_watchdog(struct ifnet *);
     201             : int axe_miibus_readreg(struct device *, int, int);
     202             : void axe_miibus_writereg(struct device *, int, int, int);
     203             : void axe_miibus_statchg(struct device *);
     204             : int axe_cmd(struct axe_softc *, int, int, int, void *);
     205             : int axe_ifmedia_upd(struct ifnet *);
     206             : void axe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
     207             : void axe_reset(struct axe_softc *sc);
     208             : 
     209             : void axe_iff(struct axe_softc *);
     210             : void axe_lock_mii(struct axe_softc *sc);
     211             : void axe_unlock_mii(struct axe_softc *sc);
     212             : 
     213             : void axe_ax88178_init(struct axe_softc *);
     214             : void axe_ax88772_init(struct axe_softc *);
     215             : 
     216             : /* Get exclusive access to the MII registers */
     217             : void
     218           0 : axe_lock_mii(struct axe_softc *sc)
     219             : {
     220           0 :         sc->axe_refcnt++;
     221           0 :         rw_enter_write(&sc->axe_mii_lock);
     222           0 : }
     223             : 
     224             : void
     225           0 : axe_unlock_mii(struct axe_softc *sc)
     226             : {
     227           0 :         rw_exit_write(&sc->axe_mii_lock);
     228           0 :         if (--sc->axe_refcnt < 0)
     229           0 :                 usb_detach_wakeup(&sc->axe_dev);
     230           0 : }
     231             : 
     232             : int
     233           0 : axe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf)
     234             : {
     235           0 :         usb_device_request_t    req;
     236             :         usbd_status             err;
     237             : 
     238           0 :         if (usbd_is_dying(sc->axe_udev))
     239           0 :                 return(0);
     240             : 
     241           0 :         if (AXE_CMD_DIR(cmd))
     242           0 :                 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     243             :         else
     244           0 :                 req.bmRequestType = UT_READ_VENDOR_DEVICE;
     245           0 :         req.bRequest = AXE_CMD_CMD(cmd);
     246           0 :         USETW(req.wValue, val);
     247           0 :         USETW(req.wIndex, index);
     248           0 :         USETW(req.wLength, AXE_CMD_LEN(cmd));
     249             : 
     250           0 :         err = usbd_do_request(sc->axe_udev, &req, buf);
     251             : 
     252           0 :         if (err) {
     253             :                 DPRINTF(("axe_cmd err: cmd: %d\n", cmd));
     254           0 :                 return(-1);
     255             :         }
     256             : 
     257           0 :         return(0);
     258           0 : }
     259             : 
     260             : int
     261           0 : axe_miibus_readreg(struct device *dev, int phy, int reg)
     262             : {
     263           0 :         struct axe_softc        *sc = (void *)dev;
     264             :         usbd_status             err;
     265           0 :         uWord                   val;
     266             :         int                     ival;
     267             : 
     268           0 :         if (usbd_is_dying(sc->axe_udev)) {
     269             :                 DPRINTF(("axe: dying\n"));
     270           0 :                 return(0);
     271             :         }
     272             : 
     273             : #ifdef notdef
     274             :         /*
     275             :          * The chip tells us the MII address of any supported
     276             :          * PHYs attached to the chip, so only read from those.
     277             :          */
     278             : 
     279             :         DPRINTF(("axe_miibus_readreg: phy 0x%x reg 0x%x\n", phy, reg));
     280             : 
     281             :         if (sc->axe_phyaddrs[0] != AXE_NOPHY && phy != sc->axe_phyaddrs[0])
     282             :                 return (0);
     283             : 
     284             :         if (sc->axe_phyaddrs[1] != AXE_NOPHY && phy != sc->axe_phyaddrs[1])
     285             :                 return (0);
     286             : #endif
     287           0 :         if (sc->axe_phyno != phy)
     288           0 :                 return (0);
     289             : 
     290           0 :         USETW(val, 0);
     291             : 
     292           0 :         axe_lock_mii(sc);
     293           0 :         axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
     294           0 :         err = axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, val);
     295           0 :         axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
     296           0 :         axe_unlock_mii(sc);
     297             : 
     298           0 :         if (err) {
     299           0 :                 printf("axe%d: read PHY failed\n", sc->axe_unit);
     300           0 :                 return(-1);
     301             :         }
     302             :         DPRINTF(("axe_miibus_readreg: phy 0x%x reg 0x%x val 0x%x\n",
     303             :             phy, reg, UGETW(val)));
     304             : 
     305           0 :         ival = UGETW(val);
     306           0 :         if ((sc->axe_flags & AX772) != 0 && reg == MII_BMSR) {
     307             :                 /*
     308             :                 * BMSR of AX88772 indicates that it supports extended
     309             :                 * capability but the extended status register is
     310             :                 * revered for embedded ethernet PHY. So clear the
     311             :                 * extended capability bit of BMSR.
     312             :                 */
     313           0 :                 ival &= ~BMSR_EXTCAP;
     314           0 :         }
     315             : 
     316           0 :         return (ival);
     317           0 : }
     318             : 
     319             : void
     320           0 : axe_miibus_writereg(struct device *dev, int phy, int reg, int val)
     321             : {
     322           0 :         struct axe_softc        *sc = (void *)dev;
     323             :         usbd_status             err;
     324           0 :         uWord                   uval;
     325             : 
     326           0 :         if (usbd_is_dying(sc->axe_udev))
     327           0 :                 return;
     328           0 :         if (sc->axe_phyno != phy)
     329           0 :                 return;
     330             : 
     331           0 :         USETW(uval, val);
     332             : 
     333           0 :         axe_lock_mii(sc);
     334           0 :         axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
     335           0 :         err = axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, uval);
     336           0 :         axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
     337           0 :         axe_unlock_mii(sc);
     338             : 
     339           0 :         if (err) {
     340           0 :                 printf("axe%d: write PHY failed\n", sc->axe_unit);
     341           0 :                 return;
     342             :         }
     343           0 : }
     344             : 
     345             : void
     346           0 : axe_miibus_statchg(struct device *dev)
     347             : {
     348           0 :         struct axe_softc        *sc = (void *)dev;
     349           0 :         struct mii_data         *mii = GET_MII(sc);
     350             :         struct ifnet            *ifp;
     351             :         int                     val, err;
     352             : 
     353           0 :         ifp = GET_IFP(sc);
     354           0 :         if (mii == NULL || ifp == NULL ||
     355           0 :             (ifp->if_flags & IFF_RUNNING) == 0)
     356           0 :                 return;
     357             : 
     358           0 :         sc->axe_link = 0;
     359           0 :         if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
     360             :             (IFM_ACTIVE | IFM_AVALID)) {
     361           0 :                 switch (IFM_SUBTYPE(mii->mii_media_active)) {
     362             :                     case IFM_10_T:
     363             :                     case IFM_100_TX:
     364           0 :                         sc->axe_link++;
     365           0 :                         break;
     366             :                     case IFM_1000_T:
     367           0 :                         if ((sc->axe_flags & AX178) == 0)
     368             :                             break;
     369           0 :                         sc->axe_link++;
     370           0 :                         break;
     371             :                     default:
     372             :                         break;
     373             :                 }
     374             :         }
     375             : 
     376             :         /* Lost link, do nothing. */
     377           0 :         if (sc->axe_link == 0)
     378           0 :                 return;
     379             : 
     380             :         val = 0;
     381           0 :         if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
     382           0 :                 val |= AXE_MEDIA_FULL_DUPLEX;
     383             : 
     384           0 :         if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
     385           0 :                 val |= (AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC);
     386           0 :                 if (sc->axe_flags & AX178)
     387           0 :                         val |= AXE_178_MEDIA_ENCK;
     388             : 
     389           0 :                 switch (IFM_SUBTYPE(mii->mii_media_active)) {
     390             :                 case IFM_1000_T:
     391           0 :                         val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK;
     392           0 :                         break;
     393             :                 case IFM_100_TX:
     394           0 :                         val |= AXE_178_MEDIA_100TX;
     395           0 :                         break;
     396             :                 case IFM_10_T:
     397             :                         /* doesn't need to be handled */
     398             :                         break;
     399             :                 }
     400             :         }
     401             : 
     402             :         DPRINTF(("axe_miibus_statchg: val=0x%x\n", val));
     403           0 :         err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL);
     404           0 :         if (err) {
     405           0 :                 printf("%s: media change failed\n", sc->axe_dev.dv_xname);
     406           0 :                 return;
     407             :         }
     408           0 : }
     409             : 
     410             : /*
     411             :  * Set media options.
     412             :  */
     413             : int
     414           0 : axe_ifmedia_upd(struct ifnet *ifp)
     415             : {
     416           0 :         struct axe_softc        *sc = ifp->if_softc;
     417           0 :         struct mii_data         *mii = GET_MII(sc);
     418             : 
     419           0 :         if (mii->mii_instance) {
     420             :                 struct mii_softc        *miisc;
     421           0 :                 LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
     422           0 :                         mii_phy_reset(miisc);
     423           0 :         }
     424           0 :         mii_mediachg(mii);
     425             : 
     426           0 :         return (0);
     427             : }
     428             : 
     429             : /*
     430             :  * Report current media status.
     431             :  */
     432             : void
     433           0 : axe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
     434             : {
     435           0 :         struct axe_softc        *sc = ifp->if_softc;
     436           0 :         struct mii_data         *mii = GET_MII(sc);
     437             : 
     438           0 :         mii_pollstat(mii);
     439           0 :         ifmr->ifm_active = mii->mii_media_active;
     440           0 :         ifmr->ifm_status = mii->mii_media_status;
     441           0 : }
     442             : 
     443             : void
     444           0 : axe_iff(struct axe_softc *sc)
     445             : {
     446           0 :         struct ifnet            *ifp = GET_IFP(sc);
     447             :         struct arpcom           *ac = &sc->arpcom;
     448             :         struct ether_multi *enm;
     449             :         struct ether_multistep step;
     450             :         u_int32_t               h = 0;
     451           0 :         uWord                   urxmode;
     452             :         u_int16_t               rxmode;
     453           0 :         u_int8_t                hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
     454             : 
     455           0 :         if (usbd_is_dying(sc->axe_udev))
     456           0 :                 return;
     457             : 
     458           0 :         axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, urxmode);
     459           0 :         rxmode = UGETW(urxmode);
     460           0 :         rxmode &= ~(AXE_RXCMD_ALLMULTI | AXE_RXCMD_MULTICAST |
     461             :             AXE_RXCMD_PROMISC);
     462           0 :         ifp->if_flags &= ~IFF_ALLMULTI;
     463             : 
     464             :         /*
     465             :          * Always accept broadcast frames.
     466             :          * Always accept frames destined to our station address.
     467             :          */
     468           0 :         rxmode |= AXE_RXCMD_BROADCAST;
     469           0 :         if ((sc->axe_flags & (AX178 | AX772)) == 0)
     470           0 :                 rxmode |= AXE_172_RXCMD_UNICAST;
     471             : 
     472           0 :         if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
     473           0 :                 ifp->if_flags |= IFF_ALLMULTI;
     474           0 :                 rxmode |= AXE_RXCMD_ALLMULTI;
     475           0 :                 if (ifp->if_flags & IFF_PROMISC)
     476           0 :                         rxmode |= AXE_RXCMD_PROMISC;
     477             :         } else {
     478           0 :                 rxmode |= AXE_RXCMD_MULTICAST;
     479             : 
     480             :                 /* now program new ones */
     481           0 :                 ETHER_FIRST_MULTI(step, ac, enm);
     482           0 :                 while (enm != NULL) {
     483           0 :                         h = ether_crc32_be(enm->enm_addrlo,
     484           0 :                             ETHER_ADDR_LEN) >> 26;
     485             : 
     486           0 :                         hashtbl[h / 8] |= 1 << (h % 8);
     487             : 
     488           0 :                         ETHER_NEXT_MULTI(step, enm);
     489             :                 }
     490             :         }
     491             : 
     492           0 :         axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, (void *)&hashtbl);
     493           0 :         axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
     494           0 : }
     495             : 
     496             : void
     497           0 : axe_reset(struct axe_softc *sc)
     498             : {
     499           0 :         if (usbd_is_dying(sc->axe_udev))
     500             :                 return;
     501             :         /* XXX What to reset? */
     502             : 
     503             :         /* Wait a little while for the chip to get its brains in order. */
     504           0 :         DELAY(1000);
     505           0 :         return;
     506           0 : }
     507             : 
     508             : #define AXE_GPIO_WRITE(x,y) do {                                \
     509             :         axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, (x), NULL);          \
     510             :         usbd_delay_ms(sc->axe_udev, (y));                    \
     511             : } while (0)
     512             : 
     513             : void
     514           0 : axe_ax88178_init(struct axe_softc *sc)
     515             : {
     516             :         int gpio0 = 0, phymode = 0, ledmode;
     517           0 :         u_int16_t eeprom, val;
     518             : 
     519           0 :         axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL);
     520             :         /* XXX magic */
     521           0 :         axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom);
     522           0 :         axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL);
     523             : 
     524           0 :         eeprom = letoh16(eeprom);
     525             : 
     526             :         DPRINTF((" EEPROM is 0x%x\n", eeprom));
     527             : 
     528             :         /* if EEPROM is invalid we have to use to GPIO0 */
     529           0 :         if (eeprom == 0xffff) {
     530             :                 phymode = AXE_PHY_MODE_MARVELL;
     531             :                 gpio0 = 1;
     532             :                 ledmode = 0;
     533           0 :         } else {
     534           0 :                 phymode = eeprom & 0x7f;
     535           0 :                 gpio0 = (eeprom & 0x80) ? 0 : 1;
     536           0 :                 ledmode = eeprom >> 8;
     537             :         }
     538             : 
     539             :         DPRINTF(("use gpio0: %d, phymode 0x%02x, eeprom 0x%04x\n",
     540             :             gpio0, phymode, eeprom));
     541             : 
     542             :         /* power up external phy */
     543           0 :         AXE_GPIO_WRITE(AXE_GPIO1|AXE_GPIO1_EN | AXE_GPIO_RELOAD_EEPROM, 40);
     544           0 :         if (ledmode == 1) {
     545           0 :                 AXE_GPIO_WRITE(AXE_GPIO1_EN, 30);
     546           0 :                 AXE_GPIO_WRITE(AXE_GPIO1_EN | AXE_GPIO1, 30);
     547           0 :         } else {
     548           0 :                 val = gpio0 == 1 ? AXE_GPIO0 | AXE_GPIO0_EN : 
     549             :                     AXE_GPIO1 | AXE_GPIO1_EN;
     550           0 :                 AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, 30);
     551           0 :                 AXE_GPIO_WRITE(val | AXE_GPIO2_EN, 300);
     552           0 :                 AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, 30);
     553             :         }
     554             : 
     555             :         /* initialize phy */
     556           0 :         if (phymode == AXE_PHY_MODE_REALTEK_8211CL) {
     557           0 :                 axe_miibus_writereg(&sc->axe_dev, sc->axe_phyno, 0x1f, 0x0005);
     558           0 :                 axe_miibus_writereg(&sc->axe_dev, sc->axe_phyno, 0x0c, 0x0000);
     559           0 :                 val = axe_miibus_readreg(&sc->axe_dev, sc->axe_phyno, 0x0001);
     560           0 :                 axe_miibus_writereg(&sc->axe_dev, sc->axe_phyno, 0x01,
     561           0 :                     val | 0x0080);
     562           0 :                 axe_miibus_writereg(&sc->axe_dev, sc->axe_phyno, 0x1f, 0x0000);
     563           0 :         }
     564             : 
     565             :         /* soft reset */
     566           0 :         axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL);
     567           0 :         usbd_delay_ms(sc->axe_udev, 150);
     568           0 :         axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
     569             :             AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL);
     570           0 :         usbd_delay_ms(sc->axe_udev, 150);
     571             :         /* Enable MII/GMII/RGMII for external PHY */
     572           0 :         axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL);
     573           0 :         usbd_delay_ms(sc->axe_udev, 10);
     574           0 :         axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
     575           0 : }
     576             : 
     577             : /* Read Ethernet Address from EEPROM if it is zero */
     578             : void
     579           0 : axe_ax88772b_nodeid(struct axe_softc *sc, u_char *eaddr)
     580             : {
     581             :         int i;
     582           0 :         uint16_t val;
     583             : 
     584           0 :         for (i = 0; i < ETHER_ADDR_LEN; i++) {
     585           0 :                 if (eaddr[i] != 0)
     586             :                         break;
     587             :         }
     588             : 
     589             :         /* We already have an ethernet address */
     590           0 :         if (i != ETHER_ADDR_LEN)
     591           0 :                 return;
     592             : 
     593             :         /* read from EEPROM */
     594           0 :         for (i = 0; i < ETHER_ADDR_LEN/2; i++) {
     595           0 :                 axe_cmd(sc, AXE_CMD_SROM_READ, 0, AXE_EEPROM_772B_NODEID + i, &val);
     596           0 :                 val = ntohs(val);
     597           0 :                 *eaddr++ = (u_char)((val >> 8) & 0xff);
     598           0 :                 *eaddr++ = (u_char)(val & 0xff);
     599             :         }
     600           0 : }
     601             : 
     602             : void
     603           0 : axe_ax88772_init(struct axe_softc *sc)
     604             : {
     605           0 :         axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL);
     606           0 :         usbd_delay_ms(sc->axe_udev, 40);
     607             : 
     608           0 :         if (sc->axe_phyno == AXE_PHY_NO_AX772_EPHY) {
     609             :                 /* ask for the embedded PHY */
     610           0 :                 axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x01, NULL);
     611           0 :                 usbd_delay_ms(sc->axe_udev, 10);
     612             : 
     613             :                 /* power down and reset state, pin reset state */
     614           0 :                 axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL);
     615           0 :                 usbd_delay_ms(sc->axe_udev, 60);
     616             : 
     617             :                 /* power down/reset state, pin operating state */
     618           0 :                 axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
     619             :                     AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL);
     620           0 :                 usbd_delay_ms(sc->axe_udev, 150);
     621             : 
     622             :                 /* power up, reset */
     623           0 :                 axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL);
     624             : 
     625             :                 /* power up, operating */
     626           0 :                 axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
     627             :                     AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL);
     628           0 :         } else {
     629             :                 /* ask for external PHY */
     630           0 :                 axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x00, NULL);
     631           0 :                 usbd_delay_ms(sc->axe_udev, 10);
     632             : 
     633             :                 /* power down internal PHY */
     634           0 :                 axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
     635             :                     AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL);
     636             :         }
     637             : 
     638           0 :         usbd_delay_ms(sc->axe_udev, 150);
     639           0 :         axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
     640           0 : }
     641             : 
     642             : static int
     643           0 : axe_get_phyno(struct axe_softc *sc, int sel)
     644             : {
     645             :         int phyno = -1;
     646             : 
     647           0 :         switch (AXE_PHY_TYPE(sc->axe_phyaddrs[sel])) {
     648             :         case PHY_TYPE_100_HOME:
     649             :         case PHY_TYPE_GIG:
     650           0 :                 phyno  = AXE_PHY_NO(sc->axe_phyaddrs[sel]);
     651           0 :                 break;
     652             :         case PHY_TYPE_SPECIAL:
     653             :                 /* FALLTHROUGH */
     654             :         case PHY_TYPE_RSVD:
     655             :                 /* FALLTHROUGH */
     656             :         case PHY_TYPE_NON_SUP:
     657             :                 /* FALLTHROUGH */
     658             :         default:
     659             :                 break;
     660             :         }
     661             : 
     662           0 :         return (phyno);
     663             : }
     664             : 
     665             : /*
     666             :  * Probe for a AX88172 chip.
     667             :  */
     668             : int
     669           0 : axe_match(struct device *parent, void *match, void *aux)
     670             : {
     671           0 :         struct usb_attach_arg *uaa = aux;
     672             : 
     673           0 :         if (uaa->iface == NULL || uaa->configno != 1)
     674           0 :                 return (UMATCH_NONE);
     675             : 
     676           0 :         return (axe_lookup(uaa->vendor, uaa->product) != NULL ?
     677             :                 UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE);
     678           0 : }
     679             : 
     680             : /*
     681             :  * Attach the interface. Allocate softc structures, do ifmedia
     682             :  * setup and ethernet/BPF attach.
     683             :  */
     684             : void
     685           0 : axe_attach(struct device *parent, struct device *self, void *aux)
     686             : {
     687           0 :         struct axe_softc *sc = (struct axe_softc *)self;
     688           0 :         struct usb_attach_arg *uaa = aux;
     689             :         usb_interface_descriptor_t *id;
     690             :         usb_endpoint_descriptor_t *ed;
     691             :         struct mii_data *mii;
     692           0 :         u_char eaddr[ETHER_ADDR_LEN];
     693           0 :         char *devname = sc->axe_dev.dv_xname;
     694             :         struct ifnet *ifp;
     695             :         int i, s;
     696             : 
     697           0 :         sc->axe_unit = self->dv_unit; /*device_get_unit(self);*/
     698           0 :         sc->axe_udev = uaa->device;
     699           0 :         sc->axe_iface = uaa->iface;
     700           0 :         sc->axe_flags = axe_lookup(uaa->vendor, uaa->product)->axe_flags;
     701             : 
     702           0 :         usb_init_task(&sc->axe_tick_task, axe_tick_task, sc,
     703             :             USB_TASK_TYPE_GENERIC);
     704           0 :         rw_init(&sc->axe_mii_lock, "axemii");
     705           0 :         usb_init_task(&sc->axe_stop_task, (void (*)(void *))axe_stop, sc,
     706             :             USB_TASK_TYPE_GENERIC);
     707             : 
     708           0 :         sc->axe_product = uaa->product;
     709           0 :         sc->axe_vendor = uaa->vendor;
     710             : 
     711           0 :         id = usbd_get_interface_descriptor(sc->axe_iface);
     712             : 
     713             :         /* decide on what our bufsize will be */
     714           0 :         if (sc->axe_flags & (AX178 | AX772))
     715           0 :                 sc->axe_bufsz = (sc->axe_udev->speed == USB_SPEED_HIGH) ?
     716             :                     AXE_178_MAX_BUFSZ : AXE_178_MIN_BUFSZ;
     717             :         else
     718           0 :                 sc->axe_bufsz = AXE_172_BUFSZ;
     719             : 
     720             :         /* Find endpoints. */
     721           0 :         for (i = 0; i < id->bNumEndpoints; i++) {
     722           0 :                 ed = usbd_interface2endpoint_descriptor(sc->axe_iface, i);
     723           0 :                 if (!ed) {
     724           0 :                         printf("%s: couldn't get ep %d\n",
     725             :                             sc->axe_dev.dv_xname, i);
     726           0 :                         return;
     727             :                 }
     728           0 :                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     729           0 :                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     730           0 :                         sc->axe_ed[AXE_ENDPT_RX] = ed->bEndpointAddress;
     731           0 :                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
     732           0 :                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     733           0 :                         sc->axe_ed[AXE_ENDPT_TX] = ed->bEndpointAddress;
     734           0 :                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     735           0 :                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
     736           0 :                         sc->axe_ed[AXE_ENDPT_INTR] = ed->bEndpointAddress;
     737           0 :                 }
     738             :         }
     739             : 
     740           0 :         s = splnet();
     741             : 
     742             :         /* We need the PHYID for init dance in some cases */
     743           0 :         axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, (void *)&sc->axe_phyaddrs);
     744             : 
     745             :         DPRINTF((" phyaddrs[0]: %x phyaddrs[1]: %x\n",
     746             :             sc->axe_phyaddrs[0], sc->axe_phyaddrs[1]));
     747             : 
     748           0 :         sc->axe_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI);
     749           0 :         if (sc->axe_phyno == -1)
     750           0 :                 sc->axe_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC);
     751           0 :         if (sc->axe_phyno == -1) {
     752           0 :                 printf("%s:", sc->axe_dev.dv_xname);
     753           0 :                 printf(" no valid PHY address found, assuming PHY address 0\n");
     754           0 :                 sc->axe_phyno = 0;
     755           0 :         }
     756             : 
     757             :         DPRINTF((" get_phyno %d\n", sc->axe_phyno));
     758             : 
     759           0 :         if (sc->axe_flags & AX178)
     760           0 :                 axe_ax88178_init(sc);
     761           0 :         else if (sc->axe_flags & AX772)
     762           0 :                 axe_ax88772_init(sc);
     763             : 
     764             :         /*
     765             :          * Get station address.
     766             :          */
     767           0 :         if (sc->axe_flags & (AX178 | AX772))
     768           0 :                 axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, &eaddr);
     769             :         else
     770           0 :                 axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, &eaddr);
     771             : 
     772           0 :         if (sc->axe_flags & AX772B)
     773           0 :                 axe_ax88772b_nodeid(sc, eaddr);
     774             : 
     775             :         /*
     776             :          * Load IPG values
     777             :          */
     778           0 :         axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, (void *)&sc->axe_ipgs);
     779             : 
     780             :         /*
     781             :          * An ASIX chip was detected. Inform the world.
     782             :          */
     783           0 :         printf("%s:", sc->axe_dev.dv_xname);
     784           0 :         if (sc->axe_flags & AX178)
     785           0 :                 printf(" AX88178");
     786           0 :         else if (sc->axe_flags & AX772B)
     787           0 :                 printf(" AX88772B");
     788           0 :         else if (sc->axe_flags & AX772)
     789           0 :                 printf(" AX88772");
     790             :         else
     791           0 :                 printf(" AX88172");
     792           0 :         printf(", address %s\n", ether_sprintf(eaddr));
     793             : 
     794           0 :         bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
     795             : 
     796             :         /* Initialize interface info.*/
     797           0 :         ifp = &sc->arpcom.ac_if;
     798           0 :         ifp->if_softc = sc;
     799           0 :         strlcpy(ifp->if_xname, devname, IFNAMSIZ);
     800           0 :         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     801           0 :         ifp->if_ioctl = axe_ioctl;
     802           0 :         ifp->if_start = axe_start;
     803           0 :         ifp->if_watchdog = axe_watchdog;
     804             : 
     805           0 :         ifp->if_capabilities = IFCAP_VLAN_MTU;
     806             : 
     807             :         /* Initialize MII/media info. */
     808           0 :         mii = &sc->axe_mii;
     809           0 :         mii->mii_ifp = ifp;
     810           0 :         mii->mii_readreg = axe_miibus_readreg;
     811           0 :         mii->mii_writereg = axe_miibus_writereg;
     812           0 :         mii->mii_statchg = axe_miibus_statchg;
     813           0 :         mii->mii_flags = MIIF_AUTOTSLEEP;
     814             : 
     815           0 :         ifmedia_init(&mii->mii_media, 0, axe_ifmedia_upd, axe_ifmedia_sts);
     816           0 :         mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
     817             : 
     818           0 :         if (LIST_FIRST(&mii->mii_phys) == NULL) {
     819           0 :                 ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
     820           0 :                 ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
     821           0 :         } else
     822           0 :                 ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
     823             : 
     824             :         /* Attach the interface. */
     825           0 :         if_attach(ifp);
     826           0 :         ether_ifattach(ifp);
     827             : 
     828           0 :         timeout_set(&sc->axe_stat_ch, axe_tick, sc);
     829             : 
     830           0 :         splx(s);
     831           0 : }
     832             : 
     833             : int
     834           0 : axe_detach(struct device *self, int flags)
     835             : {
     836           0 :         struct axe_softc        *sc = (struct axe_softc *)self;
     837             :         int                     s;
     838           0 :         struct ifnet            *ifp = GET_IFP(sc);
     839             : 
     840             :         DPRINTFN(2,("%s: %s: enter\n", sc->axe_dev.dv_xname, __func__));
     841             : 
     842           0 :         if (timeout_initialized(&sc->axe_stat_ch))
     843           0 :                 timeout_del(&sc->axe_stat_ch);
     844             : 
     845           0 :         if (sc->axe_ep[AXE_ENDPT_TX] != NULL)
     846           0 :                 usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_TX]);
     847           0 :         if (sc->axe_ep[AXE_ENDPT_RX] != NULL)
     848           0 :                 usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_RX]);
     849           0 :         if (sc->axe_ep[AXE_ENDPT_INTR] != NULL)
     850           0 :                 usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_INTR]);
     851             : 
     852             :         /*
     853             :          * Remove any pending tasks.  They cannot be executing because they run
     854             :          * in the same thread as detach.
     855             :          */
     856           0 :         usb_rem_task(sc->axe_udev, &sc->axe_tick_task);
     857           0 :         usb_rem_task(sc->axe_udev, &sc->axe_stop_task);
     858             : 
     859           0 :         s = splusb();
     860             : 
     861           0 :         if (--sc->axe_refcnt >= 0) {
     862             :                 /* Wait for processes to go away */
     863           0 :                 usb_detach_wait(&sc->axe_dev);
     864           0 :         }
     865             : 
     866           0 :         if (ifp->if_flags & IFF_RUNNING)
     867           0 :                 axe_stop(sc);
     868             : 
     869           0 :         mii_detach(&sc->axe_mii, MII_PHY_ANY, MII_OFFSET_ANY);
     870           0 :         ifmedia_delete_instance(&sc->axe_mii.mii_media, IFM_INST_ANY);
     871           0 :         if (ifp->if_softc != NULL) {
     872           0 :                 ether_ifdetach(ifp);
     873           0 :                 if_detach(ifp);
     874           0 :         }
     875             : 
     876             : #ifdef DIAGNOSTIC
     877           0 :         if (sc->axe_ep[AXE_ENDPT_TX] != NULL ||
     878           0 :             sc->axe_ep[AXE_ENDPT_RX] != NULL ||
     879           0 :             sc->axe_ep[AXE_ENDPT_INTR] != NULL)
     880           0 :                 printf("%s: detach has active endpoints\n",
     881           0 :                     sc->axe_dev.dv_xname);
     882             : #endif
     883             : 
     884           0 :         if (--sc->axe_refcnt >= 0) {
     885             :                 /* Wait for processes to go away. */
     886           0 :                 usb_detach_wait(&sc->axe_dev);
     887           0 :         }
     888           0 :         splx(s);
     889             : 
     890           0 :         return (0);
     891             : }
     892             : 
     893             : struct mbuf *
     894           0 : axe_newbuf(void)
     895             : {
     896             :         struct mbuf             *m;
     897             : 
     898           0 :         MGETHDR(m, M_DONTWAIT, MT_DATA);
     899           0 :         if (m == NULL)
     900           0 :                 return (NULL);
     901             : 
     902           0 :         MCLGET(m, M_DONTWAIT);
     903           0 :         if (!(m->m_flags & M_EXT)) {
     904           0 :                 m_freem(m);
     905           0 :                 return (NULL);
     906             :         }
     907             : 
     908           0 :         m->m_len = m->m_pkthdr.len = MCLBYTES;
     909           0 :         m_adj(m, ETHER_ALIGN);
     910             : 
     911           0 :         return (m);
     912           0 : }
     913             : 
     914             : int
     915           0 : axe_rx_list_init(struct axe_softc *sc)
     916             : {
     917             :         struct axe_cdata *cd;
     918             :         struct axe_chain *c;
     919             :         int i;
     920             : 
     921             :         DPRINTF(("%s: %s: enter\n", sc->axe_dev.dv_xname, __func__));
     922             : 
     923           0 :         cd = &sc->axe_cdata;
     924           0 :         for (i = 0; i < AXE_RX_LIST_CNT; i++) {
     925           0 :                 c = &cd->axe_rx_chain[i];
     926           0 :                 c->axe_sc = sc;
     927           0 :                 c->axe_idx = i;
     928           0 :                 c->axe_mbuf = NULL;
     929           0 :                 if (c->axe_xfer == NULL) {
     930           0 :                         c->axe_xfer = usbd_alloc_xfer(sc->axe_udev);
     931           0 :                         if (c->axe_xfer == NULL)
     932           0 :                                 return (ENOBUFS);
     933           0 :                         c->axe_buf = usbd_alloc_buffer(c->axe_xfer,
     934           0 :                             sc->axe_bufsz);
     935           0 :                         if (c->axe_buf == NULL) {
     936           0 :                                 usbd_free_xfer(c->axe_xfer);
     937           0 :                                 return (ENOBUFS);
     938             :                         }
     939             :                 }
     940             :         }
     941             : 
     942           0 :         return (0);
     943           0 : }
     944             : 
     945             : int
     946           0 : axe_tx_list_init(struct axe_softc *sc)
     947             : {
     948             :         struct axe_cdata *cd;
     949             :         struct axe_chain *c;
     950             :         int i;
     951             : 
     952             :         DPRINTF(("%s: %s: enter\n", sc->axe_dev.dv_xname, __func__));
     953             : 
     954           0 :         cd = &sc->axe_cdata;
     955           0 :         for (i = 0; i < AXE_TX_LIST_CNT; i++) {
     956           0 :                 c = &cd->axe_tx_chain[i];
     957           0 :                 c->axe_sc = sc;
     958           0 :                 c->axe_idx = i;
     959           0 :                 c->axe_mbuf = NULL;
     960           0 :                 if (c->axe_xfer == NULL) {
     961           0 :                         c->axe_xfer = usbd_alloc_xfer(sc->axe_udev);
     962           0 :                         if (c->axe_xfer == NULL)
     963           0 :                                 return (ENOBUFS);
     964           0 :                         c->axe_buf = usbd_alloc_buffer(c->axe_xfer,
     965           0 :                             sc->axe_bufsz);
     966           0 :                         if (c->axe_buf == NULL) {
     967           0 :                                 usbd_free_xfer(c->axe_xfer);
     968           0 :                                 return (ENOBUFS);
     969             :                         }
     970             :                 }
     971             :         }
     972             : 
     973           0 :         return (0);
     974           0 : }
     975             : 
     976             : /*
     977             :  * A frame has been uploaded: pass the resulting mbuf chain up to
     978             :  * the higher level protocols.
     979             :  */
     980             : void
     981           0 : axe_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
     982             : {
     983           0 :         struct axe_chain        *c = (struct axe_chain *)priv;
     984           0 :         struct axe_softc        *sc = c->axe_sc;
     985           0 :         struct ifnet            *ifp = GET_IFP(sc);
     986           0 :         struct mbuf_list        ml = MBUF_LIST_INITIALIZER();
     987           0 :         u_char                  *buf = c->axe_buf;
     988           0 :         u_int32_t               total_len;
     989             :         u_int16_t               pktlen = 0;
     990             :         struct mbuf             *m;
     991             :         struct axe_sframe_hdr   hdr;
     992             :         int                     s;
     993             : 
     994             :         DPRINTFN(10,("%s: %s: enter\n", sc->axe_dev.dv_xname,__func__));
     995             : 
     996           0 :         if (usbd_is_dying(sc->axe_udev))
     997           0 :                 return;
     998             : 
     999           0 :         if (!(ifp->if_flags & IFF_RUNNING))
    1000           0 :                 return;
    1001             : 
    1002           0 :         if (status != USBD_NORMAL_COMPLETION) {
    1003           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
    1004           0 :                         return;
    1005           0 :                 if (usbd_ratecheck(&sc->axe_rx_notice)) {
    1006           0 :                         printf("%s: usb errors on rx: %s\n",
    1007           0 :                             sc->axe_dev.dv_xname, usbd_errstr(status));
    1008           0 :                 }
    1009           0 :                 if (status == USBD_STALLED)
    1010           0 :                         usbd_clear_endpoint_stall_async(sc->axe_ep[AXE_ENDPT_RX]);
    1011             :                 goto done;
    1012             :         }
    1013             : 
    1014           0 :         usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
    1015             : 
    1016           0 :         do {
    1017           0 :                 if (sc->axe_flags & (AX178 | AX772)) {
    1018           0 :                         if (total_len < sizeof(hdr)) {
    1019           0 :                                 ifp->if_ierrors++;
    1020           0 :                                 goto done;
    1021             :                         }
    1022             : 
    1023           0 :                         buf += pktlen;
    1024             : 
    1025           0 :                         memcpy(&hdr, buf, sizeof(hdr));
    1026           0 :                         total_len -= sizeof(hdr);
    1027             : 
    1028           0 :                         if (((letoh16(hdr.len) & AXE_RH1M_RXLEN_MASK) ^
    1029           0 :                             (letoh16(hdr.ilen) & AXE_RH1M_RXLEN_MASK)) !=
    1030             :                             AXE_RH1M_RXLEN_MASK) {
    1031           0 :                                 ifp->if_ierrors++;
    1032           0 :                                 goto done;
    1033             :                         }
    1034           0 :                         pktlen = letoh16(hdr.len) & AXE_RH1M_RXLEN_MASK;
    1035           0 :                         if (pktlen > total_len) {
    1036           0 :                                 ifp->if_ierrors++;
    1037           0 :                                 goto done;
    1038             :                         }
    1039             : 
    1040           0 :                         buf += sizeof(hdr);
    1041             : 
    1042           0 :                         if ((pktlen % 2) != 0)
    1043           0 :                                 pktlen++;
    1044             : 
    1045           0 :                         if (total_len < pktlen)
    1046           0 :                                 total_len = 0;
    1047             :                         else
    1048           0 :                                 total_len -= pktlen;
    1049             :                 } else {
    1050           0 :                         pktlen = total_len; /* crc on the end? */
    1051           0 :                         total_len = 0;
    1052             :                 }
    1053             : 
    1054           0 :                 m = axe_newbuf();
    1055           0 :                 if (m == NULL) {
    1056           0 :                         ifp->if_ierrors++;
    1057           0 :                         goto done;
    1058             :                 }
    1059             : 
    1060           0 :                 m->m_pkthdr.len = m->m_len = pktlen;
    1061             : 
    1062           0 :                 memcpy(mtod(m, char *), buf, pktlen);
    1063             : 
    1064           0 :                 ml_enqueue(&ml, m);
    1065             : 
    1066           0 :         } while (total_len > 0);
    1067             : 
    1068             : done:
    1069             :         /* push the packet up */
    1070           0 :         s = splnet();
    1071           0 :         if_input(ifp, &ml);
    1072           0 :         splx(s);
    1073             : 
    1074           0 :         memset(c->axe_buf, 0, sc->axe_bufsz);
    1075             : 
    1076             :         /* Setup new transfer. */
    1077           0 :         usbd_setup_xfer(xfer, sc->axe_ep[AXE_ENDPT_RX],
    1078           0 :             c, c->axe_buf, sc->axe_bufsz,
    1079             :             USBD_SHORT_XFER_OK | USBD_NO_COPY,
    1080             :             USBD_NO_TIMEOUT, axe_rxeof);
    1081           0 :         usbd_transfer(xfer);
    1082             : 
    1083             :         DPRINTFN(10,("%s: %s: start rx\n", sc->axe_dev.dv_xname, __func__));
    1084             : 
    1085           0 :         return;
    1086           0 : }
    1087             : 
    1088             : /*
    1089             :  * A frame was downloaded to the chip. It's safe for us to clean up
    1090             :  * the list buffers.
    1091             :  */
    1092             : 
    1093             : void
    1094           0 : axe_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
    1095             : {
    1096             :         struct axe_softc        *sc;
    1097             :         struct axe_chain        *c;
    1098             :         struct ifnet            *ifp;
    1099             :         int                     s;
    1100             : 
    1101           0 :         c = priv;
    1102           0 :         sc = c->axe_sc;
    1103           0 :         ifp = &sc->arpcom.ac_if;
    1104             : 
    1105           0 :         if (usbd_is_dying(sc->axe_udev))
    1106           0 :                 return;
    1107             : 
    1108           0 :         s = splnet();
    1109             : 
    1110           0 :         if (status != USBD_NORMAL_COMPLETION) {
    1111           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
    1112           0 :                         splx(s);
    1113           0 :                         return;
    1114             :                 }
    1115           0 :                 ifp->if_oerrors++;
    1116           0 :                 printf("axe%d: usb error on tx: %s\n", sc->axe_unit,
    1117           0 :                     usbd_errstr(status));
    1118           0 :                 if (status == USBD_STALLED)
    1119           0 :                         usbd_clear_endpoint_stall_async(sc->axe_ep[AXE_ENDPT_TX]);
    1120           0 :                 splx(s);
    1121           0 :                 return;
    1122             :         }
    1123             : 
    1124           0 :         ifp->if_timer = 0;
    1125           0 :         ifq_clr_oactive(&ifp->if_snd);
    1126             : 
    1127           0 :         m_freem(c->axe_mbuf);
    1128           0 :         c->axe_mbuf = NULL;
    1129             : 
    1130           0 :         if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
    1131           0 :                 axe_start(ifp);
    1132             : 
    1133           0 :         splx(s);
    1134           0 :         return;
    1135           0 : }
    1136             : 
    1137             : void
    1138           0 : axe_tick(void *xsc)
    1139             : {
    1140           0 :         struct axe_softc *sc = xsc;
    1141             : 
    1142           0 :         if (sc == NULL)
    1143           0 :                 return;
    1144             : 
    1145             :         DPRINTFN(0xff, ("%s: %s: enter\n", sc->axe_dev.dv_xname,
    1146             :                         __func__));
    1147             : 
    1148           0 :         if (usbd_is_dying(sc->axe_udev))
    1149           0 :                 return;
    1150             : 
    1151             :         /* Perform periodic stuff in process context */
    1152           0 :         usb_add_task(sc->axe_udev, &sc->axe_tick_task);
    1153             : 
    1154           0 : }
    1155             : 
    1156             : void
    1157           0 : axe_tick_task(void *xsc)
    1158             : {
    1159             :         int                     s;
    1160             :         struct axe_softc        *sc;
    1161             :         struct ifnet            *ifp;
    1162             :         struct mii_data         *mii;
    1163             : 
    1164           0 :         sc = xsc;
    1165             : 
    1166           0 :         if (sc == NULL)
    1167           0 :                 return;
    1168             : 
    1169           0 :         if (usbd_is_dying(sc->axe_udev))
    1170           0 :                 return;
    1171             : 
    1172           0 :         ifp = GET_IFP(sc);
    1173           0 :         mii = GET_MII(sc);
    1174           0 :         if (mii == NULL)
    1175           0 :                 return;
    1176             : 
    1177           0 :         s = splnet();
    1178             : 
    1179           0 :         mii_tick(mii);
    1180           0 :         if (sc->axe_link == 0)
    1181           0 :                 axe_miibus_statchg(&sc->axe_dev);
    1182           0 :         timeout_add_sec(&sc->axe_stat_ch, 1);
    1183             : 
    1184           0 :         splx(s);
    1185           0 : }
    1186             : 
    1187             : int
    1188           0 : axe_encap(struct axe_softc *sc, struct mbuf *m, int idx)
    1189             : {
    1190             :         struct axe_chain        *c;
    1191             :         usbd_status             err;
    1192             :         struct axe_sframe_hdr   hdr;
    1193             :         int                     length, boundary;
    1194             : 
    1195           0 :         c = &sc->axe_cdata.axe_tx_chain[idx];
    1196             : 
    1197           0 :         if (sc->axe_flags & (AX178 | AX772)) {
    1198           0 :                 boundary = (sc->axe_udev->speed == USB_SPEED_HIGH) ? 512 : 64;
    1199             : 
    1200           0 :                 hdr.len = htole16(m->m_pkthdr.len);
    1201           0 :                 hdr.ilen = ~hdr.len;
    1202             : 
    1203           0 :                 memcpy(c->axe_buf, &hdr, sizeof(hdr));
    1204             :                 length = sizeof(hdr);
    1205             : 
    1206           0 :                 m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf + length);
    1207           0 :                 length += m->m_pkthdr.len;
    1208             : 
    1209           0 :                 if ((length % boundary) == 0) {
    1210             :                         hdr.len = 0x0000;
    1211             :                         hdr.ilen = 0xffff;
    1212           0 :                         memcpy(c->axe_buf + length, &hdr, sizeof(hdr));
    1213           0 :                         length += sizeof(hdr);
    1214           0 :                 }
    1215             : 
    1216             :         } else {
    1217           0 :                 m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf);
    1218           0 :                 length = m->m_pkthdr.len;
    1219             :         }
    1220             : 
    1221           0 :         c->axe_mbuf = m;
    1222             : 
    1223           0 :         usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_TX],
    1224           0 :             c, c->axe_buf, length, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
    1225             :             10000, axe_txeof);
    1226             : 
    1227             :         /* Transmit */
    1228           0 :         err = usbd_transfer(c->axe_xfer);
    1229           0 :         if (err != USBD_IN_PROGRESS) {
    1230           0 :                 axe_stop(sc);
    1231           0 :                 return(EIO);
    1232             :         }
    1233             : 
    1234           0 :         sc->axe_cdata.axe_tx_cnt++;
    1235             : 
    1236           0 :         return(0);
    1237           0 : }
    1238             : 
    1239             : void
    1240           0 : axe_start(struct ifnet *ifp)
    1241             : {
    1242             :         struct axe_softc        *sc;
    1243             :         struct mbuf             *m_head = NULL;
    1244             : 
    1245           0 :         sc = ifp->if_softc;
    1246             : 
    1247           0 :         if (!sc->axe_link)
    1248           0 :                 return;
    1249             : 
    1250           0 :         if (ifq_is_oactive(&ifp->if_snd))
    1251           0 :                 return;
    1252             : 
    1253           0 :         m_head = ifq_deq_begin(&ifp->if_snd);
    1254           0 :         if (m_head == NULL)
    1255           0 :                 return;
    1256             : 
    1257           0 :         if (axe_encap(sc, m_head, 0)) {
    1258           0 :                 ifq_deq_rollback(&ifp->if_snd, m_head);
    1259           0 :                 ifq_set_oactive(&ifp->if_snd);
    1260           0 :                 return;
    1261             :         }
    1262           0 :         ifq_deq_commit(&ifp->if_snd, m_head);
    1263             : 
    1264             :         /*
    1265             :          * If there's a BPF listener, bounce a copy of this frame
    1266             :          * to him.
    1267             :          */
    1268             : #if NBPFILTER > 0
    1269           0 :         if (ifp->if_bpf)
    1270           0 :                 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
    1271             : #endif
    1272             : 
    1273           0 :         ifq_set_oactive(&ifp->if_snd);
    1274             : 
    1275             :         /*
    1276             :          * Set a timeout in case the chip goes out to lunch.
    1277             :          */
    1278           0 :         ifp->if_timer = 5;
    1279             : 
    1280           0 :         return;
    1281           0 : }
    1282             : 
    1283             : void
    1284           0 : axe_init(void *xsc)
    1285             : {
    1286           0 :         struct axe_softc        *sc = xsc;
    1287           0 :         struct ifnet            *ifp = &sc->arpcom.ac_if;
    1288             :         struct axe_chain        *c;
    1289             :         usbd_status             err;
    1290           0 :         uWord                   urxmode;
    1291             :         int                     rxmode;
    1292             :         int                     i, s;
    1293             : 
    1294           0 :         s = splnet();
    1295             : 
    1296             :         /*
    1297             :          * Cancel pending I/O and free all RX/TX buffers.
    1298             :          */
    1299           0 :         axe_reset(sc);
    1300             : 
    1301             :         /* set MAC address */
    1302           0 :         if (sc->axe_flags & (AX178 | AX772))
    1303           0 :                 axe_cmd(sc, AXE_178_CMD_WRITE_NODEID, 0, 0,
    1304           0 :                     &sc->arpcom.ac_enaddr);
    1305             : 
    1306             :         /* Enable RX logic. */
    1307             : 
    1308             :         /* Init RX ring. */
    1309           0 :         if (axe_rx_list_init(sc) == ENOBUFS) {
    1310           0 :                 printf("axe%d: rx list init failed\n", sc->axe_unit);
    1311           0 :                 splx(s);
    1312           0 :                 return;
    1313             :         }
    1314             : 
    1315             :         /* Init TX ring. */
    1316           0 :         if (axe_tx_list_init(sc) == ENOBUFS) {
    1317           0 :                 printf("axe%d: tx list init failed\n", sc->axe_unit);
    1318           0 :                 splx(s);
    1319           0 :                 return;
    1320             :         }
    1321             : 
    1322             :         /* Set transmitter IPG values */
    1323           0 :         if (sc->axe_flags & (AX178 | AX772))
    1324           0 :                 axe_cmd(sc, AXE_178_CMD_WRITE_IPG012, sc->axe_ipgs[2],
    1325           0 :                     (sc->axe_ipgs[1] << 8) | (sc->axe_ipgs[0]), NULL);
    1326             :         else {
    1327           0 :                 axe_cmd(sc, AXE_172_CMD_WRITE_IPG0, 0, sc->axe_ipgs[0], NULL);
    1328           0 :                 axe_cmd(sc, AXE_172_CMD_WRITE_IPG1, 0, sc->axe_ipgs[1], NULL);
    1329           0 :                 axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->axe_ipgs[2], NULL);
    1330             :         }
    1331             : 
    1332             :         /* Program promiscuous mode and multicast filters. */
    1333           0 :         axe_iff(sc);
    1334             : 
    1335             :         /* Enable receiver, set RX mode */
    1336           0 :         axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, urxmode);
    1337           0 :         rxmode = UGETW(urxmode);
    1338           0 :         rxmode |= AXE_RXCMD_ENABLE;
    1339           0 :         if (sc->axe_flags & AX772B)
    1340           0 :                 rxmode |= AXE_772B_RXCMD_RH1M;
    1341           0 :         else if (sc->axe_flags & (AX178 | AX772)) {
    1342           0 :                 if (sc->axe_udev->speed == USB_SPEED_HIGH) {
    1343             :                         /* largest possible USB buffer size for AX88178 */
    1344           0 :                         rxmode |= AXE_178_RXCMD_MFB;
    1345           0 :                 }
    1346             :         }
    1347           0 :         axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
    1348             : 
    1349             :         /* Open RX and TX pipes. */
    1350           0 :         err = usbd_open_pipe(sc->axe_iface, sc->axe_ed[AXE_ENDPT_RX],
    1351           0 :             USBD_EXCLUSIVE_USE, &sc->axe_ep[AXE_ENDPT_RX]);
    1352           0 :         if (err) {
    1353           0 :                 printf("axe%d: open rx pipe failed: %s\n",
    1354           0 :                     sc->axe_unit, usbd_errstr(err));
    1355           0 :                 splx(s);
    1356           0 :                 return;
    1357             :         }
    1358             : 
    1359           0 :         err = usbd_open_pipe(sc->axe_iface, sc->axe_ed[AXE_ENDPT_TX],
    1360           0 :             USBD_EXCLUSIVE_USE, &sc->axe_ep[AXE_ENDPT_TX]);
    1361           0 :         if (err) {
    1362           0 :                 printf("axe%d: open tx pipe failed: %s\n",
    1363           0 :                     sc->axe_unit, usbd_errstr(err));
    1364           0 :                 splx(s);
    1365           0 :                 return;
    1366             :         }
    1367             : 
    1368             :         /* Start up the receive pipe. */
    1369           0 :         for (i = 0; i < AXE_RX_LIST_CNT; i++) {
    1370           0 :                 c = &sc->axe_cdata.axe_rx_chain[i];
    1371           0 :                 usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_RX],
    1372           0 :                     c, c->axe_buf, sc->axe_bufsz,
    1373             :                     USBD_SHORT_XFER_OK | USBD_NO_COPY,
    1374             :                     USBD_NO_TIMEOUT, axe_rxeof);
    1375           0 :                 usbd_transfer(c->axe_xfer);
    1376             :         }
    1377             : 
    1378           0 :         sc->axe_link = 0;
    1379           0 :         ifp->if_flags |= IFF_RUNNING;
    1380           0 :         ifq_clr_oactive(&ifp->if_snd);
    1381             : 
    1382           0 :         splx(s);
    1383             : 
    1384           0 :         timeout_add_sec(&sc->axe_stat_ch, 1);
    1385           0 :         return;
    1386           0 : }
    1387             : 
    1388             : int
    1389           0 : axe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
    1390             : {
    1391           0 :         struct axe_softc        *sc = ifp->if_softc;
    1392           0 :         struct ifreq            *ifr = (struct ifreq *)data;
    1393             :         int                     s, error = 0;
    1394             : 
    1395           0 :         s = splnet();
    1396             : 
    1397           0 :         switch(cmd) {
    1398             :         case SIOCSIFADDR:
    1399           0 :                 ifp->if_flags |= IFF_UP;
    1400           0 :                 if (!(ifp->if_flags & IFF_RUNNING))
    1401           0 :                         axe_init(sc);
    1402             :                 break;
    1403             : 
    1404             :         case SIOCSIFFLAGS:
    1405           0 :                 if (ifp->if_flags & IFF_UP) {
    1406           0 :                         if (ifp->if_flags & IFF_RUNNING)
    1407           0 :                                 error = ENETRESET;
    1408             :                         else
    1409           0 :                                 axe_init(sc);
    1410             :                 } else {
    1411           0 :                         if (ifp->if_flags & IFF_RUNNING)
    1412           0 :                                 axe_stop(sc);
    1413             :                 }
    1414             :                 break;
    1415             : 
    1416             :         case SIOCGIFMEDIA:
    1417             :         case SIOCSIFMEDIA:
    1418           0 :                 error = ifmedia_ioctl(ifp, ifr, &sc->axe_mii.mii_media, cmd);
    1419           0 :                 break;
    1420             : 
    1421             :         default:
    1422           0 :                 error = ether_ioctl(ifp, &sc->arpcom, cmd, data);
    1423           0 :         }
    1424             : 
    1425           0 :         if (error == ENETRESET) {
    1426           0 :                 if (ifp->if_flags & IFF_RUNNING)
    1427           0 :                         axe_iff(sc);
    1428             :                 error = 0;
    1429           0 :         }
    1430             : 
    1431           0 :         splx(s);
    1432           0 :         return(error);
    1433             : }
    1434             : 
    1435             : void
    1436           0 : axe_watchdog(struct ifnet *ifp)
    1437             : {
    1438             :         struct axe_softc        *sc;
    1439             :         struct axe_chain        *c;
    1440           0 :         usbd_status             stat;
    1441             :         int                     s;
    1442             : 
    1443           0 :         sc = ifp->if_softc;
    1444             : 
    1445           0 :         ifp->if_oerrors++;
    1446           0 :         printf("axe%d: watchdog timeout\n", sc->axe_unit);
    1447             : 
    1448           0 :         s = splusb();
    1449           0 :         c = &sc->axe_cdata.axe_tx_chain[0];
    1450           0 :         usbd_get_xfer_status(c->axe_xfer, NULL, NULL, NULL, &stat);
    1451           0 :         axe_txeof(c->axe_xfer, c, stat);
    1452             : 
    1453           0 :         if (!IFQ_IS_EMPTY(&ifp->if_snd))
    1454           0 :                 axe_start(ifp);
    1455           0 :         splx(s);
    1456           0 : }
    1457             : 
    1458             : /*
    1459             :  * Stop the adapter and free any mbufs allocated to the
    1460             :  * RX and TX lists.
    1461             :  */
    1462             : void
    1463           0 : axe_stop(struct axe_softc *sc)
    1464             : {
    1465             :         usbd_status             err;
    1466             :         struct ifnet            *ifp;
    1467             :         int                     i;
    1468             : 
    1469           0 :         axe_reset(sc);
    1470             : 
    1471           0 :         ifp = &sc->arpcom.ac_if;
    1472           0 :         ifp->if_timer = 0;
    1473           0 :         ifp->if_flags &= ~IFF_RUNNING;
    1474           0 :         ifq_clr_oactive(&ifp->if_snd);
    1475             : 
    1476           0 :         timeout_del(&sc->axe_stat_ch);
    1477             : 
    1478             :         /* Stop transfers. */
    1479           0 :         if (sc->axe_ep[AXE_ENDPT_RX] != NULL) {
    1480           0 :                 usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_RX]);
    1481           0 :                 err = usbd_close_pipe(sc->axe_ep[AXE_ENDPT_RX]);
    1482           0 :                 if (err) {
    1483           0 :                         printf("axe%d: close rx pipe failed: %s\n",
    1484           0 :                             sc->axe_unit, usbd_errstr(err));
    1485           0 :                 }
    1486           0 :                 sc->axe_ep[AXE_ENDPT_RX] = NULL;
    1487           0 :         }
    1488             : 
    1489           0 :         if (sc->axe_ep[AXE_ENDPT_TX] != NULL) {
    1490           0 :                 usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_TX]);
    1491           0 :                 err = usbd_close_pipe(sc->axe_ep[AXE_ENDPT_TX]);
    1492           0 :                 if (err) {
    1493           0 :                         printf("axe%d: close tx pipe failed: %s\n",
    1494           0 :                             sc->axe_unit, usbd_errstr(err));
    1495           0 :                 }
    1496           0 :                 sc->axe_ep[AXE_ENDPT_TX] = NULL;
    1497           0 :         }
    1498             : 
    1499           0 :         if (sc->axe_ep[AXE_ENDPT_INTR] != NULL) {
    1500           0 :                 usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_INTR]);
    1501           0 :                 err = usbd_close_pipe(sc->axe_ep[AXE_ENDPT_INTR]);
    1502           0 :                 if (err) {
    1503           0 :                         printf("axe%d: close intr pipe failed: %s\n",
    1504           0 :                             sc->axe_unit, usbd_errstr(err));
    1505           0 :                 }
    1506           0 :                 sc->axe_ep[AXE_ENDPT_INTR] = NULL;
    1507           0 :         }
    1508             : 
    1509             :         /* Free RX resources. */
    1510           0 :         for (i = 0; i < AXE_RX_LIST_CNT; i++) {
    1511           0 :                 if (sc->axe_cdata.axe_rx_chain[i].axe_mbuf != NULL) {
    1512           0 :                         m_freem(sc->axe_cdata.axe_rx_chain[i].axe_mbuf);
    1513           0 :                         sc->axe_cdata.axe_rx_chain[i].axe_mbuf = NULL;
    1514           0 :                 }
    1515           0 :                 if (sc->axe_cdata.axe_rx_chain[i].axe_xfer != NULL) {
    1516           0 :                         usbd_free_xfer(sc->axe_cdata.axe_rx_chain[i].axe_xfer);
    1517           0 :                         sc->axe_cdata.axe_rx_chain[i].axe_xfer = NULL;
    1518           0 :                 }
    1519             :         }
    1520             : 
    1521             :         /* Free TX resources. */
    1522           0 :         for (i = 0; i < AXE_TX_LIST_CNT; i++) {
    1523           0 :                 if (sc->axe_cdata.axe_tx_chain[i].axe_mbuf != NULL) {
    1524           0 :                         m_freem(sc->axe_cdata.axe_tx_chain[i].axe_mbuf);
    1525           0 :                         sc->axe_cdata.axe_tx_chain[i].axe_mbuf = NULL;
    1526           0 :                 }
    1527           0 :                 if (sc->axe_cdata.axe_tx_chain[i].axe_xfer != NULL) {
    1528           0 :                         usbd_free_xfer(sc->axe_cdata.axe_tx_chain[i].axe_xfer);
    1529           0 :                         sc->axe_cdata.axe_tx_chain[i].axe_xfer = NULL;
    1530           0 :                 }
    1531             :         }
    1532             : 
    1533           0 :         sc->axe_link = 0;
    1534           0 : }
    1535             : 

Generated by: LCOV version 1.13