1*993e3fafSRobert Mustacchi /*
2*993e3fafSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*993e3fafSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*993e3fafSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*993e3fafSRobert Mustacchi  * 1.0 of the CDDL.
6*993e3fafSRobert Mustacchi  *
7*993e3fafSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*993e3fafSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*993e3fafSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*993e3fafSRobert Mustacchi  */
11*993e3fafSRobert Mustacchi 
12*993e3fafSRobert Mustacchi /*
13*993e3fafSRobert Mustacchi  * Copyright 2016 Joyent, Inc.
14*993e3fafSRobert Mustacchi  */
15*993e3fafSRobert Mustacchi 
16*993e3fafSRobert Mustacchi /*
17*993e3fafSRobert Mustacchi  * -----------------------
18*993e3fafSRobert Mustacchi  * Command Ring Management
19*993e3fafSRobert Mustacchi  * -----------------------
20*993e3fafSRobert Mustacchi  *
21*993e3fafSRobert Mustacchi  * The command ring is the primary means by which the xHCI controller is
22*993e3fafSRobert Mustacchi  * managed. Events may be placed on the ring, at which point they will be
23*993e3fafSRobert Mustacchi  * processed in order. When commands are finished they generate event
24*993e3fafSRobert Mustacchi  * completions and we are notified via an interrupt.
25*993e3fafSRobert Mustacchi  *
26*993e3fafSRobert Mustacchi  * Every command is formatted in a transfer request block (TRB). These TRBs are
27*993e3fafSRobert Mustacchi  * queued on the command ring. To start the command ring, a doorbell register is
28*993e3fafSRobert Mustacchi  * written to. The current state of the command ring is maintained in the
29*993e3fafSRobert Mustacchi  * command ring control register (XHCI_CRCR).
30*993e3fafSRobert Mustacchi  *
31*993e3fafSRobert Mustacchi  * Every command has a condition variable. When the driver submits a command, it
32*993e3fafSRobert Mustacchi  * blocks on the command's CV waiting for a change in the commands status. This
33*993e3fafSRobert Mustacchi  * CV will be signaled after the command completes or is aborted, allowing the
34*993e3fafSRobert Mustacchi  * caller to treat this as a synchronous, blocking operation.
35*993e3fafSRobert Mustacchi  *
36*993e3fafSRobert Mustacchi  * The command ring itself consists of three primary states:
37*993e3fafSRobert Mustacchi  *
38*993e3fafSRobert Mustacchi  * 	XHCI_COMMAND_RING_IDLE		The command ring is not currently
39*993e3fafSRobert Mustacchi  * 					processing any events. No timeout events
40*993e3fafSRobert Mustacchi  * 					are active.
41*993e3fafSRobert Mustacchi  *
42*993e3fafSRobert Mustacchi  * 	XHCI_COMMAND_RING_RUNNING	The command ring currently has one or
43*993e3fafSRobert Mustacchi  * 					more events enqueued and the hardware
44*993e3fafSRobert Mustacchi  * 					has been signalled to process commands.
45*993e3fafSRobert Mustacchi  *
46*993e3fafSRobert Mustacchi  * 	XHCI_COMMAND_RING_ABORTING	A command has timed out and we are
47*993e3fafSRobert Mustacchi  * 					attempting to abort the current command,
48*993e3fafSRobert Mustacchi  * 					which will stop the ring.
49*993e3fafSRobert Mustacchi  *
50*993e3fafSRobert Mustacchi  * 	XHCI_COMMAND_RING_ABORT_DONE	We have successfully received a
51*993e3fafSRobert Mustacchi  * 					notification that the abort worked and
52*993e3fafSRobert Mustacchi  * 					that the command ring has stopped. This
53*993e3fafSRobert Mustacchi  * 					allows us to clean up state and
54*993e3fafSRobert Mustacchi  * 					transition back to either idle or
55*993e3fafSRobert Mustacchi  * 					running, depending on if we have queued
56*993e3fafSRobert Mustacchi  * 					commands.
57*993e3fafSRobert Mustacchi  *
58*993e3fafSRobert Mustacchi  * The state transition can be summarized as:
59*993e3fafSRobert Mustacchi  *
60*993e3fafSRobert Mustacchi  *    +------+                        +---------+
61*993e3fafSRobert Mustacchi  *    | Idle |--------*-------------->| Running |<----------------------+
62*993e3fafSRobert Mustacchi  *    +------+        . Command       +---------+                       |
63*993e3fafSRobert Mustacchi  *       ^              TRB queued      |    |                          |
64*993e3fafSRobert Mustacchi  *       |              on ring         |    |                          |
65*993e3fafSRobert Mustacchi  *       |                              |    * . . Command not          |
66*993e3fafSRobert Mustacchi  *       +-------*----------------------+    |     acknowledged         |
67*993e3fafSRobert Mustacchi  *       |       . . No more                 |     within timeout       |
68*993e3fafSRobert Mustacchi  *       |           commands                |     xhci_command_wait    |
69*993e3fafSRobert Mustacchi  *       |           queued                  |                          |
70*993e3fafSRobert Mustacchi  *       |                                   v       . abort request    |
71*993e3fafSRobert Mustacchi  *       * . No commands              +----------+   . times out        |
72*993e3fafSRobert Mustacchi  *       |   queued after             | Aborting |---*--+               |
73*993e3fafSRobert Mustacchi  *       |   successful               +----------+      v               |
74*993e3fafSRobert Mustacchi  *       |   abort                         |      +----------+          |
75*993e3fafSRobert Mustacchi  *       |                       abort . . *      | HW Reset |          |
76*993e3fafSRobert Mustacchi  *       |                acknowledged     |      +----------+          |
77*993e3fafSRobert Mustacchi  *       |                                 v                            |
78*993e3fafSRobert Mustacchi  *       |                           +------------+                     |
79*993e3fafSRobert Mustacchi  *       +---------------------------| Abort Done |----*----------------+
80*993e3fafSRobert Mustacchi  *                                   +------------+    . Commands queued
81*993e3fafSRobert Mustacchi  *                                                       after successful
82*993e3fafSRobert Mustacchi  *                                                       abort
83*993e3fafSRobert Mustacchi  *
84*993e3fafSRobert Mustacchi  * ---------------------------
85*993e3fafSRobert Mustacchi  * Timeouts and Command Aborts
86*993e3fafSRobert Mustacchi  * ---------------------------
87*993e3fafSRobert Mustacchi  *
88*993e3fafSRobert Mustacchi  * Commands may time out either due to issues with the host controller or with
89*993e3fafSRobert Mustacchi  * the devices connected to it. For example, the ADDRESS DEVICE command may
90*993e3fafSRobert Mustacchi  * issue commands to the device. As such, we need to be prepared for commands to
91*993e3fafSRobert Mustacchi  * time out.
92*993e3fafSRobert Mustacchi  *
93*993e3fafSRobert Mustacchi  * To deal with a stalled command, we write to the XHCI_CRCR register to abort
94*993e3fafSRobert Mustacchi  * the currently running command. This is discussed in xHCI 1.1 / 4.6.1.2. When
95*993e3fafSRobert Mustacchi  * a command is aborted, we should eventually receive a TRB completion for that
96*993e3fafSRobert Mustacchi  * command. However, this is no guarantee that an abort will be successful. The
97*993e3fafSRobert Mustacchi  * specification recommends waiting about 5 seconds for that to finish. After
98*993e3fafSRobert Mustacchi  * which we terminate the device.
99*993e3fafSRobert Mustacchi  *
100*993e3fafSRobert Mustacchi  * For an abort to be successful, we expect two different notifications. First
101*993e3fafSRobert Mustacchi  * we should receive a TRB for the actual command itself indicating that it's
102*993e3fafSRobert Mustacchi  * terminated. Next, we should receive a TRB indicating that the command ring
103*993e3fafSRobert Mustacchi  * has stopped. Only when we receive this second one, do we consider re-enabling
104*993e3fafSRobert Mustacchi  * the command ring.
105*993e3fafSRobert Mustacchi  *
106*993e3fafSRobert Mustacchi  * -------
107*993e3fafSRobert Mustacchi  * Locking
108*993e3fafSRobert Mustacchi  * -------
109*993e3fafSRobert Mustacchi  *
110*993e3fafSRobert Mustacchi  * The command ring's lock, xhci_command_ring_t`xcr_lock, should not be accessed
111*993e3fafSRobert Mustacchi  * outside of this file. If a caller needs to take the xhci_t`xhci_lock, it must
112*993e3fafSRobert Mustacchi  * be taken before the xcr_lock is taken. It is illegal for to hold
113*993e3fafSRobert Mustacchi  * xhci_t`xhci_lock across any command functions. Doing so would lead to
114*993e3fafSRobert Mustacchi  * deadlock.
115*993e3fafSRobert Mustacchi  */
116*993e3fafSRobert Mustacchi 
117*993e3fafSRobert Mustacchi #include <sys/usb/hcd/xhci/xhci.h>
118*993e3fafSRobert Mustacchi #include <sys/sysmacros.h>
119*993e3fafSRobert Mustacchi 
120*993e3fafSRobert Mustacchi /*
121*993e3fafSRobert Mustacchi  * Recommended time to wait for an abort in from the Implementation Note
122*993e3fafSRobert Mustacchi  * in XHCI 1.1 / 4.6.1.2. The time is kept in microseconds.
123*993e3fafSRobert Mustacchi  */
124*993e3fafSRobert Mustacchi clock_t xhci_command_abort_wait = 5 * MICROSEC;
125*993e3fafSRobert Mustacchi 
126*993e3fafSRobert Mustacchi /*
127*993e3fafSRobert Mustacchi  * Default to waiting for one second for a command to time out. Time stored in
128*993e3fafSRobert Mustacchi  * microseconds.
129*993e3fafSRobert Mustacchi  */
130*993e3fafSRobert Mustacchi clock_t xhci_command_wait = MICROSEC;
131*993e3fafSRobert Mustacchi 
132*993e3fafSRobert Mustacchi /*
133*993e3fafSRobert Mustacchi  * Required forwards.
134*993e3fafSRobert Mustacchi  */
135*993e3fafSRobert Mustacchi static void xhci_command_settimeout(xhci_t *, clock_t);
136*993e3fafSRobert Mustacchi 
137*993e3fafSRobert Mustacchi void
xhci_command_ring_fini(xhci_t * xhcip)138*993e3fafSRobert Mustacchi xhci_command_ring_fini(xhci_t *xhcip)
139*993e3fafSRobert Mustacchi {
140*993e3fafSRobert Mustacchi 	xhci_command_ring_t *xcr = &xhcip->xhci_command;
141*993e3fafSRobert Mustacchi 
142*993e3fafSRobert Mustacchi 	/*
143*993e3fafSRobert Mustacchi 	 * If the ring is not allocated, then nothing else is here.
144*993e3fafSRobert Mustacchi 	 */
145*993e3fafSRobert Mustacchi 	if (xcr->xcr_ring.xr_trb == NULL)
146*993e3fafSRobert Mustacchi 		return;
147*993e3fafSRobert Mustacchi 	VERIFY(xcr->xcr_timeout == 0);
148*993e3fafSRobert Mustacchi 	xhci_ring_free(&xcr->xcr_ring);
149*993e3fafSRobert Mustacchi 	mutex_destroy(&xcr->xcr_lock);
150*993e3fafSRobert Mustacchi 	cv_destroy(&xcr->xcr_cv);
151*993e3fafSRobert Mustacchi 	list_destroy(&xcr->xcr_commands);
152*993e3fafSRobert Mustacchi }
153*993e3fafSRobert Mustacchi 
154*993e3fafSRobert Mustacchi /*
155*993e3fafSRobert Mustacchi  * Initialize or re-initialize the command ring. This will be called whenever we
156*993e3fafSRobert Mustacchi  * reset the xHCI commandler, so we may actually have already allocated DMA
157*993e3fafSRobert Mustacchi  * memory for the ring.
158*993e3fafSRobert Mustacchi  */
159*993e3fafSRobert Mustacchi int
xhci_command_ring_init(xhci_t * xhcip)160*993e3fafSRobert Mustacchi xhci_command_ring_init(xhci_t *xhcip)
161*993e3fafSRobert Mustacchi {
162*993e3fafSRobert Mustacchi 	int ret;
163*993e3fafSRobert Mustacchi 	uint64_t addr;
164*993e3fafSRobert Mustacchi 	xhci_command_ring_t *xcr = &xhcip->xhci_command;
165*993e3fafSRobert Mustacchi 
166*993e3fafSRobert Mustacchi 	if (xcr->xcr_ring.xr_trb == NULL) {
167*993e3fafSRobert Mustacchi 		if ((ret = xhci_ring_alloc(xhcip, &xcr->xcr_ring)) != 0)
168*993e3fafSRobert Mustacchi 			return (ret);
169*993e3fafSRobert Mustacchi 	}
170*993e3fafSRobert Mustacchi 
171*993e3fafSRobert Mustacchi 	if ((ret = xhci_ring_reset(xhcip, &xcr->xcr_ring)) != 0)
172*993e3fafSRobert Mustacchi 		return (ret);
173*993e3fafSRobert Mustacchi 
174*993e3fafSRobert Mustacchi #ifdef	DEBUG
175*993e3fafSRobert Mustacchi 	addr = xhci_get64(xhcip, XHCI_R_OPER, XHCI_CRCR);
176*993e3fafSRobert Mustacchi 	VERIFY0(addr & XHCI_CRCR_CRR);
177*993e3fafSRobert Mustacchi #endif
178*993e3fafSRobert Mustacchi 	addr = LE_64(xhci_dma_pa(&xcr->xcr_ring.xr_dma) | XHCI_CRCR_RCS);
179*993e3fafSRobert Mustacchi 	xhci_put64(xhcip, XHCI_R_OPER, XHCI_CRCR, addr);
180*993e3fafSRobert Mustacchi 	if (xhci_check_regs_acc(xhcip) != DDI_FM_OK)
181*993e3fafSRobert Mustacchi 		return (EIO);
182*993e3fafSRobert Mustacchi 
183*993e3fafSRobert Mustacchi 	mutex_init(&xcr->xcr_lock, NULL, MUTEX_DRIVER,
184*993e3fafSRobert Mustacchi 	    DDI_INTR_PRI(xhcip->xhci_intr_pri));
185*993e3fafSRobert Mustacchi 	cv_init(&xcr->xcr_cv, NULL, CV_DRIVER, NULL);
186*993e3fafSRobert Mustacchi 	list_create(&xcr->xcr_commands, sizeof (xhci_command_t),
187*993e3fafSRobert Mustacchi 	    offsetof(xhci_command_t, xco_link));
188*993e3fafSRobert Mustacchi 	return (0);
189*993e3fafSRobert Mustacchi }
190*993e3fafSRobert Mustacchi 
191*993e3fafSRobert Mustacchi static void
xhci_command_timeout(void * arg)192*993e3fafSRobert Mustacchi xhci_command_timeout(void *arg)
193*993e3fafSRobert Mustacchi {
194*993e3fafSRobert Mustacchi 	uint64_t reg;
195*993e3fafSRobert Mustacchi 	clock_t delay;
196*993e3fafSRobert Mustacchi 	xhci_t *xhcip = arg;
197*993e3fafSRobert Mustacchi 	xhci_command_ring_t *xcr = &xhcip->xhci_command;
198*993e3fafSRobert Mustacchi 	xhci_command_t *xco;
199*993e3fafSRobert Mustacchi 
200*993e3fafSRobert Mustacchi 	mutex_enter(&xcr->xcr_lock);
201*993e3fafSRobert Mustacchi 
202*993e3fafSRobert Mustacchi 	xco = list_head(&xcr->xcr_commands);
203*993e3fafSRobert Mustacchi 	if (xco == NULL || xco->xco_state != XHCI_COMMAND_S_QUEUED) {
204*993e3fafSRobert Mustacchi 		xcr->xcr_timeout = 0;
205*993e3fafSRobert Mustacchi 		mutex_exit(&xcr->xcr_lock);
206*993e3fafSRobert Mustacchi 		return;
207*993e3fafSRobert Mustacchi 	}
208*993e3fafSRobert Mustacchi 
209*993e3fafSRobert Mustacchi 	xcr->xcr_state = XHCI_COMMAND_RING_ABORTING;
210*993e3fafSRobert Mustacchi 	reg = xhci_get64(xhcip, XHCI_R_OPER, XHCI_CRCR);
211*993e3fafSRobert Mustacchi 	if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
212*993e3fafSRobert Mustacchi 		xcr->xcr_timeout = 0;
213*993e3fafSRobert Mustacchi 		mutex_exit(&xcr->xcr_lock);
214*993e3fafSRobert Mustacchi 		xhci_error(xhcip, "encountered fatal FM error reading command "
215*993e3fafSRobert Mustacchi 		    "ring control register: resetting device");
216*993e3fafSRobert Mustacchi 		xhci_fm_runtime_reset(xhcip);
217*993e3fafSRobert Mustacchi 		return;
218*993e3fafSRobert Mustacchi 	}
219*993e3fafSRobert Mustacchi 
220*993e3fafSRobert Mustacchi 	/*
221*993e3fafSRobert Mustacchi 	 * While all the other bits should be ignored because we're running, if
222*993e3fafSRobert Mustacchi 	 * for some reason we're not running, then this will make sure that we
223*993e3fafSRobert Mustacchi 	 * don't screw things up.
224*993e3fafSRobert Mustacchi 	 */
225*993e3fafSRobert Mustacchi 	reg |= XHCI_CRCR_CA;
226*993e3fafSRobert Mustacchi 	xhci_put64(xhcip, XHCI_R_OPER, XHCI_CRCR, reg);
227*993e3fafSRobert Mustacchi 	if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
228*993e3fafSRobert Mustacchi 		xcr->xcr_timeout = 0;
229*993e3fafSRobert Mustacchi 		mutex_exit(&xcr->xcr_lock);
230*993e3fafSRobert Mustacchi 		xhci_error(xhcip, "encountered fatal FM error writing command "
231*993e3fafSRobert Mustacchi 		    "ring control register: resetting device");
232*993e3fafSRobert Mustacchi 		xhci_fm_runtime_reset(xhcip);
233*993e3fafSRobert Mustacchi 		return;
234*993e3fafSRobert Mustacchi 	}
235*993e3fafSRobert Mustacchi 
236*993e3fafSRobert Mustacchi 	delay = drv_usectohz(xhci_command_abort_wait);
237*993e3fafSRobert Mustacchi 	while (xcr->xcr_state != XHCI_COMMAND_RING_ABORT_DONE) {
238*993e3fafSRobert Mustacchi 		int ret;
239*993e3fafSRobert Mustacchi 
240*993e3fafSRobert Mustacchi 		ret = cv_reltimedwait(&xcr->xcr_cv, &xcr->xcr_lock, delay,
241*993e3fafSRobert Mustacchi 		    TR_CLOCK_TICK);
242*993e3fafSRobert Mustacchi 		if (ret == -1) {
243*993e3fafSRobert Mustacchi 			/* Time out waiting for the abort */
244*993e3fafSRobert Mustacchi 			xcr->xcr_timeout = 0;
245*993e3fafSRobert Mustacchi 			mutex_exit(&xcr->xcr_lock);
246*993e3fafSRobert Mustacchi 			xhci_error(xhcip, "abort command timed out: resetting "
247*993e3fafSRobert Mustacchi 			    "device");
248*993e3fafSRobert Mustacchi 			xhci_fm_runtime_reset(xhcip);
249*993e3fafSRobert Mustacchi 			return;
250*993e3fafSRobert Mustacchi 		}
251*993e3fafSRobert Mustacchi 	}
252*993e3fafSRobert Mustacchi 
253*993e3fafSRobert Mustacchi 	/*
254*993e3fafSRobert Mustacchi 	 * Successful abort, transition the ring as needed.
255*993e3fafSRobert Mustacchi 	 */
256*993e3fafSRobert Mustacchi 	if (list_is_empty(&xcr->xcr_commands) != 0) {
257*993e3fafSRobert Mustacchi 		xcr->xcr_state = XHCI_COMMAND_RING_IDLE;
258*993e3fafSRobert Mustacchi 		xcr->xcr_timeout = 0;
259*993e3fafSRobert Mustacchi 	} else {
260*993e3fafSRobert Mustacchi 		xhci_put32(xhcip, XHCI_R_DOOR, XHCI_DOORBELL(0), 0);
261*993e3fafSRobert Mustacchi 		if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
262*993e3fafSRobert Mustacchi 			xcr->xcr_timeout = 0;
263*993e3fafSRobert Mustacchi 			mutex_exit(&xcr->xcr_lock);
264*993e3fafSRobert Mustacchi 			xhci_error(xhcip, "encountered fatal FM error writing "
265*993e3fafSRobert Mustacchi 			    "command ring control register: resetting device");
266*993e3fafSRobert Mustacchi 			xhci_fm_runtime_reset(xhcip);
267*993e3fafSRobert Mustacchi 			return;
268*993e3fafSRobert Mustacchi 		}
269*993e3fafSRobert Mustacchi 
270*993e3fafSRobert Mustacchi 		/*
271*993e3fafSRobert Mustacchi 		 * Reset our timeout id before we create a new timeout
272*993e3fafSRobert Mustacchi 		 */
273*993e3fafSRobert Mustacchi 		xcr->xcr_timeout = 0;
274*993e3fafSRobert Mustacchi 		xhci_command_settimeout(xhcip, xhci_command_wait);
275*993e3fafSRobert Mustacchi 		xcr->xcr_state = XHCI_COMMAND_RING_RUNNING;
276*993e3fafSRobert Mustacchi 	}
277*993e3fafSRobert Mustacchi 	mutex_exit(&xcr->xcr_lock);
278*993e3fafSRobert Mustacchi }
279*993e3fafSRobert Mustacchi 
280*993e3fafSRobert Mustacchi static void
xhci_command_settimeout(xhci_t * xhcip,clock_t microsecs)281*993e3fafSRobert Mustacchi xhci_command_settimeout(xhci_t *xhcip, clock_t microsecs)
282*993e3fafSRobert Mustacchi {
283*993e3fafSRobert Mustacchi 	clock_t delay;
284*993e3fafSRobert Mustacchi 	xhci_command_ring_t *xcr = &xhcip->xhci_command;
285*993e3fafSRobert Mustacchi 
286*993e3fafSRobert Mustacchi 	ASSERT(MUTEX_HELD(&xcr->xcr_lock));
287*993e3fafSRobert Mustacchi 	ASSERT(xcr->xcr_timeout == 0);
288*993e3fafSRobert Mustacchi 
289*993e3fafSRobert Mustacchi 	delay = drv_usectohz(microsecs);
290*993e3fafSRobert Mustacchi 	xcr->xcr_timeout = timeout(xhci_command_timeout, xhcip, delay);
291*993e3fafSRobert Mustacchi }
292*993e3fafSRobert Mustacchi 
293*993e3fafSRobert Mustacchi void
xhci_command_init(xhci_command_t * xcp)294*993e3fafSRobert Mustacchi xhci_command_init(xhci_command_t *xcp)
295*993e3fafSRobert Mustacchi {
296*993e3fafSRobert Mustacchi 	bzero(xcp, sizeof (xhci_command_t));
297*993e3fafSRobert Mustacchi 	cv_init(&xcp->xco_cv, NULL, CV_DRIVER, NULL);
298*993e3fafSRobert Mustacchi }
299*993e3fafSRobert Mustacchi 
300*993e3fafSRobert Mustacchi void
xhci_command_fini(xhci_command_t * xcp)301*993e3fafSRobert Mustacchi xhci_command_fini(xhci_command_t *xcp)
302*993e3fafSRobert Mustacchi {
303*993e3fafSRobert Mustacchi 	cv_destroy(&xcp->xco_cv);
304*993e3fafSRobert Mustacchi }
305*993e3fafSRobert Mustacchi 
306*993e3fafSRobert Mustacchi boolean_t
xhci_command_event_callback(xhci_t * xhcip,xhci_trb_t * trb)307*993e3fafSRobert Mustacchi xhci_command_event_callback(xhci_t *xhcip, xhci_trb_t *trb)
308*993e3fafSRobert Mustacchi {
309*993e3fafSRobert Mustacchi 	int cstat;
310*993e3fafSRobert Mustacchi 	timeout_id_t to;
311*993e3fafSRobert Mustacchi 	xhci_command_t *xco, *rem;
312*993e3fafSRobert Mustacchi 	xhci_command_ring_t *xcr = &xhcip->xhci_command;
313*993e3fafSRobert Mustacchi 	xhci_ring_t *xrp = &xcr->xcr_ring;
314*993e3fafSRobert Mustacchi 
315*993e3fafSRobert Mustacchi 	mutex_enter(&xcr->xcr_lock);
316*993e3fafSRobert Mustacchi 
317*993e3fafSRobert Mustacchi 	/*
318*993e3fafSRobert Mustacchi 	 * If we got an event that indicates that the command ring was stopped,
319*993e3fafSRobert Mustacchi 	 * then we have successfully finished an abort. While a command ring
320*993e3fafSRobert Mustacchi 	 * stop can also be done by writing to the XHCI_CRCR register, the
321*993e3fafSRobert Mustacchi 	 * driver does not do so at this time; however, we guard the state
322*993e3fafSRobert Mustacchi 	 * transition just in case.
323*993e3fafSRobert Mustacchi 	 */
324*993e3fafSRobert Mustacchi 	cstat = XHCI_TRB_GET_CODE(LE_32(trb->trb_status));
325*993e3fafSRobert Mustacchi 	if (cstat == XHCI_CODE_CMD_RING_STOP) {
326*993e3fafSRobert Mustacchi 		if (xcr->xcr_state == XHCI_COMMAND_RING_ABORTING)
327*993e3fafSRobert Mustacchi 			xcr->xcr_state = XHCI_COMMAND_RING_ABORT_DONE;
328*993e3fafSRobert Mustacchi 		cv_broadcast(&xcr->xcr_cv);
329*993e3fafSRobert Mustacchi 		mutex_exit(&xcr->xcr_lock);
330*993e3fafSRobert Mustacchi 		return (B_TRUE);
331*993e3fafSRobert Mustacchi 	}
332*993e3fafSRobert Mustacchi 
333*993e3fafSRobert Mustacchi 	xco = list_head(&xcr->xcr_commands);
334*993e3fafSRobert Mustacchi 	VERIFY(xco != NULL);
335*993e3fafSRobert Mustacchi 
336*993e3fafSRobert Mustacchi 	/*
337*993e3fafSRobert Mustacchi 	 * The current event should be pointed to by the ring's tail pointer.
338*993e3fafSRobert Mustacchi 	 * We need to check if this DMA address that we've been given matches
339*993e3fafSRobert Mustacchi 	 * the address that we'd expect for the tail.
340*993e3fafSRobert Mustacchi 	 */
341*993e3fafSRobert Mustacchi 	if (xhci_ring_trb_tail_valid(xrp, LE_64(trb->trb_addr)) == B_FALSE) {
342*993e3fafSRobert Mustacchi 		mutex_exit(&xcr->xcr_lock);
343*993e3fafSRobert Mustacchi 		return (B_TRUE);
344*993e3fafSRobert Mustacchi 	}
345*993e3fafSRobert Mustacchi 
346*993e3fafSRobert Mustacchi 	xco->xco_state = XHCI_COMMAND_S_RECEIVED;
347*993e3fafSRobert Mustacchi 	to = xcr->xcr_timeout;
348*993e3fafSRobert Mustacchi 	xcr->xcr_timeout = 0;
349*993e3fafSRobert Mustacchi 	if (xcr->xcr_state != XHCI_COMMAND_RING_ABORTING) {
350*993e3fafSRobert Mustacchi 		mutex_exit(&xcr->xcr_lock);
351*993e3fafSRobert Mustacchi 		(void) untimeout(to);
352*993e3fafSRobert Mustacchi 		mutex_enter(&xcr->xcr_lock);
353*993e3fafSRobert Mustacchi 	}
354*993e3fafSRobert Mustacchi 	rem = list_remove_head(&xcr->xcr_commands);
355*993e3fafSRobert Mustacchi 
356*993e3fafSRobert Mustacchi 	VERIFY3P(rem, ==, xco);
357*993e3fafSRobert Mustacchi 
358*993e3fafSRobert Mustacchi 	xco->xco_res.trb_addr = LE_64(trb->trb_addr);
359*993e3fafSRobert Mustacchi 	xco->xco_res.trb_status = LE_32(trb->trb_status);
360*993e3fafSRobert Mustacchi 	xco->xco_res.trb_flags = LE_32(trb->trb_flags);
361*993e3fafSRobert Mustacchi 	xco->xco_state = XHCI_COMMAND_S_DONE;
362*993e3fafSRobert Mustacchi 
363*993e3fafSRobert Mustacchi 	/*
364*993e3fafSRobert Mustacchi 	 * Advance the ring and wake up anyone who was waiting for a slot.
365*993e3fafSRobert Mustacchi 	 */
366*993e3fafSRobert Mustacchi 	if (xhci_ring_trb_consumed(xrp, LE_64(trb->trb_addr)) == B_FALSE) {
367*993e3fafSRobert Mustacchi 		/*
368*993e3fafSRobert Mustacchi 		 * Indicate that we need to do a runtime reset to the interrupt
369*993e3fafSRobert Mustacchi 		 * handler.
370*993e3fafSRobert Mustacchi 		 */
371*993e3fafSRobert Mustacchi 		mutex_exit(&xcr->xcr_lock);
372*993e3fafSRobert Mustacchi 		xhci_error(xhcip, "encountered invalid TRB head while "
373*993e3fafSRobert Mustacchi 		    "processing command ring: TRB with addr 0x%"PRIx64 " could "
374*993e3fafSRobert Mustacchi 		    "not be consumed", LE_64(trb->trb_addr));
375*993e3fafSRobert Mustacchi 		xhci_fm_runtime_reset(xhcip);
376*993e3fafSRobert Mustacchi 		return (B_FALSE);
377*993e3fafSRobert Mustacchi 	}
378*993e3fafSRobert Mustacchi 	cv_broadcast(&xcr->xcr_cv);
379*993e3fafSRobert Mustacchi 
380*993e3fafSRobert Mustacchi 	if (xcr->xcr_state < XHCI_COMMAND_RING_ABORTING) {
381*993e3fafSRobert Mustacchi 		if (list_is_empty(&xcr->xcr_commands) != 0) {
382*993e3fafSRobert Mustacchi 			xcr->xcr_state = XHCI_COMMAND_RING_IDLE;
383*993e3fafSRobert Mustacchi 		} else {
384*993e3fafSRobert Mustacchi 			xhci_command_settimeout(xhcip, xhci_command_wait);
385*993e3fafSRobert Mustacchi 		}
386*993e3fafSRobert Mustacchi 	}
387*993e3fafSRobert Mustacchi 	mutex_exit(&xcr->xcr_lock);
388*993e3fafSRobert Mustacchi 
389*993e3fafSRobert Mustacchi 	/*
390*993e3fafSRobert Mustacchi 	 * Now, let anyone waiting for this command to finish know it's done.
391*993e3fafSRobert Mustacchi 	 */
392*993e3fafSRobert Mustacchi 	cv_signal(&xco->xco_cv);
393*993e3fafSRobert Mustacchi 
394*993e3fafSRobert Mustacchi 	return (B_TRUE);
395*993e3fafSRobert Mustacchi }
396*993e3fafSRobert Mustacchi 
397*993e3fafSRobert Mustacchi static int
xhci_command_submit(xhci_t * xhcip,xhci_command_t * xco)398*993e3fafSRobert Mustacchi xhci_command_submit(xhci_t *xhcip, xhci_command_t *xco)
399*993e3fafSRobert Mustacchi {
400*993e3fafSRobert Mustacchi 	int ret;
401*993e3fafSRobert Mustacchi 	xhci_command_ring_t *xcr = &xhcip->xhci_command;
402*993e3fafSRobert Mustacchi 	xhci_ring_t *xrp = &xcr->xcr_ring;
403*993e3fafSRobert Mustacchi 
404*993e3fafSRobert Mustacchi 	mutex_enter(&xcr->xcr_lock);
405*993e3fafSRobert Mustacchi 
406*993e3fafSRobert Mustacchi 	while (xhci_ring_trb_space(xrp, 1U) == B_FALSE ||
407*993e3fafSRobert Mustacchi 	    xcr->xcr_state >= XHCI_COMMAND_RING_ABORTING) {
408*993e3fafSRobert Mustacchi 		cv_wait(&xcr->xcr_cv, &xcr->xcr_lock);
409*993e3fafSRobert Mustacchi 	}
410*993e3fafSRobert Mustacchi 
411*993e3fafSRobert Mustacchi 	xhci_ring_trb_put(xrp, &xco->xco_req);
412*993e3fafSRobert Mustacchi 	xco->xco_state = XHCI_COMMAND_S_QUEUED;
413*993e3fafSRobert Mustacchi 	list_insert_tail(&xcr->xcr_commands, xco);
414*993e3fafSRobert Mustacchi 
415*993e3fafSRobert Mustacchi 	/*
416*993e3fafSRobert Mustacchi 	 * Now, make sure the ring is synched up before we might ring the door
417*993e3fafSRobert Mustacchi 	 * bell and wake up the processor, if they're not currently doing so.
418*993e3fafSRobert Mustacchi 	 */
419*993e3fafSRobert Mustacchi 	XHCI_DMA_SYNC(xrp->xr_dma, DDI_DMA_SYNC_FORDEV);
420*993e3fafSRobert Mustacchi 	if (xhci_check_dma_handle(xhcip, &xrp->xr_dma) != DDI_FM_OK) {
421*993e3fafSRobert Mustacchi 		mutex_exit(&xcr->xcr_lock);
422*993e3fafSRobert Mustacchi 		xhci_error(xhcip, "encountered fatal FM error syncing command "
423*993e3fafSRobert Mustacchi 		    "ring DMA contents: resetting device");
424*993e3fafSRobert Mustacchi 		xhci_fm_runtime_reset(xhcip);
425*993e3fafSRobert Mustacchi 		return (USB_HC_HARDWARE_ERROR);
426*993e3fafSRobert Mustacchi 	}
427*993e3fafSRobert Mustacchi 
428*993e3fafSRobert Mustacchi 	/*
429*993e3fafSRobert Mustacchi 	 * Always ring the door bell. You never know what state the ring will be
430*993e3fafSRobert Mustacchi 	 * in, but we do know that we won't be waiting for an abort as we're
431*993e3fafSRobert Mustacchi 	 * protecting that state currently with the xcr_lock.
432*993e3fafSRobert Mustacchi 	 */
433*993e3fafSRobert Mustacchi 	xhci_put32(xhcip, XHCI_R_DOOR, XHCI_DOORBELL(0), 0);
434*993e3fafSRobert Mustacchi 	if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
435*993e3fafSRobert Mustacchi 		mutex_exit(&xcr->xcr_lock);
436*993e3fafSRobert Mustacchi 		xhci_error(xhcip, "encountered fatal FM error ringing command "
437*993e3fafSRobert Mustacchi 		    "ring doorbell: resetting device");
438*993e3fafSRobert Mustacchi 		xhci_fm_runtime_reset(xhcip);
439*993e3fafSRobert Mustacchi 		return (USB_HC_HARDWARE_ERROR);
440*993e3fafSRobert Mustacchi 	}
441*993e3fafSRobert Mustacchi 
442*993e3fafSRobert Mustacchi 	/*
443*993e3fafSRobert Mustacchi 	 * If the command ring is currently considered idle, make sure to start
444*993e3fafSRobert Mustacchi 	 * up the timeout.
445*993e3fafSRobert Mustacchi 	 */
446*993e3fafSRobert Mustacchi 	if (xcr->xcr_state == XHCI_COMMAND_RING_IDLE) {
447*993e3fafSRobert Mustacchi 		VERIFY(xcr->xcr_timeout == 0);
448*993e3fafSRobert Mustacchi 
449*993e3fafSRobert Mustacchi 		xhci_command_settimeout(xhcip, xhci_command_wait);
450*993e3fafSRobert Mustacchi 		xcr->xcr_state = XHCI_COMMAND_RING_RUNNING;
451*993e3fafSRobert Mustacchi 	}
452*993e3fafSRobert Mustacchi 
453*993e3fafSRobert Mustacchi 	while (xco->xco_state < XHCI_COMMAND_S_DONE)
454*993e3fafSRobert Mustacchi 		cv_wait(&xco->xco_cv, &xcr->xcr_lock);
455*993e3fafSRobert Mustacchi 
456*993e3fafSRobert Mustacchi 	/*
457*993e3fafSRobert Mustacchi 	 * When we return USB_SUCCESS, the actual error is returned in the
458*993e3fafSRobert Mustacchi 	 * command's structure.
459*993e3fafSRobert Mustacchi 	 */
460*993e3fafSRobert Mustacchi 	if (xco->xco_state == XHCI_COMMAND_S_DONE)
461*993e3fafSRobert Mustacchi 		ret = USB_SUCCESS;
462*993e3fafSRobert Mustacchi 	else
463*993e3fafSRobert Mustacchi 		ret = USB_HC_HARDWARE_ERROR;
464*993e3fafSRobert Mustacchi 	mutex_exit(&xcr->xcr_lock);
465*993e3fafSRobert Mustacchi 
466*993e3fafSRobert Mustacchi 	return (ret);
467*993e3fafSRobert Mustacchi }
468*993e3fafSRobert Mustacchi 
469*993e3fafSRobert Mustacchi int
xhci_command_enable_slot(xhci_t * xhcip,uint8_t * slotp)470*993e3fafSRobert Mustacchi xhci_command_enable_slot(xhci_t *xhcip, uint8_t *slotp)
471*993e3fafSRobert Mustacchi {
472*993e3fafSRobert Mustacchi 	int ret;
473*993e3fafSRobert Mustacchi 	uint8_t slot, code;
474*993e3fafSRobert Mustacchi 	xhci_command_t co;
475*993e3fafSRobert Mustacchi 
476*993e3fafSRobert Mustacchi 	VERIFY(xhcip != NULL);
477*993e3fafSRobert Mustacchi 	VERIFY(slotp != NULL);
478*993e3fafSRobert Mustacchi 
479*993e3fafSRobert Mustacchi 	xhci_command_init(&co);
480*993e3fafSRobert Mustacchi 
481*993e3fafSRobert Mustacchi 	/*
482*993e3fafSRobert Mustacchi 	 * Note, the slot type is supposed to vary depending on the protocol
483*993e3fafSRobert Mustacchi 	 * type. However, XHCI 1.1/7.2.2.1.4 explicitly says that this will
484*993e3fafSRobert Mustacchi 	 * always be set to zero for both USB 2 and USB 3, hence why we hardcode
485*993e3fafSRobert Mustacchi 	 * this to zero and thus only have the command to enable the slot set
486*993e3fafSRobert Mustacchi 	 * below.
487*993e3fafSRobert Mustacchi 	 */
488*993e3fafSRobert Mustacchi 	co.xco_req.trb_flags = LE_32(XHCI_CMD_ENABLE_SLOT) |
489*993e3fafSRobert Mustacchi 	    XHCI_TRB_SET_STYPE(0);
490*993e3fafSRobert Mustacchi 	ret = xhci_command_submit(xhcip, &co);
491*993e3fafSRobert Mustacchi 	if (ret != 0)
492*993e3fafSRobert Mustacchi 		goto done;
493*993e3fafSRobert Mustacchi 
494*993e3fafSRobert Mustacchi 	code = XHCI_TRB_GET_CODE(co.xco_res.trb_status);
495*993e3fafSRobert Mustacchi 	slot = XHCI_TRB_GET_SLOT(co.xco_res.trb_flags);
496*993e3fafSRobert Mustacchi 
497*993e3fafSRobert Mustacchi 	if (code == XHCI_CODE_SUCCESS) {
498*993e3fafSRobert Mustacchi 		*slotp = slot;
499*993e3fafSRobert Mustacchi 		ret = USB_SUCCESS;
500*993e3fafSRobert Mustacchi 	} else if (code == XHCI_CODE_NO_SLOTS) {
501*993e3fafSRobert Mustacchi 		ret = USB_NO_RESOURCES;
502*993e3fafSRobert Mustacchi 	} else if (code == XHCI_CODE_CMD_ABORTED) {
503*993e3fafSRobert Mustacchi 		ret = USB_CR_TIMEOUT;
504*993e3fafSRobert Mustacchi 	} else {
505*993e3fafSRobert Mustacchi 		ret = USB_HC_HARDWARE_ERROR;
506*993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!unexpected error when enabling slot: "
507*993e3fafSRobert Mustacchi 		    "%d", code);
508*993e3fafSRobert Mustacchi 	}
509*993e3fafSRobert Mustacchi 
510*993e3fafSRobert Mustacchi done:
511*993e3fafSRobert Mustacchi 	xhci_command_fini(&co);
512*993e3fafSRobert Mustacchi 	return (ret);
513*993e3fafSRobert Mustacchi }
514*993e3fafSRobert Mustacchi 
515*993e3fafSRobert Mustacchi int
xhci_command_disable_slot(xhci_t * xhcip,uint8_t slot)516*993e3fafSRobert Mustacchi xhci_command_disable_slot(xhci_t *xhcip, uint8_t slot)
517*993e3fafSRobert Mustacchi {
518*993e3fafSRobert Mustacchi 	int ret, code;
519*993e3fafSRobert Mustacchi 	xhci_command_t co;
520*993e3fafSRobert Mustacchi 
521*993e3fafSRobert Mustacchi 	VERIFY(xhcip != NULL);
522*993e3fafSRobert Mustacchi 
523*993e3fafSRobert Mustacchi 	xhci_command_init(&co);
524*993e3fafSRobert Mustacchi 	co.xco_req.trb_flags = LE_32(XHCI_CMD_DISABLE_SLOT |
525*993e3fafSRobert Mustacchi 	    XHCI_TRB_SET_SLOT(slot));
526*993e3fafSRobert Mustacchi 	ret = xhci_command_submit(xhcip, &co);
527*993e3fafSRobert Mustacchi 	if (ret != 0)
528*993e3fafSRobert Mustacchi 		goto done;
529*993e3fafSRobert Mustacchi 
530*993e3fafSRobert Mustacchi 	code = XHCI_TRB_GET_CODE(co.xco_res.trb_status);
531*993e3fafSRobert Mustacchi 	if (code == XHCI_CODE_SUCCESS) {
532*993e3fafSRobert Mustacchi 		ret = USB_SUCCESS;
533*993e3fafSRobert Mustacchi 	} else if (code == XHCI_CODE_CMD_ABORTED) {
534*993e3fafSRobert Mustacchi 		ret = USB_CR_TIMEOUT;
535*993e3fafSRobert Mustacchi 	} else {
536*993e3fafSRobert Mustacchi 		ret = USB_HC_HARDWARE_ERROR;
537*993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!unexpected error when disabling slot: "
538*993e3fafSRobert Mustacchi 		    "%d", code);
539*993e3fafSRobert Mustacchi 	}
540*993e3fafSRobert Mustacchi 
541*993e3fafSRobert Mustacchi done:
542*993e3fafSRobert Mustacchi 	xhci_command_fini(&co);
543*993e3fafSRobert Mustacchi 	return (ret);
544*993e3fafSRobert Mustacchi }
545*993e3fafSRobert Mustacchi 
546*993e3fafSRobert Mustacchi int
xhci_command_set_address(xhci_t * xhcip,xhci_device_t * xd,boolean_t bsr)547*993e3fafSRobert Mustacchi xhci_command_set_address(xhci_t *xhcip, xhci_device_t *xd, boolean_t bsr)
548*993e3fafSRobert Mustacchi {
549*993e3fafSRobert Mustacchi 	int ret, code;
550*993e3fafSRobert Mustacchi 	xhci_command_t co;
551*993e3fafSRobert Mustacchi 
552*993e3fafSRobert Mustacchi 	VERIFY(xhcip != NULL);
553*993e3fafSRobert Mustacchi 	VERIFY(xd != NULL);
554*993e3fafSRobert Mustacchi 
555*993e3fafSRobert Mustacchi 	xhci_command_init(&co);
556*993e3fafSRobert Mustacchi 	co.xco_req.trb_addr = LE_64(xhci_dma_pa(&xd->xd_ictx));
557*993e3fafSRobert Mustacchi 	co.xco_req.trb_status = 0;
558*993e3fafSRobert Mustacchi 	co.xco_req.trb_flags = LE_32(XHCI_CMD_ADDRESS_DEVICE |
559*993e3fafSRobert Mustacchi 	    XHCI_TRB_SET_SLOT(xd->xd_slot));
560*993e3fafSRobert Mustacchi 	if (bsr == B_TRUE)
561*993e3fafSRobert Mustacchi 		co.xco_req.trb_flags |= LE_32(XHCI_TRB_BSR);
562*993e3fafSRobert Mustacchi 
563*993e3fafSRobert Mustacchi 	ret = xhci_command_submit(xhcip, &co);
564*993e3fafSRobert Mustacchi 	if (ret != 0)
565*993e3fafSRobert Mustacchi 		goto done;
566*993e3fafSRobert Mustacchi 
567*993e3fafSRobert Mustacchi 	code = XHCI_TRB_GET_CODE(co.xco_res.trb_status);
568*993e3fafSRobert Mustacchi 	if (code == XHCI_CODE_SUCCESS) {
569*993e3fafSRobert Mustacchi 		ret = USB_SUCCESS;
570*993e3fafSRobert Mustacchi 	} else if (code == XHCI_CODE_CMD_ABORTED) {
571*993e3fafSRobert Mustacchi 		ret = USB_CR_TIMEOUT;
572*993e3fafSRobert Mustacchi 	} else {
573*993e3fafSRobert Mustacchi 		ret = USB_HC_HARDWARE_ERROR;
574*993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!unexpected error when setting address: "
575*993e3fafSRobert Mustacchi 		    "%d", code);
576*993e3fafSRobert Mustacchi 	}
577*993e3fafSRobert Mustacchi done:
578*993e3fafSRobert Mustacchi 	xhci_command_fini(&co);
579*993e3fafSRobert Mustacchi 	return (ret);
580*993e3fafSRobert Mustacchi }
581*993e3fafSRobert Mustacchi 
582*993e3fafSRobert Mustacchi int
xhci_command_configure_endpoint(xhci_t * xhcip,xhci_device_t * xd)583*993e3fafSRobert Mustacchi xhci_command_configure_endpoint(xhci_t *xhcip, xhci_device_t *xd)
584*993e3fafSRobert Mustacchi {
585*993e3fafSRobert Mustacchi 	int ret, code;
586*993e3fafSRobert Mustacchi 	xhci_command_t co;
587*993e3fafSRobert Mustacchi 
588*993e3fafSRobert Mustacchi 	VERIFY(xhcip != NULL);
589*993e3fafSRobert Mustacchi 	VERIFY(xd != NULL);
590*993e3fafSRobert Mustacchi 
591*993e3fafSRobert Mustacchi 	xhci_command_init(&co);
592*993e3fafSRobert Mustacchi 	co.xco_req.trb_addr = LE_64(xhci_dma_pa(&xd->xd_ictx));
593*993e3fafSRobert Mustacchi 	co.xco_req.trb_status = LE_32(0);
594*993e3fafSRobert Mustacchi 	co.xco_req.trb_flags = LE_32(XHCI_CMD_CONFIG_EP |
595*993e3fafSRobert Mustacchi 	    XHCI_TRB_SET_SLOT(xd->xd_slot));
596*993e3fafSRobert Mustacchi 
597*993e3fafSRobert Mustacchi 	ret = xhci_command_submit(xhcip, &co);
598*993e3fafSRobert Mustacchi 	if (ret != 0)
599*993e3fafSRobert Mustacchi 		goto done;
600*993e3fafSRobert Mustacchi 	code = XHCI_TRB_GET_CODE(co.xco_res.trb_status);
601*993e3fafSRobert Mustacchi 	switch (code) {
602*993e3fafSRobert Mustacchi 	case XHCI_CODE_SUCCESS:
603*993e3fafSRobert Mustacchi 		ret = USB_SUCCESS;
604*993e3fafSRobert Mustacchi 		break;
605*993e3fafSRobert Mustacchi 	case XHCI_CODE_CMD_ABORTED:
606*993e3fafSRobert Mustacchi 		ret = USB_CR_TIMEOUT;
607*993e3fafSRobert Mustacchi 		break;
608*993e3fafSRobert Mustacchi 	case XHCI_CODE_SLOT_NOT_ON:
609*993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!failed to configure endpoints for slot %d, "
610*993e3fafSRobert Mustacchi 		    "slot not on, likely driver bug!", xd->xd_slot);
611*993e3fafSRobert Mustacchi 		ret = USB_FAILURE;
612*993e3fafSRobert Mustacchi 		break;
613*993e3fafSRobert Mustacchi 	case XHCI_CODE_BANDWIDTH:
614*993e3fafSRobert Mustacchi 		ret = USB_NO_BANDWIDTH;
615*993e3fafSRobert Mustacchi 		break;
616*993e3fafSRobert Mustacchi 	case XHCI_CODE_RESOURCE:
617*993e3fafSRobert Mustacchi 		ret = USB_NO_RESOURCES;
618*993e3fafSRobert Mustacchi 		break;
619*993e3fafSRobert Mustacchi 	default:
620*993e3fafSRobert Mustacchi 		ret = USB_HC_HARDWARE_ERROR;
621*993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!unexpected error when configuring enpoints: "
622*993e3fafSRobert Mustacchi 		    "%d", code);
623*993e3fafSRobert Mustacchi 		break;
624*993e3fafSRobert Mustacchi 	}
625*993e3fafSRobert Mustacchi done:
626*993e3fafSRobert Mustacchi 	xhci_command_fini(&co);
627*993e3fafSRobert Mustacchi 	return (ret);
628*993e3fafSRobert Mustacchi }
629*993e3fafSRobert Mustacchi 
630*993e3fafSRobert Mustacchi int
xhci_command_evaluate_context(xhci_t * xhcip,xhci_device_t * xd)631*993e3fafSRobert Mustacchi xhci_command_evaluate_context(xhci_t *xhcip, xhci_device_t *xd)
632*993e3fafSRobert Mustacchi {
633*993e3fafSRobert Mustacchi 	int ret, code;
634*993e3fafSRobert Mustacchi 	xhci_command_t co;
635*993e3fafSRobert Mustacchi 
636*993e3fafSRobert Mustacchi 	VERIFY(xhcip != NULL);
637*993e3fafSRobert Mustacchi 	VERIFY(xd != NULL);
638*993e3fafSRobert Mustacchi 
639*993e3fafSRobert Mustacchi 	xhci_command_init(&co);
640*993e3fafSRobert Mustacchi 	co.xco_req.trb_addr = LE_64(xhci_dma_pa(&xd->xd_ictx));
641*993e3fafSRobert Mustacchi 	co.xco_req.trb_status = LE_32(0);
642*993e3fafSRobert Mustacchi 	co.xco_req.trb_flags = LE_32(XHCI_CMD_EVAL_CTX |
643*993e3fafSRobert Mustacchi 	    XHCI_TRB_SET_SLOT(xd->xd_slot));
644*993e3fafSRobert Mustacchi 
645*993e3fafSRobert Mustacchi 	ret = xhci_command_submit(xhcip, &co);
646*993e3fafSRobert Mustacchi 	if (ret != 0)
647*993e3fafSRobert Mustacchi 		goto done;
648*993e3fafSRobert Mustacchi 	code = XHCI_TRB_GET_CODE(co.xco_res.trb_status);
649*993e3fafSRobert Mustacchi 	switch (code) {
650*993e3fafSRobert Mustacchi 	case XHCI_CODE_SUCCESS:
651*993e3fafSRobert Mustacchi 		ret = USB_SUCCESS;
652*993e3fafSRobert Mustacchi 		break;
653*993e3fafSRobert Mustacchi 	case XHCI_CODE_CMD_ABORTED:
654*993e3fafSRobert Mustacchi 		ret = USB_CR_TIMEOUT;
655*993e3fafSRobert Mustacchi 		break;
656*993e3fafSRobert Mustacchi 	case XHCI_CODE_SLOT_NOT_ON:
657*993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!failed to evaluate endpoints for slot %d, "
658*993e3fafSRobert Mustacchi 		    "slot not on, likely driver bug!", xd->xd_slot);
659*993e3fafSRobert Mustacchi 		ret = USB_FAILURE;
660*993e3fafSRobert Mustacchi 		break;
661*993e3fafSRobert Mustacchi 	default:
662*993e3fafSRobert Mustacchi 		ret = USB_HC_HARDWARE_ERROR;
663*993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!unexpected error when evaluating enpoints: "
664*993e3fafSRobert Mustacchi 		    "%d", code);
665*993e3fafSRobert Mustacchi 		break;
666*993e3fafSRobert Mustacchi 	}
667*993e3fafSRobert Mustacchi done:
668*993e3fafSRobert Mustacchi 	xhci_command_fini(&co);
669*993e3fafSRobert Mustacchi 	return (ret);
670*993e3fafSRobert Mustacchi 
671*993e3fafSRobert Mustacchi }
672*993e3fafSRobert Mustacchi 
673*993e3fafSRobert Mustacchi int
xhci_command_reset_endpoint(xhci_t * xhcip,xhci_device_t * xd,xhci_endpoint_t * xep)674*993e3fafSRobert Mustacchi xhci_command_reset_endpoint(xhci_t *xhcip, xhci_device_t *xd,
675*993e3fafSRobert Mustacchi     xhci_endpoint_t *xep)
676*993e3fafSRobert Mustacchi {
677*993e3fafSRobert Mustacchi 	int ret, code;
678*993e3fafSRobert Mustacchi 	xhci_command_t co;
679*993e3fafSRobert Mustacchi 
680*993e3fafSRobert Mustacchi 	VERIFY(xhcip != NULL);
681*993e3fafSRobert Mustacchi 	VERIFY(xd != NULL);
682*993e3fafSRobert Mustacchi 	VERIFY(xep != NULL);
683*993e3fafSRobert Mustacchi 
684*993e3fafSRobert Mustacchi 	xhci_command_init(&co);
685*993e3fafSRobert Mustacchi 
686*993e3fafSRobert Mustacchi 	co.xco_req.trb_addr = LE_64(0);
687*993e3fafSRobert Mustacchi 	co.xco_req.trb_status = LE_32(0);
688*993e3fafSRobert Mustacchi 	co.xco_req.trb_flags = LE_32(XHCI_CMD_RESET_EP |
689*993e3fafSRobert Mustacchi 	    XHCI_TRB_SET_SLOT(xd->xd_slot) |
690*993e3fafSRobert Mustacchi 	    XHCI_TRB_SET_EP(xep->xep_num + 1));
691*993e3fafSRobert Mustacchi 
692*993e3fafSRobert Mustacchi 	ret = xhci_command_submit(xhcip, &co);
693*993e3fafSRobert Mustacchi 	if (ret != 0)
694*993e3fafSRobert Mustacchi 		goto done;
695*993e3fafSRobert Mustacchi 
696*993e3fafSRobert Mustacchi 	code = XHCI_TRB_GET_CODE(co.xco_res.trb_status);
697*993e3fafSRobert Mustacchi 	switch (code) {
698*993e3fafSRobert Mustacchi 	case XHCI_CODE_SUCCESS:
699*993e3fafSRobert Mustacchi 		ret = USB_SUCCESS;
700*993e3fafSRobert Mustacchi 		break;
701*993e3fafSRobert Mustacchi 	case XHCI_CODE_CMD_ABORTED:
702*993e3fafSRobert Mustacchi 		ret = USB_CR_TIMEOUT;
703*993e3fafSRobert Mustacchi 		break;
704*993e3fafSRobert Mustacchi 	case XHCI_CODE_CONTEXT_STATE:
705*993e3fafSRobert Mustacchi 	case XHCI_CODE_SLOT_NOT_ON:
706*993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!xhci reset endpoint command: asked to modify "
707*993e3fafSRobert Mustacchi 		    "endpoint (%u)/slot (%d) in wrong state: %d", xep->xep_num,
708*993e3fafSRobert Mustacchi 		    xd->xd_slot, code);
709*993e3fafSRobert Mustacchi 		if (code == XHCI_CODE_CONTEXT_STATE) {
710*993e3fafSRobert Mustacchi 			xhci_endpoint_context_t *epctx;
711*993e3fafSRobert Mustacchi 
712*993e3fafSRobert Mustacchi 			epctx = xd->xd_endout[xep->xep_num];
713*993e3fafSRobert Mustacchi 			xhci_log(xhcip, "!endpoint is in state %d",
714*993e3fafSRobert Mustacchi 			    XHCI_EPCTX_STATE(epctx->xec_info));
715*993e3fafSRobert Mustacchi 		}
716*993e3fafSRobert Mustacchi 		ret = USB_INVALID_CONTEXT;
717*993e3fafSRobert Mustacchi 		break;
718*993e3fafSRobert Mustacchi 	default:
719*993e3fafSRobert Mustacchi 		ret = USB_HC_HARDWARE_ERROR;
720*993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!unexpected error when resetting enpoint: %d",
721*993e3fafSRobert Mustacchi 		    code);
722*993e3fafSRobert Mustacchi 		break;
723*993e3fafSRobert Mustacchi 	}
724*993e3fafSRobert Mustacchi 
725*993e3fafSRobert Mustacchi done:
726*993e3fafSRobert Mustacchi 	xhci_command_fini(&co);
727*993e3fafSRobert Mustacchi 	return (ret);
728*993e3fafSRobert Mustacchi }
729*993e3fafSRobert Mustacchi 
730*993e3fafSRobert Mustacchi int
xhci_command_set_tr_dequeue(xhci_t * xhcip,xhci_device_t * xd,xhci_endpoint_t * xep)731*993e3fafSRobert Mustacchi xhci_command_set_tr_dequeue(xhci_t *xhcip, xhci_device_t *xd,
732*993e3fafSRobert Mustacchi     xhci_endpoint_t *xep)
733*993e3fafSRobert Mustacchi {
734*993e3fafSRobert Mustacchi 	uint64_t pa;
735*993e3fafSRobert Mustacchi 	int ret, code;
736*993e3fafSRobert Mustacchi 	xhci_command_t co;
737*993e3fafSRobert Mustacchi 	xhci_ring_t *xrp;
738*993e3fafSRobert Mustacchi 
739*993e3fafSRobert Mustacchi 	VERIFY(xhcip != NULL);
740*993e3fafSRobert Mustacchi 	VERIFY(xd != NULL);
741*993e3fafSRobert Mustacchi 	VERIFY(xep != NULL);
742*993e3fafSRobert Mustacchi 
743*993e3fafSRobert Mustacchi 	xhci_command_init(&co);
744*993e3fafSRobert Mustacchi 
745*993e3fafSRobert Mustacchi 	xrp = &xep->xep_ring;
746*993e3fafSRobert Mustacchi 	pa = xhci_dma_pa(&xrp->xr_dma) + sizeof (xhci_trb_t) * xrp->xr_tail;
747*993e3fafSRobert Mustacchi 	pa |= xrp->xr_cycle;
748*993e3fafSRobert Mustacchi 	co.xco_req.trb_addr = LE_64(pa);
749*993e3fafSRobert Mustacchi 	co.xco_req.trb_status = LE_32(0);
750*993e3fafSRobert Mustacchi 	co.xco_req.trb_flags = LE_32(XHCI_CMD_SET_TR_DEQ |
751*993e3fafSRobert Mustacchi 	    XHCI_TRB_SET_SLOT(xd->xd_slot) |
752*993e3fafSRobert Mustacchi 	    XHCI_TRB_SET_EP(xep->xep_num + 1));
753*993e3fafSRobert Mustacchi 
754*993e3fafSRobert Mustacchi 	ret = xhci_command_submit(xhcip, &co);
755*993e3fafSRobert Mustacchi 	if (ret != 0)
756*993e3fafSRobert Mustacchi 		goto done;
757*993e3fafSRobert Mustacchi 
758*993e3fafSRobert Mustacchi 	code = XHCI_TRB_GET_CODE(co.xco_res.trb_status);
759*993e3fafSRobert Mustacchi 	switch (code) {
760*993e3fafSRobert Mustacchi 	case XHCI_CODE_SUCCESS:
761*993e3fafSRobert Mustacchi 		ret = USB_SUCCESS;
762*993e3fafSRobert Mustacchi 		break;
763*993e3fafSRobert Mustacchi 	case XHCI_CODE_CMD_ABORTED:
764*993e3fafSRobert Mustacchi 		ret = USB_CR_TIMEOUT;
765*993e3fafSRobert Mustacchi 		break;
766*993e3fafSRobert Mustacchi 	case XHCI_CODE_CONTEXT_STATE:
767*993e3fafSRobert Mustacchi 	case XHCI_CODE_SLOT_NOT_ON:
768*993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!xhci set tr dequeue command: asked to modify "
769*993e3fafSRobert Mustacchi 		    "endpoint (%u)/slot (%d) in wrong state: %d", xep->xep_num,
770*993e3fafSRobert Mustacchi 		    xd->xd_slot, code);
771*993e3fafSRobert Mustacchi 		if (code == XHCI_CODE_CONTEXT_STATE) {
772*993e3fafSRobert Mustacchi 			xhci_endpoint_context_t *epctx;
773*993e3fafSRobert Mustacchi 
774*993e3fafSRobert Mustacchi 			epctx = xd->xd_endout[xep->xep_num];
775*993e3fafSRobert Mustacchi 			xhci_log(xhcip, "!endpoint is in state %d",
776*993e3fafSRobert Mustacchi 			    XHCI_EPCTX_STATE(epctx->xec_info));
777*993e3fafSRobert Mustacchi 		}
778*993e3fafSRobert Mustacchi 		ret = USB_INVALID_CONTEXT;
779*993e3fafSRobert Mustacchi 		break;
780*993e3fafSRobert Mustacchi 	default:
781*993e3fafSRobert Mustacchi 		ret = USB_HC_HARDWARE_ERROR;
782*993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!unexpected error when resetting enpoint: %d",
783*993e3fafSRobert Mustacchi 		    code);
784*993e3fafSRobert Mustacchi 		break;
785*993e3fafSRobert Mustacchi 	}
786*993e3fafSRobert Mustacchi 
787*993e3fafSRobert Mustacchi done:
788*993e3fafSRobert Mustacchi 	xhci_command_fini(&co);
789*993e3fafSRobert Mustacchi 	return (ret);
790*993e3fafSRobert Mustacchi 
791*993e3fafSRobert Mustacchi }
792*993e3fafSRobert Mustacchi 
793*993e3fafSRobert Mustacchi int
xhci_command_stop_endpoint(xhci_t * xhcip,xhci_device_t * xd,xhci_endpoint_t * xep)794*993e3fafSRobert Mustacchi xhci_command_stop_endpoint(xhci_t *xhcip, xhci_device_t *xd,
795*993e3fafSRobert Mustacchi     xhci_endpoint_t *xep)
796*993e3fafSRobert Mustacchi {
797*993e3fafSRobert Mustacchi 	int ret, code;
798*993e3fafSRobert Mustacchi 	xhci_command_t co;
799*993e3fafSRobert Mustacchi 
800*993e3fafSRobert Mustacchi 	VERIFY(xhcip != NULL);
801*993e3fafSRobert Mustacchi 	VERIFY(xd != NULL);
802*993e3fafSRobert Mustacchi 	VERIFY(xep != NULL);
803*993e3fafSRobert Mustacchi 
804*993e3fafSRobert Mustacchi 	xhci_command_init(&co);
805*993e3fafSRobert Mustacchi 
806*993e3fafSRobert Mustacchi 	co.xco_req.trb_addr = LE_64(0);
807*993e3fafSRobert Mustacchi 	co.xco_req.trb_status = LE_32(0);
808*993e3fafSRobert Mustacchi 	co.xco_req.trb_flags = LE_32(XHCI_CMD_STOP_EP |
809*993e3fafSRobert Mustacchi 	    XHCI_TRB_SET_SLOT(xd->xd_slot) |
810*993e3fafSRobert Mustacchi 	    XHCI_TRB_SET_EP(xep->xep_num + 1));
811*993e3fafSRobert Mustacchi 
812*993e3fafSRobert Mustacchi 	ret = xhci_command_submit(xhcip, &co);
813*993e3fafSRobert Mustacchi 	if (ret != 0)
814*993e3fafSRobert Mustacchi 		goto done;
815*993e3fafSRobert Mustacchi 
816*993e3fafSRobert Mustacchi 	code = XHCI_TRB_GET_CODE(co.xco_res.trb_status);
817*993e3fafSRobert Mustacchi 	switch (code) {
818*993e3fafSRobert Mustacchi 	case XHCI_CODE_SUCCESS:
819*993e3fafSRobert Mustacchi 		ret = USB_SUCCESS;
820*993e3fafSRobert Mustacchi 		break;
821*993e3fafSRobert Mustacchi 	case XHCI_CODE_CMD_ABORTED:
822*993e3fafSRobert Mustacchi 		ret = USB_CR_TIMEOUT;
823*993e3fafSRobert Mustacchi 		break;
824*993e3fafSRobert Mustacchi 	case XHCI_CODE_CONTEXT_STATE:
825*993e3fafSRobert Mustacchi 	case XHCI_CODE_SLOT_NOT_ON:
826*993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!xhci stop endpoint command (%d)/slot "
827*993e3fafSRobert Mustacchi 		    "(%u) in wrong state: %d", xep->xep_num, xd->xd_slot,
828*993e3fafSRobert Mustacchi 		    code);
829*993e3fafSRobert Mustacchi 		if (code == XHCI_CODE_CONTEXT_STATE) {
830*993e3fafSRobert Mustacchi 			xhci_endpoint_context_t *epctx;
831*993e3fafSRobert Mustacchi 
832*993e3fafSRobert Mustacchi 			epctx = xd->xd_endout[xep->xep_num];
833*993e3fafSRobert Mustacchi 			xhci_log(xhcip, "!endpoint is in state %d",
834*993e3fafSRobert Mustacchi 			    XHCI_EPCTX_STATE(epctx->xec_info));
835*993e3fafSRobert Mustacchi 		}
836*993e3fafSRobert Mustacchi 		ret = USB_INVALID_CONTEXT;
837*993e3fafSRobert Mustacchi 		break;
838*993e3fafSRobert Mustacchi 	default:
839*993e3fafSRobert Mustacchi 		ret = USB_HC_HARDWARE_ERROR;
840*993e3fafSRobert Mustacchi 		xhci_log(xhcip, "!unexpected error when resetting enpoint: %d",
841*993e3fafSRobert Mustacchi 		    code);
842*993e3fafSRobert Mustacchi 		break;
843*993e3fafSRobert Mustacchi 	}
844*993e3fafSRobert Mustacchi 
845*993e3fafSRobert Mustacchi done:
846*993e3fafSRobert Mustacchi 	xhci_command_fini(&co);
847*993e3fafSRobert Mustacchi 	return (ret);
848*993e3fafSRobert Mustacchi }
849