xref: /illumos-gate/usr/src/uts/common/io/usb/hcd/xhci/xhci_polled.c (revision ec82ef794c304d675af6962e1428b3b12ca2be8b)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright (c) 2018, Joyent, Inc.
14  *
15  * Copyright (c) 2019 by Western Digital Corporation
16  */
17 
18 /*
19  * This next series of routines is used for USB console polled I/O.
20  */
21 
22 #include <sys/usb/hcd/xhci/xhci.h>
23 
24 #include <sys/cmn_err.h>
25 
26 static void xhci_polled_panic(xhci_polled_t *xhci_polledp, const char *format,
27     ...) __KVPRINTFLIKE(2) __NORETURN;
28 
29 static void
xhci_polled_panic(xhci_polled_t * xhci_polledp,const char * format,...)30 xhci_polled_panic(xhci_polled_t *xhci_polledp, const char *format, ...)
31 {
32 	va_list ap;
33 
34 	va_start(ap, format);
35 	vdev_err(xhci_polledp->xhci_polled_xhci->xhci_dip, CE_PANIC, format,
36 	    ap);
37 
38 	/*
39 	 * We will not reach this call. However the compiler doesn't know
40 	 * that vdev_err(..., CE_PANIC, ...) will not return. So this call
41 	 * convinces it that this function does indeed never return.
42 	 */
43 	panic(__func__);
44 }
45 
46 static void
xhci_polled_set_persistent_error(xhci_polled_t * xhci_polledp,int error)47 xhci_polled_set_persistent_error(xhci_polled_t *xhci_polledp, int error)
48 {
49 	if (error != USB_SUCCESS &&
50 	    xhci_polledp->xhci_polled_persistent_error == USB_SUCCESS) {
51 		xhci_polledp->xhci_polled_persistent_error = error;
52 	}
53 }
54 
55 /*
56  * xhci_polled_init:
57  *
58  * Initialize generic information that is needed to provide USB/POLLED
59  * support.
60  */
61 static int
xhci_polled_init(usba_pipe_handle_data_t * input_pipe_handle,xhci_t * xhcip,usb_console_info_impl_t * console_info)62 xhci_polled_init(usba_pipe_handle_data_t *input_pipe_handle, xhci_t *xhcip,
63     usb_console_info_impl_t *console_info)
64 {
65 	xhci_pipe_t *xp;
66 	xhci_endpoint_t *xep;
67 	xhci_polled_t *xhci_polledp;
68 
69 	ASSERT(mutex_owned(&xhcip->xhci_lock));
70 
71 	/*
72 	 * We have already initialized this structure. If the structure
73 	 * has already been initialized, then we don't need to redo it.
74 	 */
75 	if (console_info->uci_private != NULL)
76 		return (USB_SUCCESS);
77 
78 	xp = (xhci_pipe_t *)input_pipe_handle->p_hcd_private;
79 	if (xp == NULL)
80 		return (USB_FAILURE);
81 
82 	/*
83 	 * We only support interrupt (keyboards) and not bulk (serial)
84 	 * endpoints at the moment.
85 	 */
86 	xep = xp->xp_ep;
87 	if (xep->xep_type != USB_EP_ATTR_INTR)
88 		return (USB_NOT_SUPPORTED);
89 
90 	/* Allocate and initialize a state structure */
91 	xhci_polledp = kmem_zalloc(sizeof (xhci_polled_t), KM_SLEEP);
92 
93 	xhci_polledp->xhci_polled_xhci = xhcip;
94 	xhci_polledp->xhci_polled_input_pipe_handle = input_pipe_handle;
95 	xhci_polledp->xhci_polled_endpoint = xep;
96 
97 	console_info->uci_private = (usb_console_info_private_t)xhci_polledp;
98 	return (USB_SUCCESS);
99 }
100 
101 static xhci_endpoint_t *
xhci_polled_get_endpoint(xhci_t * xhcip,xhci_trb_t * trb)102 xhci_polled_get_endpoint(xhci_t *xhcip, xhci_trb_t *trb)
103 {
104 	int slot, endpoint;
105 	xhci_device_t *xd;
106 
107 	endpoint = XHCI_TRB_GET_EP(LE_32(trb->trb_flags));
108 	slot = XHCI_TRB_GET_SLOT(LE_32(trb->trb_flags));
109 
110 	xd = xhci_device_lookup_by_slot(xhcip, slot);
111 	if (xd == NULL)
112 		return (NULL);
113 
114 	/*
115 	 * Endpoint IDs are indexed based on their Device Context Index, which
116 	 * means that we need to subtract one to get the actual ID that we use.
117 	 */
118 	return (xd->xd_endpoints[endpoint - 1]);
119 }
120 
121 static int
xhci_polled_endpoint_transfer(xhci_polled_t * xhci_polledp,xhci_endpoint_t * xep,xhci_trb_t * trb,uint_t * num_characters)122 xhci_polled_endpoint_transfer(xhci_polled_t *xhci_polledp, xhci_endpoint_t *xep,
123     xhci_trb_t *trb, uint_t *num_characters)
124 {
125 	xhci_t *xhcip = xhci_polledp->xhci_polled_xhci;
126 	xhci_device_t *xd = xep->xep_xd;
127 	uint_t off;
128 	int code;
129 	xhci_transfer_t *xt;
130 	size_t len;
131 	xhci_transfer_t *rem;
132 	int sched_err;
133 
134 	/*
135 	 * This TRB should be part of a transfer. If it's not, then we ignore
136 	 * it. We also check whether or not it's for the first transfer. Because
137 	 * the rings are serviced in order, it should be.
138 	 */
139 	if ((xt = xhci_endpoint_determine_transfer(xhcip, xep, trb, &off)) ==
140 	    NULL) {
141 		return (USB_FAILURE);
142 	}
143 
144 	code = XHCI_TRB_GET_CODE(LE_32(trb->trb_status));
145 	if (code != XHCI_CODE_SUCCESS)
146 		return (USB_FAILURE);
147 
148 	ASSERT(xep->xep_type == USB_EP_ATTR_INTR);
149 
150 	if (!xt->xt_data_tohost)
151 		return (USB_SUCCESS);
152 
153 	if (xt->xt_short != 0)
154 		return (USB_CR_DATA_UNDERRUN);
155 
156 	if (xhci_transfer_sync(xhcip, xt, DDI_DMA_SYNC_FORCPU) != DDI_FM_OK) {
157 		xhci_polled_panic(xhci_polledp, "failed to process normal "
158 		    "transfer callback for endpoint %u of device on slot %d "
159 		    "and port %d: encountered fatal FM error synchronizing "
160 		    "DMA memory", xhcip, xep->xep_num, xd->xd_slot,
161 		    xd->xd_port);
162 	}
163 
164 	len = xt->xt_buffer.xdb_len;
165 	if (len > sizeof (xhci_polledp->xhci_polled_buf))
166 		len = sizeof (xhci_polledp->xhci_polled_buf);
167 	xhci_transfer_copy(xt, xhci_polledp->xhci_polled_buf, len, B_TRUE);
168 
169 	*num_characters = (uint_t)len;
170 
171 	VERIFY(xhci_ring_trb_consumed(&xep->xep_ring, LE_64(trb->trb_addr)));
172 	rem = list_remove_head(&xep->xep_transfers);
173 	VERIFY3P(rem, ==, xt);
174 
175 	xt->xt_short = 0;
176 	xt->xt_cr = USB_CR_OK;
177 
178 	/*
179 	 * The call below can fail but there isn't much we can do other
180 	 * than panicing the machine. But that might only re-enter the
181 	 * kernel debugger with now broken keyboard input. So we are
182 	 * simply returning the keyboard input that we have succesfully
183 	 * received because it might enable some progress.
184 	 */
185 	sched_err = xhci_endpoint_schedule(xhcip, xd, xep, xt, B_TRUE);
186 	xhci_polled_set_persistent_error(xhci_polledp, sched_err);
187 
188 	return (USB_SUCCESS);
189 }
190 
191 /*
192  * Process the event ring
193  */
194 static int
xhci_polled_event_process(xhci_polled_t * xhci_polledp,uint_t * num_characters)195 xhci_polled_event_process(xhci_polled_t *xhci_polledp, uint_t *num_characters)
196 {
197 	xhci_t *xhcip = xhci_polledp->xhci_polled_xhci;
198 	xhci_ring_t *xrp = &xhcip->xhci_event.xev_ring;
199 	uint_t nevents;
200 	int ret;
201 	uint64_t addr;
202 
203 	if (xhcip->xhci_state & XHCI_S_ERROR)
204 		return (USB_HC_HARDWARE_ERROR);
205 
206 	VERIFY(xhcip->xhci_event.xev_segs != NULL);
207 
208 	XHCI_DMA_SYNC(xrp->xr_dma, DDI_DMA_SYNC_FORKERNEL);
209 
210 	/* Look for any transfer events */
211 	ret = USB_SUCCESS;
212 	for (nevents = 0; nevents < xrp->xr_ntrb; nevents++) {
213 		xhci_trb_t *trb;
214 		xhci_endpoint_t *xep;
215 		uint32_t type;
216 
217 		if ((trb = xhci_ring_event_advance(xrp)) == NULL)
218 			break;
219 
220 		xep = xhci_polled_get_endpoint(xhcip, trb);
221 		if (xep == NULL) {
222 			xhci_polled_set_persistent_error(xhci_polledp,
223 			    USB_HC_HARDWARE_ERROR);
224 			return (USB_HC_HARDWARE_ERROR);
225 		}
226 		type = LE_32(trb->trb_flags) & XHCI_TRB_TYPE_MASK;
227 
228 		if (xep != xhci_polledp->xhci_polled_endpoint ||
229 		    type != XHCI_EVT_XFER) {
230 			/*
231 			 * We got an event which we are not prepared to
232 			 * handle here. Call into the normal driver code
233 			 * which should return here after dispatching a task.
234 			 */
235 			boolean_t processed;
236 
237 			mutex_exit(&xhcip->xhci_lock);
238 			processed = xhci_event_process_trb(xhcip, trb);
239 			mutex_enter(&xhcip->xhci_lock);
240 
241 			if (!processed && xhcip->xhci_state & XHCI_S_ERROR)
242 				return (USB_HC_HARDWARE_ERROR);
243 			continue;
244 		}
245 
246 		ret = xhci_polled_endpoint_transfer(xhci_polledp, xep, trb,
247 		    num_characters);
248 		if (ret != USB_SUCCESS) {
249 			xhci_polled_set_persistent_error(xhci_polledp, ret);
250 			break;
251 		}
252 	}
253 
254 	addr = xhci_dma_pa(&xrp->xr_dma) + sizeof (xhci_trb_t) * xrp->xr_tail;
255 	addr |= XHCI_ERDP_BUSY;
256 	xhci_put64(xhcip, XHCI_R_RUN, XHCI_ERDP(0), addr);
257 
258 	return (ret);
259 }
260 
261 int
xhci_hcdi_console_input_init(usba_pipe_handle_data_t * pipe_handle,uchar_t ** polled_buf,usb_console_info_impl_t * console_input_info)262 xhci_hcdi_console_input_init(usba_pipe_handle_data_t *pipe_handle,
263     uchar_t **polled_buf, usb_console_info_impl_t *console_input_info)
264 {
265 	xhci_t *xhcip;
266 	int ret;
267 	xhci_polled_t *xhci_polledp;
268 
269 	xhcip = xhci_hcdi_get_xhcip_from_dev(pipe_handle->p_usba_device);
270 
271 	mutex_enter(&xhcip->xhci_lock);
272 
273 	ret = xhci_polled_init(pipe_handle, xhcip, console_input_info);
274 	if (ret != USB_SUCCESS) {
275 		mutex_exit(&xhcip->xhci_lock);
276 		return (ret);
277 	}
278 
279 	xhci_polledp = (xhci_polled_t *)console_input_info->uci_private;
280 	*polled_buf = xhci_polledp->xhci_polled_buf;
281 
282 	mutex_exit(&xhcip->xhci_lock);
283 
284 	return (ret);
285 }
286 
287 int
xhci_hcdi_console_input_fini(usb_console_info_impl_t * console_input_info)288 xhci_hcdi_console_input_fini(usb_console_info_impl_t *console_input_info)
289 {
290 	xhci_polled_t *xhci_polledp;
291 
292 	xhci_polledp = (xhci_polled_t *)console_input_info->uci_private;
293 	if (xhci_polledp != NULL) {
294 		kmem_free(xhci_polledp, sizeof (xhci_polled_t));
295 		console_input_info->uci_private = NULL;
296 	}
297 
298 	return (USB_SUCCESS);
299 }
300 
301 int
xhci_hcdi_console_input_enter(usb_console_info_impl_t * console_input_info)302 xhci_hcdi_console_input_enter(usb_console_info_impl_t *console_input_info)
303 {
304 	xhci_polled_t *xhci_polledp;
305 	xhci_t *xhcip;
306 	xhci_endpoint_t *xep;
307 	uint32_t status;
308 
309 	xhci_polledp = (xhci_polled_t *)console_input_info->uci_private;
310 	xhcip = xhci_polledp->xhci_polled_xhci;
311 	xep = xhci_polledp->xhci_polled_endpoint;
312 
313 	if (mutex_tryenter(&xhcip->xhci_lock) == 0)
314 		return (USB_BUSY);
315 
316 	/*
317 	 * If the controller is already switched over, just return
318 	 */
319 	if (xhci_polledp->xhci_polled_entry > 0) {
320 		xhci_polledp->xhci_polled_entry++;
321 		ASSERT(xep->xep_state & XHCI_ENDPOINT_POLLED);
322 		mutex_exit(&xhcip->xhci_lock);
323 		return (USB_SUCCESS);
324 	}
325 
326 	/*
327 	 * Check to see if we have a fatal bit set. If this is the case the
328 	 * host controller is not working properly and we don't want to
329 	 * enter the kernel debugger and leave the system unresponsive.
330 	 */
331 	status = xhci_get32(xhcip, XHCI_R_OPER, XHCI_USBSTS);
332 	if ((status & (XHCI_STS_HSE | XHCI_STS_SRE | XHCI_STS_HCE)) != 0) {
333 		mutex_exit(&xhcip->xhci_lock);
334 		xhci_polled_set_persistent_error(xhci_polledp,
335 		    USB_HC_HARDWARE_ERROR);
336 		return (USB_HC_HARDWARE_ERROR);
337 	}
338 
339 	/*
340 	 * We only support interrupt (keyboards) and not bulk (serial)
341 	 * endpoints at the moment.
342 	 */
343 	if (xhci_polledp->xhci_polled_endpoint->xep_type != USB_EP_ATTR_INTR) {
344 		mutex_exit(&xhcip->xhci_lock);
345 		return (USB_NOT_SUPPORTED);
346 	}
347 
348 	xhci_polledp->xhci_polled_persistent_error = USB_SUCCESS;
349 	xhci_polledp->xhci_polled_entry++;
350 
351 	ASSERT(!(xep->xep_state & XHCI_ENDPOINT_POLLED));
352 	xep->xep_state |= XHCI_ENDPOINT_POLLED;
353 
354 	mutex_exit(&xhcip->xhci_lock);
355 	return (USB_SUCCESS);
356 }
357 
358 int
xhci_hcdi_console_read(usb_console_info_impl_t * console_input_info,uint_t * num_characters)359 xhci_hcdi_console_read(usb_console_info_impl_t *console_input_info,
360     uint_t *num_characters)
361 {
362 	xhci_polled_t *xhci_polledp;
363 	xhci_t *xhcip;
364 	uint32_t status, iman;
365 	int ret;
366 
367 	*num_characters = 0;
368 
369 	xhci_polledp = (xhci_polled_t *)console_input_info->uci_private;
370 	VERIFY(xhci_polledp != NULL);
371 
372 	if (xhci_polledp->xhci_polled_persistent_error != USB_SUCCESS)
373 		return (xhci_polledp->xhci_polled_persistent_error);
374 
375 	xhcip = xhci_polledp->xhci_polled_xhci;
376 	if (mutex_tryenter(&xhcip->xhci_lock) == 0)
377 		return (USB_BUSY);
378 
379 	/*
380 	 * Before we read the interrupt management register, check to see if we
381 	 * have a fatal bit set. As we cannot reset the host controller while
382 	 * the kernel debugger is running we give up.
383 	 */
384 	status = xhci_get32(xhcip, XHCI_R_OPER, XHCI_USBSTS);
385 	if ((status & (XHCI_STS_HSE | XHCI_STS_SRE | XHCI_STS_HCE)) != 0) {
386 		xhci_polled_panic(xhci_polledp, "found fatal error bit in "
387 		    "status register, value: 0x%x", xhcip, status);
388 	}
389 
390 	iman = xhci_get32(xhcip, XHCI_R_RUN, XHCI_IMAN(0));
391 
392 	ret = xhci_polled_event_process(xhci_polledp, num_characters);
393 
394 	if (ret == USB_SUCCESS)
395 		xhci_put32(xhcip, XHCI_R_RUN, XHCI_IMAN(0), iman);
396 
397 	mutex_exit(&xhcip->xhci_lock);
398 	return (ret);
399 }
400 
401 int
xhci_hcdi_console_input_exit(usb_console_info_impl_t * console_input_info)402 xhci_hcdi_console_input_exit(usb_console_info_impl_t *console_input_info)
403 {
404 	xhci_polled_t *xhci_polledp;
405 	xhci_t *xhcip;
406 	xhci_endpoint_t *xep;
407 
408 	xhci_polledp = (xhci_polled_t *)console_input_info->uci_private;
409 	VERIFY(xhci_polledp != NULL);
410 
411 	xhcip = xhci_polledp->xhci_polled_xhci;
412 	mutex_enter(&xhcip->xhci_lock);
413 
414 	xep = xhci_polledp->xhci_polled_endpoint;
415 	ASSERT(xep->xep_state & XHCI_ENDPOINT_POLLED);
416 
417 	VERIFY(xhci_polledp->xhci_polled_entry > 0);
418 	xhci_polledp->xhci_polled_entry--;
419 	if (xhci_polledp->xhci_polled_entry > 0) {
420 		mutex_exit(&xhcip->xhci_lock);
421 		return (USB_SUCCESS);
422 	}
423 
424 	xep->xep_state &= ~XHCI_ENDPOINT_POLLED;
425 
426 	/*
427 	 * Initiate a reset of the host controller if we encountered problems
428 	 * or ignored events while in polled mode. The reset will not be
429 	 * performed in this context and instead be scheduled to a
430 	 * task queue. It will therefore only happen once the kernel is
431 	 * fully up and running again which should be perfectly safe.
432 	 */
433 	if (xhci_polledp->xhci_polled_persistent_error != USB_SUCCESS) {
434 		xhci_fm_runtime_reset(xhcip);
435 	}
436 
437 	mutex_exit(&xhcip->xhci_lock);
438 	return (USB_SUCCESS);
439 }
440 
441 int
xhci_hcdi_console_output_init(usba_pipe_handle_data_t * pipe_handle,usb_console_info_impl_t * console_output_info)442 xhci_hcdi_console_output_init(usba_pipe_handle_data_t *pipe_handle,
443     usb_console_info_impl_t *console_output_info)
444 {
445 	return (USB_NOT_SUPPORTED);
446 }
447 
448 int
xhci_hcdi_console_output_fini(usb_console_info_impl_t * console_output_info)449 xhci_hcdi_console_output_fini(usb_console_info_impl_t *console_output_info)
450 {
451 	return (USB_NOT_SUPPORTED);
452 }
453 
454 int
xhci_hcdi_console_output_enter(usb_console_info_impl_t * console_output_info)455 xhci_hcdi_console_output_enter(usb_console_info_impl_t *console_output_info)
456 {
457 	return (USB_NOT_SUPPORTED);
458 }
459 
460 int
xhci_hcdi_console_write(usb_console_info_impl_t * console_output_info,uchar_t * buf,uint_t num_characters,uint_t * num_characters_written)461 xhci_hcdi_console_write(usb_console_info_impl_t	*console_output_info,
462     uchar_t *buf, uint_t num_characters, uint_t *num_characters_written)
463 {
464 	return (USB_NOT_SUPPORTED);
465 }
466 
467 int
xhci_hcdi_console_output_exit(usb_console_info_impl_t * console_output_info)468 xhci_hcdi_console_output_exit(usb_console_info_impl_t *console_output_info)
469 {
470 	return (USB_NOT_SUPPORTED);
471 }
472