summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/controller/xhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/controller/xhci.c')
-rw-r--r--sys/dev/usb/controller/xhci.c70
1 files changed, 51 insertions, 19 deletions
diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c
index 6faba7f..f32e89a 100644
--- a/sys/dev/usb/controller/xhci.c
+++ b/sys/dev/usb/controller/xhci.c
@@ -2045,7 +2045,9 @@ xhci_configure_mask(struct usb_device *udev, uint32_t mask, uint8_t drop)
struct xhci_softc *sc = XHCI_BUS2SC(udev->bus);
struct usb_page_search buf_inp;
struct xhci_input_dev_ctx *pinp;
+ uint32_t temp;
uint8_t index;
+ uint8_t x;
index = udev->controller_slot_id;
@@ -2060,6 +2062,24 @@ xhci_configure_mask(struct usb_device *udev, uint32_t mask, uint8_t drop)
} else {
xhci_ctx_set_le32(sc, &pinp->ctx_input.dwInCtx0, 0);
xhci_ctx_set_le32(sc, &pinp->ctx_input.dwInCtx1, mask);
+
+ /* find most significant set bit */
+ for (x = 31; x != 1; x--) {
+ if (mask & (1 << x))
+ break;
+ }
+
+ /* adjust */
+ x--;
+
+ /* figure out maximum */
+ if (x > sc->sc_hw.devs[index].context_num) {
+ sc->sc_hw.devs[index].context_num = x;
+ temp = xhci_ctx_get_le32(sc, &pinp->ctx_slot.dwSctx0);
+ temp &= ~XHCI_SCTX_0_CTX_NUM_SET(31);
+ temp |= XHCI_SCTX_0_CTX_NUM_SET(x + 1);
+ xhci_ctx_set_le32(sc, &pinp->ctx_slot.dwSctx0, temp);
+ }
}
return (0);
}
@@ -2311,16 +2331,9 @@ xhci_configure_device(struct usb_device *udev)
DPRINTF("Route=0x%08x\n", route);
- temp = XHCI_SCTX_0_ROUTE_SET(route);
-
- switch (sc->sc_hw.devs[index].state) {
- case XHCI_ST_CONFIGURED:
- temp |= XHCI_SCTX_0_CTX_NUM_SET(XHCI_MAX_ENDPOINTS - 1);
- break;
- default:
- temp |= XHCI_SCTX_0_CTX_NUM_SET(1);
- break;
- }
+ temp = XHCI_SCTX_0_ROUTE_SET(route) |
+ XHCI_SCTX_0_CTX_NUM_SET(
+ sc->sc_hw.devs[index].context_num + 1);
switch (udev->speed) {
case USB_SPEED_LOW:
@@ -2464,8 +2477,9 @@ xhci_alloc_device_ext(struct usb_device *udev)
if (usb_pc_alloc_mem(pc, pg, sc->sc_ctx_is_64_byte ?
(2 * sizeof(struct xhci_input_dev_ctx)) :
- sizeof(struct xhci_input_dev_ctx), XHCI_PAGE_SIZE))
+ sizeof(struct xhci_input_dev_ctx), XHCI_PAGE_SIZE)) {
goto error;
+ }
pc = &sc->sc_hw.devs[index].endpoint_pc;
pg = &sc->sc_hw.devs[index].endpoint_pg;
@@ -2473,15 +2487,18 @@ xhci_alloc_device_ext(struct usb_device *udev)
/* need to initialize the page cache */
pc->tag_parent = sc->sc_bus.dma_parent_tag;
- if (usb_pc_alloc_mem(pc, pg, sizeof(struct xhci_dev_endpoint_trbs), XHCI_PAGE_SIZE))
+ if (usb_pc_alloc_mem(pc, pg,
+ sizeof(struct xhci_dev_endpoint_trbs), XHCI_PAGE_SIZE)) {
goto error;
+ }
/* initialise all endpoint LINK TRBs */
for (i = 0; i != XHCI_MAX_ENDPOINTS; i++) {
/* lookup endpoint TRB ring */
- usbd_get_page(pc, (uintptr_t)&((struct xhci_dev_endpoint_trbs *)0)->trb[i][0], &buf_ep);
+ usbd_get_page(pc, (uintptr_t)&
+ ((struct xhci_dev_endpoint_trbs *)0)->trb[i][0], &buf_ep);
/* get TRB pointer */
trb = buf_ep.buffer;
@@ -2568,8 +2585,10 @@ xhci_endpoint_doorbell(struct usb_xfer *xfer)
epno = XHCI_EPNO2EPID(epno);
index = xfer->xroot->udev->controller_slot_id;
- if (xfer->xroot->udev->flags.self_suspended == 0)
- XWRITE4(sc, door, XHCI_DOORBELL(index), epno | XHCI_DB_SID_SET(0));
+ if (xfer->xroot->udev->flags.self_suspended == 0) {
+ XWRITE4(sc, door, XHCI_DOORBELL(index),
+ epno | XHCI_DB_SID_SET(xfer->stream_id));
+ }
}
static void
@@ -3584,7 +3603,7 @@ xhci_configure_reset_endpoint(struct usb_xfer *xfer)
* endpoint context state diagram in the XHCI specification:
*/
- xhci_configure_mask(udev, 1U << epno, 0);
+ xhci_configure_mask(udev, (1U << epno) | 1U, 0);
err = xhci_cmd_evaluate_ctx(sc, buf_inp.physaddr, index);
@@ -3858,6 +3877,7 @@ xhci_device_resume(struct usb_device *udev)
struct xhci_softc *sc = XHCI_BUS2SC(udev->bus);
uint8_t index;
uint8_t n;
+ uint8_t p;
DPRINTF("\n");
@@ -3873,8 +3893,12 @@ xhci_device_resume(struct usb_device *udev)
USB_BUS_LOCK(udev->bus);
- for (n = 1; n != XHCI_MAX_ENDPOINTS; n++)
- XWRITE4(sc, door, XHCI_DOORBELL(index), n | XHCI_DB_SID_SET(0));
+ for (n = 1; n != XHCI_MAX_ENDPOINTS; n++) {
+ for (p = 0; p != XHCI_MAX_STREAMS; p++) {
+ XWRITE4(sc, door, XHCI_DOORBELL(index),
+ n | XHCI_DB_SID_SET(p));
+ }
+ }
USB_BUS_UNLOCK(udev->bus);
@@ -3948,8 +3972,12 @@ xhci_device_state_change(struct usb_device *udev)
if (sc->sc_hw.devs[index].state == XHCI_ST_DEFAULT)
break;
+ /* set default state */
sc->sc_hw.devs[index].state = XHCI_ST_DEFAULT;
+ /* reset number of contexts */
+ sc->sc_hw.devs[index].context_num = 0;
+
err = xhci_cmd_reset_dev(sc, index);
if (err != 0) {
@@ -3976,11 +4004,15 @@ xhci_device_state_change(struct usb_device *udev)
if (sc->sc_hw.devs[index].state == XHCI_ST_CONFIGURED)
break;
+ /* set configured state */
sc->sc_hw.devs[index].state = XHCI_ST_CONFIGURED;
+ /* reset number of contexts */
+ sc->sc_hw.devs[index].context_num = 0;
+
usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp);
- xhci_configure_mask(udev, 1, 0);
+ xhci_configure_mask(udev, 3, 0);
err = xhci_configure_device(udev);
if (err != 0) {
OpenPOWER on IntegriCloud