Hi, On 2018/08/18 07:37, Denis wrote: > Hi, > > checksum err (pkt#1) appears in dmesg output only. > > Right now (after 43 hours of testing) there are 15 rows with checksum > err (pkt#1) message. > > Previously, that network segment was connected by em(4), fxp(4), xl(4) > drivers w/o any issues. So the error appears for axen(4) driver > exclusively. It seems axen(4) related issue.
ierrs of netstat -in of these interfaces are 0? I added printf more informations about checksum error, and attached as axen4.diff. If you are interested in the packet body, you can see hexdump of the error packet by changing #if 0 to #if 1 in axen_rxeof(). Note that the hexdump includes MAC addresses and IP addresses. BTW original axen code leaks mbuf if checksum errors occurs. You can see mbuf usage is increasing when cksum error occur. This patch will fix that bug, too. > > Denis > > On 8/17/2018 6:26 PM, sc dying wrote: >> Hi, >> >> On 2018/08/17 07:40, Denis wrote: >>> Hi, >>> >>> 24 hour full load testing shows positive results. >> >> Good news. >> >>> >>> After axen3.diff has been implemented there is no TX/RX error present at >>> all. But 'checksum err (pkt#1)' appears repeatedly like this: >>> >>> ... >>> checksum err (pkt#1) >>> checksum err (pkt#1) >>> checksum err (pkt#1) >>> ... >>> >>> You're right DHCP client is working for axen0: >>> >>> # cat /etc/hostname.axen0 >>> dhcp lladdr yy.yy.yy.yy.yy >>> >>> What can cause 'checksum err (pkt#1)' for axen? >> >> It might be another bug of axen(4), or someone on your ethernet segment >> really sends bogus packets. >> In latter case I don't think axen should report each error to the console. >> >>> >>> Denis >>> >>> On 8/15/2018 2:29 AM, sc.dy...@gmail.com wrote: >>>> Hi, >>>> >>>> On 2018/08/14 08:19, Denis wrote: >>>>> I have 6.3 kernel compiled with option XHCI_debug and axen2.diff >>>>> implemented. >>>>> >>>>> I'm using lladdr option for /etc/hostname.axen0 to have the same IP addr >>>>> each session for different Ehternet adapters. >>>>> >>>>> Here is debug output when axen is connected: >>>> >>>> Thank you for sending report. >>>> >>>> It looks someone (maybe DHCP) makes the interface down and up repeatedly. >>>> That causes TXERR (transaction error) on RX pipe. >>>> I guess there is something inconsistent between the state of xhci and >>>> the device. xhci spec 1.1 sec 4.3.5 requires the driver shall do >>>> set_config and configure endpoint. >>>> >>>> I added set_config part to axen2.diff and attached as axen3.diff. >>>> Can you try attached axen3.diff? >>>> >>>> Thanks. >>>> >
--- sys/dev/usb/if_axen.c.orig Sun Jan 22 10:17:39 2017 +++ sys/dev/usb/if_axen.c Sat Aug 18 12:16:25 2018 @@ -53,6 +53,7 @@ #include <dev/usb/usbdi_util.h> #include <dev/usb/usbdivar.h> #include <dev/usb/usbdevs.h> +#include <dev/usb/usb_mem.h> #include <dev/usb/if_axenreg.h> @@ -121,6 +122,13 @@ void axen_unlock_mii(struct axen_softc *sc); void axen_ax88179_init(struct axen_softc *); +struct axen_qctrl axen_bulk_size[] = { + { 7, 0x4f, 0x00, 0x12, 0xff }, + { 7, 0x20, 0x03, 0x16, 0xff }, + { 7, 0xae, 0x07, 0x18, 0xff }, + { 7, 0xcc, 0x4c, 0x18, 0x08 } +}; + /* Get exclusive access to the MII registers */ void axen_lock_mii(struct axen_softc *sc) @@ -238,6 +246,8 @@ axen_miibus_statchg(struct device *dev) int err; uint16_t val; uWord wval; + uint8_t linkstat = 0; + int qctrl; ifp = GET_IFP(sc); if (mii == NULL || ifp == NULL || @@ -265,27 +275,49 @@ axen_miibus_statchg(struct device *dev) return; val = 0; - if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { val |= AXEN_MEDIUM_FDX; + 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; + } - val |= (AXEN_MEDIUM_RECV_EN | AXEN_MEDIUM_ALWAYS_ONE); - val |= (AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN); + val |= AXEN_MEDIUM_RECV_EN; + /* bulkin queue setting */ + axen_lock_mii(sc); + axen_cmd(sc, AXEN_CMD_MAC_READ, 1, AXEN_USB_UPLINK, &linkstat); + axen_unlock_mii(sc); + switch (IFM_SUBTYPE(mii->mii_media_active)) { case IFM_1000_T: val |= AXEN_MEDIUM_GIGA | AXEN_MEDIUM_EN_125MHZ; + if (linkstat & AXEN_USB_SS) + qctrl = 0; + else if (linkstat & AXEN_USB_HS) + qctrl = 1; + else + qctrl = 3; break; case IFM_100_TX: val |= AXEN_MEDIUM_PS; + if (linkstat & (AXEN_USB_SS | AXEN_USB_HS)) + qctrl = 2; + else + qctrl = 3; break; case IFM_10_T: - /* doesn't need to be handled */ + default: + qctrl = 3; break; } DPRINTF(("axen_miibus_statchg: val=0x%x\n", val)); USETW(wval, val); axen_lock_mii(sc); + axen_cmd(sc, AXEN_CMD_MAC_SET_RXSR, 5, AXEN_RX_BULKIN_QCTRL, + &axen_bulk_size[qctrl]); err = axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval); axen_unlock_mii(sc); if (err) { @@ -408,7 +440,6 @@ axen_ax88179_init(struct axen_softc *sc) uWord wval; uByte val; u_int16_t ctl, temp; - struct axen_qctrl qctrl; axen_lock_mii(sc); @@ -470,34 +501,18 @@ axen_ax88179_init(struct axen_softc *sc) 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("unknown uplink bus:0x%02x\n", 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, @@ -620,22 +635,8 @@ axen_attach(struct device *parent, struct device *self id = usbd_get_interface_descriptor(sc->axen_iface); - /* decide on what our bufsize will be */ - 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; - break; - default: - printf("%s: not supported usb bus type", sc->axen_dev.dv_xname); - return; - } - + sc->axen_bufsz = 64 * 1024; + /* Find endpoints. */ for (i = 0; i < id->bNumEndpoints; i++) { ed = usbd_interface2endpoint_descriptor(sc->axen_iface, i); @@ -708,7 +709,8 @@ axen_attach(struct device *parent, struct device *self mii->mii_flags = MIIF_AUTOTSLEEP; ifmedia_init(&mii->mii_media, 0, axen_ifmedia_upd, axen_ifmedia_sts); - mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0); + mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, + MIIF_DOPAUSE); if (LIST_FIRST(&mii->mii_phys) == NULL) { ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL); @@ -806,6 +808,23 @@ axen_newbuf(void) return m; } +static void * +axen_alloc_buffer(struct usbd_xfer *xfer, u_int32_t size) +{ + struct usbd_bus *bus = xfer->device->bus; + usbd_status err; + +#ifdef DIAGNOSTIC + if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF)) + printf("axen_alloc_buffer: xfer already has a buffer\n"); +#endif + err = usb_allocmem(bus, size, 65536, &xfer->dmabuf); + if (err) + return (NULL); + xfer->rqflags |= URQ_DEV_DMABUF; + return (KERNADDR(&xfer->dmabuf, 0)); +} + int axen_rx_list_init(struct axen_softc *sc) { @@ -825,7 +844,7 @@ axen_rx_list_init(struct axen_softc *sc) c->axen_xfer = usbd_alloc_xfer(sc->axen_udev); if (c->axen_xfer == NULL) return ENOBUFS; - c->axen_buf = usbd_alloc_buffer(c->axen_xfer, + c->axen_buf = axen_alloc_buffer(c->axen_xfer, sc->axen_bufsz); if (c->axen_buf == NULL) { usbd_free_xfer(c->axen_xfer); @@ -856,7 +875,7 @@ axen_tx_list_init(struct axen_softc *sc) c->axen_xfer = usbd_alloc_xfer(sc->axen_udev); if (c->axen_xfer == NULL) return ENOBUFS; - c->axen_buf = usbd_alloc_buffer(c->axen_xfer, + c->axen_buf = axen_alloc_buffer(c->axen_xfer, sc->axen_bufsz); if (c->axen_buf == NULL) { usbd_free_xfer(c->axen_xfer); @@ -886,7 +905,6 @@ axen_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st u_int32_t *hdr_p; u_int16_t hdr_offset, pkt_count; size_t pkt_len; - size_t temp; int s; DPRINTFN(10,("%s: %s: enter\n", sc->axen_dev.dv_xname,__func__)); @@ -912,10 +930,19 @@ axen_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); if (total_len < sizeof(pkt_hdr)) { + printf("%s: rxeof: too short transfer\n", + sc->axen_dev.dv_xname); ifp->if_ierrors++; goto done; } + if (total_len > sc->axen_bufsz) { + printf("%s: rxeof: too large transfer\n", + sc->axen_dev.dv_xname); + ifp->if_ierrors++; + goto done; + } + /* * buffer map * [packet #0]...[packet #n][pkt hdr#0]..[pkt hdr#n][recv_hdr] @@ -926,15 +953,10 @@ axen_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st hdr_offset = (u_int16_t)(rx_hdr >> 16); pkt_count = (u_int16_t)(rx_hdr & 0xffff); - if (total_len > sc->axen_bufsz) { - printf("rxeof: too large transfer\n"); - goto done; - } - /* sanity check */ if (hdr_offset > total_len) { - ifp->if_ierrors++; usbd_delay_ms(sc->axen_udev, 100); + ifp->if_ierrors++; goto done; } @@ -951,11 +973,14 @@ axen_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st if (pkt_count > AXEN_MAX_PACKED_PACKET) { DPRINTF(("Too many packets (%d) in a transaction, discard.\n", pkt_count)); + ifp->if_ierrors++; goto done; } #endif - do { + for (; pkt_count > 0; pkt_count--) { + uint16_t csum_flags = 0; + if ((buf[0] != 0xee) || (buf[1] != 0xee)){ printf("invalid buffer(pkt#%d), continue\n", pkt_count); ifp->if_ierrors += pkt_count; @@ -968,6 +993,13 @@ axen_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st DPRINTFN(10,("rxeof: packet#%d, pkt_hdr 0x%08x, pkt_len %zu\n", pkt_count, pkt_hdr, pkt_len)); + 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; + } + if ((pkt_hdr & AXEN_RXHDR_CRC_ERR) || (pkt_hdr & AXEN_RXHDR_DROP_ERR)) { ifp->if_ierrors++; @@ -976,25 +1008,29 @@ axen_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st goto nextpkt; } - /* process each packet */ - /* allocate mbuf */ - m = axen_newbuf(); - if (m == NULL) { - ifp->if_ierrors++; - goto nextpkt; - } - - /* skip pseudo header (2byte) and trailer padding (4Byte) */ - m->m_pkthdr.len = m->m_len = pkt_len - 6; - #ifdef AXEN_TOE /* cheksum err */ if ((pkt_hdr & AXEN_RXHDR_L3CSUM_ERR) || (pkt_hdr & AXEN_RXHDR_L4CSUM_ERR)) { - printf("checksum err (pkt#%d)\n", pkt_count); + printf("%s: checksum err (pkt#%hu) len %#zx total %#x" + " pkt_hdr %#x\n", sc->axen_dev.dv_xname, + pkt_count, pkt_len, total_len, pkt_hdr); +#if 0 + int i; + for (i = 0; i < min(pkt_len, 2+14+40); i++) { + printf("%02x ", buf[i]); + if (i % 16 == 7) + printf(" "); + if (i % 16 == 15) + printf("\n"); + } + if (i % 16 != 15) + printf("\n"); +#endif + ifp->if_ierrors++; goto nextpkt; } else { - m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK; + csum_flags |= M_IPV4_CSUM_IN_OK; } int l4_type; @@ -1003,12 +1039,23 @@ axen_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st 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; + csum_flags |= M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK; #endif - memcpy(mtod(m, char *), buf + 2, pkt_len - 6); + /* process each packet */ + /* allocate mbuf */ + m = axen_newbuf(); + if (m == NULL) { + ifp->if_ierrors++; + goto nextpkt; + } + /* skip pseudo header (2byte) and trailer padding (4Byte) */ + m->m_pkthdr.len = m->m_len = pkt_len - 6; + m->m_pkthdr.csum_flags |= csum_flags; + + memcpy(mtod(m, char *), buf + 2, m->m_len); + ml_enqueue(&ml, m); nextpkt: @@ -1017,11 +1064,9 @@ nextpkt: * 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 += roundup(pkt_len, 8); hdr_p++; - pkt_count--; - } while( pkt_count > 0); + } done: /* push the packet up */ @@ -1255,6 +1300,14 @@ axen_init(void *xsc) * Cancel pending I/O and free all RX/TX buffers. */ axen_reset(sc); + +#define AXEN_CONFIG_NO 1 +#define AXEN_IFACE_IDX 0 + if (usbd_set_config_no(sc->axen_udev, AXEN_CONFIG_NO, 1) || + usbd_device2interface_handle(sc->axen_udev, AXEN_IFACE_IDX, + &sc->axen_iface)) + printf("%s: set_config failed\n", sc->axen_dev.dv_xname); + usbd_delay_ms(sc->axen_udev, 10); /* XXX: ? */ bval = 0x01;