PERFORCE change 181803 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Tue Aug 3 20:39:05 UTC 2010
http://p4web.freebsd.org/@@181803?ac=10
Change 181803 by hselasky at hselasky_laptop001 on 2010/08/03 20:38:47
USB controller (XHCI):
- first compiling version of complete XHCI driver.
- added logic to reset endpoints after failed transfers.
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#12 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#13 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci_pci.c#5 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhcireg.h#12 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#12 (text+ko) ====
@@ -114,6 +114,8 @@
static void xhci_root_intr(struct xhci_softc *);
static void xhci_free_device_ext(struct usb_device *udev);
static struct xhci_endpoint_ext *xhci_get_endpoint_ext(struct usb_xfer *xfer);
+static usb_proc_callback_t xhci_configure_msg;
+static usb_error_t xhci_configure_reset_endpoint(struct usb_xfer *xfer, uint8_t set_address);
extern struct usb_bus_methods xhci_bus_methods;
@@ -363,12 +365,24 @@
return (ENOMEM);
}
+ sc->sc_config_msg[0].hdr.pm_callback = &xhci_configure_msg;
+ sc->sc_config_msg[0].bus = &sc->sc_bus;
+ sc->sc_config_msg[1].hdr.pm_callback = &xhci_configure_msg;
+ sc->sc_config_msg[1].bus = &sc->sc_bus;
+
+ if (usb_proc_create(&sc->sc_config_proc,
+ &sc->sc_bus.bus_mtx, device_get_nameunit(self), USB_PRI_MED)) {
+ printf("WARNING: Creation of XHCI configure "
+ "callback process failed.\n");
+ }
return (0);
}
void
xhci_uninit(struct xhci_softc *sc)
{
+ usb_proc_free(&sc->sc_config_proc);
+
usb_bus_mem_free_all(&sc->sc_bus, &xhci_iterate_hw_softc);
cv_destroy(&sc->sc_cmd_cv);
@@ -524,6 +538,7 @@
{
struct usb_xfer *xfer;
struct xhci_td *td;
+ struct xhci_endpoint_ext *pepext;
uint64_t td_event;
uint32_t temp;
uint32_t actlen;
@@ -536,10 +551,24 @@
/* try to find the USB transfer that generated the event */
TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+ /* check if transfer is cancelling */
+ if (xfer->flags_int.did_dma_delay)
+ continue;
+
+ pepext = xhci_get_endpoint_ext(xfer);
+
+ /* check if endpoint is halted */
+ if (pepext->trb_halted != 0)
+ continue;
+
td = xfer->td_transfer_cache;
if (td_event == td->td_event) {
+ struct xhci_endpoint_ext *pepext;
+
+ pepext = xhci_get_endpoint_ext(xfer);
+
actlen = XHCI_TRB_2_ACTLEN_GET(temp);
status = XHCI_TRB_2_ERROR_GET(temp);
@@ -852,6 +881,7 @@
return (xhci_do_command(sc, &trb, 50 /* ms */));
}
+#if 0
static usb_error_t
xhci_cmd_evaluate_ctx(struct xhci_softc *sc, uint64_t input_ctx,
uint8_t slot_id)
@@ -867,6 +897,7 @@
return (xhci_do_command(sc, &trb, 50 /* ms */));
}
+#endif
static usb_error_t
xhci_cmd_reset_ep(struct xhci_softc *sc, uint8_t preserve,
@@ -889,6 +920,7 @@
return (xhci_do_command(sc, &trb, 50 /* ms */));
}
+#if 0
static usb_error_t
xhci_cmd_stop_ep(struct xhci_softc *sc, uint8_t suspend,
uint8_t ep_id, uint8_t slot_id)
@@ -909,6 +941,7 @@
return (xhci_do_command(sc, &trb, 50 /* ms */));
}
+#endif
static usb_error_t
xhci_cmd_reset_dev(struct xhci_softc *sc, uint8_t slot_id)
@@ -975,11 +1008,18 @@
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);
+
+ /* check if endpoint is halted */
+ if (pepext->trb_halted != 0)
+ return;
+
/* transfer is transferred */
xhci_device_done(xfer, USB_ERR_TIMEOUT);
}
@@ -1431,7 +1471,7 @@
xfer->td_transfer_last = td;
}
-static usb_error_t
+static void
xhci_set_slot_pointers(struct xhci_softc *sc, uint8_t index,
uint64_t dev_addr, uint64_t scratch_addr)
{
@@ -1481,15 +1521,15 @@
uint8_t epno;
uint8_t k;
- usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp);
- usbd_get_page(&sc->sc_hw.devs[index].endpoint_pc, 0, &buf_ep);
-
pepext = xhci_get_endpoint_ext(xfer);
udev = xfer->xroot->udev;
index = udev->controller_slot_id;
+ usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp);
+ usbd_get_page(&sc->sc_hw.devs[index].endpoint_pc, 0, &buf_ep);
+
edesc = xfer->endpoint->edesc;
epno = edesc->bEndpointAddress;
@@ -1511,8 +1551,7 @@
pinp->ctx_input.dwInCtx0 = htole32(mask);
pinp->ctx_input.dwInCtx1 = 0;
} else {
- if (mask & 2)
- mask |= 1;
+ mask |= 1;
pinp->ctx_input.dwInCtx0 = 0;
pinp->ctx_input.dwInCtx1 = htole32(mask);
}
@@ -1566,14 +1605,17 @@
if (drop == 0) {
+ USB_BUS_LOCK(&sc->sc_bus);
+
pepext->trb_ccs = 1;
pepext->trb_index = 0;
- pepext->trb_halted = 0;
for (k = 0; k != XHCI_MAX_TRANSFERS; k++)
pepext->trb[k].dwTrb3 = 0;
usb_pc_cpu_flush(pepext->page_cache);
+
+ USB_BUS_UNLOCK(&sc->sc_bus);
}
addr = XHCI_EPCTX_2_DCS_SET(1) |
@@ -1587,6 +1629,8 @@
pinp->ctx_ep[epno - 1].dwEpCtx4 = htole32(temp);
usb_pc_cpu_flush(&sc->sc_hw.devs[index].input_pc);
+
+ return (0); /* success */
}
static usb_error_t
@@ -1606,6 +1650,8 @@
uint8_t rh_port;
uint8_t i;
+ index = udev->controller_slot_id;
+
pcdev = &sc->sc_hw.devs[index].device_pc;
pcinp = &sc->sc_hw.devs[index].input_pc;
@@ -1693,6 +1739,8 @@
xhci_set_slot_pointers(sc, udev->controller_slot_id, buf_dev.physaddr,
buf_inp.physaddr + (uintptr_t)&((struct xhci_input_dev_ctx *)0)->ctx_sp_buf_ptr[0]);
+
+ return (0); /* success */
}
static usb_error_t
@@ -1842,7 +1890,7 @@
pepext->trb_used--;
if (error)
- xhci_transfer_stop_endpoint(xfer);
+ pepext->trb_halted = 1;
}
}
@@ -1863,6 +1911,10 @@
pepext = xhci_get_endpoint_ext(xfer);
+ /* 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;
@@ -2270,7 +2322,6 @@
err = USB_ERR_IOERROR;
goto done;
}
- sc->sc_addr = value;
break;
case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
if ((value != 0) && (value != 1)) {
@@ -2661,71 +2712,95 @@
}
if ((parm->buf != NULL) && (parm->err == 0)) {
- struct usb_page_search buf_dev;
- struct usb_page_search buf_inp;
- struct usb_device *udev;
- struct xhci_endpoint_ext *pepext;
- struct xhci_dev_ctx *pdctx;
- struct usb_page_cache *pcdev;
- struct usb_page_cache *pcinp;
- usb_error_t err;
- uint32_t temp;
- uint8_t index;
+ parm->err = xhci_configure_reset_endpoint(xfer, 1);
+ }
+}
+
+static usb_error_t
+xhci_configure_reset_endpoint(struct usb_xfer *xfer, uint8_t set_address)
+{
+ struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus);
+ struct usb_page_search buf_dev;
+ struct usb_page_search buf_inp;
+ struct usb_device *udev;
+ struct xhci_endpoint_ext *pepext;
+ struct usb_endpoint_descriptor *edesc;
+ struct xhci_dev_ctx *pdctx;
+ struct usb_page_cache *pcdev;
+ struct usb_page_cache *pcinp;
+ usb_error_t err;
+ uint32_t temp;
+ uint8_t index;
+ uint8_t epno;
+
+ pepext = xhci_get_endpoint_ext(xfer);
+ udev = xfer->xroot->udev;
+ index = udev->controller_slot_id;
+
+ pcdev = &sc->sc_hw.devs[index].device_pc;
+ pcinp = &sc->sc_hw.devs[index].input_pc;
+
+ usbd_get_page(pcdev, 0, &buf_dev);
+ usbd_get_page(pcinp, 0, &buf_inp);
+
+ pdctx = buf_dev.buffer;
+
+ edesc = xfer->endpoint->edesc;
- pepext = xhci_get_endpoint_ext(xfer);
- udev = xfer->xroot->udev;
- index = udev->controller_slot_id;
+ epno = edesc->bEndpointAddress;
- pcdev = &sc->sc_hw.devs[index].device_pc;
- pcinp = &sc->sc_hw.devs[index].input_pc;
+ if ((edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL)
+ epno |= UE_DIR_IN;
- usbd_get_page(pcdev, 0, &buf_dev);
- usbd_get_page(pcinp, 0, &buf_inp);
+ epno = XHCI_EPNO2EPID(epno);
- pdctx = buf_dev.buffer;
+ if (epno == 0)
+ return (USB_ERR_INVAL); /* invalid */
- XHCI_CMD_LOCK(sc);
+ XHCI_CMD_LOCK(sc);
+ err = xhci_configure_device(udev);
+ if (err == 0)
err = xhci_configure_endpoint(xfer, 1);
- if (err == 0)
- err = xhci_cmd_configure_ep(sc, buf_inp.physaddr, 0, index);
- if (err == 0)
- err = xhci_configure_endpoint(xfer, 0);
- if (err == 0)
- err = xhci_cmd_configure_ep(sc, buf_inp.physaddr, 0, index);
+ if (err == 0)
+ err = xhci_cmd_configure_ep(sc, buf_inp.physaddr, 0, index);
+ if (err == 0)
+ err = xhci_configure_endpoint(xfer, 0);
+ if (err == 0)
+ err = xhci_cmd_configure_ep(sc, buf_inp.physaddr, 0, index);
+ if (err == 0)
+ err = xhci_cmd_reset_ep(sc, 0, epno - 1, index);
+ if (err != 0)
+ DPRINTFN(0, "Could not configure/reset endpoint\n");
- if (err != 0)
- DPRINTFN(0, "Could not configure endpoint\n");
+ if (xfer->flags_int.control_xfr && set_address) {
- if (xfer->flags_int.control_xfr) {
+ if (udev->address != 0) {
+ err = xhci_cmd_set_address(sc, buf_inp.physaddr, 0, index);
+ if (err == 0) {
+ usb_pc_cpu_invalidate(pcdev);
- if (udev->address != 0) {
- err = xhci_cmd_set_address(sc, buf_inp.physaddr, 0, index);
- if (err == 0) {
- usb_pc_cpu_invalidate(pcdev);
+ temp = le32toh(pdctx->ctx_slot.dwSctx3);
- temp = le32toh(pdctx->ctx_slot.dwSctx3);
+ /* update address */
+ udev->address = XHCI_SCTX_3_DEV_ADDR_GET(temp);
- /* update address */
- udev->address = XHCI_SCTX_3_DEV_ADDR_GET(temp);
-
- if (udev->address == 0)
- DPRINTFN(0, "XHCI returned address zero!\n");
+ if (udev->address == 0)
+ DPRINTFN(0, "XHCI returned address zero!\n");
}
- } else {
- err = xhci_cmd_set_address(sc, buf_inp.physaddr, 1, index);
-
- if (err != 0)
- err = xhci_cmd_reset_dev(sc, index);
- }
+ } else {
+ err = xhci_cmd_set_address(sc, buf_inp.physaddr, 1, index);
if (err != 0)
- DPRINTFN(0, "Could not set address\n");
+ err = xhci_cmd_reset_dev(sc, index);
}
- XHCI_CMD_UNLOCK(sc);
- parm->err = err;
+ if (err != 0)
+ DPRINTFN(0, "Could not set address\n");
}
+ XHCI_CMD_UNLOCK(sc);
+
+ return (err);
}
static void
@@ -2735,20 +2810,98 @@
}
static void
+xhci_start_dma_delay(struct usb_xfer *xfer)
+{
+ struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus);
+
+ /* put transfer on interrupt queue (again) */
+ usbd_transfer_enqueue(&sc->sc_bus.intr_q, xfer);
+
+ (void)usb_proc_msignal(&sc->sc_config_proc,
+ &sc->sc_config_msg[0], &sc->sc_config_msg[1]);
+}
+
+static void
+xhci_configure_msg(struct usb_proc_msg *pm)
+{
+ struct xhci_softc *sc;
+ struct xhci_endpoint_ext *pepext;
+ struct usb_xfer *xfer;
+
+ sc = XHCI_BUS2SC(((struct usb_bus_msg *)pm)->bus);
+
+ /* make sure everything that is halted is gone, else we can loop */
+
+restart0:
+ TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+
+ pepext = xhci_get_endpoint_ext(xfer);
+
+ if ((pepext->trb_halted != 0) &&
+ (xfer->flags_int.bandwidth_reclaimed != 0)) {
+ xhci_device_done(xfer, USB_ERR_IOERROR);
+ goto restart0;
+ }
+ }
+
+restart1:
+ TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+
+ pepext = xhci_get_endpoint_ext(xfer);
+
+ if (xfer->flags_int.did_dma_delay) {
+
+ if (pepext->trb_halted != 0) {
+
+ /* NOTE: The USB transfer cannot vanish in this state! */
+
+ USB_BUS_UNLOCK(&sc->sc_bus);
+
+ xhci_configure_reset_endpoint(xfer, 0);
+
+ USB_BUS_LOCK(&sc->sc_bus);
+
+ pepext->trb_reset = 1;
+ }
+
+ /* remove transfer from interrupt queue (again) */
+ usbd_transfer_dequeue(xfer);
+
+ /* we are finally done */
+ usb_dma_delay_done_cb(xfer);
+
+ /* queue changed - restart */
+ goto restart1;
+ }
+ }
+
+ /* queue up leftover transfers, if any */
+
+ TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+ pepext = xhci_get_endpoint_ext(xfer);
+
+ if ((pepext->trb_halted != 0) &&
+ (pepext->trb_reset != 0)) {
+ pepext->trb_halted = 0;
+ pepext->trb_reset = 0;
+ }
+ xhci_transfer_insert(xfer);
+ }
+}
+
+static void
xhci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc,
struct usb_endpoint *ep)
{
- struct xhci_softc *sc = XHCI_BUS2SC(udev->bus);
-
- DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n",
+ DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d\n",
ep, udev->address,
- edesc->bEndpointAddress, udev->flags.usb_mode,
- sc->sc_addr);
+ 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;
}
@@ -2874,4 +3027,5 @@
.set_hw_power = xhci_set_hw_power,
.roothub_exec = xhci_roothub_exec,
.xfer_poll = xhci_do_poll,
+ .start_dma_delay = xhci_start_dma_delay,
};
==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#13 (text+ko) ====
@@ -350,6 +350,7 @@
uint8_t trb_ccs;
uint8_t trb_index;
uint8_t trb_halted;
+ uint8_t trb_reset;
};
struct xhci_hw_dev {
@@ -400,6 +401,8 @@
struct xhci_softc {
struct xhci_hw_softc sc_hw;
struct usb_bus sc_bus; /* base device */
+ struct usb_process sc_config_proc; /* configure process */
+ struct usb_bus_msg sc_config_msg[2];
union xhci_hub_desc sc_hub_desc;
@@ -436,7 +439,6 @@
uint8_t sc_noslot; /* number of XHCI device slots */
uint8_t sc_noport; /* number of ports on root HUB */
uint8_t sc_noscratch; /* number of scratch pages */
- uint8_t sc_addr; /* root HUB device address */
uint8_t sc_conf; /* root HUB device configuration */
uint8_t sc_hub_idata[2];
@@ -444,9 +446,9 @@
};
-#define XHCI_CMD_LOCK(sc) sx_xlock(&sc->sc_cmd_sx)
-#define XHCI_CMD_UNLOCK(sc) sx_xunlock(&sc->sc_cmd_sx)
-#define XHCI_CMD_ASSERT_LOCKED(sc) sx_assert(&sc->sc_cmd_sx, SA_LOCKED)
+#define XHCI_CMD_LOCK(sc) sx_xlock(&(sc)->sc_cmd_sx)
+#define XHCI_CMD_UNLOCK(sc) sx_xunlock(&(sc)->sc_cmd_sx)
+#define XHCI_CMD_ASSERT_LOCKED(sc) sx_assert(&(sc)->sc_cmd_sx, SA_LOCKED)
/* prototypes */
==== //depot/projects/usb/src/sys/dev/usb/controller/xhci_pci.c#5 (text+ko) ====
==== //depot/projects/usb/src/sys/dev/usb/controller/xhcireg.h#12 (text+ko) ====
More information about the p4-projects
mailing list