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