Hi,

as mentioned previously, I'm looking into axen(4). While searching
for the cause of a panic (fixed since, thanks mpi@) I started to
rewrite parts of the driver. References were mainly the FreeBSD and
Linux drivers.

I didn't get around to much testing/debugging lately, therefore I
wanted to share the current state (diff below).

The current state works a lot better than previously (for me). I
used to have a huge amount of ierrs (aprrox. 1 ierr per ipkt) and
often no packets would be transferred at all (or stop being transferred
after some time).

This box hosts backups (rsync and TimeMachine), so it gets its fair
share of traffic. I could reduce the ierrs to ~2100 with 5d uptime,
and the packets keep flowing:

$ netstat -niI axen0
Name    Mtu   Network     Address              Ipkts Ierrs    Opkts Oerrs Colls
axen0   1500  <Link>      94:c6:91:1f:85:a5 141199356  2099 112289969     0     0
$ uptime
 7:15PM  up 5 days,  9:57, 3 users, load averages: 0.11, 0.13, 0.14
$ 

But there a still a few problems:

1) There are still ierrs. These happen when the rx path can't
allocate mbufs (cf. diff below for DPRINTF):
axen0: could not allocate rx mbuf (2 total, 2 remaining)
axen0: could not allocate rx mbuf (3 total, 3 remaining)
axen0: could not allocate rx mbuf (2 total, 2 remaining)
axen0: could not allocate rx mbuf (1 total, 1 remaining)

2) If the adapter is plugged into a USB 3 port at boot, it will
return 0x42 when aked for AXEN_PHYSICAL_LINK_STATUS, ie.
(AXEN_EPHY_1000|AXEN_USB_HS). The adapter most often then simply
doesn't receive packets. If I plug in the adapter after boot is
complete, 0x44 is returned (AXEN_EPHY_1000|AXEN_USB_SS), as expected.
I'm not sure if I'm still missing something in init (probably) or
if this results from something higher in the stack (xhci?).
(Didn't test USB 2 or lower.)

3) Transfer speed

Here's the diff:

