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

          Line data    Source code
       1             : /*      $OpenBSD: if_axen.c,v 1.25 2018/06/12 06:59:27 mlarkin Exp $    */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2013 Yojiro UO <yuo@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             :  * ASIX Electronics AX88178a USB 2.0 ethernet and AX88179 USB 3.0 Ethernet
      21             :  * driver.
      22             :  */
      23             : 
      24             : #include "bpfilter.h"
      25             : 
      26             : #include <sys/param.h>
      27             : #include <sys/systm.h>
      28             : #include <sys/sockio.h>
      29             : #include <sys/rwlock.h>
      30             : #include <sys/mbuf.h>
      31             : #include <sys/kernel.h>
      32             : #include <sys/socket.h>
      33             : 
      34             : #include <sys/device.h>
      35             : 
      36             : #include <machine/bus.h>
      37             : 
      38             : #include <net/if.h>
      39             : #include <net/if_media.h>
      40             : 
      41             : #if NBPFILTER > 0
      42             : #include <net/bpf.h>
      43             : #endif
      44             : 
      45             : #include <netinet/in.h>
      46             : #include <netinet/if_ether.h>
      47             : 
      48             : #include <dev/mii/mii.h>
      49             : #include <dev/mii/miivar.h>
      50             : 
      51             : #include <dev/usb/usb.h>
      52             : #include <dev/usb/usbdi.h>
      53             : #include <dev/usb/usbdi_util.h>
      54             : #include <dev/usb/usbdivar.h>
      55             : #include <dev/usb/usbdevs.h>
      56             : 
      57             : #include <dev/usb/if_axenreg.h>
      58             : 
      59             : #ifdef AXEN_DEBUG
      60             : #define DPRINTF(x)      do { if (axendebug) printf x; } while (0)
      61             : #define DPRINTFN(n,x)   do { if (axendebug >= (n)) printf x; } while (0)
      62             : int     axendebug = 0;
      63             : #else
      64             : #define DPRINTF(x)
      65             : #define DPRINTFN(n,x)
      66             : #endif
      67             : 
      68             : #define AXEN_TOE        /* enable checksum offload function */
      69             : 
      70             : /*
      71             :  * Various supported device vendors/products.
      72             :  */
      73             : const struct axen_type axen_devs[] = {
      74             : #if 0 /* not tested */
      75             :         { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178A}, AX178A },
      76             : #endif
      77             :         { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88179}, AX179 },
      78             :         { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUB1312}, AX179 },
      79             :         { { USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_AX88179}, AX179 },
      80             :         { { USB_VENDOR_SAMSUNG2, USB_PRODUCT_SAMSUNG2_AX88179}, AX179 },
      81             :         { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN032}, AX179 }
      82             : };
      83             : 
      84             : #define axen_lookup(v, p) ((struct axen_type *)usb_lookup(axen_devs, v, p))
      85             : 
      86             : int     axen_match(struct device *, void *, void *);
      87             : void    axen_attach(struct device *, struct device *, void *);
      88             : int     axen_detach(struct device *, int);
      89             : 
      90             : struct cfdriver axen_cd = {
      91             :         NULL, "axen", DV_IFNET
      92             : };
      93             : 
      94             : const struct cfattach axen_ca = {
      95             :         sizeof(struct axen_softc), axen_match, axen_attach, axen_detach
      96             : };
      97             : 
      98             : int     axen_tx_list_init(struct axen_softc *);
      99             : int     axen_rx_list_init(struct axen_softc *);
     100             : struct mbuf *axen_newbuf(void);
     101             : int     axen_encap(struct axen_softc *, struct mbuf *, int);
     102             : void    axen_rxeof(struct usbd_xfer *, void *, usbd_status);
     103             : void    axen_txeof(struct usbd_xfer *, void *, usbd_status);
     104             : void    axen_tick(void *);
     105             : void    axen_tick_task(void *);
     106             : void    axen_start(struct ifnet *);
     107             : int     axen_ioctl(struct ifnet *, u_long, caddr_t);
     108             : void    axen_init(void *);
     109             : void    axen_stop(struct axen_softc *);
     110             : void    axen_watchdog(struct ifnet *);
     111             : int     axen_miibus_readreg(struct device *, int, int);
     112             : void    axen_miibus_writereg(struct device *, int, int, int);
     113             : void    axen_miibus_statchg(struct device *);
     114             : int     axen_cmd(struct axen_softc *, int, int, int, void *);
     115             : int     axen_ifmedia_upd(struct ifnet *);
     116             : void    axen_ifmedia_sts(struct ifnet *, struct ifmediareq *);
     117             : void    axen_reset(struct axen_softc *sc);
     118             : void    axen_iff(struct axen_softc *);
     119             : void    axen_lock_mii(struct axen_softc *sc);
     120             : void    axen_unlock_mii(struct axen_softc *sc);
     121             : 
     122             : void    axen_ax88179_init(struct axen_softc *);
     123             : 
     124             : /* Get exclusive access to the MII registers */
     125             : void
     126           0 : axen_lock_mii(struct axen_softc *sc)
     127             : {
     128           0 :         sc->axen_refcnt++;
     129           0 :         rw_enter_write(&sc->axen_mii_lock);
     130           0 : }
     131             : 
     132             : void
     133           0 : axen_unlock_mii(struct axen_softc *sc)
     134             : {
     135           0 :         rw_exit_write(&sc->axen_mii_lock);
     136           0 :         if (--sc->axen_refcnt < 0)
     137           0 :                 usb_detach_wakeup(&sc->axen_dev);
     138           0 : }
     139             : 
     140             : int
     141           0 : axen_cmd(struct axen_softc *sc, int cmd, int index, int val, void *buf)
     142             : {
     143           0 :         usb_device_request_t    req;
     144             :         usbd_status             err;
     145             : 
     146           0 :         if (usbd_is_dying(sc->axen_udev))
     147           0 :                 return 0;
     148             : 
     149           0 :         if (AXEN_CMD_DIR(cmd))
     150           0 :                 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     151             :         else
     152           0 :                 req.bmRequestType = UT_READ_VENDOR_DEVICE;
     153           0 :         req.bRequest = AXEN_CMD_CMD(cmd);
     154           0 :         USETW(req.wValue, val);
     155           0 :         USETW(req.wIndex, index);
     156           0 :         USETW(req.wLength, AXEN_CMD_LEN(cmd));
     157             : 
     158           0 :         err = usbd_do_request(sc->axen_udev, &req, buf);
     159             :         DPRINTFN(5, ("axen_cmd: cmd 0x%04x val 0x%04x len %d\n",
     160             :             cmd, val, AXEN_CMD_LEN(cmd)));
     161             : 
     162           0 :         if (err) {
     163             :                 DPRINTF(("axen_cmd err: cmd: %d, error: %d\n", cmd, err));
     164           0 :                 return -1;
     165             :         }
     166             : 
     167           0 :         return 0;
     168           0 : }
     169             : 
     170             : int
     171           0 : axen_miibus_readreg(struct device *dev, int phy, int reg)
     172             : {
     173           0 :         struct axen_softc       *sc = (void *)dev;
     174             :         int                     err;
     175           0 :         uWord                   val;
     176             :         int                     ival;
     177             : 
     178           0 :         if (usbd_is_dying(sc->axen_udev)) {
     179             :                 DPRINTF(("axen: dying\n"));
     180           0 :                 return 0;
     181             :         }
     182             : 
     183           0 :         if (sc->axen_phyno != phy)
     184           0 :                 return 0;
     185             : 
     186           0 :         axen_lock_mii(sc);
     187           0 :         err = axen_cmd(sc, AXEN_CMD_MII_READ_REG, reg, phy, &val);
     188           0 :         axen_unlock_mii(sc);
     189             : 
     190           0 :         if (err) {
     191           0 :                 printf("axen%d: read PHY failed\n", sc->axen_unit);
     192           0 :                 return -1;
     193             :         }
     194             : 
     195           0 :         ival = UGETW(val);
     196             :         DPRINTFN(2,("axen_miibus_readreg: phy 0x%x reg 0x%x val 0x%x\n",
     197             :             phy, reg, ival));
     198             : 
     199           0 :         if (reg == MII_BMSR) {
     200           0 :                 ival &= ~BMSR_EXTCAP;
     201           0 :         }
     202             : 
     203           0 :         return ival;
     204           0 : }
     205             : 
     206             : void
     207           0 : axen_miibus_writereg(struct device *dev, int phy, int reg, int val)
     208             : {
     209           0 :         struct axen_softc       *sc = (void *)dev;
     210             :         int                     err;
     211           0 :         uWord                   uval;
     212             : 
     213           0 :         if (usbd_is_dying(sc->axen_udev))
     214           0 :                 return;
     215             : 
     216           0 :         if (sc->axen_phyno != phy)
     217           0 :                 return;
     218             : 
     219           0 :         USETW(uval, val);
     220           0 :         axen_lock_mii(sc);
     221           0 :         err = axen_cmd(sc, AXEN_CMD_MII_WRITE_REG, reg, phy, &uval);
     222           0 :         axen_unlock_mii(sc);
     223             :         DPRINTFN(2, ("axen_miibus_writereg: phy 0x%x reg 0x%x val 0x%0x\n",
     224             :             phy, reg, val));
     225             : 
     226           0 :         if (err) {
     227           0 :                 printf("axen%d: write PHY failed\n", sc->axen_unit);
     228           0 :                 return;
     229             :         }
     230           0 : }
     231             : 
     232             : void
     233           0 : axen_miibus_statchg(struct device *dev)
     234             : {
     235           0 :         struct axen_softc       *sc = (void *)dev;
     236           0 :         struct mii_data         *mii = GET_MII(sc);
     237             :         struct ifnet            *ifp;
     238             :         int                     err;
     239             :         uint16_t                val;
     240           0 :         uWord                   wval;
     241             : 
     242           0 :         ifp = GET_IFP(sc);
     243           0 :         if (mii == NULL || ifp == NULL ||
     244           0 :             (ifp->if_flags & IFF_RUNNING) == 0)
     245           0 :                 return;
     246             : 
     247           0 :         sc->axen_link = 0;
     248           0 :         if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
     249             :             (IFM_ACTIVE | IFM_AVALID)) {
     250           0 :                 switch (IFM_SUBTYPE(mii->mii_media_active)) {
     251             :                     case IFM_10_T:
     252             :                     case IFM_100_TX:
     253           0 :                         sc->axen_link++;
     254           0 :                         break;
     255             :                     case IFM_1000_T:
     256           0 :                         sc->axen_link++;
     257           0 :                         break;
     258             :                     default:
     259             :                         break;
     260             :                 }
     261             :         }
     262             : 
     263             :         /* Lost link, do nothing. */
     264           0 :         if (sc->axen_link == 0)
     265           0 :                 return;
     266             : 
     267             :         val = 0;
     268           0 :         if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
     269           0 :                 val |= AXEN_MEDIUM_FDX;
     270             : 
     271           0 :         val |= (AXEN_MEDIUM_RECV_EN | AXEN_MEDIUM_ALWAYS_ONE);
     272           0 :         val |= (AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN);
     273             : 
     274           0 :         switch (IFM_SUBTYPE(mii->mii_media_active)) {
     275             :         case IFM_1000_T:
     276           0 :                 val |= AXEN_MEDIUM_GIGA | AXEN_MEDIUM_EN_125MHZ;
     277           0 :                 break;
     278             :         case IFM_100_TX:
     279           0 :                 val |= AXEN_MEDIUM_PS;
     280           0 :                 break;
     281             :         case IFM_10_T:
     282             :                 /* doesn't need to be handled */
     283             :                 break;
     284             :         }
     285             : 
     286             :         DPRINTF(("axen_miibus_statchg: val=0x%x\n", val));
     287           0 :         USETW(wval, val);
     288           0 :         axen_lock_mii(sc);
     289           0 :         err = axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval);
     290           0 :         axen_unlock_mii(sc);
     291           0 :         if (err) {
     292           0 :                 printf("%s: media change failed\n", sc->axen_dev.dv_xname);
     293           0 :                 return;
     294             :         }
     295           0 : }
     296             : 
     297             : /*
     298             :  * Set media options.
     299             :  */
     300             : int
     301           0 : axen_ifmedia_upd(struct ifnet *ifp)
     302             : {
     303           0 :         struct axen_softc       *sc = ifp->if_softc;
     304           0 :         struct mii_data         *mii = GET_MII(sc);
     305             :         int err;
     306             : 
     307           0 :         sc->axen_link = 0;
     308             : 
     309           0 :         if (mii->mii_instance) {
     310             :                 struct mii_softc        *miisc;
     311           0 :                 LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
     312           0 :                         mii_phy_reset(miisc);
     313           0 :         }
     314             : 
     315           0 :         err = mii_mediachg(mii);
     316           0 :         if (err == ENXIO)
     317           0 :                 return 0;
     318             :         else
     319           0 :                 return err;
     320           0 : }
     321             : 
     322             : /*
     323             :  * Report current media status.
     324             :  */
     325             : void
     326           0 : axen_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
     327             : {
     328           0 :         struct axen_softc       *sc = ifp->if_softc;
     329           0 :         struct mii_data         *mii = GET_MII(sc);
     330             : 
     331           0 :         mii_pollstat(mii);
     332           0 :         ifmr->ifm_active = mii->mii_media_active;
     333           0 :         ifmr->ifm_status = mii->mii_media_status;
     334           0 : }
     335             : 
     336             : void
     337           0 : axen_iff(struct axen_softc *sc)
     338             : {
     339           0 :         struct ifnet            *ifp = GET_IFP(sc);
     340             :         struct arpcom           *ac = &sc->arpcom;
     341             :         struct ether_multi      *enm;
     342             :         struct ether_multistep  step;
     343             :         u_int32_t               h = 0;
     344             :         u_int16_t               rxmode;
     345           0 :         u_int8_t                hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
     346           0 :         uWord                   wval;
     347             : 
     348           0 :         if (usbd_is_dying(sc->axen_udev))
     349           0 :                 return;
     350             : 
     351             :         rxmode = 0;
     352             : 
     353             :         /* Enable receiver, set RX mode */
     354           0 :         axen_lock_mii(sc);
     355           0 :         axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval);
     356           0 :         rxmode = UGETW(wval);
     357           0 :         rxmode &= ~(AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_ACPT_PHY_MCAST |
     358             :                   AXEN_RXCTL_PROMISC);
     359           0 :         ifp->if_flags &= ~IFF_ALLMULTI;
     360             : 
     361             :         /*
     362             :          * Always accept broadcast frames.
     363             :          * Always accept frames destined to our station address.
     364             :          */
     365           0 :         rxmode |= AXEN_RXCTL_ACPT_BCAST;
     366             : 
     367           0 :         if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
     368           0 :                 ifp->if_flags |= IFF_ALLMULTI;
     369           0 :                 rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_ACPT_PHY_MCAST;
     370           0 :                 if (ifp->if_flags & IFF_PROMISC)
     371           0 :                         rxmode |= AXEN_RXCTL_PROMISC;
     372             :         } else {
     373           0 :                 rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_ACPT_PHY_MCAST;
     374             : 
     375             :                 /* now program new ones */
     376           0 :                 ETHER_FIRST_MULTI(step, ac, enm);
     377           0 :                 while (enm != NULL) {
     378           0 :                         h = ether_crc32_be(enm->enm_addrlo,
     379           0 :                             ETHER_ADDR_LEN) >> 26;
     380           0 :                         hashtbl[h / 8] |= 1 << (h % 8);
     381           0 :                         ETHER_NEXT_MULTI(step, enm);
     382             :                 }
     383             :         }
     384             : 
     385           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE_FILTER, 8, AXEN_FILTER_MULTI, 
     386             :             (void *)&hashtbl);
     387           0 :         USETW(wval, rxmode);
     388           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval);
     389           0 :         axen_unlock_mii(sc);
     390           0 : }
     391             : 
     392             : void
     393           0 : axen_reset(struct axen_softc *sc)
     394             : {
     395           0 :         if (usbd_is_dying(sc->axen_udev))
     396             :                 return;
     397             :         
     398           0 :         axen_ax88179_init(sc);
     399             : 
     400             :         /* Wait a little while for the chip to get its brains in order. */
     401           0 :         DELAY(1000);
     402           0 :         return;
     403           0 : }
     404             : 
     405             : void
     406           0 : axen_ax88179_init(struct axen_softc *sc)
     407             : {
     408           0 :         uWord           wval;
     409           0 :         uByte           val;
     410             :         u_int16_t       ctl, temp;
     411           0 :         struct axen_qctrl qctrl;
     412             : 
     413           0 :         axen_lock_mii(sc);
     414             : 
     415             :         /* XXX: ? */
     416           0 :         axen_cmd(sc, AXEN_CMD_MAC_READ, 1, AXEN_UNK_05, &val);
     417             :         DPRINTFN(5, ("AXEN_CMD_MAC_READ(0x05): 0x%02x\n", val));
     418             : 
     419             :         /* check AX88179 version, UA1 / UA2 */
     420           0 :         axen_cmd(sc, AXEN_CMD_MAC_READ, 1, AXEN_GENERAL_STATUS, &val);
     421             :         /* UA1 */
     422           0 :         if (!(val & AXEN_GENERAL_STATUS_MASK)) {
     423           0 :                 sc->axen_rev = AXEN_REV_UA1;
     424             :                 DPRINTF(("AX88179 ver. UA1\n"));
     425           0 :         } else {
     426           0 :                 sc->axen_rev = AXEN_REV_UA2;
     427             :                 DPRINTF(("AX88179 ver. UA2\n"));
     428             :         }
     429             : 
     430             :         /* power up ethernet PHY */
     431           0 :         USETW(wval, 0);
     432           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval);
     433             : 
     434           0 :         USETW(wval, AXEN_PHYPWR_RSTCTL_IPRL);
     435           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval);
     436           0 :         usbd_delay_ms(sc->axen_udev, 200);
     437             : 
     438             :         /* set clock mode */
     439           0 :         val = AXEN_PHYCLK_ACS | AXEN_PHYCLK_BCS;
     440           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val);
     441           0 :         usbd_delay_ms(sc->axen_udev, 100);
     442             : 
     443             :         /* set monitor mode (disable) */
     444           0 :         val = AXEN_MONITOR_NONE;
     445           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_MONITOR_MODE, &val);
     446             : 
     447             :         /* enable auto detach */
     448           0 :         axen_cmd(sc, AXEN_CMD_EEPROM_READ, 2, AXEN_EEPROM_STAT, &wval);
     449           0 :         temp = UGETW(wval);
     450             :         DPRINTFN(2,("EEPROM0x43 = 0x%04x\n", temp));
     451           0 :         if (!(temp == 0xffff) && !(temp & 0x0100)) {
     452             :                 /* Enable auto detach bit */
     453           0 :                 val = 0;
     454           0 :                 axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val);
     455           0 :                 val = AXEN_PHYCLK_ULR;
     456           0 :                 axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val);
     457           0 :                 usbd_delay_ms(sc->axen_udev, 100);
     458             : 
     459           0 :                 axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_PHYPWR_RSTCTL, &wval);
     460           0 :                 ctl = UGETW(wval);
     461           0 :                 ctl |= AXEN_PHYPWR_RSTCTL_AUTODETACH;
     462           0 :                 USETW(wval, ctl);
     463           0 :                 axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval);
     464           0 :                 usbd_delay_ms(sc->axen_udev, 200);
     465           0 :                 printf("%s: enable auto detach (0x%04x)\n",
     466           0 :                     sc->axen_dev.dv_xname, ctl);
     467           0 :         }
     468             : 
     469             :         /* bulkin queue setting */
     470           0 :         axen_cmd(sc, AXEN_CMD_MAC_READ, 1, AXEN_USB_UPLINK, &val);
     471           0 :         switch (val) {
     472             :         case AXEN_USB_FS:
     473             :                 DPRINTF(("uplink: USB1.1\n"));
     474           0 :                 qctrl.ctrl      = 0x07;
     475           0 :                 qctrl.timer_low = 0xcc;
     476           0 :                 qctrl.timer_high= 0x4c;
     477           0 :                 qctrl.bufsize   = AXEN_BUFSZ_LS - 1;
     478           0 :                 qctrl.ifg       = 0x08;
     479           0 :                 break;
     480             :         case AXEN_USB_HS:
     481             :                 DPRINTF(("uplink: USB2.0\n"));
     482           0 :                 qctrl.ctrl      = 0x07;
     483           0 :                 qctrl.timer_low = 0x02;
     484           0 :                 qctrl.timer_high= 0xa0;
     485           0 :                 qctrl.bufsize   = AXEN_BUFSZ_HS - 1;
     486           0 :                 qctrl.ifg       = 0xff;
     487           0 :                 break;
     488             :         case AXEN_USB_SS:
     489             :                 DPRINTF(("uplink: USB3.0\n"));
     490           0 :                 qctrl.ctrl      = 0x07;
     491           0 :                 qctrl.timer_low = 0x4f;
     492           0 :                 qctrl.timer_high= 0x00;
     493           0 :                 qctrl.bufsize   = AXEN_BUFSZ_SS - 1;
     494           0 :                 qctrl.ifg       = 0xff;
     495           0 :                 break;
     496             :         default:
     497           0 :                 printf("%s: unknown uplink bus:0x%02x\n",
     498           0 :                     sc->axen_dev.dv_xname, val);
     499           0 :                 axen_unlock_mii(sc);
     500           0 :                 return;
     501             :         }
     502           0 :         axen_cmd(sc, AXEN_CMD_MAC_SET_RXSR, 5, AXEN_RX_BULKIN_QCTRL, &qctrl);
     503             : 
     504             :         /* Set MAC address. */
     505           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE_ETHER, ETHER_ADDR_LEN,
     506           0 :             AXEN_CMD_MAC_NODE_ID, &sc->arpcom.ac_enaddr);
     507             : 
     508             :         /*
     509             :          * set buffer high/low watermark to pause/resume.
     510             :          * write 2byte will set high/log simultaneous with AXEN_PAUSE_HIGH.
     511             :          * XXX: what is the best value? OSX driver uses 0x3c-0x4c as LOW-HIGH
     512             :          * watermark parameters.
     513             :          */
     514           0 :         val = 0x34;
     515           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_PAUSE_LOW_WATERMARK, &val);
     516           0 :         val = 0x52;
     517           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_PAUSE_HIGH_WATERMARK, &val);
     518             : 
     519             :         /* Set RX/TX configuration. */
     520             :         /* Offloadng enable */
     521             : #ifdef AXEN_TOE
     522           0 :         val = AXEN_RXCOE_IPv4 | AXEN_RXCOE_TCPv4 | AXEN_RXCOE_UDPv4 |
     523             :               AXEN_RXCOE_TCPv6 | AXEN_RXCOE_UDPv6;
     524             : #else
     525             :         val = AXEN_RXCOE_OFF;
     526             : #endif
     527           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_RX_COE, &val);
     528             : 
     529             : #ifdef AXEN_TOE
     530           0 :         val = AXEN_TXCOE_IPv4 | AXEN_TXCOE_TCPv4 | AXEN_TXCOE_UDPv4 |
     531             :               AXEN_TXCOE_TCPv6 | AXEN_TXCOE_UDPv6;
     532             : #else
     533             :         val = AXEN_TXCOE_OFF;
     534             : #endif
     535           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_TX_COE, &val);
     536             : 
     537             :         /* Set RX control register */
     538             :         ctl = AXEN_RXCTL_IPE | AXEN_RXCTL_DROPCRCERR | AXEN_RXCTL_AUTOB;
     539             :         ctl |= AXEN_RXCTL_ACPT_PHY_MCAST | AXEN_RXCTL_ACPT_ALL_MCAST;
     540             :         ctl |= AXEN_RXCTL_START;
     541           0 :         USETW(wval, ctl);
     542           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval);
     543             : 
     544             :         /* set monitor mode (enable) */
     545           0 :         val = AXEN_MONITOR_PMETYPE | AXEN_MONITOR_PMEPOL | AXEN_MONITOR_RWMP;
     546           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_MONITOR_MODE, &val);
     547           0 :         axen_cmd(sc, AXEN_CMD_MAC_READ, 1, AXEN_MONITOR_MODE, &val);
     548             :         DPRINTF(("axen: Monitor mode = 0x%02x\n", val));
     549             : 
     550             :         /* set medium type */
     551             :         ctl = AXEN_MEDIUM_GIGA | AXEN_MEDIUM_FDX | AXEN_MEDIUM_ALWAYS_ONE |
     552             :               AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN;
     553             :         ctl |= AXEN_MEDIUM_RECV_EN;
     554           0 :         USETW(wval, ctl);
     555             :         DPRINTF(("axen: set to medium mode: 0x%04x\n", UGETW(wval)));
     556           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval);
     557           0 :         usbd_delay_ms(sc->axen_udev, 100);
     558             : 
     559           0 :         axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_MEDIUM_STATUS, &wval);
     560             :         DPRINTF(("axen: current medium mode: 0x%04x\n", UGETW(wval)));
     561           0 :         axen_unlock_mii(sc);
     562             : 
     563             : #if 0 /* XXX: TBD.... */
     564             : #define GMII_LED_ACTIVE         0x1a
     565             : #define GMII_PHY_PAGE_SEL       0x1e
     566             : #define GMII_PHY_PAGE_SEL       0x1f
     567             : #define GMII_PAGE_EXT           0x0007
     568             :         axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, GMII_PHY_PAGE_SEL,
     569             :             GMII_PAGE_EXT);
     570             :         axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, GMII_PHY_PAGE,
     571             :             0x002c);
     572             : #endif
     573             : 
     574             : #if 1 /* XXX: phy hack ? */
     575           0 :         axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, 0x1F, 0x0005);
     576           0 :         axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, 0x0C, 0x0000);
     577           0 :         val = axen_miibus_readreg(&sc->axen_dev, sc->axen_phyno, 0x0001);
     578           0 :         axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, 0x01,
     579           0 :             val | 0x0080);
     580           0 :         axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, 0x1F, 0x0000);
     581             : #endif
     582           0 : }
     583             : 
     584             : int
     585           0 : axen_match(struct device *parent, void *match, void *aux)
     586             : {
     587           0 :         struct usb_attach_arg *uaa = aux;
     588             : 
     589           0 :         if (uaa->iface == NULL || uaa->configno != 1)
     590           0 :                 return (UMATCH_NONE);
     591             : 
     592           0 :         return (axen_lookup(uaa->vendor, uaa->product) != NULL ?
     593             :                 UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE);
     594           0 : }
     595             : 
     596             : void
     597           0 : axen_attach(struct device *parent, struct device *self, void *aux)
     598             : {
     599           0 :         struct axen_softc       *sc = (struct axen_softc *)self;
     600           0 :         struct usb_attach_arg   *uaa = aux;
     601             :         usb_interface_descriptor_t *id;
     602             :         usb_endpoint_descriptor_t *ed;
     603             :         struct mii_data         *mii;
     604           0 :         u_char                   eaddr[ETHER_ADDR_LEN];
     605           0 :         char                    *devname = sc->axen_dev.dv_xname;
     606             :         struct ifnet            *ifp;
     607             :         int                      i, s;
     608             : 
     609           0 :         sc->axen_unit = self->dv_unit; /*device_get_unit(self);*/
     610           0 :         sc->axen_udev = uaa->device;
     611           0 :         sc->axen_iface = uaa->iface;
     612           0 :         sc->axen_flags = axen_lookup(uaa->vendor, uaa->product)->axen_flags;
     613             : 
     614           0 :         usb_init_task(&sc->axen_tick_task, axen_tick_task, sc,
     615             :             USB_TASK_TYPE_GENERIC);
     616           0 :         rw_init(&sc->axen_mii_lock, "axenmii");
     617           0 :         usb_init_task(&sc->axen_stop_task, (void (*)(void *))axen_stop, sc,
     618             :             USB_TASK_TYPE_GENERIC);
     619             : 
     620           0 :         sc->axen_product = uaa->product;
     621           0 :         sc->axen_vendor = uaa->vendor;
     622             : 
     623           0 :         id = usbd_get_interface_descriptor(sc->axen_iface);
     624             : 
     625             :         /* decide on what our bufsize will be */
     626           0 :         switch (sc->axen_udev->speed) {
     627             :         case USB_SPEED_FULL:
     628           0 :                 sc->axen_bufsz = AXEN_BUFSZ_LS * 1024; 
     629           0 :                 break;
     630             :         case USB_SPEED_HIGH:
     631           0 :                 sc->axen_bufsz = AXEN_BUFSZ_HS * 1024; 
     632           0 :                 break;
     633             :         case USB_SPEED_SUPER:
     634           0 :                 sc->axen_bufsz = AXEN_BUFSZ_SS * 1024; 
     635           0 :                 break;
     636             :         default:
     637           0 :                 printf("%s: not supported usb bus type", sc->axen_dev.dv_xname);
     638           0 :                 return;
     639             :         }
     640             :                 
     641             :         /* Find endpoints. */
     642           0 :         for (i = 0; i < id->bNumEndpoints; i++) {
     643           0 :                 ed = usbd_interface2endpoint_descriptor(sc->axen_iface, i);
     644           0 :                 if (!ed) {
     645           0 :                         printf("%s: couldn't get ep %d\n",
     646             :                             sc->axen_dev.dv_xname, i);
     647           0 :                         return;
     648             :                 }
     649           0 :                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     650           0 :                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     651           0 :                         sc->axen_ed[AXEN_ENDPT_RX] = ed->bEndpointAddress;
     652           0 :                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
     653           0 :                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     654           0 :                         sc->axen_ed[AXEN_ENDPT_TX] = ed->bEndpointAddress;
     655           0 :                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     656           0 :                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
     657           0 :                         sc->axen_ed[AXEN_ENDPT_INTR] = ed->bEndpointAddress;
     658           0 :                 }
     659             :         }
     660             : 
     661           0 :         s = splnet();
     662             : 
     663           0 :         sc->axen_phyno = AXEN_PHY_ID;
     664             :         DPRINTF((" get_phyno %d\n", sc->axen_phyno));
     665             : 
     666             :         /*
     667             :          * Get station address.
     668             :          */
     669             :         /* use MAC command */
     670           0 :         axen_lock_mii(sc);
     671           0 :         axen_cmd(sc, AXEN_CMD_MAC_READ_ETHER, ETHER_ADDR_LEN,
     672             :             AXEN_CMD_MAC_NODE_ID, &eaddr);
     673           0 :         axen_unlock_mii(sc);
     674             : 
     675             :         /*
     676             :          * An ASIX chip was detected. Inform the world.
     677             :          */
     678           0 :         printf("%s:", sc->axen_dev.dv_xname);
     679           0 :         if (sc->axen_flags & AX178A)
     680           0 :                 printf(" AX88178a");
     681           0 :         else if (sc->axen_flags & AX179)
     682           0 :                 printf(" AX88179");
     683           0 :         printf(", address %s\n", ether_sprintf(eaddr));
     684             : 
     685           0 :         bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
     686             : 
     687           0 :         axen_ax88179_init(sc);
     688             : 
     689             :         /* Initialize interface info. */
     690           0 :         ifp = &sc->arpcom.ac_if;
     691           0 :         ifp->if_softc = sc;
     692           0 :         strlcpy(ifp->if_xname, devname, IFNAMSIZ);
     693           0 :         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     694           0 :         ifp->if_ioctl = axen_ioctl;
     695           0 :         ifp->if_start = axen_start;
     696           0 :         ifp->if_watchdog = axen_watchdog;
     697             : 
     698           0 :         ifp->if_capabilities = IFCAP_VLAN_MTU;
     699             : #ifdef AXEN_TOE
     700           0 :         ifp->if_capabilities |= IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
     701             :             IFCAP_CSUM_UDPv4 | IFCAP_CSUM_TCPv6 | IFCAP_CSUM_UDPv6;
     702             : #endif
     703             : 
     704             :         /* Initialize MII/media info. */
     705           0 :         mii = &sc->axen_mii;
     706           0 :         mii->mii_ifp = ifp;
     707           0 :         mii->mii_readreg = axen_miibus_readreg;
     708           0 :         mii->mii_writereg = axen_miibus_writereg;
     709           0 :         mii->mii_statchg = axen_miibus_statchg;
     710           0 :         mii->mii_flags = MIIF_AUTOTSLEEP;
     711             : 
     712           0 :         ifmedia_init(&mii->mii_media, 0, axen_ifmedia_upd, axen_ifmedia_sts);
     713           0 :         mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
     714             : 
     715           0 :         if (LIST_FIRST(&mii->mii_phys) == NULL) {
     716           0 :                 ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
     717           0 :                 ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
     718           0 :         } else
     719           0 :                 ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
     720             : 
     721             :         /* Attach the interface. */
     722           0 :         if_attach(ifp);
     723           0 :         ether_ifattach(ifp);
     724             : 
     725           0 :         timeout_set(&sc->axen_stat_ch, axen_tick, sc);
     726             : 
     727           0 :         splx(s);
     728           0 : }
     729             : 
     730             : int
     731           0 : axen_detach(struct device *self, int flags)
     732             : {
     733           0 :         struct axen_softc       *sc = (struct axen_softc *)self;
     734             :         int                     s;
     735           0 :         struct ifnet            *ifp = GET_IFP(sc);
     736             : 
     737             :         DPRINTFN(2,("%s: %s: enter\n", sc->axen_dev.dv_xname, __func__));
     738             : 
     739           0 :         if (timeout_initialized(&sc->axen_stat_ch))
     740           0 :                 timeout_del(&sc->axen_stat_ch);
     741             : 
     742           0 :         if (sc->axen_ep[AXEN_ENDPT_TX] != NULL)
     743           0 :                 usbd_abort_pipe(sc->axen_ep[AXEN_ENDPT_TX]);
     744           0 :         if (sc->axen_ep[AXEN_ENDPT_RX] != NULL)
     745           0 :                 usbd_abort_pipe(sc->axen_ep[AXEN_ENDPT_RX]);
     746           0 :         if (sc->axen_ep[AXEN_ENDPT_INTR] != NULL)
     747           0 :                 usbd_abort_pipe(sc->axen_ep[AXEN_ENDPT_INTR]);
     748             : 
     749             :         /*
     750             :          * Remove any pending tasks.  They cannot be executing because they run
     751             :          * in the same thread as detach.
     752             :          */
     753           0 :         usb_rem_task(sc->axen_udev, &sc->axen_tick_task);
     754           0 :         usb_rem_task(sc->axen_udev, &sc->axen_stop_task);
     755             : 
     756           0 :         s = splusb();
     757             : 
     758           0 :         if (--sc->axen_refcnt >= 0) {
     759             :                 /* Wait for processes to go away */
     760           0 :                 usb_detach_wait(&sc->axen_dev);
     761           0 :         }
     762             : 
     763           0 :         if (ifp->if_flags & IFF_RUNNING)
     764           0 :                 axen_stop(sc);
     765             : 
     766           0 :         mii_detach(&sc->axen_mii, MII_PHY_ANY, MII_OFFSET_ANY);
     767           0 :         ifmedia_delete_instance(&sc->axen_mii.mii_media, IFM_INST_ANY);
     768           0 :         if (ifp->if_softc != NULL) {
     769           0 :                 ether_ifdetach(ifp);
     770           0 :                 if_detach(ifp);
     771           0 :         }
     772             : 
     773             : #ifdef DIAGNOSTIC
     774           0 :         if (sc->axen_ep[AXEN_ENDPT_TX] != NULL ||
     775           0 :             sc->axen_ep[AXEN_ENDPT_RX] != NULL ||
     776           0 :             sc->axen_ep[AXEN_ENDPT_INTR] != NULL)
     777           0 :                 printf("%s: detach has active endpoints\n",
     778           0 :                     sc->axen_dev.dv_xname);
     779             : #endif
     780             : 
     781           0 :         if (--sc->axen_refcnt >= 0) {
     782             :                 /* Wait for processes to go away. */
     783           0 :                 usb_detach_wait(&sc->axen_dev);
     784           0 :         }
     785           0 :         splx(s);
     786             : 
     787           0 :         return 0;
     788             : }
     789             : 
     790             : struct mbuf *
     791           0 : axen_newbuf(void)
     792             : {
     793             :         struct mbuf *m;
     794             : 
     795           0 :         MGETHDR(m, M_DONTWAIT, MT_DATA);
     796           0 :         if (m == NULL)
     797           0 :                 return NULL;
     798             : 
     799           0 :         MCLGET(m, M_DONTWAIT);
     800           0 :         if (!(m->m_flags & M_EXT)) {
     801           0 :                 m_freem(m);
     802           0 :                 return NULL;
     803             :         }
     804             : 
     805           0 :         m->m_len = m->m_pkthdr.len = MCLBYTES;
     806           0 :         m_adj(m, ETHER_ALIGN);
     807             : 
     808           0 :         return m;
     809           0 : }
     810             : 
     811             : int
     812           0 : axen_rx_list_init(struct axen_softc *sc)
     813             : {
     814             :         struct axen_cdata *cd;
     815             :         struct axen_chain *c;
     816             :         int i;
     817             : 
     818             :         DPRINTF(("%s: %s: enter\n", sc->axen_dev.dv_xname, __func__));
     819             : 
     820           0 :         cd = &sc->axen_cdata;
     821           0 :         for (i = 0; i < AXEN_RX_LIST_CNT; i++) {
     822           0 :                 c = &cd->axen_rx_chain[i];
     823           0 :                 c->axen_sc = sc;
     824           0 :                 c->axen_idx = i;
     825           0 :                 c->axen_mbuf = NULL;
     826           0 :                 if (c->axen_xfer == NULL) {
     827           0 :                         c->axen_xfer = usbd_alloc_xfer(sc->axen_udev);
     828           0 :                         if (c->axen_xfer == NULL)
     829           0 :                                 return ENOBUFS;
     830           0 :                         c->axen_buf = usbd_alloc_buffer(c->axen_xfer,
     831           0 :                             sc->axen_bufsz);
     832           0 :                         if (c->axen_buf == NULL) {
     833           0 :                                 usbd_free_xfer(c->axen_xfer);
     834           0 :                                 return ENOBUFS;
     835             :                         }
     836             :                 }
     837             :         }
     838             : 
     839           0 :         return 0;
     840           0 : }
     841             : 
     842             : int
     843           0 : axen_tx_list_init(struct axen_softc *sc)
     844             : {
     845             :         struct axen_cdata *cd;
     846             :         struct axen_chain *c;
     847             :         int i;
     848             : 
     849             :         DPRINTF(("%s: %s: enter\n", sc->axen_dev.dv_xname, __func__));
     850             : 
     851           0 :         cd = &sc->axen_cdata;
     852           0 :         for (i = 0; i < AXEN_TX_LIST_CNT; i++) {
     853           0 :                 c = &cd->axen_tx_chain[i];
     854           0 :                 c->axen_sc = sc;
     855           0 :                 c->axen_idx = i;
     856           0 :                 c->axen_mbuf = NULL;
     857           0 :                 if (c->axen_xfer == NULL) {
     858           0 :                         c->axen_xfer = usbd_alloc_xfer(sc->axen_udev);
     859           0 :                         if (c->axen_xfer == NULL)
     860           0 :                                 return ENOBUFS;
     861           0 :                         c->axen_buf = usbd_alloc_buffer(c->axen_xfer,
     862           0 :                             sc->axen_bufsz);
     863           0 :                         if (c->axen_buf == NULL) {
     864           0 :                                 usbd_free_xfer(c->axen_xfer);
     865           0 :                                 return ENOBUFS;
     866             :                         }
     867             :                 }
     868             :         }
     869             : 
     870           0 :         return 0;
     871           0 : }
     872             : 
     873             : /*
     874             :  * A frame has been uploaded: pass the resulting mbuf chain up to
     875             :  * the higher level protocols.
     876             :  */
     877             : void
     878           0 : axen_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
     879             : {
     880           0 :         struct axen_chain       *c = (struct axen_chain *)priv;
     881           0 :         struct axen_softc       *sc = c->axen_sc;
     882           0 :         struct ifnet            *ifp = GET_IFP(sc);
     883           0 :         u_char                  *buf = c->axen_buf;
     884           0 :         struct mbuf_list        ml = MBUF_LIST_INITIALIZER();
     885             :         struct mbuf             *m;
     886           0 :         u_int32_t               total_len;
     887             :         u_int32_t               rx_hdr, pkt_hdr;
     888             :         u_int32_t               *hdr_p;
     889             :         u_int16_t               hdr_offset, pkt_count;
     890             :         size_t                  pkt_len;
     891             :         size_t                  temp;
     892             :         int                     s;
     893             : 
     894             :         DPRINTFN(10,("%s: %s: enter\n", sc->axen_dev.dv_xname,__func__));
     895             : 
     896           0 :         if (usbd_is_dying(sc->axen_udev))
     897           0 :                 return;
     898             : 
     899           0 :         if (!(ifp->if_flags & IFF_RUNNING))
     900           0 :                 return;
     901             : 
     902           0 :         if (status != USBD_NORMAL_COMPLETION) {
     903           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
     904           0 :                         return;
     905           0 :                 if (usbd_ratecheck(&sc->axen_rx_notice)) {
     906           0 :                         printf("%s: usb errors on rx: %s\n",
     907           0 :                             sc->axen_dev.dv_xname, usbd_errstr(status));
     908           0 :                 }
     909           0 :                 if (status == USBD_STALLED)
     910           0 :                         usbd_clear_endpoint_stall_async(sc->axen_ep[AXEN_ENDPT_RX]);
     911             :                 goto done;
     912             :         }
     913             : 
     914           0 :         usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
     915             : 
     916           0 :         if (total_len < sizeof(pkt_hdr)) {
     917           0 :                 ifp->if_ierrors++;
     918           0 :                 goto done;
     919             :         }
     920             : 
     921             :         /* 
     922             :          * buffer map
     923             :          * [packet #0]...[packet #n][pkt hdr#0]..[pkt hdr#n][recv_hdr]
     924             :          * each packet has 0xeeee as psuedo header..
     925             :          */
     926           0 :         hdr_p = (u_int32_t *)(buf + total_len - sizeof(u_int32_t));
     927           0 :         rx_hdr = letoh32(*hdr_p);
     928           0 :         hdr_offset = (u_int16_t)(rx_hdr >> 16);
     929           0 :         pkt_count  = (u_int16_t)(rx_hdr & 0xffff);
     930             : 
     931           0 :         if (total_len > sc->axen_bufsz) {
     932           0 :                 printf("%s: rxeof: too large transfer\n",
     933           0 :                     sc->axen_dev.dv_xname);
     934           0 :                 goto done;
     935             :         }
     936             : 
     937             :         /* sanity check */
     938           0 :         if (hdr_offset > total_len) {
     939           0 :                 ifp->if_ierrors++;
     940           0 :                 usbd_delay_ms(sc->axen_udev, 100);
     941           0 :                 goto done;
     942             :         }
     943             : 
     944             :         /* point first packet header */
     945           0 :         hdr_p = (u_int32_t*)(buf + hdr_offset);
     946             : 
     947             :         /*
     948             :          * ax88179 will pack multiple ip packet to a USB transaction.
     949             :          * process all of packets in the buffer
     950             :          */
     951             : 
     952             : #if 1 /* XXX: paranoiac check. need to remove later */
     953             : #define AXEN_MAX_PACKED_PACKET 200 
     954           0 :         if (pkt_count > AXEN_MAX_PACKED_PACKET) {
     955             :                 DPRINTF(("Too many packets (%d) in a transaction, discard.\n", 
     956             :                     pkt_count));
     957             :                 goto done;
     958             :         }
     959             : #endif
     960             : 
     961           0 :         do {
     962           0 :                 if ((buf[0] != 0xee) || (buf[1] != 0xee)){
     963           0 :                         printf("%s: invalid buffer(pkt#%d), continue\n",
     964           0 :                             sc->axen_dev.dv_xname, pkt_count);
     965           0 :                         ifp->if_ierrors += pkt_count;
     966           0 :                         goto done;
     967             :                 }
     968             : 
     969           0 :                 pkt_hdr = letoh32(*hdr_p);
     970           0 :                 pkt_len = (pkt_hdr >> 16) & 0x1fff;
     971             : 
     972             :                 DPRINTFN(10,("rxeof: packet#%d, pkt_hdr 0x%08x, pkt_len %zu\n",
     973             :                    pkt_count, pkt_hdr, pkt_len));
     974             : 
     975           0 :                 if ((pkt_hdr & AXEN_RXHDR_CRC_ERR) ||
     976           0 :                     (pkt_hdr & AXEN_RXHDR_DROP_ERR)) {
     977           0 :                         ifp->if_ierrors++;
     978             :                         /* move to next pkt header */
     979             :                         DPRINTF(("crc err(pkt#%d)\n", pkt_count));
     980           0 :                         goto nextpkt;
     981             :                 }
     982             : 
     983             :                 /* process each packet */
     984             :                 /* allocate mbuf */
     985           0 :                 m = axen_newbuf();
     986           0 :                 if (m == NULL) {
     987           0 :                         ifp->if_ierrors++;
     988           0 :                         goto nextpkt;
     989             :                 }
     990             : 
     991             :                 /* skip pseudo header (2byte) and trailer padding (4Byte) */
     992           0 :                 m->m_pkthdr.len = m->m_len = pkt_len - 6;
     993             : 
     994             : #ifdef AXEN_TOE
     995             :                 /* cheksum err */
     996           0 :                 if ((pkt_hdr & AXEN_RXHDR_L3CSUM_ERR) || 
     997           0 :                     (pkt_hdr & AXEN_RXHDR_L4CSUM_ERR)) {
     998           0 :                         printf("%s: checksum err (pkt#%d)\n",
     999           0 :                             sc->axen_dev.dv_xname, pkt_count);
    1000           0 :                         goto nextpkt;
    1001             :                 } else {
    1002           0 :                         m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
    1003             :                 }
    1004             : 
    1005             :                 int l4_type;
    1006           0 :                 l4_type = (pkt_hdr & AXEN_RXHDR_L4_TYPE_MASK) >> 
    1007             :                     AXEN_RXHDR_L4_TYPE_OFFSET;
    1008             : 
    1009           0 :                 if ((l4_type == AXEN_RXHDR_L4_TYPE_TCP) ||
    1010           0 :                     (l4_type == AXEN_RXHDR_L4_TYPE_UDP)) 
    1011           0 :                         m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK |
    1012             :                             M_UDP_CSUM_IN_OK;
    1013             : #endif
    1014             : 
    1015           0 :                 memcpy(mtod(m, char *), buf + 2, pkt_len - 6);
    1016             : 
    1017           0 :                 ml_enqueue(&ml, m);
    1018             : 
    1019             : nextpkt:
    1020             :                 /*
    1021             :                  * prepare next packet 
    1022             :                  * as each packet will be aligned 8byte boundary,
    1023             :                  * need to fix up the start point of the buffer.
    1024             :                  */
    1025           0 :                 temp = ((pkt_len + 7) & 0xfff8);
    1026           0 :                 buf = buf + temp;
    1027           0 :                 hdr_p++;
    1028           0 :                 pkt_count--;
    1029           0 :         } while( pkt_count > 0);
    1030             : 
    1031             : done:
    1032             :         /* push the packet up */
    1033           0 :         s = splnet();
    1034           0 :         if_input(ifp, &ml);
    1035           0 :         splx(s);
    1036             : 
    1037             :         /* clear buffer for next transaction */
    1038           0 :         memset(c->axen_buf, 0, sc->axen_bufsz);
    1039             : 
    1040             :         /* Setup new transfer. */
    1041           0 :         usbd_setup_xfer(xfer, sc->axen_ep[AXEN_ENDPT_RX],
    1042           0 :             c, c->axen_buf, sc->axen_bufsz,
    1043             :             USBD_SHORT_XFER_OK | USBD_NO_COPY,
    1044             :             USBD_NO_TIMEOUT, axen_rxeof);
    1045           0 :         usbd_transfer(xfer);
    1046             : 
    1047             :         DPRINTFN(10,("%s: %s: start rx\n", sc->axen_dev.dv_xname, __func__));
    1048           0 : }
    1049             : 
    1050             : /*
    1051             :  * A frame was downloaded to the chip. It's safe for us to clean up
    1052             :  * the list buffers.
    1053             :  */
    1054             : void
    1055           0 : axen_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
    1056             : {
    1057             :         struct axen_softc       *sc;
    1058             :         struct axen_chain       *c;
    1059             :         struct ifnet            *ifp;
    1060             :         int                     s;
    1061             : 
    1062           0 :         c = priv;
    1063           0 :         sc = c->axen_sc;
    1064           0 :         ifp = &sc->arpcom.ac_if;
    1065             : 
    1066           0 :         if (usbd_is_dying(sc->axen_udev))
    1067           0 :                 return;
    1068             : 
    1069           0 :         s = splnet();
    1070             : 
    1071           0 :         if (status != USBD_NORMAL_COMPLETION) {
    1072           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
    1073           0 :                         splx(s);
    1074           0 :                         return;
    1075             :                 }
    1076           0 :                 ifp->if_oerrors++;
    1077           0 :                 printf("axen%d: usb error on tx: %s\n", sc->axen_unit,
    1078           0 :                     usbd_errstr(status));
    1079           0 :                 if (status == USBD_STALLED)
    1080           0 :                         usbd_clear_endpoint_stall_async(sc->axen_ep[AXEN_ENDPT_TX]);
    1081           0 :                 splx(s);
    1082           0 :                 return;
    1083             :         }
    1084             : 
    1085           0 :         ifp->if_timer = 0;
    1086           0 :         ifq_clr_oactive(&ifp->if_snd);
    1087             : 
    1088           0 :         m_freem(c->axen_mbuf);
    1089           0 :         c->axen_mbuf = NULL;
    1090             : 
    1091           0 :         if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
    1092           0 :                 axen_start(ifp);
    1093             : 
    1094           0 :         splx(s);
    1095           0 : }
    1096             : 
    1097             : void
    1098           0 : axen_tick(void *xsc)
    1099             : {
    1100           0 :         struct axen_softc *sc = xsc;
    1101             : 
    1102           0 :         if (sc == NULL)
    1103           0 :                 return;
    1104             : 
    1105             :         DPRINTFN(0xff, ("%s: %s: enter\n", sc->axen_dev.dv_xname,
    1106             :                         __func__));
    1107             : 
    1108           0 :         if (usbd_is_dying(sc->axen_udev))
    1109           0 :                 return;
    1110             : 
    1111             :         /* Perform periodic stuff in process context */
    1112           0 :         usb_add_task(sc->axen_udev, &sc->axen_tick_task);
    1113           0 : }
    1114             : 
    1115             : void
    1116           0 : axen_tick_task(void *xsc)
    1117             : {
    1118             :         int                     s;
    1119             :         struct axen_softc       *sc;
    1120             :         struct mii_data         *mii;
    1121             : 
    1122           0 :         sc = xsc;
    1123             : 
    1124           0 :         if (sc == NULL)
    1125           0 :                 return;
    1126             : 
    1127           0 :         if (usbd_is_dying(sc->axen_udev))
    1128           0 :                 return;
    1129             : 
    1130           0 :         mii = GET_MII(sc);
    1131           0 :         if (mii == NULL)
    1132           0 :                 return;
    1133             : 
    1134           0 :         s = splnet();
    1135             : 
    1136           0 :         mii_tick(mii);
    1137           0 :         if (sc->axen_link == 0)
    1138           0 :                 axen_miibus_statchg(&sc->axen_dev);
    1139           0 :         timeout_add_sec(&sc->axen_stat_ch, 1);
    1140             : 
    1141           0 :         splx(s);
    1142           0 : }
    1143             : 
    1144             : int
    1145           0 : axen_encap(struct axen_softc *sc, struct mbuf *m, int idx)
    1146             : {
    1147             :         struct axen_chain       *c;
    1148             :         usbd_status             err;
    1149             :         struct axen_sframe_hdr  hdr;
    1150             :         int                     length, boundary;
    1151             : 
    1152           0 :         c = &sc->axen_cdata.axen_tx_chain[idx];
    1153             : 
    1154           0 :         switch (sc->axen_udev->speed) {
    1155             :         case USB_SPEED_FULL:
    1156             :                 boundary = 64;
    1157           0 :                 break;
    1158             :         case USB_SPEED_HIGH:
    1159             :                 boundary = 512;
    1160           0 :                 break;
    1161             :         case USB_SPEED_SUPER:
    1162             :                 boundary = 4096; /* XXX */
    1163           0 :                 break;
    1164             :         default:
    1165           0 :                 printf("%s: not supported usb bus type", sc->axen_dev.dv_xname);
    1166           0 :                 return EIO;
    1167             :         }
    1168             : 
    1169           0 :         hdr.plen = htole32(m->m_pkthdr.len);
    1170             :         hdr.gso = 0; /* disable segmentation offloading */
    1171             : 
    1172           0 :         memcpy(c->axen_buf, &hdr, sizeof(hdr));
    1173             :         length = sizeof(hdr);
    1174             : 
    1175           0 :         m_copydata(m, 0, m->m_pkthdr.len, c->axen_buf + length);
    1176           0 :         length += m->m_pkthdr.len;
    1177             : 
    1178           0 :         if ((length % boundary) == 0) {
    1179             :                 hdr.plen = 0x0;
    1180             :                 hdr.gso |= 0x80008000;  /* enable padding */
    1181           0 :                 memcpy(c->axen_buf + length, &hdr, sizeof(hdr));
    1182           0 :                 length += sizeof(hdr);
    1183           0 :         }
    1184             : 
    1185           0 :         c->axen_mbuf = m;
    1186             : 
    1187           0 :         usbd_setup_xfer(c->axen_xfer, sc->axen_ep[AXEN_ENDPT_TX],
    1188           0 :             c, c->axen_buf, length, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
    1189             :             10000, axen_txeof);
    1190             : 
    1191             :         /* Transmit */
    1192           0 :         err = usbd_transfer(c->axen_xfer);
    1193           0 :         if (err != USBD_IN_PROGRESS) {
    1194           0 :                 axen_stop(sc);
    1195           0 :                 return EIO;
    1196             :         }
    1197             : 
    1198           0 :         sc->axen_cdata.axen_tx_cnt++;
    1199             : 
    1200           0 :         return 0;
    1201           0 : }
    1202             : 
    1203             : void
    1204           0 : axen_start(struct ifnet *ifp)
    1205             : {
    1206             :         struct axen_softc       *sc;
    1207             :         struct mbuf             *m_head = NULL;
    1208             : 
    1209           0 :         sc = ifp->if_softc;
    1210             : 
    1211           0 :         if (!sc->axen_link)
    1212           0 :                 return;
    1213             : 
    1214           0 :         if (ifq_is_oactive(&ifp->if_snd))
    1215           0 :                 return;
    1216             : 
    1217           0 :         m_head = ifq_deq_begin(&ifp->if_snd);
    1218           0 :         if (m_head == NULL)
    1219           0 :                 return;
    1220             : 
    1221           0 :         if (axen_encap(sc, m_head, 0)) {
    1222           0 :                 ifq_deq_rollback(&ifp->if_snd, m_head);
    1223           0 :                 ifq_set_oactive(&ifp->if_snd);
    1224           0 :                 return;
    1225             :         }
    1226           0 :         ifq_deq_commit(&ifp->if_snd, m_head);
    1227             : 
    1228             :         /*
    1229             :          * If there's a BPF listener, bounce a copy of this frame
    1230             :          * to him.
    1231             :          */
    1232             : #if NBPFILTER > 0
    1233           0 :         if (ifp->if_bpf)
    1234           0 :                 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
    1235             : #endif
    1236             : 
    1237           0 :         ifq_set_oactive(&ifp->if_snd);
    1238             : 
    1239             :         /*
    1240             :          * Set a timeout in case the chip goes out to lunch.
    1241             :          */
    1242           0 :         ifp->if_timer = 5;
    1243           0 : }
    1244             : 
    1245             : void
    1246           0 : axen_init(void *xsc)
    1247             : {
    1248           0 :         struct axen_softc       *sc = xsc;
    1249           0 :         struct ifnet            *ifp = &sc->arpcom.ac_if;
    1250             :         struct axen_chain       *c;
    1251             :         usbd_status             err;
    1252             :         int                     i, s;
    1253           0 :         uByte                   bval;
    1254           0 :         uWord                   wval;
    1255             :         uint16_t                rxmode;
    1256             : 
    1257           0 :         s = splnet();
    1258             : 
    1259             :         /*
    1260             :          * Cancel pending I/O and free all RX/TX buffers.
    1261             :          */
    1262           0 :         axen_reset(sc);
    1263             : 
    1264             :         /* XXX: ? */
    1265           0 :         bval = 0x01;
    1266           0 :         axen_lock_mii(sc);
    1267           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_UNK_28, &bval);
    1268           0 :         axen_unlock_mii(sc);
    1269             : 
    1270             :         /* Init RX ring. */
    1271           0 :         if (axen_rx_list_init(sc) == ENOBUFS) {
    1272           0 :                 printf("axen%d: rx list init failed\n", sc->axen_unit);
    1273           0 :                 splx(s);
    1274           0 :                 return;
    1275             :         }
    1276             : 
    1277             :         /* Init TX ring. */
    1278           0 :         if (axen_tx_list_init(sc) == ENOBUFS) {
    1279           0 :                 printf("axen%d: tx list init failed\n", sc->axen_unit);
    1280           0 :                 splx(s);
    1281           0 :                 return;
    1282             :         }
    1283             : 
    1284             :         /* Program promiscuous mode and multicast filters. */
    1285           0 :         axen_iff(sc);
    1286             : 
    1287             :         /* Enable receiver, set RX mode */
    1288           0 :         axen_lock_mii(sc);
    1289           0 :         axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval);
    1290           0 :         rxmode = UGETW(wval);
    1291           0 :         rxmode |= AXEN_RXCTL_START;
    1292           0 :         USETW(wval, rxmode);
    1293           0 :         axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval);
    1294           0 :         axen_unlock_mii(sc);
    1295             : 
    1296             :         /* Open RX and TX pipes. */
    1297           0 :         err = usbd_open_pipe(sc->axen_iface, sc->axen_ed[AXEN_ENDPT_RX],
    1298           0 :             USBD_EXCLUSIVE_USE, &sc->axen_ep[AXEN_ENDPT_RX]);
    1299           0 :         if (err) {
    1300           0 :                 printf("axen%d: open rx pipe failed: %s\n",
    1301           0 :                     sc->axen_unit, usbd_errstr(err));
    1302           0 :                 splx(s);
    1303           0 :                 return;
    1304             :         }
    1305             : 
    1306           0 :         err = usbd_open_pipe(sc->axen_iface, sc->axen_ed[AXEN_ENDPT_TX],
    1307           0 :             USBD_EXCLUSIVE_USE, &sc->axen_ep[AXEN_ENDPT_TX]);
    1308           0 :         if (err) {
    1309           0 :                 printf("axen%d: open tx pipe failed: %s\n",
    1310           0 :                     sc->axen_unit, usbd_errstr(err));
    1311           0 :                 splx(s);
    1312           0 :                 return;
    1313             :         }
    1314             : 
    1315             :         /* Start up the receive pipe. */
    1316           0 :         for (i = 0; i < AXEN_RX_LIST_CNT; i++) {
    1317           0 :                 c = &sc->axen_cdata.axen_rx_chain[i];
    1318           0 :                 usbd_setup_xfer(c->axen_xfer, sc->axen_ep[AXEN_ENDPT_RX],
    1319           0 :                     c, c->axen_buf, sc->axen_bufsz,
    1320             :                     USBD_SHORT_XFER_OK | USBD_NO_COPY,
    1321             :                     USBD_NO_TIMEOUT, axen_rxeof);
    1322           0 :                 usbd_transfer(c->axen_xfer);
    1323             :         }
    1324             : 
    1325           0 :         sc->axen_link = 0;
    1326           0 :         ifp->if_flags |= IFF_RUNNING;
    1327           0 :         ifq_clr_oactive(&ifp->if_snd);
    1328             : 
    1329           0 :         splx(s);
    1330             : 
    1331           0 :         timeout_add_sec(&sc->axen_stat_ch, 1);
    1332           0 :         return;
    1333           0 : }
    1334             : 
    1335             : int
    1336           0 : axen_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
    1337             : {
    1338           0 :         struct axen_softc       *sc = ifp->if_softc;
    1339           0 :         struct ifreq            *ifr = (struct ifreq *)data;
    1340             :         int                     s;
    1341             :         int                     error = 0;
    1342             : 
    1343           0 :         s = splnet();
    1344             : 
    1345           0 :         switch(cmd) {
    1346             :         case SIOCSIFADDR:
    1347           0 :                 ifp->if_flags |= IFF_UP;
    1348           0 :                 if (!(ifp->if_flags & IFF_RUNNING))
    1349           0 :                         axen_init(sc);
    1350             :                 break;
    1351             : 
    1352             :         case SIOCSIFFLAGS:
    1353           0 :                 if (ifp->if_flags & IFF_UP) {
    1354           0 :                         if (ifp->if_flags & IFF_RUNNING)
    1355           0 :                                 error = ENETRESET;
    1356             :                         else
    1357           0 :                                 axen_init(sc);
    1358             :                 } else {
    1359           0 :                         if (ifp->if_flags & IFF_RUNNING)
    1360           0 :                                 axen_stop(sc);
    1361             :                 }
    1362             :                 break;
    1363             : 
    1364             :         case SIOCGIFMEDIA:
    1365             :         case SIOCSIFMEDIA:
    1366           0 :                 error = ifmedia_ioctl(ifp, ifr, &sc->axen_mii.mii_media, cmd);
    1367           0 :                 break;
    1368             : 
    1369             : #if 0
    1370             :         case SCIOCSIFMTU:
    1371             :                 /* XXX need to set AX_MEDIUM_JUMBO_EN here? */
    1372             :                 /* fall through */
    1373             : #endif
    1374             :         default:
    1375           0 :                 error = ether_ioctl(ifp, &sc->arpcom, cmd, data);
    1376           0 :         }
    1377             : 
    1378           0 :         if (error == ENETRESET) {
    1379           0 :                 if (ifp->if_flags & IFF_RUNNING)
    1380           0 :                         axen_iff(sc);
    1381             :                 error = 0;
    1382           0 :         }
    1383             : 
    1384           0 :         splx(s);
    1385             : 
    1386           0 :         return error;
    1387             : }
    1388             : 
    1389             : void
    1390           0 : axen_watchdog(struct ifnet *ifp)
    1391             : {
    1392             :         struct axen_softc       *sc;
    1393             :         struct axen_chain       *c;
    1394           0 :         usbd_status             stat;
    1395             :         int                     s;
    1396             : 
    1397           0 :         sc = ifp->if_softc;
    1398             : 
    1399           0 :         ifp->if_oerrors++;
    1400           0 :         printf("axen%d: watchdog timeout\n", sc->axen_unit);
    1401             : 
    1402           0 :         s = splusb();
    1403           0 :         c = &sc->axen_cdata.axen_tx_chain[0];
    1404           0 :         usbd_get_xfer_status(c->axen_xfer, NULL, NULL, NULL, &stat);
    1405           0 :         axen_txeof(c->axen_xfer, c, stat);
    1406             : 
    1407           0 :         if (!IFQ_IS_EMPTY(&ifp->if_snd))
    1408           0 :                 axen_start(ifp);
    1409           0 :         splx(s);
    1410           0 : }
    1411             : 
    1412             : /*
    1413             :  * Stop the adapter and free any mbufs allocated to the
    1414             :  * RX and TX lists.
    1415             :  */
    1416             : void
    1417           0 : axen_stop(struct axen_softc *sc)
    1418             : {
    1419             :         usbd_status             err;
    1420             :         struct ifnet            *ifp;
    1421             :         int                     i;
    1422             : 
    1423           0 :         axen_reset(sc);
    1424             : 
    1425           0 :         ifp = &sc->arpcom.ac_if;
    1426           0 :         ifp->if_timer = 0;
    1427           0 :         ifp->if_flags &= ~IFF_RUNNING;
    1428           0 :         ifq_clr_oactive(&ifp->if_snd);
    1429             : 
    1430           0 :         timeout_del(&sc->axen_stat_ch);
    1431             : 
    1432             :         /* Stop transfers. */
    1433           0 :         if (sc->axen_ep[AXEN_ENDPT_RX] != NULL) {
    1434           0 :                 usbd_abort_pipe(sc->axen_ep[AXEN_ENDPT_RX]);
    1435           0 :                 err = usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_RX]);
    1436           0 :                 if (err) {
    1437           0 :                         printf("axen%d: close rx pipe failed: %s\n",
    1438           0 :                             sc->axen_unit, usbd_errstr(err));
    1439           0 :                 }
    1440           0 :                 sc->axen_ep[AXEN_ENDPT_RX] = NULL;
    1441           0 :         }
    1442             : 
    1443           0 :         if (sc->axen_ep[AXEN_ENDPT_TX] != NULL) {
    1444           0 :                 usbd_abort_pipe(sc->axen_ep[AXEN_ENDPT_TX]);
    1445           0 :                 err = usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_TX]);
    1446           0 :                 if (err) {
    1447           0 :                         printf("axen%d: close tx pipe failed: %s\n",
    1448           0 :                             sc->axen_unit, usbd_errstr(err));
    1449           0 :                 }
    1450           0 :                 sc->axen_ep[AXEN_ENDPT_TX] = NULL;
    1451           0 :         }
    1452             : 
    1453           0 :         if (sc->axen_ep[AXEN_ENDPT_INTR] != NULL) {
    1454           0 :                 usbd_abort_pipe(sc->axen_ep[AXEN_ENDPT_INTR]);
    1455           0 :                 err = usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_INTR]);
    1456           0 :                 if (err) {
    1457           0 :                         printf("axen%d: close intr pipe failed: %s\n",
    1458           0 :                             sc->axen_unit, usbd_errstr(err));
    1459           0 :                 }
    1460           0 :                 sc->axen_ep[AXEN_ENDPT_INTR] = NULL;
    1461           0 :         }
    1462             : 
    1463             :         /* Free RX resources. */
    1464           0 :         for (i = 0; i < AXEN_RX_LIST_CNT; i++) {
    1465           0 :                 if (sc->axen_cdata.axen_rx_chain[i].axen_mbuf != NULL) {
    1466           0 :                         m_freem(sc->axen_cdata.axen_rx_chain[i].axen_mbuf);
    1467           0 :                         sc->axen_cdata.axen_rx_chain[i].axen_mbuf = NULL;
    1468           0 :                 }
    1469           0 :                 if (sc->axen_cdata.axen_rx_chain[i].axen_xfer != NULL) {
    1470           0 :                         usbd_free_xfer(sc->axen_cdata.axen_rx_chain[i].axen_xfer);
    1471           0 :                         sc->axen_cdata.axen_rx_chain[i].axen_xfer = NULL;
    1472           0 :                 }
    1473             :         }
    1474             : 
    1475             :         /* Free TX resources. */
    1476           0 :         for (i = 0; i < AXEN_TX_LIST_CNT; i++) {
    1477             : 
    1478           0 :                 if (sc->axen_cdata.axen_tx_chain[i].axen_mbuf != NULL) {
    1479           0 :                         m_freem(sc->axen_cdata.axen_tx_chain[i].axen_mbuf);
    1480           0 :                         sc->axen_cdata.axen_tx_chain[i].axen_mbuf = NULL;
    1481           0 :                 }
    1482           0 :                 if (sc->axen_cdata.axen_tx_chain[i].axen_xfer != NULL) {
    1483           0 :                         usbd_free_xfer(sc->axen_cdata.axen_tx_chain[i].axen_xfer);
    1484           0 :                         sc->axen_cdata.axen_tx_chain[i].axen_xfer = NULL;
    1485           0 :                 }
    1486             :         }
    1487             : 
    1488           0 :         sc->axen_link = 0;
    1489           0 : }

Generated by: LCOV version 1.13