diff options
author | hselasky <hselasky@FreeBSD.org> | 2012-12-01 22:13:38 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2012-12-01 22:13:38 +0000 |
commit | fd7b9e3752e161a90b2d9740f7c6a7f54a0780f1 (patch) | |
tree | d3f408d23e0c13cf6275a15568334fa7c04a832c /sys/dev/usb/controller | |
parent | aee35ecd72729f8d859eba45444833f5bb23d581 (diff) | |
download | FreeBSD-src-fd7b9e3752e161a90b2d9740f7c6a7f54a0780f1.zip FreeBSD-src-fd7b9e3752e161a90b2d9740f7c6a7f54a0780f1.tar.gz |
- Add support for Etron EJ168 USB 3.0 Host Controllers.
This brand of controllers expects that the number of
contexts specified in the input slot context points
to an active endpoint context, else it refuses to
operate.
- Ring the correct doorbell when streams mode is used.
- Wrap one or two long lines.
Tested by: Markus Pfeiffer (DragonFlyBSD)
MFC after: 1 week
Diffstat (limited to 'sys/dev/usb/controller')
-rw-r--r-- | sys/dev/usb/controller/xhci.c | 70 | ||||
-rw-r--r-- | sys/dev/usb/controller/xhci.h | 2 |
2 files changed, 52 insertions, 20 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) { diff --git a/sys/dev/usb/controller/xhci.h b/sys/dev/usb/controller/xhci.h index a7e4f74..01e60ee 100644 --- a/sys/dev/usb/controller/xhci.h +++ b/sys/dev/usb/controller/xhci.h @@ -394,7 +394,7 @@ struct xhci_hw_dev { uint8_t state; uint8_t nports; uint8_t tt; - uint8_t reserved; + uint8_t context_num; }; struct xhci_hw_softc { |