Index: dev/usb/if_axen.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_axen.c,v
retrieving revision 1.26
diff -u -p -r1.26 if_axen.c
--- dev/usb/if_axen.c   5 Dec 2018 15:54:58 -0000       1.26
+++ dev/usb/if_axen.c   12 Feb 2019 18:26:48 -0000
@@ -97,7 +97,7 @@ const struct cfattach axen_ca = {
 
 int    axen_tx_list_init(struct axen_softc *);
 int    axen_rx_list_init(struct axen_softc *);
-struct mbuf *axen_newbuf(void);
+struct mbuf *axen_newbuf(struct axen_softc *);
 int    axen_encap(struct axen_softc *, struct mbuf *, int);
 void   axen_rxeof(struct usbd_xfer *, void *, usbd_status);
 void   axen_txeof(struct usbd_xfer *, void *, usbd_status);
@@ -121,6 +121,13 @@ void       axen_unlock_mii(struct axen_softc *
 
 void   axen_ax88179_init(struct axen_softc *);
 
+struct axen_qctrl axen_bulk_size[] = {
+       { 7, 0x4f, 0x00, AXEN_BUFSZ_SS, 0xff },
+       { 7, 0x20, 0x03, AXEN_BUFSZ_HS, 0xff },
+       { 7, 0xae, 0x07, AXEN_BUFSZ_LS, 0xff },
+       { 7, 0xcc, 0x4c, AXEN_BUFSZ_LS, 0x08 }
+};
+
 /* Get exclusive access to the MII registers */
 void
 axen_lock_mii(struct axen_softc *sc)
@@ -156,7 +163,7 @@ axen_cmd(struct axen_softc *sc, int cmd,
        USETW(req.wLength, AXEN_CMD_LEN(cmd));
 
        err = usbd_do_request(sc->axen_udev, &req, buf);
-       DPRINTFN(5, ("axen_cmd: cmd 0x%04x val 0x%04x len %d\n",
+       DPRINTFN(15, ("axen_cmd: cmd 0x%04x val 0x%04x len %d\n",
            cmd, val, AXEN_CMD_LEN(cmd)));
 
        if (err) {
@@ -193,7 +200,7 @@ axen_miibus_readreg(struct device *dev, 
        }
 
        ival = UGETW(val);
-       DPRINTFN(2,("axen_miibus_readreg: phy 0x%x reg 0x%x val 0x%x\n",
+       DPRINTFN(12,("axen_miibus_readreg: phy 0x%x reg 0x%x val 0x%x\n",
            phy, reg, ival));
 
        if (reg == MII_BMSR) {
@@ -220,7 +227,7 @@ axen_miibus_writereg(struct device *dev,
        axen_lock_mii(sc);
        err = axen_cmd(sc, AXEN_CMD_MII_WRITE_REG, reg, phy, &uval);
        axen_unlock_mii(sc);
-       DPRINTFN(2, ("axen_miibus_writereg: phy 0x%x reg 0x%x val 0x%0x\n",
+       DPRINTFN(12, ("axen_miibus_writereg: phy 0x%x reg 0x%x val 0x%0x\n",
            phy, reg, val));
 
        if (err) {
@@ -236,13 +243,17 @@ axen_miibus_statchg(struct device *dev)
        struct mii_data         *mii = GET_MII(sc);
        struct ifnet            *ifp;
        int                     err;
+       uint8_t                 link_status;
        uint16_t                val;
        uWord                   wval;
+       struct axen_qctrl       *qctrl;
+
+       axen_lock_mii(sc);
 
        ifp = GET_IFP(sc);
        if (mii == NULL || ifp == NULL ||
            (ifp->if_flags & IFF_RUNNING) == 0)
-               return;
+               goto done;
 
        sc->axen_link = 0;
        if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
@@ -250,10 +261,8 @@ axen_miibus_statchg(struct device *dev)
                switch (IFM_SUBTYPE(mii->mii_media_active)) {
                    case IFM_10_T:
                    case IFM_100_TX:
-                       sc->axen_link++;
-                       break;
                    case IFM_1000_T:
-                       sc->axen_link++;
+                       sc->axen_link = 1;
                        break;
                    default:
                        break;
@@ -261,37 +270,97 @@ axen_miibus_statchg(struct device *dev)
        }
 
        /* Lost link, do nothing. */
-       if (sc->axen_link == 0)
-               return;
+       if (sc->axen_link == 0) {
+               DPRINTF(("%s: %s: lost link\n", sc->axen_dev.dv_xname,
+                   __func__));
+               goto done;
+       }
 
-       val = 0;
-       if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
-               val |= AXEN_MEDIUM_FDX;
+       err = axen_cmd(sc, AXEN_CMD_MAC_READ, 1, AXEN_PHYSICAL_LINK_STATUS,
+           &link_status);
+       if (err)
+               goto error;
+       DPRINTF(("%s: %s: link status: 0x%x\n", sc->axen_dev.dv_xname,
+           __func__, link_status));
+
+       /* both freebsd and linux don't define/set AXEN_MEDIUM_ALWAYS_ONE,
+        * but 6.2.2.10 of the datasheet (p40) sets it to 1 */
+       val = AXEN_MEDIUM_RECV_EN | AXEN_MEDIUM_ALWAYS_ONE;
 
-       val |= (AXEN_MEDIUM_RECV_EN | AXEN_MEDIUM_ALWAYS_ONE);
-       val |= (AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN);
+       if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
+               val |= AXEN_MEDIUM_FDX;
+#if 0
+               if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0)
+                       val |= AXEN_MEDIUM_TXFLOW_CTRL_EN;
+               if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0)
+                       val |= AXEN_MEDIUM_RXFLOW_CTRL_EN;
+#else
+               val |= AXEN_MEDIUM_TXFLOW_CTRL_EN | AXEN_MEDIUM_RXFLOW_CTRL_EN;
+#endif
+       }
 
        switch (IFM_SUBTYPE(mii->mii_media_active)) {
        case IFM_1000_T:
-               val |= AXEN_MEDIUM_GIGA | AXEN_MEDIUM_EN_125MHZ;
+               if (!(link_status & AXEN_EPHY_1000)) {
+                       printf("%s: wrong phy link (want 1000)\n",
+                           sc->axen_dev.dv_xname);
+               }
+               val |= AXEN_MEDIUM_GIGA;
+               if (link_status & AXEN_USB_SS)
+                       qctrl = &axen_bulk_size[0];
+               else if (link_status & AXEN_USB_HS)
+                       qctrl = &axen_bulk_size[1];
+               else
+                       qctrl = &axen_bulk_size[3];
                break;
        case IFM_100_TX:
-               val |= AXEN_MEDIUM_PS;
+               if (!(link_status & AXEN_EPHY_100)) {
+                       printf("%s: wrong phy link (want 100)\n",
+                           sc->axen_dev.dv_xname);
+               }
+               val |= AXEN_MEDIUM_PORTSPEED_100;
+               if (link_status & (AXEN_USB_SS | AXEN_USB_HS))
+                       qctrl = &axen_bulk_size[2];
+               else
+                       qctrl = &axen_bulk_size[3];
                break;
        case IFM_10_T:
-               /* doesn't need to be handled */
+               if (!(link_status & AXEN_EPHY_10)) {
+                       printf("%s: wrong phy link (want 10)\n",
+                           sc->axen_dev.dv_xname);
+               }
+               qctrl = &axen_bulk_size[3];
                break;
+       default:
+               printf("%s: unknown uplink bus: 0x%02x\n",
+                   sc->axen_dev.dv_xname, link_status);
+               axen_unlock_mii(sc);
+               goto error;
        }
+       /* XXX change buffer size here */
+
+       /* RX bulk configuration. */
+       DPRINTF(("%s: %s: qtrl bufsize = 0x%x, ifg = 0x%x\n",
+           sc->axen_dev.dv_xname, __func__,
+           qctrl->bufsize, qctrl->ifg));
+       err = axen_cmd(sc, AXEN_CMD_MAC_SET_RXSR, 5, AXEN_RX_BULKIN_QCTRL,
+           qctrl);
+       if (err)
+               goto error;
 
-       DPRINTF(("axen_miibus_statchg: val=0x%x\n", val));
+       DPRINTF(("%s: %s: val=0x%x\n", sc->axen_dev.dv_xname, __func__,val));
        USETW(wval, val);
-       axen_lock_mii(sc);
        err = axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval);
+       if (err)
+               goto error;
+
+       goto done;
+
+error:
+       printf("%s: media change failed (err: 0x%x)\n", sc->axen_dev.dv_xname,
+           err);
+done:
        axen_unlock_mii(sc);
-       if (err) {
-               printf("%s: media change failed\n", sc->axen_dev.dv_xname);
-               return;
-       }
 }
 
 /*
@@ -345,6 +414,8 @@ axen_iff(struct axen_softc *sc)
        u_int8_t                hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
        uWord                   wval;
 
+       DPRINTFN(2,("%s: %s: enter\n", sc->axen_dev.dv_xname,__func__));
+
        if (usbd_is_dying(sc->axen_udev))
                return;
 
@@ -352,27 +423,27 @@ axen_iff(struct axen_softc *sc)
 
        /* Enable receiver, set RX mode */
        axen_lock_mii(sc);
-       axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval);
-       rxmode = UGETW(wval);
-       rxmode &= ~(AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_ACPT_PHY_MCAST |
-                 AXEN_RXCTL_PROMISC);
+       rxmode = AXEN_RXCTL_DROPCRCERR | AXEN_RXCTL_START;
        ifp->if_flags &= ~IFF_ALLMULTI;
 
        /*
-        * Always accept broadcast frames.
         * Always accept frames destined to our station address.
         */
-       rxmode |= AXEN_RXCTL_ACPT_BCAST;
+       rxmode |= AXEN_RXCTL_ACPT_PHY_MCAST;
+       /*
+        * Accept broadcast frames iff interface has IFF_BROADCAST set.
+        */
+       if (ifp->if_flags & IFF_BROADCAST)
+               rxmode |= AXEN_RXCTL_ACPT_BCAST;
 
        if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
                ifp->if_flags |= IFF_ALLMULTI;
-               rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_ACPT_PHY_MCAST;
+               rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST;
                if (ifp->if_flags & IFF_PROMISC)
                        rxmode |= AXEN_RXCTL_PROMISC;
        } else {
-               rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_ACPT_PHY_MCAST;
-
-               /* now program new ones */
+               rxmode |= AXEN_RXCTL_ACPT_MCAST;
+               /* compute multicast filter array */
                ETHER_FIRST_MULTI(step, ac, enm);
                while (enm != NULL) {
                        h = ether_crc32_be(enm->enm_addrlo,
@@ -382,8 +453,15 @@ axen_iff(struct axen_softc *sc)
                }
        }
 
-       axen_cmd(sc, AXEN_CMD_MAC_WRITE_FILTER, 8, AXEN_FILTER_MULTI, 
+       DPRINTFN(5,("%s: %s: hashtbl: %x %x %x %x %x %x %x %x\n",
+           sc->axen_dev.dv_xname,__func__,
+           hashtbl[0], hashtbl[1], hashtbl[2], hashtbl[3],
+           hashtbl[4], hashtbl[5], hashtbl[6], hashtbl[7]));
+       axen_cmd(sc, AXEN_CMD_MAC_WRITE_FILTER, 8, AXEN_FILTER_MULTI,
            (void *)&hashtbl);
+
+       DPRINTFN(2,("%s: %s: rxmode: 0x%x\n",
+           sc->axen_dev.dv_xname,__func__,rxmode));
        USETW(wval, rxmode);
        axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval);
        axen_unlock_mii(sc);
@@ -392,13 +470,16 @@ axen_iff(struct axen_softc *sc)
 void
 axen_reset(struct axen_softc *sc)
 {
+       DPRINTFN(2,("%s: %s: enter\n", sc->axen_dev.dv_xname,__func__));
+
        if (usbd_is_dying(sc->axen_udev))
                return;
-       
-       axen_ax88179_init(sc);
 
        /* Wait a little while for the chip to get its brains in order. */
        DELAY(1000);
+
+       axen_ax88179_init(sc);
+
        return;
 }
 
@@ -408,7 +489,8 @@ axen_ax88179_init(struct axen_softc *sc)
        uWord           wval;
        uByte           val;
        u_int16_t       ctl, temp;
-       struct axen_qctrl qctrl;
+
+       DPRINTFN(2,("%s: %s: enter\n", sc->axen_dev.dv_xname,__func__));
 
        axen_lock_mii(sc);
 
@@ -440,6 +522,10 @@ axen_ax88179_init(struct axen_softc *sc)
        axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val);
        usbd_delay_ms(sc->axen_udev, 100);
 
+       /* RX bulk configuration */
+       axen_cmd(sc, AXEN_CMD_MAC_SET_RXSR, 5, AXEN_RX_BULKIN_QCTRL,
+           &axen_bulk_size[0]);
+
        /* set monitor mode (disable) */
        val = AXEN_MONITOR_NONE;
        axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_MONITOR_MODE, &val);
@@ -466,60 +552,25 @@ axen_ax88179_init(struct axen_softc *sc)
                    sc->axen_dev.dv_xname, ctl);
        }
 
-       /* bulkin queue setting */
-       axen_cmd(sc, AXEN_CMD_MAC_READ, 1, AXEN_USB_UPLINK, &val);
-       switch (val) {
-       case AXEN_USB_FS:
-               DPRINTF(("uplink: USB1.1\n"));
-               qctrl.ctrl      = 0x07;
-               qctrl.timer_low = 0xcc;
-               qctrl.timer_high= 0x4c;
-               qctrl.bufsize   = AXEN_BUFSZ_LS - 1;
-               qctrl.ifg       = 0x08;
-               break;
-       case AXEN_USB_HS:
-               DPRINTF(("uplink: USB2.0\n"));
-               qctrl.ctrl      = 0x07;
-               qctrl.timer_low = 0x02;
-               qctrl.timer_high= 0xa0;
-               qctrl.bufsize   = AXEN_BUFSZ_HS - 1;
-               qctrl.ifg       = 0xff;
-               break;
-       case AXEN_USB_SS:
-               DPRINTF(("uplink: USB3.0\n"));
-               qctrl.ctrl      = 0x07;
-               qctrl.timer_low = 0x4f;
-               qctrl.timer_high= 0x00;
-               qctrl.bufsize   = AXEN_BUFSZ_SS - 1;
-               qctrl.ifg       = 0xff;
-               break;
-       default:
-               printf("%s: unknown uplink bus:0x%02x\n",
-                   sc->axen_dev.dv_xname, val);
-               axen_unlock_mii(sc);
-               return;
-       }
-       axen_cmd(sc, AXEN_CMD_MAC_SET_RXSR, 5, AXEN_RX_BULKIN_QCTRL, &qctrl);
-
-       /* Set MAC address. */
-       axen_cmd(sc, AXEN_CMD_MAC_WRITE_ETHER, ETHER_ADDR_LEN,
-           AXEN_CMD_MAC_NODE_ID, &sc->arpcom.ac_enaddr);
-
        /*
         * set buffer high/low watermark to pause/resume.
         * write 2byte will set high/log simultaneous with AXEN_PAUSE_HIGH.
-        * XXX: what is the best value? OSX driver uses 0x3c-0x4c as LOW-HIGH
-        * watermark parameters.
+        * XXX: what is the best value?
+        * - defaults (datasheet): 0x24-0x42 as LOW-HIGH watermark parameters.
+        * - OSX driver uses 0x3c-0x4c as LOW-HIGH watermark parameters.(?)
+        * - FreeBSD driver uses 0x34-0x52 as LOW-HIGH watermark parameters.
+        * - Linux driver uses 0x34-0x52 as LOW-HIGH watermark parameters.
         */
-       val = 0x34;
+       val = 0x24;
        axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_PAUSE_LOW_WATERMARK, &val);
-       val = 0x52;
+       val = 0x42;
        axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_PAUSE_HIGH_WATERMARK, &val);
 
        /* Set RX/TX configuration. */
-       /* Offloadng enable */
 #ifdef AXEN_TOE
+       /* enable offloading */
        val = AXEN_RXCOE_IPv4 | AXEN_RXCOE_TCPv4 | AXEN_RXCOE_UDPv4 |
+             AXEN_RXCOE_ICMP | AXEN_RXCOE_IGMP |
              AXEN_RXCOE_TCPv6 | AXEN_RXCOE_UDPv6;
 #else
        val = AXEN_RXCOE_OFF;
@@ -528,36 +579,36 @@ axen_ax88179_init(struct axen_softc *sc)
 
 #ifdef AXEN_TOE
        val = AXEN_TXCOE_IPv4 | AXEN_TXCOE_TCPv4 | AXEN_TXCOE_UDPv4 |
+             AXEN_TXCOE_ICMP | AXEN_TXCOE_IGMP |
              AXEN_TXCOE_TCPv6 | AXEN_TXCOE_UDPv6;
 #else
        val = AXEN_TXCOE_OFF;
 #endif
        axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_TX_COE, &val);
 
