socsvn commit: r257392 - soc2013/bguan/head/sys/dev/xen/usbfront
bguan at FreeBSD.org
bguan at FreeBSD.org
Mon Sep 16 01:05:35 UTC 2013
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 ***
More information about the svn-soc-all
mailing list