Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 6 Jan 2008 22:29:03 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 132649 for review
Message-ID:  <200801062229.m06MT3ah084583@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=132649

Change 132649 by hselasky@hselasky_laptop001 on 2008/01/06 22:28:36

	
	Upgrade "if_cdce" to support the new 512x4 protocol.
	
	o I should have started by reverting CDCE to get rid of
	the initial MF protocol, instead of working forward. Basically
	there are two new callbacks "cdce_bulk_write_512x4_callback" and
	"cdce_bulk_read_512x4_callback". The other callbacks do the
	same like before.
	
	o Added some code to set the correct alternate setting.
	
	o The protocol has been tested on a AT91 KB9202B board and
	there was a noticable increase in the number of frames
	transmitted per second when doing a ping flood !

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/if_cdce.c#45 edit
.. //depot/projects/usb/src/sys/dev/usb/if_cdcereg.h#16 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/if_cdce.c#45 (text+ko) ====

@@ -115,15 +115,15 @@
 		.type = UE_BULK,
 		.endpoint = UE_ADDR_ANY,
 		.direction = UE_DIR_OUT,
-		.frames = CDCE_ETH_FRAMES_MAX,
-		.bufsize = (MCLBYTES * CDCE_ETH_FRAMES_MAX),
+		.frames = CDCE_512X4_FRAGS_MAX + 1,
+		.bufsize = (CDCE_512X4_FRAMES_MAX * MCLBYTES) + sizeof(usb_cdc_mf_eth_512x4_header_t),
 		.if_index = 0,
 		/* Host Mode */
 		.mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,.ext_buffer = 1,},
 		.mh.callback = &cdce_bulk_write_callback,
 		.mh.timeout = 10000,	/* 10 seconds */
 		/* Device Mode */
-		.md.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.ext_buffer = 1,.short_frames_ok = 1,},
+		.md.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.ext_buffer = 1,},
 		.md.callback = &cdce_bulk_read_callback,
 		.md.timeout = 0,	/* no timeout */
 	},
@@ -132,11 +132,11 @@
 		.type = UE_BULK,
 		.endpoint = UE_ADDR_ANY,
 		.direction = UE_DIR_IN,
-		.frames = CDCE_ETH_FRAMES_MAX,
-		.bufsize = (MCLBYTES * CDCE_ETH_FRAMES_MAX),
+		.frames = CDCE_512X4_FRAGS_MAX + 1,
+		.bufsize = (CDCE_512X4_FRAMES_MAX * MCLBYTES) + sizeof(usb_cdc_mf_eth_512x4_header_t),
 		.if_index = 0,
 		/* Host Mode */
-		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.ext_buffer = 1,.short_frames_ok = 1,},
+		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.ext_buffer = 1,},
 		.mh.callback = &cdce_bulk_read_callback,
 		.mh.timeout = 0,	/* no timeout */
 		/* Device Mode */
@@ -280,9 +280,11 @@
 	const usb_cdc_union_descriptor_t *ud;
 	const usb_cdc_ethernet_descriptor_t *ue;
 	const usb_interface_descriptor_t *id;
+	usb_descriptor_t *desc = NULL;
 	const struct cdce_type *t;
 	struct ifnet *ifp;
 	int error;
+	uint8_t alt_index;
 	uint8_t i;
 	uint8_t eaddr[ETHER_ADDR_LEN];
 	uint8_t eaddr_str[USB_STRING_DESC_LEN(ETHER_ADDR_LEN * 2) + 1];
@@ -298,6 +300,51 @@
 	if (t) {
 		sc->sc_flags = t->cdce_flags;
 	}
+	/* search for alternate settings */
+	if (uaa->usb_mode == USB_MODE_HOST) {
+
+		id = uaa->iface->idesc;
+		i = id->bInterfaceNumber;
+		alt_index = 0;
+		while ((desc = usbd_desc_foreach(
+			usbd_get_config_descriptor(uaa->device), desc))) {
+			id = (void *)desc;
+			if ((id->bDescriptorType == UDESC_INTERFACE) &&
+			    (id->bLength >= sizeof(*id))) {
+				if (id->bInterfaceNumber != i) {
+					alt_index = 0;
+					break;
+				}
+				if ((id->bInterfaceClass == UICLASS_CDC) &&
+				    (id->bInterfaceSubClass == 
+				     UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL) &&
+				    (id->bInterfaceProtocol == UIPROTO_CDC_ETH_512X4)) {
+
+					alt_index = id->bAlternateSetting;
+					/*
+					 * We want this alt setting hence
+					 * the protocol supports multi
+					 * sub-framing !
+					 */
+					break;
+				}
+			}
+		}
+
+		if (alt_index > 0) {
+
+			error = usbd_set_alt_interface_index(uaa->device,
+			    uaa->iface_index, alt_index);
+			if (error) {
+				device_printf(dev, "Could not set alternate "
+				    "setting, error = %s\n", usbd_errstr(error));
+				return (EINVAL);
+			}
+		}
+	}
+	/* get the interface subclass we are using */
+	sc->sc_iface_protocol = uaa->iface->idesc->bInterfaceProtocol;
+
 	usbd_set_device_desc(dev);
 
 	snprintf(sc->sc_name, sizeof(sc->sc_name), "%s",
@@ -459,8 +506,13 @@
 	ifp->if_start = cdce_start_cb;
 	ifp->if_init = cdce_init_cb;
 	ifp->if_baudrate = 11000000;
-	IFQ_SET_MAXLEN(&ifp->if_snd, CDCE_IFQ_MAXLEN);
-	ifp->if_snd.ifq_drv_maxlen = CDCE_IFQ_MAXLEN;
+	if (sc->sc_iface_protocol == UIPROTO_CDC_ETH_512X4) {
+	    IFQ_SET_MAXLEN(&ifp->if_snd, CDCE_512X4_IFQ_MAXLEN);
+	    ifp->if_snd.ifq_drv_maxlen = CDCE_512X4_IFQ_MAXLEN;
+	} else {
+	    IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+	    ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
+	}
 	IFQ_SET_READY(&ifp->if_snd);
 
 	/* no IFM type for 11Mbps USB, so go with 10baseT */
@@ -547,7 +599,62 @@
 	return;
 }
 
+static uint32_t
+cdce_m_frags(struct mbuf *m)
+{
+  uint32_t temp = 1;
+  while ((m = m->m_next)) {
+	temp ++;
+  }
+  return (temp);
+}
+
+static void
+cdce_fwd_mq(struct cdce_softc *sc, struct cdce_mq *mq)
+{
+	struct mbuf *m;
+	struct ifnet *ifp = sc->sc_ifp;
+
+	if (mq->ifq_head) {
+
+		mtx_unlock(&(sc->sc_mtx));
+
+		while (1) {
+
+			_IF_DEQUEUE(mq, m);
+
+			if (m == NULL)
+				break;
+
+			(ifp->if_input) (ifp, m);
+		}
+
+		mtx_lock(&(sc->sc_mtx));
+	}
+	return;
+}
+
 static void
+cdce_free_mq(struct cdce_mq *mq)
+{
+	struct mbuf *m;
+
+	if (mq->ifq_head) {
+
+		while (1) {
+
+			_IF_DEQUEUE(mq, m);
+
+			if (m == NULL)
+				break;
+
+			m_freem(m);
+		}
+	}
+	return;
+}
+
+static void
 cdce_bulk_write_clear_stall_callback(struct usbd_xfer *xfer)
 {
 	struct cdce_softc *sc = xfer->priv_sc;
@@ -561,38 +668,140 @@
 }
 
 static void
-cdce_free_mbufs(struct mbuf **ppm)
+cdce_bulk_write_512x4_callback(struct usbd_xfer *xfer)
 {
+	struct cdce_softc *sc = xfer->priv_sc;
+	struct ifnet *ifp = sc->sc_ifp;
 	struct mbuf *m;
+	struct mbuf *mt;
 	uint16_t x;
+	uint16_t y;
+	uint16_t flen;
+
+	switch (USBD_GET_STATE(xfer)) {
+	case USBD_ST_TRANSFERRED:
+		DPRINTF(sc, 10, "transfer complete: "
+		    "%u bytes in %u fragments and %u frames\n",
+		xfer->actlen, xfer->nframes, sc->sc_tx_mq.ifq_len);
+
+		/* update packet counter */
+		ifp->if_opackets += sc->sc_tx_mq.ifq_len;
+
+		/* free all previous mbufs */
+		cdce_free_mq(&(sc->sc_tx_mq));
+
+	case USBD_ST_SETUP:
+tr_setup:
+		if (xfer->flags.stall_pipe &&
+		    (xfer->flags_int.usb_mode == USB_MODE_HOST)) {
+			/* try to clear stall */
+			usbd_transfer_start(sc->sc_xfer[2]);
+			break;
+		}
+
+		x = 0; /* number of frames */
+		y = 1; /* number of fragments */
+
+		while (x != CDCE_512X4_FRAMES_MAX) {
 
-	/* free all previous mbufs */
-	for (x = 0; x != CDCE_ETH_FRAMES_MAX; x++) {
-		m = ppm[x];
-		if (m) {
-			m_freem(m);
-			ppm[x] = NULL;
-		} else {
-			if (x != 0) {
+			IFQ_DRV_DEQUEUE(&(ifp->if_snd), m);
+
+			if (m == NULL) {
 				break;
 			}
+			if (m->m_pkthdr.len > MCLBYTES) {
+				m_freem(m);
+				ifp->if_oerrors++;
+				continue;
+			}
+			if (cdce_m_frags(m) > CDCE_512X4_FRAME_FRAG_MAX) {
+				mt = m_defrag(m, M_DONTWAIT);
+				if (mt == NULL) {
+					m_freem(m);
+					ifp->if_oerrors++;
+					continue;
+				}
+				m = mt;
+			}
+
+			_IF_ENQUEUE(&(sc->sc_tx_mq), m);
+
+			/*
+			 * if there's a BPF listener, bounce a copy
+			 * of this frame to him:
+			 */
+			BPF_MTAP(ifp, m);
+
+#if (CDCE_512X4_FRAG_LENGTH_MASK < MCLBYTES)
+#error "(CDCE_512X4_FRAG_LENGTH_MASK < MCLBYTES)"
+#endif
+			do {
+
+			    flen = m->m_len & CDCE_512X4_FRAG_LENGTH_MASK;
+			    xfer->frlengths[y] = m->m_len;
+			    usbd_set_frame_data(xfer, m->m_data, y);
+
+			    if (m->m_next == NULL) {
+				flen |= CDCE_512X4_FRAG_LAST_MASK;
+			    }
+
+			    USETW(sc->sc_tx.hdr.wFragLength[y-1], flen);
+
+			    y++;
+
+			} while ((m = m->m_next));
+
+			x++;
+		}
+
+		if (y == 1) {
+		    /* no data to transmit */
+		    break;
+		}
+
+		/* fill in Signature */
+		sc->sc_tx.hdr.bSig[0] = 'F';
+		sc->sc_tx.hdr.bSig[1] = 'L';
+
+		/* 
+		 * We ensure that the header results in a short packet
+		 * by making the length odd !
+		 */
+		USETW(sc->sc_tx.hdr.wFragLength[y-1], 0);
+		xfer->frlengths[0] = CDCE_512X4_FRAG_LENGTH_OFFSET + ((y-1) * 2) + 1;
+		usbd_set_frame_data(xfer, &(sc->sc_tx.hdr), 0);
+		xfer->nframes = y;
+		usbd_start_hardware(xfer);
+		break;
+
+	default:			/* Error */
+		DPRINTF(sc, 10, "transfer error, %s\n",
+		    usbd_errstr(xfer->error));
+
+		/* update error counter */
+		ifp->if_oerrors += sc->sc_tx_mq.ifq_len;
+
+		/* free all previous mbufs */
+		cdce_free_mq(&(sc->sc_tx_mq));
+
+		if (xfer->error != USBD_CANCELLED) {
+			/* try to clear stall first */
+			xfer->flags.stall_pipe = 1;
+			goto tr_setup;
 		}
+		break;
 	}
 	return;
 }
 
 static void
-cdce_bulk_write_callback(struct usbd_xfer *xfer)
+cdce_bulk_write_std_callback(struct usbd_xfer *xfer)
 {
 	struct cdce_softc *sc = xfer->priv_sc;
 	struct ifnet *ifp = sc->sc_ifp;
 	struct mbuf *m;
 	struct mbuf *mt;
 	uint32_t crc;
-	uint32_t x;
-
-	/* free all previous mbufs */
-	cdce_free_mbufs(sc->sc_tx_mbufs);
 
 	switch (USBD_GET_STATE(xfer)) {
 	case USBD_ST_TRANSFERRED:
@@ -602,44 +811,22 @@
 
 		ifp->if_opackets++;
 
+		/* free all previous mbufs */
+		cdce_free_mq(&(sc->sc_tx_mq));
+
 	case USBD_ST_SETUP:
 tr_setup:
 		if (xfer->flags.stall_pipe &&
 		    (xfer->flags_int.usb_mode == USB_MODE_HOST)) {
 			usbd_transfer_start(sc->sc_xfer[2]);
-			goto done;
+			break;
 		}
-#ifdef CDCE_MF_ENABLE
-		x = 1;
-#else
-		x = 0;
-#endif
-		while (x != CDCE_ETH_FRAMES_MAX) {
 
 			IFQ_DRV_DEQUEUE(&(ifp->if_snd), m);
 
 			if (m == NULL) {
-#ifdef CDCE_DO_BENCHMARK
-				/* send dummy ethernet frames */
-				usbd_set_frame_data(xfer,
-				    &(sc->sc_rx_dump), x);
-				xfer->frlengths[x] =
-				    (sizeof(sc->sc_rx_dump) / 2) + (x & 63) - 1;
-				x++;
-				continue;
-#else
 				break;
-#endif
 			}
-			if (m->m_pkthdr.len < sizeof(struct ether_header)) {
-				/*
-				 * frames of this size have special meaning
-				 * - filter away
-				 */
-				m_freem(m);
-				ifp->if_oerrors++;
-				continue;
-			}
 			if (sc->sc_flags & CDCE_FLAG_ZAURUS) {
 				/*
 				 * Zaurus wants a 32-bit CRC appended to
@@ -652,27 +839,27 @@
 				if (!m_append(m, 4, (void *)&crc)) {
 					m_freem(m);
 					ifp->if_oerrors++;
-					continue;
+					goto tr_setup;
 				}
-				m->m_pkthdr.len += 4;
 			}
 			if (m->m_len != m->m_pkthdr.len) {
 				mt = m_defrag(m, M_DONTWAIT);
 				if (mt == NULL) {
 					m_freem(m);
 					ifp->if_oerrors++;
-					continue;
+					goto tr_setup;
 				}
 				m = mt;
 			}
 			if (m->m_pkthdr.len > MCLBYTES) {
 				m->m_pkthdr.len = MCLBYTES;
 			}
-			sc->sc_tx_mbufs[x] = m;
 
-			xfer->frlengths[x] = m->m_len;
+			_IF_ENQUEUE(&(sc->sc_tx_mq), m);
 
-			usbd_set_frame_data(xfer, m->m_data, x);
+			xfer->frlengths[0] = m->m_len;
+			usbd_set_frame_data(xfer, m->m_data, 0);
+			xfer->nframes = 1;
 
 			/*
 			 * if there's a BPF listener, bounce a copy
@@ -680,51 +867,41 @@
 			 */
 			BPF_MTAP(ifp, m);
 
-			x++;
-		}
-
-		xfer->nframes = x;
-
-#ifdef CDCE_MF_ENABLE
-		if (x == 1) {
-			/* nothing to do */
-			goto done;
-		}
-		/* fill out the Multi Frame header */
-		usbd_set_frame_data(xfer, &(sc->sc_tx_eth.hdr), 0);
-		xfer->frlengths[0] = sizeof(sc->sc_tx_eth.hdr);
-		sc->sc_tx_eth.hdr.bSig0[0] = 'M';
-		sc->sc_tx_eth.hdr.bSig0[1] = 'F';
-		x--;
-		/* tell the peer how many frames are coming */
-		x += ifp->if_snd.ifq_drv_len;
-		USETDW(sc->sc_tx_eth.hdr.dwFramesAhead, x);
-		x = ~x;
-		USETDW(sc->sc_tx_eth.hdr.dwFramesAheadInverse, x);
-#else
-		if (x == 0) {
-			/* nothing to do */
-			goto done;
-		}
-#endif
 		usbd_start_hardware(xfer);
+		break;
 
-done:
-		return;
-
 	default:			/* Error */
 		DPRINTF(sc, 10, "transfer error, %s\n",
 		    usbd_errstr(xfer->error));
 
+		/* free all previous mbufs */
+		cdce_free_mq(&(sc->sc_tx_mq));
+		ifp->if_oerrors++;
+
 		if (xfer->error != USBD_CANCELLED) {
 			/* try to clear stall first */
 			xfer->flags.stall_pipe = 1;
 			goto tr_setup;
 		}
-		ifp->if_oerrors++;
-		return;
+		break;
+	}
+	return;
+}
+
+static void
+cdce_bulk_write_callback(struct usbd_xfer *xfer)
+{
+	struct cdce_softc *sc = xfer->priv_sc;
 
+	/* first call - set the correct callback */
+	if (sc->sc_iface_protocol == UIPROTO_CDC_ETH_512X4) {
+		xfer->flags.force_short_xfer = 0;
+		xfer->callback = &cdce_bulk_write_512x4_callback;
+	} else {
+		xfer->callback = &cdce_bulk_write_std_callback;
 	}
+	(xfer->callback) (xfer);
+	return;
 }
 
 static int32_t
@@ -883,16 +1060,24 @@
 }
 
 static void
-cdce_bulk_read_callback(struct usbd_xfer *xfer)
+cdce_bulk_read_512x4_callback(struct usbd_xfer *xfer)
 {
-	struct cdce_mq mq = {NULL, NULL, 0};
 	struct cdce_softc *sc = xfer->priv_sc;
 	struct ifnet *ifp = sc->sc_ifp;
 	struct mbuf *m;
-	usb_cdc_mf_eth_header_t *mf_hdr;
-	uint32_t x;
-	uint32_t ta;
-	uint32_t tb;
+	void *data_ptr;
+	uint32_t offset;
+	uint16_t x;
+	uint16_t y;
+	uint16_t z;
+	uint16_t rx_frags;
+	uint16_t flen;
+	uint8_t fwd_mq;
+	uint8_t free_mq;
+
+	fwd_mq = 0;
+	free_mq = 0;
+	rx_frags = 0;
 
 	switch (USBD_GET_STATE(xfer)) {
 	case USBD_ST_TRANSFERRED:
@@ -900,172 +1085,312 @@
 		DPRINTF(sc, 0, "received %u bytes in %u frames\n",
 		    xfer->actlen, xfer->aframes);
 
-		for (x = 0; x != xfer->nframes; x++) {
+		/* check state */
+		if (!(sc->sc_flags & CDCE_FLAG_RX_DATA)) {
 
-			if (sc->sc_flags & CDCE_FLAG_ZAURUS) {
-
-				/* Strip off CRC added by Zaurus */
-				if (xfer->frlengths[x] >= MAX(4, 14)) {
-					xfer->frlengths[x] -= 4;
-				}
+			/* verify the header */
+			if ((xfer->actlen < CDCE_512X4_FRAG_LENGTH_OFFSET) ||
+			    (sc->sc_rx.hdr.bSig[0] != 'F') ||
+			    (sc->sc_rx.hdr.bSig[1] != 'L')) {
+				/* try to clear stall first */
+				xfer->flags.stall_pipe = 1;
+				goto tr_setup;
 			}
-			m = sc->sc_rx_mbufs[x];
-			sc->sc_rx_mbufs[x] = NULL;
-			if (m == NULL) {
-				continue;
+			rx_frags = (xfer->actlen - 
+			    CDCE_512X4_FRAG_LENGTH_OFFSET) / 2;
+			if (rx_frags != 0) {
+				/* start receiving data */
+				sc->sc_flags |= CDCE_FLAG_RX_DATA;
 			}
-			if (xfer->frlengths[x] < sizeof(struct ether_header)) {
 
-#ifdef CDCE_MF_ENABLE
-				if (xfer->frlengths[x] >=
-				    CDC_MF_ETH_HEADER_SIZE) {
+			DPRINTF(sc, 0, "doing %u fragments\n", rx_frags);
 
-					mf_hdr = (void *)(m->m_data);
+		} else {
+			/* we are done receiving data */
+			sc->sc_flags &= ~CDCE_FLAG_RX_DATA;
+			fwd_mq = 1;
+		}
 
-					/*
-					 * decode and verify the multi
-					 * frame header
-					 */
+	case USBD_ST_SETUP:
+tr_setup:
+		if (xfer->flags.stall_pipe) {
 
-					ta = UGETDW(mf_hdr->dwFramesAhead);
-					tb = UGETDW(mf_hdr->dwFramesAheadInverse);
-					tb ^= ta;
+			/* we are done */
+			sc->sc_flags &= ~CDCE_FLAG_RX_DATA;
 
-					DPRINTF(sc, 0, "ta = 0x%08x, "
-					    "tb = 0x%08x\n", ta, tb);
+			if (xfer->flags_int.usb_mode == USB_MODE_HOST) {
+				usbd_transfer_start(sc->sc_xfer[3]);
+				free_mq = 1;
+				break;
+			}
+		}
+		/* we expect a Multi Frame Ethernet Header */
+		if (!(sc->sc_flags & CDCE_FLAG_RX_DATA)) {
+			DPRINTF(sc, 0, "expecting length header\n");
+			usbd_set_frame_data(xfer, &(sc->sc_rx.hdr), 0);
+			xfer->frlengths[0] = sizeof(sc->sc_rx.hdr);
+			xfer->nframes = 1;
+			xfer->flags.short_xfer_ok = 1;
+			usbd_start_hardware(xfer);
+			free_mq = 1;
+			break;
+		}
+		/* verify number of fragments */
+		if (rx_frags > CDCE_512X4_FRAGS_MAX) {
+			/* try to clear stall first */
+			xfer->flags.stall_pipe = 1;
+			goto tr_setup;
+		}
 
-					/*
-					 * check if we have a multi frame
-					 * header
-					 */
-					if ((tb == 0xFFFFFFFF) &&
-					    (mf_hdr->bSig0[0] == 'M') &&
-					    (mf_hdr->bSig0[1] == 'F')) {
+		/* check if the last fragment does not complete a frame */
+		x = rx_frags - 1;
+		flen = UGETW(sc->sc_rx.hdr.wFragLength[x]);
+		if (!(flen & CDCE_512X4_FRAG_LAST_MASK)) {
+			DPRINTF(sc, 0, "no last frag mask\n");
+			/* try to clear stall first */
+			xfer->flags.stall_pipe = 1;
+			goto tr_setup;
+		}
+		/*
+		 * Setup a new USB transfer chain to receive all the
+		 * IP-frame fragments, automagically defragged :
+		 */
+		x = 0;
+		y = 0;
+		while (1) {
 
-						DPRINTF(sc, 0, "frames ahead "
-						    "= %u\n", ta);
+			z = x;
+			offset = 0;
 
-						sc->sc_rx_frames_ahead = ta;
-					}
+			/* precompute the frame length */
+			while (1) {
+				flen = UGETW(sc->sc_rx.hdr.wFragLength[z]);
+				offset += (flen & CDCE_512X4_FRAG_LENGTH_MASK);
+				if (flen & CDCE_512X4_FRAG_LAST_MASK) {
+					break;
 				}
-#endif
+				z++;
+			}
 
-				m_freem(m);
-				continue;
-			} else {
+			if (offset >= sizeof(struct ether_header)) {
 				/*
-				 * we received a frame - decrement frames
-				 * ahead
+				 * allocate a suitable memory buffer, if
+				 * possible
 				 */
-				if (sc->sc_rx_frames_ahead) {
-					sc->sc_rx_frames_ahead--;
+				if (offset > (MCLBYTES - ETHER_ALIGN)) {
+					/* try to clear stall first */
+					xfer->flags.stall_pipe = 1;
+					goto tr_setup;
+				} if (offset > (MHLEN - ETHER_ALIGN)) {
+					m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+				} else {
+					m = m_gethdr(M_DONTWAIT, MT_DATA);
 				}
+			} else {
+				m = NULL;	/* dump it */
 			}
 
-			ifp->if_ipackets++;
-			m->m_pkthdr.rcvif = ifp;
-			m->m_pkthdr.len = m->m_len = xfer->frlengths[x];
+			DPRINTF(sc, 16, "frame %u, length = %u \n", y, offset);
+
+			/* check if we have a buffer */
+			if (m) {
+				m->m_data = USBD_ADD_BYTES(m->m_data, ETHER_ALIGN);
+				m->m_pkthdr.rcvif = ifp;
+				m->m_pkthdr.len = m->m_len = offset;
+
+				/* enqueue */
+				_IF_ENQUEUE(&(sc->sc_rx_mq), m);
+
+				data_ptr = m->m_data;
+				ifp->if_ipackets++;
+			} else {
+				data_ptr = sc->sc_rx.data;
+				ifp->if_ierrors++;
+			}
+
+			/* setup the RX chain */
+			offset = 0;
+			while (1) {
+
+				flen = UGETW(sc->sc_rx.hdr.wFragLength[x]);
+
+				usbd_set_frame_data(xfer,
+				    USBD_ADD_BYTES(data_ptr, offset), x);
+
+				xfer->frlengths[x] =
+				    (flen & CDCE_512X4_FRAG_LENGTH_MASK);
 
-			/* enqueue */
-			_IF_ENQUEUE(&(mq), m);
-		}
+				DPRINTF(sc, 16, "length[%u] = %u\n", 
+					x, xfer->frlengths[x]);
 
-	case USBD_ST_SETUP:
-tr_setup:
-		if (xfer->flags.stall_pipe) {
+				offset += xfer->frlengths[x];
 
-			/* reset number of frames ahead */
-			sc->sc_rx_frames_ahead = 0;
+				x++;
 
-			if (xfer->flags_int.usb_mode == USB_MODE_HOST) {
-				usbd_transfer_start(sc->sc_xfer[3]);
-				/*
-				 * In case the "stall_pipe" flag was set
-				 * while transferring data, we need to go to
-				 * the "tr_if_input" afterwards!
-				 */
-				goto tr_if_input;
+				if (flen & CDCE_512X4_FRAG_LAST_MASK) {
+					break;
+				}
 			}
-		}
-		/* setup a new USB transfer chain */
 
-		ta = sc->sc_rx_frames_ahead;
+			y++;
 
-		if (ta == 0) {
-			/* always receive at least one frame */
-			ta = 1;
-		}
-		if (ta > CDCE_ETH_FRAMES_MAX) {
-			ta = CDCE_ETH_FRAMES_MAX;
-		}
-		for (x = 0; x != ta; x++) {
-			m = usbd_ether_get_mbuf();
-			if (m == NULL) {
+			if (x == rx_frags) {
 				break;
 			}
-			usbd_set_frame_data(xfer, m->m_data, x);
+			if (y == CDCE_512X4_FRAMES_MAX) {
+				/* try to clear stall first */
+				xfer->flags.stall_pipe = 1;
+				goto tr_setup;
+			}
+		}
+
+		DPRINTF(sc, 0, "nframes = %u\n", x);
+
+		xfer->nframes = x;
+		xfer->flags.short_xfer_ok = 0;
+		usbd_start_hardware(xfer);
+		break;
+
+	default:			/* Error */
+		DPRINTF(sc, 0, "error = %s\n",
+		    usbd_errstr(xfer->error));
 
-			xfer->frlengths[x] = m->m_len;
-			sc->sc_rx_mbufs[x] = m;
+		if (xfer->error != USBD_CANCELLED) {
+			/* try to clear stall first */
+			xfer->flags.stall_pipe = 1;
+			goto tr_setup;
 		}
+		free_mq = 1;
+		break;
+	}
+
+	/*
+	 * At the end of a USB callback it is always safe to unlock
+	 * the private mutex of a device! 
+	 *
+	 *
+	 * By safe we mean that if "usbd_transfer_stop()" is called,
+	 * we will get a callback having the error code
+	 * USBD_CANCELLED.
+	 */
+	if (fwd_mq) {
+		cdce_fwd_mq(sc, &(sc->sc_rx_mq));
+	}
+
+	if (free_mq) {
+		cdce_free_mq(&(sc->sc_rx_mq));
+	}
+	return;
+}
+
+static void
+cdce_bulk_read_std_callback(struct usbd_xfer *xfer)
+{
+	struct cdce_softc *sc = xfer->priv_sc;
+	struct ifnet *ifp = sc->sc_ifp;
+	struct mbuf *m;
+	struct mbuf *m_rx = NULL;
 
-		for (; x != ta; x++) {
+	switch (USBD_GET_STATE(xfer)) {
+	case USBD_ST_TRANSFERRED:
 
-			/*
-			 * We are out of mbufs and need to dump all the
-			 * received data !
-			 */
-			usbd_set_frame_data(xfer, &(sc->sc_rx_dump), x);
-			xfer->frlengths[x] = sizeof(sc->sc_rx_dump);
-		}
-		xfer->nframes = ta;
-		usbd_start_hardware(xfer);
+		DPRINTF(sc, 0, "received %u bytes in %u frames\n",
+		    xfer->actlen, xfer->aframes);
 
-		/*
-		 * At the end of a USB callback it is always safe to
-		 * unlock the private mutex of a device! That is why
-		 * we do the "if_input" here, and not some lines up!
-		 *
-		 * By safe we mean that if "usbd_transfer_stop()" is
-		 * called, we will get a callback having the error
-		 * code USBD_CANCELLED.
-		 */
-tr_if_input:
-		if (mq.ifq_head) {
+		if (sc->sc_flags & CDCE_FLAG_ZAURUS) {
 
-			mtx_unlock(&(sc->sc_mtx));
+			/* Strip off CRC added by Zaurus */
+			if (xfer->frlengths[0] >= MAX(4, 14)) {
+				xfer->frlengths[0] -= 4;
+			}
+		}
 
-			while (1) {
+		_IF_DEQUEUE(&(sc->sc_rx_mq), m);
 
-				_IF_DEQUEUE(&(mq), m);
+		if (m) {
 
-				if (m == NULL)
-					break;
+			if (xfer->frlengths[0] < sizeof(struct ether_header)) {
+				m_freem(m);
+				goto tr_setup;
+			}
+			ifp->if_ipackets++;
+			m->m_pkthdr.rcvif = ifp;
+			m->m_pkthdr.len = m->m_len = xfer->frlengths[0];
+			m_rx = m;
+		}
+	case USBD_ST_SETUP:
+tr_setup:
+		if (xfer->flags.stall_pipe) {
 
-				(ifp->if_input) (ifp, m);
+			if (xfer->flags_int.usb_mode == USB_MODE_HOST) {
+				usbd_transfer_start(sc->sc_xfer[3]);
+				break;
 			}
+		}
+		m = usbd_ether_get_mbuf();
+		if (m == NULL) {
+
+			/*
+			 * We are out of mbufs and need to dump all the
+			 * received data !
+			 */
+			usbd_set_frame_data(xfer, &(sc->sc_rx.data), 0);
+			xfer->frlengths[0] = sizeof(sc->sc_rx.data);
 
-			mtx_lock(&(sc->sc_mtx));
+		} else {
+			usbd_set_frame_data(xfer, m->m_data, 0);
+			xfer->frlengths[0] = m->m_len;
+			_IF_ENQUEUE(&(sc->sc_rx_mq), m);
 		}
-		return;
+		xfer->nframes = 1;
+		usbd_start_hardware(xfer);
+		break;
 
 	default:			/* Error */
-		/* free all received data, if any */
-		cdce_free_mbufs(sc->sc_rx_mbufs);
+		DPRINTF(sc, 0, "error = %s\n",
+		    usbd_errstr(xfer->error));
 
-		/* reset number of frames ahead */
-		sc->sc_rx_frames_ahead = 0;
+		/* free all mbufs */
+		cdce_free_mq(&(sc->sc_rx_mq));
 
 		if (xfer->error != USBD_CANCELLED) {
 			/* try to clear stall first */
 			xfer->flags.stall_pipe = 1;
 			goto tr_setup;
 		}
-		DPRINTF(sc, 0, "bulk read error, %s\n",
-		    usbd_errstr(xfer->error));
 		return;
+	}
+
+	/*
+	 * At the end of a USB callback it is always safe to unlock
+	 * the private mutex of a device! That is why we do the
+	 * "if_input" here, and not some lines up!
+	 *
+	 * By safe we mean that if "usbd_transfer_stop()" is called,
+	 * we will get a callback having the error code
+	 * USBD_CANCELLED.
+	 */
+	if (m_rx) {
+		mtx_unlock(&(sc->sc_mtx));
+		(ifp->if_input) (ifp, m_rx);
+		mtx_lock(&(sc->sc_mtx));
+	}
+	return;
+}
+
+static void
+cdce_bulk_read_callback(struct usbd_xfer *xfer)
+{
+	struct cdce_softc *sc = xfer->priv_sc;
 
+	/* first call - set the correct callback */
+	if (sc->sc_iface_protocol == UIPROTO_CDC_ETH_512X4) {
+		xfer->callback = &cdce_bulk_read_512x4_callback;
+	} else {
+		xfer->callback = &cdce_bulk_read_std_callback;
 	}
+	(xfer->callback) (xfer);
+	return;
 }
 
 static int
@@ -1166,13 +1491,9 @@
 }
 
 static int
-cdce_handle_request(device_t dev, const void *req, void **pptr,
-    uint16_t *plen, uint16_t offset, uint8_t is_complete)
+cdce_handle_request(device_t dev,
+    const void *req, void **pptr, uint16_t *plen,
+    uint16_t offset, uint8_t is_complete)
 {
-#ifdef USB_DEBUG
-	struct cdce_softc *sc = device_get_softc(dev);
-
-	DPRINTF(sc, 0, "\n");
-#endif
-	return (ENXIO);			/* use builtin handling */
+	return (ENXIO); /* use builtin handler */
 }

==== //depot/projects/usb/src/sys/dev/usb/if_cdcereg.h#16 (text+ko) ====

@@ -37,21 +37,20 @@
 
 #define	CDCE_N_TRANSFER	6		/* units */
 #define	CDCE_IND_SIZE_MAX 32		/* bytes */
-#define	CDCE_ETH_FRAMES_MAX 64		/* USB ethernet acceleration factor */
-#define	CDCE_IFQ_MAXLEN MAX((2*CDCE_ETH_FRAMES_MAX), IFQ_MAXLEN)

>>> TRUNCATED FOR MAIL (1000 lines) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200801062229.m06MT3ah084583>