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_unspecified_err,
347 "Unspecified Error", KSTAT_DATA_UINT64);
348 #ifdef NOTYETNEEDED
349 kstat_named_init(&esp->hcdi_usb_failure,
350 "USB Failure", KSTAT_DATA_UINT64);
351 kstat_named_init(&esp->hcdi_usb_no_resources,
352 "No Resources", KSTAT_DATA_UINT64);
353 kstat_named_init(&esp->hcdi_usb_no_bandwidth,
354 "No Bandwidth", KSTAT_DATA_UINT64);
355 kstat_named_init(&esp->hcdi_usb_pipe_reserved,
356 "Pipe Reserved", KSTAT_DATA_UINT64);
357 kstat_named_init(&esp->hcdi_usb_pipe_unshareable,
358 "Pipe Unshareable", KSTAT_DATA_UINT64);
359 kstat_named_init(&esp->hcdi_usb_not_supported,
360 "Function Not Supported", KSTAT_DATA_UINT64);
361 kstat_named_init(&esp->hcdi_usb_pipe_error,
362 "Pipe Error", KSTAT_DATA_UINT64);
363 kstat_named_init(&esp->hcdi_usb_pipe_busy,
364 "Pipe Busy", KSTAT_DATA_UINT64);
365 #endif
366
367 HCDI_ERROR_STATS(hcdi)->ks_private = hcdi;
368 HCDI_ERROR_STATS(hcdi)->ks_update = nulldev;
369 kstat_install(HCDI_ERROR_STATS(hcdi));
370 }
371 }
372
373
374 /*
375 * Do actual error stats
376 */
377 void
usba_hcdi_update_error_stats(usba_hcdi_t * hcdi,usb_cr_t completion_reason)378 usba_hcdi_update_error_stats(usba_hcdi_t *hcdi, usb_cr_t completion_reason)
379 {
380 if (HCDI_ERROR_STATS(hcdi) == NULL) {
381
382 return;
383 }
384
385 switch (completion_reason) {
386 case USB_CR_OK:
387 break;
388 case USB_CR_CRC:
389 HCDI_ERROR_STATS_DATA(hcdi)->cc_crc.value.ui64++;
390 break;
391 case USB_CR_BITSTUFFING:
392 HCDI_ERROR_STATS_DATA(hcdi)->cc_bitstuffing.value.ui64++;
393 break;
394 case USB_CR_DATA_TOGGLE_MM:
395 HCDI_ERROR_STATS_DATA(hcdi)->cc_data_toggle_mm.value.ui64++;
396 break;
397 case USB_CR_STALL:
398 HCDI_ERROR_STATS_DATA(hcdi)->cc_stall.value.ui64++;
399 break;
400 case USB_CR_DEV_NOT_RESP:
401 HCDI_ERROR_STATS_DATA(hcdi)->cc_dev_not_resp.value.ui64++;
402 break;
403 case USB_CR_PID_CHECKFAILURE:
404 HCDI_ERROR_STATS_DATA(hcdi)->cc_pid_checkfailure.value.ui64++;
405 break;
406 case USB_CR_UNEXP_PID:
407 HCDI_ERROR_STATS_DATA(hcdi)->cc_unexp_pid.value.ui64++;
408 break;
409 case USB_CR_DATA_OVERRUN:
410 HCDI_ERROR_STATS_DATA(hcdi)->cc_data_overrun.value.ui64++;
411 break;
412 case USB_CR_DATA_UNDERRUN:
413 HCDI_ERROR_STATS_DATA(hcdi)->cc_data_underrun.value.ui64++;
414 break;
415 case USB_CR_BUFFER_OVERRUN:
416 HCDI_ERROR_STATS_DATA(hcdi)->cc_buffer_overrun.value.ui64++;
417 break;
418 case USB_CR_BUFFER_UNDERRUN:
419 HCDI_ERROR_STATS_DATA(hcdi)->cc_buffer_underrun.value.ui64++;
420 break;
421 case USB_CR_TIMEOUT:
422 HCDI_ERROR_STATS_DATA(hcdi)->cc_timeout.value.ui64++;
423 break;
424 case USB_CR_NOT_ACCESSED:
425 HCDI_ERROR_STATS_DATA(hcdi)->cc_not_accessed.value.ui64++;
426 break;
427 case USB_CR_NO_RESOURCES:
428 HCDI_ERROR_STATS_DATA(hcdi)->cc_no_resources.value.ui64++;
429 break;
430 case USB_CR_UNSPECIFIED_ERR:
431 HCDI_ERROR_STATS_DATA(hcdi)->cc_unspecified_err.value.ui64++;
432 break;
433 case USB_CR_STOPPED_POLLING:
434 HCDI_ERROR_STATS_DATA(hcdi)->cc_stopped_polling.value.ui64++;
435 break;
436 case USB_CR_PIPE_CLOSING:
437 HCDI_ERROR_STATS_DATA(hcdi)->cc_pipe_closing.value.ui64++;
438 break;
439 case USB_CR_PIPE_RESET:
440 HCDI_ERROR_STATS_DATA(hcdi)->cc_pipe_reset.value.ui64++;
441 break;
442 case USB_CR_NOT_SUPPORTED:
443 HCDI_ERROR_STATS_DATA(hcdi)->cc_not_supported.value.ui64++;
444 break;
445 case USB_CR_FLUSHED:
446 HCDI_ERROR_STATS_DATA(hcdi)->cc_flushed.value.ui64++;
447 break;
448 default:
449 break;
450 }
451 }
452
453
454 /*
455 * Destroy the hotplug kstats structure
456 */
457 static void
usba_hcdi_destroy_stats(usba_hcdi_t * hcdi)458 usba_hcdi_destroy_stats(usba_hcdi_t *hcdi)
459 {
460 if (HCDI_HOTPLUG_STATS(hcdi)) {
461 kstat_delete(HCDI_HOTPLUG_STATS(hcdi));
462 HCDI_HOTPLUG_STATS(hcdi) = NULL;
463 }
464
465 if (HCDI_ERROR_STATS(hcdi)) {
466 kstat_delete(HCDI_ERROR_STATS(hcdi));
467 HCDI_ERROR_STATS(hcdi) = NULL;
468 }
469 }
470
471
472 /*
473 * HCD callback handling
474 */
475 void
usba_hcdi_cb(usba_pipe_handle_data_t * ph_data,usb_opaque_t req,usb_cr_t completion_reason)476 usba_hcdi_cb(usba_pipe_handle_data_t *ph_data,
477 usb_opaque_t req,
478 usb_cr_t completion_reason)
479 {
480
481 usba_device_t *usba_device = ph_data->p_usba_device;
482 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(
483 usba_device->usb_root_hub_dip);
484 usba_req_wrapper_t *req_wrp = USBA_REQ2WRP(req);
485 usb_ep_descr_t *eptd = &ph_data->p_ep;
486
487 mutex_enter(&ph_data->p_mutex);
488
489 #ifdef DEBUG
490 mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex);
491
492 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
493 "usba_hcdi_cb: "
494 "ph_data=0x%p req=0x%p state=%d ref=%d cnt=%d cr=%d",
495 (void *)ph_data, (void *)req, ph_data->p_ph_impl->usba_ph_state,
496 ph_data->p_ph_impl->usba_ph_ref_count, ph_data->p_req_count,
497 completion_reason);
498
499 mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex);
500 #endif
501
502 /* Set the completion reason */
503 switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
504 case USB_EP_ATTR_CONTROL:
505 ((usb_ctrl_req_t *)req)->
506 ctrl_completion_reason = completion_reason;
507 break;
508 case USB_EP_ATTR_BULK:
509 ((usb_bulk_req_t *)req)->
510 bulk_completion_reason = completion_reason;
511 break;
512 case USB_EP_ATTR_INTR:
513 ((usb_intr_req_t *)req)->
514 intr_completion_reason = completion_reason;
515 break;
516 case USB_EP_ATTR_ISOCH:
517 ((usb_isoc_req_t *)req)->
518 isoc_completion_reason = completion_reason;
519 break;
520 }
521
522 /*
523 * exception callbacks will still go thru a taskq thread
524 * but should occur after the soft interrupt callback
525 * By design of periodic pipes, polling will stop on any
526 * exception
527 */
528 if ((ph_data->p_spec_flag & USBA_PH_FLAG_USE_SOFT_INTR) &&
529 (completion_reason == USB_CR_OK)) {
530 ph_data->p_soft_intr++;
531 mutex_exit(&ph_data->p_mutex);
532
533 usba_add_to_list(&hcdi->hcdi_cb_queue, &req_wrp->wr_queue);
534
535 if (ddi_intr_trigger_softint(hcdi->hcdi_softint_hdl, NULL) !=
536 DDI_SUCCESS)
537 USB_DPRINTF_L2(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
538 "usba_hcdi_cb: ddi_intr_trigger_softint failed");
539
540 return;
541 }
542
543 /*
544 * USBA_PH_FLAG_TQ_SHARE is for bulk and intr requests,
545 * USBA_PH_FLAG_USE_SOFT_INTR is only for isoch,
546 * so there are no conflicts.
547 */
548 if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) {
549 int iface;
550
551 mutex_exit(&ph_data->p_mutex);
552 iface = usb_get_if_number(ph_data->p_dip);
553 if (iface < 0) {
554 /* we own the device, use the first taskq */
555 iface = 0;
556 }
557 if (taskq_dispatch(usba_device->usb_shared_taskq[iface],
558 hcdi_shared_cb_thread, req_wrp, TQ_NOSLEEP) ==
559 NULL) {
560 usba_req_exc_cb(req_wrp,
561 USB_CR_NO_RESOURCES, USB_CB_ASYNC_REQ_FAILED);
562 }
563
564 return;
565 }
566
567 /* Add the callback to the pipehandles callback list */
568 usba_add_to_list(&ph_data->p_cb_queue, &req_wrp->wr_queue);
569
570 /* only dispatch if there is no thread running */
571 if (ph_data->p_thread_id == 0) {
572 if (usba_async_ph_req(ph_data, hcdi_cb_thread,
573 ph_data, USB_FLAGS_NOSLEEP) != USB_SUCCESS) {
574 USB_DPRINTF_L2(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
575 "usba_hcdi_cb: taskq_dispatch failed");
576 if (usba_rm_from_list(&ph_data->p_cb_queue,
577 &req_wrp->wr_queue) == USB_SUCCESS) {
578 mutex_exit(&ph_data->p_mutex);
579 usba_req_exc_cb(req_wrp,
580 USB_CR_NO_RESOURCES,
581 USB_CB_ASYNC_REQ_FAILED);
582
583 return;
584 }
585 } else {
586 ph_data->p_thread_id = (kthread_t *)1;
587 }
588 }
589 mutex_exit(&ph_data->p_mutex);
590 }
591
592
593 /*
594 * thread to perform the callbacks
595 */
596 static void
hcdi_cb_thread(void * arg)597 hcdi_cb_thread(void *arg)
598 {
599 usba_pipe_handle_data_t *ph_data =
600 (usba_pipe_handle_data_t *)arg;
601 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
602 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(ph_data->
603 p_usba_device->usb_root_hub_dip);
604 usba_req_wrapper_t *req_wrp;
605
606 mutex_enter(&ph_data->p_mutex);
607 ASSERT(ph_data->p_thread_id == (kthread_t *)1);
608 ph_data->p_thread_id = curthread;
609
610 /*
611 * hold the ph_data. we can't use usba_hold_ph_data() since
612 * it will return NULL if we are closing the pipe which would
613 * then leave all requests stuck in the cb_queue
614 */
615 mutex_enter(&ph_impl->usba_ph_mutex);
616 ph_impl->usba_ph_ref_count++;
617
618 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
619 "hcdi_cb_thread: ph_data=0x%p ref=%d", (void *)ph_data,
620 ph_impl->usba_ph_ref_count);
621
622 mutex_exit(&ph_impl->usba_ph_mutex);
623
624 /*
625 * wait till soft interrupt callbacks are taken care of
626 */
627 while (ph_data->p_soft_intr) {
628 mutex_exit(&ph_data->p_mutex);
629 delay(1);
630 mutex_enter(&ph_data->p_mutex);
631 }
632
633 while ((req_wrp = (usba_req_wrapper_t *)
634 usba_rm_first_pvt_from_list(&ph_data->p_cb_queue)) != NULL) {
635 hcdi_do_cb(ph_data, req_wrp, hcdi);
636 }
637
638 ph_data->p_thread_id = 0;
639 mutex_exit(&ph_data->p_mutex);
640
641 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
642 "hcdi_cb_thread done: ph_data=0x%p", (void *)ph_data);
643
644 usba_release_ph_data(ph_impl);
645 }
646
647
648 static void
hcdi_do_cb(usba_pipe_handle_data_t * ph_data,usba_req_wrapper_t * req_wrp,usba_hcdi_t * hcdi)649 hcdi_do_cb(usba_pipe_handle_data_t *ph_data, usba_req_wrapper_t *req_wrp,
650 usba_hcdi_t *hcdi)
651 {
652 usb_cr_t completion_reason;
653 usb_req_attrs_t attrs = req_wrp->wr_attrs;
654
655 switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
656 USB_EP_ATTR_MASK) {
657 case USB_EP_ATTR_CONTROL:
658 completion_reason =
659 USBA_WRP2CTRL_REQ(req_wrp)->ctrl_completion_reason;
660 break;
661 case USB_EP_ATTR_INTR:
662 completion_reason =
663 USBA_WRP2INTR_REQ(req_wrp)->intr_completion_reason;
664 break;
665 case USB_EP_ATTR_BULK:
666 completion_reason =
667 USBA_WRP2BULK_REQ(req_wrp)->bulk_completion_reason;
668 break;
669 case USB_EP_ATTR_ISOCH:
670 completion_reason =
671 USBA_WRP2ISOC_REQ(req_wrp)->isoc_completion_reason;
672 break;
673 }
674 req_wrp->wr_cr = completion_reason;
675
676 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
677 "hcdi_do_cb: wrp=0x%p cr=0x%x", (void *)req_wrp, completion_reason);
678
679 /*
680 * Normal callbacks:
681 */
682 if (completion_reason == USB_CR_OK) {
683 mutex_exit(&ph_data->p_mutex);
684 usba_req_normal_cb(req_wrp);
685 mutex_enter(&ph_data->p_mutex);
686 } else {
687 usb_pipe_state_t pipe_state;
688
689 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
690 "exception callback handling: attrs=0x%x", attrs);
691
692 /*
693 * In exception callback handling, if we were
694 * not able to clear stall, we need to modify
695 * pipe state. Also if auto-clearing is not set
696 * pipe state needs to be modified.
697 */
698 pipe_state = usba_get_ph_state(ph_data);
699
700 if (!USBA_PIPE_CLOSING(pipe_state)) {
701 switch (completion_reason) {
702 case USB_CR_STOPPED_POLLING:
703 if (pipe_state ==
704 USB_PIPE_STATE_ACTIVE) {
705 usba_pipe_new_state(ph_data,
706 USB_PIPE_STATE_IDLE);
707 }
708 break;
709 case USB_CR_NOT_SUPPORTED:
710 usba_pipe_new_state(ph_data,
711 USB_PIPE_STATE_IDLE);
712 break;
713 case USB_CR_PIPE_RESET:
714 case USB_CR_FLUSHED:
715 break;
716 default:
717 usba_pipe_new_state(ph_data,
718 USB_PIPE_STATE_ERROR);
719 break;
720 }
721 }
722
723 pipe_state = usba_get_ph_state(ph_data);
724
725 mutex_exit(&ph_data->p_mutex);
726 if (attrs & USB_ATTRS_PIPE_RESET) {
727 if ((completion_reason != USB_CR_PIPE_RESET) &&
728 (pipe_state == USB_PIPE_STATE_ERROR)) {
729
730 hcdi_autoclearing(req_wrp);
731 }
732 }
733
734 usba_req_exc_cb(req_wrp, 0, 0);
735 mutex_enter(&ph_data->p_mutex);
736 }
737
738 /* Update the hcdi error kstats */
739 if (completion_reason) {
740 mutex_enter(&hcdi->hcdi_mutex);
741 usba_hcdi_update_error_stats(hcdi, completion_reason);
742 mutex_exit(&hcdi->hcdi_mutex);
743 }
744
745 /*
746 * Once the callback is finished, release the pipe handle
747 * we start the next request first to avoid that the
748 * pipe gets closed while starting the next request
749 */
750 mutex_exit(&ph_data->p_mutex);
751 usba_start_next_req(ph_data);
752
753 mutex_enter(&ph_data->p_mutex);
754 }
755
756
757 /*
758 * thread to perform callbacks on the shared queue
759 */
760 static void
hcdi_shared_cb_thread(void * arg)761 hcdi_shared_cb_thread(void *arg)
762 {
763 usba_req_wrapper_t *req_wrp = (usba_req_wrapper_t *)arg;
764 usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data;
765 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
766 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(ph_data->
767 p_usba_device->usb_root_hub_dip);
768 /*
769 * hold the ph_data. we can't use usba_hold_ph_data() since
770 * it will return NULL if we are closing the pipe which would
771 * then leave all requests stuck in the cb_queue
772 */
773 mutex_enter(&ph_impl->usba_ph_mutex);
774 ph_impl->usba_ph_ref_count++;
775
776 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
777 "hcdi_shared_cb_thread: ph_data=0x%p ref=%d req=0x%p",
778 (void *)ph_data, ph_impl->usba_ph_ref_count, (void *)req_wrp);
779 mutex_exit(&ph_impl->usba_ph_mutex);
780
781 /* do the callback */
782 mutex_enter(&ph_data->p_mutex);
783 hcdi_do_cb(ph_data, req_wrp, hcdi);
784 mutex_exit(&ph_data->p_mutex);
785
786 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
787 "hcdi_cb_thread done: ph_data=0x%p", (void *)ph_data);
788
789 usba_release_ph_data(ph_impl);
790 }
791
792
793 /*
794 * soft interrupt handler
795 */
796 /*ARGSUSED*/
797 static uint_t
hcdi_soft_intr(caddr_t arg1,caddr_t arg2)798 hcdi_soft_intr(caddr_t arg1, caddr_t arg2)
799 {
800 usba_hcdi_t *hcdi = (void *)arg1;
801 usba_req_wrapper_t *req_wrp;
802 int count = 0;
803
804 while ((req_wrp = (usba_req_wrapper_t *)
805 usba_rm_first_pvt_from_list(&hcdi->hcdi_cb_queue)) != NULL) {
806 usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data;
807 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
808
809 /* hold the pipe */
810 mutex_enter(&ph_impl->usba_ph_mutex);
811 ph_impl->usba_ph_ref_count++;
812 mutex_exit(&ph_impl->usba_ph_mutex);
813
814 /* do the callback */
815 usba_req_normal_cb(req_wrp);
816
817 /* decrement the soft interrupt count */
818 mutex_enter(&ph_data->p_mutex);
819 ph_data->p_soft_intr--;
820 mutex_exit(&ph_data->p_mutex);
821
822 /* release the pipe */
823 mutex_enter(&ph_impl->usba_ph_mutex);
824 ph_impl->usba_ph_ref_count--;
825 mutex_exit(&ph_impl->usba_ph_mutex);
826
827 count++;
828 }
829
830 return (count == 0 ? DDI_INTR_UNCLAIMED : DDI_INTR_CLAIMED);
831 }
832
833
834 /*
835 * hcdi_autoclearing:
836 * This function is called under the taskq context. It
837 * resets the pipe, and clears the stall, if necessary
838 */
839 static void
hcdi_autoclearing(usba_req_wrapper_t * req_wrp)840 hcdi_autoclearing(usba_req_wrapper_t *req_wrp)
841 {
842 usb_cr_t cr = req_wrp->wr_cr;
843 usb_pipe_handle_t pipe_handle, def_pipe_handle;
844 usb_cr_t completion_reason;
845 usb_cb_flags_t cb_flags;
846 int rval;
847 usba_device_t *usba_device =
848 req_wrp->wr_ph_data->p_usba_device;
849 usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(
850 usba_device->usb_root_hub_dip);
851 usb_req_attrs_t attrs = req_wrp->wr_attrs;
852
853 USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle,
854 "hcdi_autoclearing: wrp=0x%p", (void *)req_wrp);
855
856 pipe_handle = usba_get_pipe_handle(req_wrp->wr_ph_data);
857 def_pipe_handle = usba_get_dflt_pipe_handle(req_wrp->wr_ph_data->p_dip);
858
859 /*
860 * first reset the pipe synchronously
861 */
862 if ((attrs & USB_ATTRS_PIPE_RESET) == USB_ATTRS_PIPE_RESET) {
863 usba_pipe_clear(pipe_handle);
864 usba_req_set_cb_flags(req_wrp, USB_CB_RESET_PIPE);
865 }
866
867 ASSERT(def_pipe_handle);
868
869 /* Do not clear if this request was a usb_get_status request */
870 if ((pipe_handle == def_pipe_handle) &&
871 (USBA_WRP2CTRL_REQ(req_wrp)->ctrl_bRequest ==
872 USB_REQ_GET_STATUS)) {
873 USB_DPRINTF_L2(DPRINT_MASK_USBAI, hcdi->hcdi_log_handle,
874 "hcdi_autoclearing: usb_get_status failed, no clearing");
875
876 /* if default pipe and stall no auto clearing */
877 } else if ((pipe_handle == def_pipe_handle) && (cr == USB_CR_STALL)) {
878 USB_DPRINTF_L2(DPRINT_MASK_USBAI, hcdi->hcdi_log_handle,
879 "hcdi_autoclearing: default pipe stalled, no clearing");
880
881 usba_req_set_cb_flags(req_wrp, USB_CB_PROTOCOL_STALL);
882
883 /* else do auto clearing */
884 } else if (((attrs & USB_ATTRS_AUTOCLEARING) ==
885 USB_ATTRS_AUTOCLEARING) && (cr == USB_CR_STALL)) {
886 ushort_t status = 0;
887
888 rval = usb_get_status(req_wrp->wr_dip, def_pipe_handle,
889 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_EP,
890 req_wrp->wr_ph_data->p_ep.bEndpointAddress,
891 &status, USB_FLAGS_SLEEP);
892 if (rval != USB_SUCCESS) {
893 USB_DPRINTF_L2(DPRINT_MASK_USBAI, hcdi->hcdi_log_handle,
894 "get status (STALL) failed: rval=%d", rval);
895
896 usba_pipe_clear(def_pipe_handle);
897 }
898
899 if ((rval != USB_SUCCESS) ||
900 (status & USB_EP_HALT_STATUS)) {
901 usba_req_set_cb_flags(req_wrp, USB_CB_FUNCTIONAL_STALL);
902
903 if ((rval = usb_pipe_sync_ctrl_xfer(
904 req_wrp->wr_dip, def_pipe_handle,
905 USB_DEV_REQ_HOST_TO_DEV |
906 USB_DEV_REQ_RCPT_EP,
907 USB_REQ_CLEAR_FEATURE,
908 0,
909 req_wrp->wr_ph_data->p_ep.bEndpointAddress,
910 0,
911 NULL, 0,
912 &completion_reason,
913 &cb_flags, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
914 USB_DPRINTF_L2(DPRINT_MASK_USBAI,
915 hcdi->hcdi_log_handle,
916 "auto clearing (STALL) failed: "
917 "rval=%d, cr=0x%x cb=0x%x",
918 rval, completion_reason, cb_flags);
919
920 usba_pipe_clear(def_pipe_handle);
921 } else {
922 usba_req_set_cb_flags(req_wrp,
923 USB_CB_STALL_CLEARED);
924 }
925 } else {
926 usba_req_set_cb_flags(req_wrp, USB_CB_PROTOCOL_STALL);
927 }
928 }
929 }
930
931
932 /*
933 * usba_hcdi_get_req_private:
934 * This function is used to get the HCD private field
935 * maintained by USBA. HCD calls this function.
936 *
937 * Arguments:
938 * req - pointer to usb_*_req_t
939 *
940 * Return Values:
941 * wr_hcd_private field from wrapper
942 */
943 usb_opaque_t
usba_hcdi_get_req_private(usb_opaque_t req)944 usba_hcdi_get_req_private(usb_opaque_t req)
945 {
946 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req);
947
948 return (wrp->wr_hcd_private);
949 }
950
951
952 /*
953 * usba_hcdi_set_req_private:
954 * This function is used to set the HCD private field
955 * maintained by USBA. HCD calls this function.
956 *
957 * Arguments:
958 * req - pointer to usb_*_req_t
959 * hcd_private - wr_hcd_private field from wrapper
960 */
961 void
usba_hcdi_set_req_private(usb_opaque_t req,usb_opaque_t hcd_private)962 usba_hcdi_set_req_private(usb_opaque_t req,
963 usb_opaque_t hcd_private)
964 {
965 usba_req_wrapper_t *wrp = USBA_REQ2WRP(req);
966
967 wrp->wr_hcd_private = hcd_private;
968 }
969
970
971 /* get data toggle information for this endpoint */
972 uchar_t
usba_hcdi_get_data_toggle(usba_device_t * usba_device,uint8_t ep_addr)973 usba_hcdi_get_data_toggle(usba_device_t *usba_device, uint8_t ep_addr)
974 {
975 uchar_t toggle;
976 usba_ph_impl_t *ph_impl;
977 int ep_index;
978
979 ep_index = usb_get_ep_index(ep_addr);
980 mutex_enter(&usba_device->usb_mutex);
981 ph_impl = &usba_device->usb_ph_list[ep_index];
982 mutex_enter(&ph_impl->usba_ph_mutex);
983 toggle = (uchar_t)(ph_impl->usba_ph_flags & USBA_PH_DATA_TOGGLE);
984 mutex_exit(&ph_impl->usba_ph_mutex);
985 mutex_exit(&usba_device->usb_mutex);
986
987 return (toggle);
988 }
989
990
991 /* set data toggle information for this endpoint */
992 void
usba_hcdi_set_data_toggle(usba_device_t * usba_device,uint8_t ep_addr,uchar_t toggle)993 usba_hcdi_set_data_toggle(usba_device_t *usba_device, uint8_t ep_addr,
994 uchar_t toggle)
995 {
996 usba_ph_impl_t *ph_impl;
997 int ep_index;
998
999 ep_index = usb_get_ep_index(ep_addr);
1000 mutex_enter(&usba_device->usb_mutex);
1001 ph_impl = &usba_device->usb_ph_list[ep_index];
1002 mutex_enter(&ph_impl->usba_ph_mutex);
1003 ph_impl->usba_ph_flags &= ~USBA_PH_DATA_TOGGLE;
1004 ph_impl->usba_ph_flags |= (USBA_PH_DATA_TOGGLE & toggle);
1005 mutex_exit(&ph_impl->usba_ph_mutex);
1006 mutex_exit(&usba_device->usb_mutex);
1007 }
1008
1009
1010 /* get pipe_handle_impl ptr for this ep */
1011 usba_pipe_handle_data_t *
usba_hcdi_get_ph_data(usba_device_t * usba_device,uint8_t ep_addr)1012 usba_hcdi_get_ph_data(usba_device_t *usba_device, uint8_t ep_addr)
1013 {
1014 return (usba_device->usb_ph_list[usb_get_ep_index(ep_addr)].
1015 usba_ph_data);
1016 }
1017