Date: Mon, 16 Sep 2013 01:05:35 GMT From: bguan@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r257392 - soc2013/bguan/head/sys/dev/xen/usbfront Message-ID: <201309160105.r8G15Z8u019296@socsvn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: bguan Date: Mon Sep 16 01:05:35 2013 New Revision: 257392 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=257392 Log: debug method xenhci_roothub_exec() for xen usb host controller Modified: soc2013/bguan/head/sys/dev/xen/usbfront/xenhci.c Modified: soc2013/bguan/head/sys/dev/xen/usbfront/xenhci.c ============================================================================== --- soc2013/bguan/head/sys/dev/xen/usbfront/xenhci.c Mon Sep 16 00:06:54 2013 (r257391) +++ soc2013/bguan/head/sys/dev/xen/usbfront/xenhci.c Mon Sep 16 01:05:35 2013 (r257392) @@ -93,92 +93,1424 @@ #define XENHCI_INTR_ENDPT 1 extern struct usb_bus_methods xenhci_bus_methods; +extern struct usb_pipe_methods xenhci_device_generic_methods; +static void xenhci_timeout(void *); +static void xenhci_device_done(struct usb_xfer *, usb_error_t); + /* static void -xenhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb) +xenhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb) +{ + //TODO need this method()? +}*/ + +usb_error_t +xenhci_start_controller(struct xenhci_softc *sc) +{ + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xenhci.c: xenhci_start_controller()\n"); + #endif + //TODO + /* catch any lost interrupts */ + xenhci_do_poll(&sc->sc_bus); + + return (0); +} + +usb_error_t +xenhci_halt_controller(struct xenhci_softc *sc) +{ + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xenhci.c: xenhci_halt_controller()\n"); + #endif + //TODO + return (0); +} + +usb_error_t +xenhci_init(struct xenhci_softc *sc, device_t dev) +{ + /* initialise some bus fields */ + sc->sc_bus.parent = dev; + + /* set up the bus struct */ + sc->sc_bus.methods = &xenhci_bus_methods; + + /* setup devices array */ + sc->sc_bus.devices = sc->sc_devices; + sc->sc_bus.devices_max = XENHCI_MAX_DEVICES; + + /* get all DMA memory */ + //if (usb_bus_mem_alloc_all(&sc->sc_bus, + // USB_GET_DMA_TAG(dev), &xenhci_iterate_hw_softc)) { + if (usb_bus_mem_alloc_all(&sc->sc_bus, + USB_GET_DMA_TAG(dev), NULL)) { + return (ENOMEM); + } + + return (0); +} + +void +xenhci_uninit(struct xenhci_softc *sc) +{ + /* TODO? + * NOTE: At this point the control transfer process is gone + * and "xenhci_configure_msg" is no longer called. Consequently + * waiting for the configuration messages to complete is not + * needed. + */ + usb_bus_mem_free_all(&sc->sc_bus, NULL); +} + +static void +xenhci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state) +{ + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xenhci.c: xenhci_set_hw_power_sleep()\n"); + #endif + //TODO + struct xenhci_softc *sc = XENHCI_BUS2SC(bus); + + switch (state) { + case USB_HW_POWER_SUSPEND: + DPRINTF("Stopping the XENHCI\n"); + xenhci_halt_controller(sc); + break; + case USB_HW_POWER_SHUTDOWN: + DPRINTF("Stopping the XENHCI\n"); + xenhci_halt_controller(sc); + break; + case USB_HW_POWER_RESUME: + DPRINTF("Starting the XENHCI\n"); + xenhci_start_controller(sc); + break; + default: + break; + } +} + +static usb_error_t +xenhci_generic_done_sub(struct usb_xfer *xfer) +{ + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xenhci.c: xenhci_generic_done_sub()\n"); + #endif + + struct xenhci_td *td; + struct xenhci_td *td_alt_next; + uint32_t len; + uint8_t status; + + td = xfer->td_transfer_cache; + td_alt_next = td->alt_next; + + if (xfer->aframes != xfer->nframes) + usbd_xfer_set_frame_len(xfer, xfer->aframes, 0); + + while (1) { + + usb_pc_cpu_invalidate(td->page_cache); + + status = td->status; + len = td->remainder; + + 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, + (unsigned int)status); + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]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, + (unsigned int)status); + #endif + + /* + * Verify the status length and + * add the length to "frlengths[]": + */ + if (len > td->len) { + /* should not happen */ + DPRINTF("Invalid status length, " + "0x%04x/0x%04x bytes\n", len, td->len); + + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]Invalid status length, " + "0x%04x/0x%04x bytes\n", len, td->len); + #endif + + status = XENHCI_TRB_ERROR_LENGTH; + } else if (xfer->aframes != xfer->nframes) { + xfer->frlengths[xfer->aframes] += td->len - len; + } + /* Check for last transfer */ + if (((void *)td) == xfer->td_transfer_last) { + td = NULL; + break; + } + /* Check for transfer error */ + if (status != XENHCI_TRB_ERROR_SHORT_PKT && + status != XENHCI_TRB_ERROR_SUCCESS) { + /* the transfer is finished */ + td = NULL; + break; + } + /* Check for short transfer */ + if (len > 0) { + if (xfer->flags_int.short_frames_ok || + xfer->flags_int.isochronous_xfr || + xfer->flags_int.control_xfr) { + /* follow alt next */ + td = td->alt_next; + } else { + /* the transfer is finished */ + td = NULL; + } + break; + } + td = td->obj_next; + + if (td->alt_next != td_alt_next) { + /* this USB frame is complete */ + break; + } + } + + /* update transfer cache */ + + xfer->td_transfer_cache = td; + + return ((status == XENHCI_TRB_ERROR_STALL) ? USB_ERR_STALLED : + (status != XENHCI_TRB_ERROR_SHORT_PKT && + status != XENHCI_TRB_ERROR_SUCCESS) ? USB_ERR_IOERROR : + USB_ERR_NORMAL_COMPLETION); +} + +static void +xenhci_generic_done(struct usb_xfer *xfer) +{ + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xenhci.c: xenhci_generic_done()\n"); + #endif + + usb_error_t err = 0; + + DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n", + xfer, xfer->endpoint); + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xfer=%p endpoint=%p transfer done\n", + xfer, xfer->endpoint); + #endif + + /* reset scanner */ + xfer->td_transfer_cache = xfer->td_transfer_first; + + if (xfer->flags_int.control_xfr) { + if (xfer->flags_int.control_hdr) + err = xenhci_generic_done_sub(xfer); + + xfer->aframes = 1; + + if (xfer->td_transfer_cache == NULL) + goto done; + } + + while (xfer->aframes != xfer->nframes) { + + err = xenhci_generic_done_sub(xfer); + xfer->aframes++; + + if (xfer->td_transfer_cache == NULL) + goto done; + } + + if (xfer->flags_int.control_xfr && + !xfer->flags_int.control_act) + err = xenhci_generic_done_sub(xfer); +done: + /* transfer is complete */ + //xhci_device_done(xfer, err); +} + +static void +xenhci_activate_transfer(struct usb_xfer *xfer) +{ + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xenhci.c: xenhci_activate_transfer()\n"); + #endif + + struct xenhci_td *td; + + td = xfer->td_transfer_cache; + + usb_pc_cpu_invalidate(td->page_cache); + + if (!(td->td_trb[0].dwTrb3 & htole32(XENHCI_TRB_3_CYCLE_BIT))) { + + /* activate the transfer */ + td->td_trb[0].dwTrb3 |= htole32(XENHCI_TRB_3_CYCLE_BIT); + usb_pc_cpu_flush(td->page_cache); + + //xhci_endpoint_doorbell(xfer);//? + } +} + +static void +xenhci_skip_transfer(struct usb_xfer *xfer) +{ + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xenhci.c: xenhci_skip_transfer()\n"); + #endif + + struct xenhci_td *td; + struct xenhci_td *td_last; + + td = xfer->td_transfer_cache; + td_last = xfer->td_transfer_last; + + td = td->alt_next; + + usb_pc_cpu_invalidate(td->page_cache); + + if (!(td->td_trb[0].dwTrb3 & htole32(XENHCI_TRB_3_CYCLE_BIT))) { + + usb_pc_cpu_invalidate(td_last->page_cache); + + /* copy LINK TRB to current waiting location */ + td->td_trb[0].qwTrb0 = td_last->td_trb[td_last->ntrb].qwTrb0; + td->td_trb[0].dwTrb2 = td_last->td_trb[td_last->ntrb].dwTrb2; + usb_pc_cpu_flush(td->page_cache); + + td->td_trb[0].dwTrb3 = td_last->td_trb[td_last->ntrb].dwTrb3; + usb_pc_cpu_flush(td->page_cache); + + //xhci_endpoint_doorbell(xfer);//? + } +} + +/*------------------------------------------------------------------------* + * xenhci_check_transfer + *------------------------------------------------------------------------*/ +static void +xenhci_check_transfer(struct xenhci_softc *sc, struct xenhci_trb *trb) +{ + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xenhci.c: xenhci_check_transfer()\n"); + #endif + + struct xenhci_endpoint_ext *pepext; + int64_t offset; + uint64_t td_event; + uint32_t temp; + uint32_t remainder; + uint16_t stream_id; + uint16_t i; + uint8_t status; + uint8_t halted; + uint8_t epno; + uint8_t index; + + /* decode TRB */ + td_event = le64toh(trb->qwTrb0); + temp = le32toh(trb->dwTrb2); + + remainder = XENHCI_TRB_2_REM_GET(temp); + + status = XENHCI_TRB_2_ERROR_GET(temp); + stream_id = XENHCI_TRB_2_STREAM_GET(temp); + + temp = le32toh(trb->dwTrb3); + epno = XENHCI_TRB_3_EP_GET(temp); + index = XENHCI_TRB_3_SLOT_GET(temp); + + /* check if error means halted */ + halted = (status != XENHCI_TRB_ERROR_SHORT_PKT && + status != XENHCI_TRB_ERROR_SUCCESS); + + DPRINTF("slot=%u epno=%u stream=%u remainder=%u status=%u\n", + index, epno, stream_id, remainder, status); + #ifdef XENUSB_BEBUG + printf("[gbtest]slot=%u epno=%u stream=%u remainder=%u status=%u\n", + index, epno, stream_id, remainder, status); + #endif + + if (index > sc->sc_noslot) { + DPRINTF("Invalid slot.\n"); + return; + } + + if ((epno == 0) || (epno >= XENHCI_MAX_ENDPOINTS)) { + DPRINTF("Invalid endpoint.\n"); + return; + } + + pepext = &sc->sc_hw.devs[index].endp[epno]; + + if (pepext->trb_ep_mode != USB_EP_MODE_STREAMS) { + stream_id = 0; + DPRINTF("stream_id=0\n"); + } else if (stream_id >= XENHCI_MAX_STREAMS) { + DPRINTF("Invalid stream ID.\n"); + return; + } + + /* try to find the USB transfer that generated the event */ + for (i = 0; i != (XENHCI_MAX_TRANSFERS - 1); i++) { + struct usb_xfer *xfer; + struct xenhci_td *td; + + xfer = pepext->xfer[i + (XENHCI_MAX_TRANSFERS * stream_id)]; + if (xfer == NULL) + continue; + + td = xfer->td_transfer_cache; + + DPRINTFN(5, "Checking if 0x%016llx == (0x%016llx .. 0x%016llx)\n", + (long long)td_event, + (long long)td->td_self, + (long long)td->td_self + sizeof(td->td_trb)); + #ifdef XENUSB_BEBUG + printf("[gbtest]Checking if 0x%016llx == (0x%016llx .. 0x%016llx)\n", + (long long)td_event, + (long long)td->td_self, + (long long)td->td_self + sizeof(td->td_trb)); + #endif + + /* + * NOTE: Some XENHCI implementations might not trigger + * an event on the last LINK TRB so we need to + * consider both the last and second last event + * address as conditions for a successful transfer. + * + * NOTE: We assume that the XENHCI will only trigger one + * event per chain of TRBs. + */ + + offset = td_event - td->td_self; + + if (offset >= 0 && + offset < (int64_t)sizeof(td->td_trb)) { + + usb_pc_cpu_invalidate(td->page_cache); + + /* compute rest of remainder, if any */ + for (i = (offset / 16) + 1; i < td->ntrb; i++) { + temp = le32toh(td->td_trb[i].dwTrb2); + remainder += XENHCI_TRB_2_BYTES_GET(temp); + } + + DPRINTFN(5, "New remainder: %u\n", remainder); + + /* clear isochronous transfer errors */ + if (xfer->flags_int.isochronous_xfr) { + if (halted) { + halted = 0; + status = XENHCI_TRB_ERROR_SUCCESS; + remainder = td->len; + } + } + + /* "td->remainder" is verified later */ + td->remainder = remainder; + td->status = status; + + usb_pc_cpu_flush(td->page_cache); + + /* + * 1) Last transfer descriptor makes the + * transfer done + */ + if (((void *)td) == xfer->td_transfer_last) { + DPRINTF("TD is last\n"); + xenhci_generic_done(xfer); + break; + } + + /* + * 2) Any kind of error makes the transfer + * done + */ + if (halted) { + DPRINTF("TD has I/O error\n"); + xenhci_generic_done(xfer); + break; + } + + /* + * 3) If there is no alternate next transfer, + * a short packet also makes the transfer done + */ + if (td->remainder > 0) { + if (td->alt_next == NULL) { + DPRINTF( + "short TD has no alternate next\n"); + xenhci_generic_done(xfer); + break; + } + DPRINTF("TD has short pkt\n"); + if (xfer->flags_int.short_frames_ok || + xfer->flags_int.isochronous_xfr || + xfer->flags_int.control_xfr) { + /* follow the alt next */ + xfer->td_transfer_cache = td->alt_next; + xenhci_activate_transfer(xfer); + break; + } + xenhci_skip_transfer(xfer); + xenhci_generic_done(xfer); + break; + } + + /* + * 4) Transfer complete - go to next TD + */ + DPRINTF("Following next TD\n"); + xfer->td_transfer_cache = td->obj_next; + xenhci_activate_transfer(xfer); + break; /* there should only be one match */ + } + } +} + +static void +xenhci_check_command(struct xenhci_softc *sc, struct xenhci_trb *trb) +{ + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xenhci.c: xenhci_check_command()\n"); + #endif + + if (sc->sc_cmd_addr == trb->qwTrb0) { + DPRINTF("Received command event\n"); + sc->sc_cmd_result[0] = trb->dwTrb2; + sc->sc_cmd_result[1] = trb->dwTrb3; + cv_signal(&sc->sc_cmd_cv); + } +} + +static void +xenhci_interrupt_poll(struct xenhci_softc *sc) +{ + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xenhci.c: xenhci_interrupt_poll()\n"); + #endif + + struct usb_page_search buf_res; + struct xenhci_hw_root *phwr; + //uint64_t addr; + uint32_t temp; + uint16_t i; + uint8_t event; + uint8_t j; + uint8_t k; + uint8_t t; + + usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); + + phwr = buf_res.buffer; + + /* Receive any events */ + + usb_pc_cpu_invalidate(&sc->sc_hw.root_pc); + + i = sc->sc_event_idx; + j = sc->sc_event_ccs; + t = 2; + + while (1) { + + temp = le32toh(phwr->hwr_events[i].dwTrb3); + + k = (temp & XENHCI_TRB_3_CYCLE_BIT) ? 1 : 0; + + if (j != k) + break; + + event = XENHCI_TRB_3_TYPE_GET(temp); + + DPRINTFN(10, "event[%u] = %u (0x%016llx 0x%08lx 0x%08lx)\n", + i, event, (long long)le64toh(phwr->hwr_events[i].qwTrb0), + (long)le32toh(phwr->hwr_events[i].dwTrb2), + (long)le32toh(phwr->hwr_events[i].dwTrb3)); + #ifdef XENUSB_BEBUG + printf("[gbtest]event[%u] = %u (0x%016llx 0x%08lx 0x%08lx)\n", + i, event, (long long)le64toh(phwr->hwr_events[i].qwTrb0), + (long)le32toh(phwr->hwr_events[i].dwTrb2), + (long)le32toh(phwr->hwr_events[i].dwTrb3)); + #endif + + switch (event) { + case XENHCI_TRB_EVENT_TRANSFER: + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xenhci.c: XENHCI_TRB_EVENT_TRANSFER\n"); + #endif + xenhci_check_transfer(sc, &phwr->hwr_events[i]); + break; + case XENHCI_TRB_EVENT_CMD_COMPLETE: + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xenhci.c: XENHCI_TRB_EVENT_CMD_COMPLETE\n"); + #endif + xenhci_check_command(sc, &phwr->hwr_events[i]); + break; + default: + DPRINTF("Unhandled event = %u\n", event); + break; + } + + i++; + + if (i == XENHCI_MAX_EVENTS) { + i = 0; + j ^= 1; + + /* check for timeout */ + if (!--t) + break; + } + } + + sc->sc_event_idx = i; + sc->sc_event_ccs = j; + + /* + * 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. + */ + + //addr = (uint32_t)buf_res.physaddr; + //addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[i]; + + /* try to clear busy bit */ + //addr |= XHCI_ERDP_LO_BUSY; + + //XWRITE4(sc, runt, XHCI_ERDP_LO(0), (uint32_t)addr); + //XWRITE4(sc, runt, XHCI_ERDP_HI(0), (uint32_t)(addr >> 32)); +} + + +/*------------------------------------------------------------------------* + * xenhci_timeout - XENHCI timeout handler + *------------------------------------------------------------------------*/ +static void +xenhci_timeout(void *arg) +{ + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xenhci.c: xenhci_timeout()\n"); + #endif + + struct usb_xfer *xfer = arg; + + DPRINTF("xfer=%p\n", xfer); + + USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); + + /* transfer is transferred */ + xenhci_device_done(xfer, USB_ERR_TIMEOUT); +} + +static void +xenhci_do_poll(struct usb_bus *bus) +{ + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xenhci.c: xenhci_do_poll()\n"); + #endif + + struct xenhci_softc *sc = XENHCI_BUS2SC(bus); + + USB_BUS_LOCK(&sc->sc_bus); + xenhci_interrupt_poll(sc); + USB_BUS_UNLOCK(&sc->sc_bus); +} + +static usb_error_t +xenhci_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t address) +{ + #ifdef XENUSB_BEBUG + printf("[xenusb_debug]xenhci.c: xenhci_set_address()\n"); + #endif + //TODO + return (0); +} + + + + + +/*------------------------------------------------------------------------* + * + */ +static void +xenhci_setup_generic_chain_sub(struct xenhci_std_temp *temp) +{ + struct usb_page_search buf_res; + struct xenhci_td *td; + struct xenhci_td *td_next; + struct xenhci_td *td_alt_next; + struct xenhci_td *td_first; + uint32_t buf_offset; + uint32_t average; + uint32_t len_old; + uint32_t npkt_off; + uint32_t dword; + uint8_t shortpkt_old; + uint8_t precompute; + uint8_t x; + + td_alt_next = NULL; + buf_offset = 0; + shortpkt_old = temp->shortpkt; + len_old = temp->len; + npkt_off = 0; + precompute = 1; + +restart: + + td = temp->td; + td_next = td_first = temp->td_next; + + while (1) { + + if (temp->len == 0) { + + if (temp->shortpkt) + break; + + /* send a Zero Length Packet, ZLP, last */ + + temp->shortpkt = 1; + average = 0; + + } else { + + average = temp->average; + + if (temp->len < average) { + if (temp->len % temp->max_packet_size) { + temp->shortpkt = 1; + } + average = temp->len; + } + } + + if (td_next == NULL) + panic("%s: out of XHCI transfer descriptors!", __FUNCTION__); + + /* get next TD */ + + td = td_next; + td_next = td->obj_next; + + /* check if we are pre-computing */ + + if (precompute) { + + /* update remaining length */ + + temp->len -= average; + + continue; + } + /* fill out current TD */ + + td->len = average; + td->remainder = 0; + td->status = 0; + + /* update remaining length */ + + temp->len -= average; + + /* reset TRB index */ + + x = 0; + + if (temp->trb_type == XENHCI_TRB_TYPE_SETUP_STAGE) { + /* immediate data */ + + if (average > 8) + average = 8; + + td->td_trb[0].qwTrb0 = 0; + + usbd_copy_out(temp->pc, temp->offset + buf_offset, + (uint8_t *)(uintptr_t)&td->td_trb[0].qwTrb0, + average); + + dword = XENHCI_TRB_2_BYTES_SET(8) | + XENHCI_TRB_2_TDSZ_SET(0) | + XENHCI_TRB_2_IRQ_SET(0); + + td->td_trb[0].dwTrb2 = htole32(dword); + + dword = XENHCI_TRB_3_TYPE_SET(XENHCI_TRB_TYPE_SETUP_STAGE) | + XENHCI_TRB_3_IDT_BIT | XENHCI_TRB_3_CYCLE_BIT; + + /* check wLength */ + if (td->td_trb[0].qwTrb0 & + htole64(XENHCI_TRB_0_WLENGTH_MASK)) { + if (td->td_trb[0].qwTrb0 & htole64(1)) + dword |= XENHCI_TRB_3_TRT_IN; + else + dword |= XENHCI_TRB_3_TRT_OUT; + } + + td->td_trb[0].dwTrb3 = htole32(dword); +#ifdef USB_DEBUG + xhci_dump_trb(&td->td_trb[x]); +#endif + x++; + + } else do { + + uint32_t npkt; + + /* fill out buffer pointers */ + + if (average == 0) { + npkt = 0; + memset(&buf_res, 0, sizeof(buf_res)); + } else { + usbd_get_page(temp->pc, temp->offset + + buf_offset, &buf_res); + + /* get length to end of page */ + if (buf_res.length > average) + buf_res.length = average; + + /* check for maximum length */ + if (buf_res.length > XENHCI_TD_PAGE_SIZE) + buf_res.length = XENHCI_TD_PAGE_SIZE; + + npkt_off += buf_res.length; + + /* setup npkt */ + npkt = (len_old - npkt_off + temp->max_packet_size - 1) / + temp->max_packet_size; + + if (npkt > 31) + npkt = 31; + } + + /* fill out TRB's */ + td->td_trb[x].qwTrb0 = + htole64((uint64_t)buf_res.physaddr); + + dword = + XENHCI_TRB_2_BYTES_SET(buf_res.length) | + XENHCI_TRB_2_TDSZ_SET(npkt) | + XENHCI_TRB_2_IRQ_SET(0); + + td->td_trb[x].dwTrb2 = htole32(dword); + + switch (temp->trb_type) { + case XENHCI_TRB_TYPE_ISOCH: + /* BEI: Interrupts are inhibited until EOT */ + dword = XENHCI_TRB_3_CHAIN_BIT | XENHCI_TRB_3_CYCLE_BIT | + XENHCI_TRB_3_BEI_BIT | + XENHCI_TRB_3_TBC_SET(temp->tbc) | + XENHCI_TRB_3_TLBPC_SET(temp->tlbpc); + if (td != td_first) { + dword |= XENHCI_TRB_3_TYPE_SET(XENHCI_TRB_TYPE_NORMAL); + } else if (temp->do_isoc_sync != 0) { + temp->do_isoc_sync = 0; + /* wait until "isoc_frame" */ + dword |= XENHCI_TRB_3_TYPE_SET(XENHCI_TRB_TYPE_ISOCH) | + XENHCI_TRB_3_FRID_SET(temp->isoc_frame / 8); + } else { + /* start data transfer at next interval */ + dword |= XENHCI_TRB_3_TYPE_SET(XENHCI_TRB_TYPE_ISOCH) | + XENHCI_TRB_3_ISO_SIA_BIT; + } + if (temp->direction == UE_DIR_IN) + dword |= XENHCI_TRB_3_DIR_IN | XENHCI_TRB_3_ISP_BIT; + break; + case XENHCI_TRB_TYPE_DATA_STAGE: + dword = XENHCI_TRB_3_CHAIN_BIT | XENHCI_TRB_3_CYCLE_BIT | + XENHCI_TRB_3_TYPE_SET(XENHCI_TRB_TYPE_DATA_STAGE) | + XENHCI_TRB_3_TBC_SET(temp->tbc) | + XENHCI_TRB_3_TLBPC_SET(temp->tlbpc); + if (temp->direction == UE_DIR_IN) + dword |= XENHCI_TRB_3_DIR_IN | XENHCI_TRB_3_ISP_BIT; + break; + case XENHCI_TRB_TYPE_STATUS_STAGE: + dword = XENHCI_TRB_3_CHAIN_BIT | XENHCI_TRB_3_CYCLE_BIT | + XENHCI_TRB_3_TYPE_SET(XENHCI_TRB_TYPE_STATUS_STAGE) | + XENHCI_TRB_3_TBC_SET(temp->tbc) | + XENHCI_TRB_3_TLBPC_SET(temp->tlbpc); + if (temp->direction == UE_DIR_IN) + dword |= XHCI_TRB_3_DIR_IN; + break; + default: /* XENHCI_TRB_TYPE_NORMAL */ + /* BEI: Interrupts are inhibited until EOT */ + dword = XENHCI_TRB_3_CHAIN_BIT | XENHCI_TRB_3_CYCLE_BIT | + XENHCI_TRB_3_TYPE_SET(XENHCI_TRB_TYPE_NORMAL) | + XENHCI_TRB_3_BEI_BIT | + XENHCI_TRB_3_TBC_SET(temp->tbc) | + XENHCI_TRB_3_TLBPC_SET(temp->tlbpc); + if (temp->direction == UE_DIR_IN) + dword |= XENHCI_TRB_3_DIR_IN | XENHCI_TRB_3_ISP_BIT; + break; + } + 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(XENHCI_TRB_3_IOC_BIT); + + /* store number of data TRB's */ + + td->ntrb = x; + + DPRINTF("NTRB=%u\n", x); + + /* fill out link TRB */ + + if (td_next != NULL) { + /* link the current TD with the next one */ + 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 = XENHCI_TRB_2_IRQ_SET(0); + + td->td_trb[x].dwTrb2 = htole32(dword); + + dword = XENHCI_TRB_3_TYPE_SET(XENHCI_TRB_TYPE_LINK) | + XENHCI_TRB_3_CYCLE_BIT | XENHCI_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); + } + + if (precompute) { + precompute = 0; + + /* setup alt next pointer, if any */ + if (temp->last_frame) { + td_alt_next = NULL; + } else { + /* we use this field internally */ + td_alt_next = td_next; + } + + /* restore */ + temp->shortpkt = shortpkt_old; + temp->len = len_old; + goto restart; + } + + /* + * Remove cycle bit from the first TRB if we are + * stepping them: + */ + if (temp->step_td != 0) { + td_first->td_trb[0].dwTrb3 &= ~htole32(XENHCI_TRB_3_CYCLE_BIT); + usb_pc_cpu_flush(td_first->page_cache); + } + + /* remove chain bit because this is the last TRB in the chain */ + td->td_trb[td->ntrb - 1].dwTrb2 &= ~htole32(XENHCI_TRB_2_TDSZ_SET(15)); + td->td_trb[td->ntrb - 1].dwTrb3 &= ~htole32(XENHCI_TRB_3_CHAIN_BIT); + + usb_pc_cpu_flush(td->page_cache); + + temp->td = td; + temp->td_next = td_next; +} + +static void +xenhci_setup_generic_chain(struct usb_xfer *xfer) { - //TODO need this method()? -}*/ + //struct xhci_std_temp temp; + struct xenhci_td *td; + uint32_t x; + uint32_t y; + uint8_t mult; + + temp.do_isoc_sync = 0; + temp.step_td = 0; + temp.tbc = 0; + temp.tlbpc = 0; + temp.average = xfer->max_hc_frame_size; + temp.max_packet_size = xfer->max_packet_size; + temp.sc = XHCI_BUS2SC(xfer->xroot->bus); + temp.pc = NULL; + temp.last_frame = 0; + temp.offset = 0; + temp.multishort = xfer->flags_int.isochronous_xfr || + xfer->flags_int.control_xfr || + xfer->flags_int.short_frames_ok; + + /* toggle the DMA set we are using */ + xfer->flags_int.curr_dma_set ^= 1; + + /* get next DMA set */ + td = xfer->td_start[xfer->flags_int.curr_dma_set]; + + temp.td = NULL; + temp.td_next = td; + + xfer->td_transfer_first = td; + xfer->td_transfer_cache = td; + + if (xfer->flags_int.isochronous_xfr) { + uint8_t shift; + + /* compute multiplier for ISOCHRONOUS transfers */ + mult = xfer->endpoint->ecomp ? + UE_GET_SS_ISO_MULT(xfer->endpoint->ecomp->bmAttributes) + : 0; + /* check for USB 2.0 multiplier */ + if (mult == 0) { + mult = (xfer->endpoint->edesc-> *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201309160105.r8G15Z8u019296>