usb/140883: commit references a PR

dfilter service dfilter at FreeBSD.ORG
Wed Dec 8 01:30:12 UTC 2010


The following reply was made to PR usb/140883; it has been noted by GNATS.

From: dfilter at FreeBSD.ORG (dfilter service)
To: bug-followup at FreeBSD.org
Cc:  
Subject: Re: usb/140883: commit references a PR
Date: Wed,  8 Dec 2010 01:24:11 +0000 (UTC)

 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));
 _______________________________________________
 svn-src-all at freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe at freebsd.org"
 


More information about the freebsd-usb mailing list