-       /* Set RX control register */
-       ctl = AXEN_RXCTL_IPE | AXEN_RXCTL_DROPCRCERR | AXEN_RXCTL_AUTOB;
-       ctl |= AXEN_RXCTL_ACPT_PHY_MCAST | AXEN_RXCTL_ACPT_ALL_MCAST;
-       ctl |= AXEN_RXCTL_START;
-       USETW(wval, ctl);
-       axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval);
-
-       /* set monitor mode (enable) */
-       val = AXEN_MONITOR_PMETYPE | AXEN_MONITOR_PMEPOL | AXEN_MONITOR_RWMP;
+       /* set monitor mode (XXX enable) */
+       /* AXEN_MONITOR_PMETYPE | AXEN_MONITOR_PMEPOL | AXEN_MONITOR_RWMP; */
+       val = 0;
        axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_MONITOR_MODE, &val);
+#ifdef AXEN_DEBUG
        axen_cmd(sc, AXEN_CMD_MAC_READ, 1, AXEN_MONITOR_MODE, &val);
        DPRINTF(("axen: Monitor mode = 0x%02x\n", val));
+#endif
 
        /* set medium type */
-       ctl = AXEN_MEDIUM_GIGA | AXEN_MEDIUM_FDX | AXEN_MEDIUM_ALWAYS_ONE |
-             AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN;
-       ctl |= AXEN_MEDIUM_RECV_EN;
+       ctl = AXEN_MEDIUM_GIGA | AXEN_MEDIUM_FDX |
+             AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN |
+             AXEN_MEDIUM_RECV_EN;
        USETW(wval, ctl);
        DPRINTF(("axen: set to medium mode: 0x%04x\n", UGETW(wval)));
        axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval);
