From owner-svn-src-all@FreeBSD.ORG Wed Dec 8 01:24:05 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 9BE961065679; Wed, 8 Dec 2010 01:24:05 +0000 (UTC) (envelope-from yongari@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 8A7398FC18; Wed, 8 Dec 2010 01:24:05 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id oB81O5Lf086077; Wed, 8 Dec 2010 01:24:05 GMT (envelope-from yongari@svn.freebsd.org) Received: (from yongari@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id oB81O5Te086075; Wed, 8 Dec 2010 01:24:05 GMT (envelope-from yongari@svn.freebsd.org) Message-Id: <201012080124.oB81O5Te086075@svn.freebsd.org> From: Pyun YongHyeon Date: Wed, 8 Dec 2010 01:24:05 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r216284 - head/sys/dev/usb/net X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 08 Dec 2010 01:24:05 -0000 Author: yongari Date: Wed Dec 8 01:24:05 2010 New Revision: 216284 URL: http://svn.freebsd.org/changeset/base/216284 Log: r184610 changed the way how TX frames are handled on AX88178 and AX88772 controllers. ASIX added a new feature for AX88178/AX88772 controllers which allows combining multiple TX frames into a single big frame. This was to overcome one of USB limitation where it can't generate more than 8k interrupts/sec which in turn means USB ethernet controllers can not send more than 8k packets per second. Using ASIX's feature greatly enhanced TX performance(more than 3~4 times) compared to 7.x driver. However it seems r184610 removed boundary checking for buffered frames which in turn caused instability issues under certain conditions. In addition, using ASIX's feature triggered another issue which made USB controller hang under certain conditions. Restarting ethernet controller didn't help under this hang condition and unplugging and replugging the controller was the only solution. I believe there is a silicon bug in TX frame combining feature on AX88178/AX88772 controllers. To address these issues, reintroduce the boundary checking for both AX88178 and AX88772 after copying a frame to USB buffer and do not use ASIX's multiple frame combining feature. Instead, use USB controller's multi-frame transmit capability to enhance TX performance as suggested by Hans[1]. This should fix a long standing axe(4) instability issues reported on AX88772 and AX88178 controllers. While I'm here remove unnecessary TX frame length check since upper stack always guarantee the size of a frame to be less than MCLBYTES. Special thanks to Derrick Brashear who tried numerous patches during last 4 months and waited real fix with patience. Without this enthusiastic support, patience and H/W donation I couldn't fix it since I was not able to trigger the issue on my box. Suggested by: hselasky [1] Tested by: Derrick Brashear (shadow <> gmail dot com> H/W donated by: Derrick Brashear (shadow <> gmail dot com> PR: usb/140883 Modified: head/sys/dev/usb/net/if_axe.c Modified: head/sys/dev/usb/net/if_axe.c ============================================================================== --- head/sys/dev/usb/net/if_axe.c Wed Dec 8 00:09:24 2010 (r216283) +++ head/sys/dev/usb/net/if_axe.c Wed Dec 8 01:24:05 2010 (r216284) @@ -200,7 +200,8 @@ static const struct usb_config axe_confi .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, - .bufsize = AXE_BULK_BUF_SIZE, + .frames = 16, + .bufsize = 16 * MCLBYTES, .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, .callback = axe_bulk_write_callback, .timeout = 10000, /* 10 seconds */ @@ -939,7 +940,7 @@ axe_bulk_write_callback(struct usb_xfer struct ifnet *ifp = uether_getifp(&sc->sc_ue); struct usb_page_cache *pc; struct mbuf *m; - int pos; + int nframes, pos; switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: @@ -956,40 +957,34 @@ tr_setup: */ return; } - pos = 0; - pc = usbd_xfer_get_frame(xfer, 0); - - while (1) { + for (nframes = 0; nframes < 16 && + !IFQ_DRV_IS_EMPTY(&ifp->if_snd); nframes++) { IFQ_DRV_DEQUEUE(&ifp->if_snd, m); - - if (m == NULL) { - if (pos > 0) - break; /* send out data */ - return; - } - if (m->m_pkthdr.len > MCLBYTES) { - m->m_pkthdr.len = MCLBYTES; - } + if (m == NULL) + break; + usbd_xfer_set_frame_offset(xfer, nframes * MCLBYTES, + nframes); + pos = 0; + pc = usbd_xfer_get_frame(xfer, nframes); if (AXE_IS_178_FAMILY(sc)) { - hdr.len = htole16(m->m_pkthdr.len); hdr.ilen = ~hdr.len; - usbd_copy_in(pc, pos, &hdr, sizeof(hdr)); - pos += sizeof(hdr); - - /* - * NOTE: Some drivers force a short packet - * by appending a dummy header with zero - * length at then end of the USB transfer. - * This driver uses the - * USB_FORCE_SHORT_XFER flag instead. - */ + usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len); + pos += m->m_pkthdr.len; + if ((pos % 512) == 0) { + hdr.len = 0; + hdr.ilen = 0xffff; + usbd_copy_in(pc, pos, &hdr, + sizeof(hdr)); + pos += sizeof(hdr); + } + } else { + usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len); + pos += m->m_pkthdr.len; } - usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len); - pos += m->m_pkthdr.len; /* * XXX @@ -1010,22 +1005,16 @@ tr_setup: m_freem(m); - if (AXE_IS_178_FAMILY(sc)) { - if (pos > (AXE_BULK_BUF_SIZE - MCLBYTES - sizeof(hdr))) { - /* send out frame(s) */ - break; - } - } else { - /* send out frame */ - break; - } + /* Set frame length. */ + usbd_xfer_set_frame_len(xfer, nframes, pos); + } + if (nframes != 0) { + usbd_xfer_set_frames(xfer, nframes); + usbd_transfer_submit(xfer); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; } - - usbd_xfer_set_frame_len(xfer, 0, pos); - usbd_transfer_submit(xfer); - ifp->if_drv_flags |= IFF_DRV_OACTIVE; return; - + /* NOTREACHED */ default: /* Error */ DPRINTFN(11, "transfer error, %s\n", usbd_errstr(error));