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>