-       usbd_delay_ms(sc->axen_udev, 100);
 
+#ifdef AXEN_DEBUG
+       usbd_delay_ms(sc->axen_udev, 100);
        axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_MEDIUM_STATUS, &wval);
        DPRINTF(("axen: current medium mode: 0x%04x\n", UGETW(wval)));
+#endif
+
        axen_unlock_mii(sc);
 
 #if 0 /* XXX: TBD.... */
@@ -571,7 +622,16 @@ axen_ax88179_init(struct axen_softc *sc)
            0x002c);
 #endif
 
-#if 1 /* XXX: phy hack ? */
+#if 1 /* disable eee */
+       axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno,
+           AXEN_GMII_PHY_PAGE_SELECT, AXEN_GMII_PHY_PGSEL_PAGE3);
+       axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno,
+           AXEN_MII_PHYADDR, 0x3246);
+       axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno,
+           AXEN_GMII_PHY_PAGE_SELECT, AXEN_GMII_PHY_PGSEL_PAGE0);
+#endif
+
+#if 0 /* XXX: phy hack ? */
        axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, 0x1F, 0x0005);
        axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, 0x0C, 0x0000);
        val = axen_miibus_readreg(&sc->axen_dev, sc->axen_phyno, 0x0001);
@@ -606,6 +666,8 @@ axen_attach(struct device *parent, struc
        struct ifnet            *ifp;
        int                      i, s;
 
+       DPRINTFN(2,("%s: %s: enter\n", sc->axen_dev.dv_xname,__func__));
+
        sc->axen_unit = self->dv_unit; /*device_get_unit(self);*/
        sc->axen_udev = uaa->device;
        sc->axen_iface = uaa->iface;
@@ -622,22 +684,23 @@ axen_attach(struct device *parent, struc
 
        id = usbd_get_interface_descriptor(sc->axen_iface);
 
-       /* decide on what our bufsize will be */
+       /*
+        * our bufsize is determined by the usb speed and link speed
+        * so set it to the biggest buffer (slowest speed) available
+        * this will be updated once the link state changes
+        */
        switch (sc->axen_udev->speed) {
        case USB_SPEED_FULL:
-               sc->axen_bufsz = AXEN_BUFSZ_LS * 1024; 
-               break;
        case USB_SPEED_HIGH:
-               sc->axen_bufsz = AXEN_BUFSZ_HS * 1024; 
-               break;
        case USB_SPEED_SUPER:
-               sc->axen_bufsz = AXEN_BUFSZ_SS * 1024; 
+               /* linux adds 2 to the buffer size (why?) */
+               sc->axen_bufsz = (AXEN_BUFSZ_MAX + 2) * 1024;
                break;
        default:
                printf("%s: not supported usb bus type", sc->axen_dev.dv_xname);
                return;
        }
-               
+
        /* Find endpoints. */
        for (i = 0; i < id->bNumEndpoints; i++) {
                ed = usbd_interface2endpoint_descriptor(sc->axen_iface, i);
@@ -733,6 +796,8 @@ axen_detach(struct device *self, int fla
        struct axen_softc       *sc = (struct axen_softc *)self;
        int                     s;
        struct ifnet            *ifp = GET_IFP(sc);
+       uWord                   wval;
+       u_int16_t               ctl;
 
        DPRINTFN(2,("%s: %s: enter\n", sc->axen_dev.dv_xname, __func__));
 
@@ -760,9 +825,26 @@ axen_detach(struct device *self, int fla
                usb_detach_wait(&sc->axen_dev);
        }
 
-       if (ifp->if_flags & IFF_RUNNING)
+       if (ifp->if_flags & IFF_RUNNING) {
                axen_stop(sc);
 
+               /* force bulk-in to return a zero-length USB packet */
+               axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_PHYPWR_RSTCTL, &wval);
+               ctl = UGETW(wval);
+               ctl |= AXEN_PHYPWR_RSTCTL_BZ | AXEN_PHYPWR_RSTCTL_IPRL;
+               ctl &= ~AXEN_PHYPWR_RSTCTL_BZ_AUTOCLEAR_DIS;
+               USETW(wval, ctl);
+               axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval);
+
+               /* set clock to zero */
+               axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, 0);
+
+               /* disable MAC */
+               ctl = AXEN_RXCTL_STOP;
+               USETW(wval, ctl);
+               axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval);
+       }
+
        mii_detach(&sc->axen_mii, MII_PHY_ANY, MII_OFFSET_ANY);
        ifmedia_delete_instance(&sc->axen_mii.mii_media, IFM_INST_ANY);
        if (ifp->if_softc != NULL) {
@@ -788,16 +870,21 @@ axen_detach(struct device *self, int fla
 }
 
 struct mbuf *
-axen_newbuf(void)
+axen_newbuf(struct axen_softc *sc)
 {
        struct mbuf *m;
 
        MGETHDR(m, M_DONTWAIT, MT_DATA);
-       if (m == NULL)
+       if (m == NULL) {
+               printf("%s: could not allocate mbuf\n",
+                   sc->axen_dev.dv_xname);
                return NULL;
+       }
 
        MCLGET(m, M_DONTWAIT);
        if (!(m->m_flags & M_EXT)) {
+               printf("%s: could not allocate mbuf cluster\n",
+                   sc->axen_dev.dv_xname);
                m_freem(m);
                return NULL;
        }
@@ -815,7 +902,8 @@ axen_rx_list_init(struct axen_softc *sc)
        struct axen_chain *c;
        int i;
 
-       DPRINTF(("%s: %s: enter\n", sc->axen_dev.dv_xname, __func__));
+       DPRINTF(("%s: %s: %d rx list entries of size %u\n",
+           sc->axen_dev.dv_xname, __func__,AXEN_RX_LIST_CNT,sc->axen_bufsz));
 
        cd = &sc->axen_cdata;
        for (i = 0; i < AXEN_RX_LIST_CNT; i++) {
@@ -846,7 +934,8 @@ axen_tx_list_init(struct axen_softc *sc)
        struct axen_chain *c;
        int i;
 
-       DPRINTF(("%s: %s: enter\n", sc->axen_dev.dv_xname, __func__));
+       DPRINTF(("%s: %s: %d tx list entries of size %u\n",
+           sc->axen_dev.dv_xname, __func__,AXEN_TX_LIST_CNT,sc->axen_bufsz));
 
        cd = &sc->axen_cdata;
        for (i = 0; i < AXEN_TX_LIST_CNT; i++) {
@@ -885,154 +974,244 @@ axen_rxeof(struct usbd_xfer *xfer, void 
        struct mbuf             *m;
        u_int32_t               total_len;
        u_int32_t               rx_hdr, pkt_hdr;
-       u_int32_t               *hdr_p;
+       u_int32_t               *hdr_p, *pkt_end, *hdr_end;
        u_int16_t               hdr_offset, pkt_count;
        size_t                  pkt_len;
-       size_t                  temp;
        int                     s;
+#ifdef AXEN_DEBUG
+       u_int16_t               total_pkt_count;
+#endif
 
        DPRINTFN(10,("%s: %s: enter\n", sc->axen_dev.dv_xname,__func__));
 
-       if (usbd_is_dying(sc->axen_udev))
+       if (usbd_is_dying(sc->axen_udev)) {
+               DPRINTFN(15,("%s: %s: usbd_is_dying\n",
+                   sc->axen_dev.dv_xname,__func__));
                return;
+       }
 
-       if (!(ifp->if_flags & IFF_RUNNING))
+       if (!(ifp->if_flags & IFF_RUNNING)) {
+               DPRINTFN(15,("%s: %s: ! IFF_RUNNING\n",
+                   sc->axen_dev.dv_xname,__func__));
                return;
+       }
 
        if (status != USBD_NORMAL_COMPLETION) {
+               DPRINTFN(9,("%s: %s: ! USBD_NORMAL_COMPLETION: 0x%x\n",
+                   sc->axen_dev.dv_xname,__func__,status));
                if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
                        return;
                if (usbd_ratecheck(&sc->axen_rx_notice)) {
                        printf("%s: usb errors on rx: %s\n",
                            sc->axen_dev.dv_xname, usbd_errstr(status));
                }
-               if (status == USBD_STALLED)
-                       
usbd_clear_endpoint_stall_async(sc->axen_ep[AXEN_ENDPT_RX]);
+               if (status == USBD_STALLED) {
+                       DPRINTFN(9,("%s: %s: USBD_STALLED\n",
+                           sc->axen_dev.dv_xname,__func__));
+                       usbd_clear_endpoint_stall_async(
+                           sc->axen_ep[AXEN_ENDPT_RX]);
+               }
+               DPRINTFN(10,("%s: %s: ! USBD_NORMAL_COMPLETION: done\n",
+                   sc->axen_dev.dv_xname,__func__));
                goto done;
        }
 
        usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
 
-       if (total_len < sizeof(pkt_hdr)) {
+       if (total_len < sizeof(rx_hdr)) {
+               printf("%s: rxeof: too short transfer (len %u)\n",
+                   sc->axen_dev.dv_xname, total_len);
+               ifp->if_ierrors++;
+               goto done;
+       }
+
+       if (total_len > sc->axen_bufsz) {
+               printf("%s: rxeof: too large transfer (len %u)\n",
+                   sc->axen_dev.dv_xname, total_len);
                ifp->if_ierrors++;
                goto done;
        }
 
-       /* 
-        * buffer map
-        * [packet #0]...[packet #n][pkt hdr#0]..[pkt hdr#n][recv_hdr]
-        * each packet has 0xeeee as psuedo header..
+       /*
+        * <--------------------- total_len -------------------->
+        * [pkt #0]...[pkt #n][pkt_hdr #0]...[pkt_hdr #n][rx_hdr]
+        * ^buf               ^pkt_end                   ^hdr_end
+        *
+        * Each RX frame is aligned on 8 bytes boundary. If RXCTL_IPE
+        * bit is set in MAC_RXCTL register, there would be 2
+        * padding bytes and 6 dummy bytes(as the padding also should
+        * be aligned on 8 bytes boundary) for each RX frame to align
+        * IP header on 32bits boundary. We don't set RXCTL_IPE bit
+        * of MAC_RXCTL register, so there should be no padding bytes
+        * which simplifies RX logic a lot.
         */
-       hdr_p = (u_int32_t *)(buf + total_len - sizeof(u_int32_t));
-       rx_hdr = letoh32(*hdr_p);
+
+       hdr_end = (u_int32_t *)(buf + total_len - sizeof(rx_hdr));
+       rx_hdr = le32toh(*hdr_end);
        hdr_offset = (u_int16_t)(rx_hdr >> 16);
        pkt_count  = (u_int16_t)(rx_hdr & 0xffff);
 
-       if (total_len > sc->axen_bufsz) {
-               printf("%s: rxeof: too large transfer\n",
-                   sc->axen_dev.dv_xname);
-               goto done;
-       }
+#ifdef AXEN_DEBUG
+       total_pkt_count = pkt_count;
+#endif
 
        /* sanity check */
-       if (hdr_offset > total_len) {
+       if (hdr_offset > total_len - sizeof(rx_hdr)) {
+               DPRINTFN(7,("%s: %s: hdr_offset (%u) > total_len (%u)"
+                   " - sizeof(pkt_hdr) (%lu)\n",
+                   sc->axen_dev.dv_xname,__func__,hdr_offset,total_len,
+                   sizeof(rx_hdr)));
                ifp->if_ierrors++;
                goto done;
        }
 
        /* point first packet header */
-       hdr_p = (u_int32_t*)(buf + hdr_offset);
-
-       /*
-        * ax88179 will pack multiple ip packet to a USB transaction.
-        * process all of packets in the buffer
-        */
+       hdr_p = pkt_end = (u_int32_t *)(buf + hdr_offset);
 
-#if 1 /* XXX: paranoiac check. need to remove later */
-#define AXEN_MAX_PACKED_PACKET 200 
+#ifdef AXEN_DEBUG
+#define AXEN_MAX_PACKED_PACKET 200
        if (pkt_count > AXEN_MAX_PACKED_PACKET) {
-               DPRINTF(("Too many packets (%d) in a transaction, discard.\n", 
+               DPRINTF(("Too many packets (%d) in a transaction, discard.\n",
                    pkt_count));
+               ifp->if_ierrors += pkt_count;
                goto done;
        }
 #endif
-
-       do {
-               if ((buf[0] != 0xee) || (buf[1] != 0xee)){
-                       printf("%s: invalid buffer(pkt#%d), continue\n",
-                           sc->axen_dev.dv_xname, pkt_count);
-                       ifp->if_ierrors += pkt_count;
-                       goto done;
+       /*
+        * ax88179 will pack multiple ip packet to a USB transaction.
+        * process all of packets in the buffer
+        */
+       DPRINTFN(10,("%s: %s: pkt_count = %u\n",
+           sc->axen_dev.dv_xname,__func__,pkt_count));
+       while(pkt_count--) {
+               /* verify the header offset */
+               if (hdr_p >= hdr_end) {
+                       DPRINTF(("%s: %s: end of packet headers(pkt#%d)\n",
+                           sc->axen_dev.dv_xname,__func__,pkt_count));
+                       ifp->if_ierrors += pkt_count + 1;
+                       goto input;
                }
 
                pkt_hdr = letoh32(*hdr_p);
                pkt_len = (pkt_hdr >> 16) & 0x1fff;
 
                DPRINTFN(10,("rxeof: packet#%d, pkt_hdr 0x%08x, pkt_len %zu\n",
-                  pkt_count, pkt_hdr, pkt_len));
+                   pkt_count, pkt_hdr, pkt_len));
 
-               if ((pkt_hdr & AXEN_RXHDR_CRC_ERR) ||
-                   (pkt_hdr & AXEN_RXHDR_DROP_ERR)) {
-                       ifp->if_ierrors++;
-                       /* move to next pkt header */
-                       DPRINTF(("crc err(pkt#%d)\n", pkt_count));
-                       goto nextpkt;
+               /* verify the data length */
+               if ((void *)buf + pkt_len > (void *)hdr_p) {
+                       DPRINTF(("%s: %s: end of packet data(pkt#%d)\n",
+                           sc->axen_dev.dv_xname,__func__,pkt_count));
+                       ifp->if_ierrors += pkt_count + 1;
+                       goto input;
                }
 
-               /* process each packet */
-               /* allocate mbuf */
-               m = axen_newbuf();
-               if (m == NULL) {
+               if (pkt_len > MCLBYTES || pkt_len < ETHER_MIN_LEN) {
+                       printf("%s: invalid pkt_len %zu\n",
+                           sc->axen_dev.dv_xname,pkt_len);
                        ifp->if_ierrors++;
                        goto nextpkt;
                }
 
-               /* skip pseudo header (2byte) and trailer padding (4Byte) */
-               m->m_pkthdr.len = m->m_len = pkt_len - 6;
+               if (AXEN_RXHDR_ERR(pkt_hdr)) {
+#ifdef AXEN_DEBUG
+                       DPRINTFN(7,("%s: %s: err(pkt#%d) pkt_hdr 0x%08x,",
+                           sc->axen_dev.dv_xname,__func__,pkt_count,pkt_hdr));
+                       if (pkt_hdr & AXEN_RXHDR_DROP_ERR)
+                               DPRINTFN(7,(" drop"));
+                       if (pkt_hdr & AXEN_RXHDR_MII_ERR)
+                               DPRINTFN(7,(" mii"));
+                       if (pkt_hdr & AXEN_RXHDR_CRC_ERR)
+                               DPRINTFN(7,(" crc"));
+                       DPRINTFN(7,("\n"));
+#endif
+                       ifp->if_ierrors++;
+                       /* move to next pkt header */
+                       goto nextpkt;
+               }
 
 #ifdef AXEN_TOE
                /* cheksum err */
-               if ((pkt_hdr & AXEN_RXHDR_L3CSUM_ERR) || 
+               if ((pkt_hdr & AXEN_RXHDR_L3CSUM_ERR) ||
                    (pkt_hdr & AXEN_RXHDR_L4CSUM_ERR)) {
                        printf("%s: checksum err (pkt#%d)\n",
                            sc->axen_dev.dv_xname, pkt_count);
                        goto nextpkt;
-               } else {
-                       m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
                }
+#endif
 
-               int l4_type;
-               l4_type = (pkt_hdr & AXEN_RXHDR_L4_TYPE_MASK) >> 
-                   AXEN_RXHDR_L4_TYPE_OFFSET;
+               /* process each packet */
+               /* allocate mbuf */
+               m = m_devget(buf, pkt_len, ETHER_ALIGN); /* axen_newbuf(sc) */
+               if (m == NULL) {
+#ifdef AXEN_DEBUG
+                       DPRINTF(("%s: could not allocate rx mbuf "
+                           "(%d total, %d remaining)\n",
+                           sc->axen_dev.dv_xname,
+                           total_pkt_count, pkt_count + 1));
+#endif
+                       ifp->if_ierrors += pkt_count + 1;
+                       goto input;
+               }
+
+#if 0 /* if using axen_newbuf() instead of m_devget() */
+               m->m_pkthdr.len = m->m_len = pkt_len;
+#endif
+
+#if 0 /* ifdef AXEN_TOE */
+               switch ((pkt_hdr & AXEN_RXHDR_L3_TYPE_MASK) >>
+                   AXEN_RXHDR_L3_TYPE_OFFSET) {
+               case AXEN_RXHDR_L3_TYPE_IPV4:
+                       m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
+                       break;
+               case AXEN_RXHDR_L3_TYPE_IPV6:
+                       /* XXX IPV6 equivalent of M_IPV4_CSUM_IN_OK? */
+                       break;
+               default:
+                       /* do we need to set something here? */
+                       break;
+               }
 
-               if ((l4_type == AXEN_RXHDR_L4_TYPE_TCP) ||
-                   (l4_type == AXEN_RXHDR_L4_TYPE_UDP)) 
-                       m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK |
-                           M_UDP_CSUM_IN_OK;
+               switch ((pkt_hdr & AXEN_RXHDR_L4_TYPE_MASK) >>
+                   AXEN_RXHDR_L4_TYPE_OFFSET) {
+               case AXEN_RXHDR_L4_TYPE_ICMP:
+                       m->m_pkthdr.csum_flags |= M_ICMP_CSUM_IN_OK;
+                       break;
+               case AXEN_RXHDR_L4_TYPE_UDP:
+                       m->m_pkthdr.csum_flags |= M_UDP_CSUM_IN_OK;
+                       break;
+               case AXEN_RXHDR_L4_TYPE_TCP:
+                       m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK;
+                       break;
+               default:
+                       /* do we need to set something here? */
+                       break;
+               }
 #endif
 
-               memcpy(mtod(m, char *), buf + 2, pkt_len - 6);
+#if 0 /* if using axen_newbuf() instead of m_devget() */
+               memcpy(mtod(m, char *), buf, pkt_len);
+#endif
 
                ml_enqueue(&ml, m);
 
 nextpkt:
                /*
-                * prepare next packet 
+                * prepare next packet
                 * as each packet will be aligned 8byte boundary,
                 * need to fix up the start point of the buffer.
                 */
-               temp = ((pkt_len + 7) & 0xfff8);
-               buf = buf + temp;
+               buf += (pkt_len + 7) & 0xfff8;
                hdr_p++;
-               pkt_count--;
-       } while( pkt_count > 0);
+       }
 
-done:
-       /* push the packet up */
+input:
+       /* push the packets up */
        s = splnet();
        if_input(ifp, &ml);
        splx(s);
 
+done:
        /* clear buffer for next transaction */
        memset(c->axen_buf, 0, sc->axen_bufsz);
 
@@ -1043,7 +1222,7 @@ done:
            USBD_NO_TIMEOUT, axen_rxeof);
        usbd_transfer(xfer);
 
-       DPRINTFN(10,("%s: %s: start rx\n", sc->axen_dev.dv_xname, __func__));
+       DPRINTFN(10,("%s: %s: end rx\n", sc->axen_dev.dv_xname, __func__));
 }
 
 /*
@@ -1076,7 +1255,8 @@ axen_txeof(struct usbd_xfer *xfer, void 
                printf("axen%d: usb error on tx: %s\n", sc->axen_unit,
                    usbd_errstr(status));
                if (status == USBD_STALLED)
-                       
usbd_clear_endpoint_stall_async(sc->axen_ep[AXEN_ENDPT_TX]);
+                       usbd_clear_endpoint_stall_async(
+                           sc->axen_ep[AXEN_ENDPT_TX]);
                splx(s);
                return;
        }
@@ -1190,6 +1370,8 @@ axen_encap(struct axen_softc *sc, struct
        /* Transmit */
        err = usbd_transfer(c->axen_xfer);
        if (err != USBD_IN_PROGRESS) {
+               DPRINTFN(2,("%s: %s: usbd_transfer err = %d\n",
+                   sc->axen_dev.dv_xname,__func__, err));
                axen_stop(sc);
                return EIO;
        }
@@ -1249,21 +1431,33 @@ axen_init(void *xsc)
        struct axen_chain       *c;
        usbd_status             err;
        int                     i, s;
-       uByte                   bval;
        uWord                   wval;
        uint16_t                rxmode;
 
+       DPRINTFN(2,("%s: %s: enter\n", sc->axen_dev.dv_xname,__func__));
+
        s = splnet();
 
        /*
         * Cancel pending I/O and free all RX/TX buffers.
         */
+       axen_stop(sc);
        axen_reset(sc);
 
-       /* XXX: ? */
-       bval = 0x01;
+       /* Set MAC address. */
+       axen_cmd(sc, AXEN_CMD_MAC_WRITE_ETHER, ETHER_ADDR_LEN,
+           AXEN_CMD_MAC_NODE_ID, &sc->arpcom.ac_enaddr);
+
+       /* Program promiscuous mode and multicast filters. */
+       axen_iff(sc);
+
+       /* Enable receiver, set RX mode */
        axen_lock_mii(sc);
-       axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_UNK_28, &bval);
+       axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval);
+       rxmode = UGETW(wval);
+       rxmode |= AXEN_RXCTL_START;
+       USETW(wval, rxmode);
+       axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval);
        axen_unlock_mii(sc);
 
        /* Init RX ring. */
@@ -1280,18 +1474,6 @@ axen_init(void *xsc)
                return;
        }
 
-       /* Program promiscuous mode and multicast filters. */
-       axen_iff(sc);
-
-       /* Enable receiver, set RX mode */
-       axen_lock_mii(sc);
-       axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval);
-       rxmode = UGETW(wval);
-       rxmode |= AXEN_RXCTL_START;
-       USETW(wval, rxmode);
-       axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval);
-       axen_unlock_mii(sc);
-
        /* Open RX and TX pipes. */
        err = usbd_open_pipe(sc->axen_iface, sc->axen_ed[AXEN_ENDPT_RX],
            USBD_EXCLUSIVE_USE, &sc->axen_ep[AXEN_ENDPT_RX]);
@@ -1396,7 +1578,7 @@ axen_watchdog(struct ifnet *ifp)
        sc = ifp->if_softc;
 
        ifp->if_oerrors++;
-       printf("axen%d: watchdog timeout\n", sc->axen_unit);
+       printf("%s: watchdog timeout\n", sc->axen_dev.dv_xname);
 
        s = splusb();
        c = &sc->axen_cdata.axen_tx_chain[0];
@@ -1418,8 +1600,10 @@ axen_stop(struct axen_softc *sc)
        usbd_status             err;
        struct ifnet            *ifp;
        int                     i;
+       u_int16_t               ctl;
+       uWord                   wval;
 
-       axen_reset(sc);
+       DPRINTFN(2,("%s: %s: enter\n", sc->axen_dev.dv_xname,__func__));
 
        ifp = &sc->arpcom.ac_if;
        ifp->if_timer = 0;
@@ -1427,6 +1611,13 @@ axen_stop(struct axen_softc *sc)
        ifq_clr_oactive(&ifp->if_snd);
 
        timeout_del(&sc->axen_stat_ch);
+
+       /* disable receive */
+       axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_MEDIUM_STATUS, &wval);
+       ctl = UGETW(wval);
+       ctl &= ~AXEN_MEDIUM_RECV_EN;
+       USETW(wval, ctl);
+       axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval);
 
        /* Stop transfers. */
        if (sc->axen_ep[AXEN_ENDPT_RX] != NULL) {
Index: dev/usb/if_axenreg.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_axenreg.h,v
retrieving revision 1.6
diff -u -p -r1.6 if_axenreg.h
--- dev/usb/if_axenreg.h        14 Sep 2016 12:41:09 -0000      1.6
+++ dev/usb/if_axenreg.h        12 Feb 2019 18:26:48 -0000
@@ -12,9 +12,10 @@
 #define AXEN_PHY_ID            0x0003
 #define AXEN_MCAST_FILTER_SIZE 8
 /* unit: KB */
-#define AXEN_BUFSZ_LS          8
-#define AXEN_BUFSZ_HS          16
-#define AXEN_BUFSZ_SS          24
+#define AXEN_BUFSZ_LS          0x18
+#define AXEN_BUFSZ_HS          0x16
+#define AXEN_BUFSZ_SS          0x12
+#define AXEN_BUFSZ_MAX         AXEN_BUFSZ_LS
 
 #define AXEN_REV_UA1           0
 #define AXEN_REV_UA2           1
@@ -26,8 +27,8 @@
  *                     |    |     ++-----L3_type (1:ipv4, 0/2:ipv6)
  *        pkt_len(13)  |    |     ||+ ++-L4_type(0: icmp, 1: UDP, 4: TCP)
  * |765|43210 76543210|7654 3210 7654 3210|
- *  ||+-crc_err              |+-L4_err |+-L4_CSUM_ERR
- *  |+-mii_err               +--L3_err +--L3_CSUM_ERR
+ *  ||+-crc_err               |+-L4_err |+-L4_CSUM_ERR
+ *  |+-mii_err                +--L3_err +--L3_CSUM_ERR
  *  +-drop_err
  *
  * ex) pkt_hdr 0x00680820
@@ -62,6 +63,10 @@
 #define AXEN_RXHDR_L3CSUM_ERR  (1U << 1)
 #define AXEN_RXHDR_L4CSUM_ERR  (1U << 0)
 
+#define        AXEN_RXHDR_ERR(x)       ((x) & (AXEN_RXHDR_DROP_ERR | \
+                                       AXEN_RXHDR_MII_ERR | \
+                                       AXEN_RXHDR_CRC_ERR))
+
 /* L4 packet type (3bit) */
 #define AXEN_RXHDR_L4_TYPE_MASK        0x0000001c
 #define AXEN_RXHDR_L4_TYPE_OFFSET      2
