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