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;

Reply via email to