@@ -70,7 +75,7 @@
 #define   AXEN_RXHDR_L4_TYPE_TCP       0x4
 
 /* L3 packet type (2bit) */
-#define AXEN_RXHDR_L3_TYPE_MASK        0x00000600
+#define AXEN_RXHDR_L3_TYPE_MASK        0x00000060
 #define AXEN_RXHDR_L3_TYPE_OFFSET      5
 #define   AXEN_RXHDR_L3_TYPE_UNDEF     0x0
 #define   AXEN_RXHDR_L3_TYPE_IPV4      0x1
@@ -88,10 +93,13 @@
 #define AXEN_CMD_MAC_READ                      0x1001
 #define AXEN_CMD_MAC_WRITE                     0x1101
 
-#define   AXEN_USB_UPLINK                      0x02
+#define   AXEN_PHYSICAL_LINK_STATUS            0x02
 #define     AXEN_USB_FS                                  0x01
 #define     AXEN_USB_HS                                  0x02
 #define     AXEN_USB_SS                                  0x04
+#define     AXEN_EPHY_10                         0x10
+#define     AXEN_EPHY_100                        0x20
+#define     AXEN_EPHY_1000                       0x40
 #define   AXEN_GENERAL_STATUS                  0x03
 #define     AXEN_GENERAL_STATUS_MASK             0x4
 #define     AXEN_REV0                            0x0
