From owner-p4-projects@FreeBSD.ORG Sat Aug 7 19:38:52 2010 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id B308F1065675; Sat, 7 Aug 2010 19:38:52 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 76FBC1065673 for ; Sat, 7 Aug 2010 19:38:52 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 628998FC0C for ; Sat, 7 Aug 2010 19:38:52 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.4/8.14.4) with ESMTP id o77JcqXD044798 for ; Sat, 7 Aug 2010 19:38:52 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.4/8.14.4/Submit) id o77JcqUS044796 for perforce@freebsd.org; Sat, 7 Aug 2010 19:38:52 GMT (envelope-from hselasky@FreeBSD.org) Date: Sat, 7 Aug 2010 19:38:52 GMT Message-Id: <201008071938.o77JcqUS044796@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 182044 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 07 Aug 2010 19:38:53 -0000 http://p4web.freebsd.org/@@182044?ac=10 Change 182044 by hselasky@hselasky_laptop001 on 2010/08/07 19:38:13 USB controller (XHCI): - fix a bunch of misunderstandings about the XHCI chip. - driver has reached a state where device enumeration is possible. - some issues are still left Affected files ... .. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#15 edit .. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#17 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#15 (text+ko) ==== @@ -32,6 +32,12 @@ * http://www.usb.org/developers/docs/usb_30_spec_060910.zip */ +/* + * A few words about the design implementation: This driver emulates + * the concept about TDs which is found in EHCI specification. This + * way we avoid too much diveration among USB drivers. + */ + #include __FBSDID("$FreeBSD: src/sys/dev/usb/controller/xhci.c $"); @@ -79,7 +85,7 @@ ((uint8_t *)&(((struct xhci_softc *)0)->sc_bus)))) #ifdef USB_DEBUG -static int xhcidebug = 15; +static int xhcidebug = 17; SYSCTL_NODE(_hw_usb, OID_AUTO, xhci, CTLFLAG_RW, 0, "USB XHCI"); SYSCTL_INT(_hw_usb_xhci, OID_AUTO, debug, CTLFLAG_RW, @@ -113,40 +119,50 @@ static void xhci_device_done(struct usb_xfer *, usb_error_t); 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 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 *xfer, uint8_t set_address); +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; #ifdef USB_DEBUG -#if 0 static void -xhci_dump_device(struct usb_device *udev) +xhci_dump_trb(struct xhci_trb *trb) { - struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); - struct usb_page_search buf_dev; - struct usb_page_cache *pcdev; - struct xhci_dev_ctx *pdev; - uint8_t index; + DPRINTFN(5, "trb = %p\n", trb); + DPRINTFN(5, "qwTrb0 = 0x%016llx\n", (long long)le64toh(trb->qwTrb0)); + DPRINTFN(5, "dwTrb2 = 0x%08x\n", le32toh(trb->dwTrb2)); + DPRINTFN(5, "dwTrb3 = 0x%08x\n", le32toh(trb->dwTrb3)); +} - index = udev->controller_slot_id; +static void +xhci_dump_endpoint(struct xhci_endp_ctx *pep) +{ + DPRINTFN(5, "pep = %p\n", pep); + DPRINTFN(5, "dwEpCtx0=0x%08x\n", pep->dwEpCtx0); + DPRINTFN(5, "dwEpCtx1=0x%08x\n", pep->dwEpCtx1); + DPRINTFN(5, "qwEpCtx2=0x%016llx\n", (long long)pep->qwEpCtx2); + DPRINTFN(5, "dwEpCtx4=0x%08x\n", pep->dwEpCtx4); + DPRINTFN(5, "dwEpCtx5=0x%08x\n", pep->dwEpCtx5); + DPRINTFN(5, "dwEpCtx6=0x%08x\n", pep->dwEpCtx6); + DPRINTFN(5, "dwEpCtx7=0x%08x\n", pep->dwEpCtx7); +} - pcdev = &sc->sc_hw.devs[index].device_pc; - - usbd_get_page(pcdev, 0, &buf_dev); - - usb_pc_cpu_invalidate(pcdev); - - pdev = buf_dev.buffer; - - DPRINTF("SCTX0=0x%08x\n", pdev->ctx_slot.dwSctx0); - DPRINTF("SCTX1=0x%08x\n", pdev->ctx_slot.dwSctx1); - DPRINTF("SCTX2=0x%08x\n", pdev->ctx_slot.dwSctx2); - DPRINTF("SCTX3=0x%08x\n", pdev->ctx_slot.dwSctx3); +static void +xhci_dump_device(struct xhci_slot_ctx *psl) +{ + DPRINTFN(5, "psl = %p\n", psl); + DPRINTFN(5, "dwSctx0=0x%08x\n", psl->dwSctx0); + DPRINTFN(5, "dwSctx1=0x%08x\n", psl->dwSctx1); + DPRINTFN(5, "dwSctx2=0x%08x\n", psl->dwSctx2); + DPRINTFN(5, "dwSctx3=0x%08x\n", psl->dwSctx3); } #endif -#endif static void xhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb) @@ -208,7 +224,7 @@ for (i = 0; i != 100; i++) { usb_pause_mtx(NULL, hz / 1000); - temp = XREAD4(sc, oper, XHCI_USBCMD) & XHCI_CMD_HCRST; + temp = XREAD4(sc, oper, XHCI_USBCMD) & (XHCI_CMD_HCRST | XHCI_STS_CNR); if (!temp) break; } @@ -242,6 +258,9 @@ /* setup number of device slots */ + DPRINTF("CONFIG=0x%08x -> 0x%08x\n", + XREAD4(sc, oper, XHCI_CONFIG), sc->sc_noslot); + XWRITE4(sc, oper, XHCI_CONFIG, sc->sc_noslot); DPRINTF("Max slots: %u\n", sc->sc_noslot); @@ -279,10 +298,11 @@ memset(pdctxa, 0, sizeof(*pdctxa)); - addr = buf_res.physaddr + (uintptr_t)&((struct xhci_dev_ctx_addr *)0)->qwSpBufPtr[0]; + addr = buf_res.physaddr; + addr += (uintptr_t)&((struct xhci_dev_ctx_addr *)0)->qwSpBufPtr[0]; /* slot 0 points to the table of scratchpad pointers */ - pdctxa->qwBaaDevCtxAddr[0] = htole64(buf_res.physaddr); + pdctxa->qwBaaDevCtxAddr[0] = htole64(addr); for (i = 0; i != sc->sc_noscratch; i++) { @@ -298,11 +318,26 @@ XWRITE4(sc, oper, XHCI_DCBAAP_LO, (uint32_t)addr); XWRITE4(sc, oper, XHCI_DCBAAP_HI, (uint32_t)(addr >> 32)); - /* Setup interrupter registers */ + XWRITE4(sc, oper, XHCI_DCBAAP_LO, (uint32_t)addr); + XWRITE4(sc, oper, XHCI_DCBAAP_HI, (uint32_t)(addr >> 32)); + + /* Setup event table size */ + + temp = XREAD4(sc, capa, XHCI_HCSPARAMS2); + + DPRINTF("HCS2=0x%08x\n", temp); + + temp = XHCI_HCS2_ERST_MAX(temp); + temp = 1U << temp; + if (temp > XHCI_MAX_RSEG) + temp = XHCI_MAX_RSEG; + + sc->sc_erst_max = temp; + + DPRINTF("ERSTSZ=0x%08x -> 0x%08x\n", + XREAD4(sc, runt, XHCI_ERSTSZ(0)), temp); - temp = XREAD4(sc, runt, XHCI_IMAN(0)); - temp |= XHCI_IMAN_INTR_ENA; - XWRITE4(sc, runt, XHCI_IMAN(0), temp); + XWRITE4(sc, runt, XHCI_ERSTSZ(0), XHCI_ERSTS_SET(temp)); /* Setup interrupt rate */ @@ -311,7 +346,8 @@ usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); phwr = buf_res.buffer; - addr = (uint64_t)buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[0]; + addr = buf_res.physaddr; + addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[0]; /* reset hardware root structure */ @@ -320,21 +356,6 @@ phwr->hwr_ring_seg[0].qwEvrsTablePtr = htole64(addr); phwr->hwr_ring_seg[0].dwEvrsTableSize = htole32(XHCI_MAX_EVENTS); - /* Setup event table size */ - - temp = XREAD4(sc, capa, XHCI_HCSPARAMS2); - - DPRINTF("HCS2=0x%08x\n", temp); - - temp = XHCI_HCS2_ERST_MAX(temp); - temp = 1U << temp; - if (temp > XHCI_MAX_RSEG) - temp = XHCI_MAX_RSEG; - - sc->sc_erst_max = temp; - - XWRITE4(sc, runt, XHCI_ERSTSZ(0), XHCI_ERSTS_SET(temp)); - DPRINTF("ERDP(0)=0x%016llx\n", (unsigned long long)addr); XWRITE4(sc, runt, XHCI_ERDP_LO(0), (uint32_t)addr); @@ -347,9 +368,16 @@ XWRITE4(sc, runt, XHCI_ERSTBA_LO(0), (uint32_t)addr); XWRITE4(sc, runt, XHCI_ERSTBA_HI(0), (uint32_t)(addr >> 32)); + /* Setup interrupter registers */ + + temp = XREAD4(sc, runt, XHCI_IMAN(0)); + temp |= XHCI_IMAN_INTR_ENA; + XWRITE4(sc, runt, XHCI_IMAN(0), temp); + /* setup command ring control base address */ - addr = (uint64_t)buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[0]; + addr = buf_res.physaddr; + addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[0]; DPRINTF("CRCR=0x%016llx\n", (unsigned long long)addr); @@ -428,12 +456,6 @@ sc->sc_bus.devices = sc->sc_devices; sc->sc_bus.devices_max = XHCI_MAX_DEVICES; - /* - * The XHCI is very high level at this point and requires - * special handling. - */ - sc->sc_bus.no_set_address = 1; - /* setup command queue mutex and condition varible */ cv_init(&sc->sc_cmd_cv, "CMDQ"); sx_init(&sc->sc_cmd_sx, "CMDQ lock"); @@ -509,7 +531,7 @@ status = td->status; len = td->remainder; - DPRINTFN(4, "xfer=%p[%u/%u] len=%u/%u status=%u\n", + DPRINTFN(4, "xfer=%p[%u/%u] rem=%u/%u status=%u\n", xfer, (unsigned int)xfer->aframes, (unsigned int)xfer->nframes, (unsigned int)len, (unsigned int)td->len, @@ -620,13 +642,23 @@ struct xhci_endpoint_ext *pepext; uint64_t td_event; uint32_t temp; - uint32_t actlen; + uint32_t remainder; uint8_t status; + uint8_t halted; /* decode TRB */ - td_event = trb->qwTrb0; + td_event = le64toh(trb->qwTrb0); temp = le32toh(trb->dwTrb2); + remainder = XHCI_TRB_2_REM_GET(temp); + status = XHCI_TRB_2_ERROR_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); + /* try to find the USB transfer that generated the event */ TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { @@ -634,7 +666,8 @@ if (xfer->flags_int.did_dma_delay) continue; - pepext = xhci_get_endpoint_ext(xfer); + pepext = xhci_get_endpoint_ext(xfer->xroot->udev, + xfer->endpoint->edesc); /* check if endpoint is halted */ if (pepext->trb_halted != 0) @@ -642,19 +675,24 @@ td = xfer->td_transfer_cache; - if (td_event == td->td_event) { + DPRINTF("0x%08llx == (0x%08llx .. 0x%08llx)\n", + (long long)td_event, + (long long)td->td_self, + (long long)td->td_event_last); + + if ((td_event == td->td_event_last) || + (halted && (td_event >= td->td_self) && + (td_event < td->td_event_last))) { 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); + pepext = xhci_get_endpoint_ext(xfer->xroot->udev, + xfer->endpoint->edesc); usb_pc_cpu_invalidate(td->page_cache); /* "td->remainder" is verified later */ - td->remainder -= actlen; + td->remainder = remainder; td->status = status; usb_pc_cpu_flush(td->page_cache); @@ -664,6 +702,7 @@ * transfer done */ if (((void *)td) == xfer->td_transfer_last) { + DPRINTF("TD is last\n"); xhci_generic_done(xfer); break; } @@ -672,8 +711,8 @@ * 2) Any kind of error makes the transfer * done */ - if ((status != XHCI_TRB_ERROR_SHORT_PKT) && - (status != XHCI_TRB_ERROR_SUCCESS)) { + if (halted) { + DPRINTF("TD has I/O error\n"); xhci_generic_done(xfer); break; } @@ -683,6 +722,7 @@ * a short packet also makes the transfer done */ if (td->remainder > 0) { + DPRINTF("TD has short pkt\n"); if (xfer->flags_int.short_frames_ok) { /* follow alt next */ if (td->alt_next != NULL) { @@ -697,6 +737,7 @@ /* * 4) Transfer complete - go to next TD */ + DPRINTF("Following next TD\n"); xfer->td_transfer_cache = td->obj_next; break; /* there should only be one match */ } @@ -719,6 +760,7 @@ { struct usb_page_search buf_res; struct xhci_hw_root *phwr; + uint64_t addr; uint32_t temp; uint16_t i; uint8_t event; @@ -741,6 +783,7 @@ while (1) { temp = le32toh(phwr->hwr_events[i].dwTrb3); + k = (temp & XHCI_TRB_3_CYCLE_BIT) ? 1 : 0; if (j != k) @@ -761,7 +804,7 @@ xhci_check_command(sc, &phwr->hwr_events[i]); break; default: - DPRINTF("Received event = 0x%x\n", event); + DPRINTF("Unhandled event = %u\n", event); break; } @@ -777,16 +820,24 @@ } } - temp = buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[i]; + sc->sc_event_idx = i; + sc->sc_event_ccs = j; - /* we are within a PAGE - no need to update the high bits */ + /* + * NOTE: The Event Ring Dequeue Pointer Register is 64-bit + * latched. That means to activate the register we need to + * write both the low and high double word of the 64-bit + * register. + */ - temp |= XHCI_ERDP_LO_SINDEX(i) | XHCI_ERDP_LO_BUSY; + addr = (uint32_t)buf_res.physaddr; + addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[i]; - XWRITE4(sc, runt, XHCI_ERDP_LO(0), temp); + /* try to clear busy bit */ + addr |= XHCI_ERDP_LO_BUSY; - sc->sc_event_idx = i; - sc->sc_event_ccs = j; + XWRITE4(sc, runt, XHCI_ERDP_LO(0), (uint32_t)addr); + XWRITE4(sc, runt, XHCI_ERDP_HI(0), (uint32_t)(addr >> 32)); } static usb_error_t @@ -817,7 +868,7 @@ j = sc->sc_command_ccs; DPRINTFN(10, "command[%u] = %u (0x%016llx, 0x%08lx, 0x%08lx)\n", - i, XHCI_TRB_3_TYPE_GET(le32toh(trb->qwTrb0)), + i, XHCI_TRB_3_TYPE_GET(le32toh(trb->dwTrb3)), (long long)le64toh(trb->qwTrb0), (long)le32toh(trb->dwTrb2), (long)le32toh(trb->dwTrb3)); @@ -840,8 +891,8 @@ usb_pc_cpu_flush(&sc->sc_hw.root_pc); - addr = (uint64_t)buf_res.physaddr + - (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[i]; + addr = buf_res.physaddr; + addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[i]; sc->sc_cmd_addr = htole64(addr); @@ -850,12 +901,12 @@ if (i == (XHCI_MAX_COMMANDS - 1)) { if (j) { - temp |= htole32(XHCI_TRB_3_CYCLE_BIT | + temp = htole32(XHCI_TRB_3_TC_BIT | XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) | - XHCI_TRB_3_TC_BIT); + XHCI_TRB_3_CYCLE_BIT); } else { - temp &= htole32(XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) | - XHCI_TRB_3_TC_BIT); + temp = htole32(XHCI_TRB_3_TC_BIT | + XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK)); } phwr->hwr_commands[i].dwTrb3 = temp; @@ -882,7 +933,7 @@ } else { temp = le32toh(sc->sc_cmd_result[0]); if (XHCI_TRB_2_ERROR_GET(temp) != XHCI_TRB_ERROR_SUCCESS) - err = USB_ERR_INVAL; + err = USB_ERR_IOERROR; trb->dwTrb2 = sc->sc_cmd_result[0]; trb->dwTrb3 = sc->sc_cmd_result[1]; @@ -974,9 +1025,117 @@ trb.dwTrb3 = htole32(temp); - return (xhci_do_command(sc, &trb, 50 /* ms */)); + return (xhci_do_command(sc, &trb, 500 /* ms */)); +} + +static usb_error_t +xhci_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t address) +{ + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + struct xhci_hw_dev *hdev; + usb_error_t err; + uint8_t index; + + /* the root HUB case is not handled here */ + if (udev->parent_hub == NULL) + return (USB_ERR_INVAL); + + index = udev->controller_slot_id; + + hdev = &sc->sc_hw.devs[index]; + + if (mtx != NULL) + mtx_unlock(mtx); + + XHCI_CMD_LOCK(sc); + + switch (hdev->state) { + case XHCI_ST_ADDRESSED: + err = 0; + break; + + case XHCI_ST_ENABLED: + if (address == 0) { + err = 0; + break; + } + /* FALLTHROUGH */ + + case XHCI_ST_DEFAULT: + + /* set configure mask to slot and EP0 */ + xhci_configure_mask(udev, 3, 0); + + /* configure input slot context structure */ + err = xhci_configure_device(udev); + + /* configure input endpoint context structure */ + if (err == 0) { + struct xhci_endpoint_ext *pepext; + uint16_t mps; + + switch (udev->speed) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + mps = 8; + break; + case USB_SPEED_HIGH: + mps = 64; + break; + default: + mps = 512; + break; + } + + pepext = xhci_get_endpoint_ext(udev, + &udev->ctrl_ep_desc); + err = xhci_configure_endpoint(udev, + &udev->ctrl_ep_desc, pepext->physaddr, + 0, 1, mps, mps); + } + + /* execute set address command */ + if (err == 0) { + struct usb_page_search buf_inp; + + usbd_get_page(&hdev->input_pc, 0, &buf_inp); + + err = xhci_cmd_set_address(sc, buf_inp.physaddr, + (address == 0), index); + } + + /* update device address and state to new value */ + if (err == 0) { + struct usb_page_search buf_dev; + struct xhci_dev_ctx *pdev; + + if (address == 0) + hdev->state = XHCI_ST_DEFAULT; + else + hdev->state = XHCI_ST_ADDRESSED; + + usbd_get_page(&hdev->device_pc, 0, &buf_dev); + pdev = buf_dev.buffer; + usb_pc_cpu_invalidate(&hdev->device_pc); + udev->address = XHCI_SCTX_3_DEV_ADDR_GET(pdev->ctx_slot.dwSctx3); + } + break; + + default: + DPRINTF("Wrong state for set address.\n"); + err = USB_ERR_IOERROR; + break; + } + + XHCI_CMD_UNLOCK(sc); + + if (mtx != NULL) + mtx_lock(mtx); + + return (err); } +#if 0 static usb_error_t xhci_cmd_configure_ep(struct xhci_softc *sc, uint64_t input_ctx, uint8_t deconfigure, uint8_t slot_id) @@ -998,8 +1157,8 @@ return (xhci_do_command(sc, &trb, 50 /* ms */)); } +#endif -#if 0 static usb_error_t xhci_cmd_evaluate_ctx(struct xhci_softc *sc, uint64_t input_ctx, uint8_t slot_id) @@ -1017,7 +1176,6 @@ return (xhci_do_command(sc, &trb, 50 /* ms */)); } -#endif static usb_error_t xhci_cmd_reset_ep(struct xhci_softc *sc, uint8_t preserve, @@ -1042,7 +1200,6 @@ 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) @@ -1065,7 +1222,6 @@ 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) @@ -1105,9 +1261,11 @@ temp = XREAD4(sc, runt, XHCI_IMAN(0)); /* acknowledge pending event */ + XWRITE4(sc, runt, XHCI_IMAN(0), temp); - DPRINTFN(16, "real interrupt (sts=0x%08x, iman=0x%08x)\n", status, temp); + DPRINTFN(16, "real interrupt (sts=0x%08x, " + "iman=0x%08x)\n", status, temp); if (status != 0) { if (status & XHCI_STS_PCD) { @@ -1148,7 +1306,8 @@ USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); - pepext = xhci_get_endpoint_ext(xfer); + pepext = xhci_get_endpoint_ext(xfer->xroot->udev, + xfer->endpoint->edesc); #if 0 /* check if endpoint is halted */ @@ -1177,6 +1336,7 @@ struct xhci_td *td; struct xhci_td *td_next; struct xhci_td *td_alt_next; + uint64_t addr; uint32_t buf_offset; uint32_t average; uint32_t len_old; @@ -1241,7 +1401,7 @@ /* fill out current TD */ td->len = average; - td->remainder = average; + td->remainder = 0; td->status = 0; /* update remaining length */ @@ -1270,7 +1430,7 @@ td->td_trb[0].dwTrb2 = htole32(dword); dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_SETUP_STAGE) | - XHCI_TRB_3_IDT_BIT; + XHCI_TRB_3_IDT_BIT | XHCI_TRB_3_CYCLE_BIT; /* check wLength */ if (td->td_trb[0].qwTrb0 & htole64(0xFFFF00000000ULL)) { @@ -1281,7 +1441,9 @@ } td->td_trb[0].dwTrb3 = htole32(dword); - +#ifdef USB_DEBUG + xhci_dump_trb(&td->td_trb[x]); +#endif x++; } else do { @@ -1294,7 +1456,8 @@ npkt = 1; memset(&buf_res, 0, sizeof(buf_res)); } else { - usbd_get_page(temp->pc, temp->offset + buf_offset, &buf_res); + usbd_get_page(temp->pc, temp->offset + + buf_offset, &buf_res); /* get length to end of page */ if (buf_res.length > average) @@ -1305,7 +1468,9 @@ buf_res.length = XHCI_TD_PAGE_SIZE; /* setup npkt */ - npkt = (average + temp->max_packet_size - 1) / temp->max_packet_size; + npkt = (average + temp->max_packet_size - 1) / + temp->max_packet_size; + if (npkt > 31) npkt = 31; } @@ -1321,42 +1486,50 @@ td->td_trb[x].dwTrb2 = htole32(dword); - dword = XHCI_TRB_3_CHAIN_BIT | + dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT | XHCI_TRB_3_TYPE_SET(temp->trb_type) | XHCI_TRB_3_FRID_SET(temp->isoc_frame); if (temp->direction == UE_DIR_IN) dword |= XHCI_TRB_3_DIR_IN; + if (average == 0) + dword |= XHCI_TRB_3_IDT_BIT; + td->td_trb[x].dwTrb3 = htole32(dword); average -= buf_res.length; buf_offset += buf_res.length; +#ifdef USB_DEBUG + xhci_dump_trb(&td->td_trb[x]); +#endif x++; } while (average != 0); + td->td_trb[x-1].dwTrb3 |= htole32(XHCI_TRB_3_IOC_BIT); + /* store number of data TRB's */ td->ntrb = x; + DPRINTF("NTRB=%u\n", x); + /* compute event pointer */ - if (1) { - uint64_t td_event; - - td_event = le64toh(td->td_self); - td_event += x * sizeof(td->td_trb[0]); - td->td_event = htole64(td_event); - } + addr = td->td_self; + addr += (x - 1) * sizeof(struct xhci_trb); + td->td_event_last = addr; /* fill out link TRB */ if (td_next != NULL) { /* link the current TD with the next one */ - td->td_trb[x].qwTrb0 = td_next->td_self; + td->td_trb[x].qwTrb0 = htole64((uint64_t)td_next->td_self); + DPRINTF("LINK=0x%08llx\n", (long long)td_next->td_self); } else { /* this field will get updated later */ + DPRINTF("NOLINK\n"); } dword = XHCI_TRB_2_IRQ_SET(0); @@ -1364,12 +1537,15 @@ td->td_trb[x].dwTrb2 = htole32(dword); dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) | - XHCI_TRB_3_IOC_BIT | XHCI_TRB_3_CHAIN_BIT; + XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT | + XHCI_TRB_3_IOC_BIT; td->td_trb[x].dwTrb3 = htole32(dword); td->alt_next = td_alt_next; - +#ifdef USB_DEBUG + xhci_dump_trb(&td->td_trb[x]); +#endif usb_pc_cpu_flush(td->page_cache); } @@ -1388,15 +1564,15 @@ temp->shortpkt = shortpkt_old; temp->len = len_old; goto restart; - } else { - if (temp->multishort == 0) { - /* remove chain bit and clear TD SIZE - end of frame */ - td->td_trb[td->ntrb - 1].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15)); - td->td_trb[td->ntrb - 1].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT); - td->td_trb[td->ntrb].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15)); - td->td_trb[td->ntrb].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT); - usb_pc_cpu_flush(td->page_cache); - } + } + + if (temp->multishort == 0) { + /* remove chain bit and clear TD SIZE - end of frame */ + td->td_trb[td->ntrb - 1].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15)); + td->td_trb[td->ntrb - 1].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT); + td->td_trb[td->ntrb].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15)); + td->td_trb[td->ntrb].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT); + usb_pc_cpu_flush(td->page_cache); } temp->td = td; temp->td_next = td_next; @@ -1605,6 +1781,8 @@ /* must have at least one frame! */ xfer->td_transfer_last = td; + + DPRINTF("first=%p last=%p\n", xfer->td_transfer_first, td); } static void @@ -1617,6 +1795,8 @@ pdctxa = buf_res.buffer; + DPRINTF("addr[%u]=0x%016llx\n", index, (long long)dev_addr); + pdctxa->qwBaaDevCtxAddr[index] = htole64(dev_addr); usb_pc_cpu_flush(&sc->sc_hw.ctx_pc); @@ -1640,31 +1820,49 @@ } static usb_error_t -xhci_configure_endpoint(struct usb_xfer *xfer, uint8_t drop) +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; + uint8_t index; + + index = udev->controller_slot_id; + + usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp); + + pinp = buf_inp.buffer; + + if (drop) { + mask &= 0xFFFFFFFC; + pinp->ctx_input.dwInCtx0 = htole32(mask); + pinp->ctx_input.dwInCtx1 = 0; + } else { + pinp->ctx_input.dwInCtx0 = 0; + pinp->ctx_input.dwInCtx1 = htole32(mask); + } + return (0); +} + +static usb_error_t +xhci_configure_endpoint(struct usb_device *udev, + struct usb_endpoint_descriptor *edesc, uint64_t ring_addr, + uint16_t interval, uint8_t max_packet_count, + uint16_t max_packet_size, uint16_t max_frame_size) { struct usb_page_search buf_inp; - struct usb_page_search buf_ep; - struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus); + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); struct xhci_input_dev_ctx *pinp; - struct usb_endpoint_descriptor *edesc; - struct xhci_endpoint_ext *pepext; - struct usb_device *udev; - uint64_t addr; uint32_t temp; - uint32_t mask; uint8_t index; uint8_t epno; uint8_t k; - 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); - edesc = xfer->endpoint->edesc; + pinp = buf_inp.buffer; epno = edesc->bEndpointAddress; @@ -1674,23 +1872,12 @@ epno = XHCI_EPNO2EPID(epno); if (epno == 0) - return (USB_ERR_INVAL); /* invalid */ + return (USB_ERR_NO_PIPE); /* invalid */ - usbd_get_page(&sc->sc_hw.devs[index].endpoint_pc, (XHCI_MAX_TRANSFERS * sizeof(struct xhci_trb)) * epno, &buf_ep); + if (max_packet_count == 0) + return (USB_ERR_BAD_BUFSIZE); - pinp = buf_inp.buffer; - - mask = 1U << epno; - - if (drop) { - mask &= 0xFFFFFFFC; - pinp->ctx_input.dwInCtx0 = htole32(mask); - pinp->ctx_input.dwInCtx1 = 0; - } else { - mask |= 1; - pinp->ctx_input.dwInCtx0 = 0; - pinp->ctx_input.dwInCtx1 = htole32(mask); - } + max_packet_count --; temp = XHCI_EPCTX_0_EPSTATE_SET(0) | XHCI_EPCTX_0_MAXP_STREAMS_SET(0) | @@ -1698,12 +1885,12 @@ switch (edesc->bmAttributes & UE_XFERTYPE) { case UE_INTERRUPT: - k = xhci_log2(xfer->interval) + 3; + k = xhci_log2(interval) + 3; temp |= XHCI_EPCTX_0_IVAL_SET(k); break; case UE_ISOCHRONOUS: if (udev->speed == USB_SPEED_SUPER) - temp |= XHCI_EPCTX_0_MULT_SET(xfer->max_packet_count - 1); + temp |= XHCI_EPCTX_0_MULT_SET(max_packet_count); break; default: break; @@ -1713,8 +1900,8 @@ temp = XHCI_EPCTX_1_HID_SET(0) | - XHCI_EPCTX_1_MAXB_SET(xfer->max_packet_count - 1) | - XHCI_EPCTX_1_MAXP_SIZE_SET(xfer->max_packet_size); + XHCI_EPCTX_1_MAXB_SET(max_packet_count) | + XHCI_EPCTX_1_MAXP_SIZE_SET(max_packet_size); if ((udev->parent_hs_hub != NULL) || (udev->address != 0)) temp |= XHCI_EPCTX_1_CERR_SET(3); @@ -1739,34 +1926,38 @@ pinp->ctx_ep[epno - 1].dwEpCtx1 = htole32(temp); - if (drop == 0) { + ring_addr |= XHCI_EPCTX_2_DCS_SET(1); - USB_BUS_LOCK(&sc->sc_bus); + pinp->ctx_ep[epno - 1].qwEpCtx2 = htole64(ring_addr); - pepext->trb_ccs = 1; - pepext->trb_index = 0; + temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(max_frame_size) | + XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(max_frame_size); - for (k = 0; k != XHCI_MAX_TRANSFERS; k++) - pepext->trb[k].dwTrb3 = 0; + pinp->ctx_ep[epno - 1].dwEpCtx4 = htole32(temp); - usb_pc_cpu_flush(pepext->page_cache); +#ifdef USB_DEBUG + xhci_dump_endpoint(&pinp->ctx_ep[epno - 1]); +#endif + usb_pc_cpu_flush(&sc->sc_hw.devs[index].input_pc); - USB_BUS_UNLOCK(&sc->sc_bus); - } + return (0); /* success */ +} - addr = XHCI_EPCTX_2_DCS_SET(1) | - (buf_ep.physaddr + (uintptr_t)&((struct xhci_dev_endpoint_trbs *)0)->trb[epno][0]); +static usb_error_t +xhci_configure_endpoint_by_xfer(struct usb_xfer *xfer) +{ + struct xhci_endpoint_ext *pepext; - pinp->ctx_ep[epno - 1].qwEpCtx2 = htole64(addr); + pepext = xhci_get_endpoint_ext(xfer->xroot->udev, + xfer->endpoint->edesc); - temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(xfer->max_frame_size) | - XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(xfer->max_frame_size); + pepext->trb[0].dwTrb3 = 0; /* halt any transfers */ + usb_pc_cpu_flush(pepext->page_cache); - pinp->ctx_ep[epno - 1].dwEpCtx4 = htole32(temp); - - usb_pc_cpu_flush(&sc->sc_hw.devs[index].input_pc); - - return (0); /* success */ + return (xhci_configure_endpoint(xfer->xroot->udev, + xfer->endpoint->edesc, pepext->physaddr, + xfer->interval, xfer->max_packet_count, + xfer->max_packet_size, xfer->max_frame_size)); } static usb_error_t @@ -1778,39 +1969,57 @@ struct usb_page_cache *pcdev; struct usb_page_cache *pcinp; struct xhci_input_dev_ctx *pinp; + struct xhci_dev_ctx *pdev; struct usb_device *hubdev; uint32_t temp; + uint32_t route; + uint8_t is_hub; uint8_t index; uint8_t rh_port; index = udev->controller_slot_id; + DPRINTF("index=%u\n", index); + pcdev = &sc->sc_hw.devs[index].device_pc; >>> TRUNCATED FOR MAIL (1000 lines) <<<