tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
xhci patch 20150623
Hello,
Here is xhci patch for nick-nhusb branch.
nh-xhci-check.diff
+ Add port range check in xhci_rhpsc().
+ Add sanity check if xfer->ux_pipe != NULL in xhci_handle_event().
nh-xhci-prc.diff
+ Remove SET_FEATURE C_PORT_RESET(PRC) -- what would happen?
nh-xhci-methods1.diff
+ Sync return type of xhci_close_pipe() with return type of
upm_close method.
nh-xhci-abort.diff
+ Add routines for aborting xfer and command.
nh-xhci-comments.diff
+ Update comments.
nh-usb_subr.diff
+ Don't give up doing SET_CONFIG in usbd_set_config_index()
even if it fails to get BOS descriptor.
In this case ud_bdesc will be NULL.
Known problems:
+ HS hub in 3.0 hub under 3.0 port is disconnected and reconnected every
several minutes repeatedly.
I don't know what is culprit yet.
+ Detaching hubs or devices might cause panic.
Especially when the hub that hangs many devices is disconnected.
+ KASSERT(sc->sc_command_addr == 0) in xhci_do_command() may fail.
If two or more threads run xhci_do_command(), all of them except one
should be blocked at mutex_enter. But one of blocked thread can get
sc_lock with sc_command_addr != 0 when cv_timedwait() unlocks sc_lock.
+ xhci.c cannot handle cross-64k transfer yet.
(It works anyway though.)
+ Power management is not implemented.
+ USB keyboard interaction is laggy and annoying.
+ ASM1042 and some Intel PCH do not work at all.
No interrupts.
+ Fresco1100 does not report CSC if the device is connected at boot.
Only PortResetChange is set in change bits.
uhub ignores ports without CSC bit, so cannot detect devices.
+ SS part of asm107x hub under hudson2 xhci roothub is not recognized.
It drops Port Enable Disable (PED) bit after port reset.
rhpsc: 0x21203<CSC,PIC=0x0,XSPEED=0x4=SS,PP,PLS=0x0=U0,PED,CCS>
after reset: 0x6202c0<PLC,PRC,CSC,PIC=0x0,XSPEED=0x0=NONE,PP,PLS=0x6=SS_INA>
+ axen does not work after interface up -> down -> up.
When the interface goes down, axen driver closes both of RX and TX pipes.
That causes transtion slot state of this device to ADDRESSED from CONFIGURED.
+ xhci.c does not snoop SET_CONFIG request and does not transtion the
slot state to CONFIGURED from ADDRESSED even if SET_CONFIG is issued.
+ Isochronous transfer is not implemented.
+ Stream protocol is not supported.
+ Conexant CX93010 umodem is not recognized (XACT in ADDRESS_DEVICE).
It can be recognized by inserting 150ms delay before port reset
while enumeration.
+ usbd_clear_endpoint_stall{,_async}() does not work on xhci to clear stall
condition because this function does not issue RESET_ENDPOINT command.
However, xhci.c detects whether xfer is stalled and issues RESET_ENDPOINT
automatically.
+ Address of root hub is 0 (but it works anyway).
+ Not sure it work on big endian machines.
+ usbdevs(8) does not report correctly if num of ports > 16.
Size of udi_ports in struct usb_device_info should be
expanded from 16 to 256. Needs compat treatment.
(currently usbdevs is not part of nick-nhusb branch.)
--
t-hash
--- src/sys/dev/usb/xhci.c.orig 2015-06-08 20:49:41.000000000 +0900
+++ src/sys/dev/usb/xhci.c 2015-06-08 21:15:24.000000000 +0900
@@ -1683,11 +1683,15 @@ xhci_rhpsc(struct xhci_softc * const sc,
uint8_t *p;
XHCIHIST_FUNC(); XHCIHIST_CALLED();
- DPRINTFN(4, "port %u status change", port, 0, 0, 0);
+ DPRINTFN(4, "xhci%d: port %u status change",
+ device_unit(sc->sc_dev), port, 0, 0);
if (xfer == NULL)
return;
+ if (!(port >= 1 && port <= sc->sc_maxports))
+ return;
+
p = xfer->ux_buf;
memset(p, 0, xfer->ux_length);
p[port/NBBY] |= 1 << (port%NBBY);
@@ -1771,6 +1775,10 @@ xhci_handle_event(struct xhci_softc * co
}
DPRINTFN(14, "xfer %p", xfer, 0, 0, 0);
/* XXX I dunno why this happens */
+ if (xfer->ux_pipe == NULL) {
+ DPRINTFN(1, "xfer done: ux_pipe is NULL", 0, 0, 0, 0);
+ break;
+ }
if (!xfer->ux_pipe->up_repeat &&
SIMPLEQ_EMPTY(&xfer->ux_pipe->up_queue)) {
DPRINTFN(1, "xfer done: xfer not started", 0, 0, 0, 0);
--- src/sys/dev/usb/xhci.c.orig 2015-06-14 16:07:49.000000000 +0900
+++ src/sys/dev/usb/xhci.c 2015-06-14 16:14:28.000000000 +0900
@@ -2867,9 +2867,6 @@ xhci_roothub_ctrl(struct usbd_bus *bus,
/* XXX power control */
break;
/* XXX more */
- case UHF_C_PORT_RESET:
- xhci_op_write_4(sc, port, v | XHCI_PS_PRC);
- break;
case UHF_PORT_U1_TIMEOUT:
if (USB_IS_SS(xhci_xspeed2speed(XHCI_PS_SPEED_GET(v)))){
return -1;
--- src/sys/dev/usb/xhci.c.orig 2015-06-14 16:14:28.000000000 +0900
+++ src/sys/dev/usb/xhci.c 2015-06-14 16:57:52.000000000 +0900
@@ -125,6 +125,7 @@ struct xhci_pipe {
#define XHCI_TRB_3_ED_BIT XHCI_TRB_3_ISP_BIT
static usbd_status xhci_open(struct usbd_pipe *);
+static void xhci_close_pipe(struct usbd_pipe *);
static int xhci_intr1(struct xhci_softc * const);
static void xhci_softintr(void *);
static void xhci_poll(struct usbd_bus *);
@@ -1506,7 +1507,7 @@ xhci_open(struct usbd_pipe *pipe)
* If the endpoint to be closed is ep0, disable_slot.
* Should be called with sc_lock held.
*/
-static usbd_status
+static void
xhci_close_pipe(struct usbd_pipe *pipe)
{
struct xhci_softc * const sc = pipe->up_dev->ud_bus->ub_hcpriv;
@@ -1514,17 +1515,16 @@ xhci_close_pipe(struct usbd_pipe *pipe)
usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
const u_int dci = xhci_ep_get_dci(ed);
struct xhci_trb trb;
- usbd_status err;
uint32_t *cp;
XHCIHIST_FUNC(); XHCIHIST_CALLED();
if (sc->sc_dying)
- return USBD_IOERROR;
+ return;
if (xs == NULL || xs->xs_idx == 0)
/* xs is uninitialized before xhci_init_slot */
- return USBD_IOERROR;
+ return;
DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
@@ -1532,11 +1532,12 @@ xhci_close_pipe(struct usbd_pipe *pipe)
KASSERT(mutex_owned(&sc->sc_lock));
if (pipe->up_dev->ud_depth == 0)
- return USBD_NORMAL_COMPLETION;
+ return;
if (dci == XHCI_DCI_EP_CONTROL) {
DPRINTFN(4, "closing ep0", 0, 0, 0, 0);
- return xhci_disable_slot(sc, xs->xs_idx);
+ xhci_disable_slot(sc, xs->xs_idx);
+ return;
}
/*
@@ -1566,10 +1567,8 @@ xhci_close_pipe(struct usbd_pipe *pipe)
trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) |
XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP);
- err = xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
+ (void)xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD);
-
- return err;
}
/*
--- src/sys/dev/usb/xhci.c.orig 2015-06-14 16:57:52.000000000 +0900
+++ src/sys/dev/usb/xhci.c 2015-06-14 20:20:33.000000000 +0900
@@ -139,17 +139,12 @@ static int xhci_roothub_ctrl(struct usbd
static usbd_status xhci_configure_endpoint(struct usbd_pipe *);
//static usbd_status xhci_unconfigure_endpoint(struct usbd_pipe *);
-static usbd_status xhci_reset_endpoint(struct usbd_pipe *);
-static usbd_status xhci_stop_endpoint(struct usbd_pipe *);
-
-static usbd_status xhci_set_dequeue(struct usbd_pipe *);
+static usbd_status xhci_reset_endpoint(struct usbd_pipe *, int);
+static usbd_status xhci_stop_endpoint(struct usbd_pipe *, int);
+static usbd_status xhci_set_dequeue(struct usbd_pipe *, int);
static usbd_status xhci_do_command(struct xhci_softc * const,
- struct xhci_trb * const, int);
-static usbd_status xhci_do_command1(struct xhci_softc * const,
struct xhci_trb * const, int, int);
-static usbd_status xhci_do_command_locked(struct xhci_softc * const,
- struct xhci_trb * const, int);
static usbd_status xhci_init_slot(struct usbd_device *, uint32_t, int, int);
static usbd_status xhci_enable_slot(struct xhci_softc * const,
uint8_t * const);
@@ -290,7 +285,6 @@ xhci_op_write_4(const struct xhci_softc
bus_space_write_4(sc->sc_iot, sc->sc_obh, offset, value);
}
-#if 0 /* unused */
static inline uint64_t
xhci_op_read_8(const struct xhci_softc * const sc, bus_size_t offset)
{
@@ -310,7 +304,6 @@ xhci_op_read_8(const struct xhci_softc *
return value;
}
-#endif /* unused */
static inline void
xhci_op_write_8(const struct xhci_softc * const sc, bus_size_t offset,
@@ -498,6 +491,15 @@ xhci_trb_put(struct xhci_trb * const trb
trb->trb_3 = control;
}
+static unsigned int
+xhci_get_epstate(struct xhci_softc * const sc, struct xhci_slot * const xs,
+ u_int dci)
+{
+ return XHCI_EPCTX_0_EPSTATE_GET(
+ le32toh(((uint32_t *)xhci_slot_get_dcv(sc, xs, dci)))
+ [0]);
+}
+
/* --- */
void
@@ -1320,7 +1322,7 @@ xhci_configure_endpoint(struct usbd_pipe
trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) |
XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP);
- err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
+ err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT, 0);
usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD);
hexdump("output context", xhci_slot_get_dcv(sc, xs, dci),
@@ -1346,7 +1348,7 @@ xhci_unconfigure_endpoint(struct usbd_pi
/* 4.6.8, 6.4.3.7 */
static usbd_status
-xhci_reset_endpoint(struct usbd_pipe *pipe)
+xhci_reset_endpoint(struct usbd_pipe *pipe, int locked)
{
struct xhci_softc * const sc = pipe->up_dev->ud_bus->ub_hcpriv;
struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
@@ -1357,7 +1359,8 @@ xhci_reset_endpoint(struct usbd_pipe *pi
XHCIHIST_FUNC(); XHCIHIST_CALLED();
DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
- KASSERT(!mutex_owned(&sc->sc_lock));
+ if (!locked)
+ KASSERT(!mutex_owned(&sc->sc_lock));
trb.trb_0 = 0;
trb.trb_2 = 0;
@@ -1365,7 +1368,7 @@ xhci_reset_endpoint(struct usbd_pipe *pi
XHCI_TRB_3_EP_SET(dci) |
XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_EP);
- err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
+ err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT, locked);
return err;
}
@@ -1376,7 +1379,7 @@ xhci_reset_endpoint(struct usbd_pipe *pi
* Should be called with sc_lock held.
*/
static usbd_status
-xhci_stop_endpoint(struct usbd_pipe *pipe)
+xhci_stop_endpoint(struct usbd_pipe *pipe, int locked)
{
struct xhci_softc * const sc = pipe->up_dev->ud_bus->ub_hcpriv;
struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
@@ -1395,7 +1398,7 @@ xhci_stop_endpoint(struct usbd_pipe *pip
XHCI_TRB_3_EP_SET(dci) |
XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STOP_EP);
- err = xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
+ err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT, locked);
return err;
}
@@ -1407,7 +1410,7 @@ xhci_stop_endpoint(struct usbd_pipe *pip
* EPSTATE of endpoint must be ERROR or STOPPED, or CONTEXT_STATE error.
*/
static usbd_status
-xhci_set_dequeue(struct usbd_pipe *pipe)
+xhci_set_dequeue(struct usbd_pipe *pipe, int locked)
{
struct xhci_softc * const sc = pipe->up_dev->ud_bus->ub_hcpriv;
struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
@@ -1419,6 +1422,9 @@ xhci_set_dequeue(struct usbd_pipe *pipe)
XHCIHIST_FUNC(); XHCIHIST_CALLED();
DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
+ if (!locked)
+ KASSERT(!mutex_owned(&sc->sc_lock));
+
memset(xr->xr_trb, 0, xr->xr_ntrb * XHCI_TRB_SIZE);
usb_syncmem(&xr->xr_dma, 0, xr->xr_ntrb * XHCI_TRB_SIZE,
BUS_DMASYNC_PREWRITE);
@@ -1433,7 +1439,7 @@ xhci_set_dequeue(struct usbd_pipe *pipe)
XHCI_TRB_3_EP_SET(dci) |
XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_SET_TR_DEQUEUE);
- err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
+ err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT, locked);
return err;
}
@@ -1526,7 +1532,7 @@ xhci_close_pipe(struct usbd_pipe *pipe)
/* xs is uninitialized before xhci_init_slot */
return;
- DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
+ DPRINTFN(4, "pipe %p slot %u dci %u", pipe, xs->xs_idx, dci, 0);
KASSERTMSG(!cpu_intr_p() && !cpu_softintr_p(), "called from intr ctx");
KASSERT(mutex_owned(&sc->sc_lock));
@@ -1540,11 +1546,8 @@ xhci_close_pipe(struct usbd_pipe *pipe)
return;
}
- /*
- * This may fail in the case that xhci_close_pipe is called after
- * xhci_abort_xfer e.g. usbd_kill_pipe.
- */
- (void)xhci_stop_endpoint(pipe);
+ if (xhci_get_epstate(sc, xs, dci) != XHCI_EPSTATE_STOPPED)
+ (void)xhci_stop_endpoint(pipe, 1);
/*
* set appropriate bit to be dropped.
@@ -1567,7 +1570,7 @@ xhci_close_pipe(struct usbd_pipe *pipe)
trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) |
XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP);
- (void)xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
+ (void)xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT, 1);
usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD);
}
@@ -1580,10 +1583,12 @@ static void
xhci_abort_xfer(struct usbd_xfer *xfer, usbd_status status)
{
struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
+ struct xhci_slot * const xs = xfer->ux_pipe->up_dev->ud_hcpriv;
+ const u_int dci = xhci_ep_get_dci(xfer->ux_pipe->up_endpoint->ue_edesc);
XHCIHIST_FUNC(); XHCIHIST_CALLED();
- DPRINTFN(4, "xfer %p pipe %p status %d",
- xfer, xfer->ux_pipe, status, 0);
+ DPRINTFN(4, "xfer %p status %u slot %u dci %u",
+ xfer, status, xs->xs_idx, dci);
KASSERT(mutex_owned(&sc->sc_lock));
@@ -1596,10 +1601,77 @@ xhci_abort_xfer(struct usbd_xfer *xfer,
return;
}
- /* XXX need more stuff */
- xfer->ux_status = status;
+ /*
+ * If an abort is already in progress then just wait for it to
+ * complete and return.
+ */
+ if (xfer->ux_hcflags & UXFER_ABORTING) {
+ DPRINTFN(4, "already aborting", 0, 0, 0, 0);
+#ifdef DIAGNOSTIC
+ if (status == USBD_TIMEOUT)
+ DPRINTFN(4, "TIMEOUT while aborting", 0, 0, 0, 0);
+#endif
+ /* Override the status which might be USBD_TIMEOUT. */
+ xfer->ux_status = status;
+ DPRINTFN(4, "waiting for abort to finish", 0, 0, 0, 0);
+ xfer->ux_hcflags |= UXFER_ABORTWAIT;
+ while (xfer->ux_hcflags & UXFER_ABORTING)
+ cv_wait(&xfer->ux_hccv, &sc->sc_lock);
+ return;
+ }
+ xfer->ux_hcflags |= UXFER_ABORTING;
+
+ /*
+ * Step 1: Make interrupt routine and hardware ignore xfer.
+ */
+ xfer->ux_status = status; /* make software ignore it */
callout_stop(&xfer->ux_callout);
- usb_transfer_complete(xfer);
+
+ /* Stop execution of TDs, so we can manipulate TDs on ring */
+ switch (xhci_get_epstate(sc, xs, dci)) {
+ case XHCI_EPSTATE_HALTED:
+ (void)xhci_reset_endpoint(xfer->ux_pipe, 1);
+ break;
+ case XHCI_EPSTATE_STOPPED:
+ break;
+ default:
+ (void)xhci_stop_endpoint(xfer->ux_pipe, 1);
+ break;
+ }
+
+ /*
+ * Step 2: Wait until we know hardware has finished any possible
+ * use of the xfer. Also make sure the soft interrupt routine
+ * has run.
+ */
+ sc->sc_softwake = 1;
+ usb_schedsoftintr(&sc->sc_bus);
+ cv_wait(&sc->sc_softwake_cv, &sc->sc_lock);
+
+ /*
+ * Step 3: Remove any vestiges of the xfer from the hardware.
+ * The complication here is that the hardware may have executed
+ * beyond the xfer we're trying to abort. So as we're scanning
+ * the TDs of this xfer we check if the hardware points to
+ * any of them.
+ */
+ xhci_set_dequeue(xfer->ux_pipe, 1);
+
+ /*
+ * Step 4: Execute callback.
+ */
+ int wake = xfer->ux_hcflags & UXFER_ABORTWAIT;
+ xfer->ux_hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);
+ if (xfer != NULL &&
+ xfer->ux_pipe != NULL &&
+ xfer->ux_state == XFER_ONQU &&
+ !(xfer->ux_pipe->up_repeat ||
+ SIMPLEQ_EMPTY(&xfer->ux_pipe->up_queue))) {
+ usb_transfer_complete(xfer);
+ }
+ if (wake) {
+ cv_broadcast(&xfer->ux_hccv);
+ }
KASSERT(mutex_owned(&sc->sc_lock));
}
@@ -1624,8 +1696,8 @@ xhci_clear_endpoint_stall_async_task(voi
XHCIHIST_FUNC(); XHCIHIST_CALLED();
DPRINTFN(4, "xfer %p slot %u dci %u", xfer, xs->xs_idx, dci, 0);
- xhci_reset_endpoint(xfer->ux_pipe);
- xhci_set_dequeue(xfer->ux_pipe);
+ xhci_reset_endpoint(xfer->ux_pipe, 0);
+ xhci_set_dequeue(xfer->ux_pipe, 0);
mutex_enter(&sc->sc_lock);
tr->is_halted = false;
@@ -1905,6 +1977,13 @@ xhci_softintr(void *v)
xhci_rt_write_8(sc, XHCI_ERDP(0), xhci_ring_trbp(er, er->xr_ep) |
XHCI_ERDP_LO_BUSY);
+ /* notify abort_xfer that softint has been done */
+ if (sc->sc_softwake) {
+ DPRINTFN(4, "cv_broadcast on softwake", 0, 0, 0, 0);
+ sc->sc_softwake = 0;
+ cv_broadcast(&sc->sc_softwake_cv);
+ }
+
DPRINTFN(16, "ends", 0, 0, 0, 0);
return;
@@ -2341,6 +2420,32 @@ xhci_ring_put(struct xhci_softc * const
DPRINTFN(12, "%p xr_ep 0x%x xr_cs %u", xr, xr->xr_ep, xr->xr_cs, 0);
}
+static void
+xhci_abort_command(struct xhci_softc *sc)
+{
+ uint64_t crcr;
+ int i;
+
+ XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+ /* 4.6.1.2 Aborting a Command */
+ DPRINTFN(14, "command %p timeout, aborting",
+ sc->sc_command_addr, 0, 0, 0);
+ crcr = xhci_op_read_8(sc, XHCI_CRCR);
+ xhci_op_write_8(sc, XHCI_CRCR, crcr | XHCI_CRCR_LO_CA);
+
+ for (i = 0; i < 500; i++) {
+ crcr = xhci_op_read_8(sc, XHCI_CRCR);
+ if ((crcr & XHCI_CRCR_LO_CRR) == 0)
+ break;
+ usb_delay_ms(&sc->sc_bus, 1);
+ }
+ if ((crcr & XHCI_CRCR_LO_CRR) != 0) {
+ DPRINTFN(1, "Command Abort timeout", 0, 0, 0, 0);
+ /* reset HC here? */
+ }
+}
+
/*
* Put a command on command ring, ring bell, set timer, and cv_timedwait.
* Command completion is notified by cv_signal from xhci_handle_event
@@ -2349,7 +2454,7 @@ xhci_ring_put(struct xhci_softc * const
* trb_0 in CMD_COMPLETE TRB and sc->sc_command_addr are identical.
*/
static usbd_status
-xhci_do_command1(struct xhci_softc * const sc, struct xhci_trb * const trb,
+xhci_do_command(struct xhci_softc * const sc, struct xhci_trb * const trb,
int timeout, int locked)
{
struct xhci_ring * const cr = &sc->sc_cr;
@@ -2376,6 +2481,7 @@ xhci_do_command1(struct xhci_softc * con
if (cv_timedwait(&sc->sc_command_cv, &sc->sc_lock,
MAX(1, mstohz(timeout))) == EWOULDBLOCK) {
+ xhci_abort_command(sc);
err = USBD_TIMEOUT;
goto timedout;
}
@@ -2408,25 +2514,6 @@ timedout:
}
static usbd_status
-xhci_do_command(struct xhci_softc * const sc, struct xhci_trb * const trb,
- int timeout)
-{
- return xhci_do_command1(sc, trb, timeout, 0);
-}
-
-/*
- * This allows xhci_do_command with already sc_lock held.
- * This is needed as USB stack calls close methods with sc_lock_held.
- * (see usbdivar.h)
- */
-static usbd_status
-xhci_do_command_locked(struct xhci_softc * const sc,
- struct xhci_trb * const trb, int timeout)
-{
- return xhci_do_command1(sc, trb, timeout, 1);
-}
-
-static usbd_status
xhci_enable_slot(struct xhci_softc * const sc, uint8_t * const slotp)
{
struct xhci_trb trb;
@@ -2438,7 +2525,7 @@ xhci_enable_slot(struct xhci_softc * con
trb.trb_2 = 0;
trb.trb_3 = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ENABLE_SLOT);
- err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
+ err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT, 0);
if (err != USBD_NORMAL_COMPLETION) {
return err;
}
@@ -2479,7 +2566,7 @@ xhci_disable_slot(struct xhci_softc * co
XHCI_TRB_3_SLOT_SET(slot) |
XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DISABLE_SLOT));
- return xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
+ return xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT, 1);
}
/*
@@ -2503,7 +2590,7 @@ xhci_address_device(struct xhci_softc *
XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ADDRESS_DEVICE) |
(bsr ? XHCI_TRB_3_BSR_BIT : 0);
- err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
+ err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT, 0);
return err;
}
@@ -2535,7 +2622,7 @@ xhci_update_ep0_mps(struct xhci_softc *
trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) |
XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_EVALUATE_CTX);
- err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
+ err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT, 0);
KASSERT(err == USBD_NORMAL_COMPLETION); /* XXX */
return err;
}
@@ -3027,9 +3114,9 @@ xhci_device_ctrl_start(struct usbd_xfer
if (tr->is_halted) {
DPRINTFN(1, "ctrl xfer %p halted: slot %u dci %u",
xfer, xs->xs_idx, dci, 0);
- xhci_reset_endpoint(xfer->ux_pipe);
+ xhci_reset_endpoint(xfer->ux_pipe, 0);
tr->is_halted = false;
- xhci_set_dequeue(xfer->ux_pipe);
+ xhci_set_dequeue(xfer->ux_pipe, 0);
}
/* we rely on the bottom bits for extra info */
@@ -3414,11 +3501,6 @@ xhci_timeout_task(void *addr)
XHCIHIST_FUNC(); XHCIHIST_CALLED();
mutex_enter(&sc->sc_lock);
-#if 0
xhci_abort_xfer(xfer, USBD_TIMEOUT);
-#else
- xfer->ux_status = USBD_TIMEOUT;
- usb_transfer_complete(xfer);
-#endif
mutex_exit(&sc->sc_lock);
}
--- src/sys/dev/usb/xhcivar.h.orig 2015-04-07 17:55:43.000000000 +0900
+++ src/sys/dev/usb/xhcivar.h 2015-06-02 10:11:37.000000000 +0900
@@ -75,6 +75,7 @@ struct xhci_softc {
kmutex_t sc_lock;
kmutex_t sc_intr_lock;
kcondvar_t sc_softwake_cv;
+ char sc_softwake;
struct usbd_xfer *sc_intrxfer;
--- src/sys/dev/usb/xhci.c.orig 2015-06-14 20:20:33.000000000 +0900
+++ src/sys/dev/usb/xhci.c 2015-06-14 20:29:13.000000000 +0900
@@ -1407,7 +1407,8 @@ xhci_stop_endpoint(struct usbd_pipe *pip
* Set TR Dequeue Pointer.
* xCHI 1.1 4.6.10 6.4.3.9
* Purge all of the transfer requests on ring.
- * EPSTATE of endpoint must be ERROR or STOPPED, or CONTEXT_STATE error.
+ * EPSTATE of endpoint must be ERROR or STOPPED, otherwise CONTEXT_STATE
+ * error will be generated.
*/
static usbd_status
xhci_set_dequeue(struct usbd_pipe *pipe, int locked)
@@ -1818,7 +1819,10 @@ xhci_handle_event(struct xhci_softc * co
} else {
xx = (void *)(uintptr_t)(trb_0 & ~0x3);
}
- /* XXX this may not happen */
+ /*
+ * stop_endpoint may cause ERR_STOPPED_LENGTH_INVALID,
+ * in which case this condition may happen.
+ */
if (xx == NULL) {
DPRINTFN(1, "xfer done: xx is NULL", 0, 0, 0, 0);
break;
@@ -2225,6 +2229,7 @@ xhci_new_device(device_t parent, struct
KASSERT(bus->ub_devices[dev->ud_addr] == NULL);
bus->ub_devices[dev->ud_addr] = dev;
+ /* read 64 bytes of device descriptor */
err = usbd_get_initial_ddesc(dev, dd);
if (err)
goto bad;
@@ -2452,6 +2457,10 @@ xhci_abort_command(struct xhci_softc *sc
* (called from interrupt from xHCI), or timed-out.
* Command validation is performed in xhci_handle_event by checking if
* trb_0 in CMD_COMPLETE TRB and sc->sc_command_addr are identical.
+ * locked = 0: called without lock held
+ * locked = 1: allows called with lock held
+ * 'locked' is needed as some methods are called with sc_lock_held.
+ * (see usbdivar.h)
*/
static usbd_status
xhci_do_command(struct xhci_softc * const sc, struct xhci_trb * const trb,
@@ -2469,7 +2478,7 @@ xhci_do_command(struct xhci_softc * cons
if (!locked)
mutex_enter(&sc->sc_lock);
- /* XXX KASSERT may fire when cv_timedwait unlocks sc_lock */
+ /* XXX KASSERT may fail when cv_timedwait unlocks sc_lock */
KASSERT(sc->sc_command_addr == 0);
sc->sc_command_addr = xhci_ring_trbp(cr, cr->xr_ep);
--- src/sys/dev/usb/usb_subr.c.orig 2015-06-07 01:42:33.000000000 +0900
+++ src/sys/dev/usb/usb_subr.c 2015-06-14 02:18:09.000000000 +0900
@@ -601,20 +601,20 @@ usbd_set_config_index(struct usbd_device
goto bad;
}
- if (USB_IS_SS(dev->ud_speed)) {
+ while (USB_IS_SS(dev->ud_speed)) {
int blen;
/* get short bos desc */
err = usbd_get_bos_desc(dev, index, &bd);
if (err) {
DPRINTF("get_bos_desc=%d", err, 0, 0, 0);
- goto bad;
+ break;
}
blen = UGETW(bd.wTotalLength);
bdp = kmem_alloc(blen, KM_SLEEP);
if (bdp == NULL) {
err = USBD_NOMEM;
- goto bad;
+ break;
}
/* Get the full desc */
@@ -626,15 +626,23 @@ usbd_set_config_index(struct usbd_device
}
if (err) {
DPRINTF("get_bos_desc=%d", err, 0, 0, 0);
- goto bad;
+ break;
}
- if (bdp->bDescriptorType != UDESC_BOS) {
+ if (bdp->bDescriptorType != UDESC_BOS ||
+ blen != UGETW(bdp->wTotalLength)) {
DPRINTF("bad desc %d", bdp->bDescriptorType, 0, 0, 0);
err = USBD_INVAL;
- goto bad;
+ break;
}
+ break;
}
- dev->ud_bdesc = bdp;
+ if (err) {
+ if (bdp != NULL) {
+ kmem_free(bdp, UGETW(bdp->wTotalLength));
+ bdp = NULL;
+ }
+ } else
+ dev->ud_bdesc = bdp;
/*
* Figure out if the device is self or bus powered.
Home |
Main Index |
Thread Index |
Old Index