@@ -149,9 +157,9 @@
 #define     AXEN_RXCTL_STOP                      0x0000
 #define     AXEN_RXCTL_PROMISC                   0x0001
 #define     AXEN_RXCTL_ACPT_ALL_MCAST            0x0002
-#define     AXEN_RXCTL_HA8B                      0x0004                 
-#define     AXEN_RXCTL_AUTOB                     0x0008
-#define     AXEN_RXCTL_ACPT_BCAST                0x0010
+#define     AXEN_RXCTL_AUTOPAD_BNDRY             0x0004
+#define     AXEN_RXCTL_ACPT_BCAST                0x0008
+#define     AXEN_RXCTL_ACPT_MCAST                0x0010
 #define     AXEN_RXCTL_ACPT_PHY_MCAST            0x0020
 #define     AXEN_RXCTL_START                     0x0080
 #define     AXEN_RXCTL_DROPCRCERR                0x0100
@@ -162,16 +170,27 @@
 #define            AXEN_MEDIUM_GIGA                      0x0001
 #define            AXEN_MEDIUM_FDX                       0x0002
 #define            AXEN_MEDIUM_ALWAYS_ONE                0x0004
-#define            AXEN_MEDIUM_EN_125MHZ                 0x0008
+#define            AXEN_MEDIUM_ALWAYS_ZERO1              0x0008
 #define            AXEN_MEDIUM_RXFLOW_CTRL_EN            0x0010
 #define            AXEN_MEDIUM_TXFLOW_CTRL_EN            0x0020
