diff options
author | hselasky <hselasky@FreeBSD.org> | 2012-08-12 17:53:06 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2012-08-12 17:53:06 +0000 |
commit | ce0da37e7d071995cc8533b668360082f78cb329 (patch) | |
tree | 4ef3a2c09abbce548ca79a0652beee2be50d1199 /sys/dev/usb/usb_transfer.c | |
parent | 0b3ddf87a17ef869513d045700b673f056909ab2 (diff) | |
download | FreeBSD-src-ce0da37e7d071995cc8533b668360082f78cb329.zip FreeBSD-src-ce0da37e7d071995cc8533b668360082f78cb329.tar.gz |
Add support for the so-called streams feature of BULK endpoints
in SUPER-speed mode, USB 3.0.
This feature has not been tested yet, due to lack of hardware.
This feature is useful when implementing protocols like UASP,
USB attached SCSI which promises higher USB mass storage throughput.
This patch also implements support for hardware processing of endpoints
for increased performance. The switching to hardware processing
of an endpoint is done via a callback to the USB controller driver. The
stream feature is implemented like a variant of a hardware USB protocol.
USB controller drivers implementing device mode needs to be updated to
implement the new "xfer_stall" USB controller method and remove the
"xfer" argument from the "set_stall" method.
The API's toward existing USB drivers are preserved. To setup a USB transfer
in stream mode, set the "stream_id" field of the USB config structure to
the desired value.
The maximum number of BULK streams is currently hardcoded and limited to 8
via a define in usb_freebsd.h.
All USB drivers should be re-compiled after this change.
LibUSB will be updated next week to support streams mode. A new IOCTL to
setup BULK streams as already been implemented. The ugen device nodes
currently only supports stream ID zero.
The FreeBSD version has been bumped.
MFC after: 2 weeks
Diffstat (limited to 'sys/dev/usb/usb_transfer.c')
-rw-r--r-- | sys/dev/usb/usb_transfer.c | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c index b799897..e4cb5fb 100644 --- a/sys/dev/usb/usb_transfer.c +++ b/sys/dev/usb/usb_transfer.c @@ -358,7 +358,8 @@ usbd_transfer_setup_sub(struct usb_setup_params *parm) switch (type) { case UE_ISOCHRONOUS: case UE_INTERRUPT: - xfer->max_packet_count += (xfer->max_packet_size >> 11) & 3; + xfer->max_packet_count += + (xfer->max_packet_size >> 11) & 3; /* check for invalid max packet count */ if (xfer->max_packet_count > 3) @@ -387,7 +388,8 @@ usbd_transfer_setup_sub(struct usb_setup_params *parm) if (ecomp != NULL) { uint8_t mult; - mult = (ecomp->bmAttributes & 3) + 1; + mult = UE_GET_SS_ISO_MULT( + ecomp->bmAttributes) + 1; if (mult > 3) mult = 3; @@ -946,7 +948,20 @@ usbd_transfer_setup(struct usb_device *udev, ep = usbd_get_endpoint(udev, ifaces[setup->if_index], setup); - if ((ep == NULL) || (ep->methods == NULL)) { + /* + * Check that the USB PIPE is valid and that + * the endpoint mode is proper. + * + * Make sure we don't allocate a streams + * transfer when such a combination is not + * valid. + */ + if ((ep == NULL) || (ep->methods == NULL) || + ((ep->ep_mode != USB_EP_MODE_STREAMS) && + (ep->ep_mode != USB_EP_MODE_DEFAULT)) || + (setup->stream_id != 0 && + (setup->stream_id >= USB_MAX_EP_STREAMS || + (ep->ep_mode != USB_EP_MODE_STREAMS)))) { if (setup->flags.no_pipe_ok) continue; if ((setup->usb_mode != USB_MODE_DUAL) && @@ -990,6 +1005,9 @@ usbd_transfer_setup(struct usb_device *udev, /* set transfer endpoint pointer */ xfer->endpoint = ep; + /* set transfer stream ID */ + xfer->stream_id = setup->stream_id; + parm.size[0] += sizeof(xfer[0]); parm.methods = xfer->endpoint->methods; parm.curr_xfer = xfer; @@ -1575,7 +1593,8 @@ usbd_transfer_submit(struct usb_xfer *xfer) USB_BUS_LOCK(bus); xfer->flags_int.can_cancel_immed = 1; /* start the transfer */ - usb_command_wrapper(&xfer->endpoint->endpoint_q, xfer); + usb_command_wrapper(&xfer->endpoint-> + endpoint_q[xfer->stream_id], xfer); USB_BUS_UNLOCK(bus); return; } @@ -1696,7 +1715,7 @@ usbd_pipe_enter(struct usb_xfer *xfer) } /* start the transfer */ - usb_command_wrapper(&ep->endpoint_q, xfer); + usb_command_wrapper(&ep->endpoint_q[xfer->stream_id], xfer); USB_BUS_UNLOCK(xfer->xroot->bus); } @@ -1817,8 +1836,9 @@ usbd_transfer_stop(struct usb_xfer *xfer) * If the current USB transfer is completing we need * to start the next one: */ - if (ep->endpoint_q.curr == xfer) { - usb_command_wrapper(&ep->endpoint_q, NULL); + if (ep->endpoint_q[xfer->stream_id].curr == xfer) { + usb_command_wrapper( + &ep->endpoint_q[xfer->stream_id], NULL); } } @@ -2533,7 +2553,7 @@ usbd_pipe_start(struct usb_xfer_queue *pq) if (udev->flags.usb_mode == USB_MODE_DEVICE) { (udev->bus->methods->set_stall) ( - udev, NULL, ep, &did_stall); + udev, ep, &did_stall); } else if (udev->ctrl_xfer[1]) { info = udev->ctrl_xfer[1]->xroot; usb_proc_msignal( @@ -2800,10 +2820,11 @@ usbd_callback_wrapper_sub(struct usb_xfer *xfer) * next one: */ USB_BUS_LOCK(bus); - if (ep->endpoint_q.curr == xfer) { - usb_command_wrapper(&ep->endpoint_q, NULL); + if (ep->endpoint_q[xfer->stream_id].curr == xfer) { + usb_command_wrapper(&ep->endpoint_q[xfer->stream_id], NULL); - if (ep->endpoint_q.curr || TAILQ_FIRST(&ep->endpoint_q.head)) { + if (ep->endpoint_q[xfer->stream_id].curr != NULL || + TAILQ_FIRST(&ep->endpoint_q[xfer->stream_id].head) != NULL) { /* there is another USB transfer waiting */ } else { /* this is the last USB transfer */ |