summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2012-08-12 17:53:06 +0000
committerhselasky <hselasky@FreeBSD.org>2012-08-12 17:53:06 +0000
commitce0da37e7d071995cc8533b668360082f78cb329 (patch)
tree4ef3a2c09abbce548ca79a0652beee2be50d1199 /sys/dev
parent0b3ddf87a17ef869513d045700b673f056909ab2 (diff)
downloadFreeBSD-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')
-rw-r--r--sys/dev/usb/controller/at91dci.c14
-rw-r--r--sys/dev/usb/controller/atmegadci.c13
-rw-r--r--sys/dev/usb/controller/avr32dci.c13
-rw-r--r--sys/dev/usb/controller/dwc_otg.c13
-rw-r--r--sys/dev/usb/controller/musb_otg.c13
-rw-r--r--sys/dev/usb/controller/uss820dci.c13
-rw-r--r--sys/dev/usb/controller/xhci.c123
-rw-r--r--sys/dev/usb/controller/xhci.h19
-rw-r--r--sys/dev/usb/usb.h20
-rw-r--r--sys/dev/usb/usb_controller.h7
-rw-r--r--sys/dev/usb/usb_core.h1
-rw-r--r--sys/dev/usb/usb_debug.c6
-rw-r--r--sys/dev/usb/usb_device.c87
-rw-r--r--sys/dev/usb/usb_freebsd.h2
-rw-r--r--sys/dev/usb/usb_generic.c6
-rw-r--r--sys/dev/usb/usb_hub.c8
-rw-r--r--sys/dev/usb/usb_ioctl.h6
-rw-r--r--sys/dev/usb/usb_request.c9
-rw-r--r--sys/dev/usb/usb_transfer.c43
-rw-r--r--sys/dev/usb/usbdi.h12
20 files changed, 325 insertions, 103 deletions
diff --git a/sys/dev/usb/controller/at91dci.c b/sys/dev/usb/controller/at91dci.c
index e7d5e6e..d8fdc63 100644
--- a/sys/dev/usb/controller/at91dci.c
+++ b/sys/dev/usb/controller/at91dci.c
@@ -1226,7 +1226,14 @@ at91dci_device_done(struct usb_xfer *xfer, usb_error_t error)
}
static void
-at91dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
+at91dci_xfer_stall(struct usb_xfer *xfer)
+{
+ USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
+ at91dci_device_done(xfer, USB_ERR_STALLED);
+}
+
+static void
+at91dci_set_stall(struct usb_device *udev,
struct usb_endpoint *ep, uint8_t *did_stall)
{
struct at91dci_softc *sc;
@@ -1237,10 +1244,6 @@ at91dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
DPRINTFN(5, "endpoint=%p\n", ep);
- if (xfer) {
- /* cancel any ongoing transfers */
- at91dci_device_done(xfer, USB_ERR_STALLED);
- }
/* set FORCESTALL */
sc = AT9100_DCI_BUS2SC(udev->bus);
csr_reg = (ep->edesc->bEndpointAddress & UE_ADDR);
@@ -2332,6 +2335,7 @@ struct usb_bus_methods at91dci_bus_methods =
.xfer_unsetup = &at91dci_xfer_unsetup,
.get_hw_ep_profile = &at91dci_get_hw_ep_profile,
.set_stall = &at91dci_set_stall,
+ .xfer_stall = &at91dci_xfer_stall,
.clear_stall = &at91dci_clear_stall,
.roothub_exec = &at91dci_roothub_exec,
.xfer_poll = &at91dci_do_poll,
diff --git a/sys/dev/usb/controller/atmegadci.c b/sys/dev/usb/controller/atmegadci.c
index 700ca8f..d8f9111 100644
--- a/sys/dev/usb/controller/atmegadci.c
+++ b/sys/dev/usb/controller/atmegadci.c
@@ -1113,7 +1113,13 @@ atmegadci_device_done(struct usb_xfer *xfer, usb_error_t error)
}
static void
-atmegadci_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
+atmegadci_xfer_stall(struct usb_xfer *xfer)
+{
+ atmegadci_device_done(xfer, USB_ERR_STALLED);
+}
+
+static void
+atmegadci_set_stall(struct usb_device *udev,
struct usb_endpoint *ep, uint8_t *did_stall)
{
struct atmegadci_softc *sc;
@@ -1123,10 +1129,6 @@ atmegadci_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
DPRINTFN(5, "endpoint=%p\n", ep);
- if (xfer) {
- /* cancel any ongoing transfers */
- atmegadci_device_done(xfer, USB_ERR_STALLED);
- }
sc = ATMEGA_BUS2SC(udev->bus);
/* get endpoint number */
ep_no = (ep->edesc->bEndpointAddress & UE_ADDR);
@@ -2151,6 +2153,7 @@ struct usb_bus_methods atmegadci_bus_methods =
.xfer_setup = &atmegadci_xfer_setup,
.xfer_unsetup = &atmegadci_xfer_unsetup,
.get_hw_ep_profile = &atmegadci_get_hw_ep_profile,
+ .xfer_stall = &atmegadci_xfer_stall,
.set_stall = &atmegadci_set_stall,
.clear_stall = &atmegadci_clear_stall,
.roothub_exec = &atmegadci_roothub_exec,
diff --git a/sys/dev/usb/controller/avr32dci.c b/sys/dev/usb/controller/avr32dci.c
index 9f9cd5d..7a672f6 100644
--- a/sys/dev/usb/controller/avr32dci.c
+++ b/sys/dev/usb/controller/avr32dci.c
@@ -1080,7 +1080,13 @@ avr32dci_device_done(struct usb_xfer *xfer, usb_error_t error)
}
static void
-avr32dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
+avr32dci_xfer_stall(struct usb_xfer *xfer)
+{
+ avr32dci_device_done(xfer, USB_ERR_STALLED);
+}
+
+static void
+avr32dci_set_stall(struct usb_device *udev,
struct usb_endpoint *pipe, uint8_t *did_stall)
{
struct avr32dci_softc *sc;
@@ -1090,10 +1096,6 @@ avr32dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
DPRINTFN(5, "pipe=%p\n", pipe);
- if (xfer) {
- /* cancel any ongoing transfers */
- avr32dci_device_done(xfer, USB_ERR_STALLED);
- }
sc = AVR32_BUS2SC(udev->bus);
/* get endpoint number */
ep_no = (pipe->edesc->bEndpointAddress & UE_ADDR);
@@ -2096,6 +2098,7 @@ struct usb_bus_methods avr32dci_bus_methods =
.xfer_setup = &avr32dci_xfer_setup,
.xfer_unsetup = &avr32dci_xfer_unsetup,
.get_hw_ep_profile = &avr32dci_get_hw_ep_profile,
+ .xfer_stall = &avr32dci_xfer_stall,
.set_stall = &avr32dci_set_stall,
.clear_stall = &avr32dci_clear_stall,
.roothub_exec = &avr32dci_roothub_exec,
diff --git a/sys/dev/usb/controller/dwc_otg.c b/sys/dev/usb/controller/dwc_otg.c
index f3ef19a..e5310f2 100644
--- a/sys/dev/usb/controller/dwc_otg.c
+++ b/sys/dev/usb/controller/dwc_otg.c
@@ -1524,7 +1524,13 @@ dwc_otg_device_done(struct usb_xfer *xfer, usb_error_t error)
}
static void
-dwc_otg_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
+dwc_otg_xfer_stall(struct usb_xfer *xfer)
+{
+ dwc_otg_device_done(xfer, USB_ERR_STALLED);
+}
+
+static void
+dwc_otg_set_stall(struct usb_device *udev,
struct usb_endpoint *ep, uint8_t *did_stall)
{
struct dwc_otg_softc *sc;
@@ -1534,10 +1540,6 @@ dwc_otg_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
- if (xfer) {
- /* cancel any ongoing transfers */
- dwc_otg_device_done(xfer, USB_ERR_STALLED);
- }
sc = DWC_OTG_BUS2SC(udev->bus);
/* get endpoint address */
@@ -2625,6 +2627,7 @@ struct usb_bus_methods dwc_otg_bus_methods =
.xfer_setup = &dwc_otg_xfer_setup,
.xfer_unsetup = &dwc_otg_xfer_unsetup,
.get_hw_ep_profile = &dwc_otg_get_hw_ep_profile,
+ .xfer_stall = &dwc_otg_xfer_stall,
.set_stall = &dwc_otg_set_stall,
.clear_stall = &dwc_otg_clear_stall,
.roothub_exec = &dwc_otg_roothub_exec,
diff --git a/sys/dev/usb/controller/musb_otg.c b/sys/dev/usb/controller/musb_otg.c
index db0d54f..858cd0f 100644
--- a/sys/dev/usb/controller/musb_otg.c
+++ b/sys/dev/usb/controller/musb_otg.c
@@ -1472,7 +1472,13 @@ musbotg_device_done(struct usb_xfer *xfer, usb_error_t error)
}
static void
-musbotg_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
+musbotg_xfer_stall(struct usb_xfer *xfer)
+{
+ musbotg_device_done(xfer, USB_ERR_STALLED);
+}
+
+static void
+musbotg_set_stall(struct usb_device *udev,
struct usb_endpoint *ep, uint8_t *did_stall)
{
struct musbotg_softc *sc;
@@ -1482,10 +1488,6 @@ musbotg_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
DPRINTFN(4, "endpoint=%p\n", ep);
- if (xfer) {
- /* cancel any ongoing transfers */
- musbotg_device_done(xfer, USB_ERR_STALLED);
- }
/* set FORCESTALL */
sc = MUSBOTG_BUS2SC(udev->bus);
@@ -2801,6 +2803,7 @@ struct usb_bus_methods musbotg_bus_methods =
.xfer_setup = &musbotg_xfer_setup,
.xfer_unsetup = &musbotg_xfer_unsetup,
.get_hw_ep_profile = &musbotg_get_hw_ep_profile,
+ .xfer_stall = &musbotg_xfer_stall,
.set_stall = &musbotg_set_stall,
.clear_stall = &musbotg_clear_stall,
.roothub_exec = &musbotg_roothub_exec,
diff --git a/sys/dev/usb/controller/uss820dci.c b/sys/dev/usb/controller/uss820dci.c
index 19229f8..5bd479d 100644
--- a/sys/dev/usb/controller/uss820dci.c
+++ b/sys/dev/usb/controller/uss820dci.c
@@ -1210,7 +1210,13 @@ uss820dci_device_done(struct usb_xfer *xfer, usb_error_t error)
}
static void
-uss820dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
+uss820dci_xfer_stall(struct usb_xfer *xfer)
+{
+ uss820dci_device_done(xfer, USB_ERR_STALLED);
+}
+
+static void
+uss820dci_set_stall(struct usb_device *udev,
struct usb_endpoint *ep, uint8_t *did_stall)
{
struct uss820dci_softc *sc;
@@ -1223,10 +1229,6 @@ uss820dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
DPRINTFN(5, "endpoint=%p\n", ep);
- if (xfer) {
- /* cancel any ongoing transfers */
- uss820dci_device_done(xfer, USB_ERR_STALLED);
- }
/* set FORCESTALL */
sc = USS820_DCI_BUS2SC(udev->bus);
ep_no = (ep->edesc->bEndpointAddress & UE_ADDR);
@@ -2385,6 +2387,7 @@ struct usb_bus_methods uss820dci_bus_methods =
.xfer_setup = &uss820dci_xfer_setup,
.xfer_unsetup = &uss820dci_xfer_unsetup,
.get_hw_ep_profile = &uss820dci_get_hw_ep_profile,
+ .xfer_stall = &uss820dci_xfer_stall,
.set_stall = &uss820dci_set_stall,
.clear_stall = &uss820dci_clear_stall,
.roothub_exec = &uss820dci_roothub_exec,
diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c
index 1a4e432..a20d7fa 100644
--- a/sys/dev/usb/controller/xhci.c
+++ b/sys/dev/usb/controller/xhci.c
@@ -128,7 +128,7 @@ static usb_proc_callback_t xhci_configure_msg;
static usb_error_t xhci_configure_device(struct usb_device *);
static usb_error_t xhci_configure_endpoint(struct usb_device *,
struct usb_endpoint_descriptor *, uint64_t, uint16_t,
- uint8_t, uint8_t, uint8_t, uint16_t, uint16_t);
+ uint8_t, uint8_t, uint8_t, uint16_t, uint16_t, uint8_t);
static usb_error_t xhci_configure_mask(struct usb_device *,
uint32_t, uint8_t);
static usb_error_t xhci_cmd_evaluate_ctx(struct xhci_softc *,
@@ -1245,7 +1245,7 @@ xhci_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t address)
&udev->ctrl_ep_desc);
err = xhci_configure_endpoint(udev,
&udev->ctrl_ep_desc, pepext->physaddr,
- 0, 1, 1, 0, mps, mps);
+ 0, 1, 1, 0, mps, mps, USB_EP_MODE_DEFAULT);
if (err != 0) {
DPRINTF("Could not configure default endpoint\n");
@@ -1800,7 +1800,8 @@ xhci_setup_generic_chain(struct usb_xfer *xfer)
/* compute multiplier for ISOCHRONOUS transfers */
mult = xfer->endpoint->ecomp ?
- (xfer->endpoint->ecomp->bmAttributes & 3) : 0;
+ UE_GET_SS_ISO_MULT(xfer->endpoint->ecomp->bmAttributes)
+ : 0;
/* check for USB 2.0 multiplier */
if (mult == 0) {
mult = (xfer->endpoint->edesc->
@@ -2055,7 +2056,8 @@ static usb_error_t
xhci_configure_endpoint(struct usb_device *udev,
struct usb_endpoint_descriptor *edesc, uint64_t ring_addr,
uint16_t interval, uint8_t max_packet_count, uint8_t mult,
- uint8_t fps_shift, uint16_t max_packet_size, uint16_t max_frame_size)
+ uint8_t fps_shift, uint16_t max_packet_size,
+ uint16_t max_frame_size, uint8_t ep_mode)
{
struct usb_page_search buf_inp;
struct xhci_softc *sc = XHCI_BUS2SC(udev->bus);
@@ -2090,9 +2092,20 @@ xhci_configure_endpoint(struct usb_device *udev,
if (mult == 0)
return (USB_ERR_BAD_BUFSIZE);
- temp = XHCI_EPCTX_0_EPSTATE_SET(0) |
- XHCI_EPCTX_0_MAXP_STREAMS_SET(0) |
- XHCI_EPCTX_0_LSA_SET(0);
+ if (ep_mode == USB_EP_MODE_STREAMS) {
+ temp = XHCI_EPCTX_0_EPSTATE_SET(0) |
+ XHCI_EPCTX_0_MAXP_STREAMS_SET(XHCI_MAX_STREAMS_LOG - 1) |
+ XHCI_EPCTX_0_LSA_SET(1);
+
+ ring_addr += sizeof(struct xhci_trb) *
+ XHCI_MAX_TRANSFERS * XHCI_MAX_STREAMS;
+ } else {
+ temp = XHCI_EPCTX_0_EPSTATE_SET(0) |
+ XHCI_EPCTX_0_MAXP_STREAMS_SET(0) |
+ XHCI_EPCTX_0_LSA_SET(0);
+
+ ring_addr |= XHCI_EPCTX_2_DCS_SET(1);
+ }
switch (udev->speed) {
case USB_SPEED_FULL:
@@ -2160,9 +2173,6 @@ xhci_configure_endpoint(struct usb_device *udev,
temp |= XHCI_EPCTX_1_EPTYPE_SET(4);
xhci_ctx_set_le32(sc, &pinp->ctx_ep[epno - 1].dwEpCtx1, temp);
-
- ring_addr |= XHCI_EPCTX_2_DCS_SET(1);
-
xhci_ctx_set_le64(sc, &pinp->ctx_ep[epno - 1].qwEpCtx2, ring_addr);
switch (edesc->bmAttributes & UE_XFERTYPE) {
@@ -2195,21 +2205,42 @@ xhci_configure_endpoint_by_xfer(struct usb_xfer *xfer)
{
struct xhci_endpoint_ext *pepext;
struct usb_endpoint_ss_comp_descriptor *ecomp;
+ usb_stream_t x;
pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
xfer->endpoint->edesc);
ecomp = xfer->endpoint->ecomp;
- pepext->trb[0].dwTrb3 = 0; /* halt any transfers */
+ for (x = 0; x != XHCI_MAX_STREAMS; x++) {
+ uint64_t temp;
+
+ /* halt any transfers */
+ pepext->trb[x * XHCI_MAX_TRANSFERS].dwTrb3 = 0;
+
+ /* compute start of TRB ring for stream "x" */
+ temp = pepext->physaddr +
+ (x * XHCI_MAX_TRANSFERS * sizeof(struct xhci_trb)) +
+ XHCI_SCTX_0_SCT_SEC_TR_RING;
+
+ /* make tree structure */
+ pepext->trb[(XHCI_MAX_TRANSFERS *
+ XHCI_MAX_STREAMS) + x].qwTrb0 = htole64(temp);
+
+ /* reserved fields */
+ pepext->trb[(XHCI_MAX_TRANSFERS *
+ XHCI_MAX_STREAMS) + x].dwTrb2 = 0;
+ pepext->trb[(XHCI_MAX_TRANSFERS *
+ XHCI_MAX_STREAMS) + x].dwTrb3 = 0;
+ }
usb_pc_cpu_flush(pepext->page_cache);
return (xhci_configure_endpoint(xfer->xroot->udev,
xfer->endpoint->edesc, pepext->physaddr,
xfer->interval, xfer->max_packet_count,
- (ecomp != NULL) ? (ecomp->bmAttributes & 3) + 1 : 1,
+ (ecomp != NULL) ? UE_GET_SS_ISO_MULT(ecomp->bmAttributes) + 1 : 1,
usbd_xfer_get_fps_shift(xfer), xfer->max_packet_size,
- xfer->max_frame_size));
+ xfer->max_frame_size, xfer->endpoint->ep_mode));
}
static usb_error_t
@@ -2500,7 +2531,8 @@ xhci_get_endpoint_ext(struct usb_device *udev, struct usb_endpoint_descriptor *e
pc = &sc->sc_hw.devs[index].endpoint_pc;
- usbd_get_page(pc, (uintptr_t)&((struct xhci_dev_endpoint_trbs *)0)->trb[epno][0], &buf_ep);
+ usbd_get_page(pc, (uintptr_t)&((struct xhci_dev_endpoint_trbs *)0)->
+ trb[epno][0], &buf_ep);
pepext = &sc->sc_hw.devs[index].endp[epno];
pepext->page_cache = pc;
@@ -2539,7 +2571,7 @@ xhci_transfer_remove(struct usb_xfer *xfer, usb_error_t error)
pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
xfer->endpoint->edesc);
- pepext->trb_used--;
+ pepext->trb_used[xfer->stream_id]--;
pepext->xfer[xfer->qh_pos] = NULL;
@@ -2557,12 +2589,15 @@ xhci_transfer_insert(struct usb_xfer *xfer)
struct xhci_td *td_last;
struct xhci_endpoint_ext *pepext;
uint64_t addr;
+ usb_stream_t id;
uint8_t i;
uint8_t inext;
uint8_t trb_limit;
DPRINTFN(8, "\n");
+ id = xfer->stream_id;
+
/* check if already inserted */
if (xfer->flags_int.bandwidth_reclaimed) {
DPRINTFN(8, "Already in schedule\n");
@@ -2588,7 +2623,7 @@ xhci_transfer_insert(struct usb_xfer *xfer)
break;
}
- if (pepext->trb_used >= trb_limit) {
+ if (pepext->trb_used[id] >= trb_limit) {
DPRINTFN(8, "Too many TDs queued.\n");
return (USB_ERR_NOMEM);
}
@@ -2605,10 +2640,10 @@ xhci_transfer_insert(struct usb_xfer *xfer)
return (0);
}
- pepext->trb_used++;
+ pepext->trb_used[id]++;
/* get current TRB index */
- i = pepext->trb_index;
+ i = pepext->trb_index[id];
/* get next TRB index */
inext = (i + 1);
@@ -2617,8 +2652,12 @@ xhci_transfer_insert(struct usb_xfer *xfer)
if (inext >= (XHCI_MAX_TRANSFERS - 1))
inext = 0;
+ /* offset for stream */
+ i += id * XHCI_MAX_TRANSFERS;
+ inext += id * XHCI_MAX_TRANSFERS;
+
/* compute terminating return address */
- addr += inext * sizeof(struct xhci_trb);
+ addr += (inext * sizeof(struct xhci_trb));
/* update next pointer of last link TRB */
td_last->td_trb[td_last->ntrb].qwTrb0 = htole64(addr);
@@ -2662,7 +2701,7 @@ xhci_transfer_insert(struct usb_xfer *xfer)
xfer->flags_int.bandwidth_reclaimed = 1;
- pepext->trb_index = inext;
+ pepext->trb_index[id] = inext;
xhci_endpoint_doorbell(xfer);
@@ -2750,12 +2789,12 @@ xhci_device_generic_close(struct usb_xfer *xfer)
static void
xhci_device_generic_multi_enter(struct usb_endpoint *ep,
- struct usb_xfer *enter_xfer)
+ usb_stream_t stream_id, struct usb_xfer *enter_xfer)
{
struct usb_xfer *xfer;
/* check if there is a current transfer */
- xfer = ep->endpoint_q.curr;
+ xfer = ep->endpoint_q[stream_id].curr;
if (xfer == NULL)
return;
@@ -2767,7 +2806,7 @@ xhci_device_generic_multi_enter(struct usb_endpoint *ep,
if (!xfer->flags_int.bandwidth_reclaimed)
return;
- xfer = TAILQ_FIRST(&ep->endpoint_q.head);
+ xfer = TAILQ_FIRST(&ep->endpoint_q[stream_id].head);
if (xfer == NULL) {
/*
* In case of enter we have to consider that the
@@ -2792,7 +2831,8 @@ xhci_device_generic_enter(struct usb_xfer *xfer)
/* setup TD's and QH */
xhci_setup_generic_chain(xfer);
- xhci_device_generic_multi_enter(xfer->endpoint, xfer);
+ xhci_device_generic_multi_enter(xfer->endpoint,
+ xfer->stream_id, xfer);
}
static void
@@ -2804,7 +2844,8 @@ xhci_device_generic_start(struct usb_xfer *xfer)
xhci_transfer_insert(xfer);
/* try to multi buffer */
- xhci_device_generic_multi_enter(xfer->endpoint, NULL);
+ xhci_device_generic_multi_enter(xfer->endpoint,
+ xfer->stream_id, NULL);
/* add transfer last on interrupt queue */
usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
@@ -3465,6 +3506,7 @@ xhci_configure_reset_endpoint(struct usb_xfer *xfer)
struct usb_endpoint_descriptor *edesc;
struct usb_page_cache *pcinp;
usb_error_t err;
+ usb_stream_t stream_id;
uint8_t index;
uint8_t epno;
@@ -3481,6 +3523,7 @@ xhci_configure_reset_endpoint(struct usb_xfer *xfer)
edesc = xfer->endpoint->edesc;
epno = edesc->bEndpointAddress;
+ stream_id = xfer->stream_id;
if ((edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL)
epno |= UE_DIR_IN;
@@ -3516,8 +3559,10 @@ xhci_configure_reset_endpoint(struct usb_xfer *xfer)
if (err != 0)
DPRINTF("Could not reset endpoint %u\n", epno);
- err = xhci_cmd_set_tr_dequeue_ptr(sc, pepext->physaddr |
- XHCI_EPCTX_2_DCS_SET(1), 0, epno, index);
+ err = xhci_cmd_set_tr_dequeue_ptr(sc,
+ (pepext->physaddr + (stream_id * sizeof(struct xhci_trb) *
+ XHCI_MAX_TRANSFERS)) | XHCI_EPCTX_2_DCS_SET(1),
+ stream_id, epno, index);
if (err != 0)
DPRINTF("Could not set dequeue ptr for endpoint %u\n", epno);
@@ -3615,7 +3660,8 @@ restart:
/* check if halted is still cleared */
if (pepext->trb_halted == 0) {
pepext->trb_running = 1;
- pepext->trb_index = 0;
+ memset(pepext->trb_index, 0,
+ sizeof(pepext->trb_index));
}
goto restart;
}
@@ -3639,7 +3685,8 @@ restart:
xhci_transfer_insert(xfer);
/* try to multi buffer */
- xhci_device_generic_multi_enter(xfer->endpoint, NULL);
+ xhci_device_generic_multi_enter(xfer->endpoint,
+ xfer->stream_id, NULL);
}
}
@@ -3946,6 +3993,23 @@ xhci_device_state_change(struct usb_device *udev)
XHCI_CMD_UNLOCK(sc);
}
+static usb_error_t
+xhci_set_endpoint_mode(struct usb_device *udev, struct usb_endpoint *ep,
+ uint8_t ep_mode)
+{
+ switch (ep_mode) {
+ case USB_EP_MODE_DEFAULT:
+ return (0);
+ case USB_EP_MODE_STREAMS:
+ if ((ep->edesc->bmAttributes & UE_XFERTYPE) != UE_BULK ||
+ udev->speed != USB_SPEED_SUPER)
+ return (USB_ERR_INVAL);
+ return (0);
+ default:
+ return (USB_ERR_INVAL);
+ }
+}
+
struct usb_bus_methods xhci_bus_methods = {
.endpoint_init = xhci_ep_init,
.endpoint_uninit = xhci_ep_uninit,
@@ -3964,4 +4028,5 @@ struct usb_bus_methods xhci_bus_methods = {
.clear_stall = xhci_ep_clear_stall,
.device_state_change = xhci_device_state_change,
.set_hw_power_sleep = xhci_set_hw_power_sleep,
+ .set_endpoint_mode = xhci_set_endpoint_mode,
};
diff --git a/sys/dev/usb/controller/xhci.h b/sys/dev/usb/controller/xhci.h
index 14afcaf..f6d467f 100644
--- a/sys/dev/usb/controller/xhci.h
+++ b/sys/dev/usb/controller/xhci.h
@@ -35,7 +35,15 @@
#define XHCI_MAX_COMMANDS (16 * 1)
#define XHCI_MAX_RSEG 1
#define XHCI_MAX_TRANSFERS 4
-
+#if USB_MAX_EP_STREAMS == 8
+#define XHCI_MAX_STREAMS 8
+#define XHCI_MAX_STREAMS_LOG 3
+#elif USB_MAX_EP_STREAMS == 1
+#define XHCI_MAX_STREAMS 1
+#define XHCI_MAX_STREAMS_LOG 0
+#else
+#error "The USB_MAX_EP_STREAMS value is not supported."
+#endif
#define XHCI_DEV_CTX_ADDR_ALIGN 64 /* bytes */
#define XHCI_DEV_CTX_ALIGN 64 /* bytes */
#define XHCI_INPUT_CTX_ALIGN 64 /* bytes */
@@ -307,7 +315,8 @@ struct xhci_trb {
} __aligned(4);
struct xhci_dev_endpoint_trbs {
- struct xhci_trb trb[XHCI_MAX_ENDPOINTS][XHCI_MAX_TRANSFERS];
+ struct xhci_trb trb[XHCI_MAX_ENDPOINTS]
+ [(XHCI_MAX_STREAMS * XHCI_MAX_TRANSFERS) + XHCI_MAX_STREAMS];
};
#define XHCI_TD_PAGE_NBUF 17 /* units, room enough for 64Kbytes */
@@ -353,11 +362,11 @@ struct xhci_hw_root {
struct xhci_endpoint_ext {
struct xhci_trb *trb;
- struct usb_xfer *xfer[XHCI_MAX_TRANSFERS - 1];
+ struct usb_xfer *xfer[XHCI_MAX_TRANSFERS * XHCI_MAX_STREAMS];
struct usb_page_cache *page_cache;
uint64_t physaddr;
- uint8_t trb_used;
- uint8_t trb_index;
+ uint8_t trb_used[XHCI_MAX_STREAMS];
+ uint8_t trb_index[XHCI_MAX_STREAMS];
uint8_t trb_halted;
uint8_t trb_running;
};
diff --git a/sys/dev/usb/usb.h b/sys/dev/usb/usb.h
index 38ddc2d..e6fb5e5 100644
--- a/sys/dev/usb/usb.h
+++ b/sys/dev/usb/usb.h
@@ -546,6 +546,8 @@ struct usb_endpoint_ss_comp_descriptor {
uByte bDescriptorType;
uByte bMaxBurst;
uByte bmAttributes;
+#define UE_GET_BULK_STREAMS(x) ((x) & 0x0F)
+#define UE_GET_SS_ISO_MULT(x) ((x) & 0x03)
uWord wBytesPerInterval;
} __packed;
typedef struct usb_endpoint_ss_comp_descriptor
@@ -744,7 +746,7 @@ enum usb_revision {
#define USB_REV_MAX (USB_REV_3_0+1)
/*
- * Supported host contoller modes.
+ * Supported host controller modes.
*/
enum usb_hc_mode {
USB_MODE_HOST, /* initiates transfers */
@@ -754,7 +756,7 @@ enum usb_hc_mode {
#define USB_MODE_MAX (USB_MODE_DUAL+1)
/*
- * The "USB_MODE" macros defines all the supported device states.
+ * The "USB_STATE" enums define all the supported device states.
*/
enum usb_dev_state {
USB_STATE_DETACHED,
@@ -764,4 +766,18 @@ enum usb_dev_state {
USB_STATE_CONFIGURED,
};
#define USB_STATE_MAX (USB_STATE_CONFIGURED+1)
+
+/*
+ * The "USB_EP_MODE" macros define all the currently supported
+ * endpoint modes.
+ */
+enum usb_ep_mode {
+ USB_EP_MODE_DEFAULT,
+ USB_EP_MODE_STREAMS, /* USB3.0 specific */
+ USB_EP_MODE_HW_MASS_STORAGE,
+ USB_EP_MODE_HW_SERIAL,
+ USB_EP_MODE_HW_ETHERNET_CDC,
+ USB_EP_MODE_HW_ETHERNET_NCM,
+ USB_EP_MODE_MAX
+};
#endif /* _USB_STANDARD_H_ */
diff --git a/sys/dev/usb/usb_controller.h b/sys/dev/usb/usb_controller.h
index bbbf66b..6c14454 100644
--- a/sys/dev/usb/usb_controller.h
+++ b/sys/dev/usb/usb_controller.h
@@ -108,7 +108,8 @@ struct usb_bus_methods {
/* USB Device mode only - Mandatory */
void (*get_hw_ep_profile) (struct usb_device *udev, const struct usb_hw_ep_profile **ppf, uint8_t ep_addr);
- void (*set_stall) (struct usb_device *udev, struct usb_xfer *xfer, struct usb_endpoint *ep, uint8_t *did_stall);
+ void (*xfer_stall) (struct usb_xfer *xfer);
+ void (*set_stall) (struct usb_device *udev, struct usb_endpoint *ep, uint8_t *did_stall);
/* USB Device mode mandatory. USB Host mode optional. */
@@ -143,6 +144,10 @@ struct usb_bus_methods {
/* Optional for host mode */
usb_error_t (*set_address) (struct usb_device *, struct mtx *, uint16_t);
+
+ /* Optional for device and host mode */
+
+ usb_error_t (*set_endpoint_mode) (struct usb_device *, struct usb_endpoint *, uint8_t);
};
/*
diff --git a/sys/dev/usb/usb_core.h b/sys/dev/usb/usb_core.h
index 3dfd0d1..776cf17 100644
--- a/sys/dev/usb/usb_core.h
+++ b/sys/dev/usb/usb_core.h
@@ -151,6 +151,7 @@ struct usb_xfer {
usb_frcount_t nframes; /* number of USB frames to transfer */
usb_frcount_t aframes; /* actual number of USB frames
* transferred */
+ usb_stream_t stream_id; /* USB3.0 specific field */
uint16_t max_packet_size;
uint16_t max_frame_size;
diff --git a/sys/dev/usb/usb_debug.c b/sys/dev/usb/usb_debug.c
index a39d400..ae0db7f 100644
--- a/sys/dev/usb/usb_debug.c
+++ b/sys/dev/usb/usb_debug.c
@@ -113,10 +113,12 @@ void
usb_dump_queue(struct usb_endpoint *ep)
{
struct usb_xfer *xfer;
+ usb_stream_t x;
printf("usb_dump_queue: endpoint=%p xfer: ", ep);
- TAILQ_FOREACH(xfer, &ep->endpoint_q.head, wait_entry) {
- printf(" %p", xfer);
+ for (x = 0; x != USB_MAX_EP_STREAMS; x++) {
+ TAILQ_FOREACH(xfer, &ep->endpoint_q[x].head, wait_entry)
+ printf(" %p", xfer);
}
printf("\n");
}
diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c
index de5e7d7..407d2ea 100644
--- a/sys/dev/usb/usb_device.c
+++ b/sys/dev/usb/usb_device.c
@@ -355,7 +355,6 @@ usbd_interface_count(struct usb_device *udev, uint8_t *count)
return (USB_ERR_NORMAL_COMPLETION);
}
-
/*------------------------------------------------------------------------*
* usb_init_endpoint
*
@@ -370,6 +369,7 @@ usb_init_endpoint(struct usb_device *udev, uint8_t iface_index,
struct usb_endpoint *ep)
{
struct usb_bus_methods *methods;
+ usb_stream_t x;
methods = udev->bus->methods;
@@ -379,13 +379,26 @@ usb_init_endpoint(struct usb_device *udev, uint8_t iface_index,
ep->edesc = edesc;
ep->ecomp = ecomp;
ep->iface_index = iface_index;
- TAILQ_INIT(&ep->endpoint_q.head);
- ep->endpoint_q.command = &usbd_pipe_start;
+
+ /* setup USB stream queues */
+ for (x = 0; x != USB_MAX_EP_STREAMS; x++) {
+ TAILQ_INIT(&ep->endpoint_q[x].head);
+ ep->endpoint_q[x].command = &usbd_pipe_start;
+ }
/* the pipe is not supported by the hardware */
if (ep->methods == NULL)
return;
+ /* check for SUPER-speed streams mode endpoint */
+ if (udev->speed == USB_SPEED_SUPER && ecomp != NULL &&
+ (edesc->bmAttributes & UE_XFERTYPE) == UE_BULK &&
+ (UE_GET_BULK_STREAMS(ecomp->bmAttributes) != 0)) {
+ usbd_set_endpoint_mode(udev, ep, USB_EP_MODE_STREAMS);
+ } else {
+ usbd_set_endpoint_mode(udev, ep, USB_EP_MODE_DEFAULT);
+ }
+
/* clear stall, if any */
if (methods->clear_stall != NULL) {
USB_BUS_LOCK(udev->bus);
@@ -933,6 +946,7 @@ usbd_set_endpoint_stall(struct usb_device *udev, struct usb_endpoint *ep,
uint8_t do_stall)
{
struct usb_xfer *xfer;
+ usb_stream_t x;
uint8_t et;
uint8_t was_stalled;
@@ -975,18 +989,22 @@ usbd_set_endpoint_stall(struct usb_device *udev, struct usb_endpoint *ep,
if (do_stall || (!was_stalled)) {
if (!was_stalled) {
- /* lookup the current USB transfer, if any */
- xfer = ep->endpoint_q.curr;
- } else {
- xfer = NULL;
+ for (x = 0; x != USB_MAX_EP_STREAMS; x++) {
+ /* lookup the current USB transfer, if any */
+ xfer = ep->endpoint_q[x].curr;
+ if (xfer != NULL) {
+ /*
+ * The "xfer_stall" method
+ * will complete the USB
+ * transfer like in case of a
+ * timeout setting the error
+ * code "USB_ERR_STALLED".
+ */
+ (udev->bus->methods->xfer_stall) (xfer);
+ }
+ }
}
-
- /*
- * If "xfer" is non-NULL the "set_stall" method will
- * complete the USB transfer like in case of a timeout
- * setting the error code "USB_ERR_STALLED".
- */
- (udev->bus->methods->set_stall) (udev, xfer, ep, &do_stall);
+ (udev->bus->methods->set_stall) (udev, ep, &do_stall);
}
if (!do_stall) {
ep->toggle_next = 0; /* reset data toggle */
@@ -994,8 +1012,11 @@ usbd_set_endpoint_stall(struct usb_device *udev, struct usb_endpoint *ep,
(udev->bus->methods->clear_stall) (udev, ep);
- /* start up the current or next transfer, if any */
- usb_command_wrapper(&ep->endpoint_q, ep->endpoint_q.curr);
+ /* start the current or next transfer, if any */
+ for (x = 0; x != USB_MAX_EP_STREAMS; x++) {
+ usb_command_wrapper(&ep->endpoint_q[x],
+ ep->endpoint_q[x].curr);
+ }
}
USB_BUS_UNLOCK(udev->bus);
return (0);
@@ -2745,3 +2766,37 @@ usbd_add_dynamic_quirk(struct usb_device *udev, uint16_t quirk)
}
return (USB_ERR_NOMEM);
}
+
+/*
+ * The following function is used to select the endpoint mode. It
+ * should not be called outside enumeration context.
+ */
+
+usb_error_t
+usbd_set_endpoint_mode(struct usb_device *udev, struct usb_endpoint *ep,
+ uint8_t ep_mode)
+{
+ usb_error_t error;
+
+ sx_assert(&udev->enum_sx, SA_LOCKED);
+
+ if (udev->bus->methods->set_endpoint_mode != NULL) {
+ error = (udev->bus->methods->set_endpoint_mode) (
+ udev, ep, ep_mode);
+ } else if (ep_mode != USB_EP_MODE_DEFAULT) {
+ error = USB_ERR_INVAL;
+ } else {
+ error = 0;
+ }
+
+ /* only set new mode regardless of error */
+ ep->ep_mode = ep_mode;
+
+ return (error);
+}
+
+uint8_t
+usbd_get_endpoint_mode(struct usb_device *udev, struct usb_endpoint *ep)
+{
+ return (ep->ep_mode);
+}
diff --git a/sys/dev/usb/usb_freebsd.h b/sys/dev/usb/usb_freebsd.h
index 349e13e..42a54c5 100644
--- a/sys/dev/usb/usb_freebsd.h
+++ b/sys/dev/usb/usb_freebsd.h
@@ -60,6 +60,7 @@
#define USB_MAX_DEVICES 128 /* units */
#define USB_IFACE_MAX 32 /* units */
#define USB_FIFO_MAX 128 /* units */
+#define USB_MAX_EP_STREAMS 8 /* units */
#define USB_MAX_FS_ISOC_FRAMES_PER_XFER (120) /* units */
#define USB_MAX_HS_ISOC_FRAMES_PER_XFER (8*120) /* units */
@@ -76,5 +77,6 @@ typedef uint32_t usb_frcount_t; /* units */
typedef uint32_t usb_size_t; /* bytes */
typedef uint32_t usb_ticks_t; /* system defined */
typedef uint16_t usb_power_mask_t; /* see "USB_HW_POWER_XXX" */
+typedef uint16_t usb_stream_t; /* stream ID */
#endif /* _USB_FREEBSD_H_ */
diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c
index 5f156b1..8da4119 100644
--- a/sys/dev/usb/usb_generic.c
+++ b/sys/dev/usb/usb_generic.c
@@ -253,6 +253,7 @@ ugen_open_pipe_write(struct usb_fifo *f)
usb_config[0].type = ed->bmAttributes & UE_XFERTYPE;
usb_config[0].endpoint = ed->bEndpointAddress & UE_ADDR;
+ usb_config[0].stream_id = 0; /* XXX support more stream ID's */
usb_config[0].direction = UE_DIR_TX;
usb_config[0].interval = USB_DEFAULT_INTERVAL;
usb_config[0].flags.proxy_buffer = 1;
@@ -321,6 +322,7 @@ ugen_open_pipe_read(struct usb_fifo *f)
usb_config[0].type = ed->bmAttributes & UE_XFERTYPE;
usb_config[0].endpoint = ed->bEndpointAddress & UE_ADDR;
+ usb_config[0].stream_id = 0; /* XXX support more stream ID's */
usb_config[0].direction = UE_DIR_RX;
usb_config[0].interval = USB_DEFAULT_INTERVAL;
usb_config[0].flags.proxy_buffer = 1;
@@ -1391,6 +1393,7 @@ ugen_ioctl(struct usb_fifo *f, u_long cmd, void *addr, int fflags)
struct usb_fs_start *pstart;
struct usb_fs_stop *pstop;
struct usb_fs_open *popen;
+ struct usb_fs_open_streams *popen_streams;
struct usb_fs_close *pclose;
struct usb_fs_clear_stall_sync *pstall;
void *addr;
@@ -1455,6 +1458,7 @@ ugen_ioctl(struct usb_fifo *f, u_long cmd, void *addr, int fflags)
break;
case USB_FS_OPEN:
+ case USB_FS_OPEN_STREAMS:
if (u.popen->ep_index >= f->fs_ep_max) {
error = EINVAL;
break;
@@ -1506,6 +1510,8 @@ ugen_ioctl(struct usb_fifo *f, u_long cmd, void *addr, int fflags)
usb_config[0].frames = u.popen->max_frames;
usb_config[0].bufsize = u.popen->max_bufsize;
usb_config[0].usb_mode = USB_MODE_DUAL; /* both modes */
+ if (cmd == USB_FS_OPEN_STREAMS)
+ usb_config[0].stream_id = u.popen_streams->stream_id;
if (usb_config[0].type == UE_CONTROL) {
if (f->udev->flags.usb_mode != USB_MODE_HOST) {
diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c
index 85448b9..2f3dbe5 100644
--- a/sys/dev/usb/usb_hub.c
+++ b/sys/dev/usb/usb_hub.c
@@ -1757,9 +1757,11 @@ usbd_fs_isoc_schedule_alloc_slot(struct usb_xfer *isoc_xfer, uint16_t isoc_time)
data_len += len;
}
- /* check double buffered transfers */
-
- TAILQ_FOREACH(pipe_xfer, &xfer->endpoint->endpoint_q.head,
+ /*
+ * Check double buffered transfers. Only stream ID
+ * equal to zero is valid here!
+ */
+ TAILQ_FOREACH(pipe_xfer, &xfer->endpoint->endpoint_q[0].head,
wait_entry) {
/* skip self, if any */
diff --git a/sys/dev/usb/usb_ioctl.h b/sys/dev/usb/usb_ioctl.h
index 9af6ee5..5e8dab7 100644
--- a/sys/dev/usb/usb_ioctl.h
+++ b/sys/dev/usb/usb_ioctl.h
@@ -206,6 +206,11 @@ struct usb_fs_open {
uint8_t ep_no; /* bEndpointNumber */
};
+struct usb_fs_open_streams {
+ struct usb_fs_open fs_open;
+ uint16_t stream_id;
+};
+
struct usb_fs_close {
uint8_t ep_index;
};
@@ -302,6 +307,7 @@ struct usb_gen_quirk {
#define USB_FS_OPEN _IOWR('U', 197, struct usb_fs_open)
#define USB_FS_CLOSE _IOW ('U', 198, struct usb_fs_close)
#define USB_FS_CLEAR_STALL_SYNC _IOW ('U', 199, struct usb_fs_clear_stall_sync)
+#define USB_FS_OPEN_STREAMS _IOWR('U', 200, struct usb_fs_open_streams)
/* USB quirk system interface */
#define USB_DEV_QUIRK_GET _IOWR('Q', 0, struct usb_gen_quirk)
diff --git a/sys/dev/usb/usb_request.c b/sys/dev/usb/usb_request.c
index f601154..57bd968 100644
--- a/sys/dev/usb/usb_request.c
+++ b/sys/dev/usb/usb_request.c
@@ -228,6 +228,7 @@ usb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
struct usb_endpoint *ep;
struct usb_endpoint *ep_end;
struct usb_endpoint *ep_first;
+ usb_stream_t x;
uint8_t to;
udev = xfer->xroot->udev;
@@ -255,9 +256,11 @@ tr_transferred:
ep->is_stalled = 0;
/* some hardware needs a callback to clear the data toggle */
usbd_clear_stall_locked(udev, ep);
- /* start up the current or next transfer, if any */
- usb_command_wrapper(&ep->endpoint_q,
- ep->endpoint_q.curr);
+ for (x = 0; x != USB_MAX_EP_STREAMS; x++) {
+ /* start the current or next transfer, if any */
+ usb_command_wrapper(&ep->endpoint_q[x],
+ ep->endpoint_q[x].curr);
+ }
}
ep++;
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 */
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index 653f395..4193118 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -133,7 +133,8 @@ struct usb_xfer_queue {
* USB endpoint.
*/
struct usb_endpoint {
- struct usb_xfer_queue endpoint_q; /* queue of USB transfers */
+ /* queue of USB transfers */
+ struct usb_xfer_queue endpoint_q[USB_MAX_EP_STREAMS];
struct usb_endpoint_descriptor *edesc;
struct usb_endpoint_ss_comp_descriptor *ecomp;
@@ -156,6 +157,10 @@ struct usb_endpoint {
uint8_t usb_smask; /* USB start mask */
uint8_t usb_cmask; /* USB complete mask */
uint8_t usb_uframe; /* USB microframe */
+
+ /* USB endpoint mode, see USB_EP_MODE_XXX */
+
+ uint8_t ep_mode;
};
/*
@@ -220,6 +225,7 @@ struct usb_config {
#define USB_DEFAULT_INTERVAL 0
usb_timeout_t timeout; /* transfer timeout in milliseconds */
struct usb_xfer_flags flags; /* transfer flags */
+ usb_stream_t stream_id; /* USB3.0 specific */
enum usb_hc_mode usb_mode; /* host or device mode */
uint8_t type; /* pipe type */
uint8_t endpoint; /* pipe number */
@@ -477,6 +483,10 @@ usb_error_t usbd_set_pnpinfo(struct usb_device *udev,
uint8_t iface_index, const char *pnpinfo);
usb_error_t usbd_add_dynamic_quirk(struct usb_device *udev,
uint16_t quirk);
+usb_error_t usbd_set_endpoint_mode(struct usb_device *udev,
+ struct usb_endpoint *ep, uint8_t ep_mode);
+uint8_t usbd_get_endpoint_mode(struct usb_device *udev,
+ struct usb_endpoint *ep);
const struct usb_device_id *usbd_lookup_id_by_info(
const struct usb_device_id *id, usb_size_t sizeof_id,
OpenPOWER on IntegriCloud