Date: Tue, 3 Aug 2010 20:39:04 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 181803 for review Message-ID: <201008032039.o73Kd4l3045324@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@181803?ac=10 Change 181803 by hselasky@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) ====
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201008032039.o73Kd4l3045324>