10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * USBA: Solaris USB Architecture support 300Sstevel@tonic-gate * 310Sstevel@tonic-gate * hcdi.c contains the code for client driver callbacks. A host controller 320Sstevel@tonic-gate * driver registers/unregisters with usba through usba_hcdi_register/unregister. 330Sstevel@tonic-gate * 340Sstevel@tonic-gate * When the transfer has finished, the host controller driver will call into 350Sstevel@tonic-gate * usba with the result. The call is usba_hcdi_cb(). 360Sstevel@tonic-gate * 370Sstevel@tonic-gate * The callback queue is maintained in FIFO order. usba_hcdi_cb 380Sstevel@tonic-gate * adds to the queue, and hcdi_cb_thread takes the callbacks off the queue 390Sstevel@tonic-gate * and executes them. 400Sstevel@tonic-gate */ 410Sstevel@tonic-gate #define USBA_FRAMEWORK 420Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h> 430Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h> 440Sstevel@tonic-gate #include <sys/kstat.h> 450Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate /* function prototypes, XXXX use hcdi_ prefix? */ 480Sstevel@tonic-gate static void usba_hcdi_create_stats(usba_hcdi_t *, int); 490Sstevel@tonic-gate static void usba_hcdi_update_error_stats(usba_hcdi_t *, usb_cr_t); 500Sstevel@tonic-gate static void usba_hcdi_destroy_stats(usba_hcdi_t *); 510Sstevel@tonic-gate 520Sstevel@tonic-gate /* internal functions */ 530Sstevel@tonic-gate static uint_t hcdi_soft_intr(caddr_t arg1, caddr_t arg2); 540Sstevel@tonic-gate 550Sstevel@tonic-gate static void hcdi_cb_thread(void *); 560Sstevel@tonic-gate static void hcdi_shared_cb_thread(void *); 570Sstevel@tonic-gate static void hcdi_do_cb(usba_pipe_handle_data_t *, usba_req_wrapper_t *, 580Sstevel@tonic-gate usba_hcdi_t *); 590Sstevel@tonic-gate static void hcdi_autoclearing(usba_req_wrapper_t *); 600Sstevel@tonic-gate 610Sstevel@tonic-gate /* private function from USBAI */ 620Sstevel@tonic-gate void usba_pipe_clear(usb_pipe_handle_t); 630Sstevel@tonic-gate 640Sstevel@tonic-gate /* for debug messages */ 65880Sfrits uint_t hcdi_errmask = (uint_t)DPRINT_MASK_ALL; 66880Sfrits uint_t hcdi_errlevel = USB_LOG_L4; 67880Sfrits uint_t hcdi_instance_debug = (uint_t)-1; 680Sstevel@tonic-gate 690Sstevel@tonic-gate void 700Sstevel@tonic-gate usba_hcdi_initialization() 710Sstevel@tonic-gate { 720Sstevel@tonic-gate } 730Sstevel@tonic-gate 740Sstevel@tonic-gate 750Sstevel@tonic-gate void 760Sstevel@tonic-gate usba_hcdi_destroy() 770Sstevel@tonic-gate { 780Sstevel@tonic-gate } 790Sstevel@tonic-gate 800Sstevel@tonic-gate 810Sstevel@tonic-gate /* 820Sstevel@tonic-gate * store hcdi structure in the dip 830Sstevel@tonic-gate */ 840Sstevel@tonic-gate void 850Sstevel@tonic-gate usba_hcdi_set_hcdi(dev_info_t *dip, usba_hcdi_t *hcdi) 860Sstevel@tonic-gate { 870Sstevel@tonic-gate ddi_set_driver_private(dip, hcdi); 880Sstevel@tonic-gate } 890Sstevel@tonic-gate 900Sstevel@tonic-gate 910Sstevel@tonic-gate /* 920Sstevel@tonic-gate * retrieve hcdi structure from the dip 930Sstevel@tonic-gate */ 940Sstevel@tonic-gate usba_hcdi_t * 950Sstevel@tonic-gate usba_hcdi_get_hcdi(dev_info_t *dip) 960Sstevel@tonic-gate { 970Sstevel@tonic-gate return (ddi_get_driver_private(dip)); 980Sstevel@tonic-gate } 990Sstevel@tonic-gate 1000Sstevel@tonic-gate /* 1010Sstevel@tonic-gate * Called by an HCD to attach an instance of the driver 1020Sstevel@tonic-gate * make this instance known to USBA 1030Sstevel@tonic-gate * the HCD should initialize usba_hcdi structure prior 1040Sstevel@tonic-gate * to calling this interface 1050Sstevel@tonic-gate */ 1060Sstevel@tonic-gate int 1070Sstevel@tonic-gate usba_hcdi_register(usba_hcdi_register_args_t *args, uint_t flags) 1080Sstevel@tonic-gate { 1090Sstevel@tonic-gate char *datap; 1100Sstevel@tonic-gate uint_t soft_prip; 1110Sstevel@tonic-gate usba_hcdi_t *hcdi = kmem_zalloc(sizeof (usba_hcdi_t), KM_SLEEP); 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate if (args->usba_hcdi_register_version != HCDI_REGISTER_VERS_0) { 1140Sstevel@tonic-gate kmem_free(hcdi, sizeof (usba_hcdi_t)); 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate return (USB_FAILURE); 1170Sstevel@tonic-gate } 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate hcdi->hcdi_dip = args->usba_hcdi_register_dip; 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate /* 1220Sstevel@tonic-gate * Create a log_handle 1230Sstevel@tonic-gate */ 1240Sstevel@tonic-gate hcdi->hcdi_log_handle = usb_alloc_log_hdl(hcdi->hcdi_dip, NULL, 1250Sstevel@tonic-gate &hcdi_errlevel, &hcdi_errmask, &hcdi_instance_debug, 1260Sstevel@tonic-gate 0); 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle, 1290Sstevel@tonic-gate "usba_hcdi_register: %s", ddi_node_name(hcdi->hcdi_dip)); 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate /* 1320Sstevel@tonic-gate * Initialize the mutex. Use the iblock cookie passed in 1330Sstevel@tonic-gate * by the host controller driver. 1340Sstevel@tonic-gate */ 1350Sstevel@tonic-gate mutex_init(&hcdi->hcdi_mutex, NULL, MUTEX_DRIVER, 1360Sstevel@tonic-gate args->usba_hcdi_register_iblock_cookie); 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate /* add soft interrupt */ 1390Sstevel@tonic-gate if (ddi_intr_add_softint(hcdi->hcdi_dip, &hcdi->hcdi_softint_hdl, 1400Sstevel@tonic-gate DDI_INTR_SOFTPRI_MAX, hcdi_soft_intr, (caddr_t)hcdi) != 1410Sstevel@tonic-gate DDI_SUCCESS) { 1420Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle, 1430Sstevel@tonic-gate "usba_hcd_register: add soft interrupt failed"); 1440Sstevel@tonic-gate mutex_destroy(&hcdi->hcdi_mutex); 1450Sstevel@tonic-gate usb_free_log_hdl(hcdi->hcdi_log_handle); 1460Sstevel@tonic-gate kmem_free(hcdi, sizeof (usba_hcdi_t)); 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate return (USB_FAILURE); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate if (ddi_intr_get_softint_pri(hcdi->hcdi_softint_hdl, &soft_prip) != 1520Sstevel@tonic-gate DDI_SUCCESS) { 1530Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle, 1540Sstevel@tonic-gate "usba_hcd_register: get soft interrupt priority failed"); 1550Sstevel@tonic-gate (void) ddi_intr_remove_softint(hcdi->hcdi_softint_hdl); 1560Sstevel@tonic-gate mutex_destroy(&hcdi->hcdi_mutex); 1570Sstevel@tonic-gate usb_free_log_hdl(hcdi->hcdi_log_handle); 1580Sstevel@tonic-gate kmem_free(hcdi, sizeof (usba_hcdi_t)); 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate return (USB_FAILURE); 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate /* 1640Sstevel@tonic-gate * Priority and iblock_cookie are one and the same 1650Sstevel@tonic-gate * (However, retaining hcdi_soft_iblock_cookie for now 1660Sstevel@tonic-gate * assigning it w/ priority. In future all iblock_cookie 1670Sstevel@tonic-gate * could just go) 1680Sstevel@tonic-gate */ 1690Sstevel@tonic-gate hcdi->hcdi_soft_iblock_cookie = 17042Sagiri (ddi_iblock_cookie_t)(uintptr_t)soft_prip; 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate usba_init_list(&hcdi->hcdi_cb_queue, NULL, NULL); 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate hcdi->hcdi_dma_attr = args->usba_hcdi_register_dma_attr; 1750Sstevel@tonic-gate hcdi->hcdi_flags = flags; 1760Sstevel@tonic-gate hcdi->hcdi_ops = args->usba_hcdi_register_ops; 1770Sstevel@tonic-gate hcdi->hcdi_iblock_cookie = args->usba_hcdi_register_iblock_cookie; 1780Sstevel@tonic-gate usba_hcdi_create_stats(hcdi, ddi_get_instance(hcdi->hcdi_dip)); 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate hcdi->hcdi_min_xfer = hcdi->hcdi_dma_attr->dma_attr_minxfer; 1810Sstevel@tonic-gate hcdi->hcdi_min_burst_size = 1820Sstevel@tonic-gate (1<<(ddi_ffs(hcdi->hcdi_dma_attr->dma_attr_burstsizes)-1)); 1830Sstevel@tonic-gate hcdi->hcdi_max_burst_size = 1840Sstevel@tonic-gate (1<<(ddi_fls(hcdi->hcdi_dma_attr->dma_attr_burstsizes)-1)); 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate usba_hcdi_set_hcdi(hcdi->hcdi_dip, hcdi); 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, 1890Sstevel@tonic-gate hcdi->hcdi_dip, 1900Sstevel@tonic-gate DDI_PROP_DONTPASS, "ugen-default-binding", &datap) == 1910Sstevel@tonic-gate DDI_PROP_SUCCESS) { 1920Sstevel@tonic-gate if (strcmp(datap, "device") == 0) { 1930Sstevel@tonic-gate hcdi->hcdi_ugen_default_binding = 1940Sstevel@tonic-gate USBA_UGEN_DEVICE_BINDING; 1950Sstevel@tonic-gate } else if (strcmp(datap, "interface") == 0) { 1960Sstevel@tonic-gate hcdi->hcdi_ugen_default_binding = 1970Sstevel@tonic-gate USBA_UGEN_INTERFACE_BINDING; 1980Sstevel@tonic-gate } else { 199*978Sfrits USB_DPRINTF_L2(DPRINT_MASK_HCDI, 2000Sstevel@tonic-gate hcdi->hcdi_log_handle, 2010Sstevel@tonic-gate "illegal value (%s) for " 2020Sstevel@tonic-gate "ugen_default_binding property", 2030Sstevel@tonic-gate datap); 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate ddi_prop_free(datap); 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate return (USB_SUCCESS); 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate /* 2130Sstevel@tonic-gate * Called by an HCD to detach an instance of the driver 2140Sstevel@tonic-gate */ 2150Sstevel@tonic-gate /*ARGSUSED*/ 2160Sstevel@tonic-gate void 2170Sstevel@tonic-gate usba_hcdi_unregister(dev_info_t *dip) 2180Sstevel@tonic-gate { 2190Sstevel@tonic-gate usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip); 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate if (hcdi) { 2220Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle, 2230Sstevel@tonic-gate "usba_hcdi_unregister: %s", ddi_node_name(dip)); 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate usba_hcdi_set_hcdi(dip, NULL); 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate mutex_destroy(&hcdi->hcdi_mutex); 2280Sstevel@tonic-gate usba_hcdi_destroy_stats(hcdi); 2290Sstevel@tonic-gate usb_free_log_hdl(hcdi->hcdi_log_handle); 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate /* Destroy the soft interrupt */ 2320Sstevel@tonic-gate (void) ddi_intr_remove_softint(hcdi->hcdi_softint_hdl); 2330Sstevel@tonic-gate kmem_free(hcdi, sizeof (usba_hcdi_t)); 2340Sstevel@tonic-gate } 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate /* 2390Sstevel@tonic-gate * alloc usba_hcdi_ops structure 2400Sstevel@tonic-gate * called from the HCD attach routine 2410Sstevel@tonic-gate */ 2420Sstevel@tonic-gate usba_hcdi_ops_t * 2430Sstevel@tonic-gate usba_alloc_hcdi_ops() 2440Sstevel@tonic-gate { 2450Sstevel@tonic-gate usba_hcdi_ops_t *usba_hcdi_ops; 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate usba_hcdi_ops = kmem_zalloc(sizeof (usba_hcdi_ops_t), KM_SLEEP); 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate return (usba_hcdi_ops); 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate /* 2540Sstevel@tonic-gate * dealloc usba_hcdi_ops structure 2550Sstevel@tonic-gate */ 2560Sstevel@tonic-gate void 2570Sstevel@tonic-gate usba_free_hcdi_ops(usba_hcdi_ops_t *hcdi_ops) 2580Sstevel@tonic-gate { 2590Sstevel@tonic-gate if (hcdi_ops) { 2600Sstevel@tonic-gate kmem_free(hcdi_ops, sizeof (usba_hcdi_ops_t)); 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate /* 2660Sstevel@tonic-gate * Allocate the hotplug kstats structure 2670Sstevel@tonic-gate */ 2680Sstevel@tonic-gate void 2690Sstevel@tonic-gate usba_hcdi_create_stats(usba_hcdi_t *hcdi, int instance) 2700Sstevel@tonic-gate { 2710Sstevel@tonic-gate char kstatname[KSTAT_STRLEN]; 2720Sstevel@tonic-gate const char *dname = ddi_driver_name(hcdi->hcdi_dip); 2730Sstevel@tonic-gate hcdi_hotplug_stats_t *hsp; 2740Sstevel@tonic-gate hcdi_error_stats_t *esp; 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate if (HCDI_HOTPLUG_STATS(hcdi) == NULL) { 2770Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,hotplug", 2780Sstevel@tonic-gate dname, instance); 2790Sstevel@tonic-gate HCDI_HOTPLUG_STATS(hcdi) = kstat_create("usba", instance, 2800Sstevel@tonic-gate kstatname, "usb_hotplug", KSTAT_TYPE_NAMED, 2810Sstevel@tonic-gate sizeof (hcdi_hotplug_stats_t) / sizeof (kstat_named_t), 2820Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate if (HCDI_HOTPLUG_STATS(hcdi) == NULL) { 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate return; 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate hsp = HCDI_HOTPLUG_STATS_DATA(hcdi); 2900Sstevel@tonic-gate kstat_named_init(&hsp->hcdi_hotplug_total_success, 2910Sstevel@tonic-gate "Total Hotplug Successes", KSTAT_DATA_UINT64); 2920Sstevel@tonic-gate kstat_named_init(&hsp->hcdi_hotplug_success, 2930Sstevel@tonic-gate "Hotplug Successes", KSTAT_DATA_UINT64); 2940Sstevel@tonic-gate kstat_named_init(&hsp->hcdi_hotplug_total_failure, 2950Sstevel@tonic-gate "Hotplug Total Failures", KSTAT_DATA_UINT64); 2960Sstevel@tonic-gate kstat_named_init(&hsp->hcdi_hotplug_failure, 2970Sstevel@tonic-gate "Hotplug Failures", KSTAT_DATA_UINT64); 2980Sstevel@tonic-gate kstat_named_init(&hsp->hcdi_device_count, 2990Sstevel@tonic-gate "Device Count", KSTAT_DATA_UINT64); 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate HCDI_HOTPLUG_STATS(hcdi)->ks_private = hcdi; 3020Sstevel@tonic-gate HCDI_HOTPLUG_STATS(hcdi)->ks_update = nulldev; 3030Sstevel@tonic-gate kstat_install(HCDI_HOTPLUG_STATS(hcdi)); 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate if (HCDI_ERROR_STATS(hcdi) == NULL) { 3070Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,error", 3080Sstevel@tonic-gate dname, instance); 3090Sstevel@tonic-gate HCDI_ERROR_STATS(hcdi) = kstat_create("usba", instance, 3100Sstevel@tonic-gate kstatname, "usb_errors", KSTAT_TYPE_NAMED, 3110Sstevel@tonic-gate sizeof (hcdi_error_stats_t) / sizeof (kstat_named_t), 3120Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate if (HCDI_ERROR_STATS(hcdi) == NULL) { 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate return; 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate esp = HCDI_ERROR_STATS_DATA(hcdi); 3200Sstevel@tonic-gate kstat_named_init(&esp->cc_crc, "CRC Errors", KSTAT_DATA_UINT64); 3210Sstevel@tonic-gate kstat_named_init(&esp->cc_bitstuffing, 3220Sstevel@tonic-gate "Bit Stuffing Violations", KSTAT_DATA_UINT64); 3230Sstevel@tonic-gate kstat_named_init(&esp->cc_data_toggle_mm, 3240Sstevel@tonic-gate "Data Toggle PID Errors", KSTAT_DATA_UINT64); 3250Sstevel@tonic-gate kstat_named_init(&esp->cc_stall, 3260Sstevel@tonic-gate "Endpoint Stalls", KSTAT_DATA_UINT64); 3270Sstevel@tonic-gate kstat_named_init(&esp->cc_dev_not_resp, 3280Sstevel@tonic-gate "Device Not Responding", KSTAT_DATA_UINT64); 3290Sstevel@tonic-gate kstat_named_init(&esp->cc_pid_checkfailure, 3300Sstevel@tonic-gate "PID Check Bit Errors", KSTAT_DATA_UINT64); 3310Sstevel@tonic-gate kstat_named_init(&esp->cc_unexp_pid, 3320Sstevel@tonic-gate "Invalid PID Errors", KSTAT_DATA_UINT64); 3330Sstevel@tonic-gate kstat_named_init(&esp->cc_data_overrun, 3340Sstevel@tonic-gate "Data Overruns", KSTAT_DATA_UINT64); 3350Sstevel@tonic-gate kstat_named_init(&esp->cc_data_underrun, 3360Sstevel@tonic-gate "Data Underruns", KSTAT_DATA_UINT64); 3370Sstevel@tonic-gate kstat_named_init(&esp->cc_buffer_overrun, 3380Sstevel@tonic-gate "Buffer Overruns", KSTAT_DATA_UINT64); 3390Sstevel@tonic-gate kstat_named_init(&esp->cc_buffer_underrun, 3400Sstevel@tonic-gate "Buffer Underruns", KSTAT_DATA_UINT64); 3410Sstevel@tonic-gate kstat_named_init(&esp->cc_timeout, 3420Sstevel@tonic-gate "Command Timed Out", KSTAT_DATA_UINT64); 3430Sstevel@tonic-gate kstat_named_init(&esp->cc_not_accessed, 3440Sstevel@tonic-gate "Not Accessed By Hardware", KSTAT_DATA_UINT64); 3450Sstevel@tonic-gate kstat_named_init(&esp->cc_unspecified_err, 3460Sstevel@tonic-gate "Unspecified Error", KSTAT_DATA_UINT64); 3470Sstevel@tonic-gate #ifdef NOTYETNEEDED 3480Sstevel@tonic-gate kstat_named_init(&esp->hcdi_usb_failure, 3490Sstevel@tonic-gate "USB Failure", KSTAT_DATA_UINT64); 3500Sstevel@tonic-gate kstat_named_init(&esp->hcdi_usb_no_resources, 3510Sstevel@tonic-gate "No Resources", KSTAT_DATA_UINT64); 3520Sstevel@tonic-gate kstat_named_init(&esp->hcdi_usb_no_bandwidth, 3530Sstevel@tonic-gate "No Bandwidth", KSTAT_DATA_UINT64); 3540Sstevel@tonic-gate kstat_named_init(&esp->hcdi_usb_pipe_reserved, 3550Sstevel@tonic-gate "Pipe Reserved", KSTAT_DATA_UINT64); 3560Sstevel@tonic-gate kstat_named_init(&esp->hcdi_usb_pipe_unshareable, 3570Sstevel@tonic-gate "Pipe Unshareable", KSTAT_DATA_UINT64); 3580Sstevel@tonic-gate kstat_named_init(&esp->hcdi_usb_not_supported, 3590Sstevel@tonic-gate "Function Not Supported", KSTAT_DATA_UINT64); 3600Sstevel@tonic-gate kstat_named_init(&esp->hcdi_usb_pipe_error, 3610Sstevel@tonic-gate "Pipe Error", KSTAT_DATA_UINT64); 3620Sstevel@tonic-gate kstat_named_init(&esp->hcdi_usb_pipe_busy, 3630Sstevel@tonic-gate "Pipe Busy", KSTAT_DATA_UINT64); 3640Sstevel@tonic-gate #endif 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate HCDI_ERROR_STATS(hcdi)->ks_private = hcdi; 3670Sstevel@tonic-gate HCDI_ERROR_STATS(hcdi)->ks_update = nulldev; 3680Sstevel@tonic-gate kstat_install(HCDI_ERROR_STATS(hcdi)); 3690Sstevel@tonic-gate } 3700Sstevel@tonic-gate } 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate /* 3740Sstevel@tonic-gate * Do actual error stats 3750Sstevel@tonic-gate */ 3760Sstevel@tonic-gate void 3770Sstevel@tonic-gate usba_hcdi_update_error_stats(usba_hcdi_t *hcdi, usb_cr_t completion_reason) 3780Sstevel@tonic-gate { 3790Sstevel@tonic-gate if (HCDI_ERROR_STATS(hcdi) == NULL) { 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate return; 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate switch (completion_reason) { 3850Sstevel@tonic-gate case USB_CR_OK: 3860Sstevel@tonic-gate break; 3870Sstevel@tonic-gate case USB_CR_CRC: 3880Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_crc.value.ui64++; 3890Sstevel@tonic-gate break; 3900Sstevel@tonic-gate case USB_CR_BITSTUFFING: 3910Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_bitstuffing.value.ui64++; 3920Sstevel@tonic-gate break; 3930Sstevel@tonic-gate case USB_CR_DATA_TOGGLE_MM: 3940Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_data_toggle_mm.value.ui64++; 3950Sstevel@tonic-gate break; 3960Sstevel@tonic-gate case USB_CR_STALL: 3970Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_stall.value.ui64++; 3980Sstevel@tonic-gate break; 3990Sstevel@tonic-gate case USB_CR_DEV_NOT_RESP: 4000Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_dev_not_resp.value.ui64++; 4010Sstevel@tonic-gate break; 4020Sstevel@tonic-gate case USB_CR_PID_CHECKFAILURE: 4030Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_pid_checkfailure.value.ui64++; 4040Sstevel@tonic-gate break; 4050Sstevel@tonic-gate case USB_CR_UNEXP_PID: 4060Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_unexp_pid.value.ui64++; 4070Sstevel@tonic-gate break; 4080Sstevel@tonic-gate case USB_CR_DATA_OVERRUN: 4090Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_data_overrun.value.ui64++; 4100Sstevel@tonic-gate break; 4110Sstevel@tonic-gate case USB_CR_DATA_UNDERRUN: 4120Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_data_underrun.value.ui64++; 4130Sstevel@tonic-gate break; 4140Sstevel@tonic-gate case USB_CR_BUFFER_OVERRUN: 4150Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_buffer_overrun.value.ui64++; 4160Sstevel@tonic-gate break; 4170Sstevel@tonic-gate case USB_CR_BUFFER_UNDERRUN: 4180Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_buffer_underrun.value.ui64++; 4190Sstevel@tonic-gate break; 4200Sstevel@tonic-gate case USB_CR_TIMEOUT: 4210Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_timeout.value.ui64++; 4220Sstevel@tonic-gate break; 4230Sstevel@tonic-gate case USB_CR_NOT_ACCESSED: 4240Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_not_accessed.value.ui64++; 4250Sstevel@tonic-gate break; 4260Sstevel@tonic-gate case USB_CR_NO_RESOURCES: 4270Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_no_resources.value.ui64++; 4280Sstevel@tonic-gate break; 4290Sstevel@tonic-gate case USB_CR_UNSPECIFIED_ERR: 4300Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_unspecified_err.value.ui64++; 4310Sstevel@tonic-gate break; 4320Sstevel@tonic-gate case USB_CR_STOPPED_POLLING: 4330Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_stopped_polling.value.ui64++; 4340Sstevel@tonic-gate break; 4350Sstevel@tonic-gate case USB_CR_PIPE_CLOSING: 4360Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_pipe_closing.value.ui64++; 4370Sstevel@tonic-gate break; 4380Sstevel@tonic-gate case USB_CR_PIPE_RESET: 4390Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_pipe_reset.value.ui64++; 4400Sstevel@tonic-gate break; 4410Sstevel@tonic-gate case USB_CR_NOT_SUPPORTED: 4420Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_not_supported.value.ui64++; 4430Sstevel@tonic-gate break; 4440Sstevel@tonic-gate case USB_CR_FLUSHED: 4450Sstevel@tonic-gate HCDI_ERROR_STATS_DATA(hcdi)->cc_flushed.value.ui64++; 4460Sstevel@tonic-gate break; 4470Sstevel@tonic-gate default: 4480Sstevel@tonic-gate break; 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate /* 4540Sstevel@tonic-gate * Destroy the hotplug kstats structure 4550Sstevel@tonic-gate */ 4560Sstevel@tonic-gate static void 4570Sstevel@tonic-gate usba_hcdi_destroy_stats(usba_hcdi_t *hcdi) 4580Sstevel@tonic-gate { 4590Sstevel@tonic-gate if (HCDI_HOTPLUG_STATS(hcdi)) { 4600Sstevel@tonic-gate kstat_delete(HCDI_HOTPLUG_STATS(hcdi)); 4610Sstevel@tonic-gate HCDI_HOTPLUG_STATS(hcdi) = NULL; 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate if (HCDI_ERROR_STATS(hcdi)) { 4650Sstevel@tonic-gate kstat_delete(HCDI_ERROR_STATS(hcdi)); 4660Sstevel@tonic-gate HCDI_ERROR_STATS(hcdi) = NULL; 4670Sstevel@tonic-gate } 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate /* 4720Sstevel@tonic-gate * HCD callback handling 4730Sstevel@tonic-gate */ 4740Sstevel@tonic-gate void 4750Sstevel@tonic-gate usba_hcdi_cb(usba_pipe_handle_data_t *ph_data, 4760Sstevel@tonic-gate usb_opaque_t req, 4770Sstevel@tonic-gate usb_cr_t completion_reason) 4780Sstevel@tonic-gate { 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate usba_device_t *usba_device = ph_data->p_usba_device; 4810Sstevel@tonic-gate usba_hcdi_t *hcdi = usba_hcdi_get_hcdi( 4820Sstevel@tonic-gate usba_device->usb_root_hub_dip); 4830Sstevel@tonic-gate usba_req_wrapper_t *req_wrp = USBA_REQ2WRP(req); 4840Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph_data->p_ep; 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate #ifdef DEBUG 4890Sstevel@tonic-gate mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex); 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle, 4920Sstevel@tonic-gate "usba_hcdi_cb: " 4930Sstevel@tonic-gate "ph_data=0x%p req=0x%p state=%d ref=%d cnt=%d cr=%d", 4940Sstevel@tonic-gate ph_data, req, ph_data->p_ph_impl->usba_ph_state, 4950Sstevel@tonic-gate ph_data->p_ph_impl->usba_ph_ref_count, ph_data->p_req_count, 4960Sstevel@tonic-gate completion_reason); 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex); 4990Sstevel@tonic-gate #endif 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate /* Set the completion reason */ 5020Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 5030Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 5040Sstevel@tonic-gate ((usb_ctrl_req_t *)req)-> 5050Sstevel@tonic-gate ctrl_completion_reason = completion_reason; 5060Sstevel@tonic-gate break; 5070Sstevel@tonic-gate case USB_EP_ATTR_BULK: 5080Sstevel@tonic-gate ((usb_bulk_req_t *)req)-> 5090Sstevel@tonic-gate bulk_completion_reason = completion_reason; 5100Sstevel@tonic-gate break; 5110Sstevel@tonic-gate case USB_EP_ATTR_INTR: 5120Sstevel@tonic-gate ((usb_intr_req_t *)req)-> 5130Sstevel@tonic-gate intr_completion_reason = completion_reason; 5140Sstevel@tonic-gate break; 5150Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 5160Sstevel@tonic-gate ((usb_isoc_req_t *)req)-> 5170Sstevel@tonic-gate isoc_completion_reason = completion_reason; 5180Sstevel@tonic-gate break; 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate /* 5220Sstevel@tonic-gate * exception callbacks will still go thru a taskq thread 5230Sstevel@tonic-gate * but should occur after the soft interrupt callback 5240Sstevel@tonic-gate * By design of periodic pipes, polling will stop on any 5250Sstevel@tonic-gate * exception 5260Sstevel@tonic-gate */ 5270Sstevel@tonic-gate if ((ph_data->p_spec_flag & USBA_PH_FLAG_USE_SOFT_INTR) && 5280Sstevel@tonic-gate (completion_reason == USB_CR_OK)) { 5290Sstevel@tonic-gate ph_data->p_soft_intr++; 5300Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate usba_add_to_list(&hcdi->hcdi_cb_queue, &req_wrp->wr_queue); 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate if (ddi_intr_trigger_softint(hcdi->hcdi_softint_hdl, NULL) != 5350Sstevel@tonic-gate DDI_SUCCESS) 5360Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle, 5370Sstevel@tonic-gate "usba_hcdi_cb: ddi_intr_trigger_softint failed"); 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate return; 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate /* 5430Sstevel@tonic-gate * USBA_PH_FLAG_TQ_SHARE is for bulk and intr requests, 5440Sstevel@tonic-gate * USBA_PH_FLAG_USE_SOFT_INTR is only for isoch, 5450Sstevel@tonic-gate * so there are no conflicts. 5460Sstevel@tonic-gate */ 5470Sstevel@tonic-gate if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) { 5480Sstevel@tonic-gate int iface; 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 5510Sstevel@tonic-gate iface = usb_get_if_number(ph_data->p_dip); 5520Sstevel@tonic-gate if (iface < 0) { 5530Sstevel@tonic-gate /* we own the device, use the first taskq */ 5540Sstevel@tonic-gate iface = 0; 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate if (taskq_dispatch(usba_device->usb_shared_taskq[iface], 5570Sstevel@tonic-gate hcdi_shared_cb_thread, req_wrp, TQ_NOSLEEP) == 5580Sstevel@tonic-gate NULL) { 5590Sstevel@tonic-gate usba_req_exc_cb(req_wrp, 5600Sstevel@tonic-gate USB_CR_NO_RESOURCES, USB_CB_ASYNC_REQ_FAILED); 5610Sstevel@tonic-gate } 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate return; 5640Sstevel@tonic-gate } 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate /* Add the callback to the pipehandles callback list */ 5670Sstevel@tonic-gate usba_add_to_list(&ph_data->p_cb_queue, &req_wrp->wr_queue); 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate /* only dispatch if there is no thread running */ 5700Sstevel@tonic-gate if (ph_data->p_thread_id == 0) { 5710Sstevel@tonic-gate if (usba_async_ph_req(ph_data, hcdi_cb_thread, 5720Sstevel@tonic-gate ph_data, USB_FLAGS_NOSLEEP) != USB_SUCCESS) { 5730Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle, 5740Sstevel@tonic-gate "usba_hcdi_cb: taskq_dispatch failed"); 5750Sstevel@tonic-gate if (usba_rm_from_list(&ph_data->p_cb_queue, 5760Sstevel@tonic-gate &req_wrp->wr_queue) == USB_SUCCESS) { 5770Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 5780Sstevel@tonic-gate usba_req_exc_cb(req_wrp, 5790Sstevel@tonic-gate USB_CR_NO_RESOURCES, 5800Sstevel@tonic-gate USB_CB_ASYNC_REQ_FAILED); 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate return; 5830Sstevel@tonic-gate } 5840Sstevel@tonic-gate } else { 5850Sstevel@tonic-gate ph_data->p_thread_id = (kthread_t *)1; 5860Sstevel@tonic-gate } 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 5890Sstevel@tonic-gate } 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate /* 5930Sstevel@tonic-gate * thread to perform the callbacks 5940Sstevel@tonic-gate */ 5950Sstevel@tonic-gate static void 5960Sstevel@tonic-gate hcdi_cb_thread(void *arg) 5970Sstevel@tonic-gate { 5980Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = 5990Sstevel@tonic-gate (usba_pipe_handle_data_t *)arg; 6000Sstevel@tonic-gate usba_ph_impl_t *ph_impl = ph_data->p_ph_impl; 6010Sstevel@tonic-gate usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(ph_data-> 6020Sstevel@tonic-gate p_usba_device->usb_root_hub_dip); 6030Sstevel@tonic-gate usba_req_wrapper_t *req_wrp; 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 6060Sstevel@tonic-gate ASSERT(ph_data->p_thread_id == (kthread_t *)1); 6070Sstevel@tonic-gate ph_data->p_thread_id = curthread; 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate /* 6100Sstevel@tonic-gate * hold the ph_data. we can't use usba_hold_ph_data() since 6110Sstevel@tonic-gate * it will return NULL if we are closing the pipe which would 6120Sstevel@tonic-gate * then leave all requests stuck in the cb_queue 6130Sstevel@tonic-gate */ 6140Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 6150Sstevel@tonic-gate ph_impl->usba_ph_ref_count++; 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle, 6180Sstevel@tonic-gate "hcdi_cb_thread: ph_data=0x%p ref=%d", ph_data, 6190Sstevel@tonic-gate ph_impl->usba_ph_ref_count); 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate /* 6240Sstevel@tonic-gate * wait till soft interrupt callbacks are taken care of 6250Sstevel@tonic-gate */ 6260Sstevel@tonic-gate while (ph_data->p_soft_intr) { 6270Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 6280Sstevel@tonic-gate delay(1); 6290Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 6300Sstevel@tonic-gate } 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate while ((req_wrp = (usba_req_wrapper_t *) 6330Sstevel@tonic-gate usba_rm_first_pvt_from_list(&ph_data->p_cb_queue)) != NULL) { 6340Sstevel@tonic-gate hcdi_do_cb(ph_data, req_wrp, hcdi); 6350Sstevel@tonic-gate } 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate ph_data->p_thread_id = 0; 6380Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle, 6410Sstevel@tonic-gate "hcdi_cb_thread done: ph_data=0x%p", ph_data); 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate usba_release_ph_data(ph_impl); 6440Sstevel@tonic-gate } 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate static void 6480Sstevel@tonic-gate hcdi_do_cb(usba_pipe_handle_data_t *ph_data, usba_req_wrapper_t *req_wrp, 6490Sstevel@tonic-gate usba_hcdi_t *hcdi) 6500Sstevel@tonic-gate { 6510Sstevel@tonic-gate usb_cr_t completion_reason; 6520Sstevel@tonic-gate usb_req_attrs_t attrs = req_wrp->wr_attrs; 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate switch (req_wrp->wr_ph_data->p_ep.bmAttributes & 6550Sstevel@tonic-gate USB_EP_ATTR_MASK) { 6560Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 6570Sstevel@tonic-gate completion_reason = 6580Sstevel@tonic-gate USBA_WRP2CTRL_REQ(req_wrp)->ctrl_completion_reason; 6590Sstevel@tonic-gate break; 6600Sstevel@tonic-gate case USB_EP_ATTR_INTR: 6610Sstevel@tonic-gate completion_reason = 6620Sstevel@tonic-gate USBA_WRP2INTR_REQ(req_wrp)->intr_completion_reason; 6630Sstevel@tonic-gate break; 6640Sstevel@tonic-gate case USB_EP_ATTR_BULK: 6650Sstevel@tonic-gate completion_reason = 6660Sstevel@tonic-gate USBA_WRP2BULK_REQ(req_wrp)->bulk_completion_reason; 6670Sstevel@tonic-gate break; 6680Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 6690Sstevel@tonic-gate completion_reason = 6700Sstevel@tonic-gate USBA_WRP2ISOC_REQ(req_wrp)->isoc_completion_reason; 6710Sstevel@tonic-gate break; 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate req_wrp->wr_cr = completion_reason; 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle, 6760Sstevel@tonic-gate "hcdi_do_cb: wrp=0x%p cr=0x%x", req_wrp, completion_reason); 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate /* 6790Sstevel@tonic-gate * Normal callbacks: 6800Sstevel@tonic-gate */ 6810Sstevel@tonic-gate if (completion_reason == USB_CR_OK) { 6820Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 6830Sstevel@tonic-gate usba_req_normal_cb(req_wrp); 6840Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 6850Sstevel@tonic-gate } else { 6860Sstevel@tonic-gate usb_pipe_state_t pipe_state; 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle, 6890Sstevel@tonic-gate "exception callback handling: attrs=0x%x", attrs); 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate /* 6920Sstevel@tonic-gate * In exception callback handling, if we were 6930Sstevel@tonic-gate * not able to clear stall, we need to modify 6940Sstevel@tonic-gate * pipe state. Also if auto-clearing is not set 6950Sstevel@tonic-gate * pipe state needs to be modified. 6960Sstevel@tonic-gate */ 6970Sstevel@tonic-gate pipe_state = usba_get_ph_state(ph_data); 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate if (!USBA_PIPE_CLOSING(pipe_state)) { 7000Sstevel@tonic-gate switch (completion_reason) { 7010Sstevel@tonic-gate case USB_CR_STOPPED_POLLING: 7020Sstevel@tonic-gate if (pipe_state == 7030Sstevel@tonic-gate USB_PIPE_STATE_ACTIVE) { 7040Sstevel@tonic-gate usba_pipe_new_state(ph_data, 7050Sstevel@tonic-gate USB_PIPE_STATE_IDLE); 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate break; 7080Sstevel@tonic-gate case USB_CR_NOT_SUPPORTED: 7090Sstevel@tonic-gate usba_pipe_new_state(ph_data, 7100Sstevel@tonic-gate USB_PIPE_STATE_IDLE); 7110Sstevel@tonic-gate break; 7120Sstevel@tonic-gate case USB_CR_PIPE_RESET: 7130Sstevel@tonic-gate case USB_CR_FLUSHED: 7140Sstevel@tonic-gate break; 7150Sstevel@tonic-gate default: 7160Sstevel@tonic-gate usba_pipe_new_state(ph_data, 7170Sstevel@tonic-gate USB_PIPE_STATE_ERROR); 7180Sstevel@tonic-gate break; 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate pipe_state = usba_get_ph_state(ph_data); 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 7250Sstevel@tonic-gate if (attrs & USB_ATTRS_PIPE_RESET) { 7260Sstevel@tonic-gate if ((completion_reason != USB_CR_PIPE_RESET) && 7270Sstevel@tonic-gate (pipe_state == USB_PIPE_STATE_ERROR)) { 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate hcdi_autoclearing(req_wrp); 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate } 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate usba_req_exc_cb(req_wrp, 0, 0); 7340Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 7350Sstevel@tonic-gate } 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate /* Update the hcdi error kstats */ 7380Sstevel@tonic-gate if (completion_reason) { 7390Sstevel@tonic-gate mutex_enter(&hcdi->hcdi_mutex); 7400Sstevel@tonic-gate usba_hcdi_update_error_stats(hcdi, completion_reason); 7410Sstevel@tonic-gate mutex_exit(&hcdi->hcdi_mutex); 7420Sstevel@tonic-gate } 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate /* 7450Sstevel@tonic-gate * Once the callback is finished, release the pipe handle 7460Sstevel@tonic-gate * we start the next request first to avoid that the 7470Sstevel@tonic-gate * pipe gets closed while starting the next request 7480Sstevel@tonic-gate */ 7490Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 7500Sstevel@tonic-gate usba_start_next_req(ph_data); 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate /* 7570Sstevel@tonic-gate * thread to perform callbacks on the shared queue 7580Sstevel@tonic-gate */ 7590Sstevel@tonic-gate static void 7600Sstevel@tonic-gate hcdi_shared_cb_thread(void *arg) 7610Sstevel@tonic-gate { 7620Sstevel@tonic-gate usba_req_wrapper_t *req_wrp = (usba_req_wrapper_t *)arg; 7630Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data; 7640Sstevel@tonic-gate usba_ph_impl_t *ph_impl = ph_data->p_ph_impl; 7650Sstevel@tonic-gate usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(ph_data-> 7660Sstevel@tonic-gate p_usba_device->usb_root_hub_dip); 7670Sstevel@tonic-gate /* 7680Sstevel@tonic-gate * hold the ph_data. we can't use usba_hold_ph_data() since 7690Sstevel@tonic-gate * it will return NULL if we are closing the pipe which would 7700Sstevel@tonic-gate * then leave all requests stuck in the cb_queue 7710Sstevel@tonic-gate */ 7720Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 7730Sstevel@tonic-gate ph_impl->usba_ph_ref_count++; 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle, 7760Sstevel@tonic-gate "hcdi_shared_cb_thread: ph_data=0x%p ref=%d req=0x%p", 7770Sstevel@tonic-gate ph_data, ph_impl->usba_ph_ref_count, req_wrp); 7780Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 7790Sstevel@tonic-gate 7800Sstevel@tonic-gate /* do the callback */ 7810Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 7820Sstevel@tonic-gate hcdi_do_cb(ph_data, req_wrp, hcdi); 7830Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 7840Sstevel@tonic-gate 7850Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle, 7860Sstevel@tonic-gate "hcdi_cb_thread done: ph_data=0x%p", ph_data); 7870Sstevel@tonic-gate 7880Sstevel@tonic-gate usba_release_ph_data(ph_impl); 7890Sstevel@tonic-gate } 7900Sstevel@tonic-gate 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate /* 7930Sstevel@tonic-gate * soft interrupt handler 7940Sstevel@tonic-gate */ 7950Sstevel@tonic-gate /*ARGSUSED*/ 7960Sstevel@tonic-gate static uint_t 7970Sstevel@tonic-gate hcdi_soft_intr(caddr_t arg1, caddr_t arg2) 7980Sstevel@tonic-gate { 7990Sstevel@tonic-gate usba_hcdi_t *hcdi = (usba_hcdi_t *)arg1; 8000Sstevel@tonic-gate usba_req_wrapper_t *req_wrp; 8010Sstevel@tonic-gate int count = 0; 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate while ((req_wrp = (usba_req_wrapper_t *) 8040Sstevel@tonic-gate usba_rm_first_pvt_from_list(&hcdi->hcdi_cb_queue)) != NULL) { 8050Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data; 8060Sstevel@tonic-gate usba_ph_impl_t *ph_impl = ph_data->p_ph_impl; 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate /* hold the pipe */ 8090Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 8100Sstevel@tonic-gate ph_impl->usba_ph_ref_count++; 8110Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate /* do the callback */ 8140Sstevel@tonic-gate usba_req_normal_cb(req_wrp); 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate /* decrement the soft interrupt count */ 8170Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 8180Sstevel@tonic-gate ph_data->p_soft_intr--; 8190Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate /* release the pipe */ 8220Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 8230Sstevel@tonic-gate ph_impl->usba_ph_ref_count--; 8240Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate count++; 8270Sstevel@tonic-gate } 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate return (count == 0 ? DDI_INTR_UNCLAIMED : DDI_INTR_CLAIMED); 8300Sstevel@tonic-gate } 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate /* 8340Sstevel@tonic-gate * hcdi_autoclearing: 8350Sstevel@tonic-gate * This function is called under the taskq context. It 8360Sstevel@tonic-gate * resets the pipe, and clears the stall, if necessary 8370Sstevel@tonic-gate */ 8380Sstevel@tonic-gate static void 8390Sstevel@tonic-gate hcdi_autoclearing(usba_req_wrapper_t *req_wrp) 8400Sstevel@tonic-gate { 8410Sstevel@tonic-gate usb_cr_t cr = req_wrp->wr_cr; 8420Sstevel@tonic-gate usb_pipe_handle_t pipe_handle, def_pipe_handle; 8430Sstevel@tonic-gate usb_cr_t completion_reason; 8440Sstevel@tonic-gate usb_cb_flags_t cb_flags; 8450Sstevel@tonic-gate int rval; 8460Sstevel@tonic-gate usba_device_t *usba_device = 8470Sstevel@tonic-gate req_wrp->wr_ph_data->p_usba_device; 8480Sstevel@tonic-gate usba_hcdi_t *hcdi = usba_hcdi_get_hcdi( 8490Sstevel@tonic-gate usba_device->usb_root_hub_dip); 8500Sstevel@tonic-gate usb_req_attrs_t attrs = req_wrp->wr_attrs; 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_HCDI, hcdi->hcdi_log_handle, 8530Sstevel@tonic-gate "hcdi_autoclearing: wrp=0x%p", req_wrp); 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate pipe_handle = usba_get_pipe_handle(req_wrp->wr_ph_data); 8560Sstevel@tonic-gate def_pipe_handle = usba_get_dflt_pipe_handle(req_wrp->wr_ph_data->p_dip); 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate /* 8590Sstevel@tonic-gate * first reset the pipe synchronously 8600Sstevel@tonic-gate */ 8610Sstevel@tonic-gate if ((attrs & USB_ATTRS_PIPE_RESET) == USB_ATTRS_PIPE_RESET) { 8620Sstevel@tonic-gate usba_pipe_clear(pipe_handle); 8630Sstevel@tonic-gate usba_req_set_cb_flags(req_wrp, USB_CB_RESET_PIPE); 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate ASSERT(def_pipe_handle); 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate /* Do not clear if this request was a usb_get_status request */ 8690Sstevel@tonic-gate if ((pipe_handle == def_pipe_handle) && 8700Sstevel@tonic-gate (USBA_WRP2CTRL_REQ(req_wrp)->ctrl_bRequest == 8710Sstevel@tonic-gate USB_REQ_GET_STATUS)) { 8720Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, hcdi->hcdi_log_handle, 8730Sstevel@tonic-gate "hcdi_autoclearing: usb_get_status failed, no clearing"); 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate /* if default pipe and stall no auto clearing */ 8760Sstevel@tonic-gate } else if ((pipe_handle == def_pipe_handle) && (cr == USB_CR_STALL)) { 8770Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, hcdi->hcdi_log_handle, 8780Sstevel@tonic-gate "hcdi_autoclearing: default pipe stalled, no clearing"); 8790Sstevel@tonic-gate 8800Sstevel@tonic-gate usba_req_set_cb_flags(req_wrp, USB_CB_PROTOCOL_STALL); 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate /* else do auto clearing */ 8830Sstevel@tonic-gate } else if (((attrs & USB_ATTRS_AUTOCLEARING) == 8840Sstevel@tonic-gate USB_ATTRS_AUTOCLEARING) && (cr == USB_CR_STALL)) { 8850Sstevel@tonic-gate ushort_t status = 0; 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate rval = usb_get_status(req_wrp->wr_dip, def_pipe_handle, 8880Sstevel@tonic-gate USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_EP, 8890Sstevel@tonic-gate req_wrp->wr_ph_data->p_ep.bEndpointAddress, 8900Sstevel@tonic-gate &status, USB_FLAGS_SLEEP); 8910Sstevel@tonic-gate if (rval != USB_SUCCESS) { 8920Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, hcdi->hcdi_log_handle, 8930Sstevel@tonic-gate "get status (STALL) failed: rval=%d", rval); 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate usba_pipe_clear(def_pipe_handle); 8960Sstevel@tonic-gate } 8970Sstevel@tonic-gate 8980Sstevel@tonic-gate if ((rval != USB_SUCCESS) || 8990Sstevel@tonic-gate (status & USB_EP_HALT_STATUS)) { 9000Sstevel@tonic-gate usba_req_set_cb_flags(req_wrp, USB_CB_FUNCTIONAL_STALL); 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate if ((rval = usb_pipe_sync_ctrl_xfer( 9030Sstevel@tonic-gate req_wrp->wr_dip, def_pipe_handle, 9040Sstevel@tonic-gate USB_DEV_REQ_HOST_TO_DEV | 9050Sstevel@tonic-gate USB_DEV_REQ_RCPT_EP, 9060Sstevel@tonic-gate USB_REQ_CLEAR_FEATURE, 9070Sstevel@tonic-gate 0, 9080Sstevel@tonic-gate req_wrp->wr_ph_data->p_ep.bEndpointAddress, 9090Sstevel@tonic-gate 0, 9100Sstevel@tonic-gate NULL, 0, 9110Sstevel@tonic-gate &completion_reason, 9120Sstevel@tonic-gate &cb_flags, USB_FLAGS_SLEEP)) != USB_SUCCESS) { 9130Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, 9140Sstevel@tonic-gate hcdi->hcdi_log_handle, 9150Sstevel@tonic-gate "auto clearing (STALL) failed: " 9160Sstevel@tonic-gate "rval=%d, cr=0x%x cb=0x%x", 9170Sstevel@tonic-gate rval, completion_reason, cb_flags); 9180Sstevel@tonic-gate 9190Sstevel@tonic-gate usba_pipe_clear(def_pipe_handle); 9200Sstevel@tonic-gate } else { 9210Sstevel@tonic-gate usba_req_set_cb_flags(req_wrp, 9220Sstevel@tonic-gate USB_CB_STALL_CLEARED); 9230Sstevel@tonic-gate } 9240Sstevel@tonic-gate } else { 9250Sstevel@tonic-gate usba_req_set_cb_flags(req_wrp, USB_CB_PROTOCOL_STALL); 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate } 9280Sstevel@tonic-gate } 9290Sstevel@tonic-gate 9300Sstevel@tonic-gate 9310Sstevel@tonic-gate /* 9320Sstevel@tonic-gate * usba_hcdi_get_req_private: 9330Sstevel@tonic-gate * This function is used to get the HCD private field 9340Sstevel@tonic-gate * maintained by USBA. HCD calls this function. 9350Sstevel@tonic-gate * 9360Sstevel@tonic-gate * Arguments: 9370Sstevel@tonic-gate * req - pointer to usb_*_req_t 9380Sstevel@tonic-gate * 9390Sstevel@tonic-gate * Return Values: 9400Sstevel@tonic-gate * wr_hcd_private field from wrapper 9410Sstevel@tonic-gate */ 9420Sstevel@tonic-gate usb_opaque_t 9430Sstevel@tonic-gate usba_hcdi_get_req_private(usb_opaque_t req) 9440Sstevel@tonic-gate { 9450Sstevel@tonic-gate usba_req_wrapper_t *wrp = USBA_REQ2WRP(req); 9460Sstevel@tonic-gate 9470Sstevel@tonic-gate return (wrp->wr_hcd_private); 9480Sstevel@tonic-gate } 9490Sstevel@tonic-gate 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate /* 9520Sstevel@tonic-gate * usba_hcdi_set_req_private: 9530Sstevel@tonic-gate * This function is used to set the HCD private field 9540Sstevel@tonic-gate * maintained by USBA. HCD calls this function. 9550Sstevel@tonic-gate * 9560Sstevel@tonic-gate * Arguments: 9570Sstevel@tonic-gate * req - pointer to usb_*_req_t 9580Sstevel@tonic-gate * hcd_private - wr_hcd_private field from wrapper 9590Sstevel@tonic-gate */ 9600Sstevel@tonic-gate void 9610Sstevel@tonic-gate usba_hcdi_set_req_private(usb_opaque_t req, 9620Sstevel@tonic-gate usb_opaque_t hcd_private) 9630Sstevel@tonic-gate { 9640Sstevel@tonic-gate usba_req_wrapper_t *wrp = USBA_REQ2WRP(req); 9650Sstevel@tonic-gate 9660Sstevel@tonic-gate wrp->wr_hcd_private = hcd_private; 9670Sstevel@tonic-gate } 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate /* get data toggle information for this endpoint */ 9710Sstevel@tonic-gate uchar_t 9720Sstevel@tonic-gate usba_hcdi_get_data_toggle(usba_device_t *usba_device, uint8_t ep_addr) 9730Sstevel@tonic-gate { 9740Sstevel@tonic-gate uchar_t toggle; 9750Sstevel@tonic-gate usba_ph_impl_t *ph_impl; 9760Sstevel@tonic-gate int ep_index; 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate ep_index = usb_get_ep_index(ep_addr); 9790Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 9800Sstevel@tonic-gate ph_impl = &usba_device->usb_ph_list[ep_index]; 9810Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 9820Sstevel@tonic-gate toggle = (uchar_t)(ph_impl->usba_ph_flags & USBA_PH_DATA_TOGGLE); 9830Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 9840Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate return (toggle); 9870Sstevel@tonic-gate } 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate 9900Sstevel@tonic-gate /* set data toggle information for this endpoint */ 9910Sstevel@tonic-gate void 9920Sstevel@tonic-gate usba_hcdi_set_data_toggle(usba_device_t *usba_device, uint8_t ep_addr, 9930Sstevel@tonic-gate uchar_t toggle) 9940Sstevel@tonic-gate { 9950Sstevel@tonic-gate usba_ph_impl_t *ph_impl; 9960Sstevel@tonic-gate int ep_index; 9970Sstevel@tonic-gate 9980Sstevel@tonic-gate ep_index = usb_get_ep_index(ep_addr); 9990Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 10000Sstevel@tonic-gate ph_impl = &usba_device->usb_ph_list[ep_index]; 10010Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 10020Sstevel@tonic-gate ph_impl->usba_ph_flags &= ~USBA_PH_DATA_TOGGLE; 10030Sstevel@tonic-gate ph_impl->usba_ph_flags |= (USBA_PH_DATA_TOGGLE & toggle); 10040Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 10050Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 10060Sstevel@tonic-gate } 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate 10090Sstevel@tonic-gate /* get pipe_handle_impl ptr for this ep */ 10100Sstevel@tonic-gate usba_pipe_handle_data_t * 10110Sstevel@tonic-gate usba_hcdi_get_ph_data(usba_device_t *usba_device, uint8_t ep_addr) 10120Sstevel@tonic-gate { 10130Sstevel@tonic-gate return (usba_device->usb_ph_list[usb_get_ep_index(ep_addr)]. 10140Sstevel@tonic-gate usba_ph_data); 10150Sstevel@tonic-gate } 1016