1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * USBA: Solaris USB Architecture support
28 *
29 * hcdi.c contains the code for client driver callbacks. A host controller
30 * driver registers/unregisters with usba through usba_hcdi_register/unregister.
31 *
32 * When the transfer has finished, the host controller driver will call into
33 * usba with the result. The call is usba_hcdi_cb().
34 *
35 * The callback queue is maintained in FIFO order. usba_hcdi_cb
36 * adds to the queue, and hcdi_cb_thread takes the callbacks off the queue
37 * and executes them.
38 */
39 #define USBA_FRAMEWORK
40 #include <sys/usb/usba/usba_impl.h>
41 #include <sys/usb/usba/hcdi_impl.h>
42 #include <sys/kstat.h>
43 #include <sys/ddi_impldefs.h>
44
45 /* function prototypes, XXXX use hcdi_ prefix? */
46 static void usba_hcdi_create_stats(usba_hcdi_t *, int);
47 static void usba_hcdi_update_error_stats(usba_hcdi_t *, usb_cr_t);
48 static void usba_hcdi_destroy_stats(usba_hcdi_t *);
49
50 /* internal functions */
51 static uint_t hcdi_soft_intr(caddr_t arg1, caddr_t arg2);
52
53 static void hcdi_cb_thread(void *);
54 static void hcdi_shared_cb_thread(void *);
55 static void hcdi_do_cb(usba_pipe_handle_data_t *, usba_req_wrapper_t *,
56 usba_hcdi_t *);
57 static void hcdi_autoclearing(usba_req_wrapper_t *);
58
59 /* private function from USBAI */
60 void usba_pipe_clear(usb_pipe_handle_t);
61
62 /* for debug messages */
63 uint_t hcdi_errmask = (uint_t)DPRINT_MASK_ALL;
64 uint_t hcdi_errlevel = USB_LOG_L4;
65 uint_t hcdi_instance_debug = (uint_t)-1;
66
67 void
usba_hcdi_initialization()68 usba_hcdi_initialization()
69 {
70 }
71
72
73 void
usba_hcdi_destroy()74 usba_hcdi_destroy()
75 {
76 }
77
78
79 /*
80 * store hcdi structure in the dip
81 */
82 void
usba_hcdi_set_hcdi(dev_info_t * dip,usba_hcdi_t * hcdi)83 usba_hcdi_set_hcdi(dev_info_t *dip, usba_hcdi_t *hcdi)
84 {
85 ddi_set_driver_private(dip, hcdi);
86 }
87
88
89 /*
90 * retrieve hcdi structure from the dip
91 */
92 usba_hcdi_t *
usba_hcdi_get_hcdi(dev_info_t * dip)93 usba_hcdi_get_hcdi(dev_info_t *dip)
94 {
95 return (ddi_get_driver_private(dip));
96 }
97
98 /*
99 * Called by an HCD to attach an instance of the driver
100 * make this instance known to USBA
101 * the HCD should initialize usba_hcdi structure prior
102 * to calling this interface
103 */
104 int
usba_hcdi_register(usba_hcdi_register_args_t * args,uint_t flags)105 usba_hcdi_register(usba_hcdi_register_args_t *args, uint_t flags)
106 {
107 char *datap;
108 uint_t soft_prip;
109 usba_hcdi_t *hcdi = kmem_zalloc(sizeof (usba_hcdi_t), KM_SLEEP);
110
111 if (args->usba_hcdi_register_version != HCDI_REGISTER_VERS_0) {
112 kmem_free(hcdi, sizeof (usba_hcdi_t));
113
114 return (USB_FAILURE);
115 }
116
117 hcdi->hcdi_dip = args->usba_hcdi_register_dip;
118
119 /*
120 * Create a log_handle
121 */
122 hcdi->hcdi_log_handle = usb_alloc_log_hdl(hcdi->hcdi_dip, NULL,
123 &hcdi_errlevel, &hcdi_errmask, &hcdi_instance_debug,
124 0);
125
126 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
127 "usba_hcdi_register: %s", ddi_node_name(hcdi->hcdi_dip));
128
129 /*
130 * Initialize the mutex. Use the iblock cookie passed in
131 * by the host controller driver.
132 */
133 mutex_init(&hcdi->hcdi_mutex, NULL, MUTEX_DRIVER,
134 args->usba_hcdi_register_iblock_cookie);
135
136 /* add soft interrupt */
137 if (ddi_intr_add_softint(hcdi->hcdi_dip, &hcdi->hcdi_softint_hdl,
138 DDI_INTR_SOFTPRI_MAX, hcdi_soft_intr, (caddr_t)hcdi) !=
139 DDI_SUCCESS) {
140 USB_DPRINTF_L2(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
141 "usba_hcd_register: add soft interrupt failed");
142 mutex_destroy(&hcdi->hcdi_mutex);
143 usb_free_log_hdl(hcdi->hcdi_log_handle);
144 kmem_free(hcdi, sizeof (usba_hcdi_t));
145
146 return (USB_FAILURE);
147 }
148
149 if (ddi_intr_get_softint_pri(hcdi->hcdi_softint_hdl, &soft_prip) !=
150 DDI_SUCCESS) {
151 USB_DPRINTF_L2(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
152 "usba_hcd_register: get soft interrupt priority failed");
153 (void) ddi_intr_remove_softint(hcdi->hcdi_softint_hdl);
154 mutex_destroy(&hcdi->hcdi_mutex);
155 usb_free_log_hdl(hcdi->hcdi_log_handle);
156 kmem_free(hcdi, sizeof (usba_hcdi_t));
157
158 return (USB_FAILURE);
159 }
160
161 /*
162 * Priority and iblock_cookie are one and the same
163 * (However, retaining hcdi_soft_iblock_cookie for now
164 * assigning it w/ priority. In future all iblock_cookie
165 * could just go)
166 */
167 hcdi->hcdi_soft_iblock_cookie =
168 (ddi_iblock_cookie_t)(uintptr_t)soft_prip;
169
170 usba_init_list(&hcdi->hcdi_cb_queue, NULL, NULL);
171
172 hcdi->hcdi_dma_attr = args->usba_hcdi_register_dma_attr;
173 hcdi->hcdi_flags = flags;
174 hcdi->hcdi_ops = args->usba_hcdi_register_ops;
175 hcdi->hcdi_iblock_cookie = args->usba_hcdi_register_iblock_cookie;
176 usba_hcdi_create_stats(hcdi, ddi_get_instance(hcdi->hcdi_dip));
177
178 hcdi->hcdi_min_xfer = hcdi->hcdi_dma_attr->dma_attr_minxfer;
179 hcdi->hcdi_min_burst_size =
180 (1<<(ddi_ffs(hcdi->hcdi_dma_attr->dma_attr_burstsizes)-1));
181 hcdi->hcdi_max_burst_size =
182 (1<<(ddi_fls(hcdi->hcdi_dma_attr->dma_attr_burstsizes)-1));
183
184 usba_hcdi_set_hcdi(hcdi->hcdi_dip, hcdi);
185
186 if (ddi_prop_lookup_string(DDI_DEV_T_ANY,
187 hcdi->hcdi_dip,
188 DDI_PROP_DONTPASS, "ugen-default-binding", &datap) ==
189 DDI_PROP_SUCCESS) {
190 if (strcmp(datap, "device") == 0) {
191 hcdi->hcdi_ugen_default_binding =
192 USBA_UGEN_DEVICE_BINDING;
193 } else if (strcmp(datap, "interface") == 0) {
194 hcdi->hcdi_ugen_default_binding =
195 USBA_UGEN_INTERFACE_BINDING;
196 } else if (strcmp(datap, "interface-association") == 0) {
197 hcdi->hcdi_ugen_default_binding =
198 USBA_UGEN_INTERFACE_ASSOCIATION_BINDING;
199 } else {
200 USB_DPRINTF_L2(DPRINT_MASK_HCDI,
201 hcdi->hcdi_log_handle,
202 "illegal value (%s) for "
203 "ugen_default_binding property",
204 datap);
205 }
206 ddi_prop_free(datap);
207 }
208
209 return (USB_SUCCESS);
210 }
211
212
213 /*
214 * Called by an HCD to detach an instance of the driver
215 */
216 /*ARGSUSED*/
217 void
usba_hcdi_unregister(dev_info_t * dip)218 usba_hcdi_unregister(dev_info_t *dip)
219 {
220 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
221
222 if (hcdi) {
223 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
224 "usba_hcdi_unregister: %s", ddi_node_name(dip));
225
226 usba_hcdi_set_hcdi(dip, NULL);
227
228 mutex_destroy(&hcdi->hcdi_mutex);
229 usba_hcdi_destroy_stats(hcdi);
230 usb_free_log_hdl(hcdi->hcdi_log_handle);
231
232 /* Destroy the soft interrupt */
233 (void) ddi_intr_remove_softint(hcdi->hcdi_softint_hdl);
234 kmem_free(hcdi, sizeof (usba_hcdi_t));
235 }
236 }
237
238
239 /*
240 * alloc usba_hcdi_ops structure
241 * called from the HCD attach routine
242 */
243 usba_hcdi_ops_t *
usba_alloc_hcdi_ops()244 usba_alloc_hcdi_ops()
245 {
246 usba_hcdi_ops_t *usba_hcdi_ops;
247
248 usba_hcdi_ops = kmem_zalloc(sizeof (usba_hcdi_ops_t), KM_SLEEP);
249
250 return (usba_hcdi_ops);
251 }
252
253
254 /*
255 * dealloc usba_hcdi_ops structure
256 */
257 void
usba_free_hcdi_ops(usba_hcdi_ops_t * hcdi_ops)258 usba_free_hcdi_ops(usba_hcdi_ops_t *hcdi_ops)
259 {
260 if (hcdi_ops) {
261 kmem_free(hcdi_ops, sizeof (usba_hcdi_ops_t));
262 }
263 }
264
265
266 /*
267 * Allocate the hotplug kstats structure
268 */
269 void
usba_hcdi_create_stats(usba_hcdi_t * hcdi,int instance)270 usba_hcdi_create_stats(usba_hcdi_t *hcdi, int instance)
271 {
272 char kstatname[KSTAT_STRLEN];
273 const char *dname = ddi_driver_name(hcdi->hcdi_dip);
274 hcdi_hotplug_stats_t *hsp;
275 hcdi_error_stats_t *esp;
276
277 if (HCDI_HOTPLUG_STATS(hcdi) == NULL) {
278 (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,hotplug",
279 dname, instance);
280 HCDI_HOTPLUG_STATS(hcdi) = kstat_create("usba", instance,
281 kstatname, "usb_hotplug", KSTAT_TYPE_NAMED,
282 sizeof (hcdi_hotplug_stats_t) / sizeof (kstat_named_t),
283 KSTAT_FLAG_PERSISTENT);
284
285 if (HCDI_HOTPLUG_STATS(hcdi) == NULL) {
286
287 return;
288 }
289
290 hsp = HCDI_HOTPLUG_STATS_DATA(hcdi);
291 kstat_named_init(&hsp->hcdi_hotplug_total_success,
292 "Total Hotplug Successes", KSTAT_DATA_UINT64);
293 kstat_named_init(&hsp->hcdi_hotplug_success,
294 "Hotplug Successes", KSTAT_DATA_UINT64);
295 kstat_named_init(&hsp->hcdi_hotplug_total_failure,
296 "Hotplug Total Failures", KSTAT_DATA_UINT64);
297 kstat_named_init(&hsp->hcdi_hotplug_failure,
298 "Hotplug Failures", KSTAT_DATA_UINT64);
299 kstat_named_init(&hsp->hcdi_device_count,
300 "Device Count", KSTAT_DATA_UINT64);
301
302 HCDI_HOTPLUG_STATS(hcdi)->ks_private = hcdi;
303 HCDI_HOTPLUG_STATS(hcdi)->ks_update = nulldev;
304 kstat_install(HCDI_HOTPLUG_STATS(hcdi));
305 }
306
307 if (HCDI_ERROR_STATS(hcdi) == NULL) {
308 (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,error",
309 dname, instance);
310 HCDI_ERROR_STATS(hcdi) = kstat_create("usba", instance,
311 kstatname, "usb_errors", KSTAT_TYPE_NAMED,
312 sizeof (hcdi_error_stats_t) / sizeof (kstat_named_t),
313 KSTAT_FLAG_PERSISTENT);
314
315 if (HCDI_ERROR_STATS(hcdi) == NULL) {
316
317 return;
318 }
319
320 esp = HCDI_ERROR_STATS_DATA(hcdi);
321 kstat_named_init(&esp->cc_crc, "CRC Errors", KSTAT_DATA_UINT64);
322 kstat_named_init(&esp->cc_bitstuffing,
323 "Bit Stuffing Violations", KSTAT_DATA_UINT64);
324 kstat_named_init(&esp->cc_data_toggle_mm,
325 "Data Toggle PID Errors", KSTAT_DATA_UINT64);
326 kstat_named_init(&esp->cc_stall,
327 "Endpoint Stalls", KSTAT_DATA_UINT64);
328 kstat_named_init(&esp->cc_dev_not_resp,
329 "Device Not Responding", KSTAT_DATA_UINT64);
330 kstat_named_init(&esp->cc_pid_checkfailure,
331 "PID Check Bit Errors", KSTAT_DATA_UINT64);
332 kstat_named_init(&esp->cc_unexp_pid,
333 "Invalid PID Errors", KSTAT_DATA_UINT64);
334 kstat_named_init(&esp->cc_data_overrun,
335 "Data Overruns", KSTAT_DATA_UINT64);
336 kstat_named_init(&esp->cc_data_underrun,
337 "Data Underruns", KSTAT_DATA_UINT64);
338 kstat_named_init(&esp->cc_buffer_overrun,
339 "Buffer Overruns", KSTAT_DATA_UINT64);
340 kstat_named_init(&esp->cc_buffer_underrun,
341 "Buffer Underruns", KSTAT_DATA_UINT64);
342 kstat_named_init(&esp->cc_timeout,
343 "Command Timed Out", KSTAT_DATA_UINT64);
344 kstat_named_init(&esp->cc_not_accessed,
345 "Not Accessed By Hardware", KSTAT_DATA_UINT64);
346 kstat_named_init(&esp->cc_no_resources,
347 "No Resources", KSTAT_DATA_UINT64);
348 kstat_named_init(&esp->cc_unspecified_err,
349 "Unspecified Error", KSTAT_DATA_UINT64);
350 kstat_named_init(&esp->cc_stopped_polling,
351 "Stopped Polling", KSTAT_DATA_UINT64);
352 kstat_named_init(&esp->cc_pipe_closing,
353 "Pipe Closing", KSTAT_DATA_UINT64);
354 kstat_named_init(&esp->cc_pipe_reset,
355 "Pipe Reset", KSTAT_DATA_UINT64);
356 kstat_named_init(&esp->cc_not_supported,
357 "Command Not Supported", KSTAT_DATA_UINT64);
358 kstat_named_init(&esp->cc_flushed,
359 "Request Flushed", KSTAT_DATA_UINT64);
360
361 HCDI_ERROR_STATS(hcdi)->ks_private = hcdi;
362 HCDI_ERROR_STATS(hcdi)->ks_update = nulldev;
363 kstat_install(HCDI_ERROR_STATS(hcdi));
364 }
365 }
366
367
368 /*
369 * Do actual error stats
370 */
371 void
usba_hcdi_update_error_stats(usba_hcdi_t * hcdi,usb_cr_t completion_reason)372 usba_hcdi_update_error_stats(usba_hcdi_t *hcdi, usb_cr_t completion_reason)
373 {
374 if (HCDI_ERROR_STATS(hcdi) == NULL) {
375
376 return;
377 }
378
379 switch (completion_reason) {
380 case USB_CR_OK:
381 break;
382 case USB_CR_CRC:
383 HCDI_ERROR_STATS_DATA(hcdi)->cc_crc.value.ui64++;
384 break;
385 case USB_CR_BITSTUFFING:
386 HCDI_ERROR_STATS_DATA(hcdi)->cc_bitstuffing.value.ui64++;
387 break;
388 case USB_CR_DATA_TOGGLE_MM:
389 HCDI_ERROR_STATS_DATA(hcdi)->cc_data_toggle_mm.value.ui64++;
390 break;
391 case USB_CR_STALL:
392 HCDI_ERROR_STATS_DATA(hcdi)->cc_stall.value.ui64++;
393 break;
394 case USB_CR_DEV_NOT_RESP:
395 HCDI_ERROR_STATS_DATA(hcdi)->cc_dev_not_resp.value.ui64++;
396 break;
397 case USB_CR_PID_CHECKFAILURE:
398 HCDI_ERROR_STATS_DATA(hcdi)->cc_pid_checkfailure.value.ui64++;
399 break;
400 case USB_CR_UNEXP_PID:
401 HCDI_ERROR_STATS_DATA(hcdi)->cc_unexp_pid.value.ui64++;
402 break;
403 case USB_CR_DATA_OVERRUN:
404 HCDI_ERROR_STATS_DATA(hcdi)->cc_data_overrun.value.ui64++;
405 break;
406 case USB_CR_DATA_UNDERRUN:
407 HCDI_ERROR_STATS_DATA(hcdi)->cc_data_underrun.value.ui64++;
408 break;
409 case USB_CR_BUFFER_OVERRUN:
410 HCDI_ERROR_STATS_DATA(hcdi)->cc_buffer_overrun.value.ui64++;
411 break;
412 case USB_CR_BUFFER_UNDERRUN:
413 HCDI_ERROR_STATS_DATA(hcdi)->cc_buffer_underrun.value.ui64++;
414 break;
415 case USB_CR_TIMEOUT:
416 HCDI_ERROR_STATS_DATA(hcdi)->cc_timeout.value.ui64++;
417 break;
418 case USB_CR_NOT_ACCESSED:
419 HCDI_ERROR_STATS_DATA(hcdi)->cc_not_accessed.value.ui64++;
420 break;
421 case USB_CR_NO_RESOURCES:
422 HCDI_ERROR_STATS_DATA(hcdi)->cc_no_resources.value.ui64++;
423 break;
424 case USB_CR_UNSPECIFIED_ERR:
425 HCDI_ERROR_STATS_DATA(hcdi)->cc_unspecified_err.value.ui64++;
426 break;
427 case USB_CR_STOPPED_POLLING:
428 HCDI_ERROR_STATS_DATA(hcdi)->cc_stopped_polling.value.ui64++;
429 break;
430 case USB_CR_PIPE_CLOSING:
431 HCDI_ERROR_STATS_DATA(hcdi)->cc_pipe_closing.value.ui64++;
432 break;
433 case USB_CR_PIPE_RESET:
434 HCDI_ERROR_STATS_DATA(hcdi)->cc_pipe_reset.value.ui64++;
435 break;
436 case USB_CR_NOT_SUPPORTED:
437 HCDI_ERROR_STATS_DATA(hcdi)->cc_not_supported.value.ui64++;
438 break;
439 case USB_CR_FLUSHED:
440 HCDI_ERROR_STATS_DATA(hcdi)->cc_flushed.value.ui64++;
441 break;
442 default:
443 break;
444 }
445 }
446
447
448 /*
449 * Destroy the hotplug kstats structure
450 */
451 static void
usba_hcdi_destroy_stats(usba_hcdi_t * hcdi)452 usba_hcdi_destroy_stats(usba_hcdi_t *hcdi)
453 {
454 if (HCDI_HOTPLUG_STATS(hcdi)) {
455 kstat_delete(HCDI_HOTPLUG_STATS(hcdi));
456 HCDI_HOTPLUG_STATS(hcdi) = NULL;
457 }
458
459 if (HCDI_ERROR_STATS(hcdi)) {
460 kstat_delete(HCDI_ERROR_STATS(hcdi));
461 HCDI_ERROR_STATS(hcdi) = NULL;
462 }
463 }
464
465
466 /*
467 * HCD callback handling
468 */
469 void
usba_hcdi_cb(usba_pipe_handle_data_t * ph_data,usb_opaque_t req,usb_cr_t completion_reason)470 usba_hcdi_cb(usba_pipe_handle_data_t *ph_data,
471 usb_opaque_t req,
472 usb_cr_t completion_reason)
473 {
474
475 usba_device_t *usba_device = ph_data->p_usba_device;
476 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(
477 usba_device->usb_root_hub_dip);
478 usba_req_wrapper_t *req_wrp = USBA_REQ2WRP(req);
479 usb_ep_descr_t *eptd = &ph_data->p_ep;
480
481 mutex_enter(&ph_data->p_mutex);
482
483 #ifdef DEBUG
484 mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex);
485
486 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
487 "usba_hcdi_cb: "
488 "ph_data=0x%p req=0x%p state=%d ref=%d cnt=%d cr=%d",
489 (void *)ph_data, (void *)req, ph_data->p_ph_impl->usba_ph_state,
490 ph_data->p_ph_impl->usba_ph_ref_count, ph_data->p_req_count,
491 completion_reason);
492
493 mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex);
494 #endif
495
496 /* Set the completion reason */
497 switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
498 case USB_EP_ATTR_CONTROL:
499 ((usb_ctrl_req_t *)req)->
500 ctrl_completion_reason = completion_reason;
501 break;
502 case USB_EP_ATTR_BULK:
503 ((usb_bulk_req_t *)req)->
504 bulk_completion_reason = completion_reason;
505 break;
506 case USB_EP_ATTR_INTR:
507 ((usb_intr_req_t *)req)->
508 intr_completion_reason = completion_reason;
509 break;
510 case USB_EP_ATTR_ISOCH:
511 ((usb_isoc_req_t *)req)->
512 isoc_completion_reason = completion_reason;
513 break;
514 }
515
516 /*
517 * exception callbacks will still go thru a taskq thread
518 * but should occur after the soft interrupt callback
519 * By design of periodic pipes, polling will stop on any
520 * exception
521 */
522 if ((ph_data->p_spec_flag & USBA_PH_FLAG_USE_SOFT_INTR) &&
523 (completion_reason == USB_CR_OK)) {
524 ph_data->p_soft_intr++;
525 mutex_exit(&ph_data->p_mutex);
526
527 usba_add_to_list(&hcdi->hcdi_cb_queue, &req_wrp->wr_queue);
528
529 if (ddi_intr_trigger_softint(hcdi->hcdi_softint_hdl, NULL) !=
530 DDI_SUCCESS)
531 USB_DPRINTF_L2(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
532 "usba_hcdi_cb: ddi_intr_trigger_softint failed");
533
534 return;
535 }
536
537 /*
538 * USBA_PH_FLAG_TQ_SHARE is for bulk and intr requests,
539 * USBA_PH_FLAG_USE_SOFT_INTR is only for isoch,
540 * so there are no conflicts.
541 */
542 if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) {
543 int iface;
544
545 mutex_exit(&ph_data->p_mutex);
546 iface = usb_get_if_number(ph_data->p_dip);
547 if (iface < 0) {
548 /* we own the device, use the first taskq */
549 iface = 0;
550 }
551 if (taskq_dispatch(usba_device->usb_shared_taskq[iface],
552 hcdi_shared_cb_thread, req_wrp, TQ_NOSLEEP) ==
553 NULL) {
554 usba_req_exc_cb(req_wrp,
555 USB_CR_NO_RESOURCES, USB_CB_ASYNC_REQ_FAILED);
556 }
557
558 return;
559 }
560
561 /* Add the callback to the pipehandles callback list */
562 usba_add_to_list(&ph_data->p_cb_queue, &req_wrp->wr_queue);
563
564 /* only dispatch if there is no thread running */
565 if (ph_data->p_thread_id == 0) {
566 if (usba_async_ph_req(ph_data, hcdi_cb_thread,
567 ph_data, USB_FLAGS_NOSLEEP) != USB_SUCCESS) {
568 USB_DPRINTF_L2(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
569 "usba_hcdi_cb: taskq_dispatch failed");
570 if (usba_rm_from_list(&ph_data->p_cb_queue,
571 &req_wrp->wr_queue) == USB_SUCCESS) {
572 mutex_exit(&ph_data->p_mutex);
573 usba_req_exc_cb(req_wrp,
574 USB_CR_NO_RESOURCES,
575 USB_CB_ASYNC_REQ_FAILED);
576
577 return;
578 }
579 } else {
580 ph_data->p_thread_id = (kthread_t *)1;
581 }
582 }
583 mutex_exit(&ph_data->p_mutex);
584 }
585
586
587 /*
588 * thread to perform the callbacks
589 */
590 static void
hcdi_cb_thread(void * arg)591 hcdi_cb_thread(void *arg)
592 {
593 usba_pipe_handle_data_t *ph_data =
594 (usba_pipe_handle_data_t *)arg;
595 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
596 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(ph_data->
597 p_usba_device->usb_root_hub_dip);
598 usba_req_wrapper_t *req_wrp;
599
600 mutex_enter(&ph_data->p_mutex);
601 ASSERT(ph_data->p_thread_id == (kthread_t *)1);
602 ph_data->p_thread_id = curthread;
603
604 /*
605 * hold the ph_data. we can't use usba_hold_ph_data() since
606 * it will return NULL if we are closing the pipe which would
607 * then leave all requests stuck in the cb_queue
608 */
609 mutex_enter(&ph_impl->usba_ph_mutex);
610 ph_impl->usba_ph_ref_count++;
611
612 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
613 "hcdi_cb_thread: ph_data=0x%p ref=%d", (void *)ph_data,
614 ph_impl->usba_ph_ref_count);
615
616 mutex_exit(&ph_impl->usba_ph_mutex);
617
618 /*
619 * wait till soft interrupt callbacks are taken care of
620 */
621 while (ph_data->p_soft_intr) {
622 mutex_exit(&ph_data->p_mutex);
623 delay(1);
624 mutex_enter(&ph_data->p_mutex);
625 }
626
627 while ((req_wrp = (usba_req_wrapper_t *)
628 usba_rm_first_pvt_from_list(&ph_data->p_cb_queue)) != NULL) {
629 hcdi_do_cb(ph_data, req_wrp, hcdi);
630 }
631
632 ph_data->p_thread_id = 0;
633 mutex_exit(&ph_data->p_mutex);
634
635 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
636 "hcdi_cb_thread done: ph_data=0x%p", (void *)ph_data);
637
638 usba_release_ph_data(ph_impl);
639 }
640
641
642 static void
hcdi_do_cb(usba_pipe_handle_data_t * ph_data,usba_req_wrapper_t * req_wrp,usba_hcdi_t * hcdi)643 hcdi_do_cb(usba_pipe_handle_data_t *ph_data, usba_req_wrapper_t *req_wrp,
644 usba_hcdi_t *hcdi)
645 {
646 usb_cr_t completion_reason;
647 usb_req_attrs_t attrs = req_wrp->wr_attrs;
648
649 switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
650 USB_EP_ATTR_MASK) {
651 case USB_EP_ATTR_CONTROL:
652 completion_reason =
653 USBA_WRP2CTRL_REQ(req_wrp)->ctrl_completion_reason;
654 break;
655 case USB_EP_ATTR_INTR:
656 completion_reason =
657 USBA_WRP2INTR_REQ(req_wrp)->intr_completion_reason;
658 break;
659 case USB_EP_ATTR_BULK:
660 completion_reason =
661 USBA_WRP2BULK_REQ(req_wrp)->bulk_completion_reason;
662 break;
663 case USB_EP_ATTR_ISOCH:
664 completion_reason =
665 USBA_WRP2ISOC_REQ(req_wrp)->isoc_completion_reason;
666 break;
667 }
668 req_wrp->wr_cr = completion_reason;
669
670 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
671 "hcdi_do_cb: wrp=0x%p cr=0x%x", (void *)req_wrp, completion_reason);
672
673 /*
674 * Normal callbacks:
675 */
676 if (completion_reason == USB_CR_OK) {
677 mutex_exit(&ph_data->p_mutex);
678 usba_req_normal_cb(req_wrp);
679 mutex_enter(&ph_data->p_mutex);
680 } else {
681 usb_pipe_state_t pipe_state;
682
683 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
684 "exception callback handling: attrs=0x%x", attrs);
685
686 /*
687 * In exception callback handling, if we were
688 * not able to clear stall, we need to modify
689 * pipe state. Also if auto-clearing is not set
690 * pipe state needs to be modified.
691 */
692 pipe_state = usba_get_ph_state(ph_data);
693
694 if (!USBA_PIPE_CLOSING(pipe_state)) {
695 switch (completion_reason) {
696 case USB_CR_STOPPED_POLLING:
697 if (pipe_state ==
698 USB_PIPE_STATE_ACTIVE) {
699 usba_pipe_new_state(ph_data,
700 USB_PIPE_STATE_IDLE);
701 }
702 break;
703 case USB_CR_NOT_SUPPORTED:
704 usba_pipe_new_state(ph_data,
705 USB_PIPE_STATE_IDLE);
706 break;
707 case USB_CR_PIPE_RESET:
708 case USB_CR_FLUSHED:
709 break;
710 default:
711 usba_pipe_new_state(ph_data,
712 USB_PIPE_STATE_ERROR);
713 break;
714 }
715 }
716
717 pipe_state = usba_get_ph_state(ph_data);
718
719 mutex_exit(&ph_data->p_mutex);
720 if (attrs & USB_ATTRS_PIPE_RESET) {
721 if ((completion_reason != USB_CR_PIPE_RESET) &&
722 (pipe_state == USB_PIPE_STATE_ERROR)) {
723
724 hcdi_autoclearing(req_wrp);
725 }
726 }
727
728 usba_req_exc_cb(req_wrp, 0, 0);
729 mutex_enter(&ph_data->p_mutex);
730 }
731
732 /* Update the hcdi error kstats */
733 if (completion_reason) {
734 mutex_enter(&hcdi->hcdi_mutex);
735 usba_hcdi_update_error_stats(hcdi, completion_reason);
736 mutex_exit(&hcdi->hcdi_mutex);
737 }
738
739 /*
740 * Once the callback is finished, release the pipe handle
741 * we start the next request first to avoid that the
742 * pipe gets closed while starting the next request
743 */
744 mutex_exit(&ph_data->p_mutex);
745 usba_start_next_req(ph_data);
746
747 mutex_enter(&ph_data->p_mutex);
748 }
749
750
751 /*
752 * thread to perform callbacks on the shared queue
753 */
754 static void
hcdi_shared_cb_thread(void * arg)755 hcdi_shared_cb_thread(void *arg)
756 {
757 usba_req_wrapper_t *req_wrp = (usba_req_wrapper_t *)arg;
758 usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data;
759 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
760 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(ph_data->
761 p_usba_device->usb_root_hub_dip);
762 /*
763 * hold the ph_data. we can't use usba_hold_ph_data() since
764 * it will return NULL if we are closing the pipe which would
765 * then leave all requests stuck in the cb_queue
766 */
767 mutex_enter(&ph_impl->usba_ph_mutex);
768 ph_impl->usba_ph_ref_count++;
769
770 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
771 "hcdi_shared_cb_thread: ph_data=0x%p ref=%d req=0x%p",
772 (void *)ph_data, ph_impl->usba_ph_ref_count, (void *)req_wrp);
773 mutex_exit(&ph_impl->usba_ph_mutex);
774
775 /* do the callback */
776 mutex_enter(&ph_data->p_mutex);
777 hcdi_do_cb(ph_data, req_wrp, hcdi);
778 mutex_exit(&ph_data->p_mutex);
779
780 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
781 "hcdi_cb_thread done: ph_data=0x%p", (void *)ph_data);
782
783 usba_release_ph_data(ph_impl);
784 }
785
786
787 /*
788 * soft interrupt handler
789 */
790 /*ARGSUSED*/
791 static uint_t
hcdi_soft_intr(caddr_t arg1,caddr_t arg2)792 hcdi_soft_intr(caddr_t arg1, caddr_t arg2)
793 {
794 usba_hcdi_t *hcdi = (void *)arg1;
795 usba_req_wrapper_t *req_wrp;
796 int count = 0;
797
798 while ((req_wrp = (usba_req_wrapper_t *)
799 usba_rm_first_pvt_from_list(&hcdi->hcdi_cb_queue)) != NULL) {
800 usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data;
801 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
802
803 /* hold the pipe */
804 mutex_enter(&ph_impl->usba_ph_mutex);
805 ph_impl->usba_ph_ref_count++;
806 mutex_exit(&ph_impl->usba_ph_mutex);
807
808 /* do the callback */
809 usba_req_normal_cb(req_wrp);
810
811 /* decrement the soft interrupt count */
812 mutex_enter(&ph_data->p_mutex);
813 ph_data->p_soft_intr--;
814 mutex_exit(&ph_data->p_mutex);
815
816 /* release the pipe */
817 mutex_enter(&ph_impl->usba_ph_mutex);
818 ph_impl->usba_ph_ref_count--;
819 mutex_exit(&ph_impl->usba_ph_mutex);
820
821 count++;
822 }
823
824 return (count == 0 ? DDI_INTR_UNCLAIMED : DDI_INTR_CLAIMED);
825 }
826
827
828 /*
829 * hcdi_autoclearing:
830 * This function is called under the taskq context. It
831 * resets the pipe, and clears the stall, if necessary
832 */
833 static void
hcdi_autoclearing(usba_req_wrapper_t * req_wrp)834 hcdi_autoclearing(usba_req_wrapper_t *req_wrp)
835 {
836 usb_cr_t cr = req_wrp->wr_cr;
837 usb_pipe_handle_t pipe_handle, def_pipe_handle;
838 usb_cr_t completion_reason;
839 usb_cb_flags_t cb_flags;
840 int rval;
841 usba_device_t *usba_device =
842 req_wrp->wr_ph_data->p_usba_device;
843 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(
844 usba_device->usb_root_hub_dip);
845 usb_req_attrs_t attrs = req_wrp->wr_attrs;
846
847 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
848 "hcdi_autoclearing: wrp=0x%p", (void *)req_wrp);
849
850 pipe_handle = usba_get_pipe_handle(req_wrp->wr_ph_data);
851 def_pipe_handle = usba_get_dflt_pipe_handle(req_wrp->wr_ph_data->p_dip);
852
853 /*
854 * first reset the pipe synchronously
855 */
856 if ((attrs & USB_ATTRS_PIPE_RESET) == USB_ATTRS_PIPE_RESET) {
857 usba_pipe_clear(pipe_handle);
858 usba_req_set_cb_flags(req_wrp, USB_CB_RESET_PIPE);
859 }
860
861 ASSERT(def_pipe_handle);
862
863 /* Do not clear if this request was a usb_get_status request */
864 if ((pipe_handle == def_pipe_handle) &&
865 (USBA_WRP2CTRL_REQ(req_wrp)->ctrl_bRequest ==
866 USB_REQ_GET_STATUS)) {
867 USB_DPRINTF_L2(DPRINT_MASK_USBAI, hcdi->hcdi_log_handle,
868 "hcdi_autoclearing: usb_get_status failed, no clearing");
869
870 /* if default pipe and stall no auto clearing */
871 } else if ((pipe_handle == def_pipe_handle) && (cr == USB_CR_STALL)) {
872 USB_DPRINTF_L2(DPRINT_MASK_USBAI, hcdi->hcdi_log_handle,
873 "hcdi_autoclearing: default pipe stalled, no clearing");
874
875 usba_req_set_cb_flags(req_wrp, USB_CB_PROTOCOL_STALL);
876
877 /* else do auto clearing */
878 } else if (((attrs & USB_ATTRS_AUTOCLEARING) ==
879 USB_ATTRS_AUTOCLEARING) && (cr == USB_CR_STALL)) {
880 ushort_t status = 0;
881
882 rval = usb_get_status(req_wrp->wr_dip, def_pipe_handle,
883 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_EP,
884 req_wrp->wr_ph_data->p_ep.bEndpointAddress,
885 &status, USB_FLAGS_SLEEP);
886 if (rval != USB_SUCCESS) {
887 USB_DPRINTF_L2(DPRINT_MASK_USBAI, hcdi->hcdi_log_handle,
888 "get status (STALL) failed: rval=%d", rval);
889
890 usba_pipe_clear(def_pipe_handle);
891 }
892
893 if ((rval != USB_SUCCESS) ||
894 (status & USB_EP_HALT_STATUS)) {
895 usba_req_set_cb_flags(req_wrp, USB_CB_FUNCTIONAL_STALL);
896
897 if ((rval = usb_pipe_sync_ctrl_xfer(
898 req_wrp->wr_dip, def_pipe_handle,
899 USB_DEV_REQ_HOST_TO_DEV |
900 USB_DEV_REQ_RCPT_EP,
901 USB_REQ_CLEAR_FEATURE,
902 0,
903 req_wrp->wr_ph_data->p_ep.bEndpointAddress,
904 0,
905 NULL, 0,
906 &completion_reason,
907 &cb_flags, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
908 USB_DPRINTF_L2(DPRINT_MASK_USBAI,
909 hcdi->hcdi_log_handle,
910 "auto clearing (STALL) failed: "
911 "rval=%d, cr=0x%x cb=0x%x",
912 rval, completion_reason, cb_flags);
913
914 usba_pipe_clear(def_pipe_handle);
915 } else {
916 usba_req_set_cb_flags(req_wrp,
917 USB_CB_STALL_CLEARED);
918 }
919 } else {
920 usba_req_set_cb_flags(req_wrp, USB_CB_PROTOCOL_STALL);
921 }
922 }
923 }
924
925
926 /*
927 * usba_hcdi_get_req_private:
928 * This function is used to get the HCD private field
929 * maintained by USBA. HCD calls this function.
930 *
931 * Arguments:
932 * req - pointer to usb_*_req_t
933 *
934 * Return Values:
935 * wr_hcd_private field from wrapper
936 */
937 usb_opaque_t
usba_hcdi_get_req_private(usb_opaque_t req)938 usba_hcdi_get_req_private(usb_opaque_t req)
939 {
940 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req);
941
942 return (wrp->wr_hcd_private);
943 }
944
945
946 /*
947 * usba_hcdi_set_req_private:
948 * This function is used to set the HCD private field
949 * maintained by USBA. HCD calls this function.
950 *
951 * Arguments:
952 * req - pointer to usb_*_req_t
953 * hcd_private - wr_hcd_private field from wrapper
954 */
955 void
usba_hcdi_set_req_private(usb_opaque_t req,usb_opaque_t hcd_private)956 usba_hcdi_set_req_private(usb_opaque_t req,
957 usb_opaque_t hcd_private)
958 {
959 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req);
960
961 wrp->wr_hcd_private = hcd_private;
962 }
963
964
965 /* get data toggle information for this endpoint */
966 uchar_t
usba_hcdi_get_data_toggle(usba_device_t * usba_device,uint8_t ep_addr)967 usba_hcdi_get_data_toggle(usba_device_t *usba_device, uint8_t ep_addr)
968 {
969 uchar_t toggle;
970 usba_ph_impl_t *ph_impl;
971 int ep_index;
972
973 ep_index = usb_get_ep_index(ep_addr);
974 mutex_enter(&usba_device->usb_mutex);
975 ph_impl = &usba_device->usb_ph_list[ep_index];
976 mutex_enter(&ph_impl->usba_ph_mutex);
977 toggle = (uchar_t)(ph_impl->usba_ph_flags & USBA_PH_DATA_TOGGLE);
978 mutex_exit(&ph_impl->usba_ph_mutex);
979 mutex_exit(&usba_device->usb_mutex);
980
981 return (toggle);
982 }
983
984
985 /* set data toggle information for this endpoint */
986 void
usba_hcdi_set_data_toggle(usba_device_t * usba_device,uint8_t ep_addr,uchar_t toggle)987 usba_hcdi_set_data_toggle(usba_device_t *usba_device, uint8_t ep_addr,
988 uchar_t toggle)
989 {
990 usba_ph_impl_t *ph_impl;
991 int ep_index;
992
993 ep_index = usb_get_ep_index(ep_addr);
994 mutex_enter(&usba_device->usb_mutex);
995 ph_impl = &usba_device->usb_ph_list[ep_index];
996 mutex_enter(&ph_impl->usba_ph_mutex);
997 ph_impl->usba_ph_flags &= ~USBA_PH_DATA_TOGGLE;
998 ph_impl->usba_ph_flags |= (USBA_PH_DATA_TOGGLE & toggle);
999 mutex_exit(&ph_impl->usba_ph_mutex);
1000 mutex_exit(&usba_device->usb_mutex);
1001 }
1002
1003
1004 /* get pipe_handle_impl ptr for this ep */
1005 usba_pipe_handle_data_t *
usba_hcdi_get_ph_data(usba_device_t * usba_device,uint8_t ep_addr)1006 usba_hcdi_get_ph_data(usba_device_t *usba_device, uint8_t ep_addr)
1007 {
1008 return (usba_device->usb_ph_list[usb_get_ep_index(ep_addr)].
1009 usba_ph_data);
1010 }
1011