+#define            AXEN_MEDIUM_JUMBOFRAME_EN             0x0040
+#define            AXEN_MEDIUM_PAUSEFRAME_LT_ONLY_EN     0x0080
 #define            AXEN_MEDIUM_RECV_EN                   0x0100
-#define            AXEN_MEDIUM_PS                        0x0200
-#define            AXEN_MEDIUM_JUMBO_EN                  0x8040
+#define            AXEN_MEDIUM_PORTSPEED_100             0x0200
+#define            AXEN_MEDIUM_ALWAYS_ZERO2              0x0400
+#define            AXEN_MEDIUM_STOP_BACKPRESSURE         0x0800
+#define            AXEN_MEDIUM_SUPERMAC                  0x1000
+#define            AXEN_MEDIUM_ALWAYS_ZERO3              0x2000
+#define            AXEN_MEDIUM_ALWAYS_ZERO4              0x4000
+#define            AXEN_MEDIUM_ALWAYS_ZERO5              0x8000
+#define            AXEN_MEDIUM_JUMBO_EN \
+               (AXEN_MEDIUM_JUMBOFRAME_EN | AXEN_MEDIUM_STOP_BACKPRESSURE)
 #define   AXEN_PHYPWR_RSTCTL                   0x26
+#define     AXEN_PHYPWR_RSTCTL_BZ_AUTOCLEAR_DIS          0x0004
 #define     AXEN_PHYPWR_RSTCTL_BZ                0x0010
 #define     AXEN_PHYPWR_RSTCTL_IPRL              0x0020
 #define     AXEN_PHYPWR_RSTCTL_AUTODETACH        0x1000
