17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 53304303fSsl * Common Development and Distribution License (the "License"). 63304303fSsl * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*6a9de478Ssl * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * EHCI Host Controller Driver (EHCI) 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * The EHCI driver is a software driver which interfaces to the Universal 327c478bd9Sstevel@tonic-gate * Serial Bus layer (USBA) and the Host Controller (HC). The interface to 337c478bd9Sstevel@tonic-gate * the Host Controller is defined by the EHCI Host Controller Interface. 347c478bd9Sstevel@tonic-gate * 357c478bd9Sstevel@tonic-gate * This module contains the main EHCI driver code which handles all USB 367c478bd9Sstevel@tonic-gate * transfers, bandwidth allocations and other general functionalities. 377c478bd9Sstevel@tonic-gate */ 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h> 407c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_intr.h> 417c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_util.h> 427c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_isoch.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /* Adjustable variables for the size of the pools */ 457c478bd9Sstevel@tonic-gate extern int ehci_qh_pool_size; 467c478bd9Sstevel@tonic-gate extern int ehci_qtd_pool_size; 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate /* Endpoint Descriptor (QH) related functions */ 507c478bd9Sstevel@tonic-gate ehci_qh_t *ehci_alloc_qh( 517c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 527c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 537c478bd9Sstevel@tonic-gate uint_t flag); 547c478bd9Sstevel@tonic-gate static void ehci_unpack_endpoint( 557c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 567c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 577c478bd9Sstevel@tonic-gate ehci_qh_t *qh); 587c478bd9Sstevel@tonic-gate void ehci_insert_qh( 597c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 607c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 617c478bd9Sstevel@tonic-gate static void ehci_insert_async_qh( 627c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 637c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp); 647c478bd9Sstevel@tonic-gate static void ehci_insert_intr_qh( 657c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 667c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp); 677c478bd9Sstevel@tonic-gate static void ehci_modify_qh_status_bit( 687c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 697c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 707c478bd9Sstevel@tonic-gate halt_bit_t action); 717c478bd9Sstevel@tonic-gate static void ehci_halt_hs_qh( 727c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 737c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 747c478bd9Sstevel@tonic-gate ehci_qh_t *qh); 757c478bd9Sstevel@tonic-gate static void ehci_halt_fls_ctrl_and_bulk_qh( 767c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 777c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 787c478bd9Sstevel@tonic-gate ehci_qh_t *qh); 797c478bd9Sstevel@tonic-gate static void ehci_clear_tt_buffer( 807c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 817c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 827c478bd9Sstevel@tonic-gate ehci_qh_t *qh); 837c478bd9Sstevel@tonic-gate static void ehci_halt_fls_intr_qh( 847c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 857c478bd9Sstevel@tonic-gate ehci_qh_t *qh); 867c478bd9Sstevel@tonic-gate void ehci_remove_qh( 877c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 887c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 897c478bd9Sstevel@tonic-gate boolean_t reclaim); 907c478bd9Sstevel@tonic-gate static void ehci_remove_async_qh( 917c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 927c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 937c478bd9Sstevel@tonic-gate boolean_t reclaim); 947c478bd9Sstevel@tonic-gate static void ehci_remove_intr_qh( 957c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 967c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 977c478bd9Sstevel@tonic-gate boolean_t reclaim); 987c478bd9Sstevel@tonic-gate static void ehci_insert_qh_on_reclaim_list( 997c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1007c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp); 1017c478bd9Sstevel@tonic-gate void ehci_deallocate_qh( 1027c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1037c478bd9Sstevel@tonic-gate ehci_qh_t *old_qh); 1047c478bd9Sstevel@tonic-gate uint32_t ehci_qh_cpu_to_iommu( 1057c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1067c478bd9Sstevel@tonic-gate ehci_qh_t *addr); 1077c478bd9Sstevel@tonic-gate ehci_qh_t *ehci_qh_iommu_to_cpu( 1087c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1097c478bd9Sstevel@tonic-gate uintptr_t addr); 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate /* Transfer Descriptor (QTD) related functions */ 1127c478bd9Sstevel@tonic-gate static int ehci_initialize_dummy( 1137c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1147c478bd9Sstevel@tonic-gate ehci_qh_t *qh); 1157c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *ehci_allocate_ctrl_resources( 1167c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1177c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 1187c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 1197c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 1207c478bd9Sstevel@tonic-gate void ehci_insert_ctrl_req( 1217c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1227c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1237c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 1247c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 1257c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 1267c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *ehci_allocate_bulk_resources( 1277c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1287c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 1297c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 1307c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 1317c478bd9Sstevel@tonic-gate void ehci_insert_bulk_req( 1327c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1337c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1347c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 1357c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 1367c478bd9Sstevel@tonic-gate usb_flags_t flags); 1377c478bd9Sstevel@tonic-gate int ehci_start_periodic_pipe_polling( 1387c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1397c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1407c478bd9Sstevel@tonic-gate usb_opaque_t periodic_in_reqp, 1417c478bd9Sstevel@tonic-gate usb_flags_t flags); 1427c478bd9Sstevel@tonic-gate static int ehci_start_pipe_polling( 1437c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1447c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1457c478bd9Sstevel@tonic-gate usb_flags_t flags); 1467c478bd9Sstevel@tonic-gate static int ehci_start_intr_polling( 1477c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1487c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1497c478bd9Sstevel@tonic-gate usb_flags_t flags); 1507c478bd9Sstevel@tonic-gate static void ehci_set_periodic_pipe_polling( 1517c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1527c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 1537c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *ehci_allocate_intr_resources( 1547c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1557c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1567c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp, 1577c478bd9Sstevel@tonic-gate usb_flags_t usb_flags); 1587c478bd9Sstevel@tonic-gate void ehci_insert_intr_req( 1597c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1607c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 1617c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 1627c478bd9Sstevel@tonic-gate usb_flags_t flags); 1637c478bd9Sstevel@tonic-gate int ehci_stop_periodic_pipe_polling( 1647c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1657c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1667c478bd9Sstevel@tonic-gate usb_flags_t flags); 1677c478bd9Sstevel@tonic-gate int ehci_insert_qtd( 1687c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1697c478bd9Sstevel@tonic-gate uint32_t qtd_ctrl, 1703304303fSsl size_t qtd_dma_offs, 1717c478bd9Sstevel@tonic-gate size_t qtd_length, 1727c478bd9Sstevel@tonic-gate uint32_t qtd_ctrl_phase, 1737c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 1747c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 1757c478bd9Sstevel@tonic-gate static ehci_qtd_t *ehci_allocate_qtd_from_pool( 1767c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 1777c478bd9Sstevel@tonic-gate static void ehci_fill_in_qtd( 1787c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1797c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 1807c478bd9Sstevel@tonic-gate uint32_t qtd_ctrl, 1813304303fSsl size_t qtd_dma_offs, 1827c478bd9Sstevel@tonic-gate size_t qtd_length, 1837c478bd9Sstevel@tonic-gate uint32_t qtd_ctrl_phase, 1847c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 1857c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 1867c478bd9Sstevel@tonic-gate static void ehci_insert_qtd_on_tw( 1877c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1887c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 1897c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd); 1907c478bd9Sstevel@tonic-gate static void ehci_insert_qtd_into_active_qtd_list( 1917c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1927c478bd9Sstevel@tonic-gate ehci_qtd_t *curr_qtd); 1937c478bd9Sstevel@tonic-gate void ehci_remove_qtd_from_active_qtd_list( 1947c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1957c478bd9Sstevel@tonic-gate ehci_qtd_t *curr_qtd); 1967c478bd9Sstevel@tonic-gate static void ehci_traverse_qtds( 1977c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1987c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 1997c478bd9Sstevel@tonic-gate void ehci_deallocate_qtd( 2007c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2017c478bd9Sstevel@tonic-gate ehci_qtd_t *old_qtd); 2027c478bd9Sstevel@tonic-gate uint32_t ehci_qtd_cpu_to_iommu( 2037c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2047c478bd9Sstevel@tonic-gate ehci_qtd_t *addr); 2057c478bd9Sstevel@tonic-gate ehci_qtd_t *ehci_qtd_iommu_to_cpu( 2067c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2077c478bd9Sstevel@tonic-gate uintptr_t addr); 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate /* Transfer Wrapper (TW) functions */ 2107c478bd9Sstevel@tonic-gate static ehci_trans_wrapper_t *ehci_create_transfer_wrapper( 2117c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2127c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 2137c478bd9Sstevel@tonic-gate size_t length, 2147c478bd9Sstevel@tonic-gate uint_t usb_flags); 2157c478bd9Sstevel@tonic-gate int ehci_allocate_tds_for_tw( 2167c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2177c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 2187c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 2197c478bd9Sstevel@tonic-gate size_t qtd_count); 2207c478bd9Sstevel@tonic-gate static ehci_trans_wrapper_t *ehci_allocate_tw_resources( 2217c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2227c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 2237c478bd9Sstevel@tonic-gate size_t length, 2247c478bd9Sstevel@tonic-gate usb_flags_t usb_flags, 2257c478bd9Sstevel@tonic-gate size_t td_count); 2267c478bd9Sstevel@tonic-gate static void ehci_free_tw_td_resources( 2277c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2287c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 2297c478bd9Sstevel@tonic-gate static void ehci_start_xfer_timer( 2307c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2317c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 2327c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 2337c478bd9Sstevel@tonic-gate void ehci_stop_xfer_timer( 2347c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2357c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 2367c478bd9Sstevel@tonic-gate uint_t flag); 2377c478bd9Sstevel@tonic-gate static void ehci_xfer_timeout_handler(void *arg); 2387c478bd9Sstevel@tonic-gate static void ehci_remove_tw_from_timeout_list( 2397c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2407c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 2417c478bd9Sstevel@tonic-gate static void ehci_start_timer(ehci_state_t *ehcip, 2427c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp); 2437c478bd9Sstevel@tonic-gate void ehci_deallocate_tw( 2447c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2457c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 2467c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 2477c478bd9Sstevel@tonic-gate void ehci_free_dma_resources( 2487c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2497c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 2507c478bd9Sstevel@tonic-gate static void ehci_free_tw( 2517c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2527c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 2537c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate /* Miscellaneous functions */ 2567c478bd9Sstevel@tonic-gate int ehci_allocate_intr_in_resource( 2577c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2587c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 2597c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 2607c478bd9Sstevel@tonic-gate usb_flags_t flags); 2617c478bd9Sstevel@tonic-gate void ehci_pipe_cleanup( 2627c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2637c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 2647c478bd9Sstevel@tonic-gate static void ehci_wait_for_transfers_completion( 2657c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2667c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp); 2677c478bd9Sstevel@tonic-gate void ehci_check_for_transfers_completion( 2687c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2697c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp); 2707c478bd9Sstevel@tonic-gate static void ehci_save_data_toggle( 2717c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2727c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 2737c478bd9Sstevel@tonic-gate void ehci_restore_data_toggle( 2747c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2757c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph); 2767c478bd9Sstevel@tonic-gate void ehci_handle_outstanding_requests( 2777c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2787c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp); 2797c478bd9Sstevel@tonic-gate void ehci_deallocate_intr_in_resource( 2807c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2817c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 2827c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 2837c478bd9Sstevel@tonic-gate void ehci_do_client_periodic_in_req_callback( 2847c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2857c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 2867c478bd9Sstevel@tonic-gate usb_cr_t completion_reason); 2877c478bd9Sstevel@tonic-gate void ehci_hcdi_callback( 2887c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2897c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 2907c478bd9Sstevel@tonic-gate usb_cr_t completion_reason); 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* 2947c478bd9Sstevel@tonic-gate * Endpoint Descriptor (QH) manipulations functions 2957c478bd9Sstevel@tonic-gate */ 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate /* 2987c478bd9Sstevel@tonic-gate * ehci_alloc_qh: 2997c478bd9Sstevel@tonic-gate * 3007c478bd9Sstevel@tonic-gate * Allocate an endpoint descriptor (QH) 3017c478bd9Sstevel@tonic-gate * 3027c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 3037c478bd9Sstevel@tonic-gate */ 3047c478bd9Sstevel@tonic-gate ehci_qh_t * 3057c478bd9Sstevel@tonic-gate ehci_alloc_qh( 3067c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 3077c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 3087c478bd9Sstevel@tonic-gate uint_t flag) 3097c478bd9Sstevel@tonic-gate { 3107c478bd9Sstevel@tonic-gate int i, state; 3117c478bd9Sstevel@tonic-gate ehci_qh_t *qh; 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 3147c478bd9Sstevel@tonic-gate "ehci_alloc_qh: ph = 0x%p flag = 0x%x", (void *)ph, flag); 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate /* 3197c478bd9Sstevel@tonic-gate * If this is for a ISOC endpoint return null. 3207c478bd9Sstevel@tonic-gate * Isochronous uses ITD put directly onto the PFL. 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate if (ph) { 3237c478bd9Sstevel@tonic-gate if (EHCI_ISOC_ENDPOINT((&ph->p_ep))) { 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate return (NULL); 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* 3307c478bd9Sstevel@tonic-gate * The first 63 endpoints in the Endpoint Descriptor (QH) 3317c478bd9Sstevel@tonic-gate * buffer pool are reserved for building interrupt lattice 3327c478bd9Sstevel@tonic-gate * tree. Search for a blank endpoint descriptor in the QH 3337c478bd9Sstevel@tonic-gate * buffer pool. 3347c478bd9Sstevel@tonic-gate */ 3357c478bd9Sstevel@tonic-gate for (i = EHCI_NUM_STATIC_NODES; i < ehci_qh_pool_size; i ++) { 3367c478bd9Sstevel@tonic-gate state = Get_QH(ehcip->ehci_qh_pool_addr[i].qh_state); 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate if (state == EHCI_QH_FREE) { 3397c478bd9Sstevel@tonic-gate break; 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate } 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 3447c478bd9Sstevel@tonic-gate "ehci_alloc_qh: Allocated %d", i); 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate if (i == ehci_qh_pool_size) { 3477c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 3487c478bd9Sstevel@tonic-gate "ehci_alloc_qh: QH exhausted"); 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate return (NULL); 3517c478bd9Sstevel@tonic-gate } else { 3527c478bd9Sstevel@tonic-gate qh = &ehcip->ehci_qh_pool_addr[i]; 353*6a9de478Ssl bzero((void *)qh, sizeof (ehci_qh_t)); 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 3567c478bd9Sstevel@tonic-gate "ehci_alloc_qh: Allocated address 0x%p", (void *)qh); 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* Check polled mode flag */ 3597c478bd9Sstevel@tonic-gate if (flag == EHCI_POLLED_MODE_FLAG) { 3607c478bd9Sstevel@tonic-gate Set_QH(qh->qh_link_ptr, EHCI_QH_LINK_PTR_VALID); 3617c478bd9Sstevel@tonic-gate Set_QH(qh->qh_ctrl, EHCI_QH_CTRL_ED_INACTIVATE); 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* Unpack the endpoint descriptor into a control field */ 3657c478bd9Sstevel@tonic-gate if (ph) { 3667c478bd9Sstevel@tonic-gate if ((ehci_initialize_dummy(ehcip, 3677c478bd9Sstevel@tonic-gate qh)) == USB_NO_RESOURCES) { 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate Set_QH(qh->qh_state, EHCI_QH_FREE); 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate return (NULL); 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate ehci_unpack_endpoint(ehcip, ph, qh); 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate Set_QH(qh->qh_curr_qtd, NULL); 3777c478bd9Sstevel@tonic-gate Set_QH(qh->qh_alt_next_qtd, 3787c478bd9Sstevel@tonic-gate EHCI_QH_ALT_NEXT_QTD_PTR_VALID); 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate /* Change QH's state Active */ 3817c478bd9Sstevel@tonic-gate Set_QH(qh->qh_state, EHCI_QH_ACTIVE); 3827c478bd9Sstevel@tonic-gate } else { 3837c478bd9Sstevel@tonic-gate Set_QH(qh->qh_status, EHCI_QH_STS_HALTED); 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /* Change QH's state Static */ 3867c478bd9Sstevel@tonic-gate Set_QH(qh->qh_state, EHCI_QH_STATIC); 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate ehci_print_qh(ehcip, qh); 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate return (qh); 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* 3977c478bd9Sstevel@tonic-gate * ehci_unpack_endpoint: 3987c478bd9Sstevel@tonic-gate * 3997c478bd9Sstevel@tonic-gate * Unpack the information in the pipe handle and create the first byte 4007c478bd9Sstevel@tonic-gate * of the Host Controller's (HC) Endpoint Descriptor (QH). 4017c478bd9Sstevel@tonic-gate */ 4027c478bd9Sstevel@tonic-gate static void 4037c478bd9Sstevel@tonic-gate ehci_unpack_endpoint( 4047c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 4057c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 4067c478bd9Sstevel@tonic-gate ehci_qh_t *qh) 4077c478bd9Sstevel@tonic-gate { 4087c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 4097c478bd9Sstevel@tonic-gate uint_t maxpacketsize, addr, xactions; 4107c478bd9Sstevel@tonic-gate uint_t ctrl = 0, status = 0, split_ctrl = 0; 4117c478bd9Sstevel@tonic-gate usb_port_status_t usb_port_status; 4127c478bd9Sstevel@tonic-gate usba_device_t *usba_device = ph->p_usba_device; 4137c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 4167c478bd9Sstevel@tonic-gate "ehci_unpack_endpoint:"); 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 4197c478bd9Sstevel@tonic-gate ctrl = usba_device->usb_addr; 4207c478bd9Sstevel@tonic-gate usb_port_status = usba_device->usb_port_status; 4217c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate addr = endpoint->bEndpointAddress; 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate /* Assign the endpoint's address */ 4267c478bd9Sstevel@tonic-gate ctrl |= ((addr & USB_EP_NUM_MASK) << EHCI_QH_CTRL_ED_NUMBER_SHIFT); 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate /* Assign the speed */ 4297c478bd9Sstevel@tonic-gate switch (usb_port_status) { 4307c478bd9Sstevel@tonic-gate case USBA_LOW_SPEED_DEV: 4317c478bd9Sstevel@tonic-gate ctrl |= EHCI_QH_CTRL_ED_LOW_SPEED; 4327c478bd9Sstevel@tonic-gate break; 4337c478bd9Sstevel@tonic-gate case USBA_FULL_SPEED_DEV: 4347c478bd9Sstevel@tonic-gate ctrl |= EHCI_QH_CTRL_ED_FULL_SPEED; 4357c478bd9Sstevel@tonic-gate break; 4367c478bd9Sstevel@tonic-gate case USBA_HIGH_SPEED_DEV: 4377c478bd9Sstevel@tonic-gate ctrl |= EHCI_QH_CTRL_ED_HIGH_SPEED; 4387c478bd9Sstevel@tonic-gate break; 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate switch (endpoint->bmAttributes & USB_EP_ATTR_MASK) { 4427c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 4437c478bd9Sstevel@tonic-gate /* Assign data toggle information */ 4447c478bd9Sstevel@tonic-gate ctrl |= EHCI_QH_CTRL_DATA_TOGGLE; 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate if (usb_port_status != USBA_HIGH_SPEED_DEV) { 4477c478bd9Sstevel@tonic-gate ctrl |= EHCI_QH_CTRL_CONTROL_ED_FLAG; 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate /* FALLTHRU */ 4507c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 4517c478bd9Sstevel@tonic-gate /* Maximum nak counter */ 4527c478bd9Sstevel@tonic-gate ctrl |= EHCI_QH_CTRL_MAX_NC; 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate if (usb_port_status == USBA_HIGH_SPEED_DEV) { 4557c478bd9Sstevel@tonic-gate /* 4567c478bd9Sstevel@tonic-gate * Perform ping before executing control 4577c478bd9Sstevel@tonic-gate * and bulk transactions. 4587c478bd9Sstevel@tonic-gate */ 4597c478bd9Sstevel@tonic-gate status = EHCI_QH_STS_DO_PING; 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate break; 4627c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 4637c478bd9Sstevel@tonic-gate /* Set start split mask */ 4647c478bd9Sstevel@tonic-gate split_ctrl = (pp->pp_smask & EHCI_QH_SPLIT_CTRL_INTR_MASK); 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate /* 4677c478bd9Sstevel@tonic-gate * Set complete split mask for low/full speed 4687c478bd9Sstevel@tonic-gate * usb devices. 4697c478bd9Sstevel@tonic-gate */ 4707c478bd9Sstevel@tonic-gate if (usb_port_status != USBA_HIGH_SPEED_DEV) { 4717c478bd9Sstevel@tonic-gate split_ctrl |= ((pp->pp_cmask << 4727c478bd9Sstevel@tonic-gate EHCI_QH_SPLIT_CTRL_COMP_SHIFT) & 4737c478bd9Sstevel@tonic-gate EHCI_QH_SPLIT_CTRL_COMP_MASK); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate break; 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate /* Get the max transactions per microframe */ 4797c478bd9Sstevel@tonic-gate xactions = (endpoint->wMaxPacketSize & 4807c478bd9Sstevel@tonic-gate USB_EP_MAX_XACTS_MASK) >> USB_EP_MAX_XACTS_SHIFT; 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate switch (xactions) { 4837c478bd9Sstevel@tonic-gate case 0: 4847c478bd9Sstevel@tonic-gate split_ctrl |= EHCI_QH_SPLIT_CTRL_1_XACTS; 4857c478bd9Sstevel@tonic-gate break; 4867c478bd9Sstevel@tonic-gate case 1: 4877c478bd9Sstevel@tonic-gate split_ctrl |= EHCI_QH_SPLIT_CTRL_2_XACTS; 4887c478bd9Sstevel@tonic-gate break; 4897c478bd9Sstevel@tonic-gate case 2: 4907c478bd9Sstevel@tonic-gate split_ctrl |= EHCI_QH_SPLIT_CTRL_3_XACTS; 4917c478bd9Sstevel@tonic-gate break; 4927c478bd9Sstevel@tonic-gate default: 4937c478bd9Sstevel@tonic-gate split_ctrl |= EHCI_QH_SPLIT_CTRL_1_XACTS; 4947c478bd9Sstevel@tonic-gate break; 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate /* 4987c478bd9Sstevel@tonic-gate * For low/full speed devices, program high speed hub 4997c478bd9Sstevel@tonic-gate * address and port number. 5007c478bd9Sstevel@tonic-gate */ 5017c478bd9Sstevel@tonic-gate if (usb_port_status != USBA_HIGH_SPEED_DEV) { 5027c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 5037c478bd9Sstevel@tonic-gate split_ctrl |= ((usba_device->usb_hs_hub_addr 5047c478bd9Sstevel@tonic-gate << EHCI_QH_SPLIT_CTRL_HUB_ADDR_SHIFT) & 5057c478bd9Sstevel@tonic-gate EHCI_QH_SPLIT_CTRL_HUB_ADDR); 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate split_ctrl |= ((usba_device->usb_hs_hub_port 5087c478bd9Sstevel@tonic-gate << EHCI_QH_SPLIT_CTRL_HUB_PORT_SHIFT) & 5097c478bd9Sstevel@tonic-gate EHCI_QH_SPLIT_CTRL_HUB_PORT); 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate /* Set start split transaction state */ 5147c478bd9Sstevel@tonic-gate status = EHCI_QH_STS_DO_START_SPLIT; 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate /* Assign endpoint's maxpacketsize */ 5187c478bd9Sstevel@tonic-gate maxpacketsize = endpoint->wMaxPacketSize & USB_EP_MAX_PKTSZ_MASK; 5197c478bd9Sstevel@tonic-gate maxpacketsize = maxpacketsize << EHCI_QH_CTRL_MAXPKTSZ_SHIFT; 5207c478bd9Sstevel@tonic-gate ctrl |= (maxpacketsize & EHCI_QH_CTRL_MAXPKTSZ); 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate Set_QH(qh->qh_ctrl, ctrl); 5237c478bd9Sstevel@tonic-gate Set_QH(qh->qh_split_ctrl, split_ctrl); 5247c478bd9Sstevel@tonic-gate Set_QH(qh->qh_status, status); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate /* 5297c478bd9Sstevel@tonic-gate * ehci_insert_qh: 5307c478bd9Sstevel@tonic-gate * 5317c478bd9Sstevel@tonic-gate * Add the Endpoint Descriptor (QH) into the Host Controller's 5327c478bd9Sstevel@tonic-gate * (HC) appropriate endpoint list. 5337c478bd9Sstevel@tonic-gate */ 5347c478bd9Sstevel@tonic-gate void 5357c478bd9Sstevel@tonic-gate ehci_insert_qh( 5367c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 5377c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 5387c478bd9Sstevel@tonic-gate { 5397c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 5427c478bd9Sstevel@tonic-gate "ehci_insert_qh: qh=0x%p", pp->pp_qh); 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate switch (ph->p_ep.bmAttributes & USB_EP_ATTR_MASK) { 5477c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 5487c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 5497c478bd9Sstevel@tonic-gate ehci_insert_async_qh(ehcip, pp); 5507c478bd9Sstevel@tonic-gate ehcip->ehci_open_async_count++; 5517c478bd9Sstevel@tonic-gate break; 5527c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 5537c478bd9Sstevel@tonic-gate ehci_insert_intr_qh(ehcip, pp); 5547c478bd9Sstevel@tonic-gate ehcip->ehci_open_periodic_count++; 5557c478bd9Sstevel@tonic-gate break; 5567c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 5577c478bd9Sstevel@tonic-gate /* ISOCH does not use QH, don't do anything but update count */ 5587c478bd9Sstevel@tonic-gate ehcip->ehci_open_periodic_count++; 5597c478bd9Sstevel@tonic-gate break; 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehcip); 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate /* 5667c478bd9Sstevel@tonic-gate * ehci_insert_async_qh: 5677c478bd9Sstevel@tonic-gate * 5687c478bd9Sstevel@tonic-gate * Insert a control/bulk endpoint into the Host Controller's (HC) 5697c478bd9Sstevel@tonic-gate * Asynchronous schedule endpoint list. 5707c478bd9Sstevel@tonic-gate */ 5717c478bd9Sstevel@tonic-gate static void 5727c478bd9Sstevel@tonic-gate ehci_insert_async_qh( 5737c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 5747c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp) 5757c478bd9Sstevel@tonic-gate { 5767c478bd9Sstevel@tonic-gate ehci_qh_t *qh = pp->pp_qh; 5777c478bd9Sstevel@tonic-gate ehci_qh_t *async_head_qh; 5787c478bd9Sstevel@tonic-gate ehci_qh_t *next_qh; 5797c478bd9Sstevel@tonic-gate uintptr_t qh_addr; 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 5827c478bd9Sstevel@tonic-gate "ehci_insert_async_qh:"); 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate /* Make sure this QH is not already in the list */ 5877c478bd9Sstevel@tonic-gate ASSERT((Get_QH(qh->qh_prev) & EHCI_QH_LINK_PTR) == NULL); 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate qh_addr = ehci_qh_cpu_to_iommu(ehcip, qh); 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate /* Obtain a ptr to the head of the Async schedule list */ 5927c478bd9Sstevel@tonic-gate async_head_qh = ehcip->ehci_head_of_async_sched_list; 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate if (async_head_qh == NULL) { 5957c478bd9Sstevel@tonic-gate /* Set this QH to be the "head" of the circular list */ 5967c478bd9Sstevel@tonic-gate Set_QH(qh->qh_ctrl, 5977c478bd9Sstevel@tonic-gate (Get_QH(qh->qh_ctrl) | EHCI_QH_CTRL_RECLAIM_HEAD)); 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate /* Set new QH's link and previous pointer to itself */ 6007c478bd9Sstevel@tonic-gate Set_QH(qh->qh_link_ptr, qh_addr | EHCI_QH_LINK_REF_QH); 6017c478bd9Sstevel@tonic-gate Set_QH(qh->qh_prev, qh_addr); 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list = qh; 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate /* Set the head ptr to the new endpoint */ 6067c478bd9Sstevel@tonic-gate Set_OpReg(ehci_async_list_addr, qh_addr); 607921cd50dSgk 608921cd50dSgk /* 609921cd50dSgk * For some reason this register might get nulled out by 610921cd50dSgk * the Uli M1575 South Bridge. To workaround the hardware 611921cd50dSgk * problem, check the value after write and retry if the 612921cd50dSgk * last write fails. 613921cd50dSgk * 614921cd50dSgk * If the ASYNCLISTADDR remains "stuck" after 615921cd50dSgk * EHCI_MAX_RETRY retries, then the M1575 is broken 616921cd50dSgk * and is stuck in an inconsistent state and is about 617921cd50dSgk * to crash the machine with a trn_oor panic when it 618921cd50dSgk * does a DMA read from 0x0. It is better to panic 619921cd50dSgk * now rather than wait for the trn_oor crash; this 620921cd50dSgk * way Customer Service will have a clean signature 621921cd50dSgk * that indicts the M1575 chip rather than a 622921cd50dSgk * mysterious and hard-to-diagnose trn_oor panic. 623921cd50dSgk */ 624921cd50dSgk if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) && 625921cd50dSgk (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) && 626921cd50dSgk (qh_addr != Get_OpReg(ehci_async_list_addr))) { 627921cd50dSgk int retry = 0; 628921cd50dSgk 629921cd50dSgk Set_OpRegRetry(ehci_async_list_addr, qh_addr, retry); 630921cd50dSgk if (retry >= EHCI_MAX_RETRY) 631921cd50dSgk cmn_err(CE_PANIC, "ehci_insert_async_qh:" 632921cd50dSgk " ASYNCLISTADDR write failed."); 633921cd50dSgk 634921cd50dSgk USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 635921cd50dSgk "ehci_insert_async_qh: ASYNCLISTADDR " 636*6a9de478Ssl "write failed, retry=%d", retry); 637921cd50dSgk } 6387c478bd9Sstevel@tonic-gate } else { 6397c478bd9Sstevel@tonic-gate ASSERT(Get_QH(async_head_qh->qh_ctrl) & 6407c478bd9Sstevel@tonic-gate EHCI_QH_CTRL_RECLAIM_HEAD); 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate /* Ensure this QH's "H" bit is not set */ 6437c478bd9Sstevel@tonic-gate Set_QH(qh->qh_ctrl, 6447c478bd9Sstevel@tonic-gate (Get_QH(qh->qh_ctrl) & ~EHCI_QH_CTRL_RECLAIM_HEAD)); 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate next_qh = ehci_qh_iommu_to_cpu(ehcip, 6477c478bd9Sstevel@tonic-gate Get_QH(async_head_qh->qh_link_ptr) & EHCI_QH_LINK_PTR); 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate /* Set new QH's link and previous pointers */ 6507c478bd9Sstevel@tonic-gate Set_QH(qh->qh_link_ptr, 6517c478bd9Sstevel@tonic-gate Get_QH(async_head_qh->qh_link_ptr) | EHCI_QH_LINK_REF_QH); 6527c478bd9Sstevel@tonic-gate Set_QH(qh->qh_prev, ehci_qh_cpu_to_iommu(ehcip, async_head_qh)); 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate /* Set next QH's prev pointer */ 6557c478bd9Sstevel@tonic-gate Set_QH(next_qh->qh_prev, ehci_qh_cpu_to_iommu(ehcip, qh)); 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate /* Set QH Head's link pointer points to new QH */ 6587c478bd9Sstevel@tonic-gate Set_QH(async_head_qh->qh_link_ptr, 6597c478bd9Sstevel@tonic-gate qh_addr | EHCI_QH_LINK_REF_QH); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate /* 6657c478bd9Sstevel@tonic-gate * ehci_insert_intr_qh: 6667c478bd9Sstevel@tonic-gate * 6677c478bd9Sstevel@tonic-gate * Insert a interrupt endpoint into the Host Controller's (HC) interrupt 6687c478bd9Sstevel@tonic-gate * lattice tree. 6697c478bd9Sstevel@tonic-gate */ 6707c478bd9Sstevel@tonic-gate static void 6717c478bd9Sstevel@tonic-gate ehci_insert_intr_qh( 6727c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 6737c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp) 6747c478bd9Sstevel@tonic-gate { 6757c478bd9Sstevel@tonic-gate ehci_qh_t *qh = pp->pp_qh; 6767c478bd9Sstevel@tonic-gate ehci_qh_t *next_lattice_qh, *lattice_qh; 6777c478bd9Sstevel@tonic-gate uint_t hnode; 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 6807c478bd9Sstevel@tonic-gate "ehci_insert_intr_qh:"); 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate /* Make sure this QH is not already in the list */ 6857c478bd9Sstevel@tonic-gate ASSERT((Get_QH(qh->qh_prev) & EHCI_QH_LINK_PTR) == NULL); 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate /* 6887c478bd9Sstevel@tonic-gate * The appropriate high speed node was found 6897c478bd9Sstevel@tonic-gate * during the opening of the pipe. 6907c478bd9Sstevel@tonic-gate */ 6917c478bd9Sstevel@tonic-gate hnode = pp->pp_pnode; 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate /* Find the lattice endpoint */ 6947c478bd9Sstevel@tonic-gate lattice_qh = &ehcip->ehci_qh_pool_addr[hnode]; 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate /* Find the next lattice endpoint */ 6977c478bd9Sstevel@tonic-gate next_lattice_qh = ehci_qh_iommu_to_cpu( 6987c478bd9Sstevel@tonic-gate ehcip, (Get_QH(lattice_qh->qh_link_ptr) & EHCI_QH_LINK_PTR)); 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate /* Update the previous pointer */ 7017c478bd9Sstevel@tonic-gate Set_QH(qh->qh_prev, ehci_qh_cpu_to_iommu(ehcip, lattice_qh)); 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate /* Check next_lattice_qh value */ 7047c478bd9Sstevel@tonic-gate if (next_lattice_qh) { 7057c478bd9Sstevel@tonic-gate /* Update this qh to point to the next one in the lattice */ 7067c478bd9Sstevel@tonic-gate Set_QH(qh->qh_link_ptr, Get_QH(lattice_qh->qh_link_ptr)); 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate /* Update the previous pointer of qh->qh_link_ptr */ 7097c478bd9Sstevel@tonic-gate if (Get_QH(next_lattice_qh->qh_state) != EHCI_QH_STATIC) { 7107c478bd9Sstevel@tonic-gate Set_QH(next_lattice_qh->qh_prev, 7117c478bd9Sstevel@tonic-gate ehci_qh_cpu_to_iommu(ehcip, qh)); 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate } else { 7147c478bd9Sstevel@tonic-gate /* Update qh's link pointer to terminate periodic list */ 7157c478bd9Sstevel@tonic-gate Set_QH(qh->qh_link_ptr, 7167c478bd9Sstevel@tonic-gate (Get_QH(lattice_qh->qh_link_ptr) | EHCI_QH_LINK_PTR_VALID)); 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate /* Insert this endpoint into the lattice */ 7207c478bd9Sstevel@tonic-gate Set_QH(lattice_qh->qh_link_ptr, 7217c478bd9Sstevel@tonic-gate (ehci_qh_cpu_to_iommu(ehcip, qh) | EHCI_QH_LINK_REF_QH)); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate /* 7267c478bd9Sstevel@tonic-gate * ehci_modify_qh_status_bit: 7277c478bd9Sstevel@tonic-gate * 7287c478bd9Sstevel@tonic-gate * Modify the halt bit on the Host Controller (HC) Endpoint Descriptor (QH). 7297c478bd9Sstevel@tonic-gate * 7307c478bd9Sstevel@tonic-gate * If several threads try to halt the same pipe, they will need to wait on 7317c478bd9Sstevel@tonic-gate * a condition variable. Only one thread is allowed to halt or unhalt the 7327c478bd9Sstevel@tonic-gate * pipe at a time. 7337c478bd9Sstevel@tonic-gate * 7347c478bd9Sstevel@tonic-gate * Usually after a halt pipe, an unhalt pipe will follow soon after. There 7357c478bd9Sstevel@tonic-gate * is an assumption that an Unhalt pipe will never occur without a halt pipe. 7367c478bd9Sstevel@tonic-gate */ 7377c478bd9Sstevel@tonic-gate static void 7387c478bd9Sstevel@tonic-gate ehci_modify_qh_status_bit( 7397c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 7407c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 7417c478bd9Sstevel@tonic-gate halt_bit_t action) 7427c478bd9Sstevel@tonic-gate { 7437c478bd9Sstevel@tonic-gate ehci_qh_t *qh = pp->pp_qh; 7447c478bd9Sstevel@tonic-gate uint_t smask, eps, split_intr_qh; 7457c478bd9Sstevel@tonic-gate uint_t status; 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 7487c478bd9Sstevel@tonic-gate "ehci_modify_qh_status_bit: action=0x%x qh=0x%p", 7497c478bd9Sstevel@tonic-gate action, qh); 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate ehci_print_qh(ehcip, qh); 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate /* 7567c478bd9Sstevel@tonic-gate * If this pipe is in the middle of halting don't allow another 7577c478bd9Sstevel@tonic-gate * thread to come in and modify the same pipe. 7587c478bd9Sstevel@tonic-gate */ 7597c478bd9Sstevel@tonic-gate while (pp->pp_halt_state & EHCI_HALT_STATE_HALTING) { 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate cv_wait(&pp->pp_halt_cmpl_cv, 762*6a9de478Ssl &ehcip->ehci_int_mutex); 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate /* Sync the QH QTD pool to get up to date information */ 7667c478bd9Sstevel@tonic-gate Sync_QH_QTD_Pool(ehcip); 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate if (action == CLEAR_HALT) { 7707c478bd9Sstevel@tonic-gate /* 7717c478bd9Sstevel@tonic-gate * If the halt bit is to be cleared, just clear it. 7727c478bd9Sstevel@tonic-gate * there shouldn't be any race condition problems. 7737c478bd9Sstevel@tonic-gate * If the host controller reads the bit before the 7747c478bd9Sstevel@tonic-gate * driver has a chance to set the bit, the bit will 7757c478bd9Sstevel@tonic-gate * be reread on the next frame. 7767c478bd9Sstevel@tonic-gate */ 7777c478bd9Sstevel@tonic-gate Set_QH(qh->qh_ctrl, 7787c478bd9Sstevel@tonic-gate (Get_QH(qh->qh_ctrl) & ~EHCI_QH_CTRL_ED_INACTIVATE)); 7797c478bd9Sstevel@tonic-gate Set_QH(qh->qh_status, 7807c478bd9Sstevel@tonic-gate Get_QH(qh->qh_status) & ~(EHCI_QH_STS_XACT_STATUS)); 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate goto success; 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate /* Halt the the QH, but first check to see if it is already halted */ 7867c478bd9Sstevel@tonic-gate status = Get_QH(qh->qh_status); 7877c478bd9Sstevel@tonic-gate if (!(status & EHCI_QH_STS_HALTED)) { 7887c478bd9Sstevel@tonic-gate /* Indicate that this pipe is in the middle of halting. */ 7897c478bd9Sstevel@tonic-gate pp->pp_halt_state |= EHCI_HALT_STATE_HALTING; 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate /* 7927c478bd9Sstevel@tonic-gate * Find out if this is an full/low speed interrupt endpoint. 7937c478bd9Sstevel@tonic-gate * A non-zero Cmask indicates that this QH is an interrupt 7947c478bd9Sstevel@tonic-gate * endpoint. Check the endpoint speed to see if it is either 7957c478bd9Sstevel@tonic-gate * FULL or LOW . 7967c478bd9Sstevel@tonic-gate */ 7977c478bd9Sstevel@tonic-gate smask = Get_QH(qh->qh_split_ctrl) & 7987c478bd9Sstevel@tonic-gate EHCI_QH_SPLIT_CTRL_INTR_MASK; 7997c478bd9Sstevel@tonic-gate eps = Get_QH(qh->qh_ctrl) & EHCI_QH_CTRL_ED_SPEED; 8007c478bd9Sstevel@tonic-gate split_intr_qh = ((smask != 0) && 8017c478bd9Sstevel@tonic-gate (eps != EHCI_QH_CTRL_ED_HIGH_SPEED)); 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate if (eps == EHCI_QH_CTRL_ED_HIGH_SPEED) { 8047c478bd9Sstevel@tonic-gate ehci_halt_hs_qh(ehcip, pp, qh); 8057c478bd9Sstevel@tonic-gate } else { 8067c478bd9Sstevel@tonic-gate if (split_intr_qh) { 8077c478bd9Sstevel@tonic-gate ehci_halt_fls_intr_qh(ehcip, qh); 8087c478bd9Sstevel@tonic-gate } else { 8097c478bd9Sstevel@tonic-gate ehci_halt_fls_ctrl_and_bulk_qh(ehcip, pp, qh); 8107c478bd9Sstevel@tonic-gate } 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate /* Indicate that this pipe is not in the middle of halting. */ 8147c478bd9Sstevel@tonic-gate pp->pp_halt_state &= ~EHCI_HALT_STATE_HALTING; 8157c478bd9Sstevel@tonic-gate } 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate /* Sync the QH QTD pool again to get the most up to date information */ 8187c478bd9Sstevel@tonic-gate Sync_QH_QTD_Pool(ehcip); 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate ehci_print_qh(ehcip, qh); 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate status = Get_QH(qh->qh_status); 8237c478bd9Sstevel@tonic-gate if (!(status & EHCI_QH_STS_HALTED)) { 8247c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 8257c478bd9Sstevel@tonic-gate "ehci_modify_qh_status_bit: Failed to halt qh=0x%p", qh); 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate ehci_print_qh(ehcip, qh); 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */ 8307c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE; 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate ASSERT(status & EHCI_QH_STS_HALTED); 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate success: 8367c478bd9Sstevel@tonic-gate /* Wake up threads waiting for this pipe to be halted. */ 8377c478bd9Sstevel@tonic-gate cv_signal(&pp->pp_halt_cmpl_cv); 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate /* 8427c478bd9Sstevel@tonic-gate * ehci_halt_hs_qh: 8437c478bd9Sstevel@tonic-gate * 8447c478bd9Sstevel@tonic-gate * Halts all types of HIGH SPEED QHs. 8457c478bd9Sstevel@tonic-gate */ 8467c478bd9Sstevel@tonic-gate static void 8477c478bd9Sstevel@tonic-gate ehci_halt_hs_qh( 8487c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 8497c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 8507c478bd9Sstevel@tonic-gate ehci_qh_t *qh) 8517c478bd9Sstevel@tonic-gate { 8527c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 8557c478bd9Sstevel@tonic-gate "ehci_halt_hs_qh:"); 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate /* Remove this qh from the HCD's view, but do not reclaim it */ 8587c478bd9Sstevel@tonic-gate ehci_remove_qh(ehcip, pp, B_FALSE); 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate /* 8617c478bd9Sstevel@tonic-gate * Wait for atleast one SOF, just in case the HCD is in the 8627c478bd9Sstevel@tonic-gate * middle accessing this QH. 8637c478bd9Sstevel@tonic-gate */ 8647c478bd9Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip); 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate /* Sync the QH QTD pool to get up to date information */ 8677c478bd9Sstevel@tonic-gate Sync_QH_QTD_Pool(ehcip); 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate /* Modify the status bit and halt this QH. */ 8707c478bd9Sstevel@tonic-gate Set_QH(qh->qh_status, 8717c478bd9Sstevel@tonic-gate ((Get_QH(qh->qh_status) & 872*6a9de478Ssl ~(EHCI_QH_STS_ACTIVE)) | EHCI_QH_STS_HALTED)); 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate /* Insert this QH back into the HCD's view */ 8757c478bd9Sstevel@tonic-gate ehci_insert_qh(ehcip, ph); 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate /* 8807c478bd9Sstevel@tonic-gate * ehci_halt_fls_ctrl_and_bulk_qh: 8817c478bd9Sstevel@tonic-gate * 8827c478bd9Sstevel@tonic-gate * Halts FULL/LOW Ctrl and Bulk QHs only. 8837c478bd9Sstevel@tonic-gate */ 8847c478bd9Sstevel@tonic-gate static void 8857c478bd9Sstevel@tonic-gate ehci_halt_fls_ctrl_and_bulk_qh( 8867c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 8877c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 8887c478bd9Sstevel@tonic-gate ehci_qh_t *qh) 8897c478bd9Sstevel@tonic-gate { 8907c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 8917c478bd9Sstevel@tonic-gate uint_t status, split_status, bytes_left; 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 8957c478bd9Sstevel@tonic-gate "ehci_halt_fls_ctrl_and_bulk_qh:"); 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate /* Remove this qh from the HCD's view, but do not reclaim it */ 8987c478bd9Sstevel@tonic-gate ehci_remove_qh(ehcip, pp, B_FALSE); 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate /* 9017c478bd9Sstevel@tonic-gate * Wait for atleast one SOF, just in case the HCD is in the 9027c478bd9Sstevel@tonic-gate * middle accessing this QH. 9037c478bd9Sstevel@tonic-gate */ 9047c478bd9Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip); 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate /* Sync the QH QTD pool to get up to date information */ 9077c478bd9Sstevel@tonic-gate Sync_QH_QTD_Pool(ehcip); 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate /* Modify the status bit and halt this QH. */ 9107c478bd9Sstevel@tonic-gate Set_QH(qh->qh_status, 9117c478bd9Sstevel@tonic-gate ((Get_QH(qh->qh_status) & 912*6a9de478Ssl ~(EHCI_QH_STS_ACTIVE)) | EHCI_QH_STS_HALTED)); 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate /* Check to see if the QH was in the middle of a transaction */ 9157c478bd9Sstevel@tonic-gate status = Get_QH(qh->qh_status); 9167c478bd9Sstevel@tonic-gate split_status = status & EHCI_QH_STS_SPLIT_XSTATE; 9177c478bd9Sstevel@tonic-gate bytes_left = status & EHCI_QH_STS_BYTES_TO_XFER; 9187c478bd9Sstevel@tonic-gate if ((split_status == EHCI_QH_STS_DO_COMPLETE_SPLIT) && 9197c478bd9Sstevel@tonic-gate (bytes_left != 0)) { 9207c478bd9Sstevel@tonic-gate /* send ClearTTBuffer to this device's parent 2.0 hub */ 9217c478bd9Sstevel@tonic-gate ehci_clear_tt_buffer(ehcip, ph, qh); 9227c478bd9Sstevel@tonic-gate } 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate /* Insert this QH back into the HCD's view */ 9257c478bd9Sstevel@tonic-gate ehci_insert_qh(ehcip, ph); 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate /* 9307c478bd9Sstevel@tonic-gate * ehci_clear_tt_buffer 9317c478bd9Sstevel@tonic-gate * 9327c478bd9Sstevel@tonic-gate * This function will sent a Clear_TT_Buffer request to the pipe's 9337c478bd9Sstevel@tonic-gate * parent 2.0 hub. 9347c478bd9Sstevel@tonic-gate */ 9357c478bd9Sstevel@tonic-gate static void 9367c478bd9Sstevel@tonic-gate ehci_clear_tt_buffer( 9377c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 9387c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 9397c478bd9Sstevel@tonic-gate ehci_qh_t *qh) 9407c478bd9Sstevel@tonic-gate { 9417c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 9427c478bd9Sstevel@tonic-gate usba_device_t *hub_usba_device; 9437c478bd9Sstevel@tonic-gate usb_pipe_handle_t hub_def_ph; 9447c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd; 9457c478bd9Sstevel@tonic-gate uchar_t attributes; 9467c478bd9Sstevel@tonic-gate uint16_t wValue; 9477c478bd9Sstevel@tonic-gate usb_ctrl_setup_t setup; 9487c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 9497c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 9507c478bd9Sstevel@tonic-gate int retry; 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 9537c478bd9Sstevel@tonic-gate "ehci_clear_tt_buffer: "); 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate /* Get some information about the current pipe */ 9567c478bd9Sstevel@tonic-gate usba_device = ph->p_usba_device; 9577c478bd9Sstevel@tonic-gate eptd = &ph->p_ep; 9587c478bd9Sstevel@tonic-gate attributes = eptd->bmAttributes & USB_EP_ATTR_MASK; 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate /* 9617c478bd9Sstevel@tonic-gate * Create the wIndex for this request (usb spec 11.24.2.3) 9627c478bd9Sstevel@tonic-gate * 3..0 Endpoint Number 9637c478bd9Sstevel@tonic-gate * 10..4 Device Address 9647c478bd9Sstevel@tonic-gate * 12..11 Endpoint Type 9657c478bd9Sstevel@tonic-gate * 14..13 Reserved (must be 0) 9667c478bd9Sstevel@tonic-gate * 15 Direction 1 = IN, 0 = OUT 9677c478bd9Sstevel@tonic-gate */ 9687c478bd9Sstevel@tonic-gate wValue = 0; 9697c478bd9Sstevel@tonic-gate if ((eptd->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 9707c478bd9Sstevel@tonic-gate wValue |= 0x8000; 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate wValue |= attributes << 11; 9737c478bd9Sstevel@tonic-gate wValue |= (Get_QH(qh->qh_ctrl) & EHCI_QH_CTRL_DEVICE_ADDRESS) << 4; 9747c478bd9Sstevel@tonic-gate wValue |= (Get_QH(qh->qh_ctrl) & EHCI_QH_CTRL_ED_HIGH_SPEED) >> 9757c478bd9Sstevel@tonic-gate EHCI_QH_CTRL_ED_NUMBER_SHIFT; 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate /* Manually fill in the request. */ 9807c478bd9Sstevel@tonic-gate setup.bmRequestType = EHCI_CLEAR_TT_BUFFER_REQTYPE; 9817c478bd9Sstevel@tonic-gate setup.bRequest = EHCI_CLEAR_TT_BUFFER_BREQ; 9827c478bd9Sstevel@tonic-gate setup.wValue = wValue; 9837c478bd9Sstevel@tonic-gate setup.wIndex = 1; 9847c478bd9Sstevel@tonic-gate setup.wLength = 0; 9857c478bd9Sstevel@tonic-gate setup.attrs = USB_ATTRS_NONE; 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate /* Get the usba_device of the parent 2.0 hub. */ 9887c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 9897c478bd9Sstevel@tonic-gate hub_usba_device = usba_device->usb_hs_hub_usba_dev; 9907c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate /* Get the default ctrl pipe for the parent 2.0 hub */ 9937c478bd9Sstevel@tonic-gate mutex_enter(&hub_usba_device->usb_mutex); 9947c478bd9Sstevel@tonic-gate hub_def_ph = (usb_pipe_handle_t)&hub_usba_device->usb_ph_list[0]; 9957c478bd9Sstevel@tonic-gate mutex_exit(&hub_usba_device->usb_mutex); 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate for (retry = 0; retry < 3; retry++) { 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate /* sync send the request to the default pipe */ 10007c478bd9Sstevel@tonic-gate if (usb_pipe_ctrl_xfer_wait( 10017c478bd9Sstevel@tonic-gate hub_def_ph, 10027c478bd9Sstevel@tonic-gate &setup, 10037c478bd9Sstevel@tonic-gate NULL, 10047c478bd9Sstevel@tonic-gate &completion_reason, &cb_flags, 0) == USB_SUCCESS) { 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate break; 10077c478bd9Sstevel@tonic-gate } 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 10107c478bd9Sstevel@tonic-gate "ehci_clear_tt_buffer: Failed to clear tt buffer," 10117c478bd9Sstevel@tonic-gate "retry = %d, cr = %d, cb_flags = 0x%x\n", 10127c478bd9Sstevel@tonic-gate retry, completion_reason, cb_flags); 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate if (retry >= 3) { 10167c478bd9Sstevel@tonic-gate char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 10177c478bd9Sstevel@tonic-gate dev_info_t *dip = hub_usba_device->usb_dip; 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate /* 10207c478bd9Sstevel@tonic-gate * Ask the user to hotplug the 2.0 hub, to make sure that 10217c478bd9Sstevel@tonic-gate * all the buffer is in sync since this command has failed. 10227c478bd9Sstevel@tonic-gate */ 10237c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 10247c478bd9Sstevel@tonic-gate "Error recovery failure: Please hotplug the 2.0 hub at" 10257c478bd9Sstevel@tonic-gate "%s", ddi_pathname(dip, path)); 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate kmem_free(path, MAXPATHLEN); 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate /* 10347c478bd9Sstevel@tonic-gate * ehci_halt_fls_intr_qh: 10357c478bd9Sstevel@tonic-gate * 10367c478bd9Sstevel@tonic-gate * Halts FULL/LOW speed Intr QHs. 10377c478bd9Sstevel@tonic-gate */ 10387c478bd9Sstevel@tonic-gate static void 10397c478bd9Sstevel@tonic-gate ehci_halt_fls_intr_qh( 10407c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 10417c478bd9Sstevel@tonic-gate ehci_qh_t *qh) 10427c478bd9Sstevel@tonic-gate { 10437c478bd9Sstevel@tonic-gate usb_frame_number_t starting_frame; 10447c478bd9Sstevel@tonic-gate usb_frame_number_t frames_past; 10457c478bd9Sstevel@tonic-gate uint_t status, i; 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 10487c478bd9Sstevel@tonic-gate "ehci_halt_fls_intr_qh:"); 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate /* 10517c478bd9Sstevel@tonic-gate * Ask the HC to deactivate the QH in a 10527c478bd9Sstevel@tonic-gate * full/low periodic QH. 10537c478bd9Sstevel@tonic-gate */ 10547c478bd9Sstevel@tonic-gate Set_QH(qh->qh_ctrl, 10557c478bd9Sstevel@tonic-gate (Get_QH(qh->qh_ctrl) | EHCI_QH_CTRL_ED_INACTIVATE)); 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate starting_frame = ehci_get_current_frame_number(ehcip); 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate /* 10607c478bd9Sstevel@tonic-gate * Wait at least EHCI_NUM_INTR_QH_LISTS+2 frame or until 10617c478bd9Sstevel@tonic-gate * the QH has been halted. 10627c478bd9Sstevel@tonic-gate */ 10637c478bd9Sstevel@tonic-gate Sync_QH_QTD_Pool(ehcip); 10647c478bd9Sstevel@tonic-gate frames_past = 0; 10657c478bd9Sstevel@tonic-gate status = Get_QH(qh->qh_status) & EHCI_QTD_CTRL_ACTIVE_XACT; 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate while ((frames_past <= (EHCI_NUM_INTR_QH_LISTS + 2)) && 10687c478bd9Sstevel@tonic-gate (status != 0)) { 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip); 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate Sync_QH_QTD_Pool(ehcip); 10737c478bd9Sstevel@tonic-gate status = Get_QH(qh->qh_status) & EHCI_QTD_CTRL_ACTIVE_XACT; 10747c478bd9Sstevel@tonic-gate frames_past = ehci_get_current_frame_number(ehcip) - 10757c478bd9Sstevel@tonic-gate starting_frame; 10767c478bd9Sstevel@tonic-gate } 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate /* Modify the status bit and halt this QH. */ 10797c478bd9Sstevel@tonic-gate Sync_QH_QTD_Pool(ehcip); 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate status = Get_QH(qh->qh_status); 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate for (i = 0; i < EHCI_NUM_INTR_QH_LISTS; i++) { 10847c478bd9Sstevel@tonic-gate Set_QH(qh->qh_status, 1085*6a9de478Ssl ((Get_QH(qh->qh_status) & 1086*6a9de478Ssl ~(EHCI_QH_STS_ACTIVE)) | EHCI_QH_STS_HALTED)); 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate Sync_QH_QTD_Pool(ehcip); 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip); 10917c478bd9Sstevel@tonic-gate Sync_QH_QTD_Pool(ehcip); 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate if (Get_QH(qh->qh_status) & EHCI_QH_STS_HALTED) { 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate break; 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate } 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate Sync_QH_QTD_Pool(ehcip); 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 11027c478bd9Sstevel@tonic-gate "ehci_halt_fls_intr_qh: qh=0x%p frames past=%d, status=0x%x, 0x%x", 11037c478bd9Sstevel@tonic-gate qh, ehci_get_current_frame_number(ehcip) - starting_frame, 11047c478bd9Sstevel@tonic-gate status, Get_QH(qh->qh_status)); 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate /* 11097c478bd9Sstevel@tonic-gate * ehci_remove_qh: 11107c478bd9Sstevel@tonic-gate * 11117c478bd9Sstevel@tonic-gate * Remove the Endpoint Descriptor (QH) from the Host Controller's appropriate 11127c478bd9Sstevel@tonic-gate * endpoint list. 11137c478bd9Sstevel@tonic-gate */ 11147c478bd9Sstevel@tonic-gate void 11157c478bd9Sstevel@tonic-gate ehci_remove_qh( 11167c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 11177c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 11187c478bd9Sstevel@tonic-gate boolean_t reclaim) 11197c478bd9Sstevel@tonic-gate { 11207c478bd9Sstevel@tonic-gate uchar_t attributes; 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 11257c478bd9Sstevel@tonic-gate "ehci_remove_qh: qh=0x%p", pp->pp_qh); 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate attributes = pp->pp_pipe_handle->p_ep.bmAttributes & USB_EP_ATTR_MASK; 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate switch (attributes) { 11307c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 11317c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 11327c478bd9Sstevel@tonic-gate ehci_remove_async_qh(ehcip, pp, reclaim); 11337c478bd9Sstevel@tonic-gate ehcip->ehci_open_async_count--; 11347c478bd9Sstevel@tonic-gate break; 11357c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 11367c478bd9Sstevel@tonic-gate ehci_remove_intr_qh(ehcip, pp, reclaim); 11377c478bd9Sstevel@tonic-gate ehcip->ehci_open_periodic_count--; 11387c478bd9Sstevel@tonic-gate break; 11397c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 11407c478bd9Sstevel@tonic-gate /* ISOCH does not use QH, don't do anything but update count */ 11417c478bd9Sstevel@tonic-gate ehcip->ehci_open_periodic_count--; 11427c478bd9Sstevel@tonic-gate break; 11437c478bd9Sstevel@tonic-gate } 11447c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehcip); 11457c478bd9Sstevel@tonic-gate } 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate /* 11497c478bd9Sstevel@tonic-gate * ehci_remove_async_qh: 11507c478bd9Sstevel@tonic-gate * 11517c478bd9Sstevel@tonic-gate * Remove a control/bulk endpoint into the Host Controller's (HC) 11527c478bd9Sstevel@tonic-gate * Asynchronous schedule endpoint list. 11537c478bd9Sstevel@tonic-gate */ 11547c478bd9Sstevel@tonic-gate static void 11557c478bd9Sstevel@tonic-gate ehci_remove_async_qh( 11567c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 11577c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 11587c478bd9Sstevel@tonic-gate boolean_t reclaim) 11597c478bd9Sstevel@tonic-gate { 11607c478bd9Sstevel@tonic-gate ehci_qh_t *qh = pp->pp_qh; /* qh to be removed */ 11617c478bd9Sstevel@tonic-gate ehci_qh_t *prev_qh, *next_qh; 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 11647c478bd9Sstevel@tonic-gate "ehci_remove_async_qh:"); 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate prev_qh = ehci_qh_iommu_to_cpu(ehcip, 11697c478bd9Sstevel@tonic-gate Get_QH(qh->qh_prev) & EHCI_QH_LINK_PTR); 11707c478bd9Sstevel@tonic-gate next_qh = ehci_qh_iommu_to_cpu(ehcip, 11717c478bd9Sstevel@tonic-gate Get_QH(qh->qh_link_ptr) & EHCI_QH_LINK_PTR); 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate /* Make sure this QH is in the list */ 11747c478bd9Sstevel@tonic-gate ASSERT(prev_qh != NULL); 11757c478bd9Sstevel@tonic-gate 11767c478bd9Sstevel@tonic-gate /* 11777c478bd9Sstevel@tonic-gate * If next QH and current QH are the same, then this is the last 11787c478bd9Sstevel@tonic-gate * QH on the Asynchronous Schedule list. 11797c478bd9Sstevel@tonic-gate */ 11807c478bd9Sstevel@tonic-gate if (qh == next_qh) { 11817c478bd9Sstevel@tonic-gate ASSERT(Get_QH(qh->qh_ctrl) & EHCI_QH_CTRL_RECLAIM_HEAD); 11827c478bd9Sstevel@tonic-gate /* 11837c478bd9Sstevel@tonic-gate * Null our pointer to the async sched list, but do not 11847c478bd9Sstevel@tonic-gate * touch the host controller's list_addr. 11857c478bd9Sstevel@tonic-gate */ 11867c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list = NULL; 11877c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_open_async_count == 1); 11887c478bd9Sstevel@tonic-gate } else { 11897c478bd9Sstevel@tonic-gate /* If this QH is the HEAD then find another one to replace it */ 11907c478bd9Sstevel@tonic-gate if (ehcip->ehci_head_of_async_sched_list == qh) { 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate ASSERT(Get_QH(qh->qh_ctrl) & EHCI_QH_CTRL_RECLAIM_HEAD); 11937c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list = next_qh; 11947c478bd9Sstevel@tonic-gate Set_QH(next_qh->qh_ctrl, 11957c478bd9Sstevel@tonic-gate Get_QH(next_qh->qh_ctrl) | 11967c478bd9Sstevel@tonic-gate EHCI_QH_CTRL_RECLAIM_HEAD); 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate Set_QH(prev_qh->qh_link_ptr, Get_QH(qh->qh_link_ptr)); 11997c478bd9Sstevel@tonic-gate Set_QH(next_qh->qh_prev, Get_QH(qh->qh_prev)); 12007c478bd9Sstevel@tonic-gate } 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate /* qh_prev to indicate it is no longer in the circular list */ 12037c478bd9Sstevel@tonic-gate Set_QH(qh->qh_prev, NULL); 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate if (reclaim) { 12067c478bd9Sstevel@tonic-gate ehci_insert_qh_on_reclaim_list(ehcip, pp); 12077c478bd9Sstevel@tonic-gate } 12087c478bd9Sstevel@tonic-gate } 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate /* 12127c478bd9Sstevel@tonic-gate * ehci_remove_intr_qh: 12137c478bd9Sstevel@tonic-gate * 12147c478bd9Sstevel@tonic-gate * Set up an interrupt endpoint to be removed from the Host Controller's (HC) 12157c478bd9Sstevel@tonic-gate * interrupt lattice tree. The Endpoint Descriptor (QH) will be freed in the 12167c478bd9Sstevel@tonic-gate * interrupt handler. 12177c478bd9Sstevel@tonic-gate */ 12187c478bd9Sstevel@tonic-gate static void 12197c478bd9Sstevel@tonic-gate ehci_remove_intr_qh( 12207c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 12217c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 12227c478bd9Sstevel@tonic-gate boolean_t reclaim) 12237c478bd9Sstevel@tonic-gate { 12247c478bd9Sstevel@tonic-gate ehci_qh_t *qh = pp->pp_qh; /* qh to be removed */ 12257c478bd9Sstevel@tonic-gate ehci_qh_t *prev_qh, *next_qh; 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 12287c478bd9Sstevel@tonic-gate "ehci_remove_intr_qh:"); 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate prev_qh = ehci_qh_iommu_to_cpu(ehcip, Get_QH(qh->qh_prev)); 12337c478bd9Sstevel@tonic-gate next_qh = ehci_qh_iommu_to_cpu(ehcip, 12347c478bd9Sstevel@tonic-gate Get_QH(qh->qh_link_ptr) & EHCI_QH_LINK_PTR); 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate /* Make sure this QH is in the list */ 12377c478bd9Sstevel@tonic-gate ASSERT(prev_qh != NULL); 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate if (next_qh) { 12407c478bd9Sstevel@tonic-gate /* Update previous qh's link pointer */ 12417c478bd9Sstevel@tonic-gate Set_QH(prev_qh->qh_link_ptr, Get_QH(qh->qh_link_ptr)); 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate if (Get_QH(next_qh->qh_state) != EHCI_QH_STATIC) { 12447c478bd9Sstevel@tonic-gate /* Set the previous pointer of the next one */ 12457c478bd9Sstevel@tonic-gate Set_QH(next_qh->qh_prev, Get_QH(qh->qh_prev)); 12467c478bd9Sstevel@tonic-gate } 12477c478bd9Sstevel@tonic-gate } else { 12487c478bd9Sstevel@tonic-gate /* Update previous qh's link pointer */ 12497c478bd9Sstevel@tonic-gate Set_QH(prev_qh->qh_link_ptr, 12507c478bd9Sstevel@tonic-gate (Get_QH(qh->qh_link_ptr) | EHCI_QH_LINK_PTR_VALID)); 12517c478bd9Sstevel@tonic-gate } 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate /* qh_prev to indicate it is no longer in the circular list */ 12547c478bd9Sstevel@tonic-gate Set_QH(qh->qh_prev, NULL); 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate if (reclaim) { 12577c478bd9Sstevel@tonic-gate ehci_insert_qh_on_reclaim_list(ehcip, pp); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate /* 12637c478bd9Sstevel@tonic-gate * ehci_insert_qh_on_reclaim_list: 12647c478bd9Sstevel@tonic-gate * 12657c478bd9Sstevel@tonic-gate * Insert Endpoint onto the reclaim list 12667c478bd9Sstevel@tonic-gate */ 12677c478bd9Sstevel@tonic-gate static void 12687c478bd9Sstevel@tonic-gate ehci_insert_qh_on_reclaim_list( 12697c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 12707c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp) 12717c478bd9Sstevel@tonic-gate { 12727c478bd9Sstevel@tonic-gate ehci_qh_t *qh = pp->pp_qh; /* qh to be removed */ 12737c478bd9Sstevel@tonic-gate ehci_qh_t *next_qh, *prev_qh; 12747c478bd9Sstevel@tonic-gate usb_frame_number_t frame_number; 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate /* 12797c478bd9Sstevel@tonic-gate * Read current usb frame number and add appropriate number of 12807c478bd9Sstevel@tonic-gate * usb frames needs to wait before reclaiming current endpoint. 12817c478bd9Sstevel@tonic-gate */ 12827c478bd9Sstevel@tonic-gate frame_number = 12837c478bd9Sstevel@tonic-gate ehci_get_current_frame_number(ehcip) + MAX_SOF_WAIT_COUNT; 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate /* Store 32-bit ID */ 12867c478bd9Sstevel@tonic-gate Set_QH(qh->qh_reclaim_frame, 12877c478bd9Sstevel@tonic-gate ((uint32_t)(EHCI_GET_ID((void *)(uintptr_t)frame_number)))); 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate /* Insert the endpoint onto the reclamation list */ 12907c478bd9Sstevel@tonic-gate if (ehcip->ehci_reclaim_list) { 12917c478bd9Sstevel@tonic-gate next_qh = ehcip->ehci_reclaim_list; 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate while (next_qh) { 12947c478bd9Sstevel@tonic-gate prev_qh = next_qh; 12957c478bd9Sstevel@tonic-gate next_qh = ehci_qh_iommu_to_cpu(ehcip, 12967c478bd9Sstevel@tonic-gate Get_QH(next_qh->qh_reclaim_next)); 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate Set_QH(prev_qh->qh_reclaim_next, 13007c478bd9Sstevel@tonic-gate ehci_qh_cpu_to_iommu(ehcip, qh)); 13017c478bd9Sstevel@tonic-gate } else { 13027c478bd9Sstevel@tonic-gate ehcip->ehci_reclaim_list = qh; 13037c478bd9Sstevel@tonic-gate } 13047c478bd9Sstevel@tonic-gate 13057c478bd9Sstevel@tonic-gate ASSERT(Get_QH(qh->qh_reclaim_next) == NULL); 13067c478bd9Sstevel@tonic-gate } 13077c478bd9Sstevel@tonic-gate 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate /* 13107c478bd9Sstevel@tonic-gate * ehci_deallocate_qh: 13117c478bd9Sstevel@tonic-gate * 13127c478bd9Sstevel@tonic-gate * Deallocate a Host Controller's (HC) Endpoint Descriptor (QH). 13137c478bd9Sstevel@tonic-gate * 13147c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 13157c478bd9Sstevel@tonic-gate */ 13167c478bd9Sstevel@tonic-gate void 13177c478bd9Sstevel@tonic-gate ehci_deallocate_qh( 13187c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 13197c478bd9Sstevel@tonic-gate ehci_qh_t *old_qh) 13207c478bd9Sstevel@tonic-gate { 13217c478bd9Sstevel@tonic-gate ehci_qtd_t *first_dummy_qtd, *second_dummy_qtd; 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 13247c478bd9Sstevel@tonic-gate "ehci_deallocate_qh:"); 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 13277c478bd9Sstevel@tonic-gate 13287c478bd9Sstevel@tonic-gate first_dummy_qtd = ehci_qtd_iommu_to_cpu(ehcip, 13297c478bd9Sstevel@tonic-gate (Get_QH(old_qh->qh_next_qtd) & EHCI_QH_NEXT_QTD_PTR)); 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate if (first_dummy_qtd) { 13327c478bd9Sstevel@tonic-gate ASSERT(Get_QTD(first_dummy_qtd->qtd_state) == EHCI_QTD_DUMMY); 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate second_dummy_qtd = ehci_qtd_iommu_to_cpu(ehcip, 13357c478bd9Sstevel@tonic-gate Get_QTD(first_dummy_qtd->qtd_next_qtd)); 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate if (second_dummy_qtd) { 13387c478bd9Sstevel@tonic-gate ASSERT(Get_QTD(second_dummy_qtd->qtd_state) == 13397c478bd9Sstevel@tonic-gate EHCI_QTD_DUMMY); 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate ehci_deallocate_qtd(ehcip, second_dummy_qtd); 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate ehci_deallocate_qtd(ehcip, first_dummy_qtd); 13457c478bd9Sstevel@tonic-gate } 13467c478bd9Sstevel@tonic-gate 13477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 13487c478bd9Sstevel@tonic-gate "ehci_deallocate_qh: Deallocated 0x%p", (void *)old_qh); 13497c478bd9Sstevel@tonic-gate 13507c478bd9Sstevel@tonic-gate Set_QH(old_qh->qh_state, EHCI_QH_FREE); 13517c478bd9Sstevel@tonic-gate } 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate /* 13557c478bd9Sstevel@tonic-gate * ehci_qh_cpu_to_iommu: 13567c478bd9Sstevel@tonic-gate * 13577c478bd9Sstevel@tonic-gate * This function converts for the given Endpoint Descriptor (QH) CPU address 13587c478bd9Sstevel@tonic-gate * to IO address. 13597c478bd9Sstevel@tonic-gate * 13607c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 13617c478bd9Sstevel@tonic-gate */ 13627c478bd9Sstevel@tonic-gate uint32_t 13637c478bd9Sstevel@tonic-gate ehci_qh_cpu_to_iommu( 13647c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 13657c478bd9Sstevel@tonic-gate ehci_qh_t *addr) 13667c478bd9Sstevel@tonic-gate { 13677c478bd9Sstevel@tonic-gate uint32_t qh; 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate qh = (uint32_t)ehcip->ehci_qh_pool_cookie.dmac_address + 13707c478bd9Sstevel@tonic-gate (uint32_t)((uintptr_t)addr - (uintptr_t)(ehcip->ehci_qh_pool_addr)); 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate ASSERT(qh >= ehcip->ehci_qh_pool_cookie.dmac_address); 13737c478bd9Sstevel@tonic-gate ASSERT(qh <= ehcip->ehci_qh_pool_cookie.dmac_address + 13747c478bd9Sstevel@tonic-gate sizeof (ehci_qh_t) * ehci_qh_pool_size); 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate return (qh); 13777c478bd9Sstevel@tonic-gate } 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate /* 13817c478bd9Sstevel@tonic-gate * ehci_qh_iommu_to_cpu: 13827c478bd9Sstevel@tonic-gate * 13837c478bd9Sstevel@tonic-gate * This function converts for the given Endpoint Descriptor (QH) IO address 13847c478bd9Sstevel@tonic-gate * to CPU address. 13857c478bd9Sstevel@tonic-gate */ 13867c478bd9Sstevel@tonic-gate ehci_qh_t * 13877c478bd9Sstevel@tonic-gate ehci_qh_iommu_to_cpu( 13887c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 13897c478bd9Sstevel@tonic-gate uintptr_t addr) 13907c478bd9Sstevel@tonic-gate { 13917c478bd9Sstevel@tonic-gate ehci_qh_t *qh; 13927c478bd9Sstevel@tonic-gate 13937c478bd9Sstevel@tonic-gate if (addr == NULL) { 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate return (NULL); 13967c478bd9Sstevel@tonic-gate } 13977c478bd9Sstevel@tonic-gate 13987c478bd9Sstevel@tonic-gate qh = (ehci_qh_t *)((uintptr_t) 13997c478bd9Sstevel@tonic-gate (addr - ehcip->ehci_qh_pool_cookie.dmac_address) + 14007c478bd9Sstevel@tonic-gate (uintptr_t)ehcip->ehci_qh_pool_addr); 14017c478bd9Sstevel@tonic-gate 14027c478bd9Sstevel@tonic-gate ASSERT(qh >= ehcip->ehci_qh_pool_addr); 14037c478bd9Sstevel@tonic-gate ASSERT((uintptr_t)qh <= (uintptr_t)ehcip->ehci_qh_pool_addr + 14047c478bd9Sstevel@tonic-gate (uintptr_t)(sizeof (ehci_qh_t) * ehci_qh_pool_size)); 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate return (qh); 14077c478bd9Sstevel@tonic-gate } 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate /* 14117c478bd9Sstevel@tonic-gate * Transfer Descriptor manipulations functions 14127c478bd9Sstevel@tonic-gate */ 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate /* 14157c478bd9Sstevel@tonic-gate * ehci_initialize_dummy: 14167c478bd9Sstevel@tonic-gate * 14177c478bd9Sstevel@tonic-gate * An Endpoint Descriptor (QH) has a dummy Transfer Descriptor (QTD) on the 14187c478bd9Sstevel@tonic-gate * end of its QTD list. Initially, both the head and tail pointers of the QH 14197c478bd9Sstevel@tonic-gate * point to the dummy QTD. 14207c478bd9Sstevel@tonic-gate */ 14217c478bd9Sstevel@tonic-gate static int 14227c478bd9Sstevel@tonic-gate ehci_initialize_dummy( 14237c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 14247c478bd9Sstevel@tonic-gate ehci_qh_t *qh) 14257c478bd9Sstevel@tonic-gate { 14267c478bd9Sstevel@tonic-gate ehci_qtd_t *first_dummy_qtd, *second_dummy_qtd; 14277c478bd9Sstevel@tonic-gate 14287c478bd9Sstevel@tonic-gate /* Allocate first dummy QTD */ 14297c478bd9Sstevel@tonic-gate first_dummy_qtd = ehci_allocate_qtd_from_pool(ehcip); 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate if (first_dummy_qtd == NULL) { 14327c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 14337c478bd9Sstevel@tonic-gate } 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate /* Allocate second dummy QTD */ 14367c478bd9Sstevel@tonic-gate second_dummy_qtd = ehci_allocate_qtd_from_pool(ehcip); 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate if (second_dummy_qtd == NULL) { 14397c478bd9Sstevel@tonic-gate /* Deallocate first dummy QTD */ 14407c478bd9Sstevel@tonic-gate ehci_deallocate_qtd(ehcip, first_dummy_qtd); 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 14437c478bd9Sstevel@tonic-gate } 14447c478bd9Sstevel@tonic-gate 14457c478bd9Sstevel@tonic-gate /* Next QTD pointer of an QH point to this new dummy QTD */ 14467c478bd9Sstevel@tonic-gate Set_QH(qh->qh_next_qtd, ehci_qtd_cpu_to_iommu(ehcip, 14477c478bd9Sstevel@tonic-gate first_dummy_qtd) & EHCI_QH_NEXT_QTD_PTR); 14487c478bd9Sstevel@tonic-gate 14497c478bd9Sstevel@tonic-gate /* Set qh's dummy qtd field */ 14507c478bd9Sstevel@tonic-gate Set_QH(qh->qh_dummy_qtd, ehci_qtd_cpu_to_iommu(ehcip, first_dummy_qtd)); 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate /* Set first_dummy's next qtd pointer */ 14537c478bd9Sstevel@tonic-gate Set_QTD(first_dummy_qtd->qtd_next_qtd, 14547c478bd9Sstevel@tonic-gate ehci_qtd_cpu_to_iommu(ehcip, second_dummy_qtd)); 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate /* 14607c478bd9Sstevel@tonic-gate * ehci_allocate_ctrl_resources: 14617c478bd9Sstevel@tonic-gate * 14627c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a ctrl transfer, and allocates 14637c478bd9Sstevel@tonic-gate * all the resources necessary. 14647c478bd9Sstevel@tonic-gate * 14657c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW. 14667c478bd9Sstevel@tonic-gate */ 14677c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t * 14687c478bd9Sstevel@tonic-gate ehci_allocate_ctrl_resources( 14697c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 14707c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 14717c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 14727c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 14737c478bd9Sstevel@tonic-gate { 14747c478bd9Sstevel@tonic-gate size_t qtd_count = 2; 14753304303fSsl size_t ctrl_buf_size; 14767c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw; 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate /* Add one more td for data phase */ 14797c478bd9Sstevel@tonic-gate if (ctrl_reqp->ctrl_wLength) { 14807c478bd9Sstevel@tonic-gate qtd_count += 1; 14817c478bd9Sstevel@tonic-gate } 14827c478bd9Sstevel@tonic-gate 14833304303fSsl /* 14843304303fSsl * If we have a control data phase, the data buffer starts 14853304303fSsl * on the next 4K page boundary. So the TW buffer is allocated 14863304303fSsl * to be larger than required. The buffer in the range of 14873304303fSsl * [SETUP_SIZE, EHCI_MAX_QTD_BUF_SIZE) is just for padding 14883304303fSsl * and not to be transferred. 14893304303fSsl */ 14903304303fSsl if (ctrl_reqp->ctrl_wLength) { 14913304303fSsl ctrl_buf_size = EHCI_MAX_QTD_BUF_SIZE + 14923304303fSsl ctrl_reqp->ctrl_wLength; 14933304303fSsl } else { 14943304303fSsl ctrl_buf_size = SETUP_SIZE; 14953304303fSsl } 14963304303fSsl 14973304303fSsl tw = ehci_allocate_tw_resources(ehcip, pp, ctrl_buf_size, 14987c478bd9Sstevel@tonic-gate usb_flags, qtd_count); 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate return (tw); 15017c478bd9Sstevel@tonic-gate } 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate /* 15047c478bd9Sstevel@tonic-gate * ehci_insert_ctrl_req: 15057c478bd9Sstevel@tonic-gate * 15067c478bd9Sstevel@tonic-gate * Create a Transfer Descriptor (QTD) and a data buffer for a control endpoint. 15077c478bd9Sstevel@tonic-gate */ 15087c478bd9Sstevel@tonic-gate /* ARGSUSED */ 15097c478bd9Sstevel@tonic-gate void 15107c478bd9Sstevel@tonic-gate ehci_insert_ctrl_req( 15117c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 15127c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 15137c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp, 15147c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 15157c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 15167c478bd9Sstevel@tonic-gate { 15177c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 15187c478bd9Sstevel@tonic-gate uchar_t bmRequestType = ctrl_reqp->ctrl_bmRequestType; 15197c478bd9Sstevel@tonic-gate uchar_t bRequest = ctrl_reqp->ctrl_bRequest; 15207c478bd9Sstevel@tonic-gate uint16_t wValue = ctrl_reqp->ctrl_wValue; 15217c478bd9Sstevel@tonic-gate uint16_t wIndex = ctrl_reqp->ctrl_wIndex; 15227c478bd9Sstevel@tonic-gate uint16_t wLength = ctrl_reqp->ctrl_wLength; 15237c478bd9Sstevel@tonic-gate mblk_t *data = ctrl_reqp->ctrl_data; 15247c478bd9Sstevel@tonic-gate uint32_t ctrl = 0; 15257c478bd9Sstevel@tonic-gate uint8_t setup_packet[8]; 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 15287c478bd9Sstevel@tonic-gate "ehci_insert_ctrl_req:"); 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 15317c478bd9Sstevel@tonic-gate 15327c478bd9Sstevel@tonic-gate /* 15337c478bd9Sstevel@tonic-gate * Save current control request pointer and timeout values 15347c478bd9Sstevel@tonic-gate * in transfer wrapper. 15357c478bd9Sstevel@tonic-gate */ 15367c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)ctrl_reqp; 15377c478bd9Sstevel@tonic-gate tw->tw_timeout = ctrl_reqp->ctrl_timeout ? 15387c478bd9Sstevel@tonic-gate ctrl_reqp->ctrl_timeout : EHCI_DEFAULT_XFER_TIMEOUT; 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate /* 15417c478bd9Sstevel@tonic-gate * Initialize the callback and any callback data for when 15427c478bd9Sstevel@tonic-gate * the qtd completes. 15437c478bd9Sstevel@tonic-gate */ 15447c478bd9Sstevel@tonic-gate tw->tw_handle_qtd = ehci_handle_ctrl_qtd; 15457c478bd9Sstevel@tonic-gate tw->tw_handle_callback_value = NULL; 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate /* 15487c478bd9Sstevel@tonic-gate * swap the setup bytes where necessary since we specified 15497c478bd9Sstevel@tonic-gate * NEVERSWAP 15507c478bd9Sstevel@tonic-gate */ 15517c478bd9Sstevel@tonic-gate setup_packet[0] = bmRequestType; 15527c478bd9Sstevel@tonic-gate setup_packet[1] = bRequest; 15537c478bd9Sstevel@tonic-gate setup_packet[2] = wValue; 15547c478bd9Sstevel@tonic-gate setup_packet[3] = wValue >> 8; 15557c478bd9Sstevel@tonic-gate setup_packet[4] = wIndex; 15567c478bd9Sstevel@tonic-gate setup_packet[5] = wIndex >> 8; 15577c478bd9Sstevel@tonic-gate setup_packet[6] = wLength; 15587c478bd9Sstevel@tonic-gate setup_packet[7] = wLength >> 8; 15597c478bd9Sstevel@tonic-gate 15607c478bd9Sstevel@tonic-gate bcopy(setup_packet, tw->tw_buf, SETUP_SIZE); 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate Sync_IO_Buffer_for_device(tw->tw_dmahandle, SETUP_SIZE); 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate ctrl = (EHCI_QTD_CTRL_DATA_TOGGLE_0 | EHCI_QTD_CTRL_SETUP_PID); 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate /* 15677c478bd9Sstevel@tonic-gate * The QTD's are placed on the QH one at a time. 15687c478bd9Sstevel@tonic-gate * Once this QTD is placed on the done list, the 15697c478bd9Sstevel@tonic-gate * data or status phase QTD will be enqueued. 15707c478bd9Sstevel@tonic-gate */ 15713304303fSsl (void) ehci_insert_qtd(ehcip, ctrl, 0, SETUP_SIZE, 15727c478bd9Sstevel@tonic-gate EHCI_CTRL_SETUP_PHASE, pp, tw); 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 15757c478bd9Sstevel@tonic-gate "ehci_insert_ctrl_req: pp 0x%p", (void *)pp); 15767c478bd9Sstevel@tonic-gate 15777c478bd9Sstevel@tonic-gate /* 15787c478bd9Sstevel@tonic-gate * If this control transfer has a data phase, record the 15797c478bd9Sstevel@tonic-gate * direction. If the data phase is an OUT transaction, 15807c478bd9Sstevel@tonic-gate * copy the data into the buffer of the transfer wrapper. 15817c478bd9Sstevel@tonic-gate */ 15827c478bd9Sstevel@tonic-gate if (wLength != 0) { 15837c478bd9Sstevel@tonic-gate /* There is a data stage. Find the direction */ 15847c478bd9Sstevel@tonic-gate if (bmRequestType & USB_DEV_REQ_DEV_TO_HOST) { 15857c478bd9Sstevel@tonic-gate tw->tw_direction = EHCI_QTD_CTRL_IN_PID; 15867c478bd9Sstevel@tonic-gate } else { 15877c478bd9Sstevel@tonic-gate tw->tw_direction = EHCI_QTD_CTRL_OUT_PID; 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate /* Copy the data into the message */ 15903304303fSsl bcopy(data->b_rptr, tw->tw_buf + EHCI_MAX_QTD_BUF_SIZE, 1591*6a9de478Ssl wLength); 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate Sync_IO_Buffer_for_device(tw->tw_dmahandle, 1594*6a9de478Ssl wLength + EHCI_MAX_QTD_BUF_SIZE); 15957c478bd9Sstevel@tonic-gate } 15967c478bd9Sstevel@tonic-gate 15977c478bd9Sstevel@tonic-gate ctrl = (EHCI_QTD_CTRL_DATA_TOGGLE_1 | tw->tw_direction); 15987c478bd9Sstevel@tonic-gate 15997c478bd9Sstevel@tonic-gate /* 16007c478bd9Sstevel@tonic-gate * Create the QTD. If this is an OUT transaction, 16017c478bd9Sstevel@tonic-gate * the data is already in the buffer of the TW. 16023304303fSsl * The transfer should start from EHCI_MAX_QTD_BUF_SIZE 16033304303fSsl * which is 4K aligned, though the ctrl phase only 16043304303fSsl * transfers a length of SETUP_SIZE. The padding data 16053304303fSsl * in the TW buffer are discarded. 16067c478bd9Sstevel@tonic-gate */ 16073304303fSsl (void) ehci_insert_qtd(ehcip, ctrl, EHCI_MAX_QTD_BUF_SIZE, 16083304303fSsl tw->tw_length - EHCI_MAX_QTD_BUF_SIZE, 16093304303fSsl EHCI_CTRL_DATA_PHASE, pp, tw); 16107c478bd9Sstevel@tonic-gate 16117c478bd9Sstevel@tonic-gate /* 16127c478bd9Sstevel@tonic-gate * The direction of the STATUS QTD depends on 16137c478bd9Sstevel@tonic-gate * the direction of the transfer. 16147c478bd9Sstevel@tonic-gate */ 16157c478bd9Sstevel@tonic-gate if (tw->tw_direction == EHCI_QTD_CTRL_IN_PID) { 16167c478bd9Sstevel@tonic-gate ctrl = (EHCI_QTD_CTRL_DATA_TOGGLE_1| 16177c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_OUT_PID | 16187c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_INTR_ON_COMPLETE); 16197c478bd9Sstevel@tonic-gate } else { 16207c478bd9Sstevel@tonic-gate ctrl = (EHCI_QTD_CTRL_DATA_TOGGLE_1| 16217c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_IN_PID | 16227c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_INTR_ON_COMPLETE); 16237c478bd9Sstevel@tonic-gate } 16247c478bd9Sstevel@tonic-gate } else { 16257c478bd9Sstevel@tonic-gate /* 16267c478bd9Sstevel@tonic-gate * There is no data stage, then initiate 16277c478bd9Sstevel@tonic-gate * status phase from the host. 16287c478bd9Sstevel@tonic-gate */ 16297c478bd9Sstevel@tonic-gate ctrl = (EHCI_QTD_CTRL_DATA_TOGGLE_1 | 16307c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_IN_PID | 16317c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_INTR_ON_COMPLETE); 16327c478bd9Sstevel@tonic-gate } 16337c478bd9Sstevel@tonic-gate 16347c478bd9Sstevel@tonic-gate 16353304303fSsl (void) ehci_insert_qtd(ehcip, ctrl, 0, 0, 16367c478bd9Sstevel@tonic-gate EHCI_CTRL_STATUS_PHASE, pp, tw); 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate /* Start the timer for this control transfer */ 16397c478bd9Sstevel@tonic-gate ehci_start_xfer_timer(ehcip, pp, tw); 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate /* 16447c478bd9Sstevel@tonic-gate * ehci_allocate_bulk_resources: 16457c478bd9Sstevel@tonic-gate * 16467c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a ctrl transfer, and allocates 16477c478bd9Sstevel@tonic-gate * all the resources necessary. 16487c478bd9Sstevel@tonic-gate * 16497c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW. 16507c478bd9Sstevel@tonic-gate */ 16517c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t * 16527c478bd9Sstevel@tonic-gate ehci_allocate_bulk_resources( 16537c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 16547c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 16557c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 16567c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 16577c478bd9Sstevel@tonic-gate { 16587c478bd9Sstevel@tonic-gate size_t qtd_count = 0; 16597c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw; 16607c478bd9Sstevel@tonic-gate 16617c478bd9Sstevel@tonic-gate /* Check the size of bulk request */ 16627c478bd9Sstevel@tonic-gate if (bulk_reqp->bulk_len > EHCI_MAX_BULK_XFER_SIZE) { 16637c478bd9Sstevel@tonic-gate 16647c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 16657c478bd9Sstevel@tonic-gate "ehci_allocate_bulk_resources: Bulk request size 0x%x is " 16667c478bd9Sstevel@tonic-gate "more than 0x%x", bulk_reqp->bulk_len, 16677c478bd9Sstevel@tonic-gate EHCI_MAX_BULK_XFER_SIZE); 16687c478bd9Sstevel@tonic-gate 16697c478bd9Sstevel@tonic-gate return (NULL); 16707c478bd9Sstevel@tonic-gate } 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate /* Get the required bulk packet size */ 16737c478bd9Sstevel@tonic-gate qtd_count = bulk_reqp->bulk_len / EHCI_MAX_QTD_XFER_SIZE; 1674688b07c5Sgc if (bulk_reqp->bulk_len % EHCI_MAX_QTD_XFER_SIZE || 1675*6a9de478Ssl bulk_reqp->bulk_len == 0) { 16767c478bd9Sstevel@tonic-gate qtd_count += 1; 16777c478bd9Sstevel@tonic-gate } 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate tw = ehci_allocate_tw_resources(ehcip, pp, bulk_reqp->bulk_len, 16807c478bd9Sstevel@tonic-gate usb_flags, qtd_count); 16817c478bd9Sstevel@tonic-gate 16827c478bd9Sstevel@tonic-gate return (tw); 16837c478bd9Sstevel@tonic-gate } 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate /* 16867c478bd9Sstevel@tonic-gate * ehci_insert_bulk_req: 16877c478bd9Sstevel@tonic-gate * 16887c478bd9Sstevel@tonic-gate * Create a Transfer Descriptor (QTD) and a data buffer for a bulk 16897c478bd9Sstevel@tonic-gate * endpoint. 16907c478bd9Sstevel@tonic-gate */ 16917c478bd9Sstevel@tonic-gate /* ARGSUSED */ 16927c478bd9Sstevel@tonic-gate void 16937c478bd9Sstevel@tonic-gate ehci_insert_bulk_req( 16947c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 16957c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 16967c478bd9Sstevel@tonic-gate usb_bulk_req_t *bulk_reqp, 16977c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 16987c478bd9Sstevel@tonic-gate usb_flags_t flags) 16997c478bd9Sstevel@tonic-gate { 17007c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 17017c478bd9Sstevel@tonic-gate uint_t bulk_pkt_size, count; 17027c478bd9Sstevel@tonic-gate size_t residue = 0, len = 0; 17037c478bd9Sstevel@tonic-gate uint32_t ctrl = 0; 17047c478bd9Sstevel@tonic-gate int pipe_dir; 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 17077c478bd9Sstevel@tonic-gate "ehci_insert_bulk_req: bulk_reqp = 0x%p flags = 0x%x", 17087c478bd9Sstevel@tonic-gate bulk_reqp, flags); 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 17117c478bd9Sstevel@tonic-gate 17127c478bd9Sstevel@tonic-gate /* Get the bulk pipe direction */ 17137c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate /* Get the required bulk packet size */ 17167c478bd9Sstevel@tonic-gate bulk_pkt_size = min(bulk_reqp->bulk_len, EHCI_MAX_QTD_XFER_SIZE); 17177c478bd9Sstevel@tonic-gate 1718688b07c5Sgc if (bulk_pkt_size) { 1719688b07c5Sgc residue = tw->tw_length % bulk_pkt_size; 1720688b07c5Sgc } 17217c478bd9Sstevel@tonic-gate 17227c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 17237c478bd9Sstevel@tonic-gate "ehci_insert_bulk_req: bulk_pkt_size = %d", bulk_pkt_size); 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate /* 17267c478bd9Sstevel@tonic-gate * Save current bulk request pointer and timeout values 17277c478bd9Sstevel@tonic-gate * in transfer wrapper. 17287c478bd9Sstevel@tonic-gate */ 17297c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)bulk_reqp; 17307c478bd9Sstevel@tonic-gate tw->tw_timeout = bulk_reqp->bulk_timeout; 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate /* 17337c478bd9Sstevel@tonic-gate * Initialize the callback and any callback 17347c478bd9Sstevel@tonic-gate * data required when the qtd completes. 17357c478bd9Sstevel@tonic-gate */ 17367c478bd9Sstevel@tonic-gate tw->tw_handle_qtd = ehci_handle_bulk_qtd; 17377c478bd9Sstevel@tonic-gate tw->tw_handle_callback_value = NULL; 17387c478bd9Sstevel@tonic-gate 17397c478bd9Sstevel@tonic-gate tw->tw_direction = (pipe_dir == USB_EP_DIR_OUT) ? 17407c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_OUT_PID : EHCI_QTD_CTRL_IN_PID; 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate if (tw->tw_direction == EHCI_QTD_CTRL_OUT_PID) { 17437c478bd9Sstevel@tonic-gate 1744688b07c5Sgc if (bulk_reqp->bulk_len) { 1745688b07c5Sgc ASSERT(bulk_reqp->bulk_data != NULL); 17467c478bd9Sstevel@tonic-gate 1747688b07c5Sgc bcopy(bulk_reqp->bulk_data->b_rptr, tw->tw_buf, 1748*6a9de478Ssl bulk_reqp->bulk_len); 17497c478bd9Sstevel@tonic-gate 1750688b07c5Sgc Sync_IO_Buffer_for_device(tw->tw_dmahandle, 1751*6a9de478Ssl bulk_reqp->bulk_len); 1752688b07c5Sgc } 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate ctrl = tw->tw_direction; 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate /* Insert all the bulk QTDs */ 17587c478bd9Sstevel@tonic-gate for (count = 0; count < tw->tw_num_qtds; count++) { 17597c478bd9Sstevel@tonic-gate 17607c478bd9Sstevel@tonic-gate /* Check for last qtd */ 17617c478bd9Sstevel@tonic-gate if (count == (tw->tw_num_qtds - 1)) { 17627c478bd9Sstevel@tonic-gate 17637c478bd9Sstevel@tonic-gate ctrl |= EHCI_QTD_CTRL_INTR_ON_COMPLETE; 17647c478bd9Sstevel@tonic-gate 17657c478bd9Sstevel@tonic-gate /* Check for inserting residue data */ 17667c478bd9Sstevel@tonic-gate if (residue) { 17677c478bd9Sstevel@tonic-gate bulk_pkt_size = residue; 17687c478bd9Sstevel@tonic-gate } 17697c478bd9Sstevel@tonic-gate } 17707c478bd9Sstevel@tonic-gate 17717c478bd9Sstevel@tonic-gate /* Insert the QTD onto the endpoint */ 17723304303fSsl (void) ehci_insert_qtd(ehcip, ctrl, len, bulk_pkt_size, 17733304303fSsl 0, pp, tw); 17747c478bd9Sstevel@tonic-gate 17757c478bd9Sstevel@tonic-gate len = len + bulk_pkt_size; 17767c478bd9Sstevel@tonic-gate } 17777c478bd9Sstevel@tonic-gate 17787c478bd9Sstevel@tonic-gate /* Start the timer for this bulk transfer */ 17797c478bd9Sstevel@tonic-gate ehci_start_xfer_timer(ehcip, pp, tw); 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate 17837c478bd9Sstevel@tonic-gate /* 17847c478bd9Sstevel@tonic-gate * ehci_start_periodic_pipe_polling: 17857c478bd9Sstevel@tonic-gate * 17867c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 17877c478bd9Sstevel@tonic-gate */ 17887c478bd9Sstevel@tonic-gate int 17897c478bd9Sstevel@tonic-gate ehci_start_periodic_pipe_polling( 17907c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 17917c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 17927c478bd9Sstevel@tonic-gate usb_opaque_t periodic_in_reqp, 17937c478bd9Sstevel@tonic-gate usb_flags_t flags) 17947c478bd9Sstevel@tonic-gate { 17957c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 17967c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 17977c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 17987c478bd9Sstevel@tonic-gate 17997c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 18007c478bd9Sstevel@tonic-gate "ehci_start_periodic_pipe_polling: ep%d", 18017c478bd9Sstevel@tonic-gate ph->p_ep.bEndpointAddress & USB_EP_NUM_MASK); 18027c478bd9Sstevel@tonic-gate 18037c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 18047c478bd9Sstevel@tonic-gate 18057c478bd9Sstevel@tonic-gate /* 18067c478bd9Sstevel@tonic-gate * Check and handle start polling on root hub interrupt pipe. 18077c478bd9Sstevel@tonic-gate */ 18087c478bd9Sstevel@tonic-gate if ((ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) && 18097c478bd9Sstevel@tonic-gate ((eptd->bmAttributes & USB_EP_ATTR_MASK) == 18107c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR)) { 18117c478bd9Sstevel@tonic-gate 18127c478bd9Sstevel@tonic-gate error = ehci_handle_root_hub_pipe_start_intr_polling(ph, 18137c478bd9Sstevel@tonic-gate (usb_intr_req_t *)periodic_in_reqp, flags); 18147c478bd9Sstevel@tonic-gate 18157c478bd9Sstevel@tonic-gate return (error); 18167c478bd9Sstevel@tonic-gate } 18177c478bd9Sstevel@tonic-gate 18187c478bd9Sstevel@tonic-gate switch (pp->pp_state) { 18197c478bd9Sstevel@tonic-gate case EHCI_PIPE_STATE_IDLE: 18207c478bd9Sstevel@tonic-gate /* Save the Original client's Periodic IN request */ 18217c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = periodic_in_reqp; 18227c478bd9Sstevel@tonic-gate 18237c478bd9Sstevel@tonic-gate /* 18247c478bd9Sstevel@tonic-gate * This pipe is uninitialized or if a valid QTD is 18257c478bd9Sstevel@tonic-gate * not found then insert a QTD on the interrupt IN 18267c478bd9Sstevel@tonic-gate * endpoint. 18277c478bd9Sstevel@tonic-gate */ 18287c478bd9Sstevel@tonic-gate error = ehci_start_pipe_polling(ehcip, ph, flags); 18297c478bd9Sstevel@tonic-gate 18307c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 18317c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, 18327c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 18337c478bd9Sstevel@tonic-gate "ehci_start_periodic_pipe_polling: " 18347c478bd9Sstevel@tonic-gate "Start polling failed"); 18357c478bd9Sstevel@tonic-gate 18367c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL; 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate return (error); 18397c478bd9Sstevel@tonic-gate } 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 18427c478bd9Sstevel@tonic-gate "ehci_start_periodic_pipe_polling: PP = 0x%p", pp); 18437c478bd9Sstevel@tonic-gate 18447c478bd9Sstevel@tonic-gate #ifdef DEBUG 18457c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 18467c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 18477c478bd9Sstevel@tonic-gate ASSERT((pp->pp_tw_head != NULL) && 18487c478bd9Sstevel@tonic-gate (pp->pp_tw_tail != NULL)); 18497c478bd9Sstevel@tonic-gate break; 18507c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 18517c478bd9Sstevel@tonic-gate ASSERT((pp->pp_itw_head != NULL) && 18527c478bd9Sstevel@tonic-gate (pp->pp_itw_tail != NULL)); 18537c478bd9Sstevel@tonic-gate break; 18547c478bd9Sstevel@tonic-gate } 18557c478bd9Sstevel@tonic-gate #endif 18567c478bd9Sstevel@tonic-gate 18577c478bd9Sstevel@tonic-gate break; 18587c478bd9Sstevel@tonic-gate case EHCI_PIPE_STATE_ACTIVE: 18597c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, 18607c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 18617c478bd9Sstevel@tonic-gate "ehci_start_periodic_pipe_polling: " 18627c478bd9Sstevel@tonic-gate "Polling is already in progress"); 18637c478bd9Sstevel@tonic-gate 18647c478bd9Sstevel@tonic-gate error = USB_FAILURE; 18657c478bd9Sstevel@tonic-gate break; 18667c478bd9Sstevel@tonic-gate case EHCI_PIPE_STATE_ERROR: 18677c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, 18687c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 18697c478bd9Sstevel@tonic-gate "ehci_start_periodic_pipe_polling: " 18707c478bd9Sstevel@tonic-gate "Pipe is halted and perform reset" 18717c478bd9Sstevel@tonic-gate "before restart polling"); 18727c478bd9Sstevel@tonic-gate 18737c478bd9Sstevel@tonic-gate error = USB_FAILURE; 18747c478bd9Sstevel@tonic-gate break; 18757c478bd9Sstevel@tonic-gate default: 18767c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, 18777c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 18787c478bd9Sstevel@tonic-gate "ehci_start_periodic_pipe_polling: " 18797c478bd9Sstevel@tonic-gate "Undefined state"); 18807c478bd9Sstevel@tonic-gate 18817c478bd9Sstevel@tonic-gate error = USB_FAILURE; 18827c478bd9Sstevel@tonic-gate break; 18837c478bd9Sstevel@tonic-gate } 18847c478bd9Sstevel@tonic-gate 18857c478bd9Sstevel@tonic-gate return (error); 18867c478bd9Sstevel@tonic-gate } 18877c478bd9Sstevel@tonic-gate 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate /* 18907c478bd9Sstevel@tonic-gate * ehci_start_pipe_polling: 18917c478bd9Sstevel@tonic-gate * 18927c478bd9Sstevel@tonic-gate * Insert the number of periodic requests corresponding to polling 18937c478bd9Sstevel@tonic-gate * interval as calculated during pipe open. 18947c478bd9Sstevel@tonic-gate */ 18957c478bd9Sstevel@tonic-gate static int 18967c478bd9Sstevel@tonic-gate ehci_start_pipe_polling( 18977c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 18987c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 18997c478bd9Sstevel@tonic-gate usb_flags_t flags) 19007c478bd9Sstevel@tonic-gate { 19017c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 19027c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 19037c478bd9Sstevel@tonic-gate int error = USB_FAILURE; 19047c478bd9Sstevel@tonic-gate 19057c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 19067c478bd9Sstevel@tonic-gate "ehci_start_pipe_polling:"); 19077c478bd9Sstevel@tonic-gate 19087c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 19097c478bd9Sstevel@tonic-gate 19107c478bd9Sstevel@tonic-gate /* 19117c478bd9Sstevel@tonic-gate * For the start polling, pp_max_periodic_req_cnt will be zero 19127c478bd9Sstevel@tonic-gate * and for the restart polling request, it will be non zero. 19137c478bd9Sstevel@tonic-gate * 19147c478bd9Sstevel@tonic-gate * In case of start polling request, find out number of requests 19157c478bd9Sstevel@tonic-gate * required for the Interrupt IN endpoints corresponding to the 19167c478bd9Sstevel@tonic-gate * endpoint polling interval. For Isochronous IN endpoints, it is 19177c478bd9Sstevel@tonic-gate * always fixed since its polling interval will be one ms. 19187c478bd9Sstevel@tonic-gate */ 19197c478bd9Sstevel@tonic-gate if (pp->pp_max_periodic_req_cnt == 0) { 19207c478bd9Sstevel@tonic-gate 19217c478bd9Sstevel@tonic-gate ehci_set_periodic_pipe_polling(ehcip, ph); 19227c478bd9Sstevel@tonic-gate } 19237c478bd9Sstevel@tonic-gate 19247c478bd9Sstevel@tonic-gate ASSERT(pp->pp_max_periodic_req_cnt != 0); 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 19277c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 19287c478bd9Sstevel@tonic-gate error = ehci_start_intr_polling(ehcip, ph, flags); 19297c478bd9Sstevel@tonic-gate break; 19307c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 19317c478bd9Sstevel@tonic-gate error = ehci_start_isoc_polling(ehcip, ph, flags); 19327c478bd9Sstevel@tonic-gate break; 19337c478bd9Sstevel@tonic-gate } 19347c478bd9Sstevel@tonic-gate 19357c478bd9Sstevel@tonic-gate return (error); 19367c478bd9Sstevel@tonic-gate } 19377c478bd9Sstevel@tonic-gate 19387c478bd9Sstevel@tonic-gate static int 19397c478bd9Sstevel@tonic-gate ehci_start_intr_polling( 19407c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 19417c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 19427c478bd9Sstevel@tonic-gate usb_flags_t flags) 19437c478bd9Sstevel@tonic-gate { 19447c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 19457c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw_list, *tw; 19467c478bd9Sstevel@tonic-gate int i, total_tws; 19477c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 19487c478bd9Sstevel@tonic-gate 19497c478bd9Sstevel@tonic-gate /* Allocate all the necessary resources for the IN transfer */ 19507c478bd9Sstevel@tonic-gate tw_list = NULL; 19517c478bd9Sstevel@tonic-gate total_tws = pp->pp_max_periodic_req_cnt - pp->pp_cur_periodic_req_cnt; 19527c478bd9Sstevel@tonic-gate for (i = 0; i < total_tws; i += 1) { 19537c478bd9Sstevel@tonic-gate tw = ehci_allocate_intr_resources(ehcip, ph, NULL, flags); 19547c478bd9Sstevel@tonic-gate if (tw == NULL) { 19557c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES; 19567c478bd9Sstevel@tonic-gate /* There are not enough resources, deallocate the TWs */ 19577c478bd9Sstevel@tonic-gate tw = tw_list; 19587c478bd9Sstevel@tonic-gate while (tw != NULL) { 19597c478bd9Sstevel@tonic-gate tw_list = tw->tw_next; 19607c478bd9Sstevel@tonic-gate ehci_deallocate_intr_in_resource( 1961*6a9de478Ssl ehcip, pp, tw); 19627c478bd9Sstevel@tonic-gate ehci_deallocate_tw(ehcip, pp, tw); 19637c478bd9Sstevel@tonic-gate tw = tw_list; 19647c478bd9Sstevel@tonic-gate } 19657c478bd9Sstevel@tonic-gate 19667c478bd9Sstevel@tonic-gate return (error); 19677c478bd9Sstevel@tonic-gate } else { 19687c478bd9Sstevel@tonic-gate if (tw_list == NULL) { 19697c478bd9Sstevel@tonic-gate tw_list = tw; 19707c478bd9Sstevel@tonic-gate } 19717c478bd9Sstevel@tonic-gate } 19727c478bd9Sstevel@tonic-gate } 19737c478bd9Sstevel@tonic-gate 19747c478bd9Sstevel@tonic-gate while (pp->pp_cur_periodic_req_cnt < pp->pp_max_periodic_req_cnt) { 19757c478bd9Sstevel@tonic-gate 19767c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 19777c478bd9Sstevel@tonic-gate "ehci_start_pipe_polling: max = %d curr = %d tw = %p:", 19787c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt, pp->pp_cur_periodic_req_cnt, 19797c478bd9Sstevel@tonic-gate tw_list); 19807c478bd9Sstevel@tonic-gate 19817c478bd9Sstevel@tonic-gate tw = tw_list; 19827c478bd9Sstevel@tonic-gate tw_list = tw->tw_next; 19837c478bd9Sstevel@tonic-gate 19847c478bd9Sstevel@tonic-gate ehci_insert_intr_req(ehcip, pp, tw, flags); 19857c478bd9Sstevel@tonic-gate 19867c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt++; 19877c478bd9Sstevel@tonic-gate } 19887c478bd9Sstevel@tonic-gate 19897c478bd9Sstevel@tonic-gate return (error); 19907c478bd9Sstevel@tonic-gate } 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate 19937c478bd9Sstevel@tonic-gate /* 19947c478bd9Sstevel@tonic-gate * ehci_set_periodic_pipe_polling: 19957c478bd9Sstevel@tonic-gate * 19967c478bd9Sstevel@tonic-gate * Calculate the number of periodic requests needed corresponding to the 19977c478bd9Sstevel@tonic-gate * interrupt IN endpoints polling interval. Table below gives the number 19987c478bd9Sstevel@tonic-gate * of periodic requests needed for the interrupt IN endpoints according 19997c478bd9Sstevel@tonic-gate * to endpoint polling interval. 20007c478bd9Sstevel@tonic-gate * 20017c478bd9Sstevel@tonic-gate * Polling interval Number of periodic requests 20027c478bd9Sstevel@tonic-gate * 20037c478bd9Sstevel@tonic-gate * 1ms 4 20047c478bd9Sstevel@tonic-gate * 2ms 2 20057c478bd9Sstevel@tonic-gate * 4ms to 32ms 1 20067c478bd9Sstevel@tonic-gate */ 20077c478bd9Sstevel@tonic-gate static void 20087c478bd9Sstevel@tonic-gate ehci_set_periodic_pipe_polling( 20097c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 20107c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 20117c478bd9Sstevel@tonic-gate { 20127c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 20137c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 20147c478bd9Sstevel@tonic-gate uchar_t ep_attr = endpoint->bmAttributes; 20157c478bd9Sstevel@tonic-gate uint_t interval; 20167c478bd9Sstevel@tonic-gate 20177c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 20187c478bd9Sstevel@tonic-gate "ehci_set_periodic_pipe_polling:"); 20197c478bd9Sstevel@tonic-gate 20207c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 20217c478bd9Sstevel@tonic-gate 20227c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt = 0; 20237c478bd9Sstevel@tonic-gate 20247c478bd9Sstevel@tonic-gate /* 20257c478bd9Sstevel@tonic-gate * Check usb flag whether USB_FLAGS_ONE_TIME_POLL flag is 20267c478bd9Sstevel@tonic-gate * set and if so, set pp->pp_max_periodic_req_cnt to one. 20277c478bd9Sstevel@tonic-gate */ 20287c478bd9Sstevel@tonic-gate if (((ep_attr & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) && 20297c478bd9Sstevel@tonic-gate (pp->pp_client_periodic_in_reqp)) { 20307c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp = (usb_intr_req_t *) 2031*6a9de478Ssl pp->pp_client_periodic_in_reqp; 20327c478bd9Sstevel@tonic-gate 20337c478bd9Sstevel@tonic-gate if (intr_reqp->intr_attributes & 20347c478bd9Sstevel@tonic-gate USB_ATTRS_ONE_XFER) { 20357c478bd9Sstevel@tonic-gate 20367c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = EHCI_INTR_XMS_REQS; 20377c478bd9Sstevel@tonic-gate 20387c478bd9Sstevel@tonic-gate return; 20397c478bd9Sstevel@tonic-gate } 20407c478bd9Sstevel@tonic-gate } 20417c478bd9Sstevel@tonic-gate 20427c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_usba_device->usb_mutex); 20437c478bd9Sstevel@tonic-gate 20447c478bd9Sstevel@tonic-gate /* 20457c478bd9Sstevel@tonic-gate * The ehci_adjust_polling_interval function will not fail 20467c478bd9Sstevel@tonic-gate * at this instance since bandwidth allocation is already 20477c478bd9Sstevel@tonic-gate * done. Here we are getting only the periodic interval. 20487c478bd9Sstevel@tonic-gate */ 20497c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, 2050*6a9de478Ssl ph->p_usba_device->usb_port_status); 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_usba_device->usb_mutex); 20537c478bd9Sstevel@tonic-gate 20547c478bd9Sstevel@tonic-gate switch (interval) { 20557c478bd9Sstevel@tonic-gate case EHCI_INTR_1MS_POLL: 20567c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = EHCI_INTR_1MS_REQS; 20577c478bd9Sstevel@tonic-gate break; 20587c478bd9Sstevel@tonic-gate case EHCI_INTR_2MS_POLL: 20597c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = EHCI_INTR_2MS_REQS; 20607c478bd9Sstevel@tonic-gate break; 20617c478bd9Sstevel@tonic-gate default: 20627c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt = EHCI_INTR_XMS_REQS; 20637c478bd9Sstevel@tonic-gate break; 20647c478bd9Sstevel@tonic-gate } 20657c478bd9Sstevel@tonic-gate 20667c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 20677c478bd9Sstevel@tonic-gate "ehci_set_periodic_pipe_polling: Max periodic requests = %d", 20687c478bd9Sstevel@tonic-gate pp->pp_max_periodic_req_cnt); 20697c478bd9Sstevel@tonic-gate } 20707c478bd9Sstevel@tonic-gate 20717c478bd9Sstevel@tonic-gate /* 20727c478bd9Sstevel@tonic-gate * ehci_allocate_intr_resources: 20737c478bd9Sstevel@tonic-gate * 20747c478bd9Sstevel@tonic-gate * Calculates the number of tds necessary for a intr transfer, and allocates 20757c478bd9Sstevel@tonic-gate * all the necessary resources. 20767c478bd9Sstevel@tonic-gate * 20777c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW. 20787c478bd9Sstevel@tonic-gate */ 20797c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t * 20807c478bd9Sstevel@tonic-gate ehci_allocate_intr_resources( 20817c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 20827c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 20837c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp, 20847c478bd9Sstevel@tonic-gate usb_flags_t flags) 20857c478bd9Sstevel@tonic-gate { 20867c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 20877c478bd9Sstevel@tonic-gate int pipe_dir; 20887c478bd9Sstevel@tonic-gate size_t qtd_count = 1; 20897c478bd9Sstevel@tonic-gate size_t tw_length; 20907c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw; 20917c478bd9Sstevel@tonic-gate 20927c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 20937c478bd9Sstevel@tonic-gate "ehci_allocate_intr_resources:"); 20947c478bd9Sstevel@tonic-gate 20957c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 20967c478bd9Sstevel@tonic-gate 20977c478bd9Sstevel@tonic-gate pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 20987c478bd9Sstevel@tonic-gate 20997c478bd9Sstevel@tonic-gate /* Get the length of interrupt transfer & alloc data */ 21007c478bd9Sstevel@tonic-gate if (intr_reqp) { 21017c478bd9Sstevel@tonic-gate tw_length = intr_reqp->intr_len; 21027c478bd9Sstevel@tonic-gate } else { 21037c478bd9Sstevel@tonic-gate ASSERT(pipe_dir == USB_EP_DIR_IN); 21047c478bd9Sstevel@tonic-gate tw_length = (pp->pp_client_periodic_in_reqp) ? 21057c478bd9Sstevel@tonic-gate (((usb_intr_req_t *)pp-> 21067c478bd9Sstevel@tonic-gate pp_client_periodic_in_reqp)->intr_len) : 21077c478bd9Sstevel@tonic-gate ph->p_ep.wMaxPacketSize; 21087c478bd9Sstevel@tonic-gate } 21097c478bd9Sstevel@tonic-gate 21107c478bd9Sstevel@tonic-gate /* Check the size of interrupt request */ 21117c478bd9Sstevel@tonic-gate if (tw_length > EHCI_MAX_QTD_XFER_SIZE) { 21127c478bd9Sstevel@tonic-gate 21137c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 21147c478bd9Sstevel@tonic-gate "ehci_allocate_intr_resources: Intr request size 0x%lx is " 21157c478bd9Sstevel@tonic-gate "more than 0x%x", tw_length, EHCI_MAX_QTD_XFER_SIZE); 21167c478bd9Sstevel@tonic-gate 21177c478bd9Sstevel@tonic-gate return (NULL); 21187c478bd9Sstevel@tonic-gate } 21197c478bd9Sstevel@tonic-gate 21207c478bd9Sstevel@tonic-gate if ((tw = ehci_allocate_tw_resources(ehcip, pp, tw_length, flags, 21217c478bd9Sstevel@tonic-gate qtd_count)) == NULL) { 21227c478bd9Sstevel@tonic-gate 21237c478bd9Sstevel@tonic-gate return (NULL); 21247c478bd9Sstevel@tonic-gate } 21257c478bd9Sstevel@tonic-gate 21267c478bd9Sstevel@tonic-gate if (pipe_dir == USB_EP_DIR_IN) { 21277c478bd9Sstevel@tonic-gate if (ehci_allocate_intr_in_resource(ehcip, pp, tw, flags) != 21287c478bd9Sstevel@tonic-gate USB_SUCCESS) { 21297c478bd9Sstevel@tonic-gate ehci_deallocate_tw(ehcip, pp, tw); 21307c478bd9Sstevel@tonic-gate } 21317c478bd9Sstevel@tonic-gate tw->tw_direction = EHCI_QTD_CTRL_IN_PID; 21327c478bd9Sstevel@tonic-gate } else { 2133688b07c5Sgc if (tw_length) { 2134688b07c5Sgc ASSERT(intr_reqp->intr_data != NULL); 21357c478bd9Sstevel@tonic-gate 2136688b07c5Sgc /* Copy the data into the buffer */ 2137688b07c5Sgc bcopy(intr_reqp->intr_data->b_rptr, tw->tw_buf, 2138688b07c5Sgc intr_reqp->intr_len); 21397c478bd9Sstevel@tonic-gate 2140688b07c5Sgc Sync_IO_Buffer_for_device(tw->tw_dmahandle, 2141688b07c5Sgc intr_reqp->intr_len); 2142688b07c5Sgc } 21437c478bd9Sstevel@tonic-gate 21447c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)intr_reqp; 21457c478bd9Sstevel@tonic-gate tw->tw_direction = EHCI_QTD_CTRL_OUT_PID; 21467c478bd9Sstevel@tonic-gate } 21477c478bd9Sstevel@tonic-gate 21487c478bd9Sstevel@tonic-gate if (intr_reqp) { 21497c478bd9Sstevel@tonic-gate tw->tw_timeout = intr_reqp->intr_timeout; 21507c478bd9Sstevel@tonic-gate } 21517c478bd9Sstevel@tonic-gate 21527c478bd9Sstevel@tonic-gate /* 21537c478bd9Sstevel@tonic-gate * Initialize the callback and any callback 21547c478bd9Sstevel@tonic-gate * data required when the qtd completes. 21557c478bd9Sstevel@tonic-gate */ 21567c478bd9Sstevel@tonic-gate tw->tw_handle_qtd = ehci_handle_intr_qtd; 21577c478bd9Sstevel@tonic-gate tw->tw_handle_callback_value = NULL; 21587c478bd9Sstevel@tonic-gate 21597c478bd9Sstevel@tonic-gate return (tw); 21607c478bd9Sstevel@tonic-gate } 21617c478bd9Sstevel@tonic-gate 21627c478bd9Sstevel@tonic-gate 21637c478bd9Sstevel@tonic-gate /* 21647c478bd9Sstevel@tonic-gate * ehci_insert_intr_req: 21657c478bd9Sstevel@tonic-gate * 21667c478bd9Sstevel@tonic-gate * Insert an Interrupt request into the Host Controller's periodic list. 21677c478bd9Sstevel@tonic-gate */ 21687c478bd9Sstevel@tonic-gate /* ARGSUSED */ 21697c478bd9Sstevel@tonic-gate void 21707c478bd9Sstevel@tonic-gate ehci_insert_intr_req( 21717c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 21727c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 21737c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 21747c478bd9Sstevel@tonic-gate usb_flags_t flags) 21757c478bd9Sstevel@tonic-gate { 21767c478bd9Sstevel@tonic-gate uint_t ctrl = 0; 21777c478bd9Sstevel@tonic-gate 21787c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 21797c478bd9Sstevel@tonic-gate 21807c478bd9Sstevel@tonic-gate ASSERT(tw->tw_curr_xfer_reqp != NULL); 21817c478bd9Sstevel@tonic-gate 21827c478bd9Sstevel@tonic-gate ctrl = (tw->tw_direction | EHCI_QTD_CTRL_INTR_ON_COMPLETE); 21837c478bd9Sstevel@tonic-gate 21847c478bd9Sstevel@tonic-gate /* Insert another interrupt QTD */ 21853304303fSsl (void) ehci_insert_qtd(ehcip, ctrl, 0, tw->tw_length, 0, pp, tw); 21867c478bd9Sstevel@tonic-gate 21877c478bd9Sstevel@tonic-gate /* Start the timer for this Interrupt transfer */ 21887c478bd9Sstevel@tonic-gate ehci_start_xfer_timer(ehcip, pp, tw); 21897c478bd9Sstevel@tonic-gate } 21907c478bd9Sstevel@tonic-gate 21917c478bd9Sstevel@tonic-gate 21927c478bd9Sstevel@tonic-gate /* 21937c478bd9Sstevel@tonic-gate * ehci_stop_periodic_pipe_polling: 21947c478bd9Sstevel@tonic-gate */ 21957c478bd9Sstevel@tonic-gate /* ARGSUSED */ 21967c478bd9Sstevel@tonic-gate int 21977c478bd9Sstevel@tonic-gate ehci_stop_periodic_pipe_polling( 21987c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 21997c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 22007c478bd9Sstevel@tonic-gate usb_flags_t flags) 22017c478bd9Sstevel@tonic-gate { 22027c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 22037c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 22047c478bd9Sstevel@tonic-gate 22057c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 22067c478bd9Sstevel@tonic-gate "ehci_stop_periodic_pipe_polling: Flags = 0x%x", flags); 22077c478bd9Sstevel@tonic-gate 22087c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 22097c478bd9Sstevel@tonic-gate 22107c478bd9Sstevel@tonic-gate /* 22117c478bd9Sstevel@tonic-gate * Check and handle stop polling on root hub interrupt pipe. 22127c478bd9Sstevel@tonic-gate */ 22137c478bd9Sstevel@tonic-gate if ((ph->p_usba_device->usb_addr == ROOT_HUB_ADDR) && 22147c478bd9Sstevel@tonic-gate ((eptd->bmAttributes & USB_EP_ATTR_MASK) == 22157c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR)) { 22167c478bd9Sstevel@tonic-gate 22177c478bd9Sstevel@tonic-gate ehci_handle_root_hub_pipe_stop_intr_polling(ph, flags); 22187c478bd9Sstevel@tonic-gate 22197c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 22207c478bd9Sstevel@tonic-gate } 22217c478bd9Sstevel@tonic-gate 22227c478bd9Sstevel@tonic-gate if (pp->pp_state != EHCI_PIPE_STATE_ACTIVE) { 22237c478bd9Sstevel@tonic-gate 22247c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 22257c478bd9Sstevel@tonic-gate "ehci_stop_periodic_pipe_polling: " 22267c478bd9Sstevel@tonic-gate "Polling already stopped"); 22277c478bd9Sstevel@tonic-gate 22287c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 22297c478bd9Sstevel@tonic-gate } 22307c478bd9Sstevel@tonic-gate 22317c478bd9Sstevel@tonic-gate /* Set pipe state to pipe stop polling */ 22327c478bd9Sstevel@tonic-gate pp->pp_state = EHCI_PIPE_STATE_STOP_POLLING; 22337c478bd9Sstevel@tonic-gate 22347c478bd9Sstevel@tonic-gate ehci_pipe_cleanup(ehcip, ph); 22357c478bd9Sstevel@tonic-gate 22367c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 22377c478bd9Sstevel@tonic-gate } 22387c478bd9Sstevel@tonic-gate 22397c478bd9Sstevel@tonic-gate 22407c478bd9Sstevel@tonic-gate /* 22417c478bd9Sstevel@tonic-gate * ehci_insert_qtd: 22427c478bd9Sstevel@tonic-gate * 22437c478bd9Sstevel@tonic-gate * Insert a Transfer Descriptor (QTD) on an Endpoint Descriptor (QH). 22447c478bd9Sstevel@tonic-gate * Always returns USB_SUCCESS for now. Once Isoch has been implemented, 22457c478bd9Sstevel@tonic-gate * it may return USB_FAILURE. 22467c478bd9Sstevel@tonic-gate */ 22477c478bd9Sstevel@tonic-gate int 22487c478bd9Sstevel@tonic-gate ehci_insert_qtd( 22497c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 22507c478bd9Sstevel@tonic-gate uint32_t qtd_ctrl, 22513304303fSsl size_t qtd_dma_offs, 22527c478bd9Sstevel@tonic-gate size_t qtd_length, 22537c478bd9Sstevel@tonic-gate uint32_t qtd_ctrl_phase, 22547c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 22557c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 22567c478bd9Sstevel@tonic-gate { 22577c478bd9Sstevel@tonic-gate ehci_qtd_t *curr_dummy_qtd, *next_dummy_qtd; 22587c478bd9Sstevel@tonic-gate ehci_qtd_t *new_dummy_qtd; 22597c478bd9Sstevel@tonic-gate ehci_qh_t *qh = pp->pp_qh; 22607c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 22617c478bd9Sstevel@tonic-gate 22627c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 22637c478bd9Sstevel@tonic-gate 22647c478bd9Sstevel@tonic-gate /* Allocate new dummy QTD */ 22657c478bd9Sstevel@tonic-gate new_dummy_qtd = tw->tw_qtd_free_list; 22667c478bd9Sstevel@tonic-gate 22677c478bd9Sstevel@tonic-gate ASSERT(new_dummy_qtd != NULL); 22687c478bd9Sstevel@tonic-gate tw->tw_qtd_free_list = ehci_qtd_iommu_to_cpu(ehcip, 22697c478bd9Sstevel@tonic-gate Get_QTD(new_dummy_qtd->qtd_tw_next_qtd)); 22707c478bd9Sstevel@tonic-gate Set_QTD(new_dummy_qtd->qtd_tw_next_qtd, NULL); 22717c478bd9Sstevel@tonic-gate 22727c478bd9Sstevel@tonic-gate /* Get the current and next dummy QTDs */ 22737c478bd9Sstevel@tonic-gate curr_dummy_qtd = ehci_qtd_iommu_to_cpu(ehcip, 22747c478bd9Sstevel@tonic-gate Get_QH(qh->qh_dummy_qtd)); 22757c478bd9Sstevel@tonic-gate next_dummy_qtd = ehci_qtd_iommu_to_cpu(ehcip, 22767c478bd9Sstevel@tonic-gate Get_QTD(curr_dummy_qtd->qtd_next_qtd)); 22777c478bd9Sstevel@tonic-gate 22787c478bd9Sstevel@tonic-gate /* Update QH's dummy qtd field */ 22797c478bd9Sstevel@tonic-gate Set_QH(qh->qh_dummy_qtd, ehci_qtd_cpu_to_iommu(ehcip, next_dummy_qtd)); 22807c478bd9Sstevel@tonic-gate 22817c478bd9Sstevel@tonic-gate /* Update next dummy's next qtd pointer */ 22827c478bd9Sstevel@tonic-gate Set_QTD(next_dummy_qtd->qtd_next_qtd, 22837c478bd9Sstevel@tonic-gate ehci_qtd_cpu_to_iommu(ehcip, new_dummy_qtd)); 22847c478bd9Sstevel@tonic-gate 22857c478bd9Sstevel@tonic-gate /* 22867c478bd9Sstevel@tonic-gate * Fill in the current dummy qtd and 22877c478bd9Sstevel@tonic-gate * add the new dummy to the end. 22887c478bd9Sstevel@tonic-gate */ 22897c478bd9Sstevel@tonic-gate ehci_fill_in_qtd(ehcip, curr_dummy_qtd, qtd_ctrl, 22903304303fSsl qtd_dma_offs, qtd_length, qtd_ctrl_phase, pp, tw); 22917c478bd9Sstevel@tonic-gate 22927c478bd9Sstevel@tonic-gate /* Insert this qtd onto the tw */ 22937c478bd9Sstevel@tonic-gate ehci_insert_qtd_on_tw(ehcip, tw, curr_dummy_qtd); 22947c478bd9Sstevel@tonic-gate 22957c478bd9Sstevel@tonic-gate /* 22967c478bd9Sstevel@tonic-gate * Insert this qtd onto active qtd list. 22977c478bd9Sstevel@tonic-gate * Don't insert polled mode qtd here. 22987c478bd9Sstevel@tonic-gate */ 22997c478bd9Sstevel@tonic-gate if (pp->pp_flag != EHCI_POLLED_MODE_FLAG) { 23007c478bd9Sstevel@tonic-gate /* Insert this qtd onto active qtd list */ 23017c478bd9Sstevel@tonic-gate ehci_insert_qtd_into_active_qtd_list(ehcip, curr_dummy_qtd); 23027c478bd9Sstevel@tonic-gate } 23037c478bd9Sstevel@tonic-gate 23047c478bd9Sstevel@tonic-gate /* Print qh and qtd */ 23057c478bd9Sstevel@tonic-gate ehci_print_qh(ehcip, qh); 23067c478bd9Sstevel@tonic-gate ehci_print_qtd(ehcip, curr_dummy_qtd); 23077c478bd9Sstevel@tonic-gate 23087c478bd9Sstevel@tonic-gate return (error); 23097c478bd9Sstevel@tonic-gate } 23107c478bd9Sstevel@tonic-gate 23117c478bd9Sstevel@tonic-gate 23127c478bd9Sstevel@tonic-gate /* 23137c478bd9Sstevel@tonic-gate * ehci_allocate_qtd_from_pool: 23147c478bd9Sstevel@tonic-gate * 23157c478bd9Sstevel@tonic-gate * Allocate a Transfer Descriptor (QTD) from the QTD buffer pool. 23167c478bd9Sstevel@tonic-gate */ 23177c478bd9Sstevel@tonic-gate static ehci_qtd_t * 23187c478bd9Sstevel@tonic-gate ehci_allocate_qtd_from_pool(ehci_state_t *ehcip) 23197c478bd9Sstevel@tonic-gate { 23207c478bd9Sstevel@tonic-gate int i, ctrl; 23217c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd; 23227c478bd9Sstevel@tonic-gate 23237c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 23247c478bd9Sstevel@tonic-gate 23257c478bd9Sstevel@tonic-gate /* 23267c478bd9Sstevel@tonic-gate * Search for a blank Transfer Descriptor (QTD) 23277c478bd9Sstevel@tonic-gate * in the QTD buffer pool. 23287c478bd9Sstevel@tonic-gate */ 23297c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_qtd_pool_size; i ++) { 23307c478bd9Sstevel@tonic-gate ctrl = Get_QTD(ehcip->ehci_qtd_pool_addr[i].qtd_state); 23317c478bd9Sstevel@tonic-gate if (ctrl == EHCI_QTD_FREE) { 23327c478bd9Sstevel@tonic-gate break; 23337c478bd9Sstevel@tonic-gate } 23347c478bd9Sstevel@tonic-gate } 23357c478bd9Sstevel@tonic-gate 23367c478bd9Sstevel@tonic-gate if (i >= ehci_qtd_pool_size) { 23377c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 23387c478bd9Sstevel@tonic-gate "ehci_allocate_qtd_from_pool: QTD exhausted"); 23397c478bd9Sstevel@tonic-gate 23407c478bd9Sstevel@tonic-gate return (NULL); 23417c478bd9Sstevel@tonic-gate } 23427c478bd9Sstevel@tonic-gate 23437c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 23447c478bd9Sstevel@tonic-gate "ehci_allocate_qtd_from_pool: Allocated %d", i); 23457c478bd9Sstevel@tonic-gate 23467c478bd9Sstevel@tonic-gate /* Create a new dummy for the end of the QTD list */ 23477c478bd9Sstevel@tonic-gate qtd = &ehcip->ehci_qtd_pool_addr[i]; 23487c478bd9Sstevel@tonic-gate 23497c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 23507c478bd9Sstevel@tonic-gate "ehci_allocate_qtd_from_pool: qtd 0x%p", (void *)qtd); 23517c478bd9Sstevel@tonic-gate 23527c478bd9Sstevel@tonic-gate /* Mark the newly allocated QTD as a dummy */ 23537c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_state, EHCI_QTD_DUMMY); 23547c478bd9Sstevel@tonic-gate 23557c478bd9Sstevel@tonic-gate /* Mark the status of this new QTD to halted state */ 23567c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_ctrl, EHCI_QTD_CTRL_HALTED_XACT); 23577c478bd9Sstevel@tonic-gate 23587c478bd9Sstevel@tonic-gate /* Disable dummy QTD's next and alternate next pointers */ 23597c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_next_qtd, EHCI_QTD_NEXT_QTD_PTR_VALID); 23607c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_alt_next_qtd, EHCI_QTD_ALT_NEXT_QTD_PTR_VALID); 23617c478bd9Sstevel@tonic-gate 23627c478bd9Sstevel@tonic-gate return (qtd); 23637c478bd9Sstevel@tonic-gate } 23647c478bd9Sstevel@tonic-gate 23657c478bd9Sstevel@tonic-gate 23667c478bd9Sstevel@tonic-gate /* 23677c478bd9Sstevel@tonic-gate * ehci_fill_in_qtd: 23687c478bd9Sstevel@tonic-gate * 23697c478bd9Sstevel@tonic-gate * Fill in the fields of a Transfer Descriptor (QTD). 23703304303fSsl * The "Buffer Pointer" fields of a QTD are retrieved from the TW 23713304303fSsl * it is associated with. 23723304303fSsl * 23733304303fSsl * Note: 23743304303fSsl * qtd_dma_offs - the starting offset into the TW buffer, where the QTD 23753304303fSsl * should transfer from. It should be 4K aligned. And when 23763304303fSsl * a TW has more than one QTDs, the QTDs must be filled in 23773304303fSsl * increasing order. 23783304303fSsl * qtd_length - the total bytes to transfer. 23797c478bd9Sstevel@tonic-gate */ 23807c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 23817c478bd9Sstevel@tonic-gate static void 23827c478bd9Sstevel@tonic-gate ehci_fill_in_qtd( 23837c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 23847c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, 23857c478bd9Sstevel@tonic-gate uint32_t qtd_ctrl, 23863304303fSsl size_t qtd_dma_offs, 23877c478bd9Sstevel@tonic-gate size_t qtd_length, 23887c478bd9Sstevel@tonic-gate uint32_t qtd_ctrl_phase, 23897c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 23907c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 23917c478bd9Sstevel@tonic-gate { 23923304303fSsl uint32_t buf_addr; 23937c478bd9Sstevel@tonic-gate size_t buf_len = qtd_length; 23947c478bd9Sstevel@tonic-gate uint32_t ctrl = qtd_ctrl; 23957c478bd9Sstevel@tonic-gate uint_t i = 0; 23963304303fSsl int rem_len; 23977c478bd9Sstevel@tonic-gate 23987c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 23993304303fSsl "ehci_fill_in_qtd: qtd 0x%p ctrl 0x%x bufoffs 0x%lx " 24003304303fSsl "len 0x%lx", qtd, qtd_ctrl, qtd_dma_offs, qtd_length); 24017c478bd9Sstevel@tonic-gate 24027c478bd9Sstevel@tonic-gate /* Assert that the qtd to be filled in is a dummy */ 24037c478bd9Sstevel@tonic-gate ASSERT(Get_QTD(qtd->qtd_state) == EHCI_QTD_DUMMY); 24047c478bd9Sstevel@tonic-gate 24057c478bd9Sstevel@tonic-gate /* Change QTD's state Active */ 24067c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_state, EHCI_QTD_ACTIVE); 24077c478bd9Sstevel@tonic-gate 24087c478bd9Sstevel@tonic-gate /* Set the total length data transfer */ 24097c478bd9Sstevel@tonic-gate ctrl |= (((qtd_length << EHCI_QTD_CTRL_BYTES_TO_XFER_SHIFT) 24107c478bd9Sstevel@tonic-gate & EHCI_QTD_CTRL_BYTES_TO_XFER) | EHCI_QTD_CTRL_MAX_ERR_COUNTS); 24117c478bd9Sstevel@tonic-gate 24127c478bd9Sstevel@tonic-gate /* 24133304303fSsl * QTDs must be filled in increasing DMA offset order. 24143304303fSsl * tw_dma_offs is initialized to be 0 at TW creation and 24153304303fSsl * is only increased in this function. 24163304303fSsl */ 24173304303fSsl ASSERT(buf_len == 0 || qtd_dma_offs >= tw->tw_dma_offs); 24183304303fSsl 24193304303fSsl /* 24203304303fSsl * Save the starting dma buffer offset used and 24217c478bd9Sstevel@tonic-gate * length of data that will be transfered in 24227c478bd9Sstevel@tonic-gate * the current QTD. 24237c478bd9Sstevel@tonic-gate */ 24243304303fSsl Set_QTD(qtd->qtd_xfer_offs, qtd_dma_offs); 24257c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_xfer_len, buf_len); 24267c478bd9Sstevel@tonic-gate 24277c478bd9Sstevel@tonic-gate while (buf_len) { 24283304303fSsl /* 24293304303fSsl * Advance to the next DMA cookie until finding the cookie 24303304303fSsl * that qtd_dma_offs falls in. 24313304303fSsl * It is very likely this loop will never repeat more than 24323304303fSsl * once. It is here just to accommodate the case qtd_dma_offs 24333304303fSsl * is increased by multiple cookies during two consecutive 24343304303fSsl * calls into this function. In that case, the interim DMA 24353304303fSsl * buffer is allowed to be skipped. 24363304303fSsl */ 24373304303fSsl while ((tw->tw_dma_offs + tw->tw_cookie.dmac_size) <= 24383304303fSsl qtd_dma_offs) { 24393304303fSsl /* 24403304303fSsl * tw_dma_offs always points to the starting offset 24413304303fSsl * of a cookie 24423304303fSsl */ 24433304303fSsl tw->tw_dma_offs += tw->tw_cookie.dmac_size; 24443304303fSsl ddi_dma_nextcookie(tw->tw_dmahandle, &tw->tw_cookie); 24453304303fSsl tw->tw_cookie_idx++; 24463304303fSsl ASSERT(tw->tw_cookie_idx < tw->tw_ncookies); 24473304303fSsl } 24483304303fSsl 24493304303fSsl /* 24503304303fSsl * Counting the remained buffer length to be filled in 24513304303fSsl * the QTD for current DMA cookie 24523304303fSsl */ 24533304303fSsl rem_len = (tw->tw_dma_offs + tw->tw_cookie.dmac_size) - 24543304303fSsl qtd_dma_offs; 24553304303fSsl 24567c478bd9Sstevel@tonic-gate /* Update the beginning of the buffer */ 24573304303fSsl buf_addr = (qtd_dma_offs - tw->tw_dma_offs) + 24583304303fSsl tw->tw_cookie.dmac_address; 24593304303fSsl ASSERT((buf_addr % EHCI_4K_ALIGN) == 0); 24607c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_buf[i], buf_addr); 24617c478bd9Sstevel@tonic-gate 24623304303fSsl USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 24633304303fSsl "ehci_fill_in_qtd: dmac_addr 0x%p dmac_size " 24643304303fSsl "0x%lx idx %d", buf_addr, tw->tw_cookie.dmac_size, 24653304303fSsl tw->tw_cookie_idx); 24663304303fSsl 24677c478bd9Sstevel@tonic-gate if (buf_len <= EHCI_MAX_QTD_BUF_SIZE) { 24683304303fSsl ASSERT(buf_len <= rem_len); 24697c478bd9Sstevel@tonic-gate break; 24707c478bd9Sstevel@tonic-gate } else { 24713304303fSsl ASSERT(rem_len >= EHCI_MAX_QTD_BUF_SIZE); 24727c478bd9Sstevel@tonic-gate buf_len -= EHCI_MAX_QTD_BUF_SIZE; 24733304303fSsl qtd_dma_offs += EHCI_MAX_QTD_BUF_SIZE; 24747c478bd9Sstevel@tonic-gate } 24757c478bd9Sstevel@tonic-gate 24767c478bd9Sstevel@tonic-gate i++; 24777c478bd9Sstevel@tonic-gate } 24787c478bd9Sstevel@tonic-gate 24797c478bd9Sstevel@tonic-gate /* 24807c478bd9Sstevel@tonic-gate * Setup the alternate next qTD pointer if appropriate. The alternate 24817c478bd9Sstevel@tonic-gate * qtd is currently pointing to a QTD that is not yet linked, but will 24827c478bd9Sstevel@tonic-gate * be in the very near future. If a short_xfer occurs in this 24837c478bd9Sstevel@tonic-gate * situation , the HC will automatically skip this QH. Eventually 24847c478bd9Sstevel@tonic-gate * everything will be placed and the alternate_qtd will be valid QTD. 24857c478bd9Sstevel@tonic-gate * For more information on alternate qtds look at section 3.5.2 in the 24867c478bd9Sstevel@tonic-gate * EHCI spec. 24877c478bd9Sstevel@tonic-gate */ 24887c478bd9Sstevel@tonic-gate if (tw->tw_alt_qtd != NULL) { 24897c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_alt_next_qtd, 24907c478bd9Sstevel@tonic-gate (ehci_qtd_cpu_to_iommu(ehcip, tw->tw_alt_qtd) & 24917c478bd9Sstevel@tonic-gate EHCI_QTD_ALT_NEXT_QTD_PTR)); 24927c478bd9Sstevel@tonic-gate } 24937c478bd9Sstevel@tonic-gate 24947c478bd9Sstevel@tonic-gate /* 24957c478bd9Sstevel@tonic-gate * For control, bulk and interrupt QTD, now 24967c478bd9Sstevel@tonic-gate * enable current QTD by setting active bit. 24977c478bd9Sstevel@tonic-gate */ 24987c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_ctrl, (ctrl | EHCI_QTD_CTRL_ACTIVE_XACT)); 24997c478bd9Sstevel@tonic-gate 25007c478bd9Sstevel@tonic-gate /* 25017c478bd9Sstevel@tonic-gate * For Control Xfer, qtd_ctrl_phase is a valid filed. 25027c478bd9Sstevel@tonic-gate */ 25037c478bd9Sstevel@tonic-gate if (qtd_ctrl_phase) { 25047c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_ctrl_phase, qtd_ctrl_phase); 25057c478bd9Sstevel@tonic-gate } 25067c478bd9Sstevel@tonic-gate 25077c478bd9Sstevel@tonic-gate /* Set the transfer wrapper */ 25087c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 25097c478bd9Sstevel@tonic-gate ASSERT(tw->tw_id != NULL); 25107c478bd9Sstevel@tonic-gate 25117c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_trans_wrapper, (uint32_t)tw->tw_id); 25127c478bd9Sstevel@tonic-gate } 25137c478bd9Sstevel@tonic-gate 25147c478bd9Sstevel@tonic-gate 25157c478bd9Sstevel@tonic-gate /* 25167c478bd9Sstevel@tonic-gate * ehci_insert_qtd_on_tw: 25177c478bd9Sstevel@tonic-gate * 25187c478bd9Sstevel@tonic-gate * The transfer wrapper keeps a list of all Transfer Descriptors (QTD) that 25197c478bd9Sstevel@tonic-gate * are allocated for this transfer. Insert a QTD onto this list. The list 25207c478bd9Sstevel@tonic-gate * of QTD's does not include the dummy QTD that is at the end of the list of 25217c478bd9Sstevel@tonic-gate * QTD's for the endpoint. 25227c478bd9Sstevel@tonic-gate */ 25237c478bd9Sstevel@tonic-gate static void 25247c478bd9Sstevel@tonic-gate ehci_insert_qtd_on_tw( 25257c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 25267c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 25277c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd) 25287c478bd9Sstevel@tonic-gate { 25297c478bd9Sstevel@tonic-gate /* 25307c478bd9Sstevel@tonic-gate * Set the next pointer to NULL because 25317c478bd9Sstevel@tonic-gate * this is the last QTD on list. 25327c478bd9Sstevel@tonic-gate */ 25337c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_tw_next_qtd, NULL); 25347c478bd9Sstevel@tonic-gate 25357c478bd9Sstevel@tonic-gate if (tw->tw_qtd_head == NULL) { 25367c478bd9Sstevel@tonic-gate ASSERT(tw->tw_qtd_tail == NULL); 25377c478bd9Sstevel@tonic-gate tw->tw_qtd_head = qtd; 25387c478bd9Sstevel@tonic-gate tw->tw_qtd_tail = qtd; 25397c478bd9Sstevel@tonic-gate } else { 25407c478bd9Sstevel@tonic-gate ehci_qtd_t *dummy = (ehci_qtd_t *)tw->tw_qtd_tail; 25417c478bd9Sstevel@tonic-gate 25427c478bd9Sstevel@tonic-gate ASSERT(dummy != NULL); 25437c478bd9Sstevel@tonic-gate ASSERT(dummy != qtd); 25447c478bd9Sstevel@tonic-gate ASSERT(Get_QTD(qtd->qtd_state) != EHCI_QTD_DUMMY); 25457c478bd9Sstevel@tonic-gate 25467c478bd9Sstevel@tonic-gate /* Add the qtd to the end of the list */ 25477c478bd9Sstevel@tonic-gate Set_QTD(dummy->qtd_tw_next_qtd, 25487c478bd9Sstevel@tonic-gate ehci_qtd_cpu_to_iommu(ehcip, qtd)); 25497c478bd9Sstevel@tonic-gate 25507c478bd9Sstevel@tonic-gate tw->tw_qtd_tail = qtd; 25517c478bd9Sstevel@tonic-gate 25527c478bd9Sstevel@tonic-gate ASSERT(Get_QTD(qtd->qtd_tw_next_qtd) == NULL); 25537c478bd9Sstevel@tonic-gate } 25547c478bd9Sstevel@tonic-gate } 25557c478bd9Sstevel@tonic-gate 25567c478bd9Sstevel@tonic-gate 25577c478bd9Sstevel@tonic-gate /* 25587c478bd9Sstevel@tonic-gate * ehci_insert_qtd_into_active_qtd_list: 25597c478bd9Sstevel@tonic-gate * 25607c478bd9Sstevel@tonic-gate * Insert current QTD into active QTD list. 25617c478bd9Sstevel@tonic-gate */ 25627c478bd9Sstevel@tonic-gate static void 25637c478bd9Sstevel@tonic-gate ehci_insert_qtd_into_active_qtd_list( 25647c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 25657c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd) 25667c478bd9Sstevel@tonic-gate { 25677c478bd9Sstevel@tonic-gate ehci_qtd_t *curr_qtd, *next_qtd; 25687c478bd9Sstevel@tonic-gate 25697c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 25707c478bd9Sstevel@tonic-gate 25717c478bd9Sstevel@tonic-gate curr_qtd = ehcip->ehci_active_qtd_list; 25727c478bd9Sstevel@tonic-gate 25737c478bd9Sstevel@tonic-gate /* Insert this QTD into QTD Active List */ 25747c478bd9Sstevel@tonic-gate if (curr_qtd) { 25757c478bd9Sstevel@tonic-gate next_qtd = ehci_qtd_iommu_to_cpu(ehcip, 25767c478bd9Sstevel@tonic-gate Get_QTD(curr_qtd->qtd_active_qtd_next)); 25777c478bd9Sstevel@tonic-gate 25787c478bd9Sstevel@tonic-gate while (next_qtd) { 25797c478bd9Sstevel@tonic-gate curr_qtd = next_qtd; 25807c478bd9Sstevel@tonic-gate next_qtd = ehci_qtd_iommu_to_cpu(ehcip, 25817c478bd9Sstevel@tonic-gate Get_QTD(curr_qtd->qtd_active_qtd_next)); 25827c478bd9Sstevel@tonic-gate } 25837c478bd9Sstevel@tonic-gate 25847c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_active_qtd_prev, 25857c478bd9Sstevel@tonic-gate ehci_qtd_cpu_to_iommu(ehcip, curr_qtd)); 25867c478bd9Sstevel@tonic-gate 25877c478bd9Sstevel@tonic-gate Set_QTD(curr_qtd->qtd_active_qtd_next, 25887c478bd9Sstevel@tonic-gate ehci_qtd_cpu_to_iommu(ehcip, qtd)); 25897c478bd9Sstevel@tonic-gate } else { 25907c478bd9Sstevel@tonic-gate ehcip->ehci_active_qtd_list = qtd; 25917c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_active_qtd_next, NULL); 25927c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_active_qtd_prev, NULL); 25937c478bd9Sstevel@tonic-gate } 25947c478bd9Sstevel@tonic-gate } 25957c478bd9Sstevel@tonic-gate 25967c478bd9Sstevel@tonic-gate 25977c478bd9Sstevel@tonic-gate /* 25987c478bd9Sstevel@tonic-gate * ehci_remove_qtd_from_active_qtd_list: 25997c478bd9Sstevel@tonic-gate * 26007c478bd9Sstevel@tonic-gate * Remove current QTD from the active QTD list. 26017c478bd9Sstevel@tonic-gate * 26027c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 26037c478bd9Sstevel@tonic-gate */ 26047c478bd9Sstevel@tonic-gate void 26057c478bd9Sstevel@tonic-gate ehci_remove_qtd_from_active_qtd_list( 26067c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 26077c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd) 26087c478bd9Sstevel@tonic-gate { 26097c478bd9Sstevel@tonic-gate ehci_qtd_t *curr_qtd, *prev_qtd, *next_qtd; 26107c478bd9Sstevel@tonic-gate 26117c478bd9Sstevel@tonic-gate ASSERT(qtd != NULL); 26127c478bd9Sstevel@tonic-gate 26137c478bd9Sstevel@tonic-gate curr_qtd = ehcip->ehci_active_qtd_list; 26147c478bd9Sstevel@tonic-gate 26157c478bd9Sstevel@tonic-gate while ((curr_qtd) && (curr_qtd != qtd)) { 26167c478bd9Sstevel@tonic-gate curr_qtd = ehci_qtd_iommu_to_cpu(ehcip, 26177c478bd9Sstevel@tonic-gate Get_QTD(curr_qtd->qtd_active_qtd_next)); 26187c478bd9Sstevel@tonic-gate } 26197c478bd9Sstevel@tonic-gate 26207c478bd9Sstevel@tonic-gate if ((curr_qtd) && (curr_qtd == qtd)) { 26217c478bd9Sstevel@tonic-gate prev_qtd = ehci_qtd_iommu_to_cpu(ehcip, 26227c478bd9Sstevel@tonic-gate Get_QTD(curr_qtd->qtd_active_qtd_prev)); 26237c478bd9Sstevel@tonic-gate next_qtd = ehci_qtd_iommu_to_cpu(ehcip, 26247c478bd9Sstevel@tonic-gate Get_QTD(curr_qtd->qtd_active_qtd_next)); 26257c478bd9Sstevel@tonic-gate 26267c478bd9Sstevel@tonic-gate if (prev_qtd) { 26277c478bd9Sstevel@tonic-gate Set_QTD(prev_qtd->qtd_active_qtd_next, 26287c478bd9Sstevel@tonic-gate Get_QTD(curr_qtd->qtd_active_qtd_next)); 26297c478bd9Sstevel@tonic-gate } else { 26307c478bd9Sstevel@tonic-gate ehcip->ehci_active_qtd_list = next_qtd; 26317c478bd9Sstevel@tonic-gate } 26327c478bd9Sstevel@tonic-gate 26337c478bd9Sstevel@tonic-gate if (next_qtd) { 26347c478bd9Sstevel@tonic-gate Set_QTD(next_qtd->qtd_active_qtd_prev, 26357c478bd9Sstevel@tonic-gate Get_QTD(curr_qtd->qtd_active_qtd_prev)); 26367c478bd9Sstevel@tonic-gate } 26377c478bd9Sstevel@tonic-gate } else { 26387c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 26397c478bd9Sstevel@tonic-gate "ehci_remove_qtd_from_active_qtd_list: " 2640*6a9de478Ssl "Unable to find QTD in active_qtd_list"); 26417c478bd9Sstevel@tonic-gate } 26427c478bd9Sstevel@tonic-gate } 26437c478bd9Sstevel@tonic-gate 26447c478bd9Sstevel@tonic-gate 26457c478bd9Sstevel@tonic-gate /* 26467c478bd9Sstevel@tonic-gate * ehci_traverse_qtds: 26477c478bd9Sstevel@tonic-gate * 26487c478bd9Sstevel@tonic-gate * Traverse the list of QTDs for given pipe using transfer wrapper. Since 26497c478bd9Sstevel@tonic-gate * the endpoint is marked as Halted, the Host Controller (HC) is no longer 26507c478bd9Sstevel@tonic-gate * accessing these QTDs. Remove all the QTDs that are attached to endpoint. 26517c478bd9Sstevel@tonic-gate */ 26527c478bd9Sstevel@tonic-gate static void 26537c478bd9Sstevel@tonic-gate ehci_traverse_qtds( 26547c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 26557c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 26567c478bd9Sstevel@tonic-gate { 26577c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 26587c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *next_tw; 26597c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd; 26607c478bd9Sstevel@tonic-gate ehci_qtd_t *next_qtd; 26617c478bd9Sstevel@tonic-gate 26627c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 26637c478bd9Sstevel@tonic-gate 26647c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 26657c478bd9Sstevel@tonic-gate "ehci_traverse_qtds:"); 26667c478bd9Sstevel@tonic-gate 26677c478bd9Sstevel@tonic-gate /* Process the transfer wrappers for this pipe */ 26687c478bd9Sstevel@tonic-gate next_tw = pp->pp_tw_head; 26697c478bd9Sstevel@tonic-gate 26707c478bd9Sstevel@tonic-gate while (next_tw) { 26717c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */ 26727c478bd9Sstevel@tonic-gate ehci_stop_xfer_timer(ehcip, next_tw, EHCI_REMOVE_XFER_ALWAYS); 26737c478bd9Sstevel@tonic-gate 26747c478bd9Sstevel@tonic-gate qtd = (ehci_qtd_t *)next_tw->tw_qtd_head; 26757c478bd9Sstevel@tonic-gate 26767c478bd9Sstevel@tonic-gate /* Walk through each QTD for this transfer wrapper */ 26777c478bd9Sstevel@tonic-gate while (qtd) { 26787c478bd9Sstevel@tonic-gate /* Remove this QTD from active QTD list */ 26797c478bd9Sstevel@tonic-gate ehci_remove_qtd_from_active_qtd_list(ehcip, qtd); 26807c478bd9Sstevel@tonic-gate 26817c478bd9Sstevel@tonic-gate next_qtd = ehci_qtd_iommu_to_cpu(ehcip, 26827c478bd9Sstevel@tonic-gate Get_QTD(qtd->qtd_tw_next_qtd)); 26837c478bd9Sstevel@tonic-gate 26847c478bd9Sstevel@tonic-gate /* Deallocate this QTD */ 26857c478bd9Sstevel@tonic-gate ehci_deallocate_qtd(ehcip, qtd); 26867c478bd9Sstevel@tonic-gate 26877c478bd9Sstevel@tonic-gate qtd = next_qtd; 26887c478bd9Sstevel@tonic-gate } 26897c478bd9Sstevel@tonic-gate 26907c478bd9Sstevel@tonic-gate next_tw = next_tw->tw_next; 26917c478bd9Sstevel@tonic-gate } 26927c478bd9Sstevel@tonic-gate 26937c478bd9Sstevel@tonic-gate /* Clear current qtd pointer */ 26947c478bd9Sstevel@tonic-gate Set_QH(pp->pp_qh->qh_curr_qtd, (uint32_t)0x00000000); 26957c478bd9Sstevel@tonic-gate 26967c478bd9Sstevel@tonic-gate /* Update the next qtd pointer in the QH */ 26977c478bd9Sstevel@tonic-gate Set_QH(pp->pp_qh->qh_next_qtd, Get_QH(pp->pp_qh->qh_dummy_qtd)); 26987c478bd9Sstevel@tonic-gate } 26997c478bd9Sstevel@tonic-gate 27007c478bd9Sstevel@tonic-gate 27017c478bd9Sstevel@tonic-gate /* 27027c478bd9Sstevel@tonic-gate * ehci_deallocate_qtd: 27037c478bd9Sstevel@tonic-gate * 27047c478bd9Sstevel@tonic-gate * Deallocate a Host Controller's (HC) Transfer Descriptor (QTD). 27057c478bd9Sstevel@tonic-gate * 27067c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 27077c478bd9Sstevel@tonic-gate */ 27087c478bd9Sstevel@tonic-gate void 27097c478bd9Sstevel@tonic-gate ehci_deallocate_qtd( 27107c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 27117c478bd9Sstevel@tonic-gate ehci_qtd_t *old_qtd) 27127c478bd9Sstevel@tonic-gate { 27137c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw = NULL; 27147c478bd9Sstevel@tonic-gate 27157c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 27167c478bd9Sstevel@tonic-gate "ehci_deallocate_qtd: old_qtd = 0x%p", (void *)old_qtd); 27177c478bd9Sstevel@tonic-gate 27187c478bd9Sstevel@tonic-gate /* 27197c478bd9Sstevel@tonic-gate * Obtain the transaction wrapper and tw will be 27207c478bd9Sstevel@tonic-gate * NULL for the dummy QTDs. 27217c478bd9Sstevel@tonic-gate */ 27227c478bd9Sstevel@tonic-gate if (Get_QTD(old_qtd->qtd_state) != EHCI_QTD_DUMMY) { 27237c478bd9Sstevel@tonic-gate tw = (ehci_trans_wrapper_t *) 2724*6a9de478Ssl EHCI_LOOKUP_ID((uint32_t) 2725*6a9de478Ssl Get_QTD(old_qtd->qtd_trans_wrapper)); 27267c478bd9Sstevel@tonic-gate 27277c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 27287c478bd9Sstevel@tonic-gate } 27297c478bd9Sstevel@tonic-gate 27307c478bd9Sstevel@tonic-gate /* 27317c478bd9Sstevel@tonic-gate * If QTD's transfer wrapper is NULL, don't access its TW. 27327c478bd9Sstevel@tonic-gate * Just free the QTD. 27337c478bd9Sstevel@tonic-gate */ 27347c478bd9Sstevel@tonic-gate if (tw) { 27357c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd, *next_qtd; 27367c478bd9Sstevel@tonic-gate 27377c478bd9Sstevel@tonic-gate qtd = tw->tw_qtd_head; 27387c478bd9Sstevel@tonic-gate 27397c478bd9Sstevel@tonic-gate if (old_qtd != qtd) { 27407c478bd9Sstevel@tonic-gate next_qtd = ehci_qtd_iommu_to_cpu( 2741*6a9de478Ssl ehcip, Get_QTD(qtd->qtd_tw_next_qtd)); 27427c478bd9Sstevel@tonic-gate 27437c478bd9Sstevel@tonic-gate while (next_qtd != old_qtd) { 27447c478bd9Sstevel@tonic-gate qtd = next_qtd; 27457c478bd9Sstevel@tonic-gate next_qtd = ehci_qtd_iommu_to_cpu( 27467c478bd9Sstevel@tonic-gate ehcip, Get_QTD(qtd->qtd_tw_next_qtd)); 27477c478bd9Sstevel@tonic-gate } 27487c478bd9Sstevel@tonic-gate 27497c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_tw_next_qtd, old_qtd->qtd_tw_next_qtd); 27507c478bd9Sstevel@tonic-gate 27517c478bd9Sstevel@tonic-gate if (qtd->qtd_tw_next_qtd == NULL) { 27527c478bd9Sstevel@tonic-gate tw->tw_qtd_tail = qtd; 27537c478bd9Sstevel@tonic-gate } 27547c478bd9Sstevel@tonic-gate } else { 27557c478bd9Sstevel@tonic-gate tw->tw_qtd_head = ehci_qtd_iommu_to_cpu( 27567c478bd9Sstevel@tonic-gate ehcip, Get_QTD(old_qtd->qtd_tw_next_qtd)); 27577c478bd9Sstevel@tonic-gate 27587c478bd9Sstevel@tonic-gate if (tw->tw_qtd_head == NULL) { 27597c478bd9Sstevel@tonic-gate tw->tw_qtd_tail = NULL; 27607c478bd9Sstevel@tonic-gate } 27617c478bd9Sstevel@tonic-gate } 27627c478bd9Sstevel@tonic-gate } 27637c478bd9Sstevel@tonic-gate 27647c478bd9Sstevel@tonic-gate bzero((void *)old_qtd, sizeof (ehci_qtd_t)); 27657c478bd9Sstevel@tonic-gate Set_QTD(old_qtd->qtd_state, EHCI_QTD_FREE); 27667c478bd9Sstevel@tonic-gate 27677c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 27687c478bd9Sstevel@tonic-gate "Dealloc_qtd: qtd 0x%p", (void *)old_qtd); 27697c478bd9Sstevel@tonic-gate } 27707c478bd9Sstevel@tonic-gate 27717c478bd9Sstevel@tonic-gate 27727c478bd9Sstevel@tonic-gate /* 27737c478bd9Sstevel@tonic-gate * ehci_qtd_cpu_to_iommu: 27747c478bd9Sstevel@tonic-gate * 27757c478bd9Sstevel@tonic-gate * This function converts for the given Transfer Descriptor (QTD) CPU address 27767c478bd9Sstevel@tonic-gate * to IO address. 27777c478bd9Sstevel@tonic-gate * 27787c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 27797c478bd9Sstevel@tonic-gate */ 27807c478bd9Sstevel@tonic-gate uint32_t 27817c478bd9Sstevel@tonic-gate ehci_qtd_cpu_to_iommu( 27827c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 27837c478bd9Sstevel@tonic-gate ehci_qtd_t *addr) 27847c478bd9Sstevel@tonic-gate { 27857c478bd9Sstevel@tonic-gate uint32_t td; 27867c478bd9Sstevel@tonic-gate 27877c478bd9Sstevel@tonic-gate td = (uint32_t)ehcip->ehci_qtd_pool_cookie.dmac_address + 27887c478bd9Sstevel@tonic-gate (uint32_t)((uintptr_t)addr - 27897c478bd9Sstevel@tonic-gate (uintptr_t)(ehcip->ehci_qtd_pool_addr)); 27907c478bd9Sstevel@tonic-gate 27917c478bd9Sstevel@tonic-gate ASSERT((ehcip->ehci_qtd_pool_cookie.dmac_address + 27927c478bd9Sstevel@tonic-gate (uint32_t) (sizeof (ehci_qtd_t) * 27937c478bd9Sstevel@tonic-gate (addr - ehcip->ehci_qtd_pool_addr))) == 27947c478bd9Sstevel@tonic-gate (ehcip->ehci_qtd_pool_cookie.dmac_address + 27957c478bd9Sstevel@tonic-gate (uint32_t)((uintptr_t)addr - (uintptr_t) 27967c478bd9Sstevel@tonic-gate (ehcip->ehci_qtd_pool_addr)))); 27977c478bd9Sstevel@tonic-gate 27987c478bd9Sstevel@tonic-gate ASSERT(td >= ehcip->ehci_qtd_pool_cookie.dmac_address); 27997c478bd9Sstevel@tonic-gate ASSERT(td <= ehcip->ehci_qtd_pool_cookie.dmac_address + 28007c478bd9Sstevel@tonic-gate sizeof (ehci_qtd_t) * ehci_qtd_pool_size); 28017c478bd9Sstevel@tonic-gate 28027c478bd9Sstevel@tonic-gate return (td); 28037c478bd9Sstevel@tonic-gate } 28047c478bd9Sstevel@tonic-gate 28057c478bd9Sstevel@tonic-gate 28067c478bd9Sstevel@tonic-gate /* 28077c478bd9Sstevel@tonic-gate * ehci_qtd_iommu_to_cpu: 28087c478bd9Sstevel@tonic-gate * 28097c478bd9Sstevel@tonic-gate * This function converts for the given Transfer Descriptor (QTD) IO address 28107c478bd9Sstevel@tonic-gate * to CPU address. 28117c478bd9Sstevel@tonic-gate * 28127c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 28137c478bd9Sstevel@tonic-gate */ 28147c478bd9Sstevel@tonic-gate ehci_qtd_t * 28157c478bd9Sstevel@tonic-gate ehci_qtd_iommu_to_cpu( 28167c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 28177c478bd9Sstevel@tonic-gate uintptr_t addr) 28187c478bd9Sstevel@tonic-gate { 28197c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd; 28207c478bd9Sstevel@tonic-gate 28217c478bd9Sstevel@tonic-gate if (addr == NULL) { 28227c478bd9Sstevel@tonic-gate 28237c478bd9Sstevel@tonic-gate return (NULL); 28247c478bd9Sstevel@tonic-gate } 28257c478bd9Sstevel@tonic-gate 28267c478bd9Sstevel@tonic-gate qtd = (ehci_qtd_t *)((uintptr_t) 28277c478bd9Sstevel@tonic-gate (addr - ehcip->ehci_qtd_pool_cookie.dmac_address) + 28287c478bd9Sstevel@tonic-gate (uintptr_t)ehcip->ehci_qtd_pool_addr); 28297c478bd9Sstevel@tonic-gate 28307c478bd9Sstevel@tonic-gate ASSERT(qtd >= ehcip->ehci_qtd_pool_addr); 28317c478bd9Sstevel@tonic-gate ASSERT((uintptr_t)qtd <= (uintptr_t)ehcip->ehci_qtd_pool_addr + 28327c478bd9Sstevel@tonic-gate (uintptr_t)(sizeof (ehci_qtd_t) * ehci_qtd_pool_size)); 28337c478bd9Sstevel@tonic-gate 28347c478bd9Sstevel@tonic-gate return (qtd); 28357c478bd9Sstevel@tonic-gate } 28367c478bd9Sstevel@tonic-gate 28377c478bd9Sstevel@tonic-gate /* 28387c478bd9Sstevel@tonic-gate * ehci_allocate_tds_for_tw_resources: 28397c478bd9Sstevel@tonic-gate * 28407c478bd9Sstevel@tonic-gate * Allocate n Transfer Descriptors (TD) from the TD buffer pool and places it 28417c478bd9Sstevel@tonic-gate * into the TW. Also chooses the correct alternate qtd when required. It is 28427c478bd9Sstevel@tonic-gate * used for hardware short transfer support. For more information on 28437c478bd9Sstevel@tonic-gate * alternate qtds look at section 3.5.2 in the EHCI spec. 28447c478bd9Sstevel@tonic-gate * Here is how each alternate qtd's are used: 28457c478bd9Sstevel@tonic-gate * 28467c478bd9Sstevel@tonic-gate * Bulk: used fully. 28477c478bd9Sstevel@tonic-gate * Intr: xfers only require 1 QTD, so alternate qtds are never used. 28487c478bd9Sstevel@tonic-gate * Ctrl: Should not use alternate QTD 28497c478bd9Sstevel@tonic-gate * Isoch: Doesn't support short_xfer nor does it use QTD 28507c478bd9Sstevel@tonic-gate * 28517c478bd9Sstevel@tonic-gate * Returns USB_NO_RESOURCES if it was not able to allocate all the requested TD 28527c478bd9Sstevel@tonic-gate * otherwise USB_SUCCESS. 28537c478bd9Sstevel@tonic-gate */ 28547c478bd9Sstevel@tonic-gate int 28557c478bd9Sstevel@tonic-gate ehci_allocate_tds_for_tw( 28567c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 28577c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 28587c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 28597c478bd9Sstevel@tonic-gate size_t qtd_count) 28607c478bd9Sstevel@tonic-gate { 28617c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep; 28627c478bd9Sstevel@tonic-gate uchar_t attributes; 28637c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd; 28647c478bd9Sstevel@tonic-gate uint32_t qtd_addr; 28657c478bd9Sstevel@tonic-gate int i; 28667c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 28677c478bd9Sstevel@tonic-gate 28687c478bd9Sstevel@tonic-gate attributes = eptd->bmAttributes & USB_EP_ATTR_MASK; 28697c478bd9Sstevel@tonic-gate 28707c478bd9Sstevel@tonic-gate for (i = 0; i < qtd_count; i += 1) { 28717c478bd9Sstevel@tonic-gate qtd = ehci_allocate_qtd_from_pool(ehcip); 28727c478bd9Sstevel@tonic-gate if (qtd == NULL) { 28737c478bd9Sstevel@tonic-gate error = USB_NO_RESOURCES; 28747c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 28757c478bd9Sstevel@tonic-gate "ehci_allocate_qtds_for_tw: " 28767c478bd9Sstevel@tonic-gate "Unable to allocate %lu QTDs", 28777c478bd9Sstevel@tonic-gate qtd_count); 28787c478bd9Sstevel@tonic-gate break; 28797c478bd9Sstevel@tonic-gate } 28807c478bd9Sstevel@tonic-gate if (i > 0) { 28817c478bd9Sstevel@tonic-gate qtd_addr = ehci_qtd_cpu_to_iommu(ehcip, 28827c478bd9Sstevel@tonic-gate tw->tw_qtd_free_list); 28837c478bd9Sstevel@tonic-gate Set_QTD(qtd->qtd_tw_next_qtd, qtd_addr); 28847c478bd9Sstevel@tonic-gate } 28857c478bd9Sstevel@tonic-gate tw->tw_qtd_free_list = qtd; 28867c478bd9Sstevel@tonic-gate 28877c478bd9Sstevel@tonic-gate /* 28887c478bd9Sstevel@tonic-gate * Save the second one as a pointer to the new dummy 1. 28897c478bd9Sstevel@tonic-gate * It is used later for the alt_qtd_ptr. Xfers with only 28907c478bd9Sstevel@tonic-gate * one qtd do not need alt_qtd_ptr. 28917c478bd9Sstevel@tonic-gate * The tds's are allocated and put into a stack, that is 28927c478bd9Sstevel@tonic-gate * why the second qtd allocated will turn out to be the 28937c478bd9Sstevel@tonic-gate * new dummy 1. 28947c478bd9Sstevel@tonic-gate */ 28957c478bd9Sstevel@tonic-gate if ((i == 1) && (attributes == USB_EP_ATTR_BULK)) { 28967c478bd9Sstevel@tonic-gate tw->tw_alt_qtd = qtd; 28977c478bd9Sstevel@tonic-gate } 28987c478bd9Sstevel@tonic-gate } 28997c478bd9Sstevel@tonic-gate 29007c478bd9Sstevel@tonic-gate return (error); 29017c478bd9Sstevel@tonic-gate } 29027c478bd9Sstevel@tonic-gate 29037c478bd9Sstevel@tonic-gate /* 29047c478bd9Sstevel@tonic-gate * ehci_allocate_tw_resources: 29057c478bd9Sstevel@tonic-gate * 29067c478bd9Sstevel@tonic-gate * Allocate a Transaction Wrapper (TW) and n Transfer Descriptors (QTD) 29077c478bd9Sstevel@tonic-gate * from the QTD buffer pool and places it into the TW. It does an all 29087c478bd9Sstevel@tonic-gate * or nothing transaction. 29097c478bd9Sstevel@tonic-gate * 29107c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW. 29117c478bd9Sstevel@tonic-gate */ 29127c478bd9Sstevel@tonic-gate static ehci_trans_wrapper_t * 29137c478bd9Sstevel@tonic-gate ehci_allocate_tw_resources( 29147c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 29157c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 29167c478bd9Sstevel@tonic-gate size_t tw_length, 29177c478bd9Sstevel@tonic-gate usb_flags_t usb_flags, 29187c478bd9Sstevel@tonic-gate size_t qtd_count) 29197c478bd9Sstevel@tonic-gate { 29207c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw; 29217c478bd9Sstevel@tonic-gate 29227c478bd9Sstevel@tonic-gate tw = ehci_create_transfer_wrapper(ehcip, pp, tw_length, usb_flags); 29237c478bd9Sstevel@tonic-gate 29247c478bd9Sstevel@tonic-gate if (tw == NULL) { 29257c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 29267c478bd9Sstevel@tonic-gate "ehci_allocate_tw_resources: Unable to allocate TW"); 29277c478bd9Sstevel@tonic-gate } else { 29287c478bd9Sstevel@tonic-gate if (ehci_allocate_tds_for_tw(ehcip, pp, tw, qtd_count) == 29297c478bd9Sstevel@tonic-gate USB_SUCCESS) { 29307c478bd9Sstevel@tonic-gate tw->tw_num_qtds = qtd_count; 29317c478bd9Sstevel@tonic-gate } else { 29327c478bd9Sstevel@tonic-gate ehci_deallocate_tw(ehcip, pp, tw); 29337c478bd9Sstevel@tonic-gate tw = NULL; 29347c478bd9Sstevel@tonic-gate } 29357c478bd9Sstevel@tonic-gate } 29367c478bd9Sstevel@tonic-gate 29377c478bd9Sstevel@tonic-gate return (tw); 29387c478bd9Sstevel@tonic-gate } 29397c478bd9Sstevel@tonic-gate 29407c478bd9Sstevel@tonic-gate 29417c478bd9Sstevel@tonic-gate /* 29427c478bd9Sstevel@tonic-gate * ehci_free_tw_td_resources: 29437c478bd9Sstevel@tonic-gate * 29447c478bd9Sstevel@tonic-gate * Free all allocated resources for Transaction Wrapper (TW). 29457c478bd9Sstevel@tonic-gate * Does not free the TW itself. 29467c478bd9Sstevel@tonic-gate * 29477c478bd9Sstevel@tonic-gate * Returns NULL if there is insufficient resources otherwise TW. 29487c478bd9Sstevel@tonic-gate */ 29497c478bd9Sstevel@tonic-gate static void 29507c478bd9Sstevel@tonic-gate ehci_free_tw_td_resources( 29517c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 29527c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 29537c478bd9Sstevel@tonic-gate { 29547c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd = NULL; 29557c478bd9Sstevel@tonic-gate ehci_qtd_t *temp_qtd = NULL; 29567c478bd9Sstevel@tonic-gate 29577c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 29587c478bd9Sstevel@tonic-gate "ehci_free_tw_td_resources: tw = 0x%p", tw); 29597c478bd9Sstevel@tonic-gate 29607c478bd9Sstevel@tonic-gate qtd = tw->tw_qtd_free_list; 29617c478bd9Sstevel@tonic-gate while (qtd != NULL) { 29627c478bd9Sstevel@tonic-gate /* Save the pointer to the next qtd before destroying it */ 29637c478bd9Sstevel@tonic-gate temp_qtd = ehci_qtd_iommu_to_cpu(ehcip, 29647c478bd9Sstevel@tonic-gate Get_QTD(qtd->qtd_tw_next_qtd)); 29657c478bd9Sstevel@tonic-gate ehci_deallocate_qtd(ehcip, qtd); 29667c478bd9Sstevel@tonic-gate qtd = temp_qtd; 29677c478bd9Sstevel@tonic-gate } 29687c478bd9Sstevel@tonic-gate tw->tw_qtd_free_list = NULL; 29697c478bd9Sstevel@tonic-gate } 29707c478bd9Sstevel@tonic-gate 29717c478bd9Sstevel@tonic-gate /* 29727c478bd9Sstevel@tonic-gate * Transfer Wrapper functions 29737c478bd9Sstevel@tonic-gate * 29747c478bd9Sstevel@tonic-gate * ehci_create_transfer_wrapper: 29757c478bd9Sstevel@tonic-gate * 29767c478bd9Sstevel@tonic-gate * Create a Transaction Wrapper (TW) and this involves the allocating of DMA 29777c478bd9Sstevel@tonic-gate * resources. 29787c478bd9Sstevel@tonic-gate */ 29797c478bd9Sstevel@tonic-gate static ehci_trans_wrapper_t * 29807c478bd9Sstevel@tonic-gate ehci_create_transfer_wrapper( 29817c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 29827c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 29837c478bd9Sstevel@tonic-gate size_t length, 29847c478bd9Sstevel@tonic-gate uint_t usb_flags) 29857c478bd9Sstevel@tonic-gate { 29867c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 29873304303fSsl ddi_dma_attr_t dma_attr; 29887c478bd9Sstevel@tonic-gate int result; 29897c478bd9Sstevel@tonic-gate size_t real_length; 29907c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw; 29913304303fSsl int kmem_flag; 29923304303fSsl int (*dmamem_wait)(caddr_t); 29937c478bd9Sstevel@tonic-gate 29947c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 29957c478bd9Sstevel@tonic-gate "ehci_create_transfer_wrapper: length = 0x%lx flags = 0x%x", 29967c478bd9Sstevel@tonic-gate length, usb_flags); 29977c478bd9Sstevel@tonic-gate 29987c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 29997c478bd9Sstevel@tonic-gate 30003304303fSsl /* SLEEP flag should not be used in interrupt context */ 30013304303fSsl if (servicing_interrupt()) { 30023304303fSsl kmem_flag = KM_NOSLEEP; 30033304303fSsl dmamem_wait = DDI_DMA_DONTWAIT; 30043304303fSsl } else { 30053304303fSsl kmem_flag = KM_SLEEP; 30063304303fSsl dmamem_wait = DDI_DMA_SLEEP; 30073304303fSsl } 30083304303fSsl 30097c478bd9Sstevel@tonic-gate /* Allocate space for the transfer wrapper */ 30103304303fSsl tw = kmem_zalloc(sizeof (ehci_trans_wrapper_t), kmem_flag); 30117c478bd9Sstevel@tonic-gate 30127c478bd9Sstevel@tonic-gate if (tw == NULL) { 30137c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 30147c478bd9Sstevel@tonic-gate "ehci_create_transfer_wrapper: kmem_zalloc failed"); 30157c478bd9Sstevel@tonic-gate 30167c478bd9Sstevel@tonic-gate return (NULL); 30177c478bd9Sstevel@tonic-gate } 30187c478bd9Sstevel@tonic-gate 3019688b07c5Sgc /* zero-length packet doesn't need to allocate dma memory */ 3020688b07c5Sgc if (length == 0) { 3021688b07c5Sgc 3022688b07c5Sgc goto dmadone; 3023688b07c5Sgc } 3024688b07c5Sgc 30253304303fSsl /* allow sg lists for transfer wrapper dma memory */ 30263304303fSsl bcopy(&ehcip->ehci_dma_attr, &dma_attr, sizeof (ddi_dma_attr_t)); 30273304303fSsl dma_attr.dma_attr_sgllen = EHCI_DMA_ATTR_TW_SGLLEN; 30283304303fSsl dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 30297c478bd9Sstevel@tonic-gate 30307c478bd9Sstevel@tonic-gate /* Allocate the DMA handle */ 30317c478bd9Sstevel@tonic-gate result = ddi_dma_alloc_handle(ehcip->ehci_dip, 30323304303fSsl &dma_attr, dmamem_wait, 0, &tw->tw_dmahandle); 30337c478bd9Sstevel@tonic-gate 30347c478bd9Sstevel@tonic-gate if (result != DDI_SUCCESS) { 30357c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 30367c478bd9Sstevel@tonic-gate "ehci_create_transfer_wrapper: Alloc handle failed"); 30377c478bd9Sstevel@tonic-gate 30387c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ehci_trans_wrapper_t)); 30397c478bd9Sstevel@tonic-gate 30407c478bd9Sstevel@tonic-gate return (NULL); 30417c478bd9Sstevel@tonic-gate } 30427c478bd9Sstevel@tonic-gate 30437c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 30447c478bd9Sstevel@tonic-gate 30457c478bd9Sstevel@tonic-gate /* no need for swapping the raw data */ 30467c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 30477c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 30487c478bd9Sstevel@tonic-gate 30497c478bd9Sstevel@tonic-gate /* Allocate the memory */ 30507c478bd9Sstevel@tonic-gate result = ddi_dma_mem_alloc(tw->tw_dmahandle, length, 30513304303fSsl &dev_attr, DDI_DMA_CONSISTENT, dmamem_wait, NULL, 30527c478bd9Sstevel@tonic-gate (caddr_t *)&tw->tw_buf, &real_length, &tw->tw_accesshandle); 30537c478bd9Sstevel@tonic-gate 30547c478bd9Sstevel@tonic-gate if (result != DDI_SUCCESS) { 30557c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 30567c478bd9Sstevel@tonic-gate "ehci_create_transfer_wrapper: dma_mem_alloc fail"); 30577c478bd9Sstevel@tonic-gate 30587c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&tw->tw_dmahandle); 30597c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ehci_trans_wrapper_t)); 30607c478bd9Sstevel@tonic-gate 30617c478bd9Sstevel@tonic-gate return (NULL); 30627c478bd9Sstevel@tonic-gate } 30637c478bd9Sstevel@tonic-gate 30647c478bd9Sstevel@tonic-gate ASSERT(real_length >= length); 30657c478bd9Sstevel@tonic-gate 30667c478bd9Sstevel@tonic-gate /* Bind the handle */ 30677c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(tw->tw_dmahandle, NULL, 30687c478bd9Sstevel@tonic-gate (caddr_t)tw->tw_buf, real_length, DDI_DMA_RDWR|DDI_DMA_CONSISTENT, 30693304303fSsl dmamem_wait, NULL, &tw->tw_cookie, &tw->tw_ncookies); 30707c478bd9Sstevel@tonic-gate 30713304303fSsl if (result != DDI_DMA_MAPPED) { 30727c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result); 30737c478bd9Sstevel@tonic-gate 30747c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&tw->tw_accesshandle); 30757c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&tw->tw_dmahandle); 30767c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ehci_trans_wrapper_t)); 30777c478bd9Sstevel@tonic-gate 30787c478bd9Sstevel@tonic-gate return (NULL); 30797c478bd9Sstevel@tonic-gate } 30807c478bd9Sstevel@tonic-gate 30813304303fSsl tw->tw_cookie_idx = 0; 30823304303fSsl tw->tw_dma_offs = 0; 30833304303fSsl 3084688b07c5Sgc dmadone: 30857c478bd9Sstevel@tonic-gate /* 30867c478bd9Sstevel@tonic-gate * Only allow one wrapper to be added at a time. Insert the 30877c478bd9Sstevel@tonic-gate * new transaction wrapper into the list for this pipe. 30887c478bd9Sstevel@tonic-gate */ 30897c478bd9Sstevel@tonic-gate if (pp->pp_tw_head == NULL) { 30907c478bd9Sstevel@tonic-gate pp->pp_tw_head = tw; 30917c478bd9Sstevel@tonic-gate pp->pp_tw_tail = tw; 30927c478bd9Sstevel@tonic-gate } else { 30937c478bd9Sstevel@tonic-gate pp->pp_tw_tail->tw_next = tw; 30947c478bd9Sstevel@tonic-gate pp->pp_tw_tail = tw; 30957c478bd9Sstevel@tonic-gate } 30967c478bd9Sstevel@tonic-gate 30977c478bd9Sstevel@tonic-gate /* Store the transfer length */ 30987c478bd9Sstevel@tonic-gate tw->tw_length = length; 30997c478bd9Sstevel@tonic-gate 31007c478bd9Sstevel@tonic-gate /* Store a back pointer to the pipe private structure */ 31017c478bd9Sstevel@tonic-gate tw->tw_pipe_private = pp; 31027c478bd9Sstevel@tonic-gate 31037c478bd9Sstevel@tonic-gate /* Store the transfer type - synchronous or asynchronous */ 31047c478bd9Sstevel@tonic-gate tw->tw_flags = usb_flags; 31057c478bd9Sstevel@tonic-gate 31067c478bd9Sstevel@tonic-gate /* Get and Store 32bit ID */ 31077c478bd9Sstevel@tonic-gate tw->tw_id = EHCI_GET_ID((void *)tw); 31087c478bd9Sstevel@tonic-gate 31097c478bd9Sstevel@tonic-gate ASSERT(tw->tw_id != NULL); 31107c478bd9Sstevel@tonic-gate 31117c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 31123304303fSsl "ehci_create_transfer_wrapper: tw = 0x%p, ncookies = %u", 31133304303fSsl tw, tw->tw_ncookies); 31147c478bd9Sstevel@tonic-gate 31157c478bd9Sstevel@tonic-gate return (tw); 31167c478bd9Sstevel@tonic-gate } 31177c478bd9Sstevel@tonic-gate 31187c478bd9Sstevel@tonic-gate 31197c478bd9Sstevel@tonic-gate /* 31207c478bd9Sstevel@tonic-gate * ehci_start_xfer_timer: 31217c478bd9Sstevel@tonic-gate * 31227c478bd9Sstevel@tonic-gate * Start the timer for the control, bulk and for one time interrupt 31237c478bd9Sstevel@tonic-gate * transfers. 31247c478bd9Sstevel@tonic-gate */ 31257c478bd9Sstevel@tonic-gate /* ARGSUSED */ 31267c478bd9Sstevel@tonic-gate static void 31277c478bd9Sstevel@tonic-gate ehci_start_xfer_timer( 31287c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 31297c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 31307c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 31317c478bd9Sstevel@tonic-gate { 31327c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 31337c478bd9Sstevel@tonic-gate "ehci_start_xfer_timer: tw = 0x%p", tw); 31347c478bd9Sstevel@tonic-gate 31357c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 31367c478bd9Sstevel@tonic-gate 31377c478bd9Sstevel@tonic-gate /* 31387c478bd9Sstevel@tonic-gate * The timeout handling is done only for control, bulk and for 31397c478bd9Sstevel@tonic-gate * one time Interrupt transfers. 31407c478bd9Sstevel@tonic-gate * 31417c478bd9Sstevel@tonic-gate * NOTE: If timeout is zero; Assume infinite timeout and don't 31427c478bd9Sstevel@tonic-gate * insert this transfer on the timeout list. 31437c478bd9Sstevel@tonic-gate */ 31447c478bd9Sstevel@tonic-gate if (tw->tw_timeout) { 31457c478bd9Sstevel@tonic-gate /* 31467c478bd9Sstevel@tonic-gate * Add this transfer wrapper to the head of the pipe's 31477c478bd9Sstevel@tonic-gate * tw timeout list. 31487c478bd9Sstevel@tonic-gate */ 31497c478bd9Sstevel@tonic-gate if (pp->pp_timeout_list) { 31507c478bd9Sstevel@tonic-gate tw->tw_timeout_next = pp->pp_timeout_list; 31517c478bd9Sstevel@tonic-gate } 31527c478bd9Sstevel@tonic-gate 31537c478bd9Sstevel@tonic-gate pp->pp_timeout_list = tw; 31547c478bd9Sstevel@tonic-gate ehci_start_timer(ehcip, pp); 31557c478bd9Sstevel@tonic-gate } 31567c478bd9Sstevel@tonic-gate } 31577c478bd9Sstevel@tonic-gate 31587c478bd9Sstevel@tonic-gate 31597c478bd9Sstevel@tonic-gate /* 31607c478bd9Sstevel@tonic-gate * ehci_stop_xfer_timer: 31617c478bd9Sstevel@tonic-gate * 31627c478bd9Sstevel@tonic-gate * Start the timer for the control, bulk and for one time interrupt 31637c478bd9Sstevel@tonic-gate * transfers. 31647c478bd9Sstevel@tonic-gate */ 31657c478bd9Sstevel@tonic-gate void 31667c478bd9Sstevel@tonic-gate ehci_stop_xfer_timer( 31677c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 31687c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 31697c478bd9Sstevel@tonic-gate uint_t flag) 31707c478bd9Sstevel@tonic-gate { 31717c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; 31727c478bd9Sstevel@tonic-gate timeout_id_t timer_id; 31737c478bd9Sstevel@tonic-gate 31747c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 31757c478bd9Sstevel@tonic-gate "ehci_stop_xfer_timer: tw = 0x%p", tw); 31767c478bd9Sstevel@tonic-gate 31777c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 31787c478bd9Sstevel@tonic-gate 31797c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 31807c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 31817c478bd9Sstevel@tonic-gate 31827c478bd9Sstevel@tonic-gate /* check if the timeout tw list is empty */ 31837c478bd9Sstevel@tonic-gate if (pp->pp_timeout_list == NULL) { 31847c478bd9Sstevel@tonic-gate 31857c478bd9Sstevel@tonic-gate return; 31867c478bd9Sstevel@tonic-gate } 31877c478bd9Sstevel@tonic-gate 31887c478bd9Sstevel@tonic-gate switch (flag) { 31897c478bd9Sstevel@tonic-gate case EHCI_REMOVE_XFER_IFLAST: 31907c478bd9Sstevel@tonic-gate if (tw->tw_qtd_head != tw->tw_qtd_tail) { 31917c478bd9Sstevel@tonic-gate break; 31927c478bd9Sstevel@tonic-gate } 31937c478bd9Sstevel@tonic-gate 31947c478bd9Sstevel@tonic-gate /* FALLTHRU */ 31957c478bd9Sstevel@tonic-gate case EHCI_REMOVE_XFER_ALWAYS: 31967c478bd9Sstevel@tonic-gate ehci_remove_tw_from_timeout_list(ehcip, tw); 31977c478bd9Sstevel@tonic-gate 31987c478bd9Sstevel@tonic-gate if ((pp->pp_timeout_list == NULL) && 31997c478bd9Sstevel@tonic-gate (pp->pp_timer_id)) { 32007c478bd9Sstevel@tonic-gate 32017c478bd9Sstevel@tonic-gate timer_id = pp->pp_timer_id; 32027c478bd9Sstevel@tonic-gate 32037c478bd9Sstevel@tonic-gate /* Reset the timer id to zero */ 32047c478bd9Sstevel@tonic-gate pp->pp_timer_id = 0; 32057c478bd9Sstevel@tonic-gate 32067c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 32077c478bd9Sstevel@tonic-gate 32087c478bd9Sstevel@tonic-gate (void) untimeout(timer_id); 32097c478bd9Sstevel@tonic-gate 32107c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 32117c478bd9Sstevel@tonic-gate } 32127c478bd9Sstevel@tonic-gate break; 32137c478bd9Sstevel@tonic-gate default: 32147c478bd9Sstevel@tonic-gate break; 32157c478bd9Sstevel@tonic-gate } 32167c478bd9Sstevel@tonic-gate } 32177c478bd9Sstevel@tonic-gate 32187c478bd9Sstevel@tonic-gate 32197c478bd9Sstevel@tonic-gate /* 32207c478bd9Sstevel@tonic-gate * ehci_xfer_timeout_handler: 32217c478bd9Sstevel@tonic-gate * 32227c478bd9Sstevel@tonic-gate * Control or bulk transfer timeout handler. 32237c478bd9Sstevel@tonic-gate */ 32247c478bd9Sstevel@tonic-gate static void 32257c478bd9Sstevel@tonic-gate ehci_xfer_timeout_handler(void *arg) 32267c478bd9Sstevel@tonic-gate { 32277c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = (usba_pipe_handle_data_t *)arg; 32287c478bd9Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state( 3229*6a9de478Ssl ph->p_usba_device->usb_root_hub_dip); 32307c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 32317c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, *next; 32327c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *expire_xfer_list = NULL; 32337c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd; 32347c478bd9Sstevel@tonic-gate 32357c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 32367c478bd9Sstevel@tonic-gate "ehci_xfer_timeout_handler: ehcip = 0x%p, ph = 0x%p", ehcip, ph); 32377c478bd9Sstevel@tonic-gate 32387c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 32397c478bd9Sstevel@tonic-gate 32407c478bd9Sstevel@tonic-gate /* 32417c478bd9Sstevel@tonic-gate * Check whether still timeout handler is valid. 32427c478bd9Sstevel@tonic-gate */ 32437c478bd9Sstevel@tonic-gate if (pp->pp_timer_id != 0) { 32447c478bd9Sstevel@tonic-gate 32457c478bd9Sstevel@tonic-gate /* Reset the timer id to zero */ 32467c478bd9Sstevel@tonic-gate pp->pp_timer_id = 0; 32477c478bd9Sstevel@tonic-gate } else { 32487c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 32497c478bd9Sstevel@tonic-gate 32507c478bd9Sstevel@tonic-gate return; 32517c478bd9Sstevel@tonic-gate } 32527c478bd9Sstevel@tonic-gate 32537c478bd9Sstevel@tonic-gate /* Get the transfer timeout list head */ 32547c478bd9Sstevel@tonic-gate tw = pp->pp_timeout_list; 32557c478bd9Sstevel@tonic-gate 32567c478bd9Sstevel@tonic-gate while (tw) { 32577c478bd9Sstevel@tonic-gate 32587c478bd9Sstevel@tonic-gate /* Get the transfer on the timeout list */ 32597c478bd9Sstevel@tonic-gate next = tw->tw_timeout_next; 32607c478bd9Sstevel@tonic-gate 32617c478bd9Sstevel@tonic-gate tw->tw_timeout--; 32627c478bd9Sstevel@tonic-gate 32637c478bd9Sstevel@tonic-gate if (tw->tw_timeout <= 0) { 32647c478bd9Sstevel@tonic-gate 32657c478bd9Sstevel@tonic-gate /* remove the tw from the timeout list */ 32667c478bd9Sstevel@tonic-gate ehci_remove_tw_from_timeout_list(ehcip, tw); 32677c478bd9Sstevel@tonic-gate 32687c478bd9Sstevel@tonic-gate /* remove QTDs from active QTD list */ 32697c478bd9Sstevel@tonic-gate qtd = tw->tw_qtd_head; 32707c478bd9Sstevel@tonic-gate while (qtd) { 32717c478bd9Sstevel@tonic-gate ehci_remove_qtd_from_active_qtd_list( 3272*6a9de478Ssl ehcip, qtd); 32737c478bd9Sstevel@tonic-gate 32747c478bd9Sstevel@tonic-gate /* Get the next QTD from the wrapper */ 32757c478bd9Sstevel@tonic-gate qtd = ehci_qtd_iommu_to_cpu(ehcip, 32767c478bd9Sstevel@tonic-gate Get_QTD(qtd->qtd_tw_next_qtd)); 32777c478bd9Sstevel@tonic-gate } 32787c478bd9Sstevel@tonic-gate 32797c478bd9Sstevel@tonic-gate /* 32807c478bd9Sstevel@tonic-gate * Preserve the order to the requests 32817c478bd9Sstevel@tonic-gate * started time sequence. 32827c478bd9Sstevel@tonic-gate */ 32837c478bd9Sstevel@tonic-gate tw->tw_timeout_next = expire_xfer_list; 32847c478bd9Sstevel@tonic-gate expire_xfer_list = tw; 32857c478bd9Sstevel@tonic-gate } 32867c478bd9Sstevel@tonic-gate 32877c478bd9Sstevel@tonic-gate tw = next; 32887c478bd9Sstevel@tonic-gate } 32897c478bd9Sstevel@tonic-gate 32907c478bd9Sstevel@tonic-gate /* 32917c478bd9Sstevel@tonic-gate * The timer should be started before the callbacks. 32927c478bd9Sstevel@tonic-gate * There is always a chance that ehci interrupts come 32937c478bd9Sstevel@tonic-gate * in when we release the mutex while calling the tw back. 32947c478bd9Sstevel@tonic-gate * To keep an accurate timeout it should be restarted 32957c478bd9Sstevel@tonic-gate * as soon as possible. 32967c478bd9Sstevel@tonic-gate */ 32977c478bd9Sstevel@tonic-gate ehci_start_timer(ehcip, pp); 32987c478bd9Sstevel@tonic-gate 32997c478bd9Sstevel@tonic-gate /* Get the expired transfer timeout list head */ 33007c478bd9Sstevel@tonic-gate tw = expire_xfer_list; 33017c478bd9Sstevel@tonic-gate 33027c478bd9Sstevel@tonic-gate while (tw) { 33037c478bd9Sstevel@tonic-gate 33047c478bd9Sstevel@tonic-gate /* Get the next tw on the expired transfer timeout list */ 33057c478bd9Sstevel@tonic-gate next = tw->tw_timeout_next; 33067c478bd9Sstevel@tonic-gate 33077c478bd9Sstevel@tonic-gate /* 33087c478bd9Sstevel@tonic-gate * The error handle routine will release the mutex when 33097c478bd9Sstevel@tonic-gate * calling back to USBA. But this will not cause any race. 33107c478bd9Sstevel@tonic-gate * We do the callback and are relying on ehci_pipe_cleanup() 33117c478bd9Sstevel@tonic-gate * to halt the queue head and clean up since we should not 33127c478bd9Sstevel@tonic-gate * block in timeout context. 33137c478bd9Sstevel@tonic-gate */ 33147c478bd9Sstevel@tonic-gate ehci_handle_error(ehcip, tw->tw_qtd_head, USB_CR_TIMEOUT); 33157c478bd9Sstevel@tonic-gate 33167c478bd9Sstevel@tonic-gate tw = next; 33177c478bd9Sstevel@tonic-gate } 33187c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 33197c478bd9Sstevel@tonic-gate } 33207c478bd9Sstevel@tonic-gate 33217c478bd9Sstevel@tonic-gate 33227c478bd9Sstevel@tonic-gate /* 33237c478bd9Sstevel@tonic-gate * ehci_remove_tw_from_timeout_list: 33247c478bd9Sstevel@tonic-gate * 33257c478bd9Sstevel@tonic-gate * Remove Control or bulk transfer from the timeout list. 33267c478bd9Sstevel@tonic-gate */ 33277c478bd9Sstevel@tonic-gate static void 33287c478bd9Sstevel@tonic-gate ehci_remove_tw_from_timeout_list( 33297c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 33307c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 33317c478bd9Sstevel@tonic-gate { 33327c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; 33337c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *prev, *next; 33347c478bd9Sstevel@tonic-gate 33357c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 33367c478bd9Sstevel@tonic-gate "ehci_remove_tw_from_timeout_list: tw = 0x%p", tw); 33377c478bd9Sstevel@tonic-gate 33387c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 33397c478bd9Sstevel@tonic-gate 33407c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 33417c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 33427c478bd9Sstevel@tonic-gate 33437c478bd9Sstevel@tonic-gate if (pp->pp_timeout_list) { 33447c478bd9Sstevel@tonic-gate if (pp->pp_timeout_list == tw) { 33457c478bd9Sstevel@tonic-gate pp->pp_timeout_list = tw->tw_timeout_next; 33467c478bd9Sstevel@tonic-gate 33477c478bd9Sstevel@tonic-gate tw->tw_timeout_next = NULL; 33487c478bd9Sstevel@tonic-gate } else { 33497c478bd9Sstevel@tonic-gate prev = pp->pp_timeout_list; 33507c478bd9Sstevel@tonic-gate next = prev->tw_timeout_next; 33517c478bd9Sstevel@tonic-gate 33527c478bd9Sstevel@tonic-gate while (next && (next != tw)) { 33537c478bd9Sstevel@tonic-gate prev = next; 33547c478bd9Sstevel@tonic-gate next = next->tw_timeout_next; 33557c478bd9Sstevel@tonic-gate } 33567c478bd9Sstevel@tonic-gate 33577c478bd9Sstevel@tonic-gate if (next == tw) { 33587c478bd9Sstevel@tonic-gate prev->tw_timeout_next = 3359*6a9de478Ssl next->tw_timeout_next; 33607c478bd9Sstevel@tonic-gate tw->tw_timeout_next = NULL; 33617c478bd9Sstevel@tonic-gate } 33627c478bd9Sstevel@tonic-gate } 33637c478bd9Sstevel@tonic-gate } 33647c478bd9Sstevel@tonic-gate } 33657c478bd9Sstevel@tonic-gate 33667c478bd9Sstevel@tonic-gate 33677c478bd9Sstevel@tonic-gate /* 33687c478bd9Sstevel@tonic-gate * ehci_start_timer: 33697c478bd9Sstevel@tonic-gate * 33707c478bd9Sstevel@tonic-gate * Start the pipe's timer 33717c478bd9Sstevel@tonic-gate */ 33727c478bd9Sstevel@tonic-gate static void 33737c478bd9Sstevel@tonic-gate ehci_start_timer( 33747c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 33757c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp) 33767c478bd9Sstevel@tonic-gate { 33777c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 33787c478bd9Sstevel@tonic-gate "ehci_start_timer: ehcip = 0x%p, pp = 0x%p", ehcip, pp); 33797c478bd9Sstevel@tonic-gate 33807c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 33817c478bd9Sstevel@tonic-gate 33827c478bd9Sstevel@tonic-gate /* 33837c478bd9Sstevel@tonic-gate * Start the pipe's timer only if currently timer is not 33847c478bd9Sstevel@tonic-gate * running and if there are any transfers on the timeout 33857c478bd9Sstevel@tonic-gate * list. This timer will be per pipe. 33867c478bd9Sstevel@tonic-gate */ 33877c478bd9Sstevel@tonic-gate if ((!pp->pp_timer_id) && (pp->pp_timeout_list)) { 33887c478bd9Sstevel@tonic-gate pp->pp_timer_id = timeout(ehci_xfer_timeout_handler, 33897c478bd9Sstevel@tonic-gate (void *)(pp->pp_pipe_handle), drv_usectohz(1000000)); 33907c478bd9Sstevel@tonic-gate } 33917c478bd9Sstevel@tonic-gate } 33927c478bd9Sstevel@tonic-gate 33937c478bd9Sstevel@tonic-gate /* 33947c478bd9Sstevel@tonic-gate * ehci_deallocate_tw: 33957c478bd9Sstevel@tonic-gate * 33967c478bd9Sstevel@tonic-gate * Deallocate of a Transaction Wrapper (TW) and this involves the freeing of 33977c478bd9Sstevel@tonic-gate * of DMA resources. 33987c478bd9Sstevel@tonic-gate */ 33997c478bd9Sstevel@tonic-gate void 34007c478bd9Sstevel@tonic-gate ehci_deallocate_tw( 34017c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 34027c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 34037c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 34047c478bd9Sstevel@tonic-gate { 34057c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *prev, *next; 34067c478bd9Sstevel@tonic-gate 34077c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 34087c478bd9Sstevel@tonic-gate "ehci_deallocate_tw: tw = 0x%p", tw); 34097c478bd9Sstevel@tonic-gate 34107c478bd9Sstevel@tonic-gate /* 34117c478bd9Sstevel@tonic-gate * If the transfer wrapper has no Host Controller (HC) 34127c478bd9Sstevel@tonic-gate * Transfer Descriptors (QTD) associated with it, then 34137c478bd9Sstevel@tonic-gate * remove the transfer wrapper. 34147c478bd9Sstevel@tonic-gate */ 34157c478bd9Sstevel@tonic-gate if (tw->tw_qtd_head) { 34167c478bd9Sstevel@tonic-gate ASSERT(tw->tw_qtd_tail != NULL); 34177c478bd9Sstevel@tonic-gate 34187c478bd9Sstevel@tonic-gate return; 34197c478bd9Sstevel@tonic-gate } 34207c478bd9Sstevel@tonic-gate 34217c478bd9Sstevel@tonic-gate ASSERT(tw->tw_qtd_tail == NULL); 34227c478bd9Sstevel@tonic-gate 34237c478bd9Sstevel@tonic-gate /* Make sure we return all the unused qtd's to the pool as well */ 34247c478bd9Sstevel@tonic-gate ehci_free_tw_td_resources(ehcip, tw); 34257c478bd9Sstevel@tonic-gate 34267c478bd9Sstevel@tonic-gate /* 34277c478bd9Sstevel@tonic-gate * If pp->pp_tw_head and pp->pp_tw_tail are pointing to 34287c478bd9Sstevel@tonic-gate * given TW then set the head and tail equal to NULL. 34297c478bd9Sstevel@tonic-gate * Otherwise search for this TW in the linked TW's list 34307c478bd9Sstevel@tonic-gate * and then remove this TW from the list. 34317c478bd9Sstevel@tonic-gate */ 34327c478bd9Sstevel@tonic-gate if (pp->pp_tw_head == tw) { 34337c478bd9Sstevel@tonic-gate if (pp->pp_tw_tail == tw) { 34347c478bd9Sstevel@tonic-gate pp->pp_tw_head = NULL; 34357c478bd9Sstevel@tonic-gate pp->pp_tw_tail = NULL; 34367c478bd9Sstevel@tonic-gate } else { 34377c478bd9Sstevel@tonic-gate pp->pp_tw_head = tw->tw_next; 34387c478bd9Sstevel@tonic-gate } 34397c478bd9Sstevel@tonic-gate } else { 34407c478bd9Sstevel@tonic-gate prev = pp->pp_tw_head; 34417c478bd9Sstevel@tonic-gate next = prev->tw_next; 34427c478bd9Sstevel@tonic-gate 34437c478bd9Sstevel@tonic-gate while (next && (next != tw)) { 34447c478bd9Sstevel@tonic-gate prev = next; 34457c478bd9Sstevel@tonic-gate next = next->tw_next; 34467c478bd9Sstevel@tonic-gate } 34477c478bd9Sstevel@tonic-gate 34487c478bd9Sstevel@tonic-gate if (next == tw) { 34497c478bd9Sstevel@tonic-gate prev->tw_next = next->tw_next; 34507c478bd9Sstevel@tonic-gate 34517c478bd9Sstevel@tonic-gate if (pp->pp_tw_tail == tw) { 34527c478bd9Sstevel@tonic-gate pp->pp_tw_tail = prev; 34537c478bd9Sstevel@tonic-gate } 34547c478bd9Sstevel@tonic-gate } 34557c478bd9Sstevel@tonic-gate } 34567c478bd9Sstevel@tonic-gate 34577c478bd9Sstevel@tonic-gate /* 34587c478bd9Sstevel@tonic-gate * Make sure that, this TW has been removed 34597c478bd9Sstevel@tonic-gate * from the timeout list. 34607c478bd9Sstevel@tonic-gate */ 34617c478bd9Sstevel@tonic-gate ehci_remove_tw_from_timeout_list(ehcip, tw); 34627c478bd9Sstevel@tonic-gate 34637c478bd9Sstevel@tonic-gate /* Deallocate this TW */ 34647c478bd9Sstevel@tonic-gate ehci_free_tw(ehcip, pp, tw); 34657c478bd9Sstevel@tonic-gate } 34667c478bd9Sstevel@tonic-gate 34677c478bd9Sstevel@tonic-gate 34687c478bd9Sstevel@tonic-gate /* 34697c478bd9Sstevel@tonic-gate * ehci_free_dma_resources: 34707c478bd9Sstevel@tonic-gate * 34717c478bd9Sstevel@tonic-gate * Free dma resources of a Transfer Wrapper (TW) and also free the TW. 34727c478bd9Sstevel@tonic-gate * 34737c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 34747c478bd9Sstevel@tonic-gate */ 34757c478bd9Sstevel@tonic-gate void 34767c478bd9Sstevel@tonic-gate ehci_free_dma_resources( 34777c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 34787c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 34797c478bd9Sstevel@tonic-gate { 34807c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 34817c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *head_tw = pp->pp_tw_head; 34827c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *next_tw, *tw; 34837c478bd9Sstevel@tonic-gate 34847c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 34857c478bd9Sstevel@tonic-gate "ehci_free_dma_resources: ph = 0x%p", (void *)ph); 34867c478bd9Sstevel@tonic-gate 34877c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 34887c478bd9Sstevel@tonic-gate 34897c478bd9Sstevel@tonic-gate /* Process the Transfer Wrappers */ 34907c478bd9Sstevel@tonic-gate next_tw = head_tw; 34917c478bd9Sstevel@tonic-gate while (next_tw) { 34927c478bd9Sstevel@tonic-gate tw = next_tw; 34937c478bd9Sstevel@tonic-gate next_tw = tw->tw_next; 34947c478bd9Sstevel@tonic-gate 34957c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 34967c478bd9Sstevel@tonic-gate "ehci_free_dma_resources: Free TW = 0x%p", (void *)tw); 34977c478bd9Sstevel@tonic-gate 34987c478bd9Sstevel@tonic-gate ehci_free_tw(ehcip, pp, tw); 34997c478bd9Sstevel@tonic-gate } 35007c478bd9Sstevel@tonic-gate 35017c478bd9Sstevel@tonic-gate /* Adjust the head and tail pointers */ 35027c478bd9Sstevel@tonic-gate pp->pp_tw_head = NULL; 35037c478bd9Sstevel@tonic-gate pp->pp_tw_tail = NULL; 35047c478bd9Sstevel@tonic-gate } 35057c478bd9Sstevel@tonic-gate 35067c478bd9Sstevel@tonic-gate 35077c478bd9Sstevel@tonic-gate /* 35087c478bd9Sstevel@tonic-gate * ehci_free_tw: 35097c478bd9Sstevel@tonic-gate * 35107c478bd9Sstevel@tonic-gate * Free the Transfer Wrapper (TW). 35117c478bd9Sstevel@tonic-gate */ 35127c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 35137c478bd9Sstevel@tonic-gate static void 35147c478bd9Sstevel@tonic-gate ehci_free_tw( 35157c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 35167c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 35177c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 35187c478bd9Sstevel@tonic-gate { 35197c478bd9Sstevel@tonic-gate int rval; 35207c478bd9Sstevel@tonic-gate 35217c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 35227c478bd9Sstevel@tonic-gate "ehci_free_tw: tw = 0x%p", tw); 35237c478bd9Sstevel@tonic-gate 35247c478bd9Sstevel@tonic-gate ASSERT(tw != NULL); 35257c478bd9Sstevel@tonic-gate ASSERT(tw->tw_id != NULL); 35267c478bd9Sstevel@tonic-gate 35277c478bd9Sstevel@tonic-gate /* Free 32bit ID */ 35287c478bd9Sstevel@tonic-gate EHCI_FREE_ID((uint32_t)tw->tw_id); 35297c478bd9Sstevel@tonic-gate 3530688b07c5Sgc if (tw->tw_dmahandle != NULL) { 3531688b07c5Sgc rval = ddi_dma_unbind_handle(tw->tw_dmahandle); 3532688b07c5Sgc ASSERT(rval == DDI_SUCCESS); 35337c478bd9Sstevel@tonic-gate 3534688b07c5Sgc ddi_dma_mem_free(&tw->tw_accesshandle); 3535688b07c5Sgc ddi_dma_free_handle(&tw->tw_dmahandle); 3536688b07c5Sgc } 35377c478bd9Sstevel@tonic-gate 35387c478bd9Sstevel@tonic-gate /* Free transfer wrapper */ 35397c478bd9Sstevel@tonic-gate kmem_free(tw, sizeof (ehci_trans_wrapper_t)); 35407c478bd9Sstevel@tonic-gate } 35417c478bd9Sstevel@tonic-gate 35427c478bd9Sstevel@tonic-gate 35437c478bd9Sstevel@tonic-gate /* 35447c478bd9Sstevel@tonic-gate * Miscellaneous functions 35457c478bd9Sstevel@tonic-gate */ 35467c478bd9Sstevel@tonic-gate 35477c478bd9Sstevel@tonic-gate /* 35487c478bd9Sstevel@tonic-gate * ehci_allocate_intr_in_resource 35497c478bd9Sstevel@tonic-gate * 35507c478bd9Sstevel@tonic-gate * Allocate interrupt request structure for the interrupt IN transfer. 35517c478bd9Sstevel@tonic-gate */ 35527c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 35537c478bd9Sstevel@tonic-gate int 35547c478bd9Sstevel@tonic-gate ehci_allocate_intr_in_resource( 35557c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 35567c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 35577c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 35587c478bd9Sstevel@tonic-gate usb_flags_t flags) 35597c478bd9Sstevel@tonic-gate { 35607c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 35617c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp; 35627c478bd9Sstevel@tonic-gate usb_opaque_t client_periodic_in_reqp; 35637c478bd9Sstevel@tonic-gate size_t length = 0; 35647c478bd9Sstevel@tonic-gate 35657c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 35667c478bd9Sstevel@tonic-gate "ehci_allocate_intr_in_resource:" 35677c478bd9Sstevel@tonic-gate "pp = 0x%p tw = 0x%p flags = 0x%x", pp, tw, flags); 35687c478bd9Sstevel@tonic-gate 35697c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 35707c478bd9Sstevel@tonic-gate ASSERT(tw->tw_curr_xfer_reqp == NULL); 35717c478bd9Sstevel@tonic-gate 35727c478bd9Sstevel@tonic-gate /* Get the client periodic in request pointer */ 35737c478bd9Sstevel@tonic-gate client_periodic_in_reqp = pp->pp_client_periodic_in_reqp; 35747c478bd9Sstevel@tonic-gate 35757c478bd9Sstevel@tonic-gate /* 35767c478bd9Sstevel@tonic-gate * If it a periodic IN request and periodic request is NULL, 35777c478bd9Sstevel@tonic-gate * allocate corresponding usb periodic IN request for the 35787c478bd9Sstevel@tonic-gate * current periodic polling request and copy the information 35797c478bd9Sstevel@tonic-gate * from the saved periodic request structure. 35807c478bd9Sstevel@tonic-gate */ 35817c478bd9Sstevel@tonic-gate if (client_periodic_in_reqp) { 35827c478bd9Sstevel@tonic-gate 35837c478bd9Sstevel@tonic-gate /* Get the interrupt transfer length */ 35847c478bd9Sstevel@tonic-gate length = ((usb_intr_req_t *) 35857c478bd9Sstevel@tonic-gate client_periodic_in_reqp)->intr_len; 35867c478bd9Sstevel@tonic-gate 35877c478bd9Sstevel@tonic-gate curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip, 35887c478bd9Sstevel@tonic-gate (usb_intr_req_t *)client_periodic_in_reqp, length, flags); 35897c478bd9Sstevel@tonic-gate } else { 35907c478bd9Sstevel@tonic-gate curr_intr_reqp = usb_alloc_intr_req(ph->p_dip, length, flags); 35917c478bd9Sstevel@tonic-gate } 35927c478bd9Sstevel@tonic-gate 35937c478bd9Sstevel@tonic-gate if (curr_intr_reqp == NULL) { 35947c478bd9Sstevel@tonic-gate 35957c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 35967c478bd9Sstevel@tonic-gate "ehci_allocate_intr_in_resource: Interrupt" 35977c478bd9Sstevel@tonic-gate "request structure allocation failed"); 35987c478bd9Sstevel@tonic-gate 35997c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 36007c478bd9Sstevel@tonic-gate } 36017c478bd9Sstevel@tonic-gate 36027c478bd9Sstevel@tonic-gate /* For polled mode */ 36037c478bd9Sstevel@tonic-gate if (client_periodic_in_reqp == NULL) { 36047c478bd9Sstevel@tonic-gate curr_intr_reqp->intr_attributes = USB_ATTRS_SHORT_XFER_OK; 36057c478bd9Sstevel@tonic-gate curr_intr_reqp->intr_len = ph->p_ep.wMaxPacketSize; 36067c478bd9Sstevel@tonic-gate } else { 36077c478bd9Sstevel@tonic-gate /* Check and save the timeout value */ 36087c478bd9Sstevel@tonic-gate tw->tw_timeout = (curr_intr_reqp->intr_attributes & 36097c478bd9Sstevel@tonic-gate USB_ATTRS_ONE_XFER) ? curr_intr_reqp->intr_timeout: 0; 36107c478bd9Sstevel@tonic-gate } 36117c478bd9Sstevel@tonic-gate 36127c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = (usb_opaque_t)curr_intr_reqp; 36137c478bd9Sstevel@tonic-gate tw->tw_length = curr_intr_reqp->intr_len; 36147c478bd9Sstevel@tonic-gate 36157c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 36167c478bd9Sstevel@tonic-gate ph->p_req_count++; 36177c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 36187c478bd9Sstevel@tonic-gate 36197c478bd9Sstevel@tonic-gate pp->pp_state = EHCI_PIPE_STATE_ACTIVE; 36207c478bd9Sstevel@tonic-gate 36217c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 36227c478bd9Sstevel@tonic-gate } 36237c478bd9Sstevel@tonic-gate 36247c478bd9Sstevel@tonic-gate /* 36257c478bd9Sstevel@tonic-gate * ehci_pipe_cleanup 36267c478bd9Sstevel@tonic-gate * 36277c478bd9Sstevel@tonic-gate * Cleanup ehci pipe. 36287c478bd9Sstevel@tonic-gate */ 36297c478bd9Sstevel@tonic-gate void 36307c478bd9Sstevel@tonic-gate ehci_pipe_cleanup( 36317c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 36327c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 36337c478bd9Sstevel@tonic-gate { 36347c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 36357c478bd9Sstevel@tonic-gate uint_t pipe_state = pp->pp_state; 36367c478bd9Sstevel@tonic-gate usb_cr_t completion_reason; 36377c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 36387c478bd9Sstevel@tonic-gate 36397c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 36407c478bd9Sstevel@tonic-gate "ehci_pipe_cleanup: ph = 0x%p", ph); 36417c478bd9Sstevel@tonic-gate 36427c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 36437c478bd9Sstevel@tonic-gate 36447c478bd9Sstevel@tonic-gate if (EHCI_ISOC_ENDPOINT(eptd)) { 36457c478bd9Sstevel@tonic-gate ehci_isoc_pipe_cleanup(ehcip, ph); 36467c478bd9Sstevel@tonic-gate 36477c478bd9Sstevel@tonic-gate return; 36487c478bd9Sstevel@tonic-gate } 36497c478bd9Sstevel@tonic-gate 36507c478bd9Sstevel@tonic-gate ASSERT(!servicing_interrupt()); 36517c478bd9Sstevel@tonic-gate 36527c478bd9Sstevel@tonic-gate /* 36537c478bd9Sstevel@tonic-gate * Set the QH's status to Halt condition. 36547c478bd9Sstevel@tonic-gate * If another thread is halting this function will automatically 36557c478bd9Sstevel@tonic-gate * wait. If a pipe close happens at this time 36567c478bd9Sstevel@tonic-gate * we will be in lots of trouble. 36577c478bd9Sstevel@tonic-gate * If we are in an interrupt thread, don't halt, because it may 36587c478bd9Sstevel@tonic-gate * do a wait_for_sof. 36597c478bd9Sstevel@tonic-gate */ 36607c478bd9Sstevel@tonic-gate ehci_modify_qh_status_bit(ehcip, pp, SET_HALT); 36617c478bd9Sstevel@tonic-gate 36627c478bd9Sstevel@tonic-gate /* 36637c478bd9Sstevel@tonic-gate * Wait for processing all completed transfers and 36647c478bd9Sstevel@tonic-gate * to send results to upstream. 36657c478bd9Sstevel@tonic-gate */ 36667c478bd9Sstevel@tonic-gate ehci_wait_for_transfers_completion(ehcip, pp); 36677c478bd9Sstevel@tonic-gate 36687c478bd9Sstevel@tonic-gate /* Save the data toggle information */ 36697c478bd9Sstevel@tonic-gate ehci_save_data_toggle(ehcip, ph); 36707c478bd9Sstevel@tonic-gate 36717c478bd9Sstevel@tonic-gate /* 36727c478bd9Sstevel@tonic-gate * Traverse the list of QTDs for this pipe using transfer 36737c478bd9Sstevel@tonic-gate * wrapper. Process these QTDs depending on their status. 36747c478bd9Sstevel@tonic-gate * And stop the timer of this pipe. 36757c478bd9Sstevel@tonic-gate */ 36767c478bd9Sstevel@tonic-gate ehci_traverse_qtds(ehcip, ph); 36777c478bd9Sstevel@tonic-gate 36787c478bd9Sstevel@tonic-gate /* Make sure the timer is not running */ 36797c478bd9Sstevel@tonic-gate ASSERT(pp->pp_timer_id == 0); 36807c478bd9Sstevel@tonic-gate 36817c478bd9Sstevel@tonic-gate /* Do callbacks for all unfinished requests */ 36827c478bd9Sstevel@tonic-gate ehci_handle_outstanding_requests(ehcip, pp); 36837c478bd9Sstevel@tonic-gate 36847c478bd9Sstevel@tonic-gate /* Free DMA resources */ 36857c478bd9Sstevel@tonic-gate ehci_free_dma_resources(ehcip, ph); 36867c478bd9Sstevel@tonic-gate 36877c478bd9Sstevel@tonic-gate switch (pipe_state) { 36887c478bd9Sstevel@tonic-gate case EHCI_PIPE_STATE_CLOSE: 36897c478bd9Sstevel@tonic-gate completion_reason = USB_CR_PIPE_CLOSING; 36907c478bd9Sstevel@tonic-gate break; 36917c478bd9Sstevel@tonic-gate case EHCI_PIPE_STATE_RESET: 36927c478bd9Sstevel@tonic-gate case EHCI_PIPE_STATE_STOP_POLLING: 36937c478bd9Sstevel@tonic-gate /* Set completion reason */ 36947c478bd9Sstevel@tonic-gate completion_reason = (pipe_state == 36957c478bd9Sstevel@tonic-gate EHCI_PIPE_STATE_RESET) ? 36967c478bd9Sstevel@tonic-gate USB_CR_PIPE_RESET: USB_CR_STOPPED_POLLING; 36977c478bd9Sstevel@tonic-gate 36987c478bd9Sstevel@tonic-gate /* Restore the data toggle information */ 36997c478bd9Sstevel@tonic-gate ehci_restore_data_toggle(ehcip, ph); 37007c478bd9Sstevel@tonic-gate 37017c478bd9Sstevel@tonic-gate /* 37027c478bd9Sstevel@tonic-gate * Clear the halt bit to restart all the 37037c478bd9Sstevel@tonic-gate * transactions on this pipe. 37047c478bd9Sstevel@tonic-gate */ 37057c478bd9Sstevel@tonic-gate ehci_modify_qh_status_bit(ehcip, pp, CLEAR_HALT); 37067c478bd9Sstevel@tonic-gate 37077c478bd9Sstevel@tonic-gate /* Set pipe state to idle */ 37087c478bd9Sstevel@tonic-gate pp->pp_state = EHCI_PIPE_STATE_IDLE; 37097c478bd9Sstevel@tonic-gate 37107c478bd9Sstevel@tonic-gate break; 37117c478bd9Sstevel@tonic-gate } 37127c478bd9Sstevel@tonic-gate 37137c478bd9Sstevel@tonic-gate /* 37147c478bd9Sstevel@tonic-gate * Do the callback for the original client 37157c478bd9Sstevel@tonic-gate * periodic IN request. 37167c478bd9Sstevel@tonic-gate */ 37177c478bd9Sstevel@tonic-gate if ((EHCI_PERIODIC_ENDPOINT(eptd)) && 37187c478bd9Sstevel@tonic-gate ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == 37197c478bd9Sstevel@tonic-gate USB_EP_DIR_IN)) { 37207c478bd9Sstevel@tonic-gate 37217c478bd9Sstevel@tonic-gate ehci_do_client_periodic_in_req_callback( 37227c478bd9Sstevel@tonic-gate ehcip, pp, completion_reason); 37237c478bd9Sstevel@tonic-gate } 37247c478bd9Sstevel@tonic-gate } 37257c478bd9Sstevel@tonic-gate 37267c478bd9Sstevel@tonic-gate 37277c478bd9Sstevel@tonic-gate /* 37287c478bd9Sstevel@tonic-gate * ehci_wait_for_transfers_completion: 37297c478bd9Sstevel@tonic-gate * 37307c478bd9Sstevel@tonic-gate * Wait for processing all completed transfers and to send results 37317c478bd9Sstevel@tonic-gate * to upstream. 37327c478bd9Sstevel@tonic-gate */ 37337c478bd9Sstevel@tonic-gate static void 37347c478bd9Sstevel@tonic-gate ehci_wait_for_transfers_completion( 37357c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 37367c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp) 37377c478bd9Sstevel@tonic-gate { 37387c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *next_tw = pp->pp_tw_head; 37397c478bd9Sstevel@tonic-gate clock_t xfer_cmpl_time_wait; 37407c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd; 37417c478bd9Sstevel@tonic-gate 37427c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, 37437c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 37447c478bd9Sstevel@tonic-gate "ehci_wait_for_transfers_completion: pp = 0x%p", pp); 37457c478bd9Sstevel@tonic-gate 37467c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 37477c478bd9Sstevel@tonic-gate 37487c478bd9Sstevel@tonic-gate if ((ehci_state_is_operational(ehcip)) != USB_SUCCESS) { 37497c478bd9Sstevel@tonic-gate 37507c478bd9Sstevel@tonic-gate return; 37517c478bd9Sstevel@tonic-gate } 37527c478bd9Sstevel@tonic-gate 37537c478bd9Sstevel@tonic-gate pp->pp_count_done_qtds = 0; 37547c478bd9Sstevel@tonic-gate 37557c478bd9Sstevel@tonic-gate /* Process the transfer wrappers for this pipe */ 37567c478bd9Sstevel@tonic-gate while (next_tw) { 37577c478bd9Sstevel@tonic-gate qtd = (ehci_qtd_t *)next_tw->tw_qtd_head; 37587c478bd9Sstevel@tonic-gate 37597c478bd9Sstevel@tonic-gate /* 37607c478bd9Sstevel@tonic-gate * Walk through each QTD for this transfer wrapper. 37617c478bd9Sstevel@tonic-gate * If a QTD still exists, then it is either on done 37627c478bd9Sstevel@tonic-gate * list or on the QH's list. 37637c478bd9Sstevel@tonic-gate */ 37647c478bd9Sstevel@tonic-gate while (qtd) { 37657c478bd9Sstevel@tonic-gate if (!(Get_QTD(qtd->qtd_ctrl) & 37667c478bd9Sstevel@tonic-gate EHCI_QTD_CTRL_ACTIVE_XACT)) { 37677c478bd9Sstevel@tonic-gate pp->pp_count_done_qtds++; 37687c478bd9Sstevel@tonic-gate } 37697c478bd9Sstevel@tonic-gate 37707c478bd9Sstevel@tonic-gate qtd = ehci_qtd_iommu_to_cpu(ehcip, 37717c478bd9Sstevel@tonic-gate Get_QTD(qtd->qtd_tw_next_qtd)); 37727c478bd9Sstevel@tonic-gate } 37737c478bd9Sstevel@tonic-gate 37747c478bd9Sstevel@tonic-gate next_tw = next_tw->tw_next; 37757c478bd9Sstevel@tonic-gate } 37767c478bd9Sstevel@tonic-gate 37777c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 37787c478bd9Sstevel@tonic-gate "ehci_wait_for_transfers_completion: count_done_qtds = 0x%x", 37797c478bd9Sstevel@tonic-gate pp->pp_count_done_qtds); 37807c478bd9Sstevel@tonic-gate 37817c478bd9Sstevel@tonic-gate if (!pp->pp_count_done_qtds) { 37827c478bd9Sstevel@tonic-gate 37837c478bd9Sstevel@tonic-gate return; 37847c478bd9Sstevel@tonic-gate } 37857c478bd9Sstevel@tonic-gate 37867c478bd9Sstevel@tonic-gate /* Get the number of clock ticks to wait */ 37877c478bd9Sstevel@tonic-gate xfer_cmpl_time_wait = drv_usectohz(EHCI_XFER_CMPL_TIMEWAIT * 1000000); 37887c478bd9Sstevel@tonic-gate 37897c478bd9Sstevel@tonic-gate (void) cv_timedwait(&pp->pp_xfer_cmpl_cv, 37907c478bd9Sstevel@tonic-gate &ehcip->ehci_int_mutex, 37917c478bd9Sstevel@tonic-gate ddi_get_lbolt() + xfer_cmpl_time_wait); 37927c478bd9Sstevel@tonic-gate 37937c478bd9Sstevel@tonic-gate if (pp->pp_count_done_qtds) { 37947c478bd9Sstevel@tonic-gate 37957c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 37967c478bd9Sstevel@tonic-gate "ehci_wait_for_transfers_completion:" 37977c478bd9Sstevel@tonic-gate "No transfers completion confirmation received"); 37987c478bd9Sstevel@tonic-gate } 37997c478bd9Sstevel@tonic-gate } 38007c478bd9Sstevel@tonic-gate 38017c478bd9Sstevel@tonic-gate /* 38027c478bd9Sstevel@tonic-gate * ehci_check_for_transfers_completion: 38037c478bd9Sstevel@tonic-gate * 38047c478bd9Sstevel@tonic-gate * Check whether anybody is waiting for transfers completion event. If so, send 38057c478bd9Sstevel@tonic-gate * this event and also stop initiating any new transfers on this pipe. 38067c478bd9Sstevel@tonic-gate */ 38077c478bd9Sstevel@tonic-gate void 38087c478bd9Sstevel@tonic-gate ehci_check_for_transfers_completion( 38097c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 38107c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp) 38117c478bd9Sstevel@tonic-gate { 38127c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, 38137c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 38147c478bd9Sstevel@tonic-gate "ehci_check_for_transfers_completion: pp = 0x%p", pp); 38157c478bd9Sstevel@tonic-gate 38167c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 38177c478bd9Sstevel@tonic-gate 38187c478bd9Sstevel@tonic-gate if ((pp->pp_state == EHCI_PIPE_STATE_STOP_POLLING) && 38197c478bd9Sstevel@tonic-gate (pp->pp_error == USB_CR_NO_RESOURCES) && 38207c478bd9Sstevel@tonic-gate (pp->pp_cur_periodic_req_cnt == 0)) { 38217c478bd9Sstevel@tonic-gate 38227c478bd9Sstevel@tonic-gate /* Reset pipe error to zero */ 38237c478bd9Sstevel@tonic-gate pp->pp_error = 0; 38247c478bd9Sstevel@tonic-gate 38257c478bd9Sstevel@tonic-gate /* Do callback for original request */ 38267c478bd9Sstevel@tonic-gate ehci_do_client_periodic_in_req_callback( 38277c478bd9Sstevel@tonic-gate ehcip, pp, USB_CR_NO_RESOURCES); 38287c478bd9Sstevel@tonic-gate } 38297c478bd9Sstevel@tonic-gate 38307c478bd9Sstevel@tonic-gate if (pp->pp_count_done_qtds) { 38317c478bd9Sstevel@tonic-gate 38327c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 38337c478bd9Sstevel@tonic-gate "ehci_check_for_transfers_completion:" 38347c478bd9Sstevel@tonic-gate "count_done_qtds = 0x%x", pp->pp_count_done_qtds); 38357c478bd9Sstevel@tonic-gate 38367c478bd9Sstevel@tonic-gate /* Decrement the done qtd count */ 38377c478bd9Sstevel@tonic-gate pp->pp_count_done_qtds--; 38387c478bd9Sstevel@tonic-gate 38397c478bd9Sstevel@tonic-gate if (!pp->pp_count_done_qtds) { 38407c478bd9Sstevel@tonic-gate 38417c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 38427c478bd9Sstevel@tonic-gate "ehci_check_for_transfers_completion:" 38437c478bd9Sstevel@tonic-gate "Sent transfers completion event pp = 0x%p", pp); 38447c478bd9Sstevel@tonic-gate 38457c478bd9Sstevel@tonic-gate /* Send the transfer completion signal */ 38467c478bd9Sstevel@tonic-gate cv_signal(&pp->pp_xfer_cmpl_cv); 38477c478bd9Sstevel@tonic-gate } 38487c478bd9Sstevel@tonic-gate } 38497c478bd9Sstevel@tonic-gate } 38507c478bd9Sstevel@tonic-gate 38517c478bd9Sstevel@tonic-gate 38527c478bd9Sstevel@tonic-gate /* 38537c478bd9Sstevel@tonic-gate * ehci_save_data_toggle: 38547c478bd9Sstevel@tonic-gate * 38557c478bd9Sstevel@tonic-gate * Save the data toggle information. 38567c478bd9Sstevel@tonic-gate */ 38577c478bd9Sstevel@tonic-gate static void 38587c478bd9Sstevel@tonic-gate ehci_save_data_toggle( 38597c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 38607c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 38617c478bd9Sstevel@tonic-gate { 38627c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 38637c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 38647c478bd9Sstevel@tonic-gate uint_t data_toggle; 38657c478bd9Sstevel@tonic-gate usb_cr_t error = pp->pp_error; 38667c478bd9Sstevel@tonic-gate ehci_qh_t *qh = pp->pp_qh; 38677c478bd9Sstevel@tonic-gate 38687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, 38697c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 38707c478bd9Sstevel@tonic-gate "ehci_save_data_toggle: ph = 0x%p", ph); 38717c478bd9Sstevel@tonic-gate 38727c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 38737c478bd9Sstevel@tonic-gate 38747c478bd9Sstevel@tonic-gate /* Reset the pipe error value */ 38757c478bd9Sstevel@tonic-gate pp->pp_error = USB_CR_OK; 38767c478bd9Sstevel@tonic-gate 38777c478bd9Sstevel@tonic-gate /* Return immediately if it is a control pipe */ 38787c478bd9Sstevel@tonic-gate if ((eptd->bmAttributes & USB_EP_ATTR_MASK) == 38797c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) { 38807c478bd9Sstevel@tonic-gate 38817c478bd9Sstevel@tonic-gate return; 38827c478bd9Sstevel@tonic-gate } 38837c478bd9Sstevel@tonic-gate 38847c478bd9Sstevel@tonic-gate /* Get the data toggle information from the endpoint (QH) */ 38857c478bd9Sstevel@tonic-gate data_toggle = (Get_QH(qh->qh_status) & 38867c478bd9Sstevel@tonic-gate EHCI_QH_STS_DATA_TOGGLE)? DATA1:DATA0; 38877c478bd9Sstevel@tonic-gate 38887c478bd9Sstevel@tonic-gate /* 38897c478bd9Sstevel@tonic-gate * If error is STALL, then, set 38907c478bd9Sstevel@tonic-gate * data toggle to zero. 38917c478bd9Sstevel@tonic-gate */ 38927c478bd9Sstevel@tonic-gate if (error == USB_CR_STALL) { 38937c478bd9Sstevel@tonic-gate data_toggle = DATA0; 38947c478bd9Sstevel@tonic-gate } 38957c478bd9Sstevel@tonic-gate 38967c478bd9Sstevel@tonic-gate /* 38977c478bd9Sstevel@tonic-gate * Save the data toggle information 38987c478bd9Sstevel@tonic-gate * in the usb device structure. 38997c478bd9Sstevel@tonic-gate */ 39007c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 39017c478bd9Sstevel@tonic-gate usba_hcdi_set_data_toggle(ph->p_usba_device, ph->p_ep.bEndpointAddress, 39027c478bd9Sstevel@tonic-gate data_toggle); 39037c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 39047c478bd9Sstevel@tonic-gate } 39057c478bd9Sstevel@tonic-gate 39067c478bd9Sstevel@tonic-gate 39077c478bd9Sstevel@tonic-gate /* 39087c478bd9Sstevel@tonic-gate * ehci_restore_data_toggle: 39097c478bd9Sstevel@tonic-gate * 39107c478bd9Sstevel@tonic-gate * Restore the data toggle information. 39117c478bd9Sstevel@tonic-gate */ 39127c478bd9Sstevel@tonic-gate void 39137c478bd9Sstevel@tonic-gate ehci_restore_data_toggle( 39147c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 39157c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph) 39167c478bd9Sstevel@tonic-gate { 39177c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 39187c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 39197c478bd9Sstevel@tonic-gate uint_t data_toggle = 0; 39207c478bd9Sstevel@tonic-gate 39217c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, 39227c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 39237c478bd9Sstevel@tonic-gate "ehci_restore_data_toggle: ph = 0x%p", ph); 39247c478bd9Sstevel@tonic-gate 39257c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 39267c478bd9Sstevel@tonic-gate 39277c478bd9Sstevel@tonic-gate /* Return immediately if it is a control pipe */ 39287c478bd9Sstevel@tonic-gate if ((eptd->bmAttributes & USB_EP_ATTR_MASK) == 39297c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) { 39307c478bd9Sstevel@tonic-gate 39317c478bd9Sstevel@tonic-gate return; 39327c478bd9Sstevel@tonic-gate } 39337c478bd9Sstevel@tonic-gate 39347c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 39357c478bd9Sstevel@tonic-gate 39367c478bd9Sstevel@tonic-gate data_toggle = usba_hcdi_get_data_toggle(ph->p_usba_device, 39377c478bd9Sstevel@tonic-gate ph->p_ep.bEndpointAddress); 39387c478bd9Sstevel@tonic-gate usba_hcdi_set_data_toggle(ph->p_usba_device, ph->p_ep.bEndpointAddress, 39397c478bd9Sstevel@tonic-gate 0); 39407c478bd9Sstevel@tonic-gate 39417c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 39427c478bd9Sstevel@tonic-gate 39437c478bd9Sstevel@tonic-gate /* 39447c478bd9Sstevel@tonic-gate * Restore the data toggle bit depending on the 39457c478bd9Sstevel@tonic-gate * previous data toggle information. 39467c478bd9Sstevel@tonic-gate */ 39477c478bd9Sstevel@tonic-gate if (data_toggle) { 39487c478bd9Sstevel@tonic-gate Set_QH(pp->pp_qh->qh_status, 39497c478bd9Sstevel@tonic-gate Get_QH(pp->pp_qh->qh_status) | EHCI_QH_STS_DATA_TOGGLE); 39507c478bd9Sstevel@tonic-gate } else { 39517c478bd9Sstevel@tonic-gate Set_QH(pp->pp_qh->qh_status, 39527c478bd9Sstevel@tonic-gate Get_QH(pp->pp_qh->qh_status) & (~EHCI_QH_STS_DATA_TOGGLE)); 39537c478bd9Sstevel@tonic-gate } 39547c478bd9Sstevel@tonic-gate } 39557c478bd9Sstevel@tonic-gate 39567c478bd9Sstevel@tonic-gate 39577c478bd9Sstevel@tonic-gate /* 39587c478bd9Sstevel@tonic-gate * ehci_handle_outstanding_requests 39597c478bd9Sstevel@tonic-gate * 39607c478bd9Sstevel@tonic-gate * Deallocate interrupt request structure for the interrupt IN transfer. 39617c478bd9Sstevel@tonic-gate * Do the callbacks for all unfinished requests. 39627c478bd9Sstevel@tonic-gate * 39637c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 39647c478bd9Sstevel@tonic-gate */ 39657c478bd9Sstevel@tonic-gate void 39667c478bd9Sstevel@tonic-gate ehci_handle_outstanding_requests( 39677c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 39687c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp) 39697c478bd9Sstevel@tonic-gate { 39707c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 39717c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 39727c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *curr_tw; 39737c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *next_tw; 39747c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp; 39757c478bd9Sstevel@tonic-gate 39767c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, 39777c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 39787c478bd9Sstevel@tonic-gate "ehci_handle_outstanding_requests: pp = 0x%p", pp); 39797c478bd9Sstevel@tonic-gate 39807c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 39817c478bd9Sstevel@tonic-gate 39827c478bd9Sstevel@tonic-gate /* Deallocate all pre-allocated interrupt requests */ 39837c478bd9Sstevel@tonic-gate next_tw = pp->pp_tw_head; 39847c478bd9Sstevel@tonic-gate 39857c478bd9Sstevel@tonic-gate while (next_tw) { 39867c478bd9Sstevel@tonic-gate curr_tw = next_tw; 39877c478bd9Sstevel@tonic-gate next_tw = curr_tw->tw_next; 39887c478bd9Sstevel@tonic-gate 39897c478bd9Sstevel@tonic-gate curr_xfer_reqp = curr_tw->tw_curr_xfer_reqp; 39907c478bd9Sstevel@tonic-gate 39917c478bd9Sstevel@tonic-gate /* Deallocate current interrupt request */ 39927c478bd9Sstevel@tonic-gate if (curr_xfer_reqp) { 39937c478bd9Sstevel@tonic-gate 39947c478bd9Sstevel@tonic-gate if ((EHCI_PERIODIC_ENDPOINT(eptd)) && 39957c478bd9Sstevel@tonic-gate (curr_tw->tw_direction == EHCI_QTD_CTRL_IN_PID)) { 39967c478bd9Sstevel@tonic-gate 39977c478bd9Sstevel@tonic-gate /* Decrement periodic in request count */ 39987c478bd9Sstevel@tonic-gate pp->pp_cur_periodic_req_cnt--; 39997c478bd9Sstevel@tonic-gate 40007c478bd9Sstevel@tonic-gate ehci_deallocate_intr_in_resource( 40017c478bd9Sstevel@tonic-gate ehcip, pp, curr_tw); 40027c478bd9Sstevel@tonic-gate } else { 40037c478bd9Sstevel@tonic-gate ehci_hcdi_callback(ph, curr_tw, USB_CR_FLUSHED); 40047c478bd9Sstevel@tonic-gate } 40057c478bd9Sstevel@tonic-gate } 40067c478bd9Sstevel@tonic-gate } 40077c478bd9Sstevel@tonic-gate } 40087c478bd9Sstevel@tonic-gate 40097c478bd9Sstevel@tonic-gate 40107c478bd9Sstevel@tonic-gate /* 40117c478bd9Sstevel@tonic-gate * ehci_deallocate_intr_in_resource 40127c478bd9Sstevel@tonic-gate * 40137c478bd9Sstevel@tonic-gate * Deallocate interrupt request structure for the interrupt IN transfer. 40147c478bd9Sstevel@tonic-gate */ 40157c478bd9Sstevel@tonic-gate void 40167c478bd9Sstevel@tonic-gate ehci_deallocate_intr_in_resource( 40177c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 40187c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 40197c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 40207c478bd9Sstevel@tonic-gate { 40217c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 40227c478bd9Sstevel@tonic-gate uchar_t ep_attr = ph->p_ep.bmAttributes; 40237c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp; 40247c478bd9Sstevel@tonic-gate 40257c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, 40267c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 40277c478bd9Sstevel@tonic-gate "ehci_deallocate_intr_in_resource: " 40287c478bd9Sstevel@tonic-gate "pp = 0x%p tw = 0x%p", pp, tw); 40297c478bd9Sstevel@tonic-gate 40307c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 40317c478bd9Sstevel@tonic-gate ASSERT((ep_attr & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR); 40327c478bd9Sstevel@tonic-gate 40337c478bd9Sstevel@tonic-gate curr_xfer_reqp = tw->tw_curr_xfer_reqp; 40347c478bd9Sstevel@tonic-gate 40357c478bd9Sstevel@tonic-gate /* Check the current periodic in request pointer */ 40367c478bd9Sstevel@tonic-gate if (curr_xfer_reqp) { 40377c478bd9Sstevel@tonic-gate 40387c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = NULL; 40397c478bd9Sstevel@tonic-gate 40407c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex); 40417c478bd9Sstevel@tonic-gate ph->p_req_count--; 40427c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex); 40437c478bd9Sstevel@tonic-gate 40447c478bd9Sstevel@tonic-gate /* Free pre-allocated interrupt requests */ 40457c478bd9Sstevel@tonic-gate usb_free_intr_req((usb_intr_req_t *)curr_xfer_reqp); 40467c478bd9Sstevel@tonic-gate 40477c478bd9Sstevel@tonic-gate /* Set periodic in pipe state to idle */ 40487c478bd9Sstevel@tonic-gate pp->pp_state = EHCI_PIPE_STATE_IDLE; 40497c478bd9Sstevel@tonic-gate } 40507c478bd9Sstevel@tonic-gate } 40517c478bd9Sstevel@tonic-gate 40527c478bd9Sstevel@tonic-gate 40537c478bd9Sstevel@tonic-gate /* 40547c478bd9Sstevel@tonic-gate * ehci_do_client_periodic_in_req_callback 40557c478bd9Sstevel@tonic-gate * 40567c478bd9Sstevel@tonic-gate * Do callback for the original client periodic IN request. 40577c478bd9Sstevel@tonic-gate */ 40587c478bd9Sstevel@tonic-gate void 40597c478bd9Sstevel@tonic-gate ehci_do_client_periodic_in_req_callback( 40607c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 40617c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 40627c478bd9Sstevel@tonic-gate usb_cr_t completion_reason) 40637c478bd9Sstevel@tonic-gate { 40647c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph = pp->pp_pipe_handle; 40657c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep; 40667c478bd9Sstevel@tonic-gate 40677c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, 40687c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 40697c478bd9Sstevel@tonic-gate "ehci_do_client_periodic_in_req_callback: " 40707c478bd9Sstevel@tonic-gate "pp = 0x%p cc = 0x%x", pp, completion_reason); 40717c478bd9Sstevel@tonic-gate 40727c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 40737c478bd9Sstevel@tonic-gate 40747c478bd9Sstevel@tonic-gate /* 40757c478bd9Sstevel@tonic-gate * Check for Interrupt/Isochronous IN, whether we need to do 40767c478bd9Sstevel@tonic-gate * callback for the original client's periodic IN request. 40777c478bd9Sstevel@tonic-gate */ 40787c478bd9Sstevel@tonic-gate if (pp->pp_client_periodic_in_reqp) { 40797c478bd9Sstevel@tonic-gate ASSERT(pp->pp_cur_periodic_req_cnt == 0); 40807c478bd9Sstevel@tonic-gate if (EHCI_ISOC_ENDPOINT(eptd)) { 40817c478bd9Sstevel@tonic-gate ehci_hcdi_isoc_callback(ph, NULL, completion_reason); 40827c478bd9Sstevel@tonic-gate } else { 40837c478bd9Sstevel@tonic-gate ehci_hcdi_callback(ph, NULL, completion_reason); 40847c478bd9Sstevel@tonic-gate } 40857c478bd9Sstevel@tonic-gate } 40867c478bd9Sstevel@tonic-gate } 40877c478bd9Sstevel@tonic-gate 40887c478bd9Sstevel@tonic-gate 40897c478bd9Sstevel@tonic-gate /* 40907c478bd9Sstevel@tonic-gate * ehci_hcdi_callback() 40917c478bd9Sstevel@tonic-gate * 40927c478bd9Sstevel@tonic-gate * Convenience wrapper around usba_hcdi_cb() other than root hub. 40937c478bd9Sstevel@tonic-gate */ 40947c478bd9Sstevel@tonic-gate void 40957c478bd9Sstevel@tonic-gate ehci_hcdi_callback( 40967c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 40977c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw, 40987c478bd9Sstevel@tonic-gate usb_cr_t completion_reason) 40997c478bd9Sstevel@tonic-gate { 41007c478bd9Sstevel@tonic-gate ehci_state_t *ehcip = ehci_obtain_state( 4101*6a9de478Ssl ph->p_usba_device->usb_root_hub_dip); 41027c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp = (ehci_pipe_private_t *)ph->p_hcd_private; 41037c478bd9Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp; 41047c478bd9Sstevel@tonic-gate uint_t pipe_state = 0; 41057c478bd9Sstevel@tonic-gate 41067c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl, 41077c478bd9Sstevel@tonic-gate "ehci_hcdi_callback: ph = 0x%p, tw = 0x%p, cr = 0x%x", 41087c478bd9Sstevel@tonic-gate ph, tw, completion_reason); 41097c478bd9Sstevel@tonic-gate 41107c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 41117c478bd9Sstevel@tonic-gate 41127c478bd9Sstevel@tonic-gate /* Set the pipe state as per completion reason */ 41137c478bd9Sstevel@tonic-gate switch (completion_reason) { 41147c478bd9Sstevel@tonic-gate case USB_CR_OK: 41157c478bd9Sstevel@tonic-gate pipe_state = pp->pp_state; 41167c478bd9Sstevel@tonic-gate break; 41177c478bd9Sstevel@tonic-gate case USB_CR_NO_RESOURCES: 41187c478bd9Sstevel@tonic-gate case USB_CR_NOT_SUPPORTED: 41197c478bd9Sstevel@tonic-gate case USB_CR_PIPE_RESET: 41207c478bd9Sstevel@tonic-gate case USB_CR_STOPPED_POLLING: 41217c478bd9Sstevel@tonic-gate pipe_state = EHCI_PIPE_STATE_IDLE; 41227c478bd9Sstevel@tonic-gate break; 41237c478bd9Sstevel@tonic-gate case USB_CR_PIPE_CLOSING: 41247c478bd9Sstevel@tonic-gate break; 41257c478bd9Sstevel@tonic-gate default: 41267c478bd9Sstevel@tonic-gate /* Set the pipe state to error */ 41277c478bd9Sstevel@tonic-gate pipe_state = EHCI_PIPE_STATE_ERROR; 41287c478bd9Sstevel@tonic-gate pp->pp_error = completion_reason; 41297c478bd9Sstevel@tonic-gate break; 41307c478bd9Sstevel@tonic-gate 41317c478bd9Sstevel@tonic-gate } 41327c478bd9Sstevel@tonic-gate 41337c478bd9Sstevel@tonic-gate pp->pp_state = pipe_state; 41347c478bd9Sstevel@tonic-gate 41357c478bd9Sstevel@tonic-gate if (tw && tw->tw_curr_xfer_reqp) { 41367c478bd9Sstevel@tonic-gate curr_xfer_reqp = tw->tw_curr_xfer_reqp; 41377c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp = NULL; 41387c478bd9Sstevel@tonic-gate } else { 41397c478bd9Sstevel@tonic-gate ASSERT(pp->pp_client_periodic_in_reqp != NULL); 41407c478bd9Sstevel@tonic-gate 41417c478bd9Sstevel@tonic-gate curr_xfer_reqp = pp->pp_client_periodic_in_reqp; 41427c478bd9Sstevel@tonic-gate pp->pp_client_periodic_in_reqp = NULL; 41437c478bd9Sstevel@tonic-gate } 41447c478bd9Sstevel@tonic-gate 41457c478bd9Sstevel@tonic-gate ASSERT(curr_xfer_reqp != NULL); 41467c478bd9Sstevel@tonic-gate 41477c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 41487c478bd9Sstevel@tonic-gate 41497c478bd9Sstevel@tonic-gate usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason); 41507c478bd9Sstevel@tonic-gate 41517c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 41527c478bd9Sstevel@tonic-gate } 4153