try to align attach/detach/init/stop routines with what freebsd and linux are doing.
one important part of this diff is disabling Energy Efficient Ethernet (EEE) and setting the low/high watermarks. this reduces the amount of RXHDR_DROP_ERRs, but could maybe be tweaked (improved). --- dev/usb/if_axen.c | 145 +++++++++++++++++++++++++++---------------- dev/usb/if_axenreg.h | 20 +++++- 2 files changed, 110 insertions(+), 55 deletions(-) diff --git a/dev/usb/if_axen.c b/dev/usb/if_axen.c index 088f40f..817cad8 100644 --- a/dev/usb/if_axen.c +++ b/dev/usb/if_axen.c @@ -433,13 +433,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; } @@ -510,63 +513,65 @@ axen_ax88179_init(struct axen_softc *sc) sc->axen_dev.dv_xname, ctl); } - /* 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 - val = AXEN_RXCOE_IPv4 | AXEN_RXCOE_TCPv4 | AXEN_RXCOE_UDPv4 | - AXEN_RXCOE_TCPv6 | AXEN_RXCOE_UDPv6; + /* enable offloading */ + val = AXEN_RXCOE_IPv4 | + AXEN_RXCOE_TCPv4 | AXEN_RXCOE_UDPv4 | AXEN_RXCOE_ICMPv4 | + AXEN_RXCOE_IGMP | + AXEN_RXCOE_TCPv6 | AXEN_RXCOE_UDPv6 | AXEN_RXCOE_ICMPv6; #else val = AXEN_RXCOE_OFF; #endif axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_RX_COE, &val); #ifdef AXEN_TOE - val = AXEN_TXCOE_IPv4 | AXEN_TXCOE_TCPv4 | AXEN_TXCOE_UDPv4 | - AXEN_TXCOE_TCPv6 | AXEN_TXCOE_UDPv6; + val = AXEN_TXCOE_IPv4 | + AXEN_TXCOE_TCPv4 | AXEN_TXCOE_UDPv4 |AXEN_TXCOE_ICMPv4 | + AXEN_TXCOE_IGMP | + AXEN_TXCOE_TCPv6 | AXEN_TXCOE_UDPv6 | AXEN_TXCOE_ICMPv6; #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_DROPCRCERR; - 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.... */ @@ -580,7 +585,15 @@ axen_ax88179_init(struct axen_softc *sc) 0x002c); #endif -#if 1 /* XXX: phy hack ? */ + /* 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); + +#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); @@ -631,16 +644,17 @@ axen_attach(struct device *parent, struct device *self, void *aux) 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); @@ -742,6 +756,8 @@ axen_detach(struct device *self, int flags) 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__)); @@ -769,9 +785,26 @@ axen_detach(struct device *self, int flags) 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) { @@ -1269,7 +1302,6 @@ axen_init(void *xsc) struct axen_chain *c; usbd_status err; int i, s; - uByte bval; uWord wval; uint16_t rxmode; @@ -1278,12 +1310,23 @@ axen_init(void *xsc) /* * 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. */ @@ -1300,18 +1343,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]); @@ -1438,8 +1469,9 @@ axen_stop(struct axen_softc *sc) usbd_status err; struct ifnet *ifp; int i; + u_int16_t ctl; + uWord wval; - axen_reset(sc); ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; @@ -1448,6 +1480,13 @@ axen_stop(struct axen_softc *sc) 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) { usbd_abort_pipe(sc->axen_ep[AXEN_ENDPT_RX]); diff --git a/dev/usb/if_axenreg.h b/dev/usb/if_axenreg.h index 766c89e..bc594a0 100644 --- a/dev/usb/if_axenreg.h +++ b/dev/usb/if_axenreg.h @@ -15,6 +15,7 @@ #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 @@ -129,7 +130,7 @@ #define AXEN_RXCOE_IPv4 0x01 #define AXEN_RXCOE_TCPv4 0x02 #define AXEN_RXCOE_UDPv4 0x04 -#define AXEN_RXCOE_ICMP 0x08 +#define AXEN_RXCOE_ICMPv4 0x08 #define AXEN_RXCOE_IGMP 0x10 #define AXEN_RXCOE_TCPv6 0x20 #define AXEN_RXCOE_UDPv6 0x40 @@ -139,7 +140,7 @@ #define AXEN_TXCOE_IPv4 0x01 #define AXEN_TXCOE_TCPv4 0x02 #define AXEN_TXCOE_UDPv4 0x04 -#define AXEN_TXCOE_ICMP 0x08 +#define AXEN_TXCOE_ICMPv4 0x08 #define AXEN_TXCOE_IGMP 0x10 #define AXEN_TXCOE_TCPv6 0x20 #define AXEN_TXCOE_UDPv6 0x40 @@ -176,6 +177,7 @@ #define AXEN_MEDIUM_PORTSPEED_100 0x0200 #define AXEN_MEDIUM_JUMBO_EN 0x8040 #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 @@ -220,6 +222,20 @@ #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 * by the ASIX part. -- 2.20.1