+#define     AXEN_PHYPWR_RSTCTL_WOL_LOWPOWER      0x8000
 
 #define AXEN_CMD_EEPROM_READ                   0x2004
 #define            AXEN_EEPROM_STAT                      0x43
@@ -212,6 +231,20 @@
 #define AXEN_RX_LIST_CNT               1
 #define AXEN_TX_LIST_CNT               1
 
+
+/* ---GMII--- */
+#define AXEN_GMII_PHYPAGE                      0x1e
+#define AXEN_GMII_PHY_PAGE_SELECT              0x1f
+#define AXEN_GMII_PHY_PGSEL_EXT                          0x0007
+#define AXEN_GMII_PHY_PGSEL_PAGE0                0x0000
+#define AXEN_GMII_PHY_PGSEL_PAGE3                0x0003
+#define AXEN_GMII_PHY_PGSEL_PAGE5                0x0005
+#define AXEN_GMII_PHY_PGSEL_PAGE5                0x0005
+
+#define AXEN_MII_PHYADDR                       0x19
+#define AXEN_MII_PHYADDR_EEE_DIS                 0x3246
+#define AXEN_MII_PHYADDR_EEE_EN1                 0x3247
+#define AXEN_MII_PHYADDR_EEE_EN2                 0x0680
 
 /*
  * The interrupt endpoint is currently unused

Reply via email to