1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * EHCI Host Controller Driver (EHCI) 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * The EHCI driver is a software driver which interfaces to the Universal 33*7c478bd9Sstevel@tonic-gate * Serial Bus layer (USBA) and the Host Controller (HC). The interface to 34*7c478bd9Sstevel@tonic-gate * the Host Controller is defined by the EHCI Host Controller Interface. 35*7c478bd9Sstevel@tonic-gate * 36*7c478bd9Sstevel@tonic-gate * This module contains the main EHCI driver code which handles all USB 37*7c478bd9Sstevel@tonic-gate * transfers, bandwidth allocations and other general functionalities. 38*7c478bd9Sstevel@tonic-gate */ 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_isoch.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h> 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate /* Pointer to the state structure */ 45*7c478bd9Sstevel@tonic-gate extern void *ehci_statep; 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate extern void ehci_handle_endpoint_reclaimation(ehci_state_t *); 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate extern uint_t ehci_vt62x2_workaround; 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate /* Adjustable variables for the size of the pools */ 52*7c478bd9Sstevel@tonic-gate int ehci_qh_pool_size = EHCI_QH_POOL_SIZE; 53*7c478bd9Sstevel@tonic-gate int ehci_qtd_pool_size = EHCI_QTD_POOL_SIZE; 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate /* 56*7c478bd9Sstevel@tonic-gate * Initialize the values which the order of 32ms intr qh are executed 57*7c478bd9Sstevel@tonic-gate * by the host controller in the lattice tree. 58*7c478bd9Sstevel@tonic-gate */ 59*7c478bd9Sstevel@tonic-gate static uchar_t ehci_index[EHCI_NUM_INTR_QH_LISTS] = 60*7c478bd9Sstevel@tonic-gate {0x00, 0x10, 0x08, 0x18, 61*7c478bd9Sstevel@tonic-gate 0x04, 0x14, 0x0c, 0x1c, 62*7c478bd9Sstevel@tonic-gate 0x02, 0x12, 0x0a, 0x1a, 63*7c478bd9Sstevel@tonic-gate 0x06, 0x16, 0x0e, 0x1e, 64*7c478bd9Sstevel@tonic-gate 0x01, 0x11, 0x09, 0x19, 65*7c478bd9Sstevel@tonic-gate 0x05, 0x15, 0x0d, 0x1d, 66*7c478bd9Sstevel@tonic-gate 0x03, 0x13, 0x0b, 0x1b, 67*7c478bd9Sstevel@tonic-gate 0x07, 0x17, 0x0f, 0x1f}; 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate /* 70*7c478bd9Sstevel@tonic-gate * Initialize the values which are used to calculate start split mask 71*7c478bd9Sstevel@tonic-gate * for the low/full/high speed interrupt and isochronous endpoints. 72*7c478bd9Sstevel@tonic-gate */ 73*7c478bd9Sstevel@tonic-gate static uint_t ehci_start_split_mask[15] = { 74*7c478bd9Sstevel@tonic-gate /* 75*7c478bd9Sstevel@tonic-gate * For high/full/low speed usb devices. For high speed 76*7c478bd9Sstevel@tonic-gate * device with polling interval greater than or equal 77*7c478bd9Sstevel@tonic-gate * to 8us (125us). 78*7c478bd9Sstevel@tonic-gate */ 79*7c478bd9Sstevel@tonic-gate 0x01, /* 00000001 */ 80*7c478bd9Sstevel@tonic-gate 0x02, /* 00000010 */ 81*7c478bd9Sstevel@tonic-gate 0x04, /* 00000100 */ 82*7c478bd9Sstevel@tonic-gate 0x08, /* 00001000 */ 83*7c478bd9Sstevel@tonic-gate 0x10, /* 00010000 */ 84*7c478bd9Sstevel@tonic-gate 0x20, /* 00100000 */ 85*7c478bd9Sstevel@tonic-gate 0x40, /* 01000000 */ 86*7c478bd9Sstevel@tonic-gate 0x80, /* 10000000 */ 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate /* Only for high speed devices with polling interval 4us */ 89*7c478bd9Sstevel@tonic-gate 0x11, /* 00010001 */ 90*7c478bd9Sstevel@tonic-gate 0x22, /* 00100010 */ 91*7c478bd9Sstevel@tonic-gate 0x44, /* 01000100 */ 92*7c478bd9Sstevel@tonic-gate 0x88, /* 10001000 */ 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate /* Only for high speed devices with polling interval 2us */ 95*7c478bd9Sstevel@tonic-gate 0x55, /* 01010101 */ 96*7c478bd9Sstevel@tonic-gate 0xaa, /* 10101010 */ 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate /* Only for high speed devices with polling interval 1us */ 99*7c478bd9Sstevel@tonic-gate 0xff /* 11111111 */ 100*7c478bd9Sstevel@tonic-gate }; 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate /* 103*7c478bd9Sstevel@tonic-gate * Initialize the values which are used to calculate complete split mask 104*7c478bd9Sstevel@tonic-gate * for the low/full speed interrupt and isochronous endpoints. 105*7c478bd9Sstevel@tonic-gate */ 106*7c478bd9Sstevel@tonic-gate static uint_t ehci_intr_complete_split_mask[7] = { 107*7c478bd9Sstevel@tonic-gate /* Only full/low speed devices */ 108*7c478bd9Sstevel@tonic-gate 0x1c, /* 00011100 */ 109*7c478bd9Sstevel@tonic-gate 0x38, /* 00111000 */ 110*7c478bd9Sstevel@tonic-gate 0x70, /* 01110000 */ 111*7c478bd9Sstevel@tonic-gate 0xe0, /* 11100000 */ 112*7c478bd9Sstevel@tonic-gate 0x00, /* Need FSTN feature */ 113*7c478bd9Sstevel@tonic-gate 0x00, /* Need FSTN feature */ 114*7c478bd9Sstevel@tonic-gate 0x00 /* Need FSTN feature */ 115*7c478bd9Sstevel@tonic-gate }; 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate /* 119*7c478bd9Sstevel@tonic-gate * EHCI Internal Function Prototypes 120*7c478bd9Sstevel@tonic-gate */ 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) initialization functions */ 123*7c478bd9Sstevel@tonic-gate void ehci_set_dma_attributes(ehci_state_t *ehcip); 124*7c478bd9Sstevel@tonic-gate int ehci_allocate_pools(ehci_state_t *ehcip); 125*7c478bd9Sstevel@tonic-gate void ehci_decode_ddi_dma_addr_bind_handle_result( 126*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 127*7c478bd9Sstevel@tonic-gate int result); 128*7c478bd9Sstevel@tonic-gate int ehci_map_regs(ehci_state_t *ehcip); 129*7c478bd9Sstevel@tonic-gate int ehci_register_intrs_and_init_mutex( 130*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 131*7c478bd9Sstevel@tonic-gate int ehci_init_ctlr(ehci_state_t *ehcip); 132*7c478bd9Sstevel@tonic-gate static int ehci_take_control(ehci_state_t *ehcip); 133*7c478bd9Sstevel@tonic-gate static int ehci_init_periodic_frame_lst_table( 134*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 135*7c478bd9Sstevel@tonic-gate static void ehci_build_interrupt_lattice( 136*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 137*7c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *ehci_alloc_hcdi_ops(ehci_state_t *ehcip); 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) deinitialization functions */ 140*7c478bd9Sstevel@tonic-gate int ehci_cleanup(ehci_state_t *ehcip); 141*7c478bd9Sstevel@tonic-gate int ehci_cpr_suspend(ehci_state_t *ehcip); 142*7c478bd9Sstevel@tonic-gate int ehci_cpr_resume(ehci_state_t *ehcip); 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate /* Bandwidth Allocation functions */ 145*7c478bd9Sstevel@tonic-gate int ehci_allocate_bandwidth(ehci_state_t *ehcip, 146*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 147*7c478bd9Sstevel@tonic-gate uint_t *pnode, 148*7c478bd9Sstevel@tonic-gate uchar_t *smask, 149*7c478bd9Sstevel@tonic-gate uchar_t *cmask); 150*7c478bd9Sstevel@tonic-gate static int ehci_allocate_high_speed_bandwidth( 151*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 152*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 153*7c478bd9Sstevel@tonic-gate uint_t *hnode, 154*7c478bd9Sstevel@tonic-gate uchar_t *smask, 155*7c478bd9Sstevel@tonic-gate uchar_t *cmask); 156*7c478bd9Sstevel@tonic-gate static int ehci_allocate_classic_tt_bandwidth( 157*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 158*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 159*7c478bd9Sstevel@tonic-gate uint_t pnode); 160*7c478bd9Sstevel@tonic-gate void ehci_deallocate_bandwidth(ehci_state_t *ehcip, 161*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 162*7c478bd9Sstevel@tonic-gate uint_t pnode, 163*7c478bd9Sstevel@tonic-gate uchar_t smask, 164*7c478bd9Sstevel@tonic-gate uchar_t cmask); 165*7c478bd9Sstevel@tonic-gate static void ehci_deallocate_high_speed_bandwidth( 166*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 167*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 168*7c478bd9Sstevel@tonic-gate uint_t hnode, 169*7c478bd9Sstevel@tonic-gate uchar_t smask, 170*7c478bd9Sstevel@tonic-gate uchar_t cmask); 171*7c478bd9Sstevel@tonic-gate static void ehci_deallocate_classic_tt_bandwidth( 172*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 173*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 174*7c478bd9Sstevel@tonic-gate uint_t pnode); 175*7c478bd9Sstevel@tonic-gate static int ehci_compute_high_speed_bandwidth( 176*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 177*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 178*7c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 179*7c478bd9Sstevel@tonic-gate uint_t *sbandwidth, 180*7c478bd9Sstevel@tonic-gate uint_t *cbandwidth); 181*7c478bd9Sstevel@tonic-gate static int ehci_compute_classic_bandwidth( 182*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 183*7c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 184*7c478bd9Sstevel@tonic-gate uint_t *bandwidth); 185*7c478bd9Sstevel@tonic-gate int ehci_adjust_polling_interval( 186*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 187*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 188*7c478bd9Sstevel@tonic-gate usb_port_status_t port_status); 189*7c478bd9Sstevel@tonic-gate static int ehci_adjust_high_speed_polling_interval( 190*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 191*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint); 192*7c478bd9Sstevel@tonic-gate static uint_t ehci_lattice_height(uint_t interval); 193*7c478bd9Sstevel@tonic-gate static uint_t ehci_lattice_parent(uint_t node); 194*7c478bd9Sstevel@tonic-gate static uint_t ehci_find_periodic_node( 195*7c478bd9Sstevel@tonic-gate uint_t leaf, 196*7c478bd9Sstevel@tonic-gate int interval); 197*7c478bd9Sstevel@tonic-gate static uint_t ehci_leftmost_leaf(uint_t node, 198*7c478bd9Sstevel@tonic-gate uint_t height); 199*7c478bd9Sstevel@tonic-gate static uint_t ehci_pow_2(uint_t x); 200*7c478bd9Sstevel@tonic-gate static uint_t ehci_log_2(uint_t x); 201*7c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_hs_mask( 202*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 203*7c478bd9Sstevel@tonic-gate uchar_t *smask, 204*7c478bd9Sstevel@tonic-gate uint_t *pnode, 205*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 206*7c478bd9Sstevel@tonic-gate uint_t bandwidth, 207*7c478bd9Sstevel@tonic-gate int interval); 208*7c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_ls_intr_mask( 209*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 210*7c478bd9Sstevel@tonic-gate uchar_t *smask, 211*7c478bd9Sstevel@tonic-gate uchar_t *cmask, 212*7c478bd9Sstevel@tonic-gate uint_t *pnode, 213*7c478bd9Sstevel@tonic-gate uint_t sbandwidth, 214*7c478bd9Sstevel@tonic-gate uint_t cbandwidth, 215*7c478bd9Sstevel@tonic-gate int interval); 216*7c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_sitd_in_mask( 217*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 218*7c478bd9Sstevel@tonic-gate uchar_t *smask, 219*7c478bd9Sstevel@tonic-gate uchar_t *cmask, 220*7c478bd9Sstevel@tonic-gate uint_t *pnode, 221*7c478bd9Sstevel@tonic-gate uint_t sbandwidth, 222*7c478bd9Sstevel@tonic-gate uint_t cbandwidth, 223*7c478bd9Sstevel@tonic-gate int interval); 224*7c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_sitd_out_mask( 225*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 226*7c478bd9Sstevel@tonic-gate uchar_t *smask, 227*7c478bd9Sstevel@tonic-gate uint_t *pnode, 228*7c478bd9Sstevel@tonic-gate uint_t sbandwidth, 229*7c478bd9Sstevel@tonic-gate int interval); 230*7c478bd9Sstevel@tonic-gate static uint_t ehci_calculate_bw_availability_mask( 231*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 232*7c478bd9Sstevel@tonic-gate uint_t bandwidth, 233*7c478bd9Sstevel@tonic-gate int leaf, 234*7c478bd9Sstevel@tonic-gate int leaf_count, 235*7c478bd9Sstevel@tonic-gate uchar_t *bw_mask); 236*7c478bd9Sstevel@tonic-gate static void ehci_update_bw_availability( 237*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 238*7c478bd9Sstevel@tonic-gate int bandwidth, 239*7c478bd9Sstevel@tonic-gate int leftmost_leaf, 240*7c478bd9Sstevel@tonic-gate int leaf_count, 241*7c478bd9Sstevel@tonic-gate uchar_t mask); 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate /* Miscellaneous functions */ 244*7c478bd9Sstevel@tonic-gate ehci_state_t *ehci_obtain_state( 245*7c478bd9Sstevel@tonic-gate dev_info_t *dip); 246*7c478bd9Sstevel@tonic-gate int ehci_state_is_operational( 247*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 248*7c478bd9Sstevel@tonic-gate int ehci_do_soft_reset( 249*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 250*7c478bd9Sstevel@tonic-gate usb_req_attrs_t ehci_get_xfer_attrs(ehci_state_t *ehcip, 251*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 252*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 253*7c478bd9Sstevel@tonic-gate usb_frame_number_t ehci_get_current_frame_number( 254*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 255*7c478bd9Sstevel@tonic-gate static void ehci_cpr_cleanup( 256*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 257*7c478bd9Sstevel@tonic-gate int ehci_wait_for_sof( 258*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 259*7c478bd9Sstevel@tonic-gate void ehci_toggle_scheduler( 260*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 261*7c478bd9Sstevel@tonic-gate void ehci_print_caps(ehci_state_t *ehcip); 262*7c478bd9Sstevel@tonic-gate void ehci_print_regs(ehci_state_t *ehcip); 263*7c478bd9Sstevel@tonic-gate void ehci_print_qh(ehci_state_t *ehcip, 264*7c478bd9Sstevel@tonic-gate ehci_qh_t *qh); 265*7c478bd9Sstevel@tonic-gate void ehci_print_qtd(ehci_state_t *ehcip, 266*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd); 267*7c478bd9Sstevel@tonic-gate void ehci_create_stats(ehci_state_t *ehcip); 268*7c478bd9Sstevel@tonic-gate void ehci_destroy_stats(ehci_state_t *ehcip); 269*7c478bd9Sstevel@tonic-gate void ehci_do_intrs_stats(ehci_state_t *ehcip, 270*7c478bd9Sstevel@tonic-gate int val); 271*7c478bd9Sstevel@tonic-gate void ehci_do_byte_stats(ehci_state_t *ehcip, 272*7c478bd9Sstevel@tonic-gate size_t len, 273*7c478bd9Sstevel@tonic-gate uint8_t attr, 274*7c478bd9Sstevel@tonic-gate uint8_t addr); 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate /* 277*7c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) initialization functions 278*7c478bd9Sstevel@tonic-gate */ 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate /* 281*7c478bd9Sstevel@tonic-gate * ehci_set_dma_attributes: 282*7c478bd9Sstevel@tonic-gate * 283*7c478bd9Sstevel@tonic-gate * Set the limits in the DMA attributes structure. Most of the values used 284*7c478bd9Sstevel@tonic-gate * in the DMA limit structures are the default values as specified by the 285*7c478bd9Sstevel@tonic-gate * Writing PCI device drivers document. 286*7c478bd9Sstevel@tonic-gate */ 287*7c478bd9Sstevel@tonic-gate void 288*7c478bd9Sstevel@tonic-gate ehci_set_dma_attributes(ehci_state_t *ehcip) 289*7c478bd9Sstevel@tonic-gate { 290*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 291*7c478bd9Sstevel@tonic-gate "ehci_set_dma_attributes:"); 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate /* Initialize the DMA attributes */ 294*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_version = DMA_ATTR_V0; 295*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_addr_lo = 0x00000000ull; 296*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_addr_hi = 0xfffffffeull; 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate /* 32 bit addressing */ 299*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_count_max = EHCI_DMA_ATTR_COUNT_MAX; 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate /* Byte alignment */ 302*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate /* 305*7c478bd9Sstevel@tonic-gate * Since PCI specification is byte alignment, the 306*7c478bd9Sstevel@tonic-gate * burst size field should be set to 1 for PCI devices. 307*7c478bd9Sstevel@tonic-gate */ 308*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_burstsizes = 0x1; 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_minxfer = 0x1; 311*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_maxxfer = EHCI_DMA_ATTR_MAX_XFER; 312*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_seg = 0xffffffffull; 313*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_sgllen = 1; 314*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_granular = EHCI_DMA_ATTR_GRANULAR; 315*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_flags = 0; 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate 319*7c478bd9Sstevel@tonic-gate /* 320*7c478bd9Sstevel@tonic-gate * ehci_allocate_pools: 321*7c478bd9Sstevel@tonic-gate * 322*7c478bd9Sstevel@tonic-gate * Allocate the system memory for the Endpoint Descriptor (QH) and for the 323*7c478bd9Sstevel@tonic-gate * Transfer Descriptor (QTD) pools. Both QH and QTD structures must be aligned 324*7c478bd9Sstevel@tonic-gate * to a 16 byte boundary. 325*7c478bd9Sstevel@tonic-gate */ 326*7c478bd9Sstevel@tonic-gate int 327*7c478bd9Sstevel@tonic-gate ehci_allocate_pools(ehci_state_t *ehcip) 328*7c478bd9Sstevel@tonic-gate { 329*7c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 330*7c478bd9Sstevel@tonic-gate size_t real_length; 331*7c478bd9Sstevel@tonic-gate int result; 332*7c478bd9Sstevel@tonic-gate uint_t ccount; 333*7c478bd9Sstevel@tonic-gate int i; 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 336*7c478bd9Sstevel@tonic-gate "ehci_allocate_pools:"); 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 339*7c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 340*7c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 341*7c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate /* Byte alignment */ 344*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_TD_QH_ALIGNMENT; 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate /* Allocate the QTD pool DMA handle */ 347*7c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr, 348*7c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 0, 349*7c478bd9Sstevel@tonic-gate &ehcip->ehci_qtd_pool_dma_handle) != DDI_SUCCESS) { 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate goto failure; 352*7c478bd9Sstevel@tonic-gate } 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate /* Allocate the memory for the QTD pool */ 355*7c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_qtd_pool_dma_handle, 356*7c478bd9Sstevel@tonic-gate ehci_qtd_pool_size * sizeof (ehci_qtd_t), 357*7c478bd9Sstevel@tonic-gate &dev_attr, 358*7c478bd9Sstevel@tonic-gate DDI_DMA_CONSISTENT, 359*7c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 360*7c478bd9Sstevel@tonic-gate 0, 361*7c478bd9Sstevel@tonic-gate (caddr_t *)&ehcip->ehci_qtd_pool_addr, 362*7c478bd9Sstevel@tonic-gate &real_length, 363*7c478bd9Sstevel@tonic-gate &ehcip->ehci_qtd_pool_mem_handle)) { 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate goto failure; 366*7c478bd9Sstevel@tonic-gate } 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate /* Map the QTD pool into the I/O address space */ 369*7c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle( 370*7c478bd9Sstevel@tonic-gate ehcip->ehci_qtd_pool_dma_handle, 371*7c478bd9Sstevel@tonic-gate NULL, 372*7c478bd9Sstevel@tonic-gate (caddr_t)ehcip->ehci_qtd_pool_addr, 373*7c478bd9Sstevel@tonic-gate real_length, 374*7c478bd9Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 375*7c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 376*7c478bd9Sstevel@tonic-gate NULL, 377*7c478bd9Sstevel@tonic-gate &ehcip->ehci_qtd_pool_cookie, 378*7c478bd9Sstevel@tonic-gate &ccount); 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate bzero((void *)ehcip->ehci_qtd_pool_addr, 381*7c478bd9Sstevel@tonic-gate ehci_qtd_pool_size * sizeof (ehci_qtd_t)); 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate /* Process the result */ 384*7c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 385*7c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 386*7c478bd9Sstevel@tonic-gate if (ccount != 1) { 387*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 388*7c478bd9Sstevel@tonic-gate "ehci_allocate_pools: More than 1 cookie"); 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate goto failure; 391*7c478bd9Sstevel@tonic-gate } 392*7c478bd9Sstevel@tonic-gate } else { 393*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 394*7c478bd9Sstevel@tonic-gate "ehci_allocate_pools: Result = %d", result); 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result); 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate goto failure; 399*7c478bd9Sstevel@tonic-gate } 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate /* 402*7c478bd9Sstevel@tonic-gate * DMA addresses for QTD pools are bound 403*7c478bd9Sstevel@tonic-gate */ 404*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_QTD_POOL_BOUND; 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate /* Initialize the QTD pool */ 407*7c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_qtd_pool_size; i ++) { 408*7c478bd9Sstevel@tonic-gate Set_QTD(ehcip->ehci_qtd_pool_addr[i]. 409*7c478bd9Sstevel@tonic-gate qtd_state, EHCI_QTD_FREE); 410*7c478bd9Sstevel@tonic-gate } 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate /* Allocate the QTD pool DMA handle */ 413*7c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip, 414*7c478bd9Sstevel@tonic-gate &ehcip->ehci_dma_attr, 415*7c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 416*7c478bd9Sstevel@tonic-gate 0, 417*7c478bd9Sstevel@tonic-gate &ehcip->ehci_qh_pool_dma_handle) != DDI_SUCCESS) { 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate goto failure; 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate /* Allocate the memory for the QH pool */ 423*7c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_qh_pool_dma_handle, 424*7c478bd9Sstevel@tonic-gate ehci_qh_pool_size * sizeof (ehci_qh_t), 425*7c478bd9Sstevel@tonic-gate &dev_attr, 426*7c478bd9Sstevel@tonic-gate DDI_DMA_CONSISTENT, 427*7c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 428*7c478bd9Sstevel@tonic-gate 0, 429*7c478bd9Sstevel@tonic-gate (caddr_t *)&ehcip->ehci_qh_pool_addr, 430*7c478bd9Sstevel@tonic-gate &real_length, 431*7c478bd9Sstevel@tonic-gate &ehcip->ehci_qh_pool_mem_handle) != DDI_SUCCESS) { 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate goto failure; 434*7c478bd9Sstevel@tonic-gate } 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ehcip->ehci_qh_pool_dma_handle, 437*7c478bd9Sstevel@tonic-gate NULL, 438*7c478bd9Sstevel@tonic-gate (caddr_t)ehcip->ehci_qh_pool_addr, 439*7c478bd9Sstevel@tonic-gate real_length, 440*7c478bd9Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 441*7c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 442*7c478bd9Sstevel@tonic-gate NULL, 443*7c478bd9Sstevel@tonic-gate &ehcip->ehci_qh_pool_cookie, 444*7c478bd9Sstevel@tonic-gate &ccount); 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate bzero((void *)ehcip->ehci_qh_pool_addr, 447*7c478bd9Sstevel@tonic-gate ehci_qh_pool_size * sizeof (ehci_qh_t)); 448*7c478bd9Sstevel@tonic-gate 449*7c478bd9Sstevel@tonic-gate /* Process the result */ 450*7c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 451*7c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 452*7c478bd9Sstevel@tonic-gate if (ccount != 1) { 453*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 454*7c478bd9Sstevel@tonic-gate "ehci_allocate_pools: More than 1 cookie"); 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate goto failure; 457*7c478bd9Sstevel@tonic-gate } 458*7c478bd9Sstevel@tonic-gate } else { 459*7c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result); 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate goto failure; 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate /* 465*7c478bd9Sstevel@tonic-gate * DMA addresses for QH pools are bound 466*7c478bd9Sstevel@tonic-gate */ 467*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_QH_POOL_BOUND; 468*7c478bd9Sstevel@tonic-gate 469*7c478bd9Sstevel@tonic-gate /* Initialize the QH pool */ 470*7c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_qh_pool_size; i ++) { 471*7c478bd9Sstevel@tonic-gate Set_QH(ehcip->ehci_qh_pool_addr[i].qh_state, EHCI_QH_FREE); 472*7c478bd9Sstevel@tonic-gate } 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate /* Byte alignment */ 475*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 476*7c478bd9Sstevel@tonic-gate 477*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate failure: 480*7c478bd9Sstevel@tonic-gate /* Byte alignment */ 481*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate 487*7c478bd9Sstevel@tonic-gate /* 488*7c478bd9Sstevel@tonic-gate * ehci_decode_ddi_dma_addr_bind_handle_result: 489*7c478bd9Sstevel@tonic-gate * 490*7c478bd9Sstevel@tonic-gate * Process the return values of ddi_dma_addr_bind_handle() 491*7c478bd9Sstevel@tonic-gate */ 492*7c478bd9Sstevel@tonic-gate void 493*7c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result( 494*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 495*7c478bd9Sstevel@tonic-gate int result) 496*7c478bd9Sstevel@tonic-gate { 497*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 498*7c478bd9Sstevel@tonic-gate "ehci_decode_ddi_dma_addr_bind_handle_result:"); 499*7c478bd9Sstevel@tonic-gate 500*7c478bd9Sstevel@tonic-gate switch (result) { 501*7c478bd9Sstevel@tonic-gate case DDI_DMA_PARTIAL_MAP: 502*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 503*7c478bd9Sstevel@tonic-gate "Partial transfers not allowed"); 504*7c478bd9Sstevel@tonic-gate break; 505*7c478bd9Sstevel@tonic-gate case DDI_DMA_INUSE: 506*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 507*7c478bd9Sstevel@tonic-gate "Handle is in use"); 508*7c478bd9Sstevel@tonic-gate break; 509*7c478bd9Sstevel@tonic-gate case DDI_DMA_NORESOURCES: 510*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 511*7c478bd9Sstevel@tonic-gate "No resources"); 512*7c478bd9Sstevel@tonic-gate break; 513*7c478bd9Sstevel@tonic-gate case DDI_DMA_NOMAPPING: 514*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 515*7c478bd9Sstevel@tonic-gate "No mapping"); 516*7c478bd9Sstevel@tonic-gate break; 517*7c478bd9Sstevel@tonic-gate case DDI_DMA_TOOBIG: 518*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 519*7c478bd9Sstevel@tonic-gate "Object is too big"); 520*7c478bd9Sstevel@tonic-gate break; 521*7c478bd9Sstevel@tonic-gate default: 522*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 523*7c478bd9Sstevel@tonic-gate "Unknown dma error"); 524*7c478bd9Sstevel@tonic-gate } 525*7c478bd9Sstevel@tonic-gate } 526*7c478bd9Sstevel@tonic-gate 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate /* 529*7c478bd9Sstevel@tonic-gate * ehci_map_regs: 530*7c478bd9Sstevel@tonic-gate * 531*7c478bd9Sstevel@tonic-gate * The Host Controller (HC) contains a set of on-chip operational registers 532*7c478bd9Sstevel@tonic-gate * and which should be mapped into a non-cacheable portion of the system 533*7c478bd9Sstevel@tonic-gate * addressable space. 534*7c478bd9Sstevel@tonic-gate */ 535*7c478bd9Sstevel@tonic-gate int 536*7c478bd9Sstevel@tonic-gate ehci_map_regs(ehci_state_t *ehcip) 537*7c478bd9Sstevel@tonic-gate { 538*7c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 539*7c478bd9Sstevel@tonic-gate uint16_t cmd_reg; 540*7c478bd9Sstevel@tonic-gate uint_t length; 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_map_regs:"); 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate /* Check to make sure we have memory access */ 545*7c478bd9Sstevel@tonic-gate if (pci_config_setup(ehcip->ehci_dip, 546*7c478bd9Sstevel@tonic-gate &ehcip->ehci_config_handle) != DDI_SUCCESS) { 547*7c478bd9Sstevel@tonic-gate 548*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 549*7c478bd9Sstevel@tonic-gate "ehci_map_regs: Config error"); 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 552*7c478bd9Sstevel@tonic-gate } 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate /* Make sure Memory Access Enable is set */ 555*7c478bd9Sstevel@tonic-gate cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM); 556*7c478bd9Sstevel@tonic-gate 557*7c478bd9Sstevel@tonic-gate if (!(cmd_reg & PCI_COMM_MAE)) { 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 560*7c478bd9Sstevel@tonic-gate "ehci_map_regs: Memory base address access disabled"); 561*7c478bd9Sstevel@tonic-gate 562*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 563*7c478bd9Sstevel@tonic-gate } 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 566*7c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 567*7c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 568*7c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 569*7c478bd9Sstevel@tonic-gate 570*7c478bd9Sstevel@tonic-gate /* Map in EHCI Capability registers */ 571*7c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(ehcip->ehci_dip, 1, 572*7c478bd9Sstevel@tonic-gate (caddr_t *)&ehcip->ehci_capsp, 0, 573*7c478bd9Sstevel@tonic-gate sizeof (ehci_caps_t), &attr, 574*7c478bd9Sstevel@tonic-gate &ehcip->ehci_caps_handle) != DDI_SUCCESS) { 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 577*7c478bd9Sstevel@tonic-gate "ehci_map_regs: Map setup error"); 578*7c478bd9Sstevel@tonic-gate 579*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 580*7c478bd9Sstevel@tonic-gate } 581*7c478bd9Sstevel@tonic-gate 582*7c478bd9Sstevel@tonic-gate length = ddi_get8(ehcip->ehci_caps_handle, 583*7c478bd9Sstevel@tonic-gate (uint8_t *)&ehcip->ehci_capsp->ehci_caps_length); 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate /* Free the original mapping */ 586*7c478bd9Sstevel@tonic-gate ddi_regs_map_free(&ehcip->ehci_caps_handle); 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate /* Re-map in EHCI Capability and Operational registers */ 589*7c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(ehcip->ehci_dip, 1, 590*7c478bd9Sstevel@tonic-gate (caddr_t *)&ehcip->ehci_capsp, 0, 591*7c478bd9Sstevel@tonic-gate length + sizeof (ehci_regs_t), &attr, 592*7c478bd9Sstevel@tonic-gate &ehcip->ehci_caps_handle) != DDI_SUCCESS) { 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 595*7c478bd9Sstevel@tonic-gate "ehci_map_regs: Map setup error"); 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 598*7c478bd9Sstevel@tonic-gate } 599*7c478bd9Sstevel@tonic-gate 600*7c478bd9Sstevel@tonic-gate /* Get the pointer to EHCI Operational Register */ 601*7c478bd9Sstevel@tonic-gate ehcip->ehci_regsp = (ehci_regs_t *) 602*7c478bd9Sstevel@tonic-gate ((uintptr_t)ehcip->ehci_capsp + length); 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 605*7c478bd9Sstevel@tonic-gate "ehci_map_regs: Capsp 0x%p Regsp 0x%p\n", 606*7c478bd9Sstevel@tonic-gate ehcip->ehci_capsp, ehcip->ehci_regsp); 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 609*7c478bd9Sstevel@tonic-gate } 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate /* 613*7c478bd9Sstevel@tonic-gate * ehci_register_intrs_and_init_mutex: 614*7c478bd9Sstevel@tonic-gate * 615*7c478bd9Sstevel@tonic-gate * Register interrupts and initialize each mutex and condition variables 616*7c478bd9Sstevel@tonic-gate */ 617*7c478bd9Sstevel@tonic-gate int 618*7c478bd9Sstevel@tonic-gate ehci_register_intrs_and_init_mutex(ehci_state_t *ehcip) 619*7c478bd9Sstevel@tonic-gate { 620*7c478bd9Sstevel@tonic-gate int type, count = 0, actual, ret; 621*7c478bd9Sstevel@tonic-gate 622*7c478bd9Sstevel@tonic-gate #if defined(__x86) 623*7c478bd9Sstevel@tonic-gate uint8_t iline; 624*7c478bd9Sstevel@tonic-gate #endif 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 627*7c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex:"); 628*7c478bd9Sstevel@tonic-gate 629*7c478bd9Sstevel@tonic-gate #if defined(__x86) 630*7c478bd9Sstevel@tonic-gate /* 631*7c478bd9Sstevel@tonic-gate * Make sure that the interrupt pin is connected to the 632*7c478bd9Sstevel@tonic-gate * interrupt controller on x86. Interrupt line 255 means 633*7c478bd9Sstevel@tonic-gate * "unknown" or "not connected" (PCI spec 6.2.4, footnote 43). 634*7c478bd9Sstevel@tonic-gate */ 635*7c478bd9Sstevel@tonic-gate iline = pci_config_get8(ehcip->ehci_config_handle, 636*7c478bd9Sstevel@tonic-gate PCI_CONF_ILINE); 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate if (iline == 255) { 639*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 640*7c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 641*7c478bd9Sstevel@tonic-gate "interrupt line value out of range (%d)", 642*7c478bd9Sstevel@tonic-gate iline); 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 645*7c478bd9Sstevel@tonic-gate } 646*7c478bd9Sstevel@tonic-gate #endif /* __x86 */ 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate ret = ddi_intr_get_supported_types(ehcip->ehci_dip, &type); 649*7c478bd9Sstevel@tonic-gate 650*7c478bd9Sstevel@tonic-gate if ((ret != DDI_SUCCESS) || (!(type & DDI_INTR_TYPE_FIXED))) { 651*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 652*7c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 653*7c478bd9Sstevel@tonic-gate "Fixed type interrupt is not supported"); 654*7c478bd9Sstevel@tonic-gate 655*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 656*7c478bd9Sstevel@tonic-gate } 657*7c478bd9Sstevel@tonic-gate 658*7c478bd9Sstevel@tonic-gate ret = ddi_intr_get_nintrs(ehcip->ehci_dip, DDI_INTR_TYPE_FIXED, &count); 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate /* 661*7c478bd9Sstevel@tonic-gate * Fixed interrupts can only have one interrupt. Check to make 662*7c478bd9Sstevel@tonic-gate * sure that number of supported interrupts and number of 663*7c478bd9Sstevel@tonic-gate * available interrupts are both equal to 1. 664*7c478bd9Sstevel@tonic-gate */ 665*7c478bd9Sstevel@tonic-gate if ((ret != DDI_SUCCESS) || (count != 1)) { 666*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 667*7c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 668*7c478bd9Sstevel@tonic-gate "no fixed interrupts"); 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 671*7c478bd9Sstevel@tonic-gate } 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate ehcip->ehci_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP); 674*7c478bd9Sstevel@tonic-gate ret = ddi_intr_alloc(ehcip->ehci_dip, ehcip->ehci_htable, 675*7c478bd9Sstevel@tonic-gate DDI_INTR_TYPE_FIXED, 0, count, &actual, 0); 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate if ((ret != DDI_SUCCESS) || (actual != 1)) { 678*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 679*7c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 680*7c478bd9Sstevel@tonic-gate "ddi_intr_alloc() failed 0x%x", ret); 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t)); 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 685*7c478bd9Sstevel@tonic-gate } 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate /* Sanity check that count and avail are the same. */ 688*7c478bd9Sstevel@tonic-gate ASSERT(count == actual); 689*7c478bd9Sstevel@tonic-gate 690*7c478bd9Sstevel@tonic-gate if (ddi_intr_get_pri(ehcip->ehci_htable[0], &ehcip->ehci_intr_pri)) { 691*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 692*7c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 693*7c478bd9Sstevel@tonic-gate "ddi_intr_get_pri() failed"); 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate (void) ddi_intr_free(ehcip->ehci_htable[0]); 696*7c478bd9Sstevel@tonic-gate kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t)); 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 699*7c478bd9Sstevel@tonic-gate } 700*7c478bd9Sstevel@tonic-gate 701*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 702*7c478bd9Sstevel@tonic-gate "Supported Interrupt priority = 0x%x", ehcip->ehci_intr_pri); 703*7c478bd9Sstevel@tonic-gate 704*7c478bd9Sstevel@tonic-gate /* Test for high level mutex */ 705*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_intr_pri >= ddi_intr_get_hilevel_pri()) { 706*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 707*7c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 708*7c478bd9Sstevel@tonic-gate "Hi level interrupt not supported"); 709*7c478bd9Sstevel@tonic-gate 710*7c478bd9Sstevel@tonic-gate (void) ddi_intr_free(ehcip->ehci_htable[0]); 711*7c478bd9Sstevel@tonic-gate kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t)); 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 714*7c478bd9Sstevel@tonic-gate } 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate /* Initialize the mutex */ 717*7c478bd9Sstevel@tonic-gate mutex_init(&ehcip->ehci_int_mutex, NULL, MUTEX_DRIVER, 718*7c478bd9Sstevel@tonic-gate (void *)(uintptr_t)ehcip->ehci_intr_pri); 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate if (ddi_intr_add_handler(ehcip->ehci_htable[0], 721*7c478bd9Sstevel@tonic-gate (ddi_intr_handler_t *)ehci_intr, (caddr_t)ehcip, NULL) != 722*7c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 723*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 724*7c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 725*7c478bd9Sstevel@tonic-gate "ddi_intr_add_handler() failed"); 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate mutex_destroy(&ehcip->ehci_int_mutex); 728*7c478bd9Sstevel@tonic-gate (void) ddi_intr_free(ehcip->ehci_htable[0]); 729*7c478bd9Sstevel@tonic-gate kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t)); 730*7c478bd9Sstevel@tonic-gate 731*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 732*7c478bd9Sstevel@tonic-gate } 733*7c478bd9Sstevel@tonic-gate 734*7c478bd9Sstevel@tonic-gate if (ddi_intr_enable(ehcip->ehci_htable[0]) != DDI_SUCCESS) { 735*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 736*7c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 737*7c478bd9Sstevel@tonic-gate "ddi_intr_enable() failed"); 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate (void) ddi_intr_remove_handler(ehcip->ehci_htable[0]); 740*7c478bd9Sstevel@tonic-gate mutex_destroy(&ehcip->ehci_int_mutex); 741*7c478bd9Sstevel@tonic-gate (void) ddi_intr_free(ehcip->ehci_htable[0]); 742*7c478bd9Sstevel@tonic-gate kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t)); 743*7c478bd9Sstevel@tonic-gate 744*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 745*7c478bd9Sstevel@tonic-gate } 746*7c478bd9Sstevel@tonic-gate 747*7c478bd9Sstevel@tonic-gate /* Create prototype for advance on async schedule */ 748*7c478bd9Sstevel@tonic-gate cv_init(&ehcip->ehci_async_schedule_advance_cv, 749*7c478bd9Sstevel@tonic-gate NULL, CV_DRIVER, NULL); 750*7c478bd9Sstevel@tonic-gate 751*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 752*7c478bd9Sstevel@tonic-gate } 753*7c478bd9Sstevel@tonic-gate 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate /* 756*7c478bd9Sstevel@tonic-gate * ehci_init_ctlr: 757*7c478bd9Sstevel@tonic-gate * 758*7c478bd9Sstevel@tonic-gate * Initialize the Host Controller (HC). 759*7c478bd9Sstevel@tonic-gate */ 760*7c478bd9Sstevel@tonic-gate int 761*7c478bd9Sstevel@tonic-gate ehci_init_ctlr(ehci_state_t *ehcip) 762*7c478bd9Sstevel@tonic-gate { 763*7c478bd9Sstevel@tonic-gate int revision; 764*7c478bd9Sstevel@tonic-gate uint16_t cmd_reg; 765*7c478bd9Sstevel@tonic-gate clock_t sof_time_wait; 766*7c478bd9Sstevel@tonic-gate int abort_on_BIOS_take_over_failure; 767*7c478bd9Sstevel@tonic-gate 768*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_init_ctlr:"); 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate /* Take control from the BIOS */ 771*7c478bd9Sstevel@tonic-gate if (ehci_take_control(ehcip) != USB_SUCCESS) { 772*7c478bd9Sstevel@tonic-gate 773*7c478bd9Sstevel@tonic-gate /* read .conf file properties */ 774*7c478bd9Sstevel@tonic-gate abort_on_BIOS_take_over_failure = 775*7c478bd9Sstevel@tonic-gate ddi_prop_get_int(DDI_DEV_T_ANY, 776*7c478bd9Sstevel@tonic-gate ehcip->ehci_dip, DDI_PROP_DONTPASS, 777*7c478bd9Sstevel@tonic-gate "abort-on-BIOS-take-over-failure", 0); 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate if (abort_on_BIOS_take_over_failure) { 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 782*7c478bd9Sstevel@tonic-gate "Unable to take control from BIOS."); 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 785*7c478bd9Sstevel@tonic-gate } 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 788*7c478bd9Sstevel@tonic-gate "Unable to take control from BIOS. Failure is ignored."); 789*7c478bd9Sstevel@tonic-gate } 790*7c478bd9Sstevel@tonic-gate 791*7c478bd9Sstevel@tonic-gate /* set Memory Master Enable */ 792*7c478bd9Sstevel@tonic-gate cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM); 793*7c478bd9Sstevel@tonic-gate cmd_reg |= (PCI_COMM_MAE | PCI_COMM_ME); 794*7c478bd9Sstevel@tonic-gate pci_config_put16(ehcip->ehci_config_handle, PCI_CONF_COMM, cmd_reg); 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate /* Reset the EHCI host controller */ 797*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 798*7c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) | EHCI_CMD_HOST_CTRL_RESET); 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate /* Wait 10ms for reset to complete */ 801*7c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT); 802*7c478bd9Sstevel@tonic-gate 803*7c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED); 804*7c478bd9Sstevel@tonic-gate 805*7c478bd9Sstevel@tonic-gate /* Verify the version number */ 806*7c478bd9Sstevel@tonic-gate revision = Get_16Cap(ehci_version); 807*7c478bd9Sstevel@tonic-gate 808*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 809*7c478bd9Sstevel@tonic-gate "ehci_init_ctlr: Revision 0x%x", revision); 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate /* 812*7c478bd9Sstevel@tonic-gate * EHCI driver supports EHCI host controllers compliant to 813*7c478bd9Sstevel@tonic-gate * 0.95 and higher revisions of EHCI specifications. 814*7c478bd9Sstevel@tonic-gate */ 815*7c478bd9Sstevel@tonic-gate if (revision < EHCI_REVISION_0_95) { 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 818*7c478bd9Sstevel@tonic-gate "Revision 0x%x is not supported", revision); 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 821*7c478bd9Sstevel@tonic-gate } 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_hc_soft_state == EHCI_CTLR_INIT_STATE) { 824*7c478bd9Sstevel@tonic-gate 825*7c478bd9Sstevel@tonic-gate /* Get the ehci chip vendor and device id */ 826*7c478bd9Sstevel@tonic-gate ehcip->ehci_vendor_id = pci_config_get16( 827*7c478bd9Sstevel@tonic-gate ehcip->ehci_config_handle, PCI_CONF_VENID); 828*7c478bd9Sstevel@tonic-gate ehcip->ehci_device_id = pci_config_get16( 829*7c478bd9Sstevel@tonic-gate ehcip->ehci_config_handle, PCI_CONF_DEVID); 830*7c478bd9Sstevel@tonic-gate ehcip->ehci_rev_id = pci_config_get8( 831*7c478bd9Sstevel@tonic-gate ehcip->ehci_config_handle, PCI_CONF_REVID); 832*7c478bd9Sstevel@tonic-gate 833*7c478bd9Sstevel@tonic-gate /* Initialize the Frame list base address area */ 834*7c478bd9Sstevel@tonic-gate if (ehci_init_periodic_frame_lst_table(ehcip) != DDI_SUCCESS) { 835*7c478bd9Sstevel@tonic-gate 836*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 837*7c478bd9Sstevel@tonic-gate } 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate /* 840*7c478bd9Sstevel@tonic-gate * For performance reasons, do not insert anything into the 841*7c478bd9Sstevel@tonic-gate * asynchronous list or activate the asynch list schedule until 842*7c478bd9Sstevel@tonic-gate * there is a valid QH. 843*7c478bd9Sstevel@tonic-gate */ 844*7c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list = NULL; 845*7c478bd9Sstevel@tonic-gate 846*7c478bd9Sstevel@tonic-gate if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) && 847*7c478bd9Sstevel@tonic-gate (ehci_vt62x2_workaround & EHCI_VIA_ASYNC_SCHEDULE)) { 848*7c478bd9Sstevel@tonic-gate /* 849*7c478bd9Sstevel@tonic-gate * The driver is unable to reliably stop the asynch 850*7c478bd9Sstevel@tonic-gate * list schedule on VIA VT6202 controllers, so we 851*7c478bd9Sstevel@tonic-gate * always keep a dummy QH on the list. 852*7c478bd9Sstevel@tonic-gate */ 853*7c478bd9Sstevel@tonic-gate ehci_qh_t *dummy_async_qh = 854*7c478bd9Sstevel@tonic-gate ehci_alloc_qh(ehcip, NULL, NULL); 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_link_ptr, 857*7c478bd9Sstevel@tonic-gate ((ehci_qh_cpu_to_iommu(ehcip, dummy_async_qh) & 858*7c478bd9Sstevel@tonic-gate EHCI_QH_LINK_PTR) | EHCI_QH_LINK_REF_QH)); 859*7c478bd9Sstevel@tonic-gate 860*7c478bd9Sstevel@tonic-gate /* Set this QH to be the "head" of the circular list */ 861*7c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_ctrl, 862*7c478bd9Sstevel@tonic-gate Get_QH(dummy_async_qh->qh_ctrl) | 863*7c478bd9Sstevel@tonic-gate EHCI_QH_CTRL_RECLAIM_HEAD); 864*7c478bd9Sstevel@tonic-gate 865*7c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_next_qtd, 866*7c478bd9Sstevel@tonic-gate EHCI_QH_NEXT_QTD_PTR_VALID); 867*7c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_alt_next_qtd, 868*7c478bd9Sstevel@tonic-gate EHCI_QH_ALT_NEXT_QTD_PTR_VALID); 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list = dummy_async_qh; 871*7c478bd9Sstevel@tonic-gate ehcip->ehci_open_async_count++; 872*7c478bd9Sstevel@tonic-gate } 873*7c478bd9Sstevel@tonic-gate } 874*7c478bd9Sstevel@tonic-gate 875*7c478bd9Sstevel@tonic-gate /* 876*7c478bd9Sstevel@tonic-gate * Check for Asynchronous schedule park capability feature. If this 877*7c478bd9Sstevel@tonic-gate * feature is supported, then, program ehci command register with 878*7c478bd9Sstevel@tonic-gate * appropriate values.. 879*7c478bd9Sstevel@tonic-gate */ 880*7c478bd9Sstevel@tonic-gate if (Get_Cap(ehci_hcc_params) & EHCI_HCC_ASYNC_SCHED_PARK_CAP) { 881*7c478bd9Sstevel@tonic-gate 882*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 883*7c478bd9Sstevel@tonic-gate "ehci_init_ctlr: Async park mode is supported"); 884*7c478bd9Sstevel@tonic-gate 885*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) | 886*7c478bd9Sstevel@tonic-gate (EHCI_CMD_ASYNC_PARK_ENABLE | 887*7c478bd9Sstevel@tonic-gate EHCI_CMD_ASYNC_PARK_COUNT_3))); 888*7c478bd9Sstevel@tonic-gate } 889*7c478bd9Sstevel@tonic-gate 890*7c478bd9Sstevel@tonic-gate /* 891*7c478bd9Sstevel@tonic-gate * Check for programmable periodic frame list feature. If this 892*7c478bd9Sstevel@tonic-gate * feature is supported, then, program ehci command register with 893*7c478bd9Sstevel@tonic-gate * 1024 frame list value. 894*7c478bd9Sstevel@tonic-gate */ 895*7c478bd9Sstevel@tonic-gate if (Get_Cap(ehci_hcc_params) & EHCI_HCC_PROG_FRAME_LIST_FLAG) { 896*7c478bd9Sstevel@tonic-gate 897*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 898*7c478bd9Sstevel@tonic-gate "ehci_init_ctlr: Variable programmable periodic " 899*7c478bd9Sstevel@tonic-gate "frame list is supported"); 900*7c478bd9Sstevel@tonic-gate 901*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) | 902*7c478bd9Sstevel@tonic-gate EHCI_CMD_FRAME_1024_SIZE)); 903*7c478bd9Sstevel@tonic-gate } 904*7c478bd9Sstevel@tonic-gate 905*7c478bd9Sstevel@tonic-gate /* 906*7c478bd9Sstevel@tonic-gate * Currently EHCI driver doesn't support 64 bit addressing. 907*7c478bd9Sstevel@tonic-gate * 908*7c478bd9Sstevel@tonic-gate * If we are using 64 bit addressing capability, then, program 909*7c478bd9Sstevel@tonic-gate * ehci_ctrl_segment register with 4 Gigabyte segment where all 910*7c478bd9Sstevel@tonic-gate * of the interface data structures are allocated. 911*7c478bd9Sstevel@tonic-gate */ 912*7c478bd9Sstevel@tonic-gate if (Get_Cap(ehci_hcc_params) & EHCI_HCC_64BIT_ADDR_CAP) { 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 915*7c478bd9Sstevel@tonic-gate "ehci_init_ctlr: EHCI driver doesn't support " 916*7c478bd9Sstevel@tonic-gate "64 bit addressing"); 917*7c478bd9Sstevel@tonic-gate } 918*7c478bd9Sstevel@tonic-gate 919*7c478bd9Sstevel@tonic-gate /* 64 bit addressing is not support */ 920*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_ctrl_segment, 0x00000000); 921*7c478bd9Sstevel@tonic-gate 922*7c478bd9Sstevel@tonic-gate /* Turn on/off the schedulers */ 923*7c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehcip); 924*7c478bd9Sstevel@tonic-gate 925*7c478bd9Sstevel@tonic-gate /* 926*7c478bd9Sstevel@tonic-gate * Set the Periodic Frame List Base Address register with the 927*7c478bd9Sstevel@tonic-gate * starting physical address of the Periodic Frame List. 928*7c478bd9Sstevel@tonic-gate */ 929*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_periodic_list_base, 930*7c478bd9Sstevel@tonic-gate (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address & 0xFFFFF000)); 931*7c478bd9Sstevel@tonic-gate 932*7c478bd9Sstevel@tonic-gate /* 933*7c478bd9Sstevel@tonic-gate * Set ehci_interrupt to enable all interrupts except Root 934*7c478bd9Sstevel@tonic-gate * Hub Status change interrupt. 935*7c478bd9Sstevel@tonic-gate */ 936*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR | 937*7c478bd9Sstevel@tonic-gate EHCI_INTR_FRAME_LIST_ROLLOVER | EHCI_INTR_USB_ERROR | 938*7c478bd9Sstevel@tonic-gate EHCI_INTR_USB); 939*7c478bd9Sstevel@tonic-gate 940*7c478bd9Sstevel@tonic-gate /* 941*7c478bd9Sstevel@tonic-gate * Set the desired interrupt threshold and turn on EHCI host controller. 942*7c478bd9Sstevel@tonic-gate */ 943*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 944*7c478bd9Sstevel@tonic-gate ((Get_OpReg(ehci_command) & ~EHCI_CMD_INTR_THRESHOLD) | 945*7c478bd9Sstevel@tonic-gate (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN))); 946*7c478bd9Sstevel@tonic-gate 947*7c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(ehci_command) & EHCI_CMD_HOST_CTRL_RUN); 948*7c478bd9Sstevel@tonic-gate 949*7c478bd9Sstevel@tonic-gate /* 950*7c478bd9Sstevel@tonic-gate * Acer Labs Inc. M5273 EHCI controller does not send 951*7c478bd9Sstevel@tonic-gate * interrupts unless the Root hub ports are routed to the EHCI 952*7c478bd9Sstevel@tonic-gate * host controller; so route the ports now, before we test for 953*7c478bd9Sstevel@tonic-gate * the presence of SOFs interrupts. 954*7c478bd9Sstevel@tonic-gate */ 955*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) { 956*7c478bd9Sstevel@tonic-gate /* Route all Root hub ports to EHCI host controller */ 957*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI); 958*7c478bd9Sstevel@tonic-gate } 959*7c478bd9Sstevel@tonic-gate 960*7c478bd9Sstevel@tonic-gate /* 961*7c478bd9Sstevel@tonic-gate * VIA chips have some issues and may not work reliably. 962*7c478bd9Sstevel@tonic-gate * If we were bound using class pciclass,0c0320, 963*7c478bd9Sstevel@tonic-gate * complain, else proceed. This will allow the user 964*7c478bd9Sstevel@tonic-gate * to bind ehci specifically to this chip and not 965*7c478bd9Sstevel@tonic-gate * have the warnings 966*7c478bd9Sstevel@tonic-gate */ 967*7c478bd9Sstevel@tonic-gate if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) && 968*7c478bd9Sstevel@tonic-gate (strcmp(DEVI(ehcip->ehci_dip)->devi_binding_name, 969*7c478bd9Sstevel@tonic-gate "pciclass,0c0320") == 0)) { 970*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 971*7c478bd9Sstevel@tonic-gate "Due to recently discovered incompatibilities"); 972*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 973*7c478bd9Sstevel@tonic-gate "with this USB controller, USB2.x transfer"); 974*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 975*7c478bd9Sstevel@tonic-gate "support has been disabled. This device will"); 976*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 977*7c478bd9Sstevel@tonic-gate "continue to function as a USB1.x controller."); 978*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 979*7c478bd9Sstevel@tonic-gate "If you are interested in enabling USB2.x"); 980*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 981*7c478bd9Sstevel@tonic-gate "support please, refer to the ehci(7D) man page."); 982*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 983*7c478bd9Sstevel@tonic-gate "Please also refer to www.sun.com/io for"); 984*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 985*7c478bd9Sstevel@tonic-gate "Solaris Ready products and to"); 986*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 987*7c478bd9Sstevel@tonic-gate "www.sun.com/bigadmin/hcl for additional"); 988*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 989*7c478bd9Sstevel@tonic-gate "compatible USB products."); 990*7c478bd9Sstevel@tonic-gate 991*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 992*7c478bd9Sstevel@tonic-gate } else if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) && 993*7c478bd9Sstevel@tonic-gate ehci_vt62x2_workaround) { 994*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 995*7c478bd9Sstevel@tonic-gate "Applying VIA workarounds"); 996*7c478bd9Sstevel@tonic-gate } 997*7c478bd9Sstevel@tonic-gate 998*7c478bd9Sstevel@tonic-gate /* 999*7c478bd9Sstevel@tonic-gate * Get the number of clock ticks to wait. 1000*7c478bd9Sstevel@tonic-gate * This is based on the maximum time it takes for a frame list rollover 1001*7c478bd9Sstevel@tonic-gate * and maximum time wait for SOFs to begin. 1002*7c478bd9Sstevel@tonic-gate */ 1003*7c478bd9Sstevel@tonic-gate sof_time_wait = drv_usectohz((EHCI_NUM_PERIODIC_FRAME_LISTS * 1000) + 1004*7c478bd9Sstevel@tonic-gate EHCI_SOF_TIMEWAIT); 1005*7c478bd9Sstevel@tonic-gate 1006*7c478bd9Sstevel@tonic-gate /* Tell the ISR to broadcast ehci_async_schedule_advance_cv */ 1007*7c478bd9Sstevel@tonic-gate ehcip->ehci_flags |= EHCI_CV_INTR; 1008*7c478bd9Sstevel@tonic-gate 1009*7c478bd9Sstevel@tonic-gate /* We need to add a delay to allow the chip time to start running */ 1010*7c478bd9Sstevel@tonic-gate (void) cv_timedwait(&ehcip->ehci_async_schedule_advance_cv, 1011*7c478bd9Sstevel@tonic-gate &ehcip->ehci_int_mutex, ddi_get_lbolt() + sof_time_wait); 1012*7c478bd9Sstevel@tonic-gate 1013*7c478bd9Sstevel@tonic-gate /* 1014*7c478bd9Sstevel@tonic-gate * Check EHCI host controller is running, otherwise return failure. 1015*7c478bd9Sstevel@tonic-gate */ 1016*7c478bd9Sstevel@tonic-gate if ((ehcip->ehci_flags & EHCI_CV_INTR) || 1017*7c478bd9Sstevel@tonic-gate (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) { 1018*7c478bd9Sstevel@tonic-gate 1019*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1020*7c478bd9Sstevel@tonic-gate "No SOF interrupts have been received, this USB EHCI host" 1021*7c478bd9Sstevel@tonic-gate "controller is unusable"); 1022*7c478bd9Sstevel@tonic-gate 1023*7c478bd9Sstevel@tonic-gate /* 1024*7c478bd9Sstevel@tonic-gate * Route all Root hub ports to Classic host 1025*7c478bd9Sstevel@tonic-gate * controller, in case this is an unusable ALI M5273 1026*7c478bd9Sstevel@tonic-gate * EHCI controller. 1027*7c478bd9Sstevel@tonic-gate */ 1028*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) { 1029*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC); 1030*7c478bd9Sstevel@tonic-gate } 1031*7c478bd9Sstevel@tonic-gate 1032*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1033*7c478bd9Sstevel@tonic-gate } 1034*7c478bd9Sstevel@tonic-gate 1035*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1036*7c478bd9Sstevel@tonic-gate "ehci_init_ctlr: SOF's have started"); 1037*7c478bd9Sstevel@tonic-gate 1038*7c478bd9Sstevel@tonic-gate /* Route all Root hub ports to EHCI host controller */ 1039*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI); 1040*7c478bd9Sstevel@tonic-gate 1041*7c478bd9Sstevel@tonic-gate /* Set host controller soft state to operational */ 1042*7c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_OPERATIONAL_STATE; 1043*7c478bd9Sstevel@tonic-gate 1044*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1045*7c478bd9Sstevel@tonic-gate } 1046*7c478bd9Sstevel@tonic-gate 1047*7c478bd9Sstevel@tonic-gate /* 1048*7c478bd9Sstevel@tonic-gate * ehci_take_control: 1049*7c478bd9Sstevel@tonic-gate * 1050*7c478bd9Sstevel@tonic-gate * Handshake to take EHCI control from BIOS if necessary. Its only valid for 1051*7c478bd9Sstevel@tonic-gate * x86 machines, because sparc doesn't have a BIOS. 1052*7c478bd9Sstevel@tonic-gate * On x86 machine, the take control process includes 1053*7c478bd9Sstevel@tonic-gate * o get the base address of the extended capability list 1054*7c478bd9Sstevel@tonic-gate * o find out the capability for handoff synchronization in the list. 1055*7c478bd9Sstevel@tonic-gate * o check if BIOS has owned the host controller. 1056*7c478bd9Sstevel@tonic-gate * o set the OS Owned semaphore bit, ask the BIOS to release the ownership. 1057*7c478bd9Sstevel@tonic-gate * o wait for a constant time and check if BIOS has relinquished control. 1058*7c478bd9Sstevel@tonic-gate */ 1059*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1060*7c478bd9Sstevel@tonic-gate static int 1061*7c478bd9Sstevel@tonic-gate ehci_take_control(ehci_state_t *ehcip) 1062*7c478bd9Sstevel@tonic-gate { 1063*7c478bd9Sstevel@tonic-gate #if defined(__x86) 1064*7c478bd9Sstevel@tonic-gate uint32_t extended_cap; 1065*7c478bd9Sstevel@tonic-gate uint32_t extended_cap_offset; 1066*7c478bd9Sstevel@tonic-gate uint32_t extended_cap_id; 1067*7c478bd9Sstevel@tonic-gate uint_t retry; 1068*7c478bd9Sstevel@tonic-gate 1069*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1070*7c478bd9Sstevel@tonic-gate "ehci_take_control:"); 1071*7c478bd9Sstevel@tonic-gate 1072*7c478bd9Sstevel@tonic-gate /* 1073*7c478bd9Sstevel@tonic-gate * According EHCI Spec 2.2.4, get EECP base address from HCCPARAMS 1074*7c478bd9Sstevel@tonic-gate * register. 1075*7c478bd9Sstevel@tonic-gate */ 1076*7c478bd9Sstevel@tonic-gate extended_cap_offset = (Get_Cap(ehci_hcc_params) & EHCI_HCC_EECP) >> 1077*7c478bd9Sstevel@tonic-gate EHCI_HCC_EECP_SHIFT; 1078*7c478bd9Sstevel@tonic-gate 1079*7c478bd9Sstevel@tonic-gate /* 1080*7c478bd9Sstevel@tonic-gate * According EHCI Spec 2.2.4, if the extended capability offset is 1081*7c478bd9Sstevel@tonic-gate * less than 40h then its not valid. This means we don't need to 1082*7c478bd9Sstevel@tonic-gate * worry about BIOS handoff. 1083*7c478bd9Sstevel@tonic-gate */ 1084*7c478bd9Sstevel@tonic-gate if (extended_cap_offset < EHCI_HCC_EECP_MIN_OFFSET) { 1085*7c478bd9Sstevel@tonic-gate 1086*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1087*7c478bd9Sstevel@tonic-gate "ehci_take_control: Hardware doesn't support legacy."); 1088*7c478bd9Sstevel@tonic-gate 1089*7c478bd9Sstevel@tonic-gate goto success; 1090*7c478bd9Sstevel@tonic-gate } 1091*7c478bd9Sstevel@tonic-gate 1092*7c478bd9Sstevel@tonic-gate /* 1093*7c478bd9Sstevel@tonic-gate * According EHCI Spec 2.1.7, A zero offset indicates the 1094*7c478bd9Sstevel@tonic-gate * end of the extended capability list. 1095*7c478bd9Sstevel@tonic-gate */ 1096*7c478bd9Sstevel@tonic-gate while (extended_cap_offset) { 1097*7c478bd9Sstevel@tonic-gate 1098*7c478bd9Sstevel@tonic-gate /* Get the extended capability value. */ 1099*7c478bd9Sstevel@tonic-gate extended_cap = pci_config_get32(ehcip->ehci_config_handle, 1100*7c478bd9Sstevel@tonic-gate extended_cap_offset); 1101*7c478bd9Sstevel@tonic-gate 1102*7c478bd9Sstevel@tonic-gate /* Get the capability ID */ 1103*7c478bd9Sstevel@tonic-gate extended_cap_id = (extended_cap & EHCI_EX_CAP_ID) >> 1104*7c478bd9Sstevel@tonic-gate EHCI_EX_CAP_ID_SHIFT; 1105*7c478bd9Sstevel@tonic-gate 1106*7c478bd9Sstevel@tonic-gate /* Check if the card support legacy */ 1107*7c478bd9Sstevel@tonic-gate if (extended_cap_id == EHCI_EX_CAP_ID_BIOS_HANDOFF) { 1108*7c478bd9Sstevel@tonic-gate break; 1109*7c478bd9Sstevel@tonic-gate } 1110*7c478bd9Sstevel@tonic-gate 1111*7c478bd9Sstevel@tonic-gate /* Get the offset of the next capability */ 1112*7c478bd9Sstevel@tonic-gate extended_cap_offset = (extended_cap & EHCI_EX_CAP_NEXT_PTR) >> 1113*7c478bd9Sstevel@tonic-gate EHCI_EX_CAP_NEXT_PTR_SHIFT; 1114*7c478bd9Sstevel@tonic-gate } 1115*7c478bd9Sstevel@tonic-gate 1116*7c478bd9Sstevel@tonic-gate /* 1117*7c478bd9Sstevel@tonic-gate * Unable to find legacy support in hardware's extended capability list. 1118*7c478bd9Sstevel@tonic-gate * This means we don't need to worry about BIOS handoff. 1119*7c478bd9Sstevel@tonic-gate */ 1120*7c478bd9Sstevel@tonic-gate if (extended_cap_id != EHCI_EX_CAP_ID_BIOS_HANDOFF) { 1121*7c478bd9Sstevel@tonic-gate 1122*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1123*7c478bd9Sstevel@tonic-gate "ehci_take_control: Hardware doesn't support legacy"); 1124*7c478bd9Sstevel@tonic-gate 1125*7c478bd9Sstevel@tonic-gate goto success; 1126*7c478bd9Sstevel@tonic-gate } 1127*7c478bd9Sstevel@tonic-gate 1128*7c478bd9Sstevel@tonic-gate /* Check if BIOS has owned it. */ 1129*7c478bd9Sstevel@tonic-gate if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) { 1130*7c478bd9Sstevel@tonic-gate 1131*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1132*7c478bd9Sstevel@tonic-gate "ehci_take_control: BIOS does not own EHCI"); 1133*7c478bd9Sstevel@tonic-gate 1134*7c478bd9Sstevel@tonic-gate goto success; 1135*7c478bd9Sstevel@tonic-gate } 1136*7c478bd9Sstevel@tonic-gate 1137*7c478bd9Sstevel@tonic-gate /* 1138*7c478bd9Sstevel@tonic-gate * According EHCI Spec 5.1, The OS driver initiates an ownership 1139*7c478bd9Sstevel@tonic-gate * request by setting the OS Owned semaphore to a one. The OS 1140*7c478bd9Sstevel@tonic-gate * waits for the BIOS Owned bit to go to a zero before attempting 1141*7c478bd9Sstevel@tonic-gate * to use the EHCI controller. The time that OS must wait for BIOS 1142*7c478bd9Sstevel@tonic-gate * to respond to the request for ownership is beyond the scope of 1143*7c478bd9Sstevel@tonic-gate * this specification. 1144*7c478bd9Sstevel@tonic-gate * It waits up to EHCI_TAKEOVER_WAIT_COUNT*EHCI_TAKEOVER_DELAY ms 1145*7c478bd9Sstevel@tonic-gate * for BIOS to release the ownership. 1146*7c478bd9Sstevel@tonic-gate */ 1147*7c478bd9Sstevel@tonic-gate extended_cap |= EHCI_LEGSUP_OS_OWNED_SEM; 1148*7c478bd9Sstevel@tonic-gate pci_config_put32(ehcip->ehci_config_handle, extended_cap_offset, 1149*7c478bd9Sstevel@tonic-gate extended_cap); 1150*7c478bd9Sstevel@tonic-gate 1151*7c478bd9Sstevel@tonic-gate for (retry = 0; retry < EHCI_TAKEOVER_WAIT_COUNT; retry++) { 1152*7c478bd9Sstevel@tonic-gate 1153*7c478bd9Sstevel@tonic-gate /* wait a special interval */ 1154*7c478bd9Sstevel@tonic-gate delay(drv_usectohz(EHCI_TAKEOVER_DELAY)); 1155*7c478bd9Sstevel@tonic-gate 1156*7c478bd9Sstevel@tonic-gate /* Check to see if the BIOS has released the ownership */ 1157*7c478bd9Sstevel@tonic-gate extended_cap = pci_config_get32( 1158*7c478bd9Sstevel@tonic-gate ehcip->ehci_config_handle, extended_cap_offset); 1159*7c478bd9Sstevel@tonic-gate 1160*7c478bd9Sstevel@tonic-gate if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) { 1161*7c478bd9Sstevel@tonic-gate 1162*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, 1163*7c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 1164*7c478bd9Sstevel@tonic-gate "ehci_take_control: BIOS has released " 1165*7c478bd9Sstevel@tonic-gate "the ownership. retry = %d", retry); 1166*7c478bd9Sstevel@tonic-gate 1167*7c478bd9Sstevel@tonic-gate goto success; 1168*7c478bd9Sstevel@tonic-gate } 1169*7c478bd9Sstevel@tonic-gate 1170*7c478bd9Sstevel@tonic-gate } 1171*7c478bd9Sstevel@tonic-gate 1172*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1173*7c478bd9Sstevel@tonic-gate "ehci_take_control: take control from BIOS failed."); 1174*7c478bd9Sstevel@tonic-gate 1175*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1176*7c478bd9Sstevel@tonic-gate 1177*7c478bd9Sstevel@tonic-gate success: 1178*7c478bd9Sstevel@tonic-gate 1179*7c478bd9Sstevel@tonic-gate #endif /* __x86 */ 1180*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1181*7c478bd9Sstevel@tonic-gate } 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate 1184*7c478bd9Sstevel@tonic-gate /* 1185*7c478bd9Sstevel@tonic-gate * ehci_init_periodic_frame_list_table : 1186*7c478bd9Sstevel@tonic-gate * 1187*7c478bd9Sstevel@tonic-gate * Allocate the system memory and initialize Host Controller 1188*7c478bd9Sstevel@tonic-gate * Periodic Frame List table area. The starting of the Periodic 1189*7c478bd9Sstevel@tonic-gate * Frame List Table area must be 4096 byte aligned. 1190*7c478bd9Sstevel@tonic-gate */ 1191*7c478bd9Sstevel@tonic-gate static int 1192*7c478bd9Sstevel@tonic-gate ehci_init_periodic_frame_lst_table(ehci_state_t *ehcip) 1193*7c478bd9Sstevel@tonic-gate { 1194*7c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 1195*7c478bd9Sstevel@tonic-gate size_t real_length; 1196*7c478bd9Sstevel@tonic-gate uint_t ccount; 1197*7c478bd9Sstevel@tonic-gate int result; 1198*7c478bd9Sstevel@tonic-gate 1199*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1200*7c478bd9Sstevel@tonic-gate 1201*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1202*7c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table:"); 1203*7c478bd9Sstevel@tonic-gate 1204*7c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 1205*7c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 1206*7c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 1207*7c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 1208*7c478bd9Sstevel@tonic-gate 1209*7c478bd9Sstevel@tonic-gate /* Force the required 4K restrictive alignment */ 1210*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_PFL_ALIGNMENT; 1211*7c478bd9Sstevel@tonic-gate 1212*7c478bd9Sstevel@tonic-gate /* Create space for the Periodic Frame List */ 1213*7c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr, 1214*7c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 0, &ehcip->ehci_pflt_dma_handle) != DDI_SUCCESS) { 1215*7c478bd9Sstevel@tonic-gate 1216*7c478bd9Sstevel@tonic-gate goto failure; 1217*7c478bd9Sstevel@tonic-gate } 1218*7c478bd9Sstevel@tonic-gate 1219*7c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_pflt_dma_handle, 1220*7c478bd9Sstevel@tonic-gate sizeof (ehci_periodic_frame_list_t), 1221*7c478bd9Sstevel@tonic-gate &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 1222*7c478bd9Sstevel@tonic-gate 0, (caddr_t *)&ehcip->ehci_periodic_frame_list_tablep, 1223*7c478bd9Sstevel@tonic-gate &real_length, &ehcip->ehci_pflt_mem_handle)) { 1224*7c478bd9Sstevel@tonic-gate 1225*7c478bd9Sstevel@tonic-gate goto failure; 1226*7c478bd9Sstevel@tonic-gate } 1227*7c478bd9Sstevel@tonic-gate 1228*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1229*7c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: " 1230*7c478bd9Sstevel@tonic-gate "Real length %lu", real_length); 1231*7c478bd9Sstevel@tonic-gate 1232*7c478bd9Sstevel@tonic-gate /* Map the whole Periodic Frame List into the I/O address space */ 1233*7c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ehcip->ehci_pflt_dma_handle, 1234*7c478bd9Sstevel@tonic-gate NULL, (caddr_t)ehcip->ehci_periodic_frame_list_tablep, 1235*7c478bd9Sstevel@tonic-gate real_length, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1236*7c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, &ehcip->ehci_pflt_cookie, &ccount); 1237*7c478bd9Sstevel@tonic-gate 1238*7c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 1239*7c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 1240*7c478bd9Sstevel@tonic-gate if (ccount != 1) { 1241*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1242*7c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: " 1243*7c478bd9Sstevel@tonic-gate "More than 1 cookie"); 1244*7c478bd9Sstevel@tonic-gate 1245*7c478bd9Sstevel@tonic-gate goto failure; 1246*7c478bd9Sstevel@tonic-gate } 1247*7c478bd9Sstevel@tonic-gate } else { 1248*7c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result); 1249*7c478bd9Sstevel@tonic-gate 1250*7c478bd9Sstevel@tonic-gate goto failure; 1251*7c478bd9Sstevel@tonic-gate } 1252*7c478bd9Sstevel@tonic-gate 1253*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1254*7c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: virtual 0x%p physical 0x%x", 1255*7c478bd9Sstevel@tonic-gate (void *)ehcip->ehci_periodic_frame_list_tablep, 1256*7c478bd9Sstevel@tonic-gate ehcip->ehci_pflt_cookie.dmac_address); 1257*7c478bd9Sstevel@tonic-gate 1258*7c478bd9Sstevel@tonic-gate /* 1259*7c478bd9Sstevel@tonic-gate * DMA addresses for Periodic Frame List are bound. 1260*7c478bd9Sstevel@tonic-gate */ 1261*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_PFLT_DMA_BOUND; 1262*7c478bd9Sstevel@tonic-gate 1263*7c478bd9Sstevel@tonic-gate bzero((void *)ehcip->ehci_periodic_frame_list_tablep, real_length); 1264*7c478bd9Sstevel@tonic-gate 1265*7c478bd9Sstevel@tonic-gate /* Initialize the Periodic Frame List */ 1266*7c478bd9Sstevel@tonic-gate ehci_build_interrupt_lattice(ehcip); 1267*7c478bd9Sstevel@tonic-gate 1268*7c478bd9Sstevel@tonic-gate /* Reset Byte Alignment to Default */ 1269*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 1270*7c478bd9Sstevel@tonic-gate 1271*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1272*7c478bd9Sstevel@tonic-gate failure: 1273*7c478bd9Sstevel@tonic-gate /* Byte alignment */ 1274*7c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 1275*7c478bd9Sstevel@tonic-gate 1276*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1277*7c478bd9Sstevel@tonic-gate } 1278*7c478bd9Sstevel@tonic-gate 1279*7c478bd9Sstevel@tonic-gate 1280*7c478bd9Sstevel@tonic-gate /* 1281*7c478bd9Sstevel@tonic-gate * ehci_build_interrupt_lattice: 1282*7c478bd9Sstevel@tonic-gate * 1283*7c478bd9Sstevel@tonic-gate * Construct the interrupt lattice tree using static Endpoint Descriptors 1284*7c478bd9Sstevel@tonic-gate * (QH). This interrupt lattice tree will have total of 32 interrupt QH 1285*7c478bd9Sstevel@tonic-gate * lists and the Host Controller (HC) processes one interrupt QH list in 1286*7c478bd9Sstevel@tonic-gate * every frame. The Host Controller traverses the periodic schedule by 1287*7c478bd9Sstevel@tonic-gate * constructing an array offset reference from the Periodic List Base Address 1288*7c478bd9Sstevel@tonic-gate * register and bits 12 to 3 of Frame Index register. It fetches the element 1289*7c478bd9Sstevel@tonic-gate * and begins traversing the graph of linked schedule data structures. 1290*7c478bd9Sstevel@tonic-gate */ 1291*7c478bd9Sstevel@tonic-gate static void 1292*7c478bd9Sstevel@tonic-gate ehci_build_interrupt_lattice(ehci_state_t *ehcip) 1293*7c478bd9Sstevel@tonic-gate { 1294*7c478bd9Sstevel@tonic-gate ehci_qh_t *list_array = ehcip->ehci_qh_pool_addr; 1295*7c478bd9Sstevel@tonic-gate ushort_t ehci_index[EHCI_NUM_PERIODIC_FRAME_LISTS]; 1296*7c478bd9Sstevel@tonic-gate ehci_periodic_frame_list_t *periodic_frame_list = 1297*7c478bd9Sstevel@tonic-gate ehcip->ehci_periodic_frame_list_tablep; 1298*7c478bd9Sstevel@tonic-gate ushort_t *temp, num_of_nodes; 1299*7c478bd9Sstevel@tonic-gate uintptr_t addr; 1300*7c478bd9Sstevel@tonic-gate int i, j, k; 1301*7c478bd9Sstevel@tonic-gate 1302*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1303*7c478bd9Sstevel@tonic-gate "ehci_build_interrupt_lattice:"); 1304*7c478bd9Sstevel@tonic-gate 1305*7c478bd9Sstevel@tonic-gate /* 1306*7c478bd9Sstevel@tonic-gate * Reserve the first 63 Endpoint Descriptor (QH) structures 1307*7c478bd9Sstevel@tonic-gate * in the pool as static endpoints & these are required for 1308*7c478bd9Sstevel@tonic-gate * constructing interrupt lattice tree. 1309*7c478bd9Sstevel@tonic-gate */ 1310*7c478bd9Sstevel@tonic-gate for (i = 0; i < EHCI_NUM_STATIC_NODES; i++) { 1311*7c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_state, EHCI_QH_STATIC); 1312*7c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_status, EHCI_QH_STS_HALTED); 1313*7c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_next_qtd, EHCI_QH_NEXT_QTD_PTR_VALID); 1314*7c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_alt_next_qtd, 1315*7c478bd9Sstevel@tonic-gate EHCI_QH_ALT_NEXT_QTD_PTR_VALID); 1316*7c478bd9Sstevel@tonic-gate } 1317*7c478bd9Sstevel@tonic-gate 1318*7c478bd9Sstevel@tonic-gate /* 1319*7c478bd9Sstevel@tonic-gate * Make sure that last Endpoint on the periodic frame list terminates 1320*7c478bd9Sstevel@tonic-gate * periodic schedule. 1321*7c478bd9Sstevel@tonic-gate */ 1322*7c478bd9Sstevel@tonic-gate Set_QH(list_array[0].qh_link_ptr, EHCI_QH_LINK_PTR_VALID); 1323*7c478bd9Sstevel@tonic-gate 1324*7c478bd9Sstevel@tonic-gate /* Build the interrupt lattice tree */ 1325*7c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_STATIC_NODES / 2); i++) { 1326*7c478bd9Sstevel@tonic-gate /* 1327*7c478bd9Sstevel@tonic-gate * The next pointer in the host controller endpoint 1328*7c478bd9Sstevel@tonic-gate * descriptor must contain an iommu address. Calculate 1329*7c478bd9Sstevel@tonic-gate * the offset into the cpu address and add this to the 1330*7c478bd9Sstevel@tonic-gate * starting iommu address. 1331*7c478bd9Sstevel@tonic-gate */ 1332*7c478bd9Sstevel@tonic-gate addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *)&list_array[i]); 1333*7c478bd9Sstevel@tonic-gate 1334*7c478bd9Sstevel@tonic-gate Set_QH(list_array[2*i + 1].qh_link_ptr, 1335*7c478bd9Sstevel@tonic-gate addr | EHCI_QH_LINK_REF_QH); 1336*7c478bd9Sstevel@tonic-gate Set_QH(list_array[2*i + 2].qh_link_ptr, 1337*7c478bd9Sstevel@tonic-gate addr | EHCI_QH_LINK_REF_QH); 1338*7c478bd9Sstevel@tonic-gate } 1339*7c478bd9Sstevel@tonic-gate 1340*7c478bd9Sstevel@tonic-gate /* Build the tree bottom */ 1341*7c478bd9Sstevel@tonic-gate temp = (unsigned short *) 1342*7c478bd9Sstevel@tonic-gate kmem_zalloc(EHCI_NUM_PERIODIC_FRAME_LISTS * 2, KM_SLEEP); 1343*7c478bd9Sstevel@tonic-gate 1344*7c478bd9Sstevel@tonic-gate num_of_nodes = 1; 1345*7c478bd9Sstevel@tonic-gate 1346*7c478bd9Sstevel@tonic-gate /* 1347*7c478bd9Sstevel@tonic-gate * Initialize the values which are used for setting up head pointers 1348*7c478bd9Sstevel@tonic-gate * for the 32ms scheduling lists which starts from the Periodic Frame 1349*7c478bd9Sstevel@tonic-gate * List. 1350*7c478bd9Sstevel@tonic-gate */ 1351*7c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_log_2(EHCI_NUM_PERIODIC_FRAME_LISTS); i++) { 1352*7c478bd9Sstevel@tonic-gate for (j = 0, k = 0; k < num_of_nodes; k++, j++) { 1353*7c478bd9Sstevel@tonic-gate ehci_index[j++] = temp[k]; 1354*7c478bd9Sstevel@tonic-gate ehci_index[j] = temp[k] + ehci_pow_2(i); 1355*7c478bd9Sstevel@tonic-gate } 1356*7c478bd9Sstevel@tonic-gate 1357*7c478bd9Sstevel@tonic-gate num_of_nodes *= 2; 1358*7c478bd9Sstevel@tonic-gate for (k = 0; k < num_of_nodes; k++) 1359*7c478bd9Sstevel@tonic-gate temp[k] = ehci_index[k]; 1360*7c478bd9Sstevel@tonic-gate } 1361*7c478bd9Sstevel@tonic-gate 1362*7c478bd9Sstevel@tonic-gate kmem_free((void *)temp, (EHCI_NUM_PERIODIC_FRAME_LISTS * 2)); 1363*7c478bd9Sstevel@tonic-gate 1364*7c478bd9Sstevel@tonic-gate /* 1365*7c478bd9Sstevel@tonic-gate * Initialize the interrupt list in the Periodic Frame List Table 1366*7c478bd9Sstevel@tonic-gate * so that it points to the bottom of the tree. 1367*7c478bd9Sstevel@tonic-gate */ 1368*7c478bd9Sstevel@tonic-gate for (i = 0, j = 0; i < ehci_pow_2(TREE_HEIGHT); i++) { 1369*7c478bd9Sstevel@tonic-gate addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *) 1370*7c478bd9Sstevel@tonic-gate (&list_array[((EHCI_NUM_STATIC_NODES + 1) / 2) + i - 1])); 1371*7c478bd9Sstevel@tonic-gate 1372*7c478bd9Sstevel@tonic-gate ASSERT(addr); 1373*7c478bd9Sstevel@tonic-gate 1374*7c478bd9Sstevel@tonic-gate for (k = 0; k < ehci_pow_2(TREE_HEIGHT); k++) { 1375*7c478bd9Sstevel@tonic-gate Set_PFLT(periodic_frame_list-> 1376*7c478bd9Sstevel@tonic-gate ehci_periodic_frame_list_table[ehci_index[j++]], 1377*7c478bd9Sstevel@tonic-gate (uint32_t)(addr | EHCI_QH_LINK_REF_QH)); 1378*7c478bd9Sstevel@tonic-gate } 1379*7c478bd9Sstevel@tonic-gate } 1380*7c478bd9Sstevel@tonic-gate } 1381*7c478bd9Sstevel@tonic-gate 1382*7c478bd9Sstevel@tonic-gate 1383*7c478bd9Sstevel@tonic-gate /* 1384*7c478bd9Sstevel@tonic-gate * ehci_alloc_hcdi_ops: 1385*7c478bd9Sstevel@tonic-gate * 1386*7c478bd9Sstevel@tonic-gate * The HCDI interfaces or entry points are the software interfaces used by 1387*7c478bd9Sstevel@tonic-gate * the Universal Serial Bus Driver (USBA) to access the services of the 1388*7c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD). During HCD initialization, inform USBA 1389*7c478bd9Sstevel@tonic-gate * about all available HCDI interfaces or entry points. 1390*7c478bd9Sstevel@tonic-gate */ 1391*7c478bd9Sstevel@tonic-gate usba_hcdi_ops_t * 1392*7c478bd9Sstevel@tonic-gate ehci_alloc_hcdi_ops(ehci_state_t *ehcip) 1393*7c478bd9Sstevel@tonic-gate { 1394*7c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *usba_hcdi_ops; 1395*7c478bd9Sstevel@tonic-gate 1396*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1397*7c478bd9Sstevel@tonic-gate "ehci_alloc_hcdi_ops:"); 1398*7c478bd9Sstevel@tonic-gate 1399*7c478bd9Sstevel@tonic-gate usba_hcdi_ops = usba_alloc_hcdi_ops(); 1400*7c478bd9Sstevel@tonic-gate 1401*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_ops_version = HCDI_OPS_VERSION; 1402*7c478bd9Sstevel@tonic-gate 1403*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_open = ehci_hcdi_pipe_open; 1404*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_close = ehci_hcdi_pipe_close; 1405*7c478bd9Sstevel@tonic-gate 1406*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_reset = ehci_hcdi_pipe_reset; 1407*7c478bd9Sstevel@tonic-gate 1408*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_ctrl_xfer = ehci_hcdi_pipe_ctrl_xfer; 1409*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_bulk_xfer = ehci_hcdi_pipe_bulk_xfer; 1410*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_intr_xfer = ehci_hcdi_pipe_intr_xfer; 1411*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_isoc_xfer = ehci_hcdi_pipe_isoc_xfer; 1412*7c478bd9Sstevel@tonic-gate 1413*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_bulk_transfer_size = 1414*7c478bd9Sstevel@tonic-gate ehci_hcdi_bulk_transfer_size; 1415*7c478bd9Sstevel@tonic-gate 1416*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_intr_polling = 1417*7c478bd9Sstevel@tonic-gate ehci_hcdi_pipe_stop_intr_polling; 1418*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_isoc_polling = 1419*7c478bd9Sstevel@tonic-gate ehci_hcdi_pipe_stop_isoc_polling; 1420*7c478bd9Sstevel@tonic-gate 1421*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_current_frame_number = 1422*7c478bd9Sstevel@tonic-gate ehci_hcdi_get_current_frame_number; 1423*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_max_isoc_pkts = 1424*7c478bd9Sstevel@tonic-gate ehci_hcdi_get_max_isoc_pkts; 1425*7c478bd9Sstevel@tonic-gate 1426*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_init = 1427*7c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_init; 1428*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_enter = 1429*7c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_enter; 1430*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_read = 1431*7c478bd9Sstevel@tonic-gate ehci_hcdi_polled_read; 1432*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_exit = 1433*7c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_exit; 1434*7c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_fini = 1435*7c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_fini; 1436*7c478bd9Sstevel@tonic-gate return (usba_hcdi_ops); 1437*7c478bd9Sstevel@tonic-gate } 1438*7c478bd9Sstevel@tonic-gate 1439*7c478bd9Sstevel@tonic-gate 1440*7c478bd9Sstevel@tonic-gate /* 1441*7c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) deinitialization functions 1442*7c478bd9Sstevel@tonic-gate */ 1443*7c478bd9Sstevel@tonic-gate 1444*7c478bd9Sstevel@tonic-gate /* 1445*7c478bd9Sstevel@tonic-gate * ehci_cleanup: 1446*7c478bd9Sstevel@tonic-gate * 1447*7c478bd9Sstevel@tonic-gate * Cleanup on attach failure or detach 1448*7c478bd9Sstevel@tonic-gate */ 1449*7c478bd9Sstevel@tonic-gate int 1450*7c478bd9Sstevel@tonic-gate ehci_cleanup(ehci_state_t *ehcip) 1451*7c478bd9Sstevel@tonic-gate { 1452*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw; 1453*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; 1454*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd; 1455*7c478bd9Sstevel@tonic-gate int i, ctrl, rval; 1456*7c478bd9Sstevel@tonic-gate int flags = ehcip->ehci_flags; 1457*7c478bd9Sstevel@tonic-gate 1458*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_cleanup:"); 1459*7c478bd9Sstevel@tonic-gate 1460*7c478bd9Sstevel@tonic-gate if (flags & EHCI_RHREG) { 1461*7c478bd9Sstevel@tonic-gate /* Unload the root hub driver */ 1462*7c478bd9Sstevel@tonic-gate if (ehci_unload_root_hub_driver(ehcip) != USB_SUCCESS) { 1463*7c478bd9Sstevel@tonic-gate 1464*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1465*7c478bd9Sstevel@tonic-gate } 1466*7c478bd9Sstevel@tonic-gate } 1467*7c478bd9Sstevel@tonic-gate 1468*7c478bd9Sstevel@tonic-gate if (flags & EHCI_USBAREG) { 1469*7c478bd9Sstevel@tonic-gate /* Unregister this HCD instance with USBA */ 1470*7c478bd9Sstevel@tonic-gate usba_hcdi_unregister(ehcip->ehci_dip); 1471*7c478bd9Sstevel@tonic-gate } 1472*7c478bd9Sstevel@tonic-gate 1473*7c478bd9Sstevel@tonic-gate if (flags & EHCI_INTR) { 1474*7c478bd9Sstevel@tonic-gate 1475*7c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 1476*7c478bd9Sstevel@tonic-gate 1477*7c478bd9Sstevel@tonic-gate /* Route all Root hub ports to Classic host controller */ 1478*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC); 1479*7c478bd9Sstevel@tonic-gate 1480*7c478bd9Sstevel@tonic-gate /* Disable all EHCI QH list processing */ 1481*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) & 1482*7c478bd9Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | 1483*7c478bd9Sstevel@tonic-gate EHCI_CMD_PERIODIC_SCHED_ENABLE))); 1484*7c478bd9Sstevel@tonic-gate 1485*7c478bd9Sstevel@tonic-gate /* Disable all EHCI interrupts */ 1486*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0); 1487*7c478bd9Sstevel@tonic-gate 1488*7c478bd9Sstevel@tonic-gate /* wait for the next SOF */ 1489*7c478bd9Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip); 1490*7c478bd9Sstevel@tonic-gate 1491*7c478bd9Sstevel@tonic-gate /* Stop the EHCI host controller */ 1492*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 1493*7c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN); 1494*7c478bd9Sstevel@tonic-gate 1495*7c478bd9Sstevel@tonic-gate /* Wait for sometime */ 1496*7c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_TIMEWAIT); 1497*7c478bd9Sstevel@tonic-gate 1498*7c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 1499*7c478bd9Sstevel@tonic-gate 1500*7c478bd9Sstevel@tonic-gate /* disable interrupt */ 1501*7c478bd9Sstevel@tonic-gate (void) ddi_intr_disable(ehcip->ehci_htable[0]); 1502*7c478bd9Sstevel@tonic-gate 1503*7c478bd9Sstevel@tonic-gate /* Remove interrupt handler */ 1504*7c478bd9Sstevel@tonic-gate (void) ddi_intr_remove_handler(ehcip->ehci_htable[0]); 1505*7c478bd9Sstevel@tonic-gate 1506*7c478bd9Sstevel@tonic-gate /* free interrupt handle */ 1507*7c478bd9Sstevel@tonic-gate (void) ddi_intr_free(ehcip->ehci_htable[0]); 1508*7c478bd9Sstevel@tonic-gate 1509*7c478bd9Sstevel@tonic-gate /* free memory */ 1510*7c478bd9Sstevel@tonic-gate kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t)); 1511*7c478bd9Sstevel@tonic-gate } 1512*7c478bd9Sstevel@tonic-gate 1513*7c478bd9Sstevel@tonic-gate /* Unmap the EHCI registers */ 1514*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_caps_handle) { 1515*7c478bd9Sstevel@tonic-gate ddi_regs_map_free(&ehcip->ehci_caps_handle); 1516*7c478bd9Sstevel@tonic-gate } 1517*7c478bd9Sstevel@tonic-gate 1518*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_config_handle) { 1519*7c478bd9Sstevel@tonic-gate pci_config_teardown(&ehcip->ehci_config_handle); 1520*7c478bd9Sstevel@tonic-gate } 1521*7c478bd9Sstevel@tonic-gate 1522*7c478bd9Sstevel@tonic-gate /* Free all the buffers */ 1523*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_qtd_pool_addr && ehcip->ehci_qtd_pool_mem_handle) { 1524*7c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_qtd_pool_size; i ++) { 1525*7c478bd9Sstevel@tonic-gate qtd = &ehcip->ehci_qtd_pool_addr[i]; 1526*7c478bd9Sstevel@tonic-gate ctrl = Get_QTD(ehcip-> 1527*7c478bd9Sstevel@tonic-gate ehci_qtd_pool_addr[i].qtd_state); 1528*7c478bd9Sstevel@tonic-gate 1529*7c478bd9Sstevel@tonic-gate if ((ctrl != EHCI_QTD_FREE) && 1530*7c478bd9Sstevel@tonic-gate (ctrl != EHCI_QTD_DUMMY) && 1531*7c478bd9Sstevel@tonic-gate (qtd->qtd_trans_wrapper)) { 1532*7c478bd9Sstevel@tonic-gate 1533*7c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 1534*7c478bd9Sstevel@tonic-gate 1535*7c478bd9Sstevel@tonic-gate tw = (ehci_trans_wrapper_t *) 1536*7c478bd9Sstevel@tonic-gate EHCI_LOOKUP_ID((uint32_t) 1537*7c478bd9Sstevel@tonic-gate Get_QTD(qtd->qtd_trans_wrapper)); 1538*7c478bd9Sstevel@tonic-gate 1539*7c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 1540*7c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 1541*7c478bd9Sstevel@tonic-gate 1542*7c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */ 1543*7c478bd9Sstevel@tonic-gate ehci_stop_xfer_timer(ehcip, tw, 1544*7c478bd9Sstevel@tonic-gate EHCI_REMOVE_XFER_ALWAYS); 1545*7c478bd9Sstevel@tonic-gate 1546*7c478bd9Sstevel@tonic-gate ehci_deallocate_tw(ehcip, pp, tw); 1547*7c478bd9Sstevel@tonic-gate 1548*7c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 1549*7c478bd9Sstevel@tonic-gate } 1550*7c478bd9Sstevel@tonic-gate } 1551*7c478bd9Sstevel@tonic-gate 1552*7c478bd9Sstevel@tonic-gate /* 1553*7c478bd9Sstevel@tonic-gate * If EHCI_QTD_POOL_BOUND flag is set, then unbind 1554*7c478bd9Sstevel@tonic-gate * the handle for QTD pools. 1555*7c478bd9Sstevel@tonic-gate */ 1556*7c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 1557*7c478bd9Sstevel@tonic-gate EHCI_QTD_POOL_BOUND) == EHCI_QTD_POOL_BOUND) { 1558*7c478bd9Sstevel@tonic-gate 1559*7c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 1560*7c478bd9Sstevel@tonic-gate ehcip->ehci_qtd_pool_dma_handle); 1561*7c478bd9Sstevel@tonic-gate 1562*7c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 1563*7c478bd9Sstevel@tonic-gate } 1564*7c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_qtd_pool_mem_handle); 1565*7c478bd9Sstevel@tonic-gate } 1566*7c478bd9Sstevel@tonic-gate 1567*7c478bd9Sstevel@tonic-gate /* Free the QTD pool */ 1568*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_qtd_pool_dma_handle) { 1569*7c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_qtd_pool_dma_handle); 1570*7c478bd9Sstevel@tonic-gate } 1571*7c478bd9Sstevel@tonic-gate 1572*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_qh_pool_addr && ehcip->ehci_qh_pool_mem_handle) { 1573*7c478bd9Sstevel@tonic-gate /* 1574*7c478bd9Sstevel@tonic-gate * If EHCI_QH_POOL_BOUND flag is set, then unbind 1575*7c478bd9Sstevel@tonic-gate * the handle for QH pools. 1576*7c478bd9Sstevel@tonic-gate */ 1577*7c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 1578*7c478bd9Sstevel@tonic-gate EHCI_QH_POOL_BOUND) == EHCI_QH_POOL_BOUND) { 1579*7c478bd9Sstevel@tonic-gate 1580*7c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 1581*7c478bd9Sstevel@tonic-gate ehcip->ehci_qh_pool_dma_handle); 1582*7c478bd9Sstevel@tonic-gate 1583*7c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 1584*7c478bd9Sstevel@tonic-gate } 1585*7c478bd9Sstevel@tonic-gate 1586*7c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_qh_pool_mem_handle); 1587*7c478bd9Sstevel@tonic-gate } 1588*7c478bd9Sstevel@tonic-gate 1589*7c478bd9Sstevel@tonic-gate /* Free the QH pool */ 1590*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_qh_pool_dma_handle) { 1591*7c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_qh_pool_dma_handle); 1592*7c478bd9Sstevel@tonic-gate } 1593*7c478bd9Sstevel@tonic-gate 1594*7c478bd9Sstevel@tonic-gate /* Free the Periodic frame list table (PFLT) area */ 1595*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_periodic_frame_list_tablep && 1596*7c478bd9Sstevel@tonic-gate ehcip->ehci_pflt_mem_handle) { 1597*7c478bd9Sstevel@tonic-gate /* 1598*7c478bd9Sstevel@tonic-gate * If EHCI_PFLT_DMA_BOUND flag is set, then unbind 1599*7c478bd9Sstevel@tonic-gate * the handle for PFLT. 1600*7c478bd9Sstevel@tonic-gate */ 1601*7c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 1602*7c478bd9Sstevel@tonic-gate EHCI_PFLT_DMA_BOUND) == EHCI_PFLT_DMA_BOUND) { 1603*7c478bd9Sstevel@tonic-gate 1604*7c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 1605*7c478bd9Sstevel@tonic-gate ehcip->ehci_pflt_dma_handle); 1606*7c478bd9Sstevel@tonic-gate 1607*7c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 1608*7c478bd9Sstevel@tonic-gate } 1609*7c478bd9Sstevel@tonic-gate 1610*7c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_pflt_mem_handle); 1611*7c478bd9Sstevel@tonic-gate } 1612*7c478bd9Sstevel@tonic-gate 1613*7c478bd9Sstevel@tonic-gate (void) ehci_isoc_cleanup(ehcip); 1614*7c478bd9Sstevel@tonic-gate 1615*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_pflt_dma_handle) { 1616*7c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_pflt_dma_handle); 1617*7c478bd9Sstevel@tonic-gate } 1618*7c478bd9Sstevel@tonic-gate 1619*7c478bd9Sstevel@tonic-gate if (flags & EHCI_INTR) { 1620*7c478bd9Sstevel@tonic-gate /* Destroy the mutex */ 1621*7c478bd9Sstevel@tonic-gate mutex_destroy(&ehcip->ehci_int_mutex); 1622*7c478bd9Sstevel@tonic-gate 1623*7c478bd9Sstevel@tonic-gate /* Destroy the async schedule advance condition variable */ 1624*7c478bd9Sstevel@tonic-gate cv_destroy(&ehcip->ehci_async_schedule_advance_cv); 1625*7c478bd9Sstevel@tonic-gate } 1626*7c478bd9Sstevel@tonic-gate 1627*7c478bd9Sstevel@tonic-gate /* clean up kstat structs */ 1628*7c478bd9Sstevel@tonic-gate ehci_destroy_stats(ehcip); 1629*7c478bd9Sstevel@tonic-gate 1630*7c478bd9Sstevel@tonic-gate /* Free ehci hcdi ops */ 1631*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_hcdi_ops) { 1632*7c478bd9Sstevel@tonic-gate usba_free_hcdi_ops(ehcip->ehci_hcdi_ops); 1633*7c478bd9Sstevel@tonic-gate } 1634*7c478bd9Sstevel@tonic-gate 1635*7c478bd9Sstevel@tonic-gate if (flags & EHCI_ZALLOC) { 1636*7c478bd9Sstevel@tonic-gate 1637*7c478bd9Sstevel@tonic-gate usb_free_log_hdl(ehcip->ehci_log_hdl); 1638*7c478bd9Sstevel@tonic-gate 1639*7c478bd9Sstevel@tonic-gate /* Remove all properties that might have been created */ 1640*7c478bd9Sstevel@tonic-gate ddi_prop_remove_all(ehcip->ehci_dip); 1641*7c478bd9Sstevel@tonic-gate 1642*7c478bd9Sstevel@tonic-gate /* Free the soft state */ 1643*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(ehci_statep, 1644*7c478bd9Sstevel@tonic-gate ddi_get_instance(ehcip->ehci_dip)); 1645*7c478bd9Sstevel@tonic-gate } 1646*7c478bd9Sstevel@tonic-gate 1647*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1648*7c478bd9Sstevel@tonic-gate } 1649*7c478bd9Sstevel@tonic-gate 1650*7c478bd9Sstevel@tonic-gate 1651*7c478bd9Sstevel@tonic-gate /* 1652*7c478bd9Sstevel@tonic-gate * ehci_cpr_suspend 1653*7c478bd9Sstevel@tonic-gate */ 1654*7c478bd9Sstevel@tonic-gate int 1655*7c478bd9Sstevel@tonic-gate ehci_cpr_suspend(ehci_state_t *ehcip) 1656*7c478bd9Sstevel@tonic-gate { 1657*7c478bd9Sstevel@tonic-gate int i; 1658*7c478bd9Sstevel@tonic-gate 1659*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1660*7c478bd9Sstevel@tonic-gate "ehci_cpr_suspend:"); 1661*7c478bd9Sstevel@tonic-gate 1662*7c478bd9Sstevel@tonic-gate /* Call into the root hub and suspend it */ 1663*7c478bd9Sstevel@tonic-gate if (usba_hubdi_detach(ehcip->ehci_dip, DDI_SUSPEND) != DDI_SUCCESS) { 1664*7c478bd9Sstevel@tonic-gate 1665*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1666*7c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: root hub fails to suspend"); 1667*7c478bd9Sstevel@tonic-gate 1668*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1669*7c478bd9Sstevel@tonic-gate } 1670*7c478bd9Sstevel@tonic-gate 1671*7c478bd9Sstevel@tonic-gate /* Only root hub's intr pipe should be open at this time */ 1672*7c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 1673*7c478bd9Sstevel@tonic-gate 1674*7c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_open_pipe_count == 0); 1675*7c478bd9Sstevel@tonic-gate 1676*7c478bd9Sstevel@tonic-gate /* Just wait till all resources are reclaimed */ 1677*7c478bd9Sstevel@tonic-gate i = 0; 1678*7c478bd9Sstevel@tonic-gate while ((ehcip->ehci_reclaim_list != NULL) && (i++ < 3)) { 1679*7c478bd9Sstevel@tonic-gate ehci_handle_endpoint_reclaimation(ehcip); 1680*7c478bd9Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip); 1681*7c478bd9Sstevel@tonic-gate } 1682*7c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_reclaim_list == NULL); 1683*7c478bd9Sstevel@tonic-gate 1684*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1685*7c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: Disable HC QH list processing"); 1686*7c478bd9Sstevel@tonic-gate 1687*7c478bd9Sstevel@tonic-gate /* Disable all EHCI QH list processing */ 1688*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) & 1689*7c478bd9Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE))); 1690*7c478bd9Sstevel@tonic-gate 1691*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1692*7c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: Disable HC interrupts"); 1693*7c478bd9Sstevel@tonic-gate 1694*7c478bd9Sstevel@tonic-gate /* Disable all EHCI interrupts */ 1695*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0); 1696*7c478bd9Sstevel@tonic-gate 1697*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1698*7c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: Wait for the next SOF"); 1699*7c478bd9Sstevel@tonic-gate 1700*7c478bd9Sstevel@tonic-gate /* Wait for the next SOF */ 1701*7c478bd9Sstevel@tonic-gate if (ehci_wait_for_sof(ehcip) != USB_SUCCESS) { 1702*7c478bd9Sstevel@tonic-gate 1703*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1704*7c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: ehci host controller suspend failed"); 1705*7c478bd9Sstevel@tonic-gate 1706*7c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 1707*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1708*7c478bd9Sstevel@tonic-gate } 1709*7c478bd9Sstevel@tonic-gate 1710*7c478bd9Sstevel@tonic-gate /* 1711*7c478bd9Sstevel@tonic-gate * Stop the ehci host controller 1712*7c478bd9Sstevel@tonic-gate * if usb keyboard is not connected. 1713*7c478bd9Sstevel@tonic-gate */ 1714*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_polled_kbd_count == 0) { 1715*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 1716*7c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN); 1717*7c478bd9Sstevel@tonic-gate } 1718*7c478bd9Sstevel@tonic-gate 1719*7c478bd9Sstevel@tonic-gate /* Set host controller soft state to suspend */ 1720*7c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_SUSPEND_STATE; 1721*7c478bd9Sstevel@tonic-gate 1722*7c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 1723*7c478bd9Sstevel@tonic-gate 1724*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1725*7c478bd9Sstevel@tonic-gate } 1726*7c478bd9Sstevel@tonic-gate 1727*7c478bd9Sstevel@tonic-gate 1728*7c478bd9Sstevel@tonic-gate /* 1729*7c478bd9Sstevel@tonic-gate * ehci_cpr_resume 1730*7c478bd9Sstevel@tonic-gate */ 1731*7c478bd9Sstevel@tonic-gate int 1732*7c478bd9Sstevel@tonic-gate ehci_cpr_resume(ehci_state_t *ehcip) 1733*7c478bd9Sstevel@tonic-gate { 1734*7c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 1735*7c478bd9Sstevel@tonic-gate 1736*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1737*7c478bd9Sstevel@tonic-gate "ehci_cpr_resume: Restart the controller"); 1738*7c478bd9Sstevel@tonic-gate 1739*7c478bd9Sstevel@tonic-gate /* Cleanup ehci specific information across cpr */ 1740*7c478bd9Sstevel@tonic-gate ehci_cpr_cleanup(ehcip); 1741*7c478bd9Sstevel@tonic-gate 1742*7c478bd9Sstevel@tonic-gate /* Restart the controller */ 1743*7c478bd9Sstevel@tonic-gate if (ehci_init_ctlr(ehcip) != DDI_SUCCESS) { 1744*7c478bd9Sstevel@tonic-gate 1745*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1746*7c478bd9Sstevel@tonic-gate "ehci_cpr_resume: ehci host controller resume failed "); 1747*7c478bd9Sstevel@tonic-gate 1748*7c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 1749*7c478bd9Sstevel@tonic-gate 1750*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1751*7c478bd9Sstevel@tonic-gate } 1752*7c478bd9Sstevel@tonic-gate 1753*7c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 1754*7c478bd9Sstevel@tonic-gate 1755*7c478bd9Sstevel@tonic-gate /* Now resume the root hub */ 1756*7c478bd9Sstevel@tonic-gate if (usba_hubdi_attach(ehcip->ehci_dip, DDI_RESUME) != DDI_SUCCESS) { 1757*7c478bd9Sstevel@tonic-gate 1758*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1759*7c478bd9Sstevel@tonic-gate } 1760*7c478bd9Sstevel@tonic-gate 1761*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1762*7c478bd9Sstevel@tonic-gate } 1763*7c478bd9Sstevel@tonic-gate 1764*7c478bd9Sstevel@tonic-gate 1765*7c478bd9Sstevel@tonic-gate /* 1766*7c478bd9Sstevel@tonic-gate * Bandwidth Allocation functions 1767*7c478bd9Sstevel@tonic-gate */ 1768*7c478bd9Sstevel@tonic-gate 1769*7c478bd9Sstevel@tonic-gate /* 1770*7c478bd9Sstevel@tonic-gate * ehci_allocate_bandwidth: 1771*7c478bd9Sstevel@tonic-gate * 1772*7c478bd9Sstevel@tonic-gate * Figure out whether or not this interval may be supported. Return the index 1773*7c478bd9Sstevel@tonic-gate * into the lattice if it can be supported. Return allocation failure if it 1774*7c478bd9Sstevel@tonic-gate * can not be supported. 1775*7c478bd9Sstevel@tonic-gate */ 1776*7c478bd9Sstevel@tonic-gate int 1777*7c478bd9Sstevel@tonic-gate ehci_allocate_bandwidth( 1778*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1779*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1780*7c478bd9Sstevel@tonic-gate uint_t *pnode, 1781*7c478bd9Sstevel@tonic-gate uchar_t *smask, 1782*7c478bd9Sstevel@tonic-gate uchar_t *cmask) 1783*7c478bd9Sstevel@tonic-gate { 1784*7c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 1785*7c478bd9Sstevel@tonic-gate 1786*7c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 1787*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1788*7c478bd9Sstevel@tonic-gate 1789*7c478bd9Sstevel@tonic-gate /* Reset the pnode to the last checked pnode */ 1790*7c478bd9Sstevel@tonic-gate *pnode = 0; 1791*7c478bd9Sstevel@tonic-gate 1792*7c478bd9Sstevel@tonic-gate /* Allocate high speed bandwidth */ 1793*7c478bd9Sstevel@tonic-gate if ((error = ehci_allocate_high_speed_bandwidth(ehcip, 1794*7c478bd9Sstevel@tonic-gate ph, pnode, smask, cmask)) != USB_SUCCESS) { 1795*7c478bd9Sstevel@tonic-gate 1796*7c478bd9Sstevel@tonic-gate return (error); 1797*7c478bd9Sstevel@tonic-gate } 1798*7c478bd9Sstevel@tonic-gate 1799*7c478bd9Sstevel@tonic-gate /* 1800*7c478bd9Sstevel@tonic-gate * For low/full speed usb devices, allocate classic TT bandwidth 1801*7c478bd9Sstevel@tonic-gate * in additional to high speed bandwidth. 1802*7c478bd9Sstevel@tonic-gate */ 1803*7c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) { 1804*7c478bd9Sstevel@tonic-gate 1805*7c478bd9Sstevel@tonic-gate /* Allocate classic TT bandwidth */ 1806*7c478bd9Sstevel@tonic-gate if ((error = ehci_allocate_classic_tt_bandwidth( 1807*7c478bd9Sstevel@tonic-gate ehcip, ph, *pnode)) != USB_SUCCESS) { 1808*7c478bd9Sstevel@tonic-gate 1809*7c478bd9Sstevel@tonic-gate /* Deallocate high speed bandwidth */ 1810*7c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth( 1811*7c478bd9Sstevel@tonic-gate ehcip, ph, *pnode, *smask, *cmask); 1812*7c478bd9Sstevel@tonic-gate } 1813*7c478bd9Sstevel@tonic-gate } 1814*7c478bd9Sstevel@tonic-gate 1815*7c478bd9Sstevel@tonic-gate return (error); 1816*7c478bd9Sstevel@tonic-gate } 1817*7c478bd9Sstevel@tonic-gate 1818*7c478bd9Sstevel@tonic-gate 1819*7c478bd9Sstevel@tonic-gate /* 1820*7c478bd9Sstevel@tonic-gate * ehci_allocate_high_speed_bandwidth: 1821*7c478bd9Sstevel@tonic-gate * 1822*7c478bd9Sstevel@tonic-gate * Allocate high speed bandwidth for the low/full/high speed interrupt and 1823*7c478bd9Sstevel@tonic-gate * isochronous endpoints. 1824*7c478bd9Sstevel@tonic-gate */ 1825*7c478bd9Sstevel@tonic-gate static int 1826*7c478bd9Sstevel@tonic-gate ehci_allocate_high_speed_bandwidth( 1827*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1828*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1829*7c478bd9Sstevel@tonic-gate uint_t *pnode, 1830*7c478bd9Sstevel@tonic-gate uchar_t *smask, 1831*7c478bd9Sstevel@tonic-gate uchar_t *cmask) 1832*7c478bd9Sstevel@tonic-gate { 1833*7c478bd9Sstevel@tonic-gate uint_t sbandwidth, cbandwidth; 1834*7c478bd9Sstevel@tonic-gate int interval; 1835*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 1836*7c478bd9Sstevel@tonic-gate usba_device_t *child_ud; 1837*7c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 1838*7c478bd9Sstevel@tonic-gate int error; 1839*7c478bd9Sstevel@tonic-gate 1840*7c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 1841*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1842*7c478bd9Sstevel@tonic-gate 1843*7c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 1844*7c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 1845*7c478bd9Sstevel@tonic-gate 1846*7c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 1847*7c478bd9Sstevel@tonic-gate 1848*7c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 1849*7c478bd9Sstevel@tonic-gate port_status = ph->p_usba_device->usb_port_status; 1850*7c478bd9Sstevel@tonic-gate 1851*7c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 1852*7c478bd9Sstevel@tonic-gate 1853*7c478bd9Sstevel@tonic-gate /* 1854*7c478bd9Sstevel@tonic-gate * Calculate the length in bytes of a transaction on this 1855*7c478bd9Sstevel@tonic-gate * periodic endpoint. Return failure if maximum packet is 1856*7c478bd9Sstevel@tonic-gate * zero. 1857*7c478bd9Sstevel@tonic-gate */ 1858*7c478bd9Sstevel@tonic-gate error = ehci_compute_high_speed_bandwidth(ehcip, endpoint, 1859*7c478bd9Sstevel@tonic-gate port_status, &sbandwidth, &cbandwidth); 1860*7c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 1861*7c478bd9Sstevel@tonic-gate 1862*7c478bd9Sstevel@tonic-gate return (error); 1863*7c478bd9Sstevel@tonic-gate } 1864*7c478bd9Sstevel@tonic-gate 1865*7c478bd9Sstevel@tonic-gate /* 1866*7c478bd9Sstevel@tonic-gate * Adjust polling interval to be a power of 2. 1867*7c478bd9Sstevel@tonic-gate * If this interval can't be supported, return 1868*7c478bd9Sstevel@tonic-gate * allocation failure. 1869*7c478bd9Sstevel@tonic-gate */ 1870*7c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 1871*7c478bd9Sstevel@tonic-gate if (interval == USB_FAILURE) { 1872*7c478bd9Sstevel@tonic-gate 1873*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 1874*7c478bd9Sstevel@tonic-gate } 1875*7c478bd9Sstevel@tonic-gate 1876*7c478bd9Sstevel@tonic-gate if (port_status == USBA_HIGH_SPEED_DEV) { 1877*7c478bd9Sstevel@tonic-gate /* Allocate bandwidth for high speed devices, except ITD */ 1878*7c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_hs_mask(ehcip, smask, pnode, 1879*7c478bd9Sstevel@tonic-gate endpoint, sbandwidth, interval); 1880*7c478bd9Sstevel@tonic-gate *cmask = 0x00; 1881*7c478bd9Sstevel@tonic-gate 1882*7c478bd9Sstevel@tonic-gate } else { 1883*7c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) == 1884*7c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR) { 1885*7c478bd9Sstevel@tonic-gate 1886*7c478bd9Sstevel@tonic-gate /* Allocate bandwidth for low speed interrupt */ 1887*7c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_ls_intr_mask(ehcip, 1888*7c478bd9Sstevel@tonic-gate smask, cmask, pnode, sbandwidth, cbandwidth, 1889*7c478bd9Sstevel@tonic-gate interval); 1890*7c478bd9Sstevel@tonic-gate } else { 1891*7c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 1892*7c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 1893*7c478bd9Sstevel@tonic-gate 1894*7c478bd9Sstevel@tonic-gate /* Allocate bandwidth for sitd in */ 1895*7c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_sitd_in_mask(ehcip, 1896*7c478bd9Sstevel@tonic-gate smask, cmask, pnode, sbandwidth, cbandwidth, 1897*7c478bd9Sstevel@tonic-gate interval); 1898*7c478bd9Sstevel@tonic-gate } else { 1899*7c478bd9Sstevel@tonic-gate 1900*7c478bd9Sstevel@tonic-gate /* Allocate bandwidth for sitd out */ 1901*7c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_sitd_out_mask(ehcip, 1902*7c478bd9Sstevel@tonic-gate smask, pnode, sbandwidth, interval); 1903*7c478bd9Sstevel@tonic-gate *cmask = 0x00; 1904*7c478bd9Sstevel@tonic-gate } 1905*7c478bd9Sstevel@tonic-gate } 1906*7c478bd9Sstevel@tonic-gate } 1907*7c478bd9Sstevel@tonic-gate 1908*7c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 1909*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 1910*7c478bd9Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: Reached maximum " 1911*7c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth for a " 1912*7c478bd9Sstevel@tonic-gate "given high-speed periodic endpoint"); 1913*7c478bd9Sstevel@tonic-gate 1914*7c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 1915*7c478bd9Sstevel@tonic-gate } 1916*7c478bd9Sstevel@tonic-gate 1917*7c478bd9Sstevel@tonic-gate return (error); 1918*7c478bd9Sstevel@tonic-gate } 1919*7c478bd9Sstevel@tonic-gate 1920*7c478bd9Sstevel@tonic-gate 1921*7c478bd9Sstevel@tonic-gate /* 1922*7c478bd9Sstevel@tonic-gate * ehci_allocate_classic_tt_speed_bandwidth: 1923*7c478bd9Sstevel@tonic-gate * 1924*7c478bd9Sstevel@tonic-gate * Allocate classic TT bandwidth for the low/full speed interrupt and 1925*7c478bd9Sstevel@tonic-gate * isochronous endpoints. 1926*7c478bd9Sstevel@tonic-gate */ 1927*7c478bd9Sstevel@tonic-gate static int 1928*7c478bd9Sstevel@tonic-gate ehci_allocate_classic_tt_bandwidth( 1929*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1930*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1931*7c478bd9Sstevel@tonic-gate uint_t pnode) 1932*7c478bd9Sstevel@tonic-gate { 1933*7c478bd9Sstevel@tonic-gate uint_t bandwidth, min; 1934*7c478bd9Sstevel@tonic-gate uint_t height, leftmost, list; 1935*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 1936*7c478bd9Sstevel@tonic-gate usba_device_t *child_ud, *parent_ud; 1937*7c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 1938*7c478bd9Sstevel@tonic-gate int i, interval; 1939*7c478bd9Sstevel@tonic-gate 1940*7c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 1941*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 1942*7c478bd9Sstevel@tonic-gate 1943*7c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 1944*7c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 1945*7c478bd9Sstevel@tonic-gate 1946*7c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 1947*7c478bd9Sstevel@tonic-gate 1948*7c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 1949*7c478bd9Sstevel@tonic-gate port_status = child_ud->usb_port_status; 1950*7c478bd9Sstevel@tonic-gate 1951*7c478bd9Sstevel@tonic-gate /* Get the parent high speed hub's usba device structure */ 1952*7c478bd9Sstevel@tonic-gate parent_ud = child_ud->usb_hs_hub_usba_dev; 1953*7c478bd9Sstevel@tonic-gate 1954*7c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 1955*7c478bd9Sstevel@tonic-gate 1956*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 1957*7c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: " 1958*7c478bd9Sstevel@tonic-gate "child_ud 0x%p parent_ud 0x%p", child_ud, parent_ud); 1959*7c478bd9Sstevel@tonic-gate 1960*7c478bd9Sstevel@tonic-gate /* 1961*7c478bd9Sstevel@tonic-gate * Calculate the length in bytes of a transaction on this 1962*7c478bd9Sstevel@tonic-gate * periodic endpoint. Return failure if maximum packet is 1963*7c478bd9Sstevel@tonic-gate * zero. 1964*7c478bd9Sstevel@tonic-gate */ 1965*7c478bd9Sstevel@tonic-gate if (ehci_compute_classic_bandwidth(endpoint, 1966*7c478bd9Sstevel@tonic-gate port_status, &bandwidth) != USB_SUCCESS) { 1967*7c478bd9Sstevel@tonic-gate 1968*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 1969*7c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Periodic endpoint " 1970*7c478bd9Sstevel@tonic-gate "with zero endpoint maximum packet size is not supported"); 1971*7c478bd9Sstevel@tonic-gate 1972*7c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 1973*7c478bd9Sstevel@tonic-gate } 1974*7c478bd9Sstevel@tonic-gate 1975*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 1976*7c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: bandwidth %d", bandwidth); 1977*7c478bd9Sstevel@tonic-gate 1978*7c478bd9Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex); 1979*7c478bd9Sstevel@tonic-gate 1980*7c478bd9Sstevel@tonic-gate /* 1981*7c478bd9Sstevel@tonic-gate * If the length in bytes plus the allocated bandwidth exceeds 1982*7c478bd9Sstevel@tonic-gate * the maximum, return bandwidth allocation failure. 1983*7c478bd9Sstevel@tonic-gate */ 1984*7c478bd9Sstevel@tonic-gate if ((parent_ud->usb_hs_hub_min_bandwidth + bandwidth) > 1985*7c478bd9Sstevel@tonic-gate FS_PERIODIC_BANDWIDTH) { 1986*7c478bd9Sstevel@tonic-gate 1987*7c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 1988*7c478bd9Sstevel@tonic-gate 1989*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 1990*7c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Reached maximum " 1991*7c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth for a " 1992*7c478bd9Sstevel@tonic-gate "given low/full speed periodic endpoint"); 1993*7c478bd9Sstevel@tonic-gate 1994*7c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 1995*7c478bd9Sstevel@tonic-gate } 1996*7c478bd9Sstevel@tonic-gate 1997*7c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 1998*7c478bd9Sstevel@tonic-gate 1999*7c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 2000*7c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 2001*7c478bd9Sstevel@tonic-gate 2002*7c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 2003*7c478bd9Sstevel@tonic-gate height = ehci_lattice_height(interval); 2004*7c478bd9Sstevel@tonic-gate 2005*7c478bd9Sstevel@tonic-gate /* Find the leftmost leaf in the subtree specified by the node. */ 2006*7c478bd9Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height); 2007*7c478bd9Sstevel@tonic-gate 2008*7c478bd9Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex); 2009*7c478bd9Sstevel@tonic-gate 2010*7c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) { 2011*7c478bd9Sstevel@tonic-gate list = ehci_index[leftmost + i]; 2012*7c478bd9Sstevel@tonic-gate 2013*7c478bd9Sstevel@tonic-gate if ((parent_ud->usb_hs_hub_bandwidth[list] + 2014*7c478bd9Sstevel@tonic-gate bandwidth) > FS_PERIODIC_BANDWIDTH) { 2015*7c478bd9Sstevel@tonic-gate 2016*7c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 2017*7c478bd9Sstevel@tonic-gate 2018*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 2019*7c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Reached " 2020*7c478bd9Sstevel@tonic-gate "maximum bandwidth value and cannot allocate " 2021*7c478bd9Sstevel@tonic-gate "bandwidth for low/full periodic endpoint"); 2022*7c478bd9Sstevel@tonic-gate 2023*7c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 2024*7c478bd9Sstevel@tonic-gate } 2025*7c478bd9Sstevel@tonic-gate } 2026*7c478bd9Sstevel@tonic-gate 2027*7c478bd9Sstevel@tonic-gate /* 2028*7c478bd9Sstevel@tonic-gate * All the leaves for this node must be updated with the bandwidth. 2029*7c478bd9Sstevel@tonic-gate */ 2030*7c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) { 2031*7c478bd9Sstevel@tonic-gate list = ehci_index[leftmost + i]; 2032*7c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_bandwidth[list] += bandwidth; 2033*7c478bd9Sstevel@tonic-gate } 2034*7c478bd9Sstevel@tonic-gate 2035*7c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */ 2036*7c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[0]; 2037*7c478bd9Sstevel@tonic-gate 2038*7c478bd9Sstevel@tonic-gate for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) { 2039*7c478bd9Sstevel@tonic-gate if (parent_ud->usb_hs_hub_bandwidth[i] < min) { 2040*7c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[i]; 2041*7c478bd9Sstevel@tonic-gate } 2042*7c478bd9Sstevel@tonic-gate } 2043*7c478bd9Sstevel@tonic-gate 2044*7c478bd9Sstevel@tonic-gate /* Save the minimum for later use */ 2045*7c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_min_bandwidth = min; 2046*7c478bd9Sstevel@tonic-gate 2047*7c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 2048*7c478bd9Sstevel@tonic-gate 2049*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 2050*7c478bd9Sstevel@tonic-gate } 2051*7c478bd9Sstevel@tonic-gate 2052*7c478bd9Sstevel@tonic-gate 2053*7c478bd9Sstevel@tonic-gate /* 2054*7c478bd9Sstevel@tonic-gate * ehci_deallocate_bandwidth: 2055*7c478bd9Sstevel@tonic-gate * 2056*7c478bd9Sstevel@tonic-gate * Deallocate bandwidth for the given node in the lattice and the length 2057*7c478bd9Sstevel@tonic-gate * of transfer. 2058*7c478bd9Sstevel@tonic-gate */ 2059*7c478bd9Sstevel@tonic-gate void 2060*7c478bd9Sstevel@tonic-gate ehci_deallocate_bandwidth( 2061*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2062*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2063*7c478bd9Sstevel@tonic-gate uint_t pnode, 2064*7c478bd9Sstevel@tonic-gate uchar_t smask, 2065*7c478bd9Sstevel@tonic-gate uchar_t cmask) 2066*7c478bd9Sstevel@tonic-gate { 2067*7c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 2068*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 2069*7c478bd9Sstevel@tonic-gate 2070*7c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth(ehcip, ph, pnode, smask, cmask); 2071*7c478bd9Sstevel@tonic-gate 2072*7c478bd9Sstevel@tonic-gate /* 2073*7c478bd9Sstevel@tonic-gate * For low/full speed usb devices, deallocate classic TT bandwidth 2074*7c478bd9Sstevel@tonic-gate * in additional to high speed bandwidth. 2075*7c478bd9Sstevel@tonic-gate */ 2076*7c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) { 2077*7c478bd9Sstevel@tonic-gate 2078*7c478bd9Sstevel@tonic-gate /* Deallocate classic TT bandwidth */ 2079*7c478bd9Sstevel@tonic-gate ehci_deallocate_classic_tt_bandwidth(ehcip, ph, pnode); 2080*7c478bd9Sstevel@tonic-gate } 2081*7c478bd9Sstevel@tonic-gate } 2082*7c478bd9Sstevel@tonic-gate 2083*7c478bd9Sstevel@tonic-gate 2084*7c478bd9Sstevel@tonic-gate /* 2085*7c478bd9Sstevel@tonic-gate * ehci_deallocate_high_speed_bandwidth: 2086*7c478bd9Sstevel@tonic-gate * 2087*7c478bd9Sstevel@tonic-gate * Deallocate high speed bandwidth of a interrupt or isochronous endpoint. 2088*7c478bd9Sstevel@tonic-gate */ 2089*7c478bd9Sstevel@tonic-gate static void 2090*7c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth( 2091*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2092*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2093*7c478bd9Sstevel@tonic-gate uint_t pnode, 2094*7c478bd9Sstevel@tonic-gate uchar_t smask, 2095*7c478bd9Sstevel@tonic-gate uchar_t cmask) 2096*7c478bd9Sstevel@tonic-gate { 2097*7c478bd9Sstevel@tonic-gate uint_t height, leftmost; 2098*7c478bd9Sstevel@tonic-gate uint_t list_count; 2099*7c478bd9Sstevel@tonic-gate uint_t sbandwidth, cbandwidth; 2100*7c478bd9Sstevel@tonic-gate int interval; 2101*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 2102*7c478bd9Sstevel@tonic-gate usba_device_t *child_ud; 2103*7c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 2104*7c478bd9Sstevel@tonic-gate 2105*7c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 2106*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 2107*7c478bd9Sstevel@tonic-gate 2108*7c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 2109*7c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 2110*7c478bd9Sstevel@tonic-gate 2111*7c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 2112*7c478bd9Sstevel@tonic-gate 2113*7c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 2114*7c478bd9Sstevel@tonic-gate port_status = ph->p_usba_device->usb_port_status; 2115*7c478bd9Sstevel@tonic-gate 2116*7c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 2117*7c478bd9Sstevel@tonic-gate 2118*7c478bd9Sstevel@tonic-gate (void) ehci_compute_high_speed_bandwidth(ehcip, endpoint, 2119*7c478bd9Sstevel@tonic-gate port_status, &sbandwidth, &cbandwidth); 2120*7c478bd9Sstevel@tonic-gate 2121*7c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 2122*7c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 2123*7c478bd9Sstevel@tonic-gate 2124*7c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 2125*7c478bd9Sstevel@tonic-gate height = ehci_lattice_height(interval); 2126*7c478bd9Sstevel@tonic-gate 2127*7c478bd9Sstevel@tonic-gate /* 2128*7c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node 2129*7c478bd9Sstevel@tonic-gate */ 2130*7c478bd9Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height); 2131*7c478bd9Sstevel@tonic-gate 2132*7c478bd9Sstevel@tonic-gate list_count = EHCI_NUM_INTR_QH_LISTS/interval; 2133*7c478bd9Sstevel@tonic-gate 2134*7c478bd9Sstevel@tonic-gate /* Delete the bandwidth from the appropriate lists */ 2135*7c478bd9Sstevel@tonic-gate if (port_status == USBA_HIGH_SPEED_DEV) { 2136*7c478bd9Sstevel@tonic-gate 2137*7c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth, 2138*7c478bd9Sstevel@tonic-gate leftmost, list_count, smask); 2139*7c478bd9Sstevel@tonic-gate } else { 2140*7c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) == 2141*7c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR) { 2142*7c478bd9Sstevel@tonic-gate 2143*7c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth, 2144*7c478bd9Sstevel@tonic-gate leftmost, list_count, smask); 2145*7c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -cbandwidth, 2146*7c478bd9Sstevel@tonic-gate leftmost, list_count, cmask); 2147*7c478bd9Sstevel@tonic-gate } else { 2148*7c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 2149*7c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 2150*7c478bd9Sstevel@tonic-gate 2151*7c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth, 2152*7c478bd9Sstevel@tonic-gate leftmost, list_count, smask); 2153*7c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, 2154*7c478bd9Sstevel@tonic-gate -MAX_UFRAME_SITD_XFER, leftmost, 2155*7c478bd9Sstevel@tonic-gate list_count, cmask); 2156*7c478bd9Sstevel@tonic-gate } else { 2157*7c478bd9Sstevel@tonic-gate 2158*7c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, 2159*7c478bd9Sstevel@tonic-gate -MAX_UFRAME_SITD_XFER, leftmost, 2160*7c478bd9Sstevel@tonic-gate list_count, smask); 2161*7c478bd9Sstevel@tonic-gate } 2162*7c478bd9Sstevel@tonic-gate } 2163*7c478bd9Sstevel@tonic-gate } 2164*7c478bd9Sstevel@tonic-gate } 2165*7c478bd9Sstevel@tonic-gate 2166*7c478bd9Sstevel@tonic-gate /* 2167*7c478bd9Sstevel@tonic-gate * ehci_deallocate_classic_tt_bandwidth: 2168*7c478bd9Sstevel@tonic-gate * 2169*7c478bd9Sstevel@tonic-gate * Deallocate high speed bandwidth of a interrupt or isochronous endpoint. 2170*7c478bd9Sstevel@tonic-gate */ 2171*7c478bd9Sstevel@tonic-gate static void 2172*7c478bd9Sstevel@tonic-gate ehci_deallocate_classic_tt_bandwidth( 2173*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2174*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 2175*7c478bd9Sstevel@tonic-gate uint_t pnode) 2176*7c478bd9Sstevel@tonic-gate { 2177*7c478bd9Sstevel@tonic-gate uint_t bandwidth, height, leftmost, list, min; 2178*7c478bd9Sstevel@tonic-gate int i, interval; 2179*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 2180*7c478bd9Sstevel@tonic-gate usba_device_t *child_ud, *parent_ud; 2181*7c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 2182*7c478bd9Sstevel@tonic-gate 2183*7c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 2184*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 2185*7c478bd9Sstevel@tonic-gate 2186*7c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 2187*7c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 2188*7c478bd9Sstevel@tonic-gate 2189*7c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 2190*7c478bd9Sstevel@tonic-gate 2191*7c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 2192*7c478bd9Sstevel@tonic-gate port_status = child_ud->usb_port_status; 2193*7c478bd9Sstevel@tonic-gate 2194*7c478bd9Sstevel@tonic-gate /* Get the parent high speed hub's usba device structure */ 2195*7c478bd9Sstevel@tonic-gate parent_ud = child_ud->usb_hs_hub_usba_dev; 2196*7c478bd9Sstevel@tonic-gate 2197*7c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 2198*7c478bd9Sstevel@tonic-gate 2199*7c478bd9Sstevel@tonic-gate /* Obtain the bandwidth */ 2200*7c478bd9Sstevel@tonic-gate (void) ehci_compute_classic_bandwidth(endpoint, 2201*7c478bd9Sstevel@tonic-gate port_status, &bandwidth); 2202*7c478bd9Sstevel@tonic-gate 2203*7c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 2204*7c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 2205*7c478bd9Sstevel@tonic-gate 2206*7c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 2207*7c478bd9Sstevel@tonic-gate height = ehci_lattice_height(interval); 2208*7c478bd9Sstevel@tonic-gate 2209*7c478bd9Sstevel@tonic-gate /* Find the leftmost leaf in the subtree specified by the node */ 2210*7c478bd9Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height); 2211*7c478bd9Sstevel@tonic-gate 2212*7c478bd9Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex); 2213*7c478bd9Sstevel@tonic-gate 2214*7c478bd9Sstevel@tonic-gate /* Delete the bandwidth from the appropriate lists */ 2215*7c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) { 2216*7c478bd9Sstevel@tonic-gate list = ehci_index[leftmost + i]; 2217*7c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_bandwidth[list] -= bandwidth; 2218*7c478bd9Sstevel@tonic-gate } 2219*7c478bd9Sstevel@tonic-gate 2220*7c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */ 2221*7c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[0]; 2222*7c478bd9Sstevel@tonic-gate 2223*7c478bd9Sstevel@tonic-gate for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) { 2224*7c478bd9Sstevel@tonic-gate if (parent_ud->usb_hs_hub_bandwidth[i] < min) { 2225*7c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[i]; 2226*7c478bd9Sstevel@tonic-gate } 2227*7c478bd9Sstevel@tonic-gate } 2228*7c478bd9Sstevel@tonic-gate 2229*7c478bd9Sstevel@tonic-gate /* Save the minimum for later use */ 2230*7c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_min_bandwidth = min; 2231*7c478bd9Sstevel@tonic-gate 2232*7c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 2233*7c478bd9Sstevel@tonic-gate } 2234*7c478bd9Sstevel@tonic-gate 2235*7c478bd9Sstevel@tonic-gate 2236*7c478bd9Sstevel@tonic-gate /* 2237*7c478bd9Sstevel@tonic-gate * ehci_compute_high_speed_bandwidth: 2238*7c478bd9Sstevel@tonic-gate * 2239*7c478bd9Sstevel@tonic-gate * Given a periodic endpoint (interrupt or isochronous) determine the total 2240*7c478bd9Sstevel@tonic-gate * bandwidth for one transaction. The EHCI host controller traverses the 2241*7c478bd9Sstevel@tonic-gate * endpoint descriptor lists on a first-come-first-serve basis. When the HC 2242*7c478bd9Sstevel@tonic-gate * services an endpoint, only a single transaction attempt is made. The HC 2243*7c478bd9Sstevel@tonic-gate * moves to the next Endpoint Descriptor after the first transaction attempt 2244*7c478bd9Sstevel@tonic-gate * rather than finishing the entire Transfer Descriptor. Therefore, when a 2245*7c478bd9Sstevel@tonic-gate * Transfer Descriptor is inserted into the lattice, we will only count the 2246*7c478bd9Sstevel@tonic-gate * number of bytes for one transaction. 2247*7c478bd9Sstevel@tonic-gate * 2248*7c478bd9Sstevel@tonic-gate * The following are the formulas used for calculating bandwidth in terms 2249*7c478bd9Sstevel@tonic-gate * bytes and it is for the single USB high speed transaction. The protocol 2250*7c478bd9Sstevel@tonic-gate * overheads will be different for each of type of USB transfer & all these 2251*7c478bd9Sstevel@tonic-gate * formulas & protocol overheads are derived from the 5.11.3 section of the 2252*7c478bd9Sstevel@tonic-gate * USB 2.0 Specification. 2253*7c478bd9Sstevel@tonic-gate * 2254*7c478bd9Sstevel@tonic-gate * High-Speed: 2255*7c478bd9Sstevel@tonic-gate * Protocol overhead + ((MaxPktSz * 7)/6) + Host_Delay 2256*7c478bd9Sstevel@tonic-gate * 2257*7c478bd9Sstevel@tonic-gate * Split Transaction: (Low/Full speed devices connected behind usb2.0 hub) 2258*7c478bd9Sstevel@tonic-gate * 2259*7c478bd9Sstevel@tonic-gate * Protocol overhead + Split transaction overhead + 2260*7c478bd9Sstevel@tonic-gate * ((MaxPktSz * 7)/6) + Host_Delay; 2261*7c478bd9Sstevel@tonic-gate */ 2262*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2263*7c478bd9Sstevel@tonic-gate static int 2264*7c478bd9Sstevel@tonic-gate ehci_compute_high_speed_bandwidth( 2265*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2266*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 2267*7c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 2268*7c478bd9Sstevel@tonic-gate uint_t *sbandwidth, 2269*7c478bd9Sstevel@tonic-gate uint_t *cbandwidth) 2270*7c478bd9Sstevel@tonic-gate { 2271*7c478bd9Sstevel@tonic-gate ushort_t maxpacketsize = endpoint->wMaxPacketSize; 2272*7c478bd9Sstevel@tonic-gate 2273*7c478bd9Sstevel@tonic-gate /* Return failure if endpoint maximum packet is zero */ 2274*7c478bd9Sstevel@tonic-gate if (maxpacketsize == 0) { 2275*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 2276*7c478bd9Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: Periodic endpoint " 2277*7c478bd9Sstevel@tonic-gate "with zero endpoint maximum packet size is not supported"); 2278*7c478bd9Sstevel@tonic-gate 2279*7c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 2280*7c478bd9Sstevel@tonic-gate } 2281*7c478bd9Sstevel@tonic-gate 2282*7c478bd9Sstevel@tonic-gate /* Add bit-stuffing overhead */ 2283*7c478bd9Sstevel@tonic-gate maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6); 2284*7c478bd9Sstevel@tonic-gate 2285*7c478bd9Sstevel@tonic-gate /* Add Host Controller specific delay to required bandwidth */ 2286*7c478bd9Sstevel@tonic-gate *sbandwidth = EHCI_HOST_CONTROLLER_DELAY; 2287*7c478bd9Sstevel@tonic-gate 2288*7c478bd9Sstevel@tonic-gate /* Add xfer specific protocol overheads */ 2289*7c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 2290*7c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) { 2291*7c478bd9Sstevel@tonic-gate /* High speed interrupt transaction */ 2292*7c478bd9Sstevel@tonic-gate *sbandwidth += HS_NON_ISOC_PROTO_OVERHEAD; 2293*7c478bd9Sstevel@tonic-gate } else { 2294*7c478bd9Sstevel@tonic-gate /* Isochronous transaction */ 2295*7c478bd9Sstevel@tonic-gate *sbandwidth += HS_ISOC_PROTO_OVERHEAD; 2296*7c478bd9Sstevel@tonic-gate } 2297*7c478bd9Sstevel@tonic-gate 2298*7c478bd9Sstevel@tonic-gate /* 2299*7c478bd9Sstevel@tonic-gate * For low/full speed devices, add split transaction specific 2300*7c478bd9Sstevel@tonic-gate * overheads. 2301*7c478bd9Sstevel@tonic-gate */ 2302*7c478bd9Sstevel@tonic-gate if (port_status != USBA_HIGH_SPEED_DEV) { 2303*7c478bd9Sstevel@tonic-gate /* 2304*7c478bd9Sstevel@tonic-gate * Add start and complete split transaction 2305*7c478bd9Sstevel@tonic-gate * tokens overheads. 2306*7c478bd9Sstevel@tonic-gate */ 2307*7c478bd9Sstevel@tonic-gate *cbandwidth = *sbandwidth + COMPLETE_SPLIT_OVERHEAD; 2308*7c478bd9Sstevel@tonic-gate *sbandwidth += START_SPLIT_OVERHEAD; 2309*7c478bd9Sstevel@tonic-gate 2310*7c478bd9Sstevel@tonic-gate /* Add data overhead depending on data direction */ 2311*7c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 2312*7c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 2313*7c478bd9Sstevel@tonic-gate *cbandwidth += maxpacketsize; 2314*7c478bd9Sstevel@tonic-gate } else { 2315*7c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 2316*7c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) { 2317*7c478bd9Sstevel@tonic-gate /* There is no compete splits for out */ 2318*7c478bd9Sstevel@tonic-gate *cbandwidth = 0; 2319*7c478bd9Sstevel@tonic-gate } 2320*7c478bd9Sstevel@tonic-gate *sbandwidth += maxpacketsize; 2321*7c478bd9Sstevel@tonic-gate } 2322*7c478bd9Sstevel@tonic-gate } else { 2323*7c478bd9Sstevel@tonic-gate uint_t xactions; 2324*7c478bd9Sstevel@tonic-gate 2325*7c478bd9Sstevel@tonic-gate /* Get the max transactions per microframe */ 2326*7c478bd9Sstevel@tonic-gate xactions = ((maxpacketsize & USB_EP_MAX_XACTS_MASK) >> 2327*7c478bd9Sstevel@tonic-gate USB_EP_MAX_XACTS_SHIFT) + 1; 2328*7c478bd9Sstevel@tonic-gate 2329*7c478bd9Sstevel@tonic-gate /* High speed transaction */ 2330*7c478bd9Sstevel@tonic-gate *sbandwidth += maxpacketsize; 2331*7c478bd9Sstevel@tonic-gate 2332*7c478bd9Sstevel@tonic-gate /* Calculate bandwidth per micro-frame */ 2333*7c478bd9Sstevel@tonic-gate *sbandwidth *= xactions; 2334*7c478bd9Sstevel@tonic-gate 2335*7c478bd9Sstevel@tonic-gate *cbandwidth = 0; 2336*7c478bd9Sstevel@tonic-gate } 2337*7c478bd9Sstevel@tonic-gate 2338*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 2339*7c478bd9Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: " 2340*7c478bd9Sstevel@tonic-gate "Start split bandwidth %d Complete split bandwidth %d", 2341*7c478bd9Sstevel@tonic-gate *sbandwidth, *cbandwidth); 2342*7c478bd9Sstevel@tonic-gate 2343*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 2344*7c478bd9Sstevel@tonic-gate } 2345*7c478bd9Sstevel@tonic-gate 2346*7c478bd9Sstevel@tonic-gate 2347*7c478bd9Sstevel@tonic-gate /* 2348*7c478bd9Sstevel@tonic-gate * ehci_compute_classic_bandwidth: 2349*7c478bd9Sstevel@tonic-gate * 2350*7c478bd9Sstevel@tonic-gate * Given a periodic endpoint (interrupt or isochronous) determine the total 2351*7c478bd9Sstevel@tonic-gate * bandwidth for one transaction. The EHCI host controller traverses the 2352*7c478bd9Sstevel@tonic-gate * endpoint descriptor lists on a first-come-first-serve basis. When the HC 2353*7c478bd9Sstevel@tonic-gate * services an endpoint, only a single transaction attempt is made. The HC 2354*7c478bd9Sstevel@tonic-gate * moves to the next Endpoint Descriptor after the first transaction attempt 2355*7c478bd9Sstevel@tonic-gate * rather than finishing the entire Transfer Descriptor. Therefore, when a 2356*7c478bd9Sstevel@tonic-gate * Transfer Descriptor is inserted into the lattice, we will only count the 2357*7c478bd9Sstevel@tonic-gate * number of bytes for one transaction. 2358*7c478bd9Sstevel@tonic-gate * 2359*7c478bd9Sstevel@tonic-gate * The following are the formulas used for calculating bandwidth in terms 2360*7c478bd9Sstevel@tonic-gate * bytes and it is for the single USB high speed transaction. The protocol 2361*7c478bd9Sstevel@tonic-gate * overheads will be different for each of type of USB transfer & all these 2362*7c478bd9Sstevel@tonic-gate * formulas & protocol overheads are derived from the 5.11.3 section of the 2363*7c478bd9Sstevel@tonic-gate * USB 2.0 Specification. 2364*7c478bd9Sstevel@tonic-gate * 2365*7c478bd9Sstevel@tonic-gate * Low-Speed: 2366*7c478bd9Sstevel@tonic-gate * Protocol overhead + Hub LS overhead + 2367*7c478bd9Sstevel@tonic-gate * (Low Speed clock * ((MaxPktSz * 7)/6)) + TT_Delay 2368*7c478bd9Sstevel@tonic-gate * 2369*7c478bd9Sstevel@tonic-gate * Full-Speed: 2370*7c478bd9Sstevel@tonic-gate * Protocol overhead + ((MaxPktSz * 7)/6) + TT_Delay 2371*7c478bd9Sstevel@tonic-gate */ 2372*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2373*7c478bd9Sstevel@tonic-gate static int 2374*7c478bd9Sstevel@tonic-gate ehci_compute_classic_bandwidth( 2375*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 2376*7c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 2377*7c478bd9Sstevel@tonic-gate uint_t *bandwidth) 2378*7c478bd9Sstevel@tonic-gate { 2379*7c478bd9Sstevel@tonic-gate ushort_t maxpacketsize = endpoint->wMaxPacketSize; 2380*7c478bd9Sstevel@tonic-gate 2381*7c478bd9Sstevel@tonic-gate /* 2382*7c478bd9Sstevel@tonic-gate * If endpoint maximum packet is zero, then return immediately. 2383*7c478bd9Sstevel@tonic-gate */ 2384*7c478bd9Sstevel@tonic-gate if (maxpacketsize == 0) { 2385*7c478bd9Sstevel@tonic-gate 2386*7c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 2387*7c478bd9Sstevel@tonic-gate } 2388*7c478bd9Sstevel@tonic-gate 2389*7c478bd9Sstevel@tonic-gate /* Add TT delay to required bandwidth */ 2390*7c478bd9Sstevel@tonic-gate *bandwidth = TT_DELAY; 2391*7c478bd9Sstevel@tonic-gate 2392*7c478bd9Sstevel@tonic-gate /* Add bit-stuffing overhead */ 2393*7c478bd9Sstevel@tonic-gate maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6); 2394*7c478bd9Sstevel@tonic-gate 2395*7c478bd9Sstevel@tonic-gate switch (port_status) { 2396*7c478bd9Sstevel@tonic-gate case USBA_LOW_SPEED_DEV: 2397*7c478bd9Sstevel@tonic-gate /* Low speed interrupt transaction */ 2398*7c478bd9Sstevel@tonic-gate *bandwidth += (LOW_SPEED_PROTO_OVERHEAD + 2399*7c478bd9Sstevel@tonic-gate HUB_LOW_SPEED_PROTO_OVERHEAD + 2400*7c478bd9Sstevel@tonic-gate (LOW_SPEED_CLOCK * maxpacketsize)); 2401*7c478bd9Sstevel@tonic-gate break; 2402*7c478bd9Sstevel@tonic-gate case USBA_FULL_SPEED_DEV: 2403*7c478bd9Sstevel@tonic-gate /* Full speed transaction */ 2404*7c478bd9Sstevel@tonic-gate *bandwidth += maxpacketsize; 2405*7c478bd9Sstevel@tonic-gate 2406*7c478bd9Sstevel@tonic-gate /* Add xfer specific protocol overheads */ 2407*7c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 2408*7c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) { 2409*7c478bd9Sstevel@tonic-gate /* Full speed interrupt transaction */ 2410*7c478bd9Sstevel@tonic-gate *bandwidth += FS_NON_ISOC_PROTO_OVERHEAD; 2411*7c478bd9Sstevel@tonic-gate } else { 2412*7c478bd9Sstevel@tonic-gate /* Isochronous and input transaction */ 2413*7c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 2414*7c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 2415*7c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_INPUT_PROTO_OVERHEAD; 2416*7c478bd9Sstevel@tonic-gate } else { 2417*7c478bd9Sstevel@tonic-gate /* Isochronous and output transaction */ 2418*7c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_OUTPUT_PROTO_OVERHEAD; 2419*7c478bd9Sstevel@tonic-gate } 2420*7c478bd9Sstevel@tonic-gate } 2421*7c478bd9Sstevel@tonic-gate break; 2422*7c478bd9Sstevel@tonic-gate } 2423*7c478bd9Sstevel@tonic-gate 2424*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 2425*7c478bd9Sstevel@tonic-gate } 2426*7c478bd9Sstevel@tonic-gate 2427*7c478bd9Sstevel@tonic-gate 2428*7c478bd9Sstevel@tonic-gate /* 2429*7c478bd9Sstevel@tonic-gate * ehci_adjust_polling_interval: 2430*7c478bd9Sstevel@tonic-gate * 2431*7c478bd9Sstevel@tonic-gate * Adjust bandwidth according usb device speed. 2432*7c478bd9Sstevel@tonic-gate */ 2433*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2434*7c478bd9Sstevel@tonic-gate int 2435*7c478bd9Sstevel@tonic-gate ehci_adjust_polling_interval( 2436*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2437*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 2438*7c478bd9Sstevel@tonic-gate usb_port_status_t port_status) 2439*7c478bd9Sstevel@tonic-gate { 2440*7c478bd9Sstevel@tonic-gate uint_t interval; 2441*7c478bd9Sstevel@tonic-gate int i = 0; 2442*7c478bd9Sstevel@tonic-gate 2443*7c478bd9Sstevel@tonic-gate /* Get the polling interval */ 2444*7c478bd9Sstevel@tonic-gate interval = endpoint->bInterval; 2445*7c478bd9Sstevel@tonic-gate 2446*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 2447*7c478bd9Sstevel@tonic-gate "ehci_adjust_polling_interval: Polling interval 0x%x", interval); 2448*7c478bd9Sstevel@tonic-gate 2449*7c478bd9Sstevel@tonic-gate /* 2450*7c478bd9Sstevel@tonic-gate * According USB 2.0 Specifications, a high-speed endpoint's 2451*7c478bd9Sstevel@tonic-gate * polling intervals are specified interms of 125us or micro 2452*7c478bd9Sstevel@tonic-gate * frame, where as full/low endpoint's polling intervals are 2453*7c478bd9Sstevel@tonic-gate * specified in milliseconds. 2454*7c478bd9Sstevel@tonic-gate * 2455*7c478bd9Sstevel@tonic-gate * A high speed interrupt/isochronous endpoints can specify 2456*7c478bd9Sstevel@tonic-gate * desired polling interval between 1 to 16 micro-frames, 2457*7c478bd9Sstevel@tonic-gate * where as full/low endpoints can specify between 1 to 255 2458*7c478bd9Sstevel@tonic-gate * milliseconds. 2459*7c478bd9Sstevel@tonic-gate */ 2460*7c478bd9Sstevel@tonic-gate switch (port_status) { 2461*7c478bd9Sstevel@tonic-gate case USBA_LOW_SPEED_DEV: 2462*7c478bd9Sstevel@tonic-gate /* 2463*7c478bd9Sstevel@tonic-gate * Low speed endpoints are limited to specifying 2464*7c478bd9Sstevel@tonic-gate * only 8ms to 255ms in this driver. If a device 2465*7c478bd9Sstevel@tonic-gate * reports a polling interval that is less than 8ms, 2466*7c478bd9Sstevel@tonic-gate * it will use 8 ms instead. 2467*7c478bd9Sstevel@tonic-gate */ 2468*7c478bd9Sstevel@tonic-gate if (interval < LS_MIN_POLL_INTERVAL) { 2469*7c478bd9Sstevel@tonic-gate 2470*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 2471*7c478bd9Sstevel@tonic-gate "Low speed endpoint's poll interval of %d ms " 2472*7c478bd9Sstevel@tonic-gate "is below threshold. Rounding up to %d ms", 2473*7c478bd9Sstevel@tonic-gate interval, LS_MIN_POLL_INTERVAL); 2474*7c478bd9Sstevel@tonic-gate 2475*7c478bd9Sstevel@tonic-gate interval = LS_MIN_POLL_INTERVAL; 2476*7c478bd9Sstevel@tonic-gate } 2477*7c478bd9Sstevel@tonic-gate 2478*7c478bd9Sstevel@tonic-gate /* 2479*7c478bd9Sstevel@tonic-gate * Return an error if the polling interval is greater 2480*7c478bd9Sstevel@tonic-gate * than 255ms. 2481*7c478bd9Sstevel@tonic-gate */ 2482*7c478bd9Sstevel@tonic-gate if (interval > LS_MAX_POLL_INTERVAL) { 2483*7c478bd9Sstevel@tonic-gate 2484*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 2485*7c478bd9Sstevel@tonic-gate "Low speed endpoint's poll interval is " 2486*7c478bd9Sstevel@tonic-gate "greater than %d ms", LS_MAX_POLL_INTERVAL); 2487*7c478bd9Sstevel@tonic-gate 2488*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 2489*7c478bd9Sstevel@tonic-gate } 2490*7c478bd9Sstevel@tonic-gate break; 2491*7c478bd9Sstevel@tonic-gate 2492*7c478bd9Sstevel@tonic-gate case USBA_FULL_SPEED_DEV: 2493*7c478bd9Sstevel@tonic-gate /* 2494*7c478bd9Sstevel@tonic-gate * Return an error if the polling interval is less 2495*7c478bd9Sstevel@tonic-gate * than 1ms and greater than 255ms. 2496*7c478bd9Sstevel@tonic-gate */ 2497*7c478bd9Sstevel@tonic-gate if ((interval < FS_MIN_POLL_INTERVAL) && 2498*7c478bd9Sstevel@tonic-gate (interval > FS_MAX_POLL_INTERVAL)) { 2499*7c478bd9Sstevel@tonic-gate 2500*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 2501*7c478bd9Sstevel@tonic-gate "Full speed endpoint's poll interval must " 2502*7c478bd9Sstevel@tonic-gate "be between %d and %d ms", FS_MIN_POLL_INTERVAL, 2503*7c478bd9Sstevel@tonic-gate FS_MAX_POLL_INTERVAL); 2504*7c478bd9Sstevel@tonic-gate 2505*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 2506*7c478bd9Sstevel@tonic-gate } 2507*7c478bd9Sstevel@tonic-gate break; 2508*7c478bd9Sstevel@tonic-gate case USBA_HIGH_SPEED_DEV: 2509*7c478bd9Sstevel@tonic-gate /* 2510*7c478bd9Sstevel@tonic-gate * Return an error if the polling interval is less 1 2511*7c478bd9Sstevel@tonic-gate * and greater than 16. Convert this value to 125us 2512*7c478bd9Sstevel@tonic-gate * units using 2^(bInterval -1). refer usb 2.0 spec 2513*7c478bd9Sstevel@tonic-gate * page 51 for details. 2514*7c478bd9Sstevel@tonic-gate */ 2515*7c478bd9Sstevel@tonic-gate if ((interval < HS_MIN_POLL_INTERVAL) && 2516*7c478bd9Sstevel@tonic-gate (interval > HS_MAX_POLL_INTERVAL)) { 2517*7c478bd9Sstevel@tonic-gate 2518*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 2519*7c478bd9Sstevel@tonic-gate "High speed endpoint's poll interval " 2520*7c478bd9Sstevel@tonic-gate "must be between %d and %d units", 2521*7c478bd9Sstevel@tonic-gate HS_MIN_POLL_INTERVAL, HS_MAX_POLL_INTERVAL); 2522*7c478bd9Sstevel@tonic-gate 2523*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 2524*7c478bd9Sstevel@tonic-gate } 2525*7c478bd9Sstevel@tonic-gate 2526*7c478bd9Sstevel@tonic-gate /* Adjust high speed device polling interval */ 2527*7c478bd9Sstevel@tonic-gate interval = 2528*7c478bd9Sstevel@tonic-gate ehci_adjust_high_speed_polling_interval(ehcip, endpoint); 2529*7c478bd9Sstevel@tonic-gate 2530*7c478bd9Sstevel@tonic-gate break; 2531*7c478bd9Sstevel@tonic-gate } 2532*7c478bd9Sstevel@tonic-gate 2533*7c478bd9Sstevel@tonic-gate /* 2534*7c478bd9Sstevel@tonic-gate * If polling interval is greater than 32ms, 2535*7c478bd9Sstevel@tonic-gate * adjust polling interval equal to 32ms. 2536*7c478bd9Sstevel@tonic-gate */ 2537*7c478bd9Sstevel@tonic-gate if (interval > EHCI_NUM_INTR_QH_LISTS) { 2538*7c478bd9Sstevel@tonic-gate interval = EHCI_NUM_INTR_QH_LISTS; 2539*7c478bd9Sstevel@tonic-gate } 2540*7c478bd9Sstevel@tonic-gate 2541*7c478bd9Sstevel@tonic-gate /* 2542*7c478bd9Sstevel@tonic-gate * Find the nearest power of 2 that's less 2543*7c478bd9Sstevel@tonic-gate * than interval. 2544*7c478bd9Sstevel@tonic-gate */ 2545*7c478bd9Sstevel@tonic-gate while ((ehci_pow_2(i)) <= interval) { 2546*7c478bd9Sstevel@tonic-gate i++; 2547*7c478bd9Sstevel@tonic-gate } 2548*7c478bd9Sstevel@tonic-gate 2549*7c478bd9Sstevel@tonic-gate return (ehci_pow_2((i - 1))); 2550*7c478bd9Sstevel@tonic-gate } 2551*7c478bd9Sstevel@tonic-gate 2552*7c478bd9Sstevel@tonic-gate 2553*7c478bd9Sstevel@tonic-gate /* 2554*7c478bd9Sstevel@tonic-gate * ehci_adjust_high_speed_polling_interval: 2555*7c478bd9Sstevel@tonic-gate */ 2556*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2557*7c478bd9Sstevel@tonic-gate static int 2558*7c478bd9Sstevel@tonic-gate ehci_adjust_high_speed_polling_interval( 2559*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2560*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint) 2561*7c478bd9Sstevel@tonic-gate { 2562*7c478bd9Sstevel@tonic-gate uint_t interval; 2563*7c478bd9Sstevel@tonic-gate 2564*7c478bd9Sstevel@tonic-gate /* Get the polling interval */ 2565*7c478bd9Sstevel@tonic-gate interval = ehci_pow_2(endpoint->bInterval - 1); 2566*7c478bd9Sstevel@tonic-gate 2567*7c478bd9Sstevel@tonic-gate /* 2568*7c478bd9Sstevel@tonic-gate * Convert polling interval from micro seconds 2569*7c478bd9Sstevel@tonic-gate * to milli seconds. 2570*7c478bd9Sstevel@tonic-gate */ 2571*7c478bd9Sstevel@tonic-gate if (interval <= EHCI_MAX_UFRAMES) { 2572*7c478bd9Sstevel@tonic-gate interval = 1; 2573*7c478bd9Sstevel@tonic-gate } else { 2574*7c478bd9Sstevel@tonic-gate interval = interval/EHCI_MAX_UFRAMES; 2575*7c478bd9Sstevel@tonic-gate } 2576*7c478bd9Sstevel@tonic-gate 2577*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 2578*7c478bd9Sstevel@tonic-gate "ehci_adjust_high_speed_polling_interval: " 2579*7c478bd9Sstevel@tonic-gate "High speed adjusted interval 0x%x", interval); 2580*7c478bd9Sstevel@tonic-gate 2581*7c478bd9Sstevel@tonic-gate return (interval); 2582*7c478bd9Sstevel@tonic-gate } 2583*7c478bd9Sstevel@tonic-gate 2584*7c478bd9Sstevel@tonic-gate 2585*7c478bd9Sstevel@tonic-gate /* 2586*7c478bd9Sstevel@tonic-gate * ehci_lattice_height: 2587*7c478bd9Sstevel@tonic-gate * 2588*7c478bd9Sstevel@tonic-gate * Given the requested bandwidth, find the height in the tree at which the 2589*7c478bd9Sstevel@tonic-gate * nodes for this bandwidth fall. The height is measured as the number of 2590*7c478bd9Sstevel@tonic-gate * nodes from the leaf to the level specified by bandwidth The root of the 2591*7c478bd9Sstevel@tonic-gate * tree is at height TREE_HEIGHT. 2592*7c478bd9Sstevel@tonic-gate */ 2593*7c478bd9Sstevel@tonic-gate static uint_t 2594*7c478bd9Sstevel@tonic-gate ehci_lattice_height(uint_t interval) 2595*7c478bd9Sstevel@tonic-gate { 2596*7c478bd9Sstevel@tonic-gate return (TREE_HEIGHT - (ehci_log_2(interval))); 2597*7c478bd9Sstevel@tonic-gate } 2598*7c478bd9Sstevel@tonic-gate 2599*7c478bd9Sstevel@tonic-gate 2600*7c478bd9Sstevel@tonic-gate /* 2601*7c478bd9Sstevel@tonic-gate * ehci_lattice_parent: 2602*7c478bd9Sstevel@tonic-gate * 2603*7c478bd9Sstevel@tonic-gate * Given a node in the lattice, find the index of the parent node 2604*7c478bd9Sstevel@tonic-gate */ 2605*7c478bd9Sstevel@tonic-gate static uint_t 2606*7c478bd9Sstevel@tonic-gate ehci_lattice_parent(uint_t node) 2607*7c478bd9Sstevel@tonic-gate { 2608*7c478bd9Sstevel@tonic-gate if ((node % 2) == 0) { 2609*7c478bd9Sstevel@tonic-gate 2610*7c478bd9Sstevel@tonic-gate return ((node/2) - 1); 2611*7c478bd9Sstevel@tonic-gate } else { 2612*7c478bd9Sstevel@tonic-gate 2613*7c478bd9Sstevel@tonic-gate return ((node + 1)/2 - 1); 2614*7c478bd9Sstevel@tonic-gate } 2615*7c478bd9Sstevel@tonic-gate } 2616*7c478bd9Sstevel@tonic-gate 2617*7c478bd9Sstevel@tonic-gate 2618*7c478bd9Sstevel@tonic-gate /* 2619*7c478bd9Sstevel@tonic-gate * ehci_find_periodic_node: 2620*7c478bd9Sstevel@tonic-gate * 2621*7c478bd9Sstevel@tonic-gate * Based on the "real" array leaf node and interval, get the periodic node. 2622*7c478bd9Sstevel@tonic-gate */ 2623*7c478bd9Sstevel@tonic-gate static uint_t 2624*7c478bd9Sstevel@tonic-gate ehci_find_periodic_node(uint_t leaf, int interval) { 2625*7c478bd9Sstevel@tonic-gate uint_t lattice_leaf; 2626*7c478bd9Sstevel@tonic-gate uint_t height = ehci_lattice_height(interval); 2627*7c478bd9Sstevel@tonic-gate uint_t pnode; 2628*7c478bd9Sstevel@tonic-gate int i; 2629*7c478bd9Sstevel@tonic-gate 2630*7c478bd9Sstevel@tonic-gate /* Get the leaf number in the lattice */ 2631*7c478bd9Sstevel@tonic-gate lattice_leaf = leaf + EHCI_NUM_INTR_QH_LISTS - 1; 2632*7c478bd9Sstevel@tonic-gate 2633*7c478bd9Sstevel@tonic-gate /* Get the node in the lattice based on the height and leaf */ 2634*7c478bd9Sstevel@tonic-gate pnode = lattice_leaf; 2635*7c478bd9Sstevel@tonic-gate for (i = 0; i < height; i++) { 2636*7c478bd9Sstevel@tonic-gate pnode = ehci_lattice_parent(pnode); 2637*7c478bd9Sstevel@tonic-gate } 2638*7c478bd9Sstevel@tonic-gate 2639*7c478bd9Sstevel@tonic-gate return (pnode); 2640*7c478bd9Sstevel@tonic-gate } 2641*7c478bd9Sstevel@tonic-gate 2642*7c478bd9Sstevel@tonic-gate 2643*7c478bd9Sstevel@tonic-gate /* 2644*7c478bd9Sstevel@tonic-gate * ehci_leftmost_leaf: 2645*7c478bd9Sstevel@tonic-gate * 2646*7c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node. Height refers 2647*7c478bd9Sstevel@tonic-gate * to number of nodes from the bottom of the tree to the node, including the 2648*7c478bd9Sstevel@tonic-gate * node. 2649*7c478bd9Sstevel@tonic-gate * 2650*7c478bd9Sstevel@tonic-gate * The formula for a zero based tree is: 2651*7c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1 2652*7c478bd9Sstevel@tonic-gate * The leaf of the tree is an array, convert the number for the array. 2653*7c478bd9Sstevel@tonic-gate * Subtract the size of nodes not in the array 2654*7c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1 - (EHCI_NUM_INTR_QH_LISTS - 1) = 2655*7c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - EHCI_NUM_INTR_QH_LISTS = 2656*7c478bd9Sstevel@tonic-gate * 2^H * (Node + 1) - EHCI_NUM_INTR_QH_LISTS 2657*7c478bd9Sstevel@tonic-gate * 0 2658*7c478bd9Sstevel@tonic-gate * 1 2 2659*7c478bd9Sstevel@tonic-gate * 0 1 2 3 2660*7c478bd9Sstevel@tonic-gate */ 2661*7c478bd9Sstevel@tonic-gate static uint_t 2662*7c478bd9Sstevel@tonic-gate ehci_leftmost_leaf( 2663*7c478bd9Sstevel@tonic-gate uint_t node, 2664*7c478bd9Sstevel@tonic-gate uint_t height) 2665*7c478bd9Sstevel@tonic-gate { 2666*7c478bd9Sstevel@tonic-gate return ((ehci_pow_2(height) * (node + 1)) - EHCI_NUM_INTR_QH_LISTS); 2667*7c478bd9Sstevel@tonic-gate } 2668*7c478bd9Sstevel@tonic-gate 2669*7c478bd9Sstevel@tonic-gate 2670*7c478bd9Sstevel@tonic-gate /* 2671*7c478bd9Sstevel@tonic-gate * ehci_pow_2: 2672*7c478bd9Sstevel@tonic-gate * 2673*7c478bd9Sstevel@tonic-gate * Compute 2 to the power 2674*7c478bd9Sstevel@tonic-gate */ 2675*7c478bd9Sstevel@tonic-gate static uint_t 2676*7c478bd9Sstevel@tonic-gate ehci_pow_2(uint_t x) 2677*7c478bd9Sstevel@tonic-gate { 2678*7c478bd9Sstevel@tonic-gate if (x == 0) { 2679*7c478bd9Sstevel@tonic-gate 2680*7c478bd9Sstevel@tonic-gate return (1); 2681*7c478bd9Sstevel@tonic-gate } else { 2682*7c478bd9Sstevel@tonic-gate 2683*7c478bd9Sstevel@tonic-gate return (2 << (x - 1)); 2684*7c478bd9Sstevel@tonic-gate } 2685*7c478bd9Sstevel@tonic-gate } 2686*7c478bd9Sstevel@tonic-gate 2687*7c478bd9Sstevel@tonic-gate 2688*7c478bd9Sstevel@tonic-gate /* 2689*7c478bd9Sstevel@tonic-gate * ehci_log_2: 2690*7c478bd9Sstevel@tonic-gate * 2691*7c478bd9Sstevel@tonic-gate * Compute log base 2 of x 2692*7c478bd9Sstevel@tonic-gate */ 2693*7c478bd9Sstevel@tonic-gate static uint_t 2694*7c478bd9Sstevel@tonic-gate ehci_log_2(uint_t x) 2695*7c478bd9Sstevel@tonic-gate { 2696*7c478bd9Sstevel@tonic-gate int i = 0; 2697*7c478bd9Sstevel@tonic-gate 2698*7c478bd9Sstevel@tonic-gate while (x != 1) { 2699*7c478bd9Sstevel@tonic-gate x = x >> 1; 2700*7c478bd9Sstevel@tonic-gate i++; 2701*7c478bd9Sstevel@tonic-gate } 2702*7c478bd9Sstevel@tonic-gate 2703*7c478bd9Sstevel@tonic-gate return (i); 2704*7c478bd9Sstevel@tonic-gate } 2705*7c478bd9Sstevel@tonic-gate 2706*7c478bd9Sstevel@tonic-gate 2707*7c478bd9Sstevel@tonic-gate /* 2708*7c478bd9Sstevel@tonic-gate * ehci_find_bestfit_hs_mask: 2709*7c478bd9Sstevel@tonic-gate * 2710*7c478bd9Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation, and update the 2711*7c478bd9Sstevel@tonic-gate * bandwidth allocation. 2712*7c478bd9Sstevel@tonic-gate */ 2713*7c478bd9Sstevel@tonic-gate static int 2714*7c478bd9Sstevel@tonic-gate ehci_find_bestfit_hs_mask( 2715*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2716*7c478bd9Sstevel@tonic-gate uchar_t *smask, 2717*7c478bd9Sstevel@tonic-gate uint_t *pnode, 2718*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 2719*7c478bd9Sstevel@tonic-gate uint_t bandwidth, 2720*7c478bd9Sstevel@tonic-gate int interval) 2721*7c478bd9Sstevel@tonic-gate { 2722*7c478bd9Sstevel@tonic-gate int i; 2723*7c478bd9Sstevel@tonic-gate uint_t elements, index; 2724*7c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 2725*7c478bd9Sstevel@tonic-gate uint_t node_bandwidth, best_node_bandwidth; 2726*7c478bd9Sstevel@tonic-gate uint_t leaf_count; 2727*7c478bd9Sstevel@tonic-gate uchar_t bw_mask; 2728*7c478bd9Sstevel@tonic-gate uchar_t best_smask; 2729*7c478bd9Sstevel@tonic-gate 2730*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 2731*7c478bd9Sstevel@tonic-gate "ehci_find_bestfit_hs_mask: "); 2732*7c478bd9Sstevel@tonic-gate 2733*7c478bd9Sstevel@tonic-gate /* Get all the valid smasks */ 2734*7c478bd9Sstevel@tonic-gate switch (ehci_pow_2(endpoint->bInterval - 1)) { 2735*7c478bd9Sstevel@tonic-gate case EHCI_INTR_1US_POLL: 2736*7c478bd9Sstevel@tonic-gate index = EHCI_1US_MASK_INDEX; 2737*7c478bd9Sstevel@tonic-gate elements = EHCI_INTR_1US_POLL; 2738*7c478bd9Sstevel@tonic-gate break; 2739*7c478bd9Sstevel@tonic-gate case EHCI_INTR_2US_POLL: 2740*7c478bd9Sstevel@tonic-gate index = EHCI_2US_MASK_INDEX; 2741*7c478bd9Sstevel@tonic-gate elements = EHCI_INTR_2US_POLL; 2742*7c478bd9Sstevel@tonic-gate break; 2743*7c478bd9Sstevel@tonic-gate case EHCI_INTR_4US_POLL: 2744*7c478bd9Sstevel@tonic-gate index = EHCI_4US_MASK_INDEX; 2745*7c478bd9Sstevel@tonic-gate elements = EHCI_INTR_4US_POLL; 2746*7c478bd9Sstevel@tonic-gate break; 2747*7c478bd9Sstevel@tonic-gate case EHCI_INTR_XUS_POLL: 2748*7c478bd9Sstevel@tonic-gate default: 2749*7c478bd9Sstevel@tonic-gate index = EHCI_XUS_MASK_INDEX; 2750*7c478bd9Sstevel@tonic-gate elements = EHCI_INTR_XUS_POLL; 2751*7c478bd9Sstevel@tonic-gate break; 2752*7c478bd9Sstevel@tonic-gate } 2753*7c478bd9Sstevel@tonic-gate 2754*7c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 2755*7c478bd9Sstevel@tonic-gate 2756*7c478bd9Sstevel@tonic-gate /* 2757*7c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 2758*7c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 2759*7c478bd9Sstevel@tonic-gate */ 2760*7c478bd9Sstevel@tonic-gate best_smask = 0x00; 2761*7c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 2762*7c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 2763*7c478bd9Sstevel@tonic-gate /* Find the bandwidth mask */ 2764*7c478bd9Sstevel@tonic-gate node_bandwidth = ehci_calculate_bw_availability_mask(ehcip, 2765*7c478bd9Sstevel@tonic-gate bandwidth, ehci_index[array_leaf], leaf_count, &bw_mask); 2766*7c478bd9Sstevel@tonic-gate 2767*7c478bd9Sstevel@tonic-gate /* 2768*7c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 2769*7c478bd9Sstevel@tonic-gate * next leaf. 2770*7c478bd9Sstevel@tonic-gate */ 2771*7c478bd9Sstevel@tonic-gate if (bw_mask == 0x00) { 2772*7c478bd9Sstevel@tonic-gate continue; 2773*7c478bd9Sstevel@tonic-gate } 2774*7c478bd9Sstevel@tonic-gate 2775*7c478bd9Sstevel@tonic-gate /* 2776*7c478bd9Sstevel@tonic-gate * Now make sure our bandwidth requirements can be 2777*7c478bd9Sstevel@tonic-gate * satisfied with one of smasks in this node. 2778*7c478bd9Sstevel@tonic-gate */ 2779*7c478bd9Sstevel@tonic-gate *smask = 0x00; 2780*7c478bd9Sstevel@tonic-gate for (i = index; i < (index + elements); i++) { 2781*7c478bd9Sstevel@tonic-gate /* Check the start split mask value */ 2782*7c478bd9Sstevel@tonic-gate if (ehci_start_split_mask[index] & bw_mask) { 2783*7c478bd9Sstevel@tonic-gate *smask = ehci_start_split_mask[index]; 2784*7c478bd9Sstevel@tonic-gate break; 2785*7c478bd9Sstevel@tonic-gate } 2786*7c478bd9Sstevel@tonic-gate } 2787*7c478bd9Sstevel@tonic-gate 2788*7c478bd9Sstevel@tonic-gate /* 2789*7c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 2790*7c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 2791*7c478bd9Sstevel@tonic-gate * - or - 2792*7c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 2793*7c478bd9Sstevel@tonic-gate */ 2794*7c478bd9Sstevel@tonic-gate if ((*smask != 0x00) && 2795*7c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 2796*7c478bd9Sstevel@tonic-gate (best_node_bandwidth > node_bandwidth))) { 2797*7c478bd9Sstevel@tonic-gate 2798*7c478bd9Sstevel@tonic-gate best_node_bandwidth = node_bandwidth; 2799*7c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 2800*7c478bd9Sstevel@tonic-gate best_smask = *smask; 2801*7c478bd9Sstevel@tonic-gate } 2802*7c478bd9Sstevel@tonic-gate } 2803*7c478bd9Sstevel@tonic-gate 2804*7c478bd9Sstevel@tonic-gate /* 2805*7c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 2806*7c478bd9Sstevel@tonic-gate * appropriate variables and return success. 2807*7c478bd9Sstevel@tonic-gate */ 2808*7c478bd9Sstevel@tonic-gate if (best_smask) { 2809*7c478bd9Sstevel@tonic-gate *smask = best_smask; 2810*7c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 2811*7c478bd9Sstevel@tonic-gate interval); 2812*7c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, bandwidth, 2813*7c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 2814*7c478bd9Sstevel@tonic-gate 2815*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 2816*7c478bd9Sstevel@tonic-gate } 2817*7c478bd9Sstevel@tonic-gate 2818*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 2819*7c478bd9Sstevel@tonic-gate } 2820*7c478bd9Sstevel@tonic-gate 2821*7c478bd9Sstevel@tonic-gate 2822*7c478bd9Sstevel@tonic-gate /* 2823*7c478bd9Sstevel@tonic-gate * ehci_find_bestfit_ls_intr_mask: 2824*7c478bd9Sstevel@tonic-gate * 2825*7c478bd9Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation. 2826*7c478bd9Sstevel@tonic-gate */ 2827*7c478bd9Sstevel@tonic-gate static int 2828*7c478bd9Sstevel@tonic-gate ehci_find_bestfit_ls_intr_mask( 2829*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2830*7c478bd9Sstevel@tonic-gate uchar_t *smask, 2831*7c478bd9Sstevel@tonic-gate uchar_t *cmask, 2832*7c478bd9Sstevel@tonic-gate uint_t *pnode, 2833*7c478bd9Sstevel@tonic-gate uint_t sbandwidth, 2834*7c478bd9Sstevel@tonic-gate uint_t cbandwidth, 2835*7c478bd9Sstevel@tonic-gate int interval) 2836*7c478bd9Sstevel@tonic-gate { 2837*7c478bd9Sstevel@tonic-gate int i; 2838*7c478bd9Sstevel@tonic-gate uint_t elements, index; 2839*7c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 2840*7c478bd9Sstevel@tonic-gate uint_t node_sbandwidth, node_cbandwidth; 2841*7c478bd9Sstevel@tonic-gate uint_t best_node_bandwidth; 2842*7c478bd9Sstevel@tonic-gate uint_t leaf_count; 2843*7c478bd9Sstevel@tonic-gate uchar_t bw_smask, bw_cmask; 2844*7c478bd9Sstevel@tonic-gate uchar_t best_smask, best_cmask; 2845*7c478bd9Sstevel@tonic-gate 2846*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 2847*7c478bd9Sstevel@tonic-gate "ehci_find_bestfit_ls_intr_mask: "); 2848*7c478bd9Sstevel@tonic-gate 2849*7c478bd9Sstevel@tonic-gate /* For low and full speed devices */ 2850*7c478bd9Sstevel@tonic-gate index = EHCI_XUS_MASK_INDEX; 2851*7c478bd9Sstevel@tonic-gate elements = EHCI_INTR_4MS_POLL; 2852*7c478bd9Sstevel@tonic-gate 2853*7c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 2854*7c478bd9Sstevel@tonic-gate 2855*7c478bd9Sstevel@tonic-gate /* 2856*7c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 2857*7c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 2858*7c478bd9Sstevel@tonic-gate */ 2859*7c478bd9Sstevel@tonic-gate best_smask = 0x00; 2860*7c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 2861*7c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 2862*7c478bd9Sstevel@tonic-gate /* Find the bandwidth mask */ 2863*7c478bd9Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip, 2864*7c478bd9Sstevel@tonic-gate sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask); 2865*7c478bd9Sstevel@tonic-gate node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip, 2866*7c478bd9Sstevel@tonic-gate cbandwidth, ehci_index[array_leaf], leaf_count, &bw_cmask); 2867*7c478bd9Sstevel@tonic-gate 2868*7c478bd9Sstevel@tonic-gate /* 2869*7c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 2870*7c478bd9Sstevel@tonic-gate * next leaf. 2871*7c478bd9Sstevel@tonic-gate */ 2872*7c478bd9Sstevel@tonic-gate if ((bw_smask == 0x00) || (bw_cmask == 0x00)) { 2873*7c478bd9Sstevel@tonic-gate continue; 2874*7c478bd9Sstevel@tonic-gate } 2875*7c478bd9Sstevel@tonic-gate 2876*7c478bd9Sstevel@tonic-gate /* 2877*7c478bd9Sstevel@tonic-gate * Now make sure our bandwidth requirements can be 2878*7c478bd9Sstevel@tonic-gate * satisfied with one of smasks in this node. 2879*7c478bd9Sstevel@tonic-gate */ 2880*7c478bd9Sstevel@tonic-gate *smask = 0x00; 2881*7c478bd9Sstevel@tonic-gate *cmask = 0x00; 2882*7c478bd9Sstevel@tonic-gate for (i = index; i < (index + elements); i++) { 2883*7c478bd9Sstevel@tonic-gate /* Check the start split mask value */ 2884*7c478bd9Sstevel@tonic-gate if ((ehci_start_split_mask[index] & bw_smask) && 2885*7c478bd9Sstevel@tonic-gate (ehci_intr_complete_split_mask[index] & bw_cmask)) { 2886*7c478bd9Sstevel@tonic-gate *smask = ehci_start_split_mask[index]; 2887*7c478bd9Sstevel@tonic-gate *cmask = ehci_intr_complete_split_mask[index]; 2888*7c478bd9Sstevel@tonic-gate break; 2889*7c478bd9Sstevel@tonic-gate } 2890*7c478bd9Sstevel@tonic-gate } 2891*7c478bd9Sstevel@tonic-gate 2892*7c478bd9Sstevel@tonic-gate /* 2893*7c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 2894*7c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 2895*7c478bd9Sstevel@tonic-gate * - or - 2896*7c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 2897*7c478bd9Sstevel@tonic-gate */ 2898*7c478bd9Sstevel@tonic-gate if ((*smask != 0x00) && 2899*7c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 2900*7c478bd9Sstevel@tonic-gate (best_node_bandwidth > 2901*7c478bd9Sstevel@tonic-gate (node_sbandwidth + node_cbandwidth)))) { 2902*7c478bd9Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth + node_cbandwidth; 2903*7c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 2904*7c478bd9Sstevel@tonic-gate best_smask = *smask; 2905*7c478bd9Sstevel@tonic-gate best_cmask = *cmask; 2906*7c478bd9Sstevel@tonic-gate } 2907*7c478bd9Sstevel@tonic-gate } 2908*7c478bd9Sstevel@tonic-gate 2909*7c478bd9Sstevel@tonic-gate /* 2910*7c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 2911*7c478bd9Sstevel@tonic-gate * appropriate variables and return success. 2912*7c478bd9Sstevel@tonic-gate */ 2913*7c478bd9Sstevel@tonic-gate if (best_smask) { 2914*7c478bd9Sstevel@tonic-gate *smask = best_smask; 2915*7c478bd9Sstevel@tonic-gate *cmask = best_cmask; 2916*7c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 2917*7c478bd9Sstevel@tonic-gate interval); 2918*7c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, sbandwidth, 2919*7c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 2920*7c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, cbandwidth, 2921*7c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_cmask); 2922*7c478bd9Sstevel@tonic-gate 2923*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 2924*7c478bd9Sstevel@tonic-gate } 2925*7c478bd9Sstevel@tonic-gate 2926*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 2927*7c478bd9Sstevel@tonic-gate } 2928*7c478bd9Sstevel@tonic-gate 2929*7c478bd9Sstevel@tonic-gate 2930*7c478bd9Sstevel@tonic-gate /* 2931*7c478bd9Sstevel@tonic-gate * ehci_find_bestfit_sitd_in_mask: 2932*7c478bd9Sstevel@tonic-gate * 2933*7c478bd9Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation. 2934*7c478bd9Sstevel@tonic-gate */ 2935*7c478bd9Sstevel@tonic-gate static int 2936*7c478bd9Sstevel@tonic-gate ehci_find_bestfit_sitd_in_mask( 2937*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2938*7c478bd9Sstevel@tonic-gate uchar_t *smask, 2939*7c478bd9Sstevel@tonic-gate uchar_t *cmask, 2940*7c478bd9Sstevel@tonic-gate uint_t *pnode, 2941*7c478bd9Sstevel@tonic-gate uint_t sbandwidth, 2942*7c478bd9Sstevel@tonic-gate uint_t cbandwidth, 2943*7c478bd9Sstevel@tonic-gate int interval) 2944*7c478bd9Sstevel@tonic-gate { 2945*7c478bd9Sstevel@tonic-gate int i, uFrames, found; 2946*7c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 2947*7c478bd9Sstevel@tonic-gate uint_t node_sbandwidth, node_cbandwidth; 2948*7c478bd9Sstevel@tonic-gate uint_t best_node_bandwidth; 2949*7c478bd9Sstevel@tonic-gate uint_t leaf_count; 2950*7c478bd9Sstevel@tonic-gate uchar_t bw_smask, bw_cmask; 2951*7c478bd9Sstevel@tonic-gate uchar_t best_smask, best_cmask; 2952*7c478bd9Sstevel@tonic-gate 2953*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 2954*7c478bd9Sstevel@tonic-gate "ehci_find_bestfit_sitd_in_mask: "); 2955*7c478bd9Sstevel@tonic-gate 2956*7c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 2957*7c478bd9Sstevel@tonic-gate 2958*7c478bd9Sstevel@tonic-gate /* 2959*7c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 2960*7c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 2961*7c478bd9Sstevel@tonic-gate * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame. 2962*7c478bd9Sstevel@tonic-gate */ 2963*7c478bd9Sstevel@tonic-gate /* 2964*7c478bd9Sstevel@tonic-gate * Need to add an additional 2 uFrames, if the "L"ast 2965*7c478bd9Sstevel@tonic-gate * complete split is before uFrame 6. See section 2966*7c478bd9Sstevel@tonic-gate * 11.8.4 in USB 2.0 Spec. Currently we do not support 2967*7c478bd9Sstevel@tonic-gate * the "Back Ptr" which means we support on IN of 2968*7c478bd9Sstevel@tonic-gate * ~4*MAX_UFRAME_SITD_XFER bandwidth/ 2969*7c478bd9Sstevel@tonic-gate */ 2970*7c478bd9Sstevel@tonic-gate uFrames = (cbandwidth / MAX_UFRAME_SITD_XFER) + 2; 2971*7c478bd9Sstevel@tonic-gate if (cbandwidth % MAX_UFRAME_SITD_XFER) { 2972*7c478bd9Sstevel@tonic-gate uFrames++; 2973*7c478bd9Sstevel@tonic-gate } 2974*7c478bd9Sstevel@tonic-gate if (uFrames > 6) { 2975*7c478bd9Sstevel@tonic-gate 2976*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 2977*7c478bd9Sstevel@tonic-gate } 2978*7c478bd9Sstevel@tonic-gate *smask = 0x1; 2979*7c478bd9Sstevel@tonic-gate *cmask = 0x00; 2980*7c478bd9Sstevel@tonic-gate for (i = 0; i < uFrames; i++) { 2981*7c478bd9Sstevel@tonic-gate *cmask = *cmask << 1; 2982*7c478bd9Sstevel@tonic-gate *cmask |= 0x1; 2983*7c478bd9Sstevel@tonic-gate } 2984*7c478bd9Sstevel@tonic-gate /* cmask must start 2 frames after the smask */ 2985*7c478bd9Sstevel@tonic-gate *cmask = *cmask << 2; 2986*7c478bd9Sstevel@tonic-gate 2987*7c478bd9Sstevel@tonic-gate found = 0; 2988*7c478bd9Sstevel@tonic-gate best_smask = 0x00; 2989*7c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 2990*7c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 2991*7c478bd9Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip, 2992*7c478bd9Sstevel@tonic-gate sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask); 2993*7c478bd9Sstevel@tonic-gate node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip, 2994*7c478bd9Sstevel@tonic-gate MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count, 2995*7c478bd9Sstevel@tonic-gate &bw_cmask); 2996*7c478bd9Sstevel@tonic-gate 2997*7c478bd9Sstevel@tonic-gate /* 2998*7c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 2999*7c478bd9Sstevel@tonic-gate * next leaf. 3000*7c478bd9Sstevel@tonic-gate */ 3001*7c478bd9Sstevel@tonic-gate if ((bw_smask == 0x00) || (bw_cmask == 0x00)) { 3002*7c478bd9Sstevel@tonic-gate continue; 3003*7c478bd9Sstevel@tonic-gate } 3004*7c478bd9Sstevel@tonic-gate 3005*7c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_MAX_UFRAMES - uFrames - 2); i++) { 3006*7c478bd9Sstevel@tonic-gate if ((*smask & bw_smask) && (*cmask & bw_cmask)) { 3007*7c478bd9Sstevel@tonic-gate found = 1; 3008*7c478bd9Sstevel@tonic-gate break; 3009*7c478bd9Sstevel@tonic-gate } 3010*7c478bd9Sstevel@tonic-gate *smask = *smask << 1; 3011*7c478bd9Sstevel@tonic-gate *cmask = *cmask << 1; 3012*7c478bd9Sstevel@tonic-gate } 3013*7c478bd9Sstevel@tonic-gate 3014*7c478bd9Sstevel@tonic-gate /* 3015*7c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 3016*7c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 3017*7c478bd9Sstevel@tonic-gate * - or - 3018*7c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 3019*7c478bd9Sstevel@tonic-gate */ 3020*7c478bd9Sstevel@tonic-gate if (found && 3021*7c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 3022*7c478bd9Sstevel@tonic-gate (best_node_bandwidth > 3023*7c478bd9Sstevel@tonic-gate (node_sbandwidth + node_cbandwidth)))) { 3024*7c478bd9Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth + node_cbandwidth; 3025*7c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 3026*7c478bd9Sstevel@tonic-gate best_smask = *smask; 3027*7c478bd9Sstevel@tonic-gate best_cmask = *cmask; 3028*7c478bd9Sstevel@tonic-gate } 3029*7c478bd9Sstevel@tonic-gate } 3030*7c478bd9Sstevel@tonic-gate 3031*7c478bd9Sstevel@tonic-gate /* 3032*7c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 3033*7c478bd9Sstevel@tonic-gate * appropriate variables and return success. 3034*7c478bd9Sstevel@tonic-gate */ 3035*7c478bd9Sstevel@tonic-gate if (best_smask) { 3036*7c478bd9Sstevel@tonic-gate *smask = best_smask; 3037*7c478bd9Sstevel@tonic-gate *cmask = best_cmask; 3038*7c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 3039*7c478bd9Sstevel@tonic-gate interval); 3040*7c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, sbandwidth, 3041*7c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 3042*7c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER, 3043*7c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_cmask); 3044*7c478bd9Sstevel@tonic-gate 3045*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 3046*7c478bd9Sstevel@tonic-gate } 3047*7c478bd9Sstevel@tonic-gate 3048*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 3049*7c478bd9Sstevel@tonic-gate } 3050*7c478bd9Sstevel@tonic-gate 3051*7c478bd9Sstevel@tonic-gate 3052*7c478bd9Sstevel@tonic-gate /* 3053*7c478bd9Sstevel@tonic-gate * ehci_find_bestfit_sitd_out_mask: 3054*7c478bd9Sstevel@tonic-gate * 3055*7c478bd9Sstevel@tonic-gate * Find the smask in the bandwidth allocation. 3056*7c478bd9Sstevel@tonic-gate */ 3057*7c478bd9Sstevel@tonic-gate static int 3058*7c478bd9Sstevel@tonic-gate ehci_find_bestfit_sitd_out_mask( 3059*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 3060*7c478bd9Sstevel@tonic-gate uchar_t *smask, 3061*7c478bd9Sstevel@tonic-gate uint_t *pnode, 3062*7c478bd9Sstevel@tonic-gate uint_t sbandwidth, 3063*7c478bd9Sstevel@tonic-gate int interval) 3064*7c478bd9Sstevel@tonic-gate { 3065*7c478bd9Sstevel@tonic-gate int i, uFrames, found; 3066*7c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 3067*7c478bd9Sstevel@tonic-gate uint_t node_sbandwidth; 3068*7c478bd9Sstevel@tonic-gate uint_t best_node_bandwidth; 3069*7c478bd9Sstevel@tonic-gate uint_t leaf_count; 3070*7c478bd9Sstevel@tonic-gate uchar_t bw_smask; 3071*7c478bd9Sstevel@tonic-gate uchar_t best_smask; 3072*7c478bd9Sstevel@tonic-gate 3073*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 3074*7c478bd9Sstevel@tonic-gate "ehci_find_bestfit_sitd_out_mask: "); 3075*7c478bd9Sstevel@tonic-gate 3076*7c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 3077*7c478bd9Sstevel@tonic-gate 3078*7c478bd9Sstevel@tonic-gate /* 3079*7c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 3080*7c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 3081*7c478bd9Sstevel@tonic-gate * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame. 3082*7c478bd9Sstevel@tonic-gate */ 3083*7c478bd9Sstevel@tonic-gate *smask = 0x00; 3084*7c478bd9Sstevel@tonic-gate uFrames = sbandwidth / MAX_UFRAME_SITD_XFER; 3085*7c478bd9Sstevel@tonic-gate if (sbandwidth % MAX_UFRAME_SITD_XFER) { 3086*7c478bd9Sstevel@tonic-gate uFrames++; 3087*7c478bd9Sstevel@tonic-gate } 3088*7c478bd9Sstevel@tonic-gate for (i = 0; i < uFrames; i++) { 3089*7c478bd9Sstevel@tonic-gate *smask = *smask << 1; 3090*7c478bd9Sstevel@tonic-gate *smask |= 0x1; 3091*7c478bd9Sstevel@tonic-gate } 3092*7c478bd9Sstevel@tonic-gate 3093*7c478bd9Sstevel@tonic-gate found = 0; 3094*7c478bd9Sstevel@tonic-gate best_smask = 0x00; 3095*7c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 3096*7c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 3097*7c478bd9Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip, 3098*7c478bd9Sstevel@tonic-gate MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count, 3099*7c478bd9Sstevel@tonic-gate &bw_smask); 3100*7c478bd9Sstevel@tonic-gate 3101*7c478bd9Sstevel@tonic-gate /* 3102*7c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 3103*7c478bd9Sstevel@tonic-gate * next leaf. 3104*7c478bd9Sstevel@tonic-gate */ 3105*7c478bd9Sstevel@tonic-gate if (bw_smask == 0x00) { 3106*7c478bd9Sstevel@tonic-gate continue; 3107*7c478bd9Sstevel@tonic-gate } 3108*7c478bd9Sstevel@tonic-gate 3109*7c478bd9Sstevel@tonic-gate /* You cannot have a start split on the 8th uFrame */ 3110*7c478bd9Sstevel@tonic-gate for (i = 0; (*smask & 0x80) == 0; i++) { 3111*7c478bd9Sstevel@tonic-gate if (*smask & bw_smask) { 3112*7c478bd9Sstevel@tonic-gate found = 1; 3113*7c478bd9Sstevel@tonic-gate break; 3114*7c478bd9Sstevel@tonic-gate } 3115*7c478bd9Sstevel@tonic-gate *smask = *smask << 1; 3116*7c478bd9Sstevel@tonic-gate } 3117*7c478bd9Sstevel@tonic-gate 3118*7c478bd9Sstevel@tonic-gate /* 3119*7c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 3120*7c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 3121*7c478bd9Sstevel@tonic-gate * - or - 3122*7c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 3123*7c478bd9Sstevel@tonic-gate */ 3124*7c478bd9Sstevel@tonic-gate if (found && 3125*7c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 3126*7c478bd9Sstevel@tonic-gate (best_node_bandwidth > node_sbandwidth))) { 3127*7c478bd9Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth; 3128*7c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 3129*7c478bd9Sstevel@tonic-gate best_smask = *smask; 3130*7c478bd9Sstevel@tonic-gate } 3131*7c478bd9Sstevel@tonic-gate } 3132*7c478bd9Sstevel@tonic-gate 3133*7c478bd9Sstevel@tonic-gate /* 3134*7c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 3135*7c478bd9Sstevel@tonic-gate * appropriate variables and return success. 3136*7c478bd9Sstevel@tonic-gate */ 3137*7c478bd9Sstevel@tonic-gate if (best_smask) { 3138*7c478bd9Sstevel@tonic-gate *smask = best_smask; 3139*7c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 3140*7c478bd9Sstevel@tonic-gate interval); 3141*7c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER, 3142*7c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 3143*7c478bd9Sstevel@tonic-gate 3144*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 3145*7c478bd9Sstevel@tonic-gate } 3146*7c478bd9Sstevel@tonic-gate 3147*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 3148*7c478bd9Sstevel@tonic-gate } 3149*7c478bd9Sstevel@tonic-gate 3150*7c478bd9Sstevel@tonic-gate 3151*7c478bd9Sstevel@tonic-gate /* 3152*7c478bd9Sstevel@tonic-gate * ehci_calculate_bw_availability_mask: 3153*7c478bd9Sstevel@tonic-gate * 3154*7c478bd9Sstevel@tonic-gate * Returns the "total bandwidth used" in this node. 3155*7c478bd9Sstevel@tonic-gate * Populates bw_mask with the uFrames that can support the bandwidth. 3156*7c478bd9Sstevel@tonic-gate * 3157*7c478bd9Sstevel@tonic-gate * If all the Frames cannot support this bandwidth, then bw_mask 3158*7c478bd9Sstevel@tonic-gate * will return 0x00 and the "total bandwidth used" will be invalid. 3159*7c478bd9Sstevel@tonic-gate */ 3160*7c478bd9Sstevel@tonic-gate static uint_t 3161*7c478bd9Sstevel@tonic-gate ehci_calculate_bw_availability_mask( 3162*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 3163*7c478bd9Sstevel@tonic-gate uint_t bandwidth, 3164*7c478bd9Sstevel@tonic-gate int leaf, 3165*7c478bd9Sstevel@tonic-gate int leaf_count, 3166*7c478bd9Sstevel@tonic-gate uchar_t *bw_mask) 3167*7c478bd9Sstevel@tonic-gate { 3168*7c478bd9Sstevel@tonic-gate int i, j; 3169*7c478bd9Sstevel@tonic-gate uchar_t bw_uframe; 3170*7c478bd9Sstevel@tonic-gate int uframe_total; 3171*7c478bd9Sstevel@tonic-gate ehci_frame_bandwidth_t *fbp; 3172*7c478bd9Sstevel@tonic-gate uint_t total_bandwidth = 0; 3173*7c478bd9Sstevel@tonic-gate 3174*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 3175*7c478bd9Sstevel@tonic-gate "ehci_calculate_bw_availability_mask: leaf %d leaf count %d", 3176*7c478bd9Sstevel@tonic-gate leaf, leaf_count); 3177*7c478bd9Sstevel@tonic-gate 3178*7c478bd9Sstevel@tonic-gate /* Start by saying all uFrames are available */ 3179*7c478bd9Sstevel@tonic-gate *bw_mask = 0xFF; 3180*7c478bd9Sstevel@tonic-gate 3181*7c478bd9Sstevel@tonic-gate for (i = 0; (i < leaf_count) || (*bw_mask == 0x00); i++) { 3182*7c478bd9Sstevel@tonic-gate fbp = &ehcip->ehci_frame_bandwidth[leaf + i]; 3183*7c478bd9Sstevel@tonic-gate 3184*7c478bd9Sstevel@tonic-gate total_bandwidth += fbp->ehci_allocated_frame_bandwidth; 3185*7c478bd9Sstevel@tonic-gate 3186*7c478bd9Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) { 3187*7c478bd9Sstevel@tonic-gate /* 3188*7c478bd9Sstevel@tonic-gate * If the uFrame in bw_mask is available check to see if 3189*7c478bd9Sstevel@tonic-gate * it can support the additional bandwidth. 3190*7c478bd9Sstevel@tonic-gate */ 3191*7c478bd9Sstevel@tonic-gate bw_uframe = (*bw_mask & (0x1 << j)); 3192*7c478bd9Sstevel@tonic-gate uframe_total = 3193*7c478bd9Sstevel@tonic-gate fbp->ehci_micro_frame_bandwidth[j] + 3194*7c478bd9Sstevel@tonic-gate bandwidth; 3195*7c478bd9Sstevel@tonic-gate if ((bw_uframe) && 3196*7c478bd9Sstevel@tonic-gate (uframe_total > HS_PERIODIC_BANDWIDTH)) { 3197*7c478bd9Sstevel@tonic-gate *bw_mask = *bw_mask & ~bw_uframe; 3198*7c478bd9Sstevel@tonic-gate } 3199*7c478bd9Sstevel@tonic-gate } 3200*7c478bd9Sstevel@tonic-gate } 3201*7c478bd9Sstevel@tonic-gate 3202*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 3203*7c478bd9Sstevel@tonic-gate "ehci_calculate_bw_availability_mask: bandwidth mask 0x%x", 3204*7c478bd9Sstevel@tonic-gate *bw_mask); 3205*7c478bd9Sstevel@tonic-gate 3206*7c478bd9Sstevel@tonic-gate return (total_bandwidth); 3207*7c478bd9Sstevel@tonic-gate } 3208*7c478bd9Sstevel@tonic-gate 3209*7c478bd9Sstevel@tonic-gate 3210*7c478bd9Sstevel@tonic-gate /* 3211*7c478bd9Sstevel@tonic-gate * ehci_update_bw_availability: 3212*7c478bd9Sstevel@tonic-gate * 3213*7c478bd9Sstevel@tonic-gate * The leftmost leaf needs to be in terms of array position and 3214*7c478bd9Sstevel@tonic-gate * not the actual lattice position. 3215*7c478bd9Sstevel@tonic-gate */ 3216*7c478bd9Sstevel@tonic-gate static void 3217*7c478bd9Sstevel@tonic-gate ehci_update_bw_availability( 3218*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 3219*7c478bd9Sstevel@tonic-gate int bandwidth, 3220*7c478bd9Sstevel@tonic-gate int leftmost_leaf, 3221*7c478bd9Sstevel@tonic-gate int leaf_count, 3222*7c478bd9Sstevel@tonic-gate uchar_t mask) 3223*7c478bd9Sstevel@tonic-gate { 3224*7c478bd9Sstevel@tonic-gate int i, j; 3225*7c478bd9Sstevel@tonic-gate ehci_frame_bandwidth_t *fbp; 3226*7c478bd9Sstevel@tonic-gate int uFrame_bandwidth[8]; 3227*7c478bd9Sstevel@tonic-gate 3228*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3229*7c478bd9Sstevel@tonic-gate "ehci_update_bw_availability: " 3230*7c478bd9Sstevel@tonic-gate "leaf %d count %d bandwidth 0x%x mask 0x%x", 3231*7c478bd9Sstevel@tonic-gate leftmost_leaf, leaf_count, bandwidth, mask); 3232*7c478bd9Sstevel@tonic-gate 3233*7c478bd9Sstevel@tonic-gate ASSERT(leftmost_leaf < 32); 3234*7c478bd9Sstevel@tonic-gate ASSERT(leftmost_leaf >= 0); 3235*7c478bd9Sstevel@tonic-gate 3236*7c478bd9Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) { 3237*7c478bd9Sstevel@tonic-gate if (mask & 0x1) { 3238*7c478bd9Sstevel@tonic-gate uFrame_bandwidth[j] = bandwidth; 3239*7c478bd9Sstevel@tonic-gate } else { 3240*7c478bd9Sstevel@tonic-gate uFrame_bandwidth[j] = 0; 3241*7c478bd9Sstevel@tonic-gate } 3242*7c478bd9Sstevel@tonic-gate 3243*7c478bd9Sstevel@tonic-gate mask = mask >> 1; 3244*7c478bd9Sstevel@tonic-gate } 3245*7c478bd9Sstevel@tonic-gate 3246*7c478bd9Sstevel@tonic-gate /* Updated all the effected leafs with the bandwidth */ 3247*7c478bd9Sstevel@tonic-gate for (i = 0; i < leaf_count; i++) { 3248*7c478bd9Sstevel@tonic-gate fbp = &ehcip->ehci_frame_bandwidth[leftmost_leaf + i]; 3249*7c478bd9Sstevel@tonic-gate 3250*7c478bd9Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) { 3251*7c478bd9Sstevel@tonic-gate fbp->ehci_micro_frame_bandwidth[j] += 3252*7c478bd9Sstevel@tonic-gate uFrame_bandwidth[j]; 3253*7c478bd9Sstevel@tonic-gate fbp->ehci_allocated_frame_bandwidth += 3254*7c478bd9Sstevel@tonic-gate uFrame_bandwidth[j]; 3255*7c478bd9Sstevel@tonic-gate } 3256*7c478bd9Sstevel@tonic-gate } 3257*7c478bd9Sstevel@tonic-gate } 3258*7c478bd9Sstevel@tonic-gate 3259*7c478bd9Sstevel@tonic-gate /* 3260*7c478bd9Sstevel@tonic-gate * Miscellaneous functions 3261*7c478bd9Sstevel@tonic-gate */ 3262*7c478bd9Sstevel@tonic-gate 3263*7c478bd9Sstevel@tonic-gate /* 3264*7c478bd9Sstevel@tonic-gate * ehci_obtain_state: 3265*7c478bd9Sstevel@tonic-gate * 3266*7c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 3267*7c478bd9Sstevel@tonic-gate */ 3268*7c478bd9Sstevel@tonic-gate ehci_state_t * 3269*7c478bd9Sstevel@tonic-gate ehci_obtain_state(dev_info_t *dip) 3270*7c478bd9Sstevel@tonic-gate { 3271*7c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 3272*7c478bd9Sstevel@tonic-gate 3273*7c478bd9Sstevel@tonic-gate ehci_state_t *state = ddi_get_soft_state(ehci_statep, instance); 3274*7c478bd9Sstevel@tonic-gate 3275*7c478bd9Sstevel@tonic-gate ASSERT(state != NULL); 3276*7c478bd9Sstevel@tonic-gate 3277*7c478bd9Sstevel@tonic-gate return (state); 3278*7c478bd9Sstevel@tonic-gate } 3279*7c478bd9Sstevel@tonic-gate 3280*7c478bd9Sstevel@tonic-gate 3281*7c478bd9Sstevel@tonic-gate /* 3282*7c478bd9Sstevel@tonic-gate * ehci_state_is_operational: 3283*7c478bd9Sstevel@tonic-gate * 3284*7c478bd9Sstevel@tonic-gate * Check the Host controller state and return proper values. 3285*7c478bd9Sstevel@tonic-gate */ 3286*7c478bd9Sstevel@tonic-gate int 3287*7c478bd9Sstevel@tonic-gate ehci_state_is_operational(ehci_state_t *ehcip) 3288*7c478bd9Sstevel@tonic-gate { 3289*7c478bd9Sstevel@tonic-gate int val; 3290*7c478bd9Sstevel@tonic-gate 3291*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 3292*7c478bd9Sstevel@tonic-gate 3293*7c478bd9Sstevel@tonic-gate switch (ehcip->ehci_hc_soft_state) { 3294*7c478bd9Sstevel@tonic-gate case EHCI_CTLR_INIT_STATE: 3295*7c478bd9Sstevel@tonic-gate case EHCI_CTLR_SUSPEND_STATE: 3296*7c478bd9Sstevel@tonic-gate val = USB_FAILURE; 3297*7c478bd9Sstevel@tonic-gate break; 3298*7c478bd9Sstevel@tonic-gate case EHCI_CTLR_OPERATIONAL_STATE: 3299*7c478bd9Sstevel@tonic-gate val = USB_SUCCESS; 3300*7c478bd9Sstevel@tonic-gate break; 3301*7c478bd9Sstevel@tonic-gate case EHCI_CTLR_ERROR_STATE: 3302*7c478bd9Sstevel@tonic-gate val = USB_HC_HARDWARE_ERROR; 3303*7c478bd9Sstevel@tonic-gate break; 3304*7c478bd9Sstevel@tonic-gate default: 3305*7c478bd9Sstevel@tonic-gate val = USB_FAILURE; 3306*7c478bd9Sstevel@tonic-gate break; 3307*7c478bd9Sstevel@tonic-gate } 3308*7c478bd9Sstevel@tonic-gate 3309*7c478bd9Sstevel@tonic-gate return (val); 3310*7c478bd9Sstevel@tonic-gate } 3311*7c478bd9Sstevel@tonic-gate 3312*7c478bd9Sstevel@tonic-gate 3313*7c478bd9Sstevel@tonic-gate /* 3314*7c478bd9Sstevel@tonic-gate * ehci_do_soft_reset 3315*7c478bd9Sstevel@tonic-gate * 3316*7c478bd9Sstevel@tonic-gate * Do soft reset of ehci host controller. 3317*7c478bd9Sstevel@tonic-gate */ 3318*7c478bd9Sstevel@tonic-gate int 3319*7c478bd9Sstevel@tonic-gate ehci_do_soft_reset(ehci_state_t *ehcip) 3320*7c478bd9Sstevel@tonic-gate { 3321*7c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 3322*7c478bd9Sstevel@tonic-gate ehci_regs_t *ehci_save_regs; 3323*7c478bd9Sstevel@tonic-gate 3324*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 3325*7c478bd9Sstevel@tonic-gate 3326*7c478bd9Sstevel@tonic-gate /* Increment host controller error count */ 3327*7c478bd9Sstevel@tonic-gate ehcip->ehci_hc_error++; 3328*7c478bd9Sstevel@tonic-gate 3329*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 3330*7c478bd9Sstevel@tonic-gate "ehci_do_soft_reset:" 3331*7c478bd9Sstevel@tonic-gate "Reset ehci host controller 0x%x", ehcip->ehci_hc_error); 3332*7c478bd9Sstevel@tonic-gate 3333*7c478bd9Sstevel@tonic-gate /* 3334*7c478bd9Sstevel@tonic-gate * Allocate space for saving current Host Controller 3335*7c478bd9Sstevel@tonic-gate * registers. Don't do any recovery if allocation 3336*7c478bd9Sstevel@tonic-gate * fails. 3337*7c478bd9Sstevel@tonic-gate */ 3338*7c478bd9Sstevel@tonic-gate ehci_save_regs = (ehci_regs_t *) 3339*7c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (ehci_regs_t), KM_NOSLEEP); 3340*7c478bd9Sstevel@tonic-gate 3341*7c478bd9Sstevel@tonic-gate if (ehci_save_regs == NULL) { 3342*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 3343*7c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: kmem_zalloc failed"); 3344*7c478bd9Sstevel@tonic-gate 3345*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 3346*7c478bd9Sstevel@tonic-gate } 3347*7c478bd9Sstevel@tonic-gate 3348*7c478bd9Sstevel@tonic-gate /* Save current ehci registers */ 3349*7c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_command = Get_OpReg(ehci_command); 3350*7c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_interrupt = Get_OpReg(ehci_interrupt); 3351*7c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_ctrl_segment = Get_OpReg(ehci_ctrl_segment); 3352*7c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_async_list_addr = Get_OpReg(ehci_async_list_addr); 3353*7c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_config_flag = Get_OpReg(ehci_config_flag); 3354*7c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_periodic_list_base = 3355*7c478bd9Sstevel@tonic-gate Get_OpReg(ehci_periodic_list_base); 3356*7c478bd9Sstevel@tonic-gate 3357*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 3358*7c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Save reg = 0x%p", ehci_save_regs); 3359*7c478bd9Sstevel@tonic-gate 3360*7c478bd9Sstevel@tonic-gate /* Disable all list processing and interrupts */ 3361*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, Get_OpReg(ehci_command) & 3362*7c478bd9Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE)); 3363*7c478bd9Sstevel@tonic-gate 3364*7c478bd9Sstevel@tonic-gate /* Disable all EHCI interrupts */ 3365*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0); 3366*7c478bd9Sstevel@tonic-gate 3367*7c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 3368*7c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_SOF_TIMEWAIT); 3369*7c478bd9Sstevel@tonic-gate 3370*7c478bd9Sstevel@tonic-gate /* Do light soft reset of ehci host controller */ 3371*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 3372*7c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) | EHCI_CMD_LIGHT_HC_RESET); 3373*7c478bd9Sstevel@tonic-gate 3374*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 3375*7c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Reset in progress"); 3376*7c478bd9Sstevel@tonic-gate 3377*7c478bd9Sstevel@tonic-gate /* Wait for reset to complete */ 3378*7c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT); 3379*7c478bd9Sstevel@tonic-gate 3380*7c478bd9Sstevel@tonic-gate /* 3381*7c478bd9Sstevel@tonic-gate * Restore previous saved EHCI register value 3382*7c478bd9Sstevel@tonic-gate * into the current EHCI registers. 3383*7c478bd9Sstevel@tonic-gate */ 3384*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_ctrl_segment, (uint32_t) 3385*7c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_ctrl_segment); 3386*7c478bd9Sstevel@tonic-gate 3387*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_periodic_list_base, (uint32_t) 3388*7c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_periodic_list_base); 3389*7c478bd9Sstevel@tonic-gate 3390*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_async_list_addr, (uint32_t) 3391*7c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_async_list_addr); 3392*7c478bd9Sstevel@tonic-gate 3393*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, (uint32_t) 3394*7c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_config_flag); 3395*7c478bd9Sstevel@tonic-gate 3396*7c478bd9Sstevel@tonic-gate /* Enable both Asynchronous and Periodic Schedule if necessary */ 3397*7c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehcip); 3398*7c478bd9Sstevel@tonic-gate 3399*7c478bd9Sstevel@tonic-gate /* 3400*7c478bd9Sstevel@tonic-gate * Set ehci_interrupt to enable all interrupts except Root 3401*7c478bd9Sstevel@tonic-gate * Hub Status change and frame list rollover interrupts. 3402*7c478bd9Sstevel@tonic-gate */ 3403*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR | 3404*7c478bd9Sstevel@tonic-gate EHCI_INTR_FRAME_LIST_ROLLOVER | 3405*7c478bd9Sstevel@tonic-gate EHCI_INTR_USB_ERROR | 3406*7c478bd9Sstevel@tonic-gate EHCI_INTR_USB); 3407*7c478bd9Sstevel@tonic-gate 3408*7c478bd9Sstevel@tonic-gate /* 3409*7c478bd9Sstevel@tonic-gate * Deallocate the space that allocated for saving 3410*7c478bd9Sstevel@tonic-gate * HC registers. 3411*7c478bd9Sstevel@tonic-gate */ 3412*7c478bd9Sstevel@tonic-gate kmem_free((void *) ehci_save_regs, sizeof (ehci_regs_t)); 3413*7c478bd9Sstevel@tonic-gate 3414*7c478bd9Sstevel@tonic-gate /* 3415*7c478bd9Sstevel@tonic-gate * Set the desired interrupt threshold, frame list size (if 3416*7c478bd9Sstevel@tonic-gate * applicable) and turn EHCI host controller. 3417*7c478bd9Sstevel@tonic-gate */ 3418*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, ((Get_OpReg(ehci_command) & 3419*7c478bd9Sstevel@tonic-gate ~EHCI_CMD_INTR_THRESHOLD) | 3420*7c478bd9Sstevel@tonic-gate (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN))); 3421*7c478bd9Sstevel@tonic-gate 3422*7c478bd9Sstevel@tonic-gate /* Wait 10ms for EHCI to start sending SOF */ 3423*7c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT); 3424*7c478bd9Sstevel@tonic-gate 3425*7c478bd9Sstevel@tonic-gate /* 3426*7c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for 3427*7c478bd9Sstevel@tonic-gate * few milliseconds. 3428*7c478bd9Sstevel@tonic-gate */ 3429*7c478bd9Sstevel@tonic-gate before_frame_number = ehci_get_current_frame_number(ehcip); 3430*7c478bd9Sstevel@tonic-gate 3431*7c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 3432*7c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_SOF_TIMEWAIT); 3433*7c478bd9Sstevel@tonic-gate 3434*7c478bd9Sstevel@tonic-gate /* 3435*7c478bd9Sstevel@tonic-gate * Get the current usb frame number after waiting for 3436*7c478bd9Sstevel@tonic-gate * few milliseconds. 3437*7c478bd9Sstevel@tonic-gate */ 3438*7c478bd9Sstevel@tonic-gate after_frame_number = ehci_get_current_frame_number(ehcip); 3439*7c478bd9Sstevel@tonic-gate 3440*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 3441*7c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Before Frame Number 0x%llx " 3442*7c478bd9Sstevel@tonic-gate "After Frame Number 0x%llx", 3443*7c478bd9Sstevel@tonic-gate before_frame_number, after_frame_number); 3444*7c478bd9Sstevel@tonic-gate 3445*7c478bd9Sstevel@tonic-gate if ((after_frame_number <= before_frame_number) && 3446*7c478bd9Sstevel@tonic-gate (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) { 3447*7c478bd9Sstevel@tonic-gate 3448*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 3449*7c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Soft reset failed"); 3450*7c478bd9Sstevel@tonic-gate 3451*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 3452*7c478bd9Sstevel@tonic-gate } 3453*7c478bd9Sstevel@tonic-gate 3454*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 3455*7c478bd9Sstevel@tonic-gate } 3456*7c478bd9Sstevel@tonic-gate 3457*7c478bd9Sstevel@tonic-gate 3458*7c478bd9Sstevel@tonic-gate /* 3459*7c478bd9Sstevel@tonic-gate * ehci_get_xfer_attrs: 3460*7c478bd9Sstevel@tonic-gate * 3461*7c478bd9Sstevel@tonic-gate * Get the attributes of a particular xfer. 3462*7c478bd9Sstevel@tonic-gate * 3463*7c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 3464*7c478bd9Sstevel@tonic-gate */ 3465*7c478bd9Sstevel@tonic-gate usb_req_attrs_t 3466*7c478bd9Sstevel@tonic-gate ehci_get_xfer_attrs( 3467*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 3468*7c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 3469*7c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 3470*7c478bd9Sstevel@tonic-gate { 3471*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep; 3472*7c478bd9Sstevel@tonic-gate usb_req_attrs_t attrs = USB_ATTRS_NONE; 3473*7c478bd9Sstevel@tonic-gate 3474*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3475*7c478bd9Sstevel@tonic-gate "ehci_get_xfer_attrs:"); 3476*7c478bd9Sstevel@tonic-gate 3477*7c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 3478*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 3479*7c478bd9Sstevel@tonic-gate attrs = ((usb_ctrl_req_t *) 3480*7c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->ctrl_attributes; 3481*7c478bd9Sstevel@tonic-gate break; 3482*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 3483*7c478bd9Sstevel@tonic-gate attrs = ((usb_bulk_req_t *) 3484*7c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->bulk_attributes; 3485*7c478bd9Sstevel@tonic-gate break; 3486*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 3487*7c478bd9Sstevel@tonic-gate attrs = ((usb_intr_req_t *) 3488*7c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->intr_attributes; 3489*7c478bd9Sstevel@tonic-gate break; 3490*7c478bd9Sstevel@tonic-gate } 3491*7c478bd9Sstevel@tonic-gate 3492*7c478bd9Sstevel@tonic-gate return (attrs); 3493*7c478bd9Sstevel@tonic-gate } 3494*7c478bd9Sstevel@tonic-gate 3495*7c478bd9Sstevel@tonic-gate 3496*7c478bd9Sstevel@tonic-gate /* 3497*7c478bd9Sstevel@tonic-gate * ehci_get_current_frame_number: 3498*7c478bd9Sstevel@tonic-gate * 3499*7c478bd9Sstevel@tonic-gate * Get the current software based usb frame number. 3500*7c478bd9Sstevel@tonic-gate */ 3501*7c478bd9Sstevel@tonic-gate usb_frame_number_t 3502*7c478bd9Sstevel@tonic-gate ehci_get_current_frame_number(ehci_state_t *ehcip) 3503*7c478bd9Sstevel@tonic-gate { 3504*7c478bd9Sstevel@tonic-gate usb_frame_number_t usb_frame_number; 3505*7c478bd9Sstevel@tonic-gate usb_frame_number_t ehci_fno, micro_frame_number; 3506*7c478bd9Sstevel@tonic-gate 3507*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 3508*7c478bd9Sstevel@tonic-gate 3509*7c478bd9Sstevel@tonic-gate ehci_fno = ehcip->ehci_fno; 3510*7c478bd9Sstevel@tonic-gate micro_frame_number = Get_OpReg(ehci_frame_index) & 0x3FFF; 3511*7c478bd9Sstevel@tonic-gate 3512*7c478bd9Sstevel@tonic-gate /* 3513*7c478bd9Sstevel@tonic-gate * Calculate current software based usb frame number. 3514*7c478bd9Sstevel@tonic-gate * 3515*7c478bd9Sstevel@tonic-gate * This code accounts for the fact that frame number is 3516*7c478bd9Sstevel@tonic-gate * updated by the Host Controller before the ehci driver 3517*7c478bd9Sstevel@tonic-gate * gets an FrameListRollover interrupt that will adjust 3518*7c478bd9Sstevel@tonic-gate * Frame higher part. 3519*7c478bd9Sstevel@tonic-gate * 3520*7c478bd9Sstevel@tonic-gate * Refer ehci specification 1.0, section 2.3.2, page 21. 3521*7c478bd9Sstevel@tonic-gate */ 3522*7c478bd9Sstevel@tonic-gate micro_frame_number = ((micro_frame_number & 0x1FFF) | 3523*7c478bd9Sstevel@tonic-gate ehci_fno) + (((micro_frame_number & 0x3FFF) ^ 3524*7c478bd9Sstevel@tonic-gate ehci_fno) & 0x2000); 3525*7c478bd9Sstevel@tonic-gate 3526*7c478bd9Sstevel@tonic-gate /* 3527*7c478bd9Sstevel@tonic-gate * Micro Frame number is equivalent to 125 usec. Eight 3528*7c478bd9Sstevel@tonic-gate * Micro Frame numbers are equivalent to one millsecond 3529*7c478bd9Sstevel@tonic-gate * or one usb frame number. 3530*7c478bd9Sstevel@tonic-gate */ 3531*7c478bd9Sstevel@tonic-gate usb_frame_number = micro_frame_number >> 3532*7c478bd9Sstevel@tonic-gate EHCI_uFRAMES_PER_USB_FRAME_SHIFT; 3533*7c478bd9Sstevel@tonic-gate 3534*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3535*7c478bd9Sstevel@tonic-gate "ehci_get_current_frame_number: " 3536*7c478bd9Sstevel@tonic-gate "Current usb uframe number = 0x%llx " 3537*7c478bd9Sstevel@tonic-gate "Current usb frame number = 0x%llx", 3538*7c478bd9Sstevel@tonic-gate micro_frame_number, usb_frame_number); 3539*7c478bd9Sstevel@tonic-gate 3540*7c478bd9Sstevel@tonic-gate return (usb_frame_number); 3541*7c478bd9Sstevel@tonic-gate } 3542*7c478bd9Sstevel@tonic-gate 3543*7c478bd9Sstevel@tonic-gate 3544*7c478bd9Sstevel@tonic-gate /* 3545*7c478bd9Sstevel@tonic-gate * ehci_cpr_cleanup: 3546*7c478bd9Sstevel@tonic-gate * 3547*7c478bd9Sstevel@tonic-gate * Cleanup ehci state and other ehci specific informations across 3548*7c478bd9Sstevel@tonic-gate * Check Point Resume (CPR). 3549*7c478bd9Sstevel@tonic-gate */ 3550*7c478bd9Sstevel@tonic-gate static void 3551*7c478bd9Sstevel@tonic-gate ehci_cpr_cleanup(ehci_state_t *ehcip) 3552*7c478bd9Sstevel@tonic-gate { 3553*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 3554*7c478bd9Sstevel@tonic-gate 3555*7c478bd9Sstevel@tonic-gate /* Reset software part of usb frame number */ 3556*7c478bd9Sstevel@tonic-gate ehcip->ehci_fno = 0; 3557*7c478bd9Sstevel@tonic-gate } 3558*7c478bd9Sstevel@tonic-gate 3559*7c478bd9Sstevel@tonic-gate 3560*7c478bd9Sstevel@tonic-gate /* 3561*7c478bd9Sstevel@tonic-gate * ehci_wait_for_sof: 3562*7c478bd9Sstevel@tonic-gate * 3563*7c478bd9Sstevel@tonic-gate * Wait for couple of SOF interrupts 3564*7c478bd9Sstevel@tonic-gate */ 3565*7c478bd9Sstevel@tonic-gate int 3566*7c478bd9Sstevel@tonic-gate ehci_wait_for_sof(ehci_state_t *ehcip) 3567*7c478bd9Sstevel@tonic-gate { 3568*7c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 3569*7c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 3570*7c478bd9Sstevel@tonic-gate 3571*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, 3572*7c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, "ehci_wait_for_sof"); 3573*7c478bd9Sstevel@tonic-gate 3574*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 3575*7c478bd9Sstevel@tonic-gate 3576*7c478bd9Sstevel@tonic-gate error = ehci_state_is_operational(ehcip); 3577*7c478bd9Sstevel@tonic-gate 3578*7c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 3579*7c478bd9Sstevel@tonic-gate 3580*7c478bd9Sstevel@tonic-gate return (error); 3581*7c478bd9Sstevel@tonic-gate } 3582*7c478bd9Sstevel@tonic-gate 3583*7c478bd9Sstevel@tonic-gate /* Get the current usb frame number before waiting for two SOFs */ 3584*7c478bd9Sstevel@tonic-gate before_frame_number = ehci_get_current_frame_number(ehcip); 3585*7c478bd9Sstevel@tonic-gate 3586*7c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 3587*7c478bd9Sstevel@tonic-gate 3588*7c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 3589*7c478bd9Sstevel@tonic-gate delay(drv_usectohz(EHCI_SOF_TIMEWAIT)); 3590*7c478bd9Sstevel@tonic-gate 3591*7c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 3592*7c478bd9Sstevel@tonic-gate 3593*7c478bd9Sstevel@tonic-gate /* Get the current usb frame number after woken up */ 3594*7c478bd9Sstevel@tonic-gate after_frame_number = ehci_get_current_frame_number(ehcip); 3595*7c478bd9Sstevel@tonic-gate 3596*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3597*7c478bd9Sstevel@tonic-gate "ehci_wait_for_sof: framenumber: before 0x%llx " 3598*7c478bd9Sstevel@tonic-gate "after 0x%llx", before_frame_number, after_frame_number); 3599*7c478bd9Sstevel@tonic-gate 3600*7c478bd9Sstevel@tonic-gate /* Return failure, if usb frame number has not been changed */ 3601*7c478bd9Sstevel@tonic-gate if (after_frame_number <= before_frame_number) { 3602*7c478bd9Sstevel@tonic-gate 3603*7c478bd9Sstevel@tonic-gate if ((ehci_do_soft_reset(ehcip)) != USB_SUCCESS) { 3604*7c478bd9Sstevel@tonic-gate 3605*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_LISTS, 3606*7c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, "No SOF interrupts"); 3607*7c478bd9Sstevel@tonic-gate 3608*7c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */ 3609*7c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE; 3610*7c478bd9Sstevel@tonic-gate 3611*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 3612*7c478bd9Sstevel@tonic-gate } 3613*7c478bd9Sstevel@tonic-gate 3614*7c478bd9Sstevel@tonic-gate /* Get new usb frame number */ 3615*7c478bd9Sstevel@tonic-gate after_frame_number = before_frame_number = 3616*7c478bd9Sstevel@tonic-gate ehci_get_current_frame_number(ehcip); 3617*7c478bd9Sstevel@tonic-gate } 3618*7c478bd9Sstevel@tonic-gate 3619*7c478bd9Sstevel@tonic-gate ASSERT(after_frame_number > before_frame_number); 3620*7c478bd9Sstevel@tonic-gate 3621*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 3622*7c478bd9Sstevel@tonic-gate } 3623*7c478bd9Sstevel@tonic-gate 3624*7c478bd9Sstevel@tonic-gate 3625*7c478bd9Sstevel@tonic-gate /* 3626*7c478bd9Sstevel@tonic-gate * ehci_toggle_scheduler: 3627*7c478bd9Sstevel@tonic-gate * 3628*7c478bd9Sstevel@tonic-gate * Turn scheduler based on pipe open count. 3629*7c478bd9Sstevel@tonic-gate */ 3630*7c478bd9Sstevel@tonic-gate void 3631*7c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehci_state_t *ehcip) { 3632*7c478bd9Sstevel@tonic-gate uint_t temp_reg, cmd_reg; 3633*7c478bd9Sstevel@tonic-gate 3634*7c478bd9Sstevel@tonic-gate cmd_reg = Get_OpReg(ehci_command); 3635*7c478bd9Sstevel@tonic-gate temp_reg = cmd_reg; 3636*7c478bd9Sstevel@tonic-gate 3637*7c478bd9Sstevel@tonic-gate /* 3638*7c478bd9Sstevel@tonic-gate * Enable/Disable asynchronous scheduler, and 3639*7c478bd9Sstevel@tonic-gate * turn on/off async list door bell 3640*7c478bd9Sstevel@tonic-gate */ 3641*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_open_async_count) { 3642*7c478bd9Sstevel@tonic-gate if (!(cmd_reg & EHCI_CMD_ASYNC_SCHED_ENABLE)) { 3643*7c478bd9Sstevel@tonic-gate /* 3644*7c478bd9Sstevel@tonic-gate * For some reason this address might get nulled out by 3645*7c478bd9Sstevel@tonic-gate * the ehci chip. Set it here just in case it is null. 3646*7c478bd9Sstevel@tonic-gate */ 3647*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_async_list_addr, 3648*7c478bd9Sstevel@tonic-gate ehci_qh_cpu_to_iommu(ehcip, 3649*7c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list)); 3650*7c478bd9Sstevel@tonic-gate } 3651*7c478bd9Sstevel@tonic-gate cmd_reg |= EHCI_CMD_ASYNC_SCHED_ENABLE; 3652*7c478bd9Sstevel@tonic-gate } else { 3653*7c478bd9Sstevel@tonic-gate cmd_reg &= ~EHCI_CMD_ASYNC_SCHED_ENABLE; 3654*7c478bd9Sstevel@tonic-gate } 3655*7c478bd9Sstevel@tonic-gate 3656*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_open_periodic_count) { 3657*7c478bd9Sstevel@tonic-gate if (!(cmd_reg & EHCI_CMD_PERIODIC_SCHED_ENABLE)) { 3658*7c478bd9Sstevel@tonic-gate /* 3659*7c478bd9Sstevel@tonic-gate * For some reason this address get's nulled out by 3660*7c478bd9Sstevel@tonic-gate * the ehci chip. Set it here just in case it is null. 3661*7c478bd9Sstevel@tonic-gate */ 3662*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_periodic_list_base, 3663*7c478bd9Sstevel@tonic-gate (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address & 3664*7c478bd9Sstevel@tonic-gate 0xFFFFF000)); 3665*7c478bd9Sstevel@tonic-gate } 3666*7c478bd9Sstevel@tonic-gate cmd_reg |= EHCI_CMD_PERIODIC_SCHED_ENABLE; 3667*7c478bd9Sstevel@tonic-gate } else { 3668*7c478bd9Sstevel@tonic-gate cmd_reg &= ~EHCI_CMD_PERIODIC_SCHED_ENABLE; 3669*7c478bd9Sstevel@tonic-gate } 3670*7c478bd9Sstevel@tonic-gate 3671*7c478bd9Sstevel@tonic-gate /* Just an optimization */ 3672*7c478bd9Sstevel@tonic-gate if (temp_reg != cmd_reg) { 3673*7c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, cmd_reg); 3674*7c478bd9Sstevel@tonic-gate } 3675*7c478bd9Sstevel@tonic-gate } 3676*7c478bd9Sstevel@tonic-gate 3677*7c478bd9Sstevel@tonic-gate /* 3678*7c478bd9Sstevel@tonic-gate * ehci print functions 3679*7c478bd9Sstevel@tonic-gate */ 3680*7c478bd9Sstevel@tonic-gate 3681*7c478bd9Sstevel@tonic-gate /* 3682*7c478bd9Sstevel@tonic-gate * ehci_print_caps: 3683*7c478bd9Sstevel@tonic-gate */ 3684*7c478bd9Sstevel@tonic-gate void 3685*7c478bd9Sstevel@tonic-gate ehci_print_caps(ehci_state_t *ehcip) 3686*7c478bd9Sstevel@tonic-gate { 3687*7c478bd9Sstevel@tonic-gate uint_t i; 3688*7c478bd9Sstevel@tonic-gate 3689*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3690*7c478bd9Sstevel@tonic-gate "\n\tUSB 2.0 Host Controller Characteristics\n"); 3691*7c478bd9Sstevel@tonic-gate 3692*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3693*7c478bd9Sstevel@tonic-gate "Caps Length: 0x%x Version: 0x%x\n", 3694*7c478bd9Sstevel@tonic-gate Get_8Cap(ehci_caps_length), Get_16Cap(ehci_version)); 3695*7c478bd9Sstevel@tonic-gate 3696*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3697*7c478bd9Sstevel@tonic-gate "Structural Parameters\n"); 3698*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3699*7c478bd9Sstevel@tonic-gate "Port indicators: %s", (Get_Cap(ehci_hcs_params) & 3700*7c478bd9Sstevel@tonic-gate EHCI_HCS_PORT_INDICATOR) ? "Yes" : "No"); 3701*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3702*7c478bd9Sstevel@tonic-gate "No of Classic host controllers: 0x%x", 3703*7c478bd9Sstevel@tonic-gate (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_COMP_CTRLS) 3704*7c478bd9Sstevel@tonic-gate >> EHCI_HCS_NUM_COMP_CTRL_SHIFT); 3705*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3706*7c478bd9Sstevel@tonic-gate "No of ports per Classic host controller: 0x%x", 3707*7c478bd9Sstevel@tonic-gate (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS_CC) 3708*7c478bd9Sstevel@tonic-gate >> EHCI_HCS_NUM_PORTS_CC_SHIFT); 3709*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3710*7c478bd9Sstevel@tonic-gate "Port routing rules: %s", (Get_Cap(ehci_hcs_params) & 3711*7c478bd9Sstevel@tonic-gate EHCI_HCS_PORT_ROUTING_RULES) ? "Yes" : "No"); 3712*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3713*7c478bd9Sstevel@tonic-gate "Port power control: %s", (Get_Cap(ehci_hcs_params) & 3714*7c478bd9Sstevel@tonic-gate EHCI_HCS_PORT_POWER_CONTROL) ? "Yes" : "No"); 3715*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3716*7c478bd9Sstevel@tonic-gate "No of root hub ports: 0x%x\n", 3717*7c478bd9Sstevel@tonic-gate Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); 3718*7c478bd9Sstevel@tonic-gate 3719*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3720*7c478bd9Sstevel@tonic-gate "Capability Parameters\n"); 3721*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3722*7c478bd9Sstevel@tonic-gate "EHCI extended capability: %s", (Get_Cap(ehci_hcc_params) & 3723*7c478bd9Sstevel@tonic-gate EHCI_HCC_EECP) ? "Yes" : "No"); 3724*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3725*7c478bd9Sstevel@tonic-gate "Isoch schedule threshold: 0x%x", 3726*7c478bd9Sstevel@tonic-gate Get_Cap(ehci_hcc_params) & EHCI_HCC_ISOCH_SCHED_THRESHOLD); 3727*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3728*7c478bd9Sstevel@tonic-gate "Async schedule park capability: %s", (Get_Cap(ehci_hcc_params) & 3729*7c478bd9Sstevel@tonic-gate EHCI_HCC_ASYNC_SCHED_PARK_CAP) ? "Yes" : "No"); 3730*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3731*7c478bd9Sstevel@tonic-gate "Programmable frame list flag: %s", (Get_Cap(ehci_hcc_params) & 3732*7c478bd9Sstevel@tonic-gate EHCI_HCC_PROG_FRAME_LIST_FLAG) ? "256/512/1024" : "1024"); 3733*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3734*7c478bd9Sstevel@tonic-gate "64bit addressing capability: %s\n", (Get_Cap(ehci_hcc_params) & 3735*7c478bd9Sstevel@tonic-gate EHCI_HCC_64BIT_ADDR_CAP) ? "Yes" : "No"); 3736*7c478bd9Sstevel@tonic-gate 3737*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3738*7c478bd9Sstevel@tonic-gate "Classic Port Route Description"); 3739*7c478bd9Sstevel@tonic-gate 3740*7c478bd9Sstevel@tonic-gate for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) { 3741*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3742*7c478bd9Sstevel@tonic-gate "\tPort Route 0x%x: 0x%x", i, Get_8Cap(ehci_port_route[i])); 3743*7c478bd9Sstevel@tonic-gate } 3744*7c478bd9Sstevel@tonic-gate } 3745*7c478bd9Sstevel@tonic-gate 3746*7c478bd9Sstevel@tonic-gate 3747*7c478bd9Sstevel@tonic-gate /* 3748*7c478bd9Sstevel@tonic-gate * ehci_print_regs: 3749*7c478bd9Sstevel@tonic-gate */ 3750*7c478bd9Sstevel@tonic-gate void 3751*7c478bd9Sstevel@tonic-gate ehci_print_regs(ehci_state_t *ehcip) 3752*7c478bd9Sstevel@tonic-gate { 3753*7c478bd9Sstevel@tonic-gate uint_t i; 3754*7c478bd9Sstevel@tonic-gate 3755*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3756*7c478bd9Sstevel@tonic-gate "\n\tEHCI%d Operational Registers\n", 3757*7c478bd9Sstevel@tonic-gate ddi_get_instance(ehcip->ehci_dip)); 3758*7c478bd9Sstevel@tonic-gate 3759*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3760*7c478bd9Sstevel@tonic-gate "Command: 0x%x Status: 0x%x", 3761*7c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command), Get_OpReg(ehci_status)); 3762*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3763*7c478bd9Sstevel@tonic-gate "Interrupt: 0x%x Frame Index: 0x%x", 3764*7c478bd9Sstevel@tonic-gate Get_OpReg(ehci_interrupt), Get_OpReg(ehci_frame_index)); 3765*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3766*7c478bd9Sstevel@tonic-gate "Control Segment: 0x%x Periodic List Base: 0x%x", 3767*7c478bd9Sstevel@tonic-gate Get_OpReg(ehci_ctrl_segment), Get_OpReg(ehci_periodic_list_base)); 3768*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3769*7c478bd9Sstevel@tonic-gate "Async List Addr: 0x%x Config Flag: 0x%x", 3770*7c478bd9Sstevel@tonic-gate Get_OpReg(ehci_async_list_addr), Get_OpReg(ehci_config_flag)); 3771*7c478bd9Sstevel@tonic-gate 3772*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3773*7c478bd9Sstevel@tonic-gate "Root Hub Port Status"); 3774*7c478bd9Sstevel@tonic-gate 3775*7c478bd9Sstevel@tonic-gate for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) { 3776*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3777*7c478bd9Sstevel@tonic-gate "\tPort Status 0x%x: 0x%x ", i, 3778*7c478bd9Sstevel@tonic-gate Get_OpReg(ehci_rh_port_status[i])); 3779*7c478bd9Sstevel@tonic-gate } 3780*7c478bd9Sstevel@tonic-gate } 3781*7c478bd9Sstevel@tonic-gate 3782*7c478bd9Sstevel@tonic-gate 3783*7c478bd9Sstevel@tonic-gate /* 3784*7c478bd9Sstevel@tonic-gate * ehci_print_qh: 3785*7c478bd9Sstevel@tonic-gate */ 3786*7c478bd9Sstevel@tonic-gate void 3787*7c478bd9Sstevel@tonic-gate ehci_print_qh( 3788*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 3789*7c478bd9Sstevel@tonic-gate ehci_qh_t *qh) 3790*7c478bd9Sstevel@tonic-gate { 3791*7c478bd9Sstevel@tonic-gate uint_t i; 3792*7c478bd9Sstevel@tonic-gate 3793*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3794*7c478bd9Sstevel@tonic-gate "ehci_print_qh: qh = 0x%p", (void *)qh); 3795*7c478bd9Sstevel@tonic-gate 3796*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3797*7c478bd9Sstevel@tonic-gate "\tqh_link_ptr: 0x%x ", Get_QH(qh->qh_link_ptr)); 3798*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3799*7c478bd9Sstevel@tonic-gate "\tqh_ctrl: 0x%x ", Get_QH(qh->qh_ctrl)); 3800*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3801*7c478bd9Sstevel@tonic-gate "\tqh_split_ctrl: 0x%x ", Get_QH(qh->qh_split_ctrl)); 3802*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3803*7c478bd9Sstevel@tonic-gate "\tqh_curr_qtd: 0x%x ", Get_QH(qh->qh_curr_qtd)); 3804*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3805*7c478bd9Sstevel@tonic-gate "\tqh_next_qtd: 0x%x ", Get_QH(qh->qh_next_qtd)); 3806*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3807*7c478bd9Sstevel@tonic-gate "\tqh_alt_next_qtd: 0x%x ", Get_QH(qh->qh_alt_next_qtd)); 3808*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3809*7c478bd9Sstevel@tonic-gate "\tqh_status: 0x%x ", Get_QH(qh->qh_status)); 3810*7c478bd9Sstevel@tonic-gate 3811*7c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 3812*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3813*7c478bd9Sstevel@tonic-gate "\tqh_buf[%d]: 0x%x ", i, Get_QH(qh->qh_buf[i])); 3814*7c478bd9Sstevel@tonic-gate } 3815*7c478bd9Sstevel@tonic-gate 3816*7c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 3817*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3818*7c478bd9Sstevel@tonic-gate "\tqh_buf_high[%d]: 0x%x ", 3819*7c478bd9Sstevel@tonic-gate i, Get_QH(qh->qh_buf_high[i])); 3820*7c478bd9Sstevel@tonic-gate } 3821*7c478bd9Sstevel@tonic-gate 3822*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3823*7c478bd9Sstevel@tonic-gate "\tqh_dummy_qtd: 0x%x ", Get_QH(qh->qh_dummy_qtd)); 3824*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3825*7c478bd9Sstevel@tonic-gate "\tqh_prev: 0x%x ", Get_QH(qh->qh_prev)); 3826*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3827*7c478bd9Sstevel@tonic-gate "\tqh_state: 0x%x ", Get_QH(qh->qh_state)); 3828*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3829*7c478bd9Sstevel@tonic-gate "\tqh_reclaim_next: 0x%x ", Get_QH(qh->qh_reclaim_next)); 3830*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3831*7c478bd9Sstevel@tonic-gate "\tqh_reclaim_frame: 0x%x ", Get_QH(qh->qh_reclaim_frame)); 3832*7c478bd9Sstevel@tonic-gate } 3833*7c478bd9Sstevel@tonic-gate 3834*7c478bd9Sstevel@tonic-gate 3835*7c478bd9Sstevel@tonic-gate /* 3836*7c478bd9Sstevel@tonic-gate * ehci_print_qtd: 3837*7c478bd9Sstevel@tonic-gate */ 3838*7c478bd9Sstevel@tonic-gate void 3839*7c478bd9Sstevel@tonic-gate ehci_print_qtd( 3840*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 3841*7c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd) 3842*7c478bd9Sstevel@tonic-gate { 3843*7c478bd9Sstevel@tonic-gate uint_t i; 3844*7c478bd9Sstevel@tonic-gate 3845*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3846*7c478bd9Sstevel@tonic-gate "ehci_print_qtd: qtd = 0x%p", (void *)qtd); 3847*7c478bd9Sstevel@tonic-gate 3848*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3849*7c478bd9Sstevel@tonic-gate "\tqtd_next_qtd: 0x%x ", Get_QTD(qtd->qtd_next_qtd)); 3850*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3851*7c478bd9Sstevel@tonic-gate "\tqtd_alt_next_qtd: 0x%x ", Get_QTD(qtd->qtd_alt_next_qtd)); 3852*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3853*7c478bd9Sstevel@tonic-gate "\tqtd_ctrl: 0x%x ", Get_QTD(qtd->qtd_ctrl)); 3854*7c478bd9Sstevel@tonic-gate 3855*7c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 3856*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3857*7c478bd9Sstevel@tonic-gate "\tqtd_buf[%d]: 0x%x ", i, Get_QTD(qtd->qtd_buf[i])); 3858*7c478bd9Sstevel@tonic-gate } 3859*7c478bd9Sstevel@tonic-gate 3860*7c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 3861*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3862*7c478bd9Sstevel@tonic-gate "\tqtd_buf_high[%d]: 0x%x ", 3863*7c478bd9Sstevel@tonic-gate i, Get_QTD(qtd->qtd_buf_high[i])); 3864*7c478bd9Sstevel@tonic-gate } 3865*7c478bd9Sstevel@tonic-gate 3866*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3867*7c478bd9Sstevel@tonic-gate "\tqtd_trans_wrapper: 0x%x ", Get_QTD(qtd->qtd_trans_wrapper)); 3868*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3869*7c478bd9Sstevel@tonic-gate "\tqtd_tw_next_qtd: 0x%x ", Get_QTD(qtd->qtd_tw_next_qtd)); 3870*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3871*7c478bd9Sstevel@tonic-gate "\tqtd_active_qtd_next: 0x%x ", Get_QTD(qtd->qtd_active_qtd_next)); 3872*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3873*7c478bd9Sstevel@tonic-gate "\tqtd_active_qtd_prev: 0x%x ", Get_QTD(qtd->qtd_active_qtd_prev)); 3874*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3875*7c478bd9Sstevel@tonic-gate "\tqtd_state: 0x%x ", Get_QTD(qtd->qtd_state)); 3876*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3877*7c478bd9Sstevel@tonic-gate "\tqtd_ctrl_phase: 0x%x ", Get_QTD(qtd->qtd_ctrl_phase)); 3878*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3879*7c478bd9Sstevel@tonic-gate "\tqtd_xfer_addr: 0x%x ", Get_QTD(qtd->qtd_xfer_addr)); 3880*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 3881*7c478bd9Sstevel@tonic-gate "\tqtd_xfer_len: 0x%x ", Get_QTD(qtd->qtd_xfer_len)); 3882*7c478bd9Sstevel@tonic-gate } 3883*7c478bd9Sstevel@tonic-gate 3884*7c478bd9Sstevel@tonic-gate /* 3885*7c478bd9Sstevel@tonic-gate * ehci kstat functions 3886*7c478bd9Sstevel@tonic-gate */ 3887*7c478bd9Sstevel@tonic-gate 3888*7c478bd9Sstevel@tonic-gate /* 3889*7c478bd9Sstevel@tonic-gate * ehci_create_stats: 3890*7c478bd9Sstevel@tonic-gate * 3891*7c478bd9Sstevel@tonic-gate * Allocate and initialize the ehci kstat structures 3892*7c478bd9Sstevel@tonic-gate */ 3893*7c478bd9Sstevel@tonic-gate void 3894*7c478bd9Sstevel@tonic-gate ehci_create_stats(ehci_state_t *ehcip) 3895*7c478bd9Sstevel@tonic-gate { 3896*7c478bd9Sstevel@tonic-gate char kstatname[KSTAT_STRLEN]; 3897*7c478bd9Sstevel@tonic-gate const char *dname = ddi_driver_name(ehcip->ehci_dip); 3898*7c478bd9Sstevel@tonic-gate char *usbtypes[USB_N_COUNT_KSTATS] = 3899*7c478bd9Sstevel@tonic-gate {"ctrl", "isoch", "bulk", "intr"}; 3900*7c478bd9Sstevel@tonic-gate uint_t instance = ehcip->ehci_instance; 3901*7c478bd9Sstevel@tonic-gate ehci_intrs_stats_t *isp; 3902*7c478bd9Sstevel@tonic-gate int i; 3903*7c478bd9Sstevel@tonic-gate 3904*7c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip) == NULL) { 3905*7c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,intrs", 3906*7c478bd9Sstevel@tonic-gate dname, instance); 3907*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip) = kstat_create("usba", instance, 3908*7c478bd9Sstevel@tonic-gate kstatname, "usb_interrupts", KSTAT_TYPE_NAMED, 3909*7c478bd9Sstevel@tonic-gate sizeof (ehci_intrs_stats_t) / sizeof (kstat_named_t), 3910*7c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 3911*7c478bd9Sstevel@tonic-gate 3912*7c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) { 3913*7c478bd9Sstevel@tonic-gate isp = EHCI_INTRS_STATS_DATA(ehcip); 3914*7c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_total, 3915*7c478bd9Sstevel@tonic-gate "Interrupts Total", KSTAT_DATA_UINT64); 3916*7c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_not_claimed, 3917*7c478bd9Sstevel@tonic-gate "Not Claimed", KSTAT_DATA_UINT64); 3918*7c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_async_sched_status, 3919*7c478bd9Sstevel@tonic-gate "Async schedule status", KSTAT_DATA_UINT64); 3920*7c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_periodic_sched_status, 3921*7c478bd9Sstevel@tonic-gate "Periodic sched status", KSTAT_DATA_UINT64); 3922*7c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_empty_async_schedule, 3923*7c478bd9Sstevel@tonic-gate "Empty async schedule", KSTAT_DATA_UINT64); 3924*7c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_host_ctrl_halted, 3925*7c478bd9Sstevel@tonic-gate "Host controller Halted", KSTAT_DATA_UINT64); 3926*7c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_async_advance_intr, 3927*7c478bd9Sstevel@tonic-gate "Intr on async advance", KSTAT_DATA_UINT64); 3928*7c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_host_system_error_intr, 3929*7c478bd9Sstevel@tonic-gate "Host system error", KSTAT_DATA_UINT64); 3930*7c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_frm_list_rollover_intr, 3931*7c478bd9Sstevel@tonic-gate "Frame list rollover", KSTAT_DATA_UINT64); 3932*7c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_rh_port_change_intr, 3933*7c478bd9Sstevel@tonic-gate "Port change detect", KSTAT_DATA_UINT64); 3934*7c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_usb_error_intr, 3935*7c478bd9Sstevel@tonic-gate "USB error interrupt", KSTAT_DATA_UINT64); 3936*7c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_usb_intr, 3937*7c478bd9Sstevel@tonic-gate "USB interrupt", KSTAT_DATA_UINT64); 3938*7c478bd9Sstevel@tonic-gate 3939*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip)->ks_private = ehcip; 3940*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip)->ks_update = nulldev; 3941*7c478bd9Sstevel@tonic-gate kstat_install(EHCI_INTRS_STATS(ehcip)); 3942*7c478bd9Sstevel@tonic-gate } 3943*7c478bd9Sstevel@tonic-gate } 3944*7c478bd9Sstevel@tonic-gate 3945*7c478bd9Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip) == NULL) { 3946*7c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,total", 3947*7c478bd9Sstevel@tonic-gate dname, instance); 3948*7c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS(ehcip) = kstat_create("usba", instance, 3949*7c478bd9Sstevel@tonic-gate kstatname, "usb_byte_count", KSTAT_TYPE_IO, 1, 3950*7c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 3951*7c478bd9Sstevel@tonic-gate 3952*7c478bd9Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip)) { 3953*7c478bd9Sstevel@tonic-gate kstat_install(EHCI_TOTAL_STATS(ehcip)); 3954*7c478bd9Sstevel@tonic-gate } 3955*7c478bd9Sstevel@tonic-gate } 3956*7c478bd9Sstevel@tonic-gate 3957*7c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) { 3958*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_count_stats[i] == NULL) { 3959*7c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,%s", 3960*7c478bd9Sstevel@tonic-gate dname, instance, usbtypes[i]); 3961*7c478bd9Sstevel@tonic-gate ehcip->ehci_count_stats[i] = kstat_create("usba", 3962*7c478bd9Sstevel@tonic-gate instance, kstatname, "usb_byte_count", 3963*7c478bd9Sstevel@tonic-gate KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT); 3964*7c478bd9Sstevel@tonic-gate 3965*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_count_stats[i]) { 3966*7c478bd9Sstevel@tonic-gate kstat_install(ehcip->ehci_count_stats[i]); 3967*7c478bd9Sstevel@tonic-gate } 3968*7c478bd9Sstevel@tonic-gate } 3969*7c478bd9Sstevel@tonic-gate } 3970*7c478bd9Sstevel@tonic-gate } 3971*7c478bd9Sstevel@tonic-gate 3972*7c478bd9Sstevel@tonic-gate 3973*7c478bd9Sstevel@tonic-gate /* 3974*7c478bd9Sstevel@tonic-gate * ehci_destroy_stats: 3975*7c478bd9Sstevel@tonic-gate * 3976*7c478bd9Sstevel@tonic-gate * Clean up ehci kstat structures 3977*7c478bd9Sstevel@tonic-gate */ 3978*7c478bd9Sstevel@tonic-gate void 3979*7c478bd9Sstevel@tonic-gate ehci_destroy_stats(ehci_state_t *ehcip) 3980*7c478bd9Sstevel@tonic-gate { 3981*7c478bd9Sstevel@tonic-gate int i; 3982*7c478bd9Sstevel@tonic-gate 3983*7c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) { 3984*7c478bd9Sstevel@tonic-gate kstat_delete(EHCI_INTRS_STATS(ehcip)); 3985*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip) = NULL; 3986*7c478bd9Sstevel@tonic-gate } 3987*7c478bd9Sstevel@tonic-gate 3988*7c478bd9Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip)) { 3989*7c478bd9Sstevel@tonic-gate kstat_delete(EHCI_TOTAL_STATS(ehcip)); 3990*7c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS(ehcip) = NULL; 3991*7c478bd9Sstevel@tonic-gate } 3992*7c478bd9Sstevel@tonic-gate 3993*7c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) { 3994*7c478bd9Sstevel@tonic-gate if (ehcip->ehci_count_stats[i]) { 3995*7c478bd9Sstevel@tonic-gate kstat_delete(ehcip->ehci_count_stats[i]); 3996*7c478bd9Sstevel@tonic-gate ehcip->ehci_count_stats[i] = NULL; 3997*7c478bd9Sstevel@tonic-gate } 3998*7c478bd9Sstevel@tonic-gate } 3999*7c478bd9Sstevel@tonic-gate } 4000*7c478bd9Sstevel@tonic-gate 4001*7c478bd9Sstevel@tonic-gate 4002*7c478bd9Sstevel@tonic-gate /* 4003*7c478bd9Sstevel@tonic-gate * ehci_do_intrs_stats: 4004*7c478bd9Sstevel@tonic-gate * 4005*7c478bd9Sstevel@tonic-gate * ehci status information 4006*7c478bd9Sstevel@tonic-gate */ 4007*7c478bd9Sstevel@tonic-gate void 4008*7c478bd9Sstevel@tonic-gate ehci_do_intrs_stats( 4009*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 4010*7c478bd9Sstevel@tonic-gate int val) 4011*7c478bd9Sstevel@tonic-gate { 4012*7c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) { 4013*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->ehci_sts_total.value.ui64++; 4014*7c478bd9Sstevel@tonic-gate switch (val) { 4015*7c478bd9Sstevel@tonic-gate case EHCI_STS_ASYNC_SCHED_STATUS: 4016*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 4017*7c478bd9Sstevel@tonic-gate ehci_sts_async_sched_status.value.ui64++; 4018*7c478bd9Sstevel@tonic-gate break; 4019*7c478bd9Sstevel@tonic-gate case EHCI_STS_PERIODIC_SCHED_STATUS: 4020*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 4021*7c478bd9Sstevel@tonic-gate ehci_sts_periodic_sched_status.value.ui64++; 4022*7c478bd9Sstevel@tonic-gate break; 4023*7c478bd9Sstevel@tonic-gate case EHCI_STS_EMPTY_ASYNC_SCHEDULE: 4024*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 4025*7c478bd9Sstevel@tonic-gate ehci_sts_empty_async_schedule.value.ui64++; 4026*7c478bd9Sstevel@tonic-gate break; 4027*7c478bd9Sstevel@tonic-gate case EHCI_STS_HOST_CTRL_HALTED: 4028*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 4029*7c478bd9Sstevel@tonic-gate ehci_sts_host_ctrl_halted.value.ui64++; 4030*7c478bd9Sstevel@tonic-gate break; 4031*7c478bd9Sstevel@tonic-gate case EHCI_STS_ASYNC_ADVANCE_INTR: 4032*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 4033*7c478bd9Sstevel@tonic-gate ehci_sts_async_advance_intr.value.ui64++; 4034*7c478bd9Sstevel@tonic-gate break; 4035*7c478bd9Sstevel@tonic-gate case EHCI_STS_HOST_SYSTEM_ERROR_INTR: 4036*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 4037*7c478bd9Sstevel@tonic-gate ehci_sts_host_system_error_intr.value.ui64++; 4038*7c478bd9Sstevel@tonic-gate break; 4039*7c478bd9Sstevel@tonic-gate case EHCI_STS_FRM_LIST_ROLLOVER_INTR: 4040*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 4041*7c478bd9Sstevel@tonic-gate ehci_sts_frm_list_rollover_intr.value.ui64++; 4042*7c478bd9Sstevel@tonic-gate break; 4043*7c478bd9Sstevel@tonic-gate case EHCI_STS_RH_PORT_CHANGE_INTR: 4044*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 4045*7c478bd9Sstevel@tonic-gate ehci_sts_rh_port_change_intr.value.ui64++; 4046*7c478bd9Sstevel@tonic-gate break; 4047*7c478bd9Sstevel@tonic-gate case EHCI_STS_USB_ERROR_INTR: 4048*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 4049*7c478bd9Sstevel@tonic-gate ehci_sts_usb_error_intr.value.ui64++; 4050*7c478bd9Sstevel@tonic-gate break; 4051*7c478bd9Sstevel@tonic-gate case EHCI_STS_USB_INTR: 4052*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 4053*7c478bd9Sstevel@tonic-gate ehci_sts_usb_intr.value.ui64++; 4054*7c478bd9Sstevel@tonic-gate break; 4055*7c478bd9Sstevel@tonic-gate default: 4056*7c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 4057*7c478bd9Sstevel@tonic-gate ehci_sts_not_claimed.value.ui64++; 4058*7c478bd9Sstevel@tonic-gate break; 4059*7c478bd9Sstevel@tonic-gate } 4060*7c478bd9Sstevel@tonic-gate } 4061*7c478bd9Sstevel@tonic-gate } 4062*7c478bd9Sstevel@tonic-gate 4063*7c478bd9Sstevel@tonic-gate 4064*7c478bd9Sstevel@tonic-gate /* 4065*7c478bd9Sstevel@tonic-gate * ehci_do_byte_stats: 4066*7c478bd9Sstevel@tonic-gate * 4067*7c478bd9Sstevel@tonic-gate * ehci data xfer information 4068*7c478bd9Sstevel@tonic-gate */ 4069*7c478bd9Sstevel@tonic-gate void 4070*7c478bd9Sstevel@tonic-gate ehci_do_byte_stats( 4071*7c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 4072*7c478bd9Sstevel@tonic-gate size_t len, 4073*7c478bd9Sstevel@tonic-gate uint8_t attr, 4074*7c478bd9Sstevel@tonic-gate uint8_t addr) 4075*7c478bd9Sstevel@tonic-gate { 4076*7c478bd9Sstevel@tonic-gate uint8_t type = attr & USB_EP_ATTR_MASK; 4077*7c478bd9Sstevel@tonic-gate uint8_t dir = addr & USB_EP_DIR_MASK; 4078*7c478bd9Sstevel@tonic-gate 4079*7c478bd9Sstevel@tonic-gate if (dir == USB_EP_DIR_IN) { 4080*7c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->reads++; 4081*7c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->nread += len; 4082*7c478bd9Sstevel@tonic-gate switch (type) { 4083*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 4084*7c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->reads++; 4085*7c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->nread += len; 4086*7c478bd9Sstevel@tonic-gate break; 4087*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 4088*7c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->reads++; 4089*7c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->nread += len; 4090*7c478bd9Sstevel@tonic-gate break; 4091*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 4092*7c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->reads++; 4093*7c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->nread += len; 4094*7c478bd9Sstevel@tonic-gate break; 4095*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 4096*7c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->reads++; 4097*7c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->nread += len; 4098*7c478bd9Sstevel@tonic-gate break; 4099*7c478bd9Sstevel@tonic-gate } 4100*7c478bd9Sstevel@tonic-gate } else if (dir == USB_EP_DIR_OUT) { 4101*7c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->writes++; 4102*7c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->nwritten += len; 4103*7c478bd9Sstevel@tonic-gate switch (type) { 4104*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 4105*7c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->writes++; 4106*7c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->nwritten += len; 4107*7c478bd9Sstevel@tonic-gate break; 4108*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 4109*7c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->writes++; 4110*7c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->nwritten += len; 4111*7c478bd9Sstevel@tonic-gate break; 4112*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 4113*7c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->writes++; 4114*7c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->nwritten += len; 4115*7c478bd9Sstevel@tonic-gate break; 4116*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 4117*7c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->writes++; 4118*7c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->nwritten += len; 4119*7c478bd9Sstevel@tonic-gate break; 4120*7c478bd9Sstevel@tonic-gate } 4121*7c478bd9Sstevel@tonic-gate } 4122*7c478bd9Sstevel@tonic-gate } 4123