PERFORCE change 181776 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Tue Aug 3 15:51:48 UTC 2010
http://p4web.freebsd.org/@@181776?ac=10
Change 181776 by hselasky at hselasky_laptop001 on 2010/08/03 15:51:26
USB controller (XHCI):
- add more XHCI command function wrappers
- rename some variables/functions
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#10 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#12 edit
.. //depot/projects/usb/src/sys/dev/usb/controller/xhci_pci.c#4 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.c#10 (text+ko) ====
@@ -117,7 +117,7 @@
extern struct usb_bus_methods xhci_bus_methods;
-void
+static void
xhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb)
{
struct xhci_softc *sc = XHCI_BUS2SC(bus);
@@ -184,7 +184,10 @@
}
sc->sc_noport = i;
- sc->sc_nodev = XHCI_HCS1_DEVSLOT_MAX(temp);
+ sc->sc_noslot = XHCI_HCS1_DEVSLOT_MAX(temp);
+
+ if (sc->sc_noslot > XHCI_MAX_DEVICES)
+ sc->sc_noslot = XHCI_MAX_DEVICES;
temp = XREAD4(sc, capa, XHCI_HCSPARAMS2);
@@ -223,7 +226,7 @@
/* setup number of device slots */
- XWRITE4(sc, oper, XHCI_CONFIG, XHCI_MAX_DEVICES);
+ XWRITE4(sc, oper, XHCI_CONFIG, sc->sc_noslot);
/* Setup interrupter registers */
@@ -277,12 +280,6 @@
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(
@@ -350,7 +347,9 @@
sc->sc_bus.devices = sc->sc_devices;
sc->sc_bus.devices_max = XHCI_MAX_DEVICES;
- TAILQ_INIT(&sc->sc_cmd_head);
+ /* setup command queue mutex and condition varible */
+ cv_init(&sc->sc_cmd_cv, "CMDQ");
+ sx_init(&sc->sc_cmd_sx, "CMDQ lock");
/* get all DMA memory */
if (usb_bus_mem_alloc_all(&sc->sc_bus,
@@ -362,6 +361,15 @@
}
void
+xhci_uninit(struct xhci_softc *sc)
+{
+ usb_bus_mem_free_all(&sc->sc_bus, &xhci_iterate_hw_softc);
+
+ cv_destroy(&sc->sc_cmd_cv);
+ sx_destroy(&sc->sc_cmd_sx);
+}
+
+void
xhci_suspend(struct xhci_softc *sc)
{
/* XXX TODO */
@@ -582,11 +590,20 @@
}
static void
+xhci_check_command(struct xhci_softc *sc, struct xhci_trb *trb)
+{
+ if (sc->sc_cmd_addr == trb->qwTrb0) {
+ sc->sc_cmd_result[0] = trb->dwTrb2;
+ sc->sc_cmd_result[1] = trb->dwTrb2;
+ cv_signal(&sc->sc_cmd_cv);
+ }
+}
+
+static void
xhci_interrupt_poll(struct xhci_softc *sc)
{
struct usb_page_search buf_res;
struct xhci_hw_root *phwr;
- struct xhci_command *pcmd;
uint32_t temp;
uint16_t i;
uint8_t event;
@@ -598,7 +615,7 @@
phwr = buf_res.buffer;
- /* 1) Receive any events */
+ /* Receive any events */
usb_pc_cpu_invalidate(&sc->sc_hw.root_pc);
@@ -622,6 +639,9 @@
case XHCI_TRB_EVENT_TRANSFER:
xhci_check_transfer(sc, &phwr->hwr_events[i]);
break;
+ case XHCI_TRB_EVENT_CMD_COMPLETE:
+ xhci_check_command(sc, &phwr->hwr_events[i]);
+ break;
default:
DPRINTF("Received event = 0x%x\n", event);
break;
@@ -647,94 +667,161 @@
sc->sc_event_idx = i;
sc->sc_event_ccs = j;
+}
+
+static usb_error_t
+xhci_do_command(struct xhci_softc *sc, struct xhci_trb *trb,
+ uint16_t timeout_ms)
+{
+ struct usb_page_search buf_res;
+ struct xhci_hw_root *phwr;
+ uint64_t addr;
+ uint32_t temp;
+ uint8_t i;
+ uint8_t j;
+ int err;
+
+ XHCI_CMD_ASSERT_LOCKED(sc);
+
+ /* get hardware root structure */
+
+ usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res);
+
+ phwr = buf_res.buffer;
- /* 2) Queue any commands */
+ /* Queue command */
+
+ USB_BUS_LOCK(&sc->sc_bus);
i = sc->sc_command_idx;
j = sc->sc_command_ccs;
- /* check if there are any commands on the queue */
- while ((pcmd = TAILQ_FIRST(&sc->sc_cmd_head)) != NULL) {
+ phwr->hwr_commands[i].qwTrb0 = trb->qwTrb0;
+ phwr->hwr_commands[i].dwTrb2 = trb->dwTrb2;
+
+ usb_pc_cpu_flush(&sc->sc_hw.root_pc);
+
+ temp = trb->dwTrb3;
+
+ if (j)
+ temp |= htole32(XHCI_TRB_3_CYCLE_BIT);
+ else
+ temp &= ~htole32(XHCI_TRB_3_CYCLE_BIT);
+
+ phwr->hwr_commands[i].dwTrb3 = temp;
- k = (phwr->hwr_events[i].dwTrb3 & htole32(XHCI_TRB_3_CYCLE_BIT)) ? 1 : 0;
+ usb_pc_cpu_flush(&sc->sc_hw.root_pc);
- temp = (uint32_t)buf_res.physaddr + (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[i];
+ DPRINTFN(10, "command[%u] = %u\n", i,
+ XHCI_TRB_3_TYPE_GET(le32toh(temp)));
- /* check if we need to wait for XHCI to process commands */
- if ((sc->sc_cmd_dp == temp) && (j == k))
- break;
+ addr = (uint64_t)buf_res.physaddr +
+ (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[i];
+ sc->sc_cmd_addr = htole64(addr);
- TAILQ_REMOVE(&sc->sc_cmd_head, pcmd, entry);
- pcmd->entry.tqe_prev = NULL;
+ i++;
- phwr->hwr_events[i].qwTrb0 = pcmd->trb.qwTrb0;
- phwr->hwr_events[i].dwTrb2 = pcmd->trb.dwTrb2;
+ if (i == (XHCI_MAX_COMMANDS - 1)) {
- usb_pc_cpu_flush(&sc->sc_hw.root_pc);
+ /* update cycle bit of LINK TRB */
- temp = pcmd->trb.dwTrb3;
+ temp = phwr->hwr_commands[i].dwTrb3;
if (j)
temp |= htole32(XHCI_TRB_3_CYCLE_BIT);
else
temp &= ~htole32(XHCI_TRB_3_CYCLE_BIT);
- phwr->hwr_events[i].dwTrb3 = temp;
+ phwr->hwr_commands[i].dwTrb3 = temp;
usb_pc_cpu_flush(&sc->sc_hw.root_pc);
- XWRITE4(sc, door, XHCI_DOORBELL(0), 0);
+ i = 0;
+ j ^= 1;
+ }
+
+ sc->sc_command_idx = i;
+ sc->sc_command_ccs = j;
+
+ XWRITE4(sc, door, XHCI_DOORBELL(0), 0);
- DPRINTFN(10, "command[%u] = %u\n", i,
- XHCI_TRB_3_TYPE_GET(le32toh(temp)));
+ err = cv_timedwait(&sc->sc_cmd_cv, &sc->sc_bus.bus_mtx,
+ USB_MS_TO_TICKS(timeout_ms));
- i++;
+ if (err) {
+ DPRINTFN(0, "Command timeout!\n");
+ err = USB_ERR_TIMEOUT;
+ trb->dwTrb2 = 0;
+ trb->dwTrb3 = 0;
+ } else {
+ temp = le32toh(sc->sc_cmd_result[0]);
+ if (XHCI_TRB_2_ERROR_GET(temp) != XHCI_TRB_ERROR_SUCCESS)
+ err = USB_ERR_INVAL;
- if (i == (XHCI_MAX_COMMANDS - 1)) {
+ trb->dwTrb2 = sc->sc_cmd_result[0];
+ trb->dwTrb3 = sc->sc_cmd_result[1];
+ }
- /* update cycle bit of LINK TRB */
+ USB_BUS_UNLOCK(&sc->sc_bus);
- temp = phwr->hwr_events[i].dwTrb3;
+ return (err);
+}
- if (j)
- temp |= htole32(XHCI_TRB_3_CYCLE_BIT);
- else
- temp &= ~htole32(XHCI_TRB_3_CYCLE_BIT);
+static usb_error_t
+xhci_cmd_enable_slot(struct xhci_softc *sc, uint8_t *pslot)
+{
+ struct xhci_trb trb;
+ uint32_t temp;
+ usb_error_t err;
- phwr->hwr_events[i].dwTrb3 = temp;
+ trb.qwTrb0 = 0;
+ trb.dwTrb2 = 0;
+ trb.dwTrb3 = htole32(XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ENABLE_SLOT));
- usb_pc_cpu_flush(&sc->sc_hw.root_pc);
+ err = xhci_do_command(sc, &trb, 50 /* ms */);
+ if (err)
+ goto done;
- XWRITE4(sc, door, XHCI_DOORBELL(0), 0);
+ temp = le32toh(trb.dwTrb3);
- i = 0;
- j ^= 1;
- }
- }
+ *pslot = XHCI_TRB_3_SLOT_GET(temp);
- sc->sc_command_idx = i;
- sc->sc_command_ccs = j;
+done:
+ return (err);
}
static usb_error_t
-xhci_do_command(struct xhci_softc *sc, struct xhci_trb *trb,
- uint16_t timeout_ms)
+xhci_cmd_disable_slot(struct xhci_softc *sc, uint8_t slot_id)
{
- XXX implement;
+ struct xhci_trb trb;
+ uint32_t temp;
+
+ trb.qwTrb0 = 0;
+ trb.dwTrb2 = 0;
+ temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DISABLE_SLOT) |
+ XHCI_TRB_3_SLOT_SET(slot_id);
+
+ trb.dwTrb3 = htole32(temp);
+
+ return (xhci_do_command(sc, &trb, 50 /* ms */));
}
static usb_error_t
-xhci_cmd_disable_slot(struct xhci_softc *sc, uint8_t slot_id)
+xhci_cmd_set_address(struct xhci_softc *sc, uint64_t input_ctx,
+ uint8_t bsr, uint8_t slot_id)
{
struct xhci_trb trb;
- uint32_t dword;
+ uint32_t temp;
- trb.qwTrb0 = 0;
+ trb.qwTrb0 = htole64(input_ctx);
trb.dwTrb2 = 0;
- dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DISABLE_SLOT) |
+ temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ADDRESS_DEVICE) |
XHCI_TRB_3_SLOT_SET(slot_id);
- trb.dwTrb3 = htole32(dword);
+ if (bsr)
+ temp |= XHCI_TRB_3_BSR_BIT;
+
+ trb.dwTrb3 = htole32(temp);
return (xhci_do_command(sc, &trb, 50 /* ms */));
}
@@ -744,17 +831,17 @@
uint8_t deconfigure, uint8_t slot_id)
{
struct xhci_trb trb;
- uint32_t dword;
+ uint32_t temp;
trb.qwTrb0 = htole64(input_ctx);
trb.dwTrb2 = 0;
- dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP) |
+ temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP) |
XHCI_TRB_3_SLOT_SET(slot_id);
if (deconfigure)
- dword |= XHCI_TRB_3_DCEP_BIT;
+ temp |= XHCI_TRB_3_DCEP_BIT;
- trb.dwTrb3 = htole32(dword);
+ trb.dwTrb3 = htole32(temp);
return (xhci_do_command(sc, &trb, 50 /* ms */));
}
@@ -764,13 +851,13 @@
uint8_t slot_id)
{
struct xhci_trb trb;
- uint32_t dword;
+ uint32_t temp;
trb.qwTrb0 = htole64(input_ctx);
trb.dwTrb2 = 0;
- dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_EVALUATE_CTX) |
+ temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_EVALUATE_CTX) |
XHCI_TRB_3_SLOT_SET(slot_id);
- trb.dwTrb3 = htole32(dword);
+ trb.dwTrb3 = htole32(temp);
return (xhci_do_command(sc, &trb, 50 /* ms */));
}
@@ -780,18 +867,18 @@
uint8_t ep_id, uint8_t slot_id)
{
struct xhci_trb trb;
- uint32_t dword;
+ uint32_t temp;
trb.qwTrb0 = 0;
trb.dwTrb2 = 0;
- dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_EP) |
+ temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_EP) |
XHCI_TRB_3_SLOT_SET(slot_id) |
XHCI_TRB_3_SLOT_SET(ep_id);
if (preserve)
- dword |= XHCI_TRB_3_PRSV_BIT;
+ temp |= XHCI_TRB_3_PRSV_BIT;
- trb.dwTrb3 = htole32(dword);
+ trb.dwTrb3 = htole32(temp);
return (xhci_do_command(sc, &trb, 50 /* ms */));
}
@@ -801,18 +888,18 @@
uint8_t ep_id, uint8_t slot_id)
{
struct xhci_trb trb;
- uint32_t dword;
+ uint32_t temp;
trb.qwTrb0 = 0;
trb.dwTrb2 = 0;
- dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STOP_EP) |
+ temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STOP_EP) |
XHCI_TRB_3_SLOT_SET(slot_id) |
XHCI_TRB_3_SLOT_SET(ep_id);
if (suspend)
- dword |= XHCI_TRB_3_SUSP_EP_BIT;
+ temp |= XHCI_TRB_3_SUSP_EP_BIT;
- trb.dwTrb3 = htole32(dword);
+ trb.dwTrb3 = htole32(temp);
return (xhci_do_command(sc, &trb, 50 /* ms */));
}
@@ -821,14 +908,14 @@
xhci_cmd_reset_dev(struct xhci_softc *sc, uint8_t slot_id)
{
struct xhci_trb trb;
- uint32_t dword;
+ uint32_t temp;
trb.qwTrb0 = 0;
trb.dwTrb2 = 0;
- dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_DEVICE) |
+ temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_DEVICE) |
XHCI_TRB_3_SLOT_SET(slot_id);
- trb.dwTrb3 = htole32(dword);
+ trb.dwTrb3 = htole32(temp);
return (xhci_do_command(sc, &trb, 50 /* ms */));
}
@@ -1339,7 +1426,7 @@
}
static usb_error_t
-xhci_set_slot_scratch(struct xhci_softc *sc, uint8_t index,
+xhci_set_slot_pointers(struct xhci_softc *sc, uint8_t index,
uint64_t dev_addr, uint64_t scratch_addr)
{
struct usb_page_search buf_res;
@@ -1372,7 +1459,7 @@
}
static usb_error_t
-xhci_configure_endpoint(struct usb_xfer *xfer)
+xhci_configure_endpoint(struct usb_xfer *xfer, uint8_t drop)
{
struct usb_page_search buf_inp;
struct usb_page_search buf_ep;
@@ -1383,6 +1470,7 @@
struct usb_device *udev;
uint64_t addr;
uint32_t temp;
+ uint32_t mask;
uint8_t index;
uint8_t epno;
uint8_t k;
@@ -1394,7 +1482,7 @@
udev = xfer->xroot->udev;
- index = udev->device_index;
+ index = udev->controller_slot_id;
edesc = xfer->endpoint->edesc;
@@ -1410,9 +1498,18 @@
pinp = buf_inp.buffer;
- XXX;
- pinp->ctx_input.dwInCtx0 |= htole32(0xFFFFFFFC);
- pinp->ctx_input.dwInCtx1 &= htole32(0x1);
+ mask = 1U << epno;
+
+ if (drop) {
+ mask &= 0xFFFFFFFC;
+ pinp->ctx_input.dwInCtx0 = htole32(mask);
+ pinp->ctx_input.dwInCtx1 = 0;
+ } else {
+ if (mask & 2)
+ mask |= 1;
+ pinp->ctx_input.dwInCtx0 = 0;
+ pinp->ctx_input.dwInCtx1 = htole32(mask);
+ }
temp = XHCI_EPCTX_0_EPSTATE_SET(0) |
XHCI_EPCTX_0_MAXP_STREAMS_SET(0) |
@@ -1461,22 +1558,25 @@
pinp->ctx_ep[epno - 1].dwEpCtx1 = htole32(temp);
- pepext->trb_ccs = 1;
- pepext->trb_index = 0;
- pepext->trb_halted = 0;
+ if (drop == 0) {
+
+ 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;
+ for (k = 0; k != XHCI_MAX_TRANSFERS; k++)
+ pepext->trb[k].dwTrb3 = 0;
- usb_pc_cpu_flush(pepext->page_cache);
+ usb_pc_cpu_flush(pepext->page_cache);
+ }
addr = XHCI_EPCTX_2_DCS_SET(1) |
(buf_ep.physaddr + (uintptr_t)&((struct xhci_dev_endpoint_trbs *)0)->trb[epno][0]);
pinp->ctx_ep[epno - 1].qwEpCtx2 = htole64(addr);
- temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET() |
- XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET();
+ temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(xfer->max_frame_size) |
+ XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(xfer->max_frame_size);
pinp->ctx_ep[epno - 1].dwEpCtx4 = htole32(temp);
@@ -1563,7 +1663,7 @@
hubdev = udev->parent_hs_hub;
if (hubdev != NULL) {
- temp |= XHCI_SCTX_2_TT_HUB_SID_SET(hubdev->device_index);
+ temp |= XHCI_SCTX_2_TT_HUB_SID_SET(hubdev->controller_slot_id);
temp |= XHCI_SCTX_2_TT_PORT_NUM_SET(hubdev->port_no);
}
@@ -1585,10 +1685,8 @@
usb_pc_cpu_flush(pcinp);
- xhci_set_slot_scratch(sc, udev->device_index, buf_dev.physaddr,
+ 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]);
-
- XXX_cmd_config();
}
static usb_error_t
@@ -1600,7 +1698,7 @@
uint8_t i;
uint8_t index;
- index = udev->device_index;
+ index = udev->controller_slot_id;
pc = &sc->sc_hw.devs[index].device_pc;
pg = &sc->sc_hw.devs[index].device_pg;
@@ -1656,9 +1754,9 @@
uint8_t index;
uint8_t i;
- index = udev->device_index;
+ index = udev->controller_slot_id;
- xhci_set_slot_scratch(sc, index, 0, 0);
+ xhci_set_slot_pointers(sc, index, 0, 0);
pc = &sc->sc_hw.devs[index].device_pc;
@@ -1694,7 +1792,7 @@
epno |= UE_DIR_IN;
epno = XHCI_EPNO2EPID(epno);
- index = xfer->xroot->udev->device_index;
+ index = xfer->xroot->udev->controller_slot_id;
pc = &sc->sc_hw.devs[index].endpoint_pc;
@@ -1720,7 +1818,7 @@
epno |= UE_DIR_IN;
epno = XHCI_EPNO2EPID(epno);
- index = xfer->xroot->udev->device_index;
+ index = xfer->xroot->udev->controller_slot_id;
XWRITE4(sc, door, XHCI_DOORBELL(index), epno | XHCI_DB_SID_SET(0));
}
@@ -1987,7 +2085,7 @@
.bLength = sizeof(xhci_bosd.usbdcd),
.bDescriptorType = UDESC_DEVICE_CAPABILITY,
.bDevCapabilityType = 3,
- .bmAttributes = XXX,
+ .bmAttributes = 0, /* XXX */
HSETW(.wSpeedsSupported, 0x000C),
.bFunctionalitySupport = 8,
.bU1DevExitLat = 255, /* dummy - not used */
@@ -1998,7 +2096,7 @@
.bDescriptorType = 1,
.bDevCapabilityType = 4,
.bReserved = 0,
- .bContainerID = XXX,
+ .bContainerID = 0, /* XXX */
},
};
@@ -2555,6 +2653,73 @@
xfer->flags_int.curr_dma_set = 1;
goto alloc_dma_set;
}
+
+ 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;
+
+ 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;
+
+ XHCI_CMD_LOCK(sc);
+
+ 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)
+ DPRINTFN(0, "Could not configure endpoint\n");
+
+ 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);
+
+ temp = le32toh(pdctx->ctx_slot.dwSctx3);
+
+ /* update address */
+ udev->address = XHCI_SCTX_3_DEV_ADDR_GET(temp);
+
+ 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);
+ }
+
+ if (err != 0)
+ DPRINTFN(0, "Could not set address\n");
+ }
+ XHCI_CMD_UNLOCK(sc);
+
+ parm->err = err;
+ }
}
static void
@@ -2578,28 +2743,75 @@
/* not supported */
return;
}
- if (udev->device_index != sc->sc_addr) {
+ if (udev->parent_hub != NULL)
+ ep->methods = &xhci_device_generic_methods;
+}
+
+static void
+xhci_ep_uninit(struct usb_device *udev, struct usb_endpoint *ep)
+{
+
+}
+
+static usb_error_t
+xhci_device_init(struct usb_device *udev)
+{
+ struct xhci_softc *sc = XHCI_BUS2SC(udev->bus);
+ usb_error_t err;
+ uint8_t temp;
+
+ /* no init for root HUB */
+ if (udev->parent_hub == NULL)
+ return (0);
+
+ XHCI_CMD_LOCK(sc);
+
+ /* set invalid default */
+
+ udev->controller_slot_id = sc->sc_noslot;
+
+ /* try to get a new slot ID from the XHCI */
+
+ err = xhci_cmd_enable_slot(sc, &temp);
- ep->methods = &xhci_device_generic_methods;
+ if (err) {
+ XHCI_CMD_UNLOCK(sc);
+ return (err);
+ }
- if ((udev->speed != USB_SPEED_HIGH) &&
- ((udev->hs_hub_addr == 0) ||
- (udev->hs_port_no == 0) ||
- (udev->parent_hs_hub == NULL) ||
- (udev->parent_hs_hub->hub == NULL))) {
- /* We need a transaction translator */
- goto done;
- }
+ if (temp >= sc->sc_noslot) {
+ XHCI_CMD_UNLOCK(sc);
+ return (USB_ERR_INVAL);
}
-done:
- return;
+
+ /* store slot ID for later reference */
+
+ udev->controller_slot_id = temp;
+
+ err = xhci_alloc_device_ext(udev);
+
+ XHCI_CMD_UNLOCK(sc);
+
+ return (err);
}
static void
-xhci_ep_uninit(struct usb_device *udev, struct usb_endpoint *ep)
+xhci_device_uninit(struct usb_device *udev)
{
+ struct xhci_softc *sc = XHCI_BUS2SC(udev->bus);
+ /* no init for root HUB */
+ if (udev->parent_hub == NULL)
+ return;
+ XHCI_CMD_LOCK(sc);
+
+ if (udev->controller_slot_id < sc->sc_noslot)
+ xhci_cmd_disable_slot(sc, udev->controller_slot_id);
+
+ xhci_free_device_ext(udev);
+
+ XHCI_CMD_UNLOCK(sc);
}
static void
@@ -2607,9 +2819,9 @@
{
/*
* Wait until the hardware has finished any possible use of
- * the transfer descriptor(s) and QH
+ * the transfer descriptor(s)
*/
- *pus = (188); /* microseconds */
+ *pus = 2048; /* microseconds */
}
static void
@@ -2649,6 +2861,8 @@
.xfer_setup = xhci_xfer_setup,
.xfer_unsetup = xhci_xfer_unsetup,
.get_dma_delay = xhci_get_dma_delay,
+ .device_init = xhci_device_init,
+ .device_uninit = xhci_device_uninit,
.device_resume = xhci_device_resume,
.device_suspend = xhci_device_suspend,
.set_hw_power = xhci_set_hw_power,
==== //depot/projects/usb/src/sys/dev/usb/controller/xhci.h#12 (text+ko) ====
@@ -159,10 +159,6 @@
struct xhci_endp_ctx ctx_epN[XHCI_MAX_ENDPOINTS - 1];
} __aligned(XHCI_DEV_CTX_ALIGN);
-struct xhci_dev_endpoint_trbs {
- struct xhci_trb trb[XHCI_MAX_ENDPOINTS][XHCI_MAX_TRANSFERS];
-};
-
struct xhci_stream_ctx {
volatile uint64_t qwSctx0;
#define XHCI_SCTX_0_DCS_GET(x) ((x) & 0x1)
@@ -210,6 +206,7 @@
#define XHCI_TRB_3_BEI_BIT (1U << 9)
#define XHCI_TRB_3_DCEP_BIT (1U << 9)
#define XHCI_TRB_3_PRSV_BIT (1U << 9)
+#define XHCI_TRB_3_BSR_BIT (1U << 9)
#define XHCI_TRB_3_TRT_MASK (3U << 16)
#define XHCI_TRB_3_TRT_NONE (0U << 16)
#define XHCI_TRB_3_TRT_OUT (2U << 16)
@@ -300,6 +297,10 @@
#define XHCI_TRB_ERROR_SPLIT_XACT 0x24
};
+struct xhci_dev_endpoint_trbs {
+ struct xhci_trb trb[XHCI_MAX_ENDPOINTS][XHCI_MAX_TRANSFERS];
+};
+
#define XHCI_TD_PAGE_NBUF 5 /* units */
#define XHCI_TD_PAGE_SIZE 4096 /* bytes */
#define XHCI_TD_PAYLOAD_MAX (XHCI_TD_PAGE_SIZE * (XHCI_TD_PAGE_NBUF - 1))
@@ -342,8 +343,6 @@
};
struct xhci_endpoint_ext {
- struct xhci_command ep_stop_cmd;
- struct xhci_command ep_config_cmd;
struct xhci_trb *trb;
struct usb_page_cache *page_cache;
uint64_t physaddr;
@@ -404,7 +403,8 @@
union xhci_hub_desc sc_hub_desc;
- TAILQ_HEAD(, xhci_command) sc_cmd_head;
+ struct cv sc_cmd_cv;
+ struct sx sc_cmd_sx;
struct usb_device *sc_devices[XHCI_MAX_DEVICES];
struct resource *sc_io_res;
@@ -415,8 +415,10 @@
bus_space_tag_t sc_io_tag;
bus_space_handle_t sc_io_hdl;
+ uint64_t sc_cmd_addr; /* current pending command */
+ uint32_t sc_cmd_result[2]; /* result of command */
+
uint32_t sc_cmd; /* copy of cmd register */
- uint32_t sc_cmd_dp; /* copy of command dequeue pointer */
uint32_t sc_exit_lat_max; /* worst case exit latency */
uint32_t sc_oper_off; /* offset to operational registers */
@@ -431,7 +433,7 @@
uint8_t sc_event_ccs;
uint8_t sc_command_ccs;
- uint8_t sc_nodev; /* number of devices on root HUB */
+ 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 */
@@ -442,14 +444,18 @@
};
+#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 */
void xhci_suspend(struct xhci_softc *);
void xhci_resume(struct xhci_softc *);
void xhci_shutdown(struct xhci_softc *);
usb_error_t xhci_init(struct xhci_softc *, device_t);
+void xhci_uninit(struct xhci_softc *);
usb_error_t xhci_start_controller(struct xhci_softc *);
-void xhci_iterate_hw_softc(struct usb_bus *, usb_bus_mem_sub_cb_t *);
usb_error_t xhci_halt_controller(struct xhci_softc *);
void xhci_interrupt(struct xhci_softc *);
==== //depot/projects/usb/src/sys/dev/usb/controller/xhci_pci.c#4 (text+ko) ====
@@ -268,7 +268,8 @@
sc->sc_io_res);
sc->sc_io_res = NULL;
}
- usb_bus_mem_free_all(&sc->sc_bus, &xhci_iterate_hw_softc);
+
+ xhci_uninit(sc);
return (0);
}
More information about the p4-projects
mailing list