PERFORCE change 182075 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Sun Aug 8 12:41:43 UTC 2010
http://p4web.freebsd.org/@@182075?ac=10
Change 182075 by hselasky at hselasky_laptop001 on 2010/08/08 12:41:08
USB controller (XHCI):
- fixes for double buffering and endpoint configuration.
- correct some wrong definitions in xhci.h
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#16 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#18 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#16 (text+ko) ====
@@ -121,11 +121,8 @@
static void xhci_free_device_ext(struct usb_device *udev);
static struct xhci_endpoint_ext *xhci_get_endpoint_ext(struct usb_device *, struct usb_endpoint_descriptor *);
static usb_proc_callback_t xhci_configure_msg;
-static usb_error_t xhci_configure_reset_endpoint(struct usb_xfer *);
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, uint16_t, uint16_t);
-static usb_error_t xhci_configure_endpoint_by_xfer(struct usb_xfer *);
-static usb_error_t xhci_set_address(struct usb_device *, struct mtx *, uint16_t);
static usb_error_t xhci_configure_mask(struct usb_device *, uint32_t, uint8_t);
extern struct usb_bus_methods xhci_bus_methods;
@@ -628,6 +625,7 @@
err = xhci_generic_done_sub(xfer);
done:
+ /* transfer is complete */
xhci_device_done(xfer, err);
}
@@ -637,14 +635,14 @@
static void
xhci_check_transfer(struct xhci_softc *sc, struct xhci_trb *trb)
{
- struct usb_xfer *xfer;
- struct xhci_td *td;
- struct xhci_endpoint_ext *pepext;
uint64_t td_event;
uint32_t temp;
uint32_t remainder;
uint8_t status;
uint8_t halted;
+ uint8_t epno;
+ uint8_t index;
+ uint8_t i;
/* decode TRB */
td_event = le64toh(trb->qwTrb0);
@@ -653,29 +651,44 @@
remainder = XHCI_TRB_2_REM_GET(temp);
status = XHCI_TRB_2_ERROR_GET(temp);
+ temp = le32toh(trb->dwTrb3);
+ epno = XHCI_TRB_3_EP_GET(temp) + 1;
+ index = XHCI_TRB_3_SLOT_GET(temp);
+
/* check if error means halted */
halted = (status != XHCI_TRB_ERROR_SHORT_PKT) &&
(status != XHCI_TRB_ERROR_SUCCESS);
- DPRINTF("remainder=%u status=%u\n", remainder, status);
+ DPRINTF("slot=%u epno=%u remainder=%u status=%u\n",
+ index, epno, remainder, status);
+
+ if (index > sc->sc_noslot) {
+ DPRINTF("Invalid slot.\n");
+ return;
+ }
+
+ epno++;
+
+ if (epno >= XHCI_MAX_ENDPOINTS) {
+ DPRINTF("Invalid endpoint.\n");
+ return;
+ }
/* try to find the USB transfer that generated the event */
- TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+ for (i = 0; i != (XHCI_MAX_TRANSFERS - 1); i++) {
+ struct usb_xfer *xfer;
+ struct xhci_td *td;
+ struct xhci_endpoint_ext *pepext;
- /* check if transfer is cancelling */
- if (xfer->flags_int.did_dma_delay)
- continue;
+ pepext = &sc->sc_hw.devs[index].endp[epno];
- pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
- xfer->endpoint->edesc);
-
- /* check if endpoint is halted */
- if (pepext->trb_halted != 0)
+ xfer = pepext->xfer[i];
+ if (xfer == NULL)
continue;
td = xfer->td_transfer_cache;
- DPRINTF("0x%08llx == (0x%08llx .. 0x%08llx)\n",
+ DPRINTFN(5, "Checking if 0x%016llx == (0x%016llx .. 0x%016llx)\n",
(long long)td_event,
(long long)td->td_self,
(long long)td->td_event_last);
@@ -684,13 +697,15 @@
(halted && (td_event >= td->td_self) &&
(td_event < td->td_event_last))) {
- struct xhci_endpoint_ext *pepext;
+ usb_pc_cpu_invalidate(td->page_cache);
- pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
- xfer->endpoint->edesc);
+ if (xfer->flags_int.isochronous_xfr) {
+ if (halted) {
+ halted = 0;
+ remainder = td->len;
+ }
+ }
- usb_pc_cpu_invalidate(td->page_cache);
-
/* "td->remainder" is verified later */
td->remainder = remainder;
td->status = status;
@@ -1126,7 +1141,6 @@
err = USB_ERR_IOERROR;
break;
}
-
XHCI_CMD_UNLOCK(sc);
if (mtx != NULL)
@@ -1190,7 +1204,7 @@
trb.dwTrb2 = 0;
temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_EP) |
XHCI_TRB_3_SLOT_SET(slot_id) |
- XHCI_TRB_3_SLOT_SET(ep_id);
+ XHCI_TRB_3_EP_SET(ep_id);
if (preserve)
temp |= XHCI_TRB_3_PRSV_BIT;
@@ -1201,6 +1215,28 @@
}
static usb_error_t
+xhci_cmd_set_tr_dequeue_ptr(struct xhci_softc *sc, uint64_t dequeue_ptr,
+ uint16_t stream_id, uint8_t ep_id, uint8_t slot_id)
+{
+ struct xhci_trb trb;
+ uint32_t temp;
+
+ DPRINTF("\n");
+
+ trb.qwTrb0 = htole64(dequeue_ptr);
+
+ temp = XHCI_TRB_2_STREAM_SET(stream_id);
+ trb.dwTrb2 = htole32(temp);
+
+ temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_SET_TR_DEQUEUE) |
+ XHCI_TRB_3_SLOT_SET(slot_id) |
+ XHCI_TRB_3_EP_SET(ep_id);
+ trb.dwTrb3 = htole32(temp);
+
+ return (xhci_do_command(sc, &trb, 50 /* ms */));
+}
+
+static usb_error_t
xhci_cmd_stop_ep(struct xhci_softc *sc, uint8_t suspend,
uint8_t ep_id, uint8_t slot_id)
{
@@ -1213,7 +1249,7 @@
trb.dwTrb2 = 0;
temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STOP_EP) |
XHCI_TRB_3_SLOT_SET(slot_id) |
- XHCI_TRB_3_SLOT_SET(ep_id);
+ XHCI_TRB_3_EP_SET(ep_id);
if (suspend)
temp |= XHCI_TRB_3_SUSP_EP_BIT;
@@ -1223,6 +1259,7 @@
return (xhci_do_command(sc, &trb, 50 /* ms */));
}
+#if 0
static usb_error_t
xhci_cmd_reset_dev(struct xhci_softc *sc, uint8_t slot_id)
{
@@ -1240,6 +1277,7 @@
return (xhci_do_command(sc, &trb, 50 /* ms */));
}
+#endif
/*------------------------------------------------------------------------*
* xhci_interrupt - XHCI interrupt handler
@@ -1300,21 +1338,11 @@
xhci_timeout(void *arg)
{
struct usb_xfer *xfer = arg;
- struct xhci_endpoint_ext *pepext;
DPRINTF("xfer=%p\n", xfer);
USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
- pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
- xfer->endpoint->edesc);
-
-#if 0
- /* check if endpoint is halted */
- if (pepext->trb_halted != 0)
- return;
-#endif
-
/* transfer is transferred */
xhci_device_done(xfer, USB_ERR_TIMEOUT);
}
@@ -2018,7 +2046,7 @@
route |= rh_port;
}
- temp = XHCI_SCTX_0_CTX_NUM_SET(1) | /* XXX XHCI_MAX_ENDPOINTS - 1) | */
+ temp = XHCI_SCTX_0_CTX_NUM_SET(XHCI_MAX_ENDPOINTS - 1) |
XHCI_SCTX_0_ROUTE_SET(route);
switch (udev->speed) {
@@ -2252,8 +2280,12 @@
pepext->trb_used--;
- if (error)
+ pepext->xfer[xfer->qh_pos] = NULL;
+
+ if (error && (pepext->trb_running != 0)) {
pepext->trb_halted = 1;
+ pepext->trb_running = 0;
+ }
}
}
@@ -2274,10 +2306,6 @@
pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
xfer->endpoint->edesc);
- /* check for halt condition */
- if (pepext->trb_halted != 0)
- return (0);
-
td_first = xfer->td_transfer_first;
td_last = xfer->td_transfer_last;
addr = pepext->physaddr;
@@ -2287,10 +2315,30 @@
return (USB_ERR_NOMEM);
}
+ /* check if transfer is not already on interrupt queue */
+ if (xfer->wait_queue != &xfer->xroot->bus->intr_q) {
+
+ /* remove transfer from pipe queue, if any */
+
+ usbd_transfer_dequeue(xfer);
+
+ /* add transfer last on interrupt queue */
+
+ usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
+ }
+
+ /* check for stopped condition, after putting transfer on interrupt queue */
+ if (pepext->trb_running == 0) {
+ struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus);
+
+ /* start configuration */
+ (void)usb_proc_msignal(&sc->sc_config_proc,
+ &sc->sc_config_msg[0], &sc->sc_config_msg[1]);
+ return (0);
+ }
+
pepext->trb_used++;
- xfer->flags_int.bandwidth_reclaimed = 1;
-
/* get current TRB index */
i = pepext->trb_index;
@@ -2338,6 +2386,12 @@
usb_pc_cpu_flush(pepext->page_cache);
+ pepext->xfer[i] = xfer;
+
+ xfer->qh_pos = i;
+
+ xfer->flags_int.bandwidth_reclaimed = 1;
+
pepext->trb_index = inext;
xhci_endpoint_doorbell(xfer);
@@ -2418,13 +2472,8 @@
/* setup TD's and QH */
xhci_setup_generic_chain(xfer);
-#ifdef NOTYET
- /* put transfer on interrupt queue */
- usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
-
/* try to insert xfer on HW queue */
xhci_transfer_insert(xfer);
-#endif
}
static void
@@ -2438,9 +2487,6 @@
"transfer %p into HW queue.\n", xfer);
}
- /* put transfer on interrupt queue */
- usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
-
/* start timeout, if any */
if (xfer->timeout != 0)
usbd_transfer_timeout_ms(xfer, &xhci_timeout, xfer->timeout);
@@ -3067,10 +3113,6 @@
xfer->flags_int.curr_dma_set = 1;
goto alloc_dma_set;
}
-
- if ((parm->buf != NULL) && (parm->err == 0)) {
- parm->err = xhci_configure_reset_endpoint(xfer);
- }
}
static usb_error_t
@@ -3092,6 +3134,7 @@
pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
xfer->endpoint->edesc);
+
udev = xfer->xroot->udev;
index = udev->controller_slot_id;
@@ -3155,18 +3198,12 @@
DPRINTF("Could not update parent HS HUB context.\n");
}
- if (0) {
-
-
- err = xhci_cmd_reset_dev(sc, index);
- }
-
/* configure endpoint */
err = xhci_configure_endpoint_by_xfer(xfer);
if (err == 0) {
- err = xhci_cmd_stop_ep(sc, 0, epno, index);
+ err = xhci_cmd_stop_ep(sc, 0, epno - 1, index);
if (err != 0)
DPRINTF("Could not stop endpoint\n");
@@ -3190,10 +3227,15 @@
if (err == 0) {
if ((edesc->bmAttributes & UE_XFERTYPE) == UE_BULK)
- err = xhci_cmd_reset_ep(sc, 0, epno, index);
+ err = xhci_cmd_reset_ep(sc, 0, epno - 1, index);
if (err != 0)
DPRINTF("Could not reset endpoint %u\n", epno);
+
+ err = xhci_cmd_set_tr_dequeue_ptr(sc, pepext->physaddr, 0, epno - 1, index);
+
+ if (err != 0)
+ DPRINTF("Could not set dequeue ptr for endpoint %u\n", epno);
}
XHCI_CMD_UNLOCK(sc);
@@ -3227,42 +3269,46 @@
sc = XHCI_BUS2SC(((struct usb_bus_msg *)pm)->bus);
- /* make sure everything that is halted is gone, else we can loop */
-
-restart0:
+restart:
TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
xfer->endpoint->edesc);
- if ((pepext->trb_halted != 0) &&
- (xfer->flags_int.bandwidth_reclaimed != 0)) {
- xhci_device_done(xfer, USB_ERR_IOERROR);
- goto restart0;
- }
- }
+ if ((pepext->trb_halted != 0) ||
+ (pepext->trb_running == 0)) {
-restart1:
- TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+ uint8_t i;
- pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
- xfer->endpoint->edesc);
+ /* clear halted and running */
+ pepext->trb_halted = 0;
+ pepext->trb_running = 0;
- if (xfer->flags_int.did_dma_delay) {
+ /* nuke remaining buffered transfers */
- if (pepext->trb_halted != 0) {
+ for (i = 0; i != (XHCI_MAX_TRANSFERS - 1); i++) {
+ if (pepext->xfer[i] != NULL)
+ xhci_device_done(pepext->xfer[i], USB_ERR_IOERROR);
+ }
- /* NOTE: The USB transfer cannot vanish in this state! */
+ /* NOTE: The USB transfer cannot vanish in this state! */
- USB_BUS_UNLOCK(&sc->sc_bus);
+ USB_BUS_UNLOCK(&sc->sc_bus);
- xhci_configure_reset_endpoint(xfer);
+ xhci_configure_reset_endpoint(xfer);
- USB_BUS_LOCK(&sc->sc_bus);
+ USB_BUS_LOCK(&sc->sc_bus);
- pepext->trb_reset = 1;
+ /* check if halted is still cleared */
+ if (pepext->trb_halted == 0) {
+ pepext->trb_running = 1;
+ pepext->trb_index = 1;
}
+ goto restart;
+ }
+ if (xfer->flags_int.did_dma_delay) {
+
/* remove transfer from interrupt queue (again) */
usbd_transfer_dequeue(xfer);
@@ -3270,22 +3316,14 @@
usb_dma_delay_done_cb(xfer);
/* queue changed - restart */
- goto restart1;
+ goto restart;
+
}
}
- /* queue up leftover transfers, if any */
-
TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
- pepext = xhci_get_endpoint_ext(xfer->xroot->udev,
- xfer->endpoint->edesc);
-
- if ((pepext->trb_halted != 0) &&
- (pepext->trb_reset != 0)) {
- pepext->trb_halted = 0;
- pepext->trb_reset = 0;
- }
- xhci_transfer_insert(xfer);
+ /* try to insert transfer in hardware schedule */
+ xhci_transfer_insert(xfer);
}
}
@@ -3293,17 +3331,28 @@
xhci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc,
struct usb_endpoint *ep)
{
+ struct xhci_endpoint_ext *pepext;
+
DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d\n",
- ep, udev->address,
- edesc->bEndpointAddress, udev->flags.usb_mode);
+ ep, udev->address, edesc->bEndpointAddress, udev->flags.usb_mode);
if (udev->flags.usb_mode != USB_MODE_HOST) {
/* not supported */
return;
}
- /* check if not root HUB */
- if (udev->parent_hub != NULL)
- ep->methods = &xhci_device_generic_methods;
+ if (udev->parent_hub == NULL) {
+ /* root HUB has special endpoint handling */
+ return;
+ }
+
+ ep->methods = &xhci_device_generic_methods;
+
+ pepext = xhci_get_endpoint_ext(udev, edesc);
+
+ USB_BUS_LOCK(udev->bus);
+ pepext->trb_halted = 1;
+ pepext->trb_running = 0;
+ USB_BUS_UNLOCK(udev->bus);
}
static void
@@ -3312,6 +3361,30 @@
}
+static void
+xhci_ep_clear_stall(struct usb_device *udev, struct usb_endpoint *ep)
+{
+ struct xhci_endpoint_ext *pepext;
+
+ DPRINTF("\n");
+
+ if (udev->flags.usb_mode != USB_MODE_HOST) {
+ /* not supported */
+ return;
+ }
+ if (udev->parent_hub == NULL) {
+ /* root HUB has special endpoint handling */
+ return;
+ }
+
+ pepext = xhci_get_endpoint_ext(udev, ep->edesc);
+
+ USB_BUS_LOCK(udev->bus);
+ pepext->trb_halted = 1;
+ pepext->trb_running = 0;
+ USB_BUS_UNLOCK(udev->bus);
+}
+
static usb_error_t
xhci_device_init(struct usb_device *udev)
{
@@ -3452,4 +3525,5 @@
.xfer_poll = xhci_do_poll,
.start_dma_delay = xhci_start_dma_delay,
.set_address = xhci_set_address,
+ .clear_stall = xhci_ep_clear_stall,
};
==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#18 (text+ko) ====
@@ -192,6 +192,8 @@
#define XHCI_TRB_2_BYTES_SET(x) ((x) & 0x1FFFF)
#define XHCI_TRB_2_IRQ_GET(x) (((x) >> 22) & 0x3FF)
#define XHCI_TRB_2_IRQ_SET(x) (((x) & 0x3FF) << 22)
+#define XHCI_TRB_2_STREAM_GET(x) (((x) >> 16) & 0xFFFF)
+#define XHCI_TRB_2_STREAM_SET(x) (((x) & 0xFFFF) << 16)
volatile uint32_t dwTrb3;
#define XHCI_TRB_3_TYPE_GET(x) (((x) >> 10) & 0x3F)
@@ -215,11 +217,11 @@
#define XHCI_TRB_3_DIR_IN (1U << 16)
#define XHCI_TRB_3_TLBPC_GET(x) (((x) >> 16) & 0xF)
#define XHCI_TRB_3_TLBPC_SET(x) (((x) & 0xF) << 16)
+#define XHCI_TRB_3_EP_GET(x) (((x) >> 16) & 0x1F)
+#define XHCI_TRB_3_EP_SET(x) (((x) & 0x1F) << 16)
#define XHCI_TRB_3_FRID_GET(x) (((x) >> 20) & 0x7FF)
#define XHCI_TRB_3_FRID_SET(x) (((x) & 0x7FF) << 20)
#define XHCI_TRB_3_ISO_SIA_BIT (1U << 31)
-#define XHCI_TRB_3_EP_GET(x) (((x) >> 20) & 0x1F)
-#define XHCI_TRB_3_EP_SET(x) (((x) & 0x1F) << 20)
#define XHCI_TRB_3_SUSP_EP_BIT (1U << 23)
#define XHCI_TRB_3_SLOT_GET(x) (((x) >> 24) & 0xFF)
#define XHCI_TRB_3_SLOT_SET(x) (((x) & 0xFF) << 24)
@@ -347,13 +349,13 @@
struct xhci_endpoint_ext {
struct xhci_trb *trb;
+ struct usb_xfer *xfer[XHCI_MAX_TRANSFERS - 1];
struct usb_page_cache *page_cache;
uint64_t physaddr;
uint8_t trb_used;
uint8_t trb_index;
uint8_t trb_halted;
- uint8_t trb_reset;
- uint8_t trb_configured;
+ uint8_t trb_running;
};
enum {
More information about the p4-projects
mailing list