PERFORCE change 181670 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Sun Aug 1 09:46:43 UTC 2010
http://p4web.freebsd.org/@@181670?ac=10
Change 181670 by hselasky at hselasky_laptop001 on 2010/08/01 09:46:06
USB controller (XHCI):
- add command queue logic
- remove XHCI QH structure
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#5 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#8 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#5 (text+ko) ====
@@ -146,6 +146,8 @@
sc->sc_event_ccs = 1;
sc->sc_event_idx = 0;
+ sc->sc_command_ccs = 1;
+ sc->sc_command_idx = 0;
DPRINTF("xHCI version = 0x%04x\n", XREAD2(sc, capa, XHCI_HCIVERSION));
@@ -258,9 +260,21 @@
addr = (uint64_t)buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[0];
- XWRITE4(sc, oper, XHCI_CRCR_LO, (uint32_t)addr);
+ XWRITE4(sc, oper, XHCI_CRCR_LO, ((uint32_t)addr) | XHCI_CRCR_LO_RCS);
XWRITE4(sc, oper, XHCI_CRCR_HI, (uint32_t)(addr >> 32));
+ /*
+ * We only need the 32-lower bits of the command dequeue
+ * pointer to keep track of the TRBs:
+ */
+ sc->sc_cmd_dp = (uint32_t)addr;
+
+ phwr->hwr_commands[XHCI_MAX_COMMANDS - 1].qwTrb0 = htole64(addr);
+ phwr->hwr_commands[XHCI_MAX_COMMANDS - 1].dwTrb2 = htole32(0);
+ phwr->hwr_commands[XHCI_MAX_COMMANDS - 1].dwTrb3 = htole32(
+ XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) |
+ XHCI_TRB_3_IOC_BIT | XHCI_TRB_3_TC_BIT);
+
usb_bus_mem_flush_all(&sc->sc_bus, &xhci_iterate_hw_softc);
/* Go! */
@@ -322,6 +336,8 @@
sc->sc_bus.devices = sc->sc_devices;
sc->sc_bus.devices_max = XHCI_MAX_DEVICES;
+ TAILQ_INIT(&sc->sc_cmd_head);
+
/* get all DMA memory */
if (usb_bus_mem_alloc_all(&sc->sc_bus,
USB_GET_DMA_TAG(self), &xhci_iterate_hw_softc)) {
@@ -556,8 +572,10 @@
{
struct usb_page_search buf_res;
struct xhci_hw_root *phwr;
+ struct xhci_command *pcmd;
uint32_t temp;
uint16_t i;
+ uint8_t event;
uint8_t j;
uint8_t k;
uint8_t t;
@@ -566,6 +584,8 @@
phwr = buf_res.buffer;
+ /* 1) Receive any events */
+
usb_pc_cpu_invalidate(&sc->sc_hw.root_pc);
i = sc->sc_event_idx;
@@ -580,13 +600,16 @@
if (j != k)
break;
- switch (XHCI_TRB_3_TYPE_GET(temp)) {
+ event = XHCI_TRB_3_TYPE_GET(temp);
+
+ DPRINTFN(10, "event[%u] = %u\n", i, event);
+
+ switch (event) {
case XHCI_TRB_EVENT_TRANSFER:
xhci_check_transfer(sc, &phwr->hwr_events[i]);
break;
default:
- DPRINTF("Received event = 0x%x\n",
- XHCI_TRB_3_TYPE_GET(temp));
+ DPRINTF("Received event = 0x%x\n", event);
break;
}
@@ -610,6 +633,59 @@
sc->sc_event_idx = i;
sc->sc_event_ccs = j;
+
+ /* 2) Queue any commands */
+
+ i = sc->sc_command_idx;
+ j = sc->sc_command_ccs;
+
+ while (1) {
+
+ k = (phwr->hwr_events[i].dwTrb3 & htole32(XHCI_TRB_3_CYCLE_BIT)) ? 1 : 0;
+
+ temp = (uint32_t)buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[i];
+
+ /* check if we need to wait for XHCI to process commands */
+ if ((sc->sc_cmd_dp == temp) && (j == k))
+ break;
+
+ /* check if there are any commands on the queue */
+ pcmd = TAILQ_FIRST(&sc->sc_cmd_head);
+ if (pcmd == NULL)
+ break;
+
+ TAILQ_REMOVE(&sc->sc_cmd_head, pcmd, entry);
+ pcmd->entry.tqe_prev = NULL;
+
+ phwr->hwr_events[i].qwTrb0 = pcmd->trb.qwTrb0;
+ phwr->hwr_events[i].dwTrb2 = pcmd->trb.dwTrb2;
+
+ usb_pc_cpu_flush(&sc->sc_hw.root_pc);
+
+ temp = pcmd->trb.dwTrb3 | htole32(XHCI_TRB_3_IOC_BIT);
+
+ if (j)
+ temp |= htole32(XHCI_TRB_3_CYCLE_BIT);
+ else
+ temp &= ~htole32(XHCI_TRB_3_CYCLE_BIT);
+
+ phwr->hwr_events[i].dwTrb3 = temp;
+
+ usb_pc_cpu_flush(&sc->sc_hw.root_pc);
+
+ DPRINTFN(10, "command[%u] = %u\n", i,
+ XHCI_TRB_3_TYPE_GET(le32toh(temp)));
+
+ i++;
+
+ if (i == (XHCI_MAX_COMMANDS - 1)) {
+ i = 0;
+ j ^= 1;
+ }
+ }
+
+ sc->sc_command_idx = i;
+ sc->sc_command_ccs = j;
}
/*------------------------------------------------------------------------*
@@ -1726,7 +1802,6 @@
struct usb_xfer *xfer;
void *last_obj;
uint32_t ntd;
- uint32_t nqh;
uint32_t n;
sc = XHCI_BUS2SC(parm->udev->bus);
@@ -1768,8 +1843,6 @@
usbd_transfer_setup_sub(parm);
- nqh = 1;
-
if (xfer->flags_int.isochronous_xfr) {
ntd = ((1 * xfer->nframes)
+ (xfer->max_data_length / xfer->max_hc_frame_size));
@@ -1817,34 +1890,6 @@
}
xfer->td_start[xfer->flags_int.curr_dma_set] = last_obj;
- last_obj = NULL;
-
- if (usbd_transfer_setup_sub_malloc(
- parm, &pc, sizeof(struct xhci_qh),
- XHCI_QH_ALIGN, nqh)) {
- parm->err = USB_ERR_NOMEM;
- return;
- }
- if (parm->buf) {
- for (n = 0; n != nqh; n++) {
- struct xhci_qh *qh;
-
- usbd_get_page(pc + n, 0, &page_info);
-
- qh = page_info.buffer;
-
- /* init QH */
- qh->qh_self = htole64((uint64_t)page_info.physaddr);
- qh->obj_next = last_obj;
- qh->page_cache = pc + n;
-
- last_obj = qh;
-
- usb_pc_cpu_flush(pc + n);
- }
- }
- xfer->qh_start[xfer->flags_int.curr_dma_set] = last_obj;
-
if (!xfer->flags_int.curr_dma_set) {
xfer->flags_int.curr_dma_set = 1;
goto alloc_dma_set;
==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#8 (text+ko) ====
@@ -189,6 +189,7 @@
#define XHCI_TRB_3_TYPE_GET(x) (((x) >> 10) & 0x3F)
#define XHCI_TRB_3_TYPE_SET(x) (((x) & 0x3F) << 10)
#define XHCI_TRB_3_CYCLE_BIT (1U << 0)
+#define XHCI_TRB_3_TC_BIT (1U << 1)
#define XHCI_TRB_3_ENT_BIT (1U << 1)
#define XHCI_TRB_3_ISP_BIT (1U << 2)
#define XHCI_TRB_3_NSNOOP_BIT (1U << 3)
@@ -304,13 +305,9 @@
} __aligned(XHCI_TRB_ALIGN);
-struct xhci_qh {
+struct xhci_command {
struct xhci_trb trb;
-
- TAILQ_ENTRY(xhci_qh) entry;
- uint64_t td_self;
- struct xhci_qh *obj_next;
- struct usb_page_cache *page_cache;
+ TAILQ_ENTRY(xhci_command) entry;
};
struct xhci_event_ring_seg {
@@ -385,6 +382,8 @@
union xhci_hub_desc sc_hub_desc;
+ TAILQ_HEAD(, xhci_command) sc_cmd_head;
+
struct usb_device *sc_devices[XHCI_MAX_DEVICES];
struct resource *sc_io_res;
struct resource *sc_irq_res;
@@ -395,6 +394,7 @@
bus_space_handle_t sc_io_hdl;
uint32_t sc_cmd; /* copy of cmd register */
+ uint32_t sc_cmd_dp; /* copy of command dequeue pointer */
uint32_t sc_oper_off; /* offset to operational registers */
uint32_t sc_capa_off; /* offset to capability registers */
@@ -404,8 +404,10 @@
uint16_t sc_flags; /* chip specific flags */
uint16_t sc_erst_max;
uint16_t sc_event_idx;
+ uint16_t sc_command_idx;
uint8_t sc_event_ccs;
+ uint8_t sc_command_ccs;
uint8_t sc_nodev; /* number of devices on root HUB */
uint8_t sc_noport; /* number of ports on root HUB */
uint8_t sc_addr; /* root HUB device address */
More information about the p4-projects
mailing list