svn commit: r215981 - in stable/8/sys/dev/usb: . net
Andrew Thompson
thompsa at FreeBSD.org
Sun Nov 28 07:04:29 UTC 2010
Author: thompsa
Date: Sun Nov 28 07:04:28 2010
New Revision: 215981
URL: http://svn.freebsd.org/changeset/base/215981
Log:
MFC r213809
USB network (NCM driver):
- correct the ethernet payload remainder which
must be post-offseted by -14 bytes instead of
0 bytes. This is not very clearly defined in the
NCM specification.
Modified:
stable/8/sys/dev/usb/net/if_cdce.c
stable/8/sys/dev/usb/net/if_cdcereg.h
stable/8/sys/dev/usb/usb_cdc.h
Directory Properties:
stable/8/sys/ (props changed)
stable/8/sys/amd64/include/xen/ (props changed)
stable/8/sys/cddl/contrib/opensolaris/ (props changed)
stable/8/sys/contrib/dev/acpica/ (props changed)
stable/8/sys/contrib/pf/ (props changed)
Modified: stable/8/sys/dev/usb/net/if_cdce.c
==============================================================================
--- stable/8/sys/dev/usb/net/if_cdce.c Sun Nov 28 07:03:21 2010 (r215980)
+++ stable/8/sys/dev/usb/net/if_cdce.c Sun Nov 28 07:04:28 2010 (r215981)
@@ -110,10 +110,13 @@ static uint32_t cdce_m_crc32(struct mbuf
#ifdef USB_DEBUG
static int cdce_debug = 0;
+static int cdce_tx_interval = 0;
SYSCTL_NODE(_hw_usb, OID_AUTO, cdce, CTLFLAG_RW, 0, "USB CDC-Ethernet");
SYSCTL_INT(_hw_usb_cdce, OID_AUTO, debug, CTLFLAG_RW, &cdce_debug, 0,
"Debug level");
+SYSCTL_INT(_hw_usb_cdce, OID_AUTO, interval, CTLFLAG_RW, &cdce_tx_interval, 0,
+ "NCM transmit interval in ms");
#endif
static const struct usb_config cdce_config[CDCE_N_TRANSFER] = {
@@ -192,7 +195,7 @@ static const struct usb_config cdce_ncm_
.if_index = 0,
.frames = CDCE_NCM_TX_FRAMES_MAX,
.bufsize = (CDCE_NCM_TX_FRAMES_MAX * CDCE_NCM_TX_MAXLEN),
- .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
+ .flags = {.pipe_bof = 1,},
.callback = cdce_ncm_bulk_write_callback,
.timeout = 10000, /* 10 seconds */
.usb_mode = USB_MODE_DUAL, /* both modes */
@@ -294,9 +297,22 @@ cdce_ncm_init(struct cdce_softc *sc)
{
struct usb_ncm_parameters temp;
struct usb_device_request req;
- uDWord value;
+ struct usb_ncm_func_descriptor *ufd;
+ uint8_t value[8];
int err;
+ ufd = usbd_find_descriptor(sc->sc_ue.ue_udev, NULL,
+ sc->sc_ifaces_index[1], UDESC_CS_INTERFACE, 0 - 1,
+ UCDC_NCM_FUNC_DESC_SUBTYPE, 0 - 1);
+
+ /* verify length of NCM functional descriptor */
+ if (ufd != NULL) {
+ if (ufd->bLength < sizeof(*ufd))
+ ufd = NULL;
+ else
+ DPRINTFN(1, "Found NCM functional descriptor.\n");
+ }
+
req.bmRequestType = UT_READ_CLASS_INTERFACE;
req.bRequest = UCDC_NCM_GET_NTB_PARAMETERS;
USETW(req.wValue, 0);
@@ -317,17 +333,19 @@ cdce_ncm_init(struct cdce_softc *sc)
sc->sc_ncm.tx_remainder = UGETW(temp.wNdpOutPayloadRemainder);
sc->sc_ncm.tx_modulus = UGETW(temp.wNdpOutDivisor);
sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpOutAlignment);
+ sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams);
} else {
sc->sc_ncm.rx_max = UGETDW(temp.dwNtbOutMaxSize);
sc->sc_ncm.tx_max = UGETDW(temp.dwNtbInMaxSize);
sc->sc_ncm.tx_remainder = UGETW(temp.wNdpInPayloadRemainder);
sc->sc_ncm.tx_modulus = UGETW(temp.wNdpInDivisor);
sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpInAlignment);
+ sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams);
}
/* Verify maximum receive length */
- if (err || (sc->sc_ncm.rx_max < 32) ||
+ if ((sc->sc_ncm.rx_max < 32) ||
(sc->sc_ncm.rx_max > CDCE_NCM_RX_MAXLEN)) {
DPRINTFN(1, "Using default maximum receive length\n");
sc->sc_ncm.rx_max = CDCE_NCM_RX_MAXLEN;
@@ -335,7 +353,7 @@ cdce_ncm_init(struct cdce_softc *sc)
/* Verify maximum transmit length */
- if (err || (sc->sc_ncm.tx_max < 32) ||
+ if ((sc->sc_ncm.tx_max < 32) ||
(sc->sc_ncm.tx_max > CDCE_NCM_TX_MAXLEN)) {
DPRINTFN(1, "Using default maximum transmit length\n");
sc->sc_ncm.tx_max = CDCE_NCM_TX_MAXLEN;
@@ -347,7 +365,7 @@ cdce_ncm_init(struct cdce_softc *sc)
* - not greater than the maximum transmit length
* - not less than four bytes
*/
- if (err || (sc->sc_ncm.tx_struct_align < 4) ||
+ if ((sc->sc_ncm.tx_struct_align < 4) ||
(sc->sc_ncm.tx_struct_align !=
((-sc->sc_ncm.tx_struct_align) & sc->sc_ncm.tx_struct_align)) ||
(sc->sc_ncm.tx_struct_align >= sc->sc_ncm.tx_max)) {
@@ -361,7 +379,7 @@ cdce_ncm_init(struct cdce_softc *sc)
* - not greater than the maximum transmit length
* - not less than four bytes
*/
- if (err || (sc->sc_ncm.tx_modulus < 4) ||
+ if ((sc->sc_ncm.tx_modulus < 4) ||
(sc->sc_ncm.tx_modulus !=
((-sc->sc_ncm.tx_modulus) & sc->sc_ncm.tx_modulus)) ||
(sc->sc_ncm.tx_modulus >= sc->sc_ncm.tx_max)) {
@@ -371,11 +389,30 @@ cdce_ncm_init(struct cdce_softc *sc)
/* Verify that the payload remainder */
- if (err || (sc->sc_ncm.tx_remainder >= sc->sc_ncm.tx_modulus)) {
+ if ((sc->sc_ncm.tx_remainder >= sc->sc_ncm.tx_modulus)) {
DPRINTFN(1, "Using default transmit remainder: 0 bytes\n");
sc->sc_ncm.tx_remainder = 0;
}
+ /*
+ * Offset the TX remainder so that IP packet payload starts at
+ * the tx_modulus. This is not too clear in the specification.
+ */
+
+ sc->sc_ncm.tx_remainder =
+ (sc->sc_ncm.tx_remainder - ETHER_HDR_LEN) &
+ (sc->sc_ncm.tx_modulus - 1);
+
+ /* Verify max datagrams */
+
+ if (sc->sc_ncm.tx_nframe == 0 ||
+ sc->sc_ncm.tx_nframe > (CDCE_NCM_SUBFRAMES_MAX - 1)) {
+ DPRINTFN(1, "Using default max "
+ "subframes: %u units\n", CDCE_NCM_SUBFRAMES_MAX - 1);
+ /* need to reserve one entry for zero padding */
+ sc->sc_ncm.tx_nframe = (CDCE_NCM_SUBFRAMES_MAX - 1);
+ }
+
/* Additional configuration, will fail in device side mode, which is OK. */
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
@@ -383,8 +420,17 @@ cdce_ncm_init(struct cdce_softc *sc)
USETW(req.wValue, 0);
req.wIndex[0] = sc->sc_ifaces_index[1];
req.wIndex[1] = 0;
- USETW(req.wLength, 4);
- USETDW(value, sc->sc_ncm.rx_max);
+
+ if (ufd != NULL &&
+ (ufd->bmNetworkCapabilities & UCDC_NCM_CAP_MAX_DGRAM)) {
+ USETW(req.wLength, 8);
+ USETDW(value, sc->sc_ncm.rx_max);
+ USETW(value + 4, (CDCE_NCM_SUBFRAMES_MAX - 1));
+ USETW(value + 6, 0);
+ } else {
+ USETW(req.wLength, 4);
+ USETDW(value, sc->sc_ncm.rx_max);
+ }
err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req,
&value, 0, NULL, 1000 /* ms */);
@@ -567,7 +613,7 @@ alloc_transfers:
} else {
- bzero(sc->sc_ue.ue_eaddr, sizeof(sc->sc_ue.ue_eaddr));
+ memset(sc->sc_ue.ue_eaddr, 0, sizeof(sc->sc_ue.ue_eaddr));
for (i = 0; i != (ETHER_ADDR_LEN * 2); i++) {
@@ -983,6 +1029,18 @@ cdce_handle_request(device_t dev,
}
#if CDCE_HAVE_NCM
+static void
+cdce_ncm_tx_zero(struct usb_page_cache *pc,
+ uint32_t start, uint32_t end)
+{
+ if (start >= CDCE_NCM_TX_MAXLEN)
+ return;
+ if (end > CDCE_NCM_TX_MAXLEN)
+ end = CDCE_NCM_TX_MAXLEN;
+
+ usbd_frame_zero(pc, start, end - start);
+}
+
static uint8_t
cdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index)
{
@@ -993,7 +1051,8 @@ cdce_ncm_fill_tx_frames(struct usb_xfer
uint32_t rem;
uint32_t offset;
uint32_t last_offset;
- uint32_t n;
+ uint16_t n;
+ uint8_t retval;
usbd_xfer_set_frame_offset(xfer, index * CDCE_NCM_TX_MAXLEN, index);
@@ -1003,11 +1062,17 @@ cdce_ncm_fill_tx_frames(struct usb_xfer
/* Store last valid offset before alignment */
last_offset = offset;
- /* Align offset correctly */
- offset = sc->sc_ncm.tx_remainder -
- ((0UL - offset) & (0UL - sc->sc_ncm.tx_modulus));
+ /* Align offset */
+ offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder,
+ offset, sc->sc_ncm.tx_modulus);
- for (n = 0; n != CDCE_NCM_SUBFRAMES_MAX; n++) {
+ /* Zero pad */
+ cdce_ncm_tx_zero(pc, last_offset, offset);
+
+ /* buffer full */
+ retval = 2;
+
+ for (n = 0; n != sc->sc_ncm.tx_nframe; n++) {
/* check if end of transmit buffer is reached */
@@ -1020,8 +1085,11 @@ cdce_ncm_fill_tx_frames(struct usb_xfer
IFQ_DRV_DEQUEUE(&(ifp->if_snd), m);
- if (m == NULL)
+ if (m == NULL) {
+ /* buffer not full */
+ retval = 1;
break;
+ }
if (m->m_pkthdr.len > rem) {
if (n == 0) {
@@ -1047,9 +1115,12 @@ cdce_ncm_fill_tx_frames(struct usb_xfer
/* Store last valid offset before alignment */
last_offset = offset;
- /* Align offset correctly */
- offset = sc->sc_ncm.tx_remainder -
- ((0UL - offset) & (0UL - sc->sc_ncm.tx_modulus));
+ /* Align offset */
+ offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder,
+ offset, sc->sc_ncm.tx_modulus);
+
+ /* Zero pad */
+ cdce_ncm_tx_zero(pc, last_offset, offset);
/*
* If there's a BPF listener, bounce a copy
@@ -1067,7 +1138,7 @@ cdce_ncm_fill_tx_frames(struct usb_xfer
}
if (n == 0)
- return (1);
+ return (0);
rem = (sizeof(sc->sc_ncm.dpt) + (4 * n) + 4);
@@ -1079,8 +1150,22 @@ cdce_ncm_fill_tx_frames(struct usb_xfer
USETW(sc->sc_ncm.dp[n].wFrameIndex, 0);
}
+ offset = last_offset;
+
+ /* Align offset */
+ offset = CDCE_NCM_ALIGN(0, offset, CDCE_NCM_TX_MINLEN);
+
+ /* Optimise, save bandwidth and force short termination */
+ if (offset >= sc->sc_ncm.tx_max)
+ offset = sc->sc_ncm.tx_max;
+ else
+ offset ++;
+
+ /* Zero pad */
+ cdce_ncm_tx_zero(pc, last_offset, offset);
+
/* set frame length */
- usbd_xfer_set_frame_len(xfer, index, last_offset);
+ usbd_xfer_set_frame_len(xfer, index, offset);
/* Fill out 16-bit header */
sc->sc_ncm.hdr.dwSignature[0] = 'N';
@@ -1088,7 +1173,7 @@ cdce_ncm_fill_tx_frames(struct usb_xfer
sc->sc_ncm.hdr.dwSignature[2] = 'M';
sc->sc_ncm.hdr.dwSignature[3] = 'H';
USETW(sc->sc_ncm.hdr.wHeaderLength, sizeof(sc->sc_ncm.hdr));
- USETW(sc->sc_ncm.hdr.wBlockLength, last_offset);
+ USETW(sc->sc_ncm.hdr.wBlockLength, offset);
USETW(sc->sc_ncm.hdr.wSequence, sc->sc_ncm.tx_seq);
USETW(sc->sc_ncm.hdr.wDptIndex, sizeof(sc->sc_ncm.hdr));
@@ -1106,7 +1191,7 @@ cdce_ncm_fill_tx_frames(struct usb_xfer
sizeof(sc->sc_ncm.dpt));
usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr) + sizeof(sc->sc_ncm.dpt),
&(sc->sc_ncm.dp), sizeof(sc->sc_ncm.dp));
- return (0);
+ return (retval);
}
static void
@@ -1115,6 +1200,7 @@ cdce_ncm_bulk_write_callback(struct usb_
struct cdce_softc *sc = usbd_xfer_softc(xfer);
struct ifnet *ifp = uether_getifp(&sc->sc_ue);
uint16_t x;
+ uint8_t temp;
int actlen;
int aframes;
@@ -1128,11 +1214,19 @@ cdce_ncm_bulk_write_callback(struct usb_
case USB_ST_SETUP:
for (x = 0; x != CDCE_NCM_TX_FRAMES_MAX; x++) {
- if (cdce_ncm_fill_tx_frames(xfer, x))
+ temp = cdce_ncm_fill_tx_frames(xfer, x);
+ if (temp == 0)
+ break;
+ if (temp == 1) {
+ x++;
break;
+ }
}
if (x != 0) {
+#ifdef USB_DEBUG
+ usbd_xfer_set_interval(xfer, cdce_tx_interval);
+#endif
usbd_xfer_set_frames(xfer, x);
usbd_transfer_submit(xfer);
}
Modified: stable/8/sys/dev/usb/net/if_cdcereg.h
==============================================================================
--- stable/8/sys/dev/usb/net/if_cdcereg.h Sun Nov 28 07:03:21 2010 (r215980)
+++ stable/8/sys/dev/usb/net/if_cdcereg.h Sun Nov 28 07:04:28 2010 (r215981)
@@ -38,7 +38,8 @@
#define CDCE_FRAMES_MAX 8 /* units */
#define CDCE_IND_SIZE_MAX 32 /* bytes */
-#define CDCE_NCM_TX_MAXLEN 2048UL /* bytes */
+#define CDCE_NCM_TX_MINLEN 512 /* bytes, must be power of two */
+#define CDCE_NCM_TX_MAXLEN (1UL << 14) /* bytes */
#define CDCE_NCM_TX_FRAMES_MAX 8 /* units */
#define CDCE_NCM_RX_MAXLEN (1UL << 14) /* bytes */
@@ -46,6 +47,10 @@
#define CDCE_NCM_SUBFRAMES_MAX 32 /* units */
+#define CDCE_NCM_ALIGN(rem,off,mod) \
+ ((uint32_t)(((uint32_t)(rem)) - \
+ ((uint32_t)((-(uint32_t)(off)) & (-(uint32_t)(mod))))))
+
#ifndef CDCE_HAVE_NCM
#define CDCE_HAVE_NCM 1
#endif
@@ -68,6 +73,7 @@ struct cdce_ncm {
uint16_t tx_modulus;
uint16_t tx_struct_align;
uint16_t tx_seq;
+ uint16_t tx_nframe;
};
struct cdce_softc {
Modified: stable/8/sys/dev/usb/usb_cdc.h
==============================================================================
--- stable/8/sys/dev/usb/usb_cdc.h Sun Nov 28 07:03:21 2010 (r215980)
+++ stable/8/sys/dev/usb/usb_cdc.h Sun Nov 28 07:04:28 2010 (r215981)
@@ -248,6 +248,7 @@ struct usb_ncm_func_descriptor {
#define UCDC_NCM_CAP_ENCAP 0x04
#define UCDC_NCM_CAP_MAX_DATA 0x08
#define UCDC_NCM_CAP_CRCMODE 0x10
+#define UCDC_NCM_CAP_MAX_DGRAM 0x20
} __packed;
/* Communications interface specific class request codes */
@@ -283,7 +284,7 @@ struct usb_ncm_parameters {
uWord wNdpOutDivisor;
uWord wNdpOutPayloadRemainder;
uWord wNdpOutAlignment;
- uWord wReserved26;
+ uWord wNtbOutMaxDatagrams;
} __packed;
/* Communications interface specific class notification codes */
More information about the svn-src-stable
mailing list