17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * EHCI Host Controller Driver (EHCI) 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * The EHCI driver is a software driver which interfaces to the Universal 337c478bd9Sstevel@tonic-gate * Serial Bus layer (USBA) and the Host Controller (HC). The interface to 347c478bd9Sstevel@tonic-gate * the Host Controller is defined by the EHCI Host Controller Interface. 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * This module contains the main EHCI driver code which handles all USB 377c478bd9Sstevel@tonic-gate * transfers, bandwidth allocations and other general functionalities. 387c478bd9Sstevel@tonic-gate */ 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h> 417c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_isoch.h> 427c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h> 437c478bd9Sstevel@tonic-gate 44*9c75c6bfSgovinda /* 45*9c75c6bfSgovinda * EHCI MSI tunable: 46*9c75c6bfSgovinda * 47*9c75c6bfSgovinda * By default MSI is enabled on all supported platforms except for the 48*9c75c6bfSgovinda * EHCI controller of ULI1575 South bridge. 49*9c75c6bfSgovinda */ 50*9c75c6bfSgovinda boolean_t ehci_enable_msi = B_TRUE; 51*9c75c6bfSgovinda 527c478bd9Sstevel@tonic-gate /* Pointer to the state structure */ 537c478bd9Sstevel@tonic-gate extern void *ehci_statep; 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate extern void ehci_handle_endpoint_reclaimation(ehci_state_t *); 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate extern uint_t ehci_vt62x2_workaround; 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate /* Adjustable variables for the size of the pools */ 607c478bd9Sstevel@tonic-gate int ehci_qh_pool_size = EHCI_QH_POOL_SIZE; 617c478bd9Sstevel@tonic-gate int ehci_qtd_pool_size = EHCI_QTD_POOL_SIZE; 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate /* 647c478bd9Sstevel@tonic-gate * Initialize the values which the order of 32ms intr qh are executed 657c478bd9Sstevel@tonic-gate * by the host controller in the lattice tree. 667c478bd9Sstevel@tonic-gate */ 677c478bd9Sstevel@tonic-gate static uchar_t ehci_index[EHCI_NUM_INTR_QH_LISTS] = 687c478bd9Sstevel@tonic-gate {0x00, 0x10, 0x08, 0x18, 697c478bd9Sstevel@tonic-gate 0x04, 0x14, 0x0c, 0x1c, 707c478bd9Sstevel@tonic-gate 0x02, 0x12, 0x0a, 0x1a, 717c478bd9Sstevel@tonic-gate 0x06, 0x16, 0x0e, 0x1e, 727c478bd9Sstevel@tonic-gate 0x01, 0x11, 0x09, 0x19, 737c478bd9Sstevel@tonic-gate 0x05, 0x15, 0x0d, 0x1d, 747c478bd9Sstevel@tonic-gate 0x03, 0x13, 0x0b, 0x1b, 757c478bd9Sstevel@tonic-gate 0x07, 0x17, 0x0f, 0x1f}; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate /* 787c478bd9Sstevel@tonic-gate * Initialize the values which are used to calculate start split mask 797c478bd9Sstevel@tonic-gate * for the low/full/high speed interrupt and isochronous endpoints. 807c478bd9Sstevel@tonic-gate */ 817c478bd9Sstevel@tonic-gate static uint_t ehci_start_split_mask[15] = { 827c478bd9Sstevel@tonic-gate /* 837c478bd9Sstevel@tonic-gate * For high/full/low speed usb devices. For high speed 847c478bd9Sstevel@tonic-gate * device with polling interval greater than or equal 857c478bd9Sstevel@tonic-gate * to 8us (125us). 867c478bd9Sstevel@tonic-gate */ 877c478bd9Sstevel@tonic-gate 0x01, /* 00000001 */ 887c478bd9Sstevel@tonic-gate 0x02, /* 00000010 */ 897c478bd9Sstevel@tonic-gate 0x04, /* 00000100 */ 907c478bd9Sstevel@tonic-gate 0x08, /* 00001000 */ 917c478bd9Sstevel@tonic-gate 0x10, /* 00010000 */ 927c478bd9Sstevel@tonic-gate 0x20, /* 00100000 */ 937c478bd9Sstevel@tonic-gate 0x40, /* 01000000 */ 947c478bd9Sstevel@tonic-gate 0x80, /* 10000000 */ 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate /* Only for high speed devices with polling interval 4us */ 977c478bd9Sstevel@tonic-gate 0x11, /* 00010001 */ 987c478bd9Sstevel@tonic-gate 0x22, /* 00100010 */ 997c478bd9Sstevel@tonic-gate 0x44, /* 01000100 */ 1007c478bd9Sstevel@tonic-gate 0x88, /* 10001000 */ 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate /* Only for high speed devices with polling interval 2us */ 1037c478bd9Sstevel@tonic-gate 0x55, /* 01010101 */ 1047c478bd9Sstevel@tonic-gate 0xaa, /* 10101010 */ 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /* Only for high speed devices with polling interval 1us */ 1077c478bd9Sstevel@tonic-gate 0xff /* 11111111 */ 1087c478bd9Sstevel@tonic-gate }; 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate /* 1117c478bd9Sstevel@tonic-gate * Initialize the values which are used to calculate complete split mask 1127c478bd9Sstevel@tonic-gate * for the low/full speed interrupt and isochronous endpoints. 1137c478bd9Sstevel@tonic-gate */ 1147c478bd9Sstevel@tonic-gate static uint_t ehci_intr_complete_split_mask[7] = { 1157c478bd9Sstevel@tonic-gate /* Only full/low speed devices */ 1167c478bd9Sstevel@tonic-gate 0x1c, /* 00011100 */ 1177c478bd9Sstevel@tonic-gate 0x38, /* 00111000 */ 1187c478bd9Sstevel@tonic-gate 0x70, /* 01110000 */ 1197c478bd9Sstevel@tonic-gate 0xe0, /* 11100000 */ 1207c478bd9Sstevel@tonic-gate 0x00, /* Need FSTN feature */ 1217c478bd9Sstevel@tonic-gate 0x00, /* Need FSTN feature */ 1227c478bd9Sstevel@tonic-gate 0x00 /* Need FSTN feature */ 1237c478bd9Sstevel@tonic-gate }; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate /* 1277c478bd9Sstevel@tonic-gate * EHCI Internal Function Prototypes 1287c478bd9Sstevel@tonic-gate */ 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) initialization functions */ 1317c478bd9Sstevel@tonic-gate void ehci_set_dma_attributes(ehci_state_t *ehcip); 1327c478bd9Sstevel@tonic-gate int ehci_allocate_pools(ehci_state_t *ehcip); 1337c478bd9Sstevel@tonic-gate void ehci_decode_ddi_dma_addr_bind_handle_result( 1347c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1357c478bd9Sstevel@tonic-gate int result); 1367c478bd9Sstevel@tonic-gate int ehci_map_regs(ehci_state_t *ehcip); 1377c478bd9Sstevel@tonic-gate int ehci_register_intrs_and_init_mutex( 1387c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 139*9c75c6bfSgovinda static int ehci_add_intrs(ehci_state_t *ehcip, 140*9c75c6bfSgovinda int intr_type); 1417c478bd9Sstevel@tonic-gate int ehci_init_ctlr(ehci_state_t *ehcip); 1427c478bd9Sstevel@tonic-gate static int ehci_take_control(ehci_state_t *ehcip); 1437c478bd9Sstevel@tonic-gate static int ehci_init_periodic_frame_lst_table( 1447c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 1457c478bd9Sstevel@tonic-gate static void ehci_build_interrupt_lattice( 1467c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 1477c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *ehci_alloc_hcdi_ops(ehci_state_t *ehcip); 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) deinitialization functions */ 1507c478bd9Sstevel@tonic-gate int ehci_cleanup(ehci_state_t *ehcip); 151*9c75c6bfSgovinda static void ehci_rem_intrs(ehci_state_t *ehcip); 1527c478bd9Sstevel@tonic-gate int ehci_cpr_suspend(ehci_state_t *ehcip); 1537c478bd9Sstevel@tonic-gate int ehci_cpr_resume(ehci_state_t *ehcip); 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate /* Bandwidth Allocation functions */ 1567c478bd9Sstevel@tonic-gate int ehci_allocate_bandwidth(ehci_state_t *ehcip, 1577c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1587c478bd9Sstevel@tonic-gate uint_t *pnode, 1597c478bd9Sstevel@tonic-gate uchar_t *smask, 1607c478bd9Sstevel@tonic-gate uchar_t *cmask); 1617c478bd9Sstevel@tonic-gate static int ehci_allocate_high_speed_bandwidth( 1627c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1637c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1647c478bd9Sstevel@tonic-gate uint_t *hnode, 1657c478bd9Sstevel@tonic-gate uchar_t *smask, 1667c478bd9Sstevel@tonic-gate uchar_t *cmask); 1677c478bd9Sstevel@tonic-gate static int ehci_allocate_classic_tt_bandwidth( 1687c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1697c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1707c478bd9Sstevel@tonic-gate uint_t pnode); 1717c478bd9Sstevel@tonic-gate void ehci_deallocate_bandwidth(ehci_state_t *ehcip, 1727c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1737c478bd9Sstevel@tonic-gate uint_t pnode, 1747c478bd9Sstevel@tonic-gate uchar_t smask, 1757c478bd9Sstevel@tonic-gate uchar_t cmask); 1767c478bd9Sstevel@tonic-gate static void ehci_deallocate_high_speed_bandwidth( 1777c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1787c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1797c478bd9Sstevel@tonic-gate uint_t hnode, 1807c478bd9Sstevel@tonic-gate uchar_t smask, 1817c478bd9Sstevel@tonic-gate uchar_t cmask); 1827c478bd9Sstevel@tonic-gate static void ehci_deallocate_classic_tt_bandwidth( 1837c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1847c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1857c478bd9Sstevel@tonic-gate uint_t pnode); 1867c478bd9Sstevel@tonic-gate static int ehci_compute_high_speed_bandwidth( 1877c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1887c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 1897c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 1907c478bd9Sstevel@tonic-gate uint_t *sbandwidth, 1917c478bd9Sstevel@tonic-gate uint_t *cbandwidth); 1927c478bd9Sstevel@tonic-gate static int ehci_compute_classic_bandwidth( 1937c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 1947c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 1957c478bd9Sstevel@tonic-gate uint_t *bandwidth); 1967c478bd9Sstevel@tonic-gate int ehci_adjust_polling_interval( 1977c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1987c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 1997c478bd9Sstevel@tonic-gate usb_port_status_t port_status); 2007c478bd9Sstevel@tonic-gate static int ehci_adjust_high_speed_polling_interval( 2017c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2027c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint); 2037c478bd9Sstevel@tonic-gate static uint_t ehci_lattice_height(uint_t interval); 2047c478bd9Sstevel@tonic-gate static uint_t ehci_lattice_parent(uint_t node); 2057c478bd9Sstevel@tonic-gate static uint_t ehci_find_periodic_node( 2067c478bd9Sstevel@tonic-gate uint_t leaf, 2077c478bd9Sstevel@tonic-gate int interval); 2087c478bd9Sstevel@tonic-gate static uint_t ehci_leftmost_leaf(uint_t node, 2097c478bd9Sstevel@tonic-gate uint_t height); 2107c478bd9Sstevel@tonic-gate static uint_t ehci_pow_2(uint_t x); 2117c478bd9Sstevel@tonic-gate static uint_t ehci_log_2(uint_t x); 2127c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_hs_mask( 2137c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2147c478bd9Sstevel@tonic-gate uchar_t *smask, 2157c478bd9Sstevel@tonic-gate uint_t *pnode, 2167c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 2177c478bd9Sstevel@tonic-gate uint_t bandwidth, 2187c478bd9Sstevel@tonic-gate int interval); 2197c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_ls_intr_mask( 2207c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2217c478bd9Sstevel@tonic-gate uchar_t *smask, 2227c478bd9Sstevel@tonic-gate uchar_t *cmask, 2237c478bd9Sstevel@tonic-gate uint_t *pnode, 2247c478bd9Sstevel@tonic-gate uint_t sbandwidth, 2257c478bd9Sstevel@tonic-gate uint_t cbandwidth, 2267c478bd9Sstevel@tonic-gate int interval); 2277c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_sitd_in_mask( 2287c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2297c478bd9Sstevel@tonic-gate uchar_t *smask, 2307c478bd9Sstevel@tonic-gate uchar_t *cmask, 2317c478bd9Sstevel@tonic-gate uint_t *pnode, 2327c478bd9Sstevel@tonic-gate uint_t sbandwidth, 2337c478bd9Sstevel@tonic-gate uint_t cbandwidth, 2347c478bd9Sstevel@tonic-gate int interval); 2357c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_sitd_out_mask( 2367c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2377c478bd9Sstevel@tonic-gate uchar_t *smask, 2387c478bd9Sstevel@tonic-gate uint_t *pnode, 2397c478bd9Sstevel@tonic-gate uint_t sbandwidth, 2407c478bd9Sstevel@tonic-gate int interval); 2417c478bd9Sstevel@tonic-gate static uint_t ehci_calculate_bw_availability_mask( 2427c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2437c478bd9Sstevel@tonic-gate uint_t bandwidth, 2447c478bd9Sstevel@tonic-gate int leaf, 2457c478bd9Sstevel@tonic-gate int leaf_count, 2467c478bd9Sstevel@tonic-gate uchar_t *bw_mask); 2477c478bd9Sstevel@tonic-gate static void ehci_update_bw_availability( 2487c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2497c478bd9Sstevel@tonic-gate int bandwidth, 2507c478bd9Sstevel@tonic-gate int leftmost_leaf, 2517c478bd9Sstevel@tonic-gate int leaf_count, 2527c478bd9Sstevel@tonic-gate uchar_t mask); 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate /* Miscellaneous functions */ 2557c478bd9Sstevel@tonic-gate ehci_state_t *ehci_obtain_state( 2567c478bd9Sstevel@tonic-gate dev_info_t *dip); 2577c478bd9Sstevel@tonic-gate int ehci_state_is_operational( 2587c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2597c478bd9Sstevel@tonic-gate int ehci_do_soft_reset( 2607c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2617c478bd9Sstevel@tonic-gate usb_req_attrs_t ehci_get_xfer_attrs(ehci_state_t *ehcip, 2627c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 2637c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 2647c478bd9Sstevel@tonic-gate usb_frame_number_t ehci_get_current_frame_number( 2657c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2667c478bd9Sstevel@tonic-gate static void ehci_cpr_cleanup( 2677c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2687c478bd9Sstevel@tonic-gate int ehci_wait_for_sof( 2697c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2707c478bd9Sstevel@tonic-gate void ehci_toggle_scheduler( 2717c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2727c478bd9Sstevel@tonic-gate void ehci_print_caps(ehci_state_t *ehcip); 2737c478bd9Sstevel@tonic-gate void ehci_print_regs(ehci_state_t *ehcip); 2747c478bd9Sstevel@tonic-gate void ehci_print_qh(ehci_state_t *ehcip, 2757c478bd9Sstevel@tonic-gate ehci_qh_t *qh); 2767c478bd9Sstevel@tonic-gate void ehci_print_qtd(ehci_state_t *ehcip, 2777c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd); 2787c478bd9Sstevel@tonic-gate void ehci_create_stats(ehci_state_t *ehcip); 2797c478bd9Sstevel@tonic-gate void ehci_destroy_stats(ehci_state_t *ehcip); 2807c478bd9Sstevel@tonic-gate void ehci_do_intrs_stats(ehci_state_t *ehcip, 2817c478bd9Sstevel@tonic-gate int val); 2827c478bd9Sstevel@tonic-gate void ehci_do_byte_stats(ehci_state_t *ehcip, 2837c478bd9Sstevel@tonic-gate size_t len, 2847c478bd9Sstevel@tonic-gate uint8_t attr, 2857c478bd9Sstevel@tonic-gate uint8_t addr); 2867c478bd9Sstevel@tonic-gate 2874610e4a0Sfrits /* 2884610e4a0Sfrits * check if this ehci controller can support PM 2894610e4a0Sfrits */ 2904610e4a0Sfrits int 2914610e4a0Sfrits ehci_hcdi_pm_support(dev_info_t *dip) 2924610e4a0Sfrits { 2934610e4a0Sfrits ehci_state_t *ehcip = ddi_get_soft_state(ehci_statep, 2944610e4a0Sfrits ddi_get_instance(dip)); 2954610e4a0Sfrits 2964610e4a0Sfrits if (((ehcip->ehci_vendor_id == PCI_VENDOR_NEC_COMBO) && 2974610e4a0Sfrits (ehcip->ehci_device_id == PCI_DEVICE_NEC_COMBO)) || 2984610e4a0Sfrits 2994610e4a0Sfrits ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) && 3004610e4a0Sfrits (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) || 3014610e4a0Sfrits 3024610e4a0Sfrits (ehcip->ehci_vendor_id == PCI_VENDOR_VIA)) { 3034610e4a0Sfrits 3044610e4a0Sfrits return (USB_SUCCESS); 3054610e4a0Sfrits } 3064610e4a0Sfrits 3074610e4a0Sfrits return (USB_FAILURE); 3084610e4a0Sfrits } 3094610e4a0Sfrits 3104610e4a0Sfrits 3117c478bd9Sstevel@tonic-gate /* 3127c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) initialization functions 3137c478bd9Sstevel@tonic-gate */ 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate /* 3167c478bd9Sstevel@tonic-gate * ehci_set_dma_attributes: 3177c478bd9Sstevel@tonic-gate * 3187c478bd9Sstevel@tonic-gate * Set the limits in the DMA attributes structure. Most of the values used 3197c478bd9Sstevel@tonic-gate * in the DMA limit structures are the default values as specified by the 3207c478bd9Sstevel@tonic-gate * Writing PCI device drivers document. 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate void 3237c478bd9Sstevel@tonic-gate ehci_set_dma_attributes(ehci_state_t *ehcip) 3247c478bd9Sstevel@tonic-gate { 3257c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3267c478bd9Sstevel@tonic-gate "ehci_set_dma_attributes:"); 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate /* Initialize the DMA attributes */ 3297c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_version = DMA_ATTR_V0; 3307c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_addr_lo = 0x00000000ull; 3317c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_addr_hi = 0xfffffffeull; 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate /* 32 bit addressing */ 3347c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_count_max = EHCI_DMA_ATTR_COUNT_MAX; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate /* Byte alignment */ 3377c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate /* 3407c478bd9Sstevel@tonic-gate * Since PCI specification is byte alignment, the 3417c478bd9Sstevel@tonic-gate * burst size field should be set to 1 for PCI devices. 3427c478bd9Sstevel@tonic-gate */ 3437c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_burstsizes = 0x1; 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_minxfer = 0x1; 3467c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_maxxfer = EHCI_DMA_ATTR_MAX_XFER; 3477c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_seg = 0xffffffffull; 3487c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_sgllen = 1; 3497c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_granular = EHCI_DMA_ATTR_GRANULAR; 3507c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_flags = 0; 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate /* 3557c478bd9Sstevel@tonic-gate * ehci_allocate_pools: 3567c478bd9Sstevel@tonic-gate * 3577c478bd9Sstevel@tonic-gate * Allocate the system memory for the Endpoint Descriptor (QH) and for the 3587c478bd9Sstevel@tonic-gate * Transfer Descriptor (QTD) pools. Both QH and QTD structures must be aligned 3597c478bd9Sstevel@tonic-gate * to a 16 byte boundary. 3607c478bd9Sstevel@tonic-gate */ 3617c478bd9Sstevel@tonic-gate int 3627c478bd9Sstevel@tonic-gate ehci_allocate_pools(ehci_state_t *ehcip) 3637c478bd9Sstevel@tonic-gate { 3647c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 3657c478bd9Sstevel@tonic-gate size_t real_length; 3667c478bd9Sstevel@tonic-gate int result; 3677c478bd9Sstevel@tonic-gate uint_t ccount; 3687c478bd9Sstevel@tonic-gate int i; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3717c478bd9Sstevel@tonic-gate "ehci_allocate_pools:"); 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 3747c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 3757c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 3767c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate /* Byte alignment */ 3797c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_TD_QH_ALIGNMENT; 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate /* Allocate the QTD pool DMA handle */ 3827c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr, 3837c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 0, 3847c478bd9Sstevel@tonic-gate &ehcip->ehci_qtd_pool_dma_handle) != DDI_SUCCESS) { 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate goto failure; 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate /* Allocate the memory for the QTD pool */ 3907c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_qtd_pool_dma_handle, 3917c478bd9Sstevel@tonic-gate ehci_qtd_pool_size * sizeof (ehci_qtd_t), 3927c478bd9Sstevel@tonic-gate &dev_attr, 3937c478bd9Sstevel@tonic-gate DDI_DMA_CONSISTENT, 3947c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 3957c478bd9Sstevel@tonic-gate 0, 3967c478bd9Sstevel@tonic-gate (caddr_t *)&ehcip->ehci_qtd_pool_addr, 3977c478bd9Sstevel@tonic-gate &real_length, 3987c478bd9Sstevel@tonic-gate &ehcip->ehci_qtd_pool_mem_handle)) { 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate goto failure; 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate /* Map the QTD pool into the I/O address space */ 4047c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle( 4057c478bd9Sstevel@tonic-gate ehcip->ehci_qtd_pool_dma_handle, 4067c478bd9Sstevel@tonic-gate NULL, 4077c478bd9Sstevel@tonic-gate (caddr_t)ehcip->ehci_qtd_pool_addr, 4087c478bd9Sstevel@tonic-gate real_length, 4097c478bd9Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 4107c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 4117c478bd9Sstevel@tonic-gate NULL, 4127c478bd9Sstevel@tonic-gate &ehcip->ehci_qtd_pool_cookie, 4137c478bd9Sstevel@tonic-gate &ccount); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate bzero((void *)ehcip->ehci_qtd_pool_addr, 4167c478bd9Sstevel@tonic-gate ehci_qtd_pool_size * sizeof (ehci_qtd_t)); 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate /* Process the result */ 4197c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 4207c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 4217c478bd9Sstevel@tonic-gate if (ccount != 1) { 4227c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 4237c478bd9Sstevel@tonic-gate "ehci_allocate_pools: More than 1 cookie"); 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate goto failure; 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate } else { 4287c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 4297c478bd9Sstevel@tonic-gate "ehci_allocate_pools: Result = %d", result); 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result); 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate goto failure; 4347c478bd9Sstevel@tonic-gate } 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate /* 4377c478bd9Sstevel@tonic-gate * DMA addresses for QTD pools are bound 4387c478bd9Sstevel@tonic-gate */ 4397c478bd9Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_QTD_POOL_BOUND; 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate /* Initialize the QTD pool */ 4427c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_qtd_pool_size; i ++) { 4437c478bd9Sstevel@tonic-gate Set_QTD(ehcip->ehci_qtd_pool_addr[i]. 4447c478bd9Sstevel@tonic-gate qtd_state, EHCI_QTD_FREE); 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate /* Allocate the QTD pool DMA handle */ 4487c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip, 4497c478bd9Sstevel@tonic-gate &ehcip->ehci_dma_attr, 4507c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 4517c478bd9Sstevel@tonic-gate 0, 4527c478bd9Sstevel@tonic-gate &ehcip->ehci_qh_pool_dma_handle) != DDI_SUCCESS) { 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate goto failure; 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate /* Allocate the memory for the QH pool */ 4587c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_qh_pool_dma_handle, 4597c478bd9Sstevel@tonic-gate ehci_qh_pool_size * sizeof (ehci_qh_t), 4607c478bd9Sstevel@tonic-gate &dev_attr, 4617c478bd9Sstevel@tonic-gate DDI_DMA_CONSISTENT, 4627c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 4637c478bd9Sstevel@tonic-gate 0, 4647c478bd9Sstevel@tonic-gate (caddr_t *)&ehcip->ehci_qh_pool_addr, 4657c478bd9Sstevel@tonic-gate &real_length, 4667c478bd9Sstevel@tonic-gate &ehcip->ehci_qh_pool_mem_handle) != DDI_SUCCESS) { 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate goto failure; 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ehcip->ehci_qh_pool_dma_handle, 4727c478bd9Sstevel@tonic-gate NULL, 4737c478bd9Sstevel@tonic-gate (caddr_t)ehcip->ehci_qh_pool_addr, 4747c478bd9Sstevel@tonic-gate real_length, 4757c478bd9Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 4767c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 4777c478bd9Sstevel@tonic-gate NULL, 4787c478bd9Sstevel@tonic-gate &ehcip->ehci_qh_pool_cookie, 4797c478bd9Sstevel@tonic-gate &ccount); 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate bzero((void *)ehcip->ehci_qh_pool_addr, 4827c478bd9Sstevel@tonic-gate ehci_qh_pool_size * sizeof (ehci_qh_t)); 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate /* Process the result */ 4857c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 4867c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 4877c478bd9Sstevel@tonic-gate if (ccount != 1) { 4887c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 4897c478bd9Sstevel@tonic-gate "ehci_allocate_pools: More than 1 cookie"); 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate goto failure; 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate } else { 4947c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result); 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate goto failure; 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate /* 5007c478bd9Sstevel@tonic-gate * DMA addresses for QH pools are bound 5017c478bd9Sstevel@tonic-gate */ 5027c478bd9Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_QH_POOL_BOUND; 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate /* Initialize the QH pool */ 5057c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_qh_pool_size; i ++) { 5067c478bd9Sstevel@tonic-gate Set_QH(ehcip->ehci_qh_pool_addr[i].qh_state, EHCI_QH_FREE); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate /* Byte alignment */ 5107c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate failure: 5157c478bd9Sstevel@tonic-gate /* Byte alignment */ 5167c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate /* 5237c478bd9Sstevel@tonic-gate * ehci_decode_ddi_dma_addr_bind_handle_result: 5247c478bd9Sstevel@tonic-gate * 5257c478bd9Sstevel@tonic-gate * Process the return values of ddi_dma_addr_bind_handle() 5267c478bd9Sstevel@tonic-gate */ 5277c478bd9Sstevel@tonic-gate void 5287c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result( 5297c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 5307c478bd9Sstevel@tonic-gate int result) 5317c478bd9Sstevel@tonic-gate { 5327c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 5337c478bd9Sstevel@tonic-gate "ehci_decode_ddi_dma_addr_bind_handle_result:"); 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate switch (result) { 5367c478bd9Sstevel@tonic-gate case DDI_DMA_PARTIAL_MAP: 5377c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5387c478bd9Sstevel@tonic-gate "Partial transfers not allowed"); 5397c478bd9Sstevel@tonic-gate break; 5407c478bd9Sstevel@tonic-gate case DDI_DMA_INUSE: 5417c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5427c478bd9Sstevel@tonic-gate "Handle is in use"); 5437c478bd9Sstevel@tonic-gate break; 5447c478bd9Sstevel@tonic-gate case DDI_DMA_NORESOURCES: 5457c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5467c478bd9Sstevel@tonic-gate "No resources"); 5477c478bd9Sstevel@tonic-gate break; 5487c478bd9Sstevel@tonic-gate case DDI_DMA_NOMAPPING: 5497c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5507c478bd9Sstevel@tonic-gate "No mapping"); 5517c478bd9Sstevel@tonic-gate break; 5527c478bd9Sstevel@tonic-gate case DDI_DMA_TOOBIG: 5537c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5547c478bd9Sstevel@tonic-gate "Object is too big"); 5557c478bd9Sstevel@tonic-gate break; 5567c478bd9Sstevel@tonic-gate default: 5577c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5587c478bd9Sstevel@tonic-gate "Unknown dma error"); 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate /* 5647c478bd9Sstevel@tonic-gate * ehci_map_regs: 5657c478bd9Sstevel@tonic-gate * 5667c478bd9Sstevel@tonic-gate * The Host Controller (HC) contains a set of on-chip operational registers 5677c478bd9Sstevel@tonic-gate * and which should be mapped into a non-cacheable portion of the system 5687c478bd9Sstevel@tonic-gate * addressable space. 5697c478bd9Sstevel@tonic-gate */ 5707c478bd9Sstevel@tonic-gate int 5717c478bd9Sstevel@tonic-gate ehci_map_regs(ehci_state_t *ehcip) 5727c478bd9Sstevel@tonic-gate { 5737c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 5747c478bd9Sstevel@tonic-gate uint16_t cmd_reg; 5757c478bd9Sstevel@tonic-gate uint_t length; 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_map_regs:"); 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate /* Check to make sure we have memory access */ 5807c478bd9Sstevel@tonic-gate if (pci_config_setup(ehcip->ehci_dip, 5817c478bd9Sstevel@tonic-gate &ehcip->ehci_config_handle) != DDI_SUCCESS) { 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 5847c478bd9Sstevel@tonic-gate "ehci_map_regs: Config error"); 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate /* Make sure Memory Access Enable is set */ 5907c478bd9Sstevel@tonic-gate cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM); 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate if (!(cmd_reg & PCI_COMM_MAE)) { 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 5957c478bd9Sstevel@tonic-gate "ehci_map_regs: Memory base address access disabled"); 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 6017c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 6027c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 6037c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate /* Map in EHCI Capability registers */ 6067c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(ehcip->ehci_dip, 1, 6077c478bd9Sstevel@tonic-gate (caddr_t *)&ehcip->ehci_capsp, 0, 6087c478bd9Sstevel@tonic-gate sizeof (ehci_caps_t), &attr, 6097c478bd9Sstevel@tonic-gate &ehcip->ehci_caps_handle) != DDI_SUCCESS) { 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 6127c478bd9Sstevel@tonic-gate "ehci_map_regs: Map setup error"); 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate length = ddi_get8(ehcip->ehci_caps_handle, 6187c478bd9Sstevel@tonic-gate (uint8_t *)&ehcip->ehci_capsp->ehci_caps_length); 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate /* Free the original mapping */ 6217c478bd9Sstevel@tonic-gate ddi_regs_map_free(&ehcip->ehci_caps_handle); 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate /* Re-map in EHCI Capability and Operational registers */ 6247c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(ehcip->ehci_dip, 1, 6257c478bd9Sstevel@tonic-gate (caddr_t *)&ehcip->ehci_capsp, 0, 6267c478bd9Sstevel@tonic-gate length + sizeof (ehci_regs_t), &attr, 6277c478bd9Sstevel@tonic-gate &ehcip->ehci_caps_handle) != DDI_SUCCESS) { 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 6307c478bd9Sstevel@tonic-gate "ehci_map_regs: Map setup error"); 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate /* Get the pointer to EHCI Operational Register */ 6367c478bd9Sstevel@tonic-gate ehcip->ehci_regsp = (ehci_regs_t *) 6377c478bd9Sstevel@tonic-gate ((uintptr_t)ehcip->ehci_capsp + length); 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 6407c478bd9Sstevel@tonic-gate "ehci_map_regs: Capsp 0x%p Regsp 0x%p\n", 6417c478bd9Sstevel@tonic-gate ehcip->ehci_capsp, ehcip->ehci_regsp); 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate /* 6487c478bd9Sstevel@tonic-gate * ehci_register_intrs_and_init_mutex: 6497c478bd9Sstevel@tonic-gate * 6507c478bd9Sstevel@tonic-gate * Register interrupts and initialize each mutex and condition variables 6517c478bd9Sstevel@tonic-gate */ 6527c478bd9Sstevel@tonic-gate int 6537c478bd9Sstevel@tonic-gate ehci_register_intrs_and_init_mutex(ehci_state_t *ehcip) 6547c478bd9Sstevel@tonic-gate { 655*9c75c6bfSgovinda int intr_types; 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate #if defined(__x86) 6587c478bd9Sstevel@tonic-gate uint8_t iline; 6597c478bd9Sstevel@tonic-gate #endif 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 6627c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex:"); 6637c478bd9Sstevel@tonic-gate 664*9c75c6bfSgovinda /* 665*9c75c6bfSgovinda * There is a known MSI hardware bug with the EHCI controller 666*9c75c6bfSgovinda * of ULI1575 southbridge. Hence MSI is disabled for this chip. 667*9c75c6bfSgovinda */ 668*9c75c6bfSgovinda if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) && 669*9c75c6bfSgovinda (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) { 670*9c75c6bfSgovinda ehcip->ehci_msi_enabled = B_FALSE; 671*9c75c6bfSgovinda } else { 672*9c75c6bfSgovinda /* Set the MSI enable flag from the global EHCI MSI tunable */ 673*9c75c6bfSgovinda ehcip->ehci_msi_enabled = ehci_enable_msi; 674*9c75c6bfSgovinda } 675*9c75c6bfSgovinda 6767c478bd9Sstevel@tonic-gate #if defined(__x86) 6777c478bd9Sstevel@tonic-gate /* 6787c478bd9Sstevel@tonic-gate * Make sure that the interrupt pin is connected to the 6797c478bd9Sstevel@tonic-gate * interrupt controller on x86. Interrupt line 255 means 6807c478bd9Sstevel@tonic-gate * "unknown" or "not connected" (PCI spec 6.2.4, footnote 43). 6814610e4a0Sfrits * If we would return failure when interrupt line equals 255, then 682f87a10b6Syq * high speed devices will be routed to companion host controllers. 6834610e4a0Sfrits * However, it is not necessary to return failure here, and 6844610e4a0Sfrits * o/uhci codes don't check the interrupt line either. 6854610e4a0Sfrits * But it's good to log a message here for debug purposes. 6867c478bd9Sstevel@tonic-gate */ 6877c478bd9Sstevel@tonic-gate iline = pci_config_get8(ehcip->ehci_config_handle, 6887c478bd9Sstevel@tonic-gate PCI_CONF_ILINE); 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate if (iline == 255) { 6917c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 6927c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 6937c478bd9Sstevel@tonic-gate "interrupt line value out of range (%d)", 6947c478bd9Sstevel@tonic-gate iline); 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate #endif /* __x86 */ 6977c478bd9Sstevel@tonic-gate 698*9c75c6bfSgovinda /* Get supported interrupt types */ 699*9c75c6bfSgovinda if (ddi_intr_get_supported_types(ehcip->ehci_dip, 700*9c75c6bfSgovinda &intr_types) != DDI_SUCCESS) { 7017c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7027c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 703*9c75c6bfSgovinda "ddi_intr_get_supported_types failed"); 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate 708*9c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 709*9c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: " 710*9c75c6bfSgovinda "supported interrupt types 0x%x", intr_types); 711*9c75c6bfSgovinda 712*9c75c6bfSgovinda if ((intr_types & DDI_INTR_TYPE_MSI) && ehcip->ehci_msi_enabled) { 713*9c75c6bfSgovinda if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_MSI) 714*9c75c6bfSgovinda != DDI_SUCCESS) { 715*9c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 716*9c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: MSI " 717*9c75c6bfSgovinda "registration failed, trying FIXED interrupt \n"); 718*9c75c6bfSgovinda } else { 719*9c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 720*9c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: " 721*9c75c6bfSgovinda "Using MSI interrupt type\n"); 722*9c75c6bfSgovinda 723*9c75c6bfSgovinda ehcip->ehci_intr_type = DDI_INTR_TYPE_MSI; 724*9c75c6bfSgovinda ehcip->ehci_flags |= EHCI_INTR; 725*9c75c6bfSgovinda } 726*9c75c6bfSgovinda } 7277c478bd9Sstevel@tonic-gate 728*9c75c6bfSgovinda if ((!(ehcip->ehci_flags & EHCI_INTR)) && 729*9c75c6bfSgovinda (intr_types & DDI_INTR_TYPE_FIXED)) { 730*9c75c6bfSgovinda if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_FIXED) 731*9c75c6bfSgovinda != DDI_SUCCESS) { 732*9c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 733*9c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: " 734*9c75c6bfSgovinda "FIXED interrupt registration failed\n"); 735*9c75c6bfSgovinda 736*9c75c6bfSgovinda return (DDI_FAILURE); 737*9c75c6bfSgovinda } 738*9c75c6bfSgovinda 739*9c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7407c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 741*9c75c6bfSgovinda "Using FIXED interrupt type\n"); 742*9c75c6bfSgovinda 743*9c75c6bfSgovinda ehcip->ehci_intr_type = DDI_INTR_TYPE_FIXED; 744*9c75c6bfSgovinda ehcip->ehci_flags |= EHCI_INTR; 745*9c75c6bfSgovinda } 746*9c75c6bfSgovinda 747*9c75c6bfSgovinda /* Create prototype for advance on async schedule */ 748*9c75c6bfSgovinda cv_init(&ehcip->ehci_async_schedule_advance_cv, 749*9c75c6bfSgovinda NULL, CV_DRIVER, NULL); 750*9c75c6bfSgovinda 751*9c75c6bfSgovinda return (DDI_SUCCESS); 752*9c75c6bfSgovinda } 753*9c75c6bfSgovinda 754*9c75c6bfSgovinda 755*9c75c6bfSgovinda /* 756*9c75c6bfSgovinda * ehci_add_intrs: 757*9c75c6bfSgovinda * 758*9c75c6bfSgovinda * Register FIXED or MSI interrupts. 759*9c75c6bfSgovinda */ 760*9c75c6bfSgovinda static int 761*9c75c6bfSgovinda ehci_add_intrs(ehci_state_t *ehcip, 762*9c75c6bfSgovinda int intr_type) 763*9c75c6bfSgovinda { 764*9c75c6bfSgovinda int actual, avail, intr_size, count = 0; 765*9c75c6bfSgovinda int i, flag, ret; 766*9c75c6bfSgovinda 767*9c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 768*9c75c6bfSgovinda "ehci_add_intrs: interrupt type 0x%x", intr_type); 769*9c75c6bfSgovinda 770*9c75c6bfSgovinda /* Get number of interrupts */ 771*9c75c6bfSgovinda ret = ddi_intr_get_nintrs(ehcip->ehci_dip, intr_type, &count); 772*9c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (count == 0)) { 773*9c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 774*9c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_nintrs() failure, " 775*9c75c6bfSgovinda "ret: %d, count: %d", ret, count); 776*9c75c6bfSgovinda 777*9c75c6bfSgovinda return (DDI_FAILURE); 778*9c75c6bfSgovinda } 779*9c75c6bfSgovinda 780*9c75c6bfSgovinda /* Get number of available interrupts */ 781*9c75c6bfSgovinda ret = ddi_intr_get_navail(ehcip->ehci_dip, intr_type, &avail); 782*9c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (avail == 0)) { 783*9c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 784*9c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_navail() failure, " 785*9c75c6bfSgovinda "ret: %d, count: %d", ret, count); 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7887c478bd9Sstevel@tonic-gate } 7897c478bd9Sstevel@tonic-gate 790*9c75c6bfSgovinda if (avail < count) { 791*9c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 792*9c75c6bfSgovinda "ehci_add_intrs: ehci_add_intrs: nintrs () " 793*9c75c6bfSgovinda "returned %d, navail returned %d\n", count, avail); 794*9c75c6bfSgovinda } 795*9c75c6bfSgovinda 796*9c75c6bfSgovinda /* Allocate an array of interrupt handles */ 797*9c75c6bfSgovinda intr_size = count * sizeof (ddi_intr_handle_t); 798*9c75c6bfSgovinda ehcip->ehci_htable = kmem_zalloc(intr_size, KM_SLEEP); 799*9c75c6bfSgovinda 800*9c75c6bfSgovinda flag = (intr_type == DDI_INTR_TYPE_MSI) ? 801*9c75c6bfSgovinda DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL; 802*9c75c6bfSgovinda 803*9c75c6bfSgovinda /* call ddi_intr_alloc() */ 8047c478bd9Sstevel@tonic-gate ret = ddi_intr_alloc(ehcip->ehci_dip, ehcip->ehci_htable, 805*9c75c6bfSgovinda intr_type, 0, count, &actual, flag); 8067c478bd9Sstevel@tonic-gate 807*9c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (actual == 0)) { 8087c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 809*9c75c6bfSgovinda "ehci_add_intrs: ddi_intr_alloc() failed %d", ret); 8107c478bd9Sstevel@tonic-gate 811*9c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8147c478bd9Sstevel@tonic-gate } 8157c478bd9Sstevel@tonic-gate 816*9c75c6bfSgovinda if (actual < count) { 817*9c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 818*9c75c6bfSgovinda "ehci_add_intrs: Requested: %d, Received: %d\n", 819*9c75c6bfSgovinda count, actual); 820*9c75c6bfSgovinda 821*9c75c6bfSgovinda for (i = 0; i < actual; i++) 822*9c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 823*9c75c6bfSgovinda 824*9c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 825*9c75c6bfSgovinda 826*9c75c6bfSgovinda return (DDI_FAILURE); 827*9c75c6bfSgovinda } 8287c478bd9Sstevel@tonic-gate 829*9c75c6bfSgovinda ehcip->ehci_intr_cnt = actual; 830*9c75c6bfSgovinda 831*9c75c6bfSgovinda if ((ret = ddi_intr_get_pri(ehcip->ehci_htable[0], 832*9c75c6bfSgovinda &ehcip->ehci_intr_pri)) != DDI_SUCCESS) { 8337c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 834*9c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_pri() failed %d", ret); 835*9c75c6bfSgovinda 836*9c75c6bfSgovinda for (i = 0; i < actual; i++) 837*9c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 8387c478bd9Sstevel@tonic-gate 839*9c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8427c478bd9Sstevel@tonic-gate } 8437c478bd9Sstevel@tonic-gate 844*9c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 845*9c75c6bfSgovinda "ehci_add_intrs: Supported Interrupt priority 0x%x", 846*9c75c6bfSgovinda ehcip->ehci_intr_pri); 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate /* Test for high level mutex */ 8497c478bd9Sstevel@tonic-gate if (ehcip->ehci_intr_pri >= ddi_intr_get_hilevel_pri()) { 8507c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 851*9c75c6bfSgovinda "ehci_add_intrs: Hi level interrupt not supported"); 852*9c75c6bfSgovinda 853*9c75c6bfSgovinda for (i = 0; i < actual; i++) 854*9c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 8557c478bd9Sstevel@tonic-gate 856*9c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate /* Initialize the mutex */ 8627c478bd9Sstevel@tonic-gate mutex_init(&ehcip->ehci_int_mutex, NULL, MUTEX_DRIVER, 863a195726fSgovinda DDI_INTR_PRI(ehcip->ehci_intr_pri)); 8647c478bd9Sstevel@tonic-gate 865*9c75c6bfSgovinda /* Call ddi_intr_add_handler() */ 866*9c75c6bfSgovinda for (i = 0; i < actual; i++) { 867*9c75c6bfSgovinda if ((ret = ddi_intr_add_handler(ehcip->ehci_htable[i], 868*9c75c6bfSgovinda ehci_intr, (caddr_t)ehcip, 869*9c75c6bfSgovinda (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 870*9c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 871*9c75c6bfSgovinda "ehci_add_intrs:ddi_intr_add_handler() " 872*9c75c6bfSgovinda "failed %d", ret); 8737c478bd9Sstevel@tonic-gate 874*9c75c6bfSgovinda for (i = 0; i < actual; i++) 875*9c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 8767c478bd9Sstevel@tonic-gate 877*9c75c6bfSgovinda mutex_destroy(&ehcip->ehci_int_mutex); 878*9c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 879*9c75c6bfSgovinda 880*9c75c6bfSgovinda return (DDI_FAILURE); 881*9c75c6bfSgovinda } 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 884*9c75c6bfSgovinda if ((ret = ddi_intr_get_cap(ehcip->ehci_htable[0], 885*9c75c6bfSgovinda &ehcip->ehci_intr_cap)) != DDI_SUCCESS) { 8867c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 887*9c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_cap() failed %d", ret); 888*9c75c6bfSgovinda 889*9c75c6bfSgovinda for (i = 0; i < actual; i++) { 890*9c75c6bfSgovinda (void) ddi_intr_remove_handler(ehcip->ehci_htable[i]); 891*9c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 892*9c75c6bfSgovinda } 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate mutex_destroy(&ehcip->ehci_int_mutex); 895*9c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8987c478bd9Sstevel@tonic-gate } 8997c478bd9Sstevel@tonic-gate 900*9c75c6bfSgovinda /* Enable all interrupts */ 901*9c75c6bfSgovinda if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) { 902*9c75c6bfSgovinda /* Call ddi_intr_block_enable() for MSI interrupts */ 903*9c75c6bfSgovinda (void) ddi_intr_block_enable(ehcip->ehci_htable, 904*9c75c6bfSgovinda ehcip->ehci_intr_cnt); 905*9c75c6bfSgovinda } else { 906*9c75c6bfSgovinda /* Call ddi_intr_enable for MSI or FIXED interrupts */ 907*9c75c6bfSgovinda for (i = 0; i < ehcip->ehci_intr_cnt; i++) 908*9c75c6bfSgovinda (void) ddi_intr_enable(ehcip->ehci_htable[i]); 909*9c75c6bfSgovinda } 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate /* 9167c478bd9Sstevel@tonic-gate * ehci_init_ctlr: 9177c478bd9Sstevel@tonic-gate * 9187c478bd9Sstevel@tonic-gate * Initialize the Host Controller (HC). 9197c478bd9Sstevel@tonic-gate */ 9207c478bd9Sstevel@tonic-gate int 9217c478bd9Sstevel@tonic-gate ehci_init_ctlr(ehci_state_t *ehcip) 9227c478bd9Sstevel@tonic-gate { 9237c478bd9Sstevel@tonic-gate int revision; 9247c478bd9Sstevel@tonic-gate uint16_t cmd_reg; 9257c478bd9Sstevel@tonic-gate clock_t sof_time_wait; 9267c478bd9Sstevel@tonic-gate int abort_on_BIOS_take_over_failure; 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_init_ctlr:"); 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate /* Take control from the BIOS */ 9317c478bd9Sstevel@tonic-gate if (ehci_take_control(ehcip) != USB_SUCCESS) { 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate /* read .conf file properties */ 9347c478bd9Sstevel@tonic-gate abort_on_BIOS_take_over_failure = 9357c478bd9Sstevel@tonic-gate ddi_prop_get_int(DDI_DEV_T_ANY, 9367c478bd9Sstevel@tonic-gate ehcip->ehci_dip, DDI_PROP_DONTPASS, 9377c478bd9Sstevel@tonic-gate "abort-on-BIOS-take-over-failure", 0); 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate if (abort_on_BIOS_take_over_failure) { 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9427c478bd9Sstevel@tonic-gate "Unable to take control from BIOS."); 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9487c478bd9Sstevel@tonic-gate "Unable to take control from BIOS. Failure is ignored."); 9497c478bd9Sstevel@tonic-gate } 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate /* set Memory Master Enable */ 9527c478bd9Sstevel@tonic-gate cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM); 9537c478bd9Sstevel@tonic-gate cmd_reg |= (PCI_COMM_MAE | PCI_COMM_ME); 9547c478bd9Sstevel@tonic-gate pci_config_put16(ehcip->ehci_config_handle, PCI_CONF_COMM, cmd_reg); 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate /* Reset the EHCI host controller */ 9577c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 9587c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) | EHCI_CMD_HOST_CTRL_RESET); 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate /* Wait 10ms for reset to complete */ 9617c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT); 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED); 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate /* Verify the version number */ 9667c478bd9Sstevel@tonic-gate revision = Get_16Cap(ehci_version); 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9697c478bd9Sstevel@tonic-gate "ehci_init_ctlr: Revision 0x%x", revision); 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate /* 9727c478bd9Sstevel@tonic-gate * EHCI driver supports EHCI host controllers compliant to 9737c478bd9Sstevel@tonic-gate * 0.95 and higher revisions of EHCI specifications. 9747c478bd9Sstevel@tonic-gate */ 9757c478bd9Sstevel@tonic-gate if (revision < EHCI_REVISION_0_95) { 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9787c478bd9Sstevel@tonic-gate "Revision 0x%x is not supported", revision); 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9817c478bd9Sstevel@tonic-gate } 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate if (ehcip->ehci_hc_soft_state == EHCI_CTLR_INIT_STATE) { 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate /* Initialize the Frame list base address area */ 9867c478bd9Sstevel@tonic-gate if (ehci_init_periodic_frame_lst_table(ehcip) != DDI_SUCCESS) { 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate /* 9927c478bd9Sstevel@tonic-gate * For performance reasons, do not insert anything into the 9937c478bd9Sstevel@tonic-gate * asynchronous list or activate the asynch list schedule until 9947c478bd9Sstevel@tonic-gate * there is a valid QH. 9957c478bd9Sstevel@tonic-gate */ 9967c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list = NULL; 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) && 9997c478bd9Sstevel@tonic-gate (ehci_vt62x2_workaround & EHCI_VIA_ASYNC_SCHEDULE)) { 10007c478bd9Sstevel@tonic-gate /* 10017c478bd9Sstevel@tonic-gate * The driver is unable to reliably stop the asynch 10027c478bd9Sstevel@tonic-gate * list schedule on VIA VT6202 controllers, so we 10037c478bd9Sstevel@tonic-gate * always keep a dummy QH on the list. 10047c478bd9Sstevel@tonic-gate */ 10057c478bd9Sstevel@tonic-gate ehci_qh_t *dummy_async_qh = 10067c478bd9Sstevel@tonic-gate ehci_alloc_qh(ehcip, NULL, NULL); 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_link_ptr, 10097c478bd9Sstevel@tonic-gate ((ehci_qh_cpu_to_iommu(ehcip, dummy_async_qh) & 10107c478bd9Sstevel@tonic-gate EHCI_QH_LINK_PTR) | EHCI_QH_LINK_REF_QH)); 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate /* Set this QH to be the "head" of the circular list */ 10137c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_ctrl, 10147c478bd9Sstevel@tonic-gate Get_QH(dummy_async_qh->qh_ctrl) | 10157c478bd9Sstevel@tonic-gate EHCI_QH_CTRL_RECLAIM_HEAD); 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_next_qtd, 10187c478bd9Sstevel@tonic-gate EHCI_QH_NEXT_QTD_PTR_VALID); 10197c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_alt_next_qtd, 10207c478bd9Sstevel@tonic-gate EHCI_QH_ALT_NEXT_QTD_PTR_VALID); 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list = dummy_async_qh; 10237c478bd9Sstevel@tonic-gate ehcip->ehci_open_async_count++; 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate /* 10287c478bd9Sstevel@tonic-gate * Check for Asynchronous schedule park capability feature. If this 10297c478bd9Sstevel@tonic-gate * feature is supported, then, program ehci command register with 10307c478bd9Sstevel@tonic-gate * appropriate values.. 10317c478bd9Sstevel@tonic-gate */ 10327c478bd9Sstevel@tonic-gate if (Get_Cap(ehci_hcc_params) & EHCI_HCC_ASYNC_SCHED_PARK_CAP) { 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 10357c478bd9Sstevel@tonic-gate "ehci_init_ctlr: Async park mode is supported"); 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) | 10387c478bd9Sstevel@tonic-gate (EHCI_CMD_ASYNC_PARK_ENABLE | 10397c478bd9Sstevel@tonic-gate EHCI_CMD_ASYNC_PARK_COUNT_3))); 10407c478bd9Sstevel@tonic-gate } 10417c478bd9Sstevel@tonic-gate 10427c478bd9Sstevel@tonic-gate /* 10437c478bd9Sstevel@tonic-gate * Check for programmable periodic frame list feature. If this 10447c478bd9Sstevel@tonic-gate * feature is supported, then, program ehci command register with 10457c478bd9Sstevel@tonic-gate * 1024 frame list value. 10467c478bd9Sstevel@tonic-gate */ 10477c478bd9Sstevel@tonic-gate if (Get_Cap(ehci_hcc_params) & EHCI_HCC_PROG_FRAME_LIST_FLAG) { 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 10507c478bd9Sstevel@tonic-gate "ehci_init_ctlr: Variable programmable periodic " 10517c478bd9Sstevel@tonic-gate "frame list is supported"); 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) | 10547c478bd9Sstevel@tonic-gate EHCI_CMD_FRAME_1024_SIZE)); 10557c478bd9Sstevel@tonic-gate } 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate /* 10587c478bd9Sstevel@tonic-gate * Currently EHCI driver doesn't support 64 bit addressing. 10597c478bd9Sstevel@tonic-gate * 10607c478bd9Sstevel@tonic-gate * If we are using 64 bit addressing capability, then, program 10617c478bd9Sstevel@tonic-gate * ehci_ctrl_segment register with 4 Gigabyte segment where all 10627c478bd9Sstevel@tonic-gate * of the interface data structures are allocated. 10637c478bd9Sstevel@tonic-gate */ 10647c478bd9Sstevel@tonic-gate if (Get_Cap(ehci_hcc_params) & EHCI_HCC_64BIT_ADDR_CAP) { 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 10677c478bd9Sstevel@tonic-gate "ehci_init_ctlr: EHCI driver doesn't support " 10687c478bd9Sstevel@tonic-gate "64 bit addressing"); 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate /* 64 bit addressing is not support */ 10727c478bd9Sstevel@tonic-gate Set_OpReg(ehci_ctrl_segment, 0x00000000); 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate /* Turn on/off the schedulers */ 10757c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehcip); 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate /* 10787c478bd9Sstevel@tonic-gate * Set the Periodic Frame List Base Address register with the 10797c478bd9Sstevel@tonic-gate * starting physical address of the Periodic Frame List. 10807c478bd9Sstevel@tonic-gate */ 10817c478bd9Sstevel@tonic-gate Set_OpReg(ehci_periodic_list_base, 10827c478bd9Sstevel@tonic-gate (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address & 0xFFFFF000)); 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate /* 10857c478bd9Sstevel@tonic-gate * Set ehci_interrupt to enable all interrupts except Root 10867c478bd9Sstevel@tonic-gate * Hub Status change interrupt. 10877c478bd9Sstevel@tonic-gate */ 10887c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR | 10897c478bd9Sstevel@tonic-gate EHCI_INTR_FRAME_LIST_ROLLOVER | EHCI_INTR_USB_ERROR | 10907c478bd9Sstevel@tonic-gate EHCI_INTR_USB); 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate /* 10937c478bd9Sstevel@tonic-gate * Set the desired interrupt threshold and turn on EHCI host controller. 10947c478bd9Sstevel@tonic-gate */ 10957c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 10967c478bd9Sstevel@tonic-gate ((Get_OpReg(ehci_command) & ~EHCI_CMD_INTR_THRESHOLD) | 10977c478bd9Sstevel@tonic-gate (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN))); 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(ehci_command) & EHCI_CMD_HOST_CTRL_RUN); 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate /* 11027c478bd9Sstevel@tonic-gate * Acer Labs Inc. M5273 EHCI controller does not send 11037c478bd9Sstevel@tonic-gate * interrupts unless the Root hub ports are routed to the EHCI 11047c478bd9Sstevel@tonic-gate * host controller; so route the ports now, before we test for 11057c478bd9Sstevel@tonic-gate * the presence of SOFs interrupts. 11067c478bd9Sstevel@tonic-gate */ 11077c478bd9Sstevel@tonic-gate if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) { 11087c478bd9Sstevel@tonic-gate /* Route all Root hub ports to EHCI host controller */ 11097c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI); 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate /* 11137c478bd9Sstevel@tonic-gate * VIA chips have some issues and may not work reliably. 1114677739beShx * Revisions >= 0x80 are part of a southbridge and appear 1115677739beShx * to be reliable with the workaround. 11164610e4a0Sfrits * For revisions < 0x80, if we were bound using class 1117677739beShx * complain, else proceed. This will allow the user to 1118677739beShx * bind ehci specifically to this chip and not have the 1119677739beShx * warnings 11207c478bd9Sstevel@tonic-gate */ 1121677739beShx if (ehcip->ehci_vendor_id == PCI_VENDOR_VIA) { 1122677739beShx 1123677739beShx if (ehcip->ehci_rev_id >= PCI_VIA_REVISION_6212) { 1124677739beShx 1125677739beShx USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1126677739beShx "ehci_init_ctlr: Applying VIA workarounds for " 1127677739beShx "the 6212 chip."); 1128677739beShx 1129677739beShx } else if (strcmp(DEVI(ehcip->ehci_dip)->devi_binding_name, 1130677739beShx "pciclass,0c0320") == 0) { 1131677739beShx 11327c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11337c478bd9Sstevel@tonic-gate "Due to recently discovered incompatibilities"); 11347c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11357c478bd9Sstevel@tonic-gate "with this USB controller, USB2.x transfer"); 11367c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11377c478bd9Sstevel@tonic-gate "support has been disabled. This device will"); 11387c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11397c478bd9Sstevel@tonic-gate "continue to function as a USB1.x controller."); 11407c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11417c478bd9Sstevel@tonic-gate "If you are interested in enabling USB2.x"); 11427c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11437c478bd9Sstevel@tonic-gate "support please, refer to the ehci(7D) man page."); 11447c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11457c478bd9Sstevel@tonic-gate "Please also refer to www.sun.com/io for"); 11467c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11477c478bd9Sstevel@tonic-gate "Solaris Ready products and to"); 11487c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11497c478bd9Sstevel@tonic-gate "www.sun.com/bigadmin/hcl for additional"); 11507c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11517c478bd9Sstevel@tonic-gate "compatible USB products."); 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1154677739beShx 1155677739beShx } else if (ehci_vt62x2_workaround) { 1156677739beShx 11577c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11587c478bd9Sstevel@tonic-gate "Applying VIA workarounds"); 1159677739beShx } 11607c478bd9Sstevel@tonic-gate } 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate /* 11637c478bd9Sstevel@tonic-gate * Get the number of clock ticks to wait. 11647c478bd9Sstevel@tonic-gate * This is based on the maximum time it takes for a frame list rollover 11657c478bd9Sstevel@tonic-gate * and maximum time wait for SOFs to begin. 11667c478bd9Sstevel@tonic-gate */ 11677c478bd9Sstevel@tonic-gate sof_time_wait = drv_usectohz((EHCI_NUM_PERIODIC_FRAME_LISTS * 1000) + 11687c478bd9Sstevel@tonic-gate EHCI_SOF_TIMEWAIT); 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate /* Tell the ISR to broadcast ehci_async_schedule_advance_cv */ 11717c478bd9Sstevel@tonic-gate ehcip->ehci_flags |= EHCI_CV_INTR; 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate /* We need to add a delay to allow the chip time to start running */ 11747c478bd9Sstevel@tonic-gate (void) cv_timedwait(&ehcip->ehci_async_schedule_advance_cv, 11757c478bd9Sstevel@tonic-gate &ehcip->ehci_int_mutex, ddi_get_lbolt() + sof_time_wait); 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate /* 11787c478bd9Sstevel@tonic-gate * Check EHCI host controller is running, otherwise return failure. 11797c478bd9Sstevel@tonic-gate */ 11807c478bd9Sstevel@tonic-gate if ((ehcip->ehci_flags & EHCI_CV_INTR) || 11817c478bd9Sstevel@tonic-gate (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) { 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11847c478bd9Sstevel@tonic-gate "No SOF interrupts have been received, this USB EHCI host" 11857c478bd9Sstevel@tonic-gate "controller is unusable"); 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate /* 11887c478bd9Sstevel@tonic-gate * Route all Root hub ports to Classic host 11897c478bd9Sstevel@tonic-gate * controller, in case this is an unusable ALI M5273 11907c478bd9Sstevel@tonic-gate * EHCI controller. 11917c478bd9Sstevel@tonic-gate */ 11927c478bd9Sstevel@tonic-gate if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) { 11937c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC); 11947c478bd9Sstevel@tonic-gate } 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 12007c478bd9Sstevel@tonic-gate "ehci_init_ctlr: SOF's have started"); 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate /* Route all Root hub ports to EHCI host controller */ 12037c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI); 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate /* Set host controller soft state to operational */ 12067c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_OPERATIONAL_STATE; 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 12097c478bd9Sstevel@tonic-gate } 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate /* 12127c478bd9Sstevel@tonic-gate * ehci_take_control: 12137c478bd9Sstevel@tonic-gate * 12147c478bd9Sstevel@tonic-gate * Handshake to take EHCI control from BIOS if necessary. Its only valid for 12157c478bd9Sstevel@tonic-gate * x86 machines, because sparc doesn't have a BIOS. 12167c478bd9Sstevel@tonic-gate * On x86 machine, the take control process includes 12177c478bd9Sstevel@tonic-gate * o get the base address of the extended capability list 12187c478bd9Sstevel@tonic-gate * o find out the capability for handoff synchronization in the list. 12197c478bd9Sstevel@tonic-gate * o check if BIOS has owned the host controller. 12207c478bd9Sstevel@tonic-gate * o set the OS Owned semaphore bit, ask the BIOS to release the ownership. 12217c478bd9Sstevel@tonic-gate * o wait for a constant time and check if BIOS has relinquished control. 12227c478bd9Sstevel@tonic-gate */ 12237c478bd9Sstevel@tonic-gate /* ARGSUSED */ 12247c478bd9Sstevel@tonic-gate static int 12257c478bd9Sstevel@tonic-gate ehci_take_control(ehci_state_t *ehcip) 12267c478bd9Sstevel@tonic-gate { 12277c478bd9Sstevel@tonic-gate #if defined(__x86) 12287c478bd9Sstevel@tonic-gate uint32_t extended_cap; 12297c478bd9Sstevel@tonic-gate uint32_t extended_cap_offset; 12307c478bd9Sstevel@tonic-gate uint32_t extended_cap_id; 12317c478bd9Sstevel@tonic-gate uint_t retry; 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 12347c478bd9Sstevel@tonic-gate "ehci_take_control:"); 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate /* 12377c478bd9Sstevel@tonic-gate * According EHCI Spec 2.2.4, get EECP base address from HCCPARAMS 12387c478bd9Sstevel@tonic-gate * register. 12397c478bd9Sstevel@tonic-gate */ 12407c478bd9Sstevel@tonic-gate extended_cap_offset = (Get_Cap(ehci_hcc_params) & EHCI_HCC_EECP) >> 12417c478bd9Sstevel@tonic-gate EHCI_HCC_EECP_SHIFT; 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate /* 12447c478bd9Sstevel@tonic-gate * According EHCI Spec 2.2.4, if the extended capability offset is 12457c478bd9Sstevel@tonic-gate * less than 40h then its not valid. This means we don't need to 12467c478bd9Sstevel@tonic-gate * worry about BIOS handoff. 12477c478bd9Sstevel@tonic-gate */ 12487c478bd9Sstevel@tonic-gate if (extended_cap_offset < EHCI_HCC_EECP_MIN_OFFSET) { 12497c478bd9Sstevel@tonic-gate 12507c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 12517c478bd9Sstevel@tonic-gate "ehci_take_control: Hardware doesn't support legacy."); 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate goto success; 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate /* 12577c478bd9Sstevel@tonic-gate * According EHCI Spec 2.1.7, A zero offset indicates the 12587c478bd9Sstevel@tonic-gate * end of the extended capability list. 12597c478bd9Sstevel@tonic-gate */ 12607c478bd9Sstevel@tonic-gate while (extended_cap_offset) { 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate /* Get the extended capability value. */ 12637c478bd9Sstevel@tonic-gate extended_cap = pci_config_get32(ehcip->ehci_config_handle, 12647c478bd9Sstevel@tonic-gate extended_cap_offset); 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate /* Get the capability ID */ 12677c478bd9Sstevel@tonic-gate extended_cap_id = (extended_cap & EHCI_EX_CAP_ID) >> 12687c478bd9Sstevel@tonic-gate EHCI_EX_CAP_ID_SHIFT; 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate /* Check if the card support legacy */ 12717c478bd9Sstevel@tonic-gate if (extended_cap_id == EHCI_EX_CAP_ID_BIOS_HANDOFF) { 12727c478bd9Sstevel@tonic-gate break; 12737c478bd9Sstevel@tonic-gate } 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate /* Get the offset of the next capability */ 12767c478bd9Sstevel@tonic-gate extended_cap_offset = (extended_cap & EHCI_EX_CAP_NEXT_PTR) >> 12777c478bd9Sstevel@tonic-gate EHCI_EX_CAP_NEXT_PTR_SHIFT; 12787c478bd9Sstevel@tonic-gate } 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate /* 12817c478bd9Sstevel@tonic-gate * Unable to find legacy support in hardware's extended capability list. 12827c478bd9Sstevel@tonic-gate * This means we don't need to worry about BIOS handoff. 12837c478bd9Sstevel@tonic-gate */ 12847c478bd9Sstevel@tonic-gate if (extended_cap_id != EHCI_EX_CAP_ID_BIOS_HANDOFF) { 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 12877c478bd9Sstevel@tonic-gate "ehci_take_control: Hardware doesn't support legacy"); 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate goto success; 12907c478bd9Sstevel@tonic-gate } 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate /* Check if BIOS has owned it. */ 12937c478bd9Sstevel@tonic-gate if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) { 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 12967c478bd9Sstevel@tonic-gate "ehci_take_control: BIOS does not own EHCI"); 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate goto success; 12997c478bd9Sstevel@tonic-gate } 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate /* 13027c478bd9Sstevel@tonic-gate * According EHCI Spec 5.1, The OS driver initiates an ownership 13037c478bd9Sstevel@tonic-gate * request by setting the OS Owned semaphore to a one. The OS 13047c478bd9Sstevel@tonic-gate * waits for the BIOS Owned bit to go to a zero before attempting 13057c478bd9Sstevel@tonic-gate * to use the EHCI controller. The time that OS must wait for BIOS 13067c478bd9Sstevel@tonic-gate * to respond to the request for ownership is beyond the scope of 13077c478bd9Sstevel@tonic-gate * this specification. 13087c478bd9Sstevel@tonic-gate * It waits up to EHCI_TAKEOVER_WAIT_COUNT*EHCI_TAKEOVER_DELAY ms 13097c478bd9Sstevel@tonic-gate * for BIOS to release the ownership. 13107c478bd9Sstevel@tonic-gate */ 13117c478bd9Sstevel@tonic-gate extended_cap |= EHCI_LEGSUP_OS_OWNED_SEM; 13127c478bd9Sstevel@tonic-gate pci_config_put32(ehcip->ehci_config_handle, extended_cap_offset, 13137c478bd9Sstevel@tonic-gate extended_cap); 13147c478bd9Sstevel@tonic-gate 13157c478bd9Sstevel@tonic-gate for (retry = 0; retry < EHCI_TAKEOVER_WAIT_COUNT; retry++) { 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate /* wait a special interval */ 13187c478bd9Sstevel@tonic-gate delay(drv_usectohz(EHCI_TAKEOVER_DELAY)); 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate /* Check to see if the BIOS has released the ownership */ 13217c478bd9Sstevel@tonic-gate extended_cap = pci_config_get32( 13227c478bd9Sstevel@tonic-gate ehcip->ehci_config_handle, extended_cap_offset); 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) { 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, 13277c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 13287c478bd9Sstevel@tonic-gate "ehci_take_control: BIOS has released " 13297c478bd9Sstevel@tonic-gate "the ownership. retry = %d", retry); 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate goto success; 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 13377c478bd9Sstevel@tonic-gate "ehci_take_control: take control from BIOS failed."); 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate return (USB_FAILURE); 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate success: 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate #endif /* __x86 */ 13447c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 13457c478bd9Sstevel@tonic-gate } 13467c478bd9Sstevel@tonic-gate 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate /* 13497c478bd9Sstevel@tonic-gate * ehci_init_periodic_frame_list_table : 13507c478bd9Sstevel@tonic-gate * 13517c478bd9Sstevel@tonic-gate * Allocate the system memory and initialize Host Controller 13527c478bd9Sstevel@tonic-gate * Periodic Frame List table area. The starting of the Periodic 13537c478bd9Sstevel@tonic-gate * Frame List Table area must be 4096 byte aligned. 13547c478bd9Sstevel@tonic-gate */ 13557c478bd9Sstevel@tonic-gate static int 13567c478bd9Sstevel@tonic-gate ehci_init_periodic_frame_lst_table(ehci_state_t *ehcip) 13577c478bd9Sstevel@tonic-gate { 13587c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 13597c478bd9Sstevel@tonic-gate size_t real_length; 13607c478bd9Sstevel@tonic-gate uint_t ccount; 13617c478bd9Sstevel@tonic-gate int result; 13627c478bd9Sstevel@tonic-gate 13637c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 13667c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table:"); 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 13697c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 13707c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 13717c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate /* Force the required 4K restrictive alignment */ 13747c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_PFL_ALIGNMENT; 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate /* Create space for the Periodic Frame List */ 13777c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr, 13787c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 0, &ehcip->ehci_pflt_dma_handle) != DDI_SUCCESS) { 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate goto failure; 13817c478bd9Sstevel@tonic-gate } 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_pflt_dma_handle, 13847c478bd9Sstevel@tonic-gate sizeof (ehci_periodic_frame_list_t), 13857c478bd9Sstevel@tonic-gate &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 13867c478bd9Sstevel@tonic-gate 0, (caddr_t *)&ehcip->ehci_periodic_frame_list_tablep, 13877c478bd9Sstevel@tonic-gate &real_length, &ehcip->ehci_pflt_mem_handle)) { 13887c478bd9Sstevel@tonic-gate 13897c478bd9Sstevel@tonic-gate goto failure; 13907c478bd9Sstevel@tonic-gate } 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 13937c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: " 13947c478bd9Sstevel@tonic-gate "Real length %lu", real_length); 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate /* Map the whole Periodic Frame List into the I/O address space */ 13977c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ehcip->ehci_pflt_dma_handle, 13987c478bd9Sstevel@tonic-gate NULL, (caddr_t)ehcip->ehci_periodic_frame_list_tablep, 13997c478bd9Sstevel@tonic-gate real_length, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 14007c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, &ehcip->ehci_pflt_cookie, &ccount); 14017c478bd9Sstevel@tonic-gate 14027c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 14037c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 14047c478bd9Sstevel@tonic-gate if (ccount != 1) { 14057c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 14067c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: " 14077c478bd9Sstevel@tonic-gate "More than 1 cookie"); 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate goto failure; 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate } else { 14127c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result); 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate goto failure; 14157c478bd9Sstevel@tonic-gate } 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 14187c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: virtual 0x%p physical 0x%x", 14197c478bd9Sstevel@tonic-gate (void *)ehcip->ehci_periodic_frame_list_tablep, 14207c478bd9Sstevel@tonic-gate ehcip->ehci_pflt_cookie.dmac_address); 14217c478bd9Sstevel@tonic-gate 14227c478bd9Sstevel@tonic-gate /* 14237c478bd9Sstevel@tonic-gate * DMA addresses for Periodic Frame List are bound. 14247c478bd9Sstevel@tonic-gate */ 14257c478bd9Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_PFLT_DMA_BOUND; 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate bzero((void *)ehcip->ehci_periodic_frame_list_tablep, real_length); 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate /* Initialize the Periodic Frame List */ 14307c478bd9Sstevel@tonic-gate ehci_build_interrupt_lattice(ehcip); 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate /* Reset Byte Alignment to Default */ 14337c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 14367c478bd9Sstevel@tonic-gate failure: 14377c478bd9Sstevel@tonic-gate /* Byte alignment */ 14387c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 14397c478bd9Sstevel@tonic-gate 14407c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14417c478bd9Sstevel@tonic-gate } 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate /* 14457c478bd9Sstevel@tonic-gate * ehci_build_interrupt_lattice: 14467c478bd9Sstevel@tonic-gate * 14477c478bd9Sstevel@tonic-gate * Construct the interrupt lattice tree using static Endpoint Descriptors 14487c478bd9Sstevel@tonic-gate * (QH). This interrupt lattice tree will have total of 32 interrupt QH 14497c478bd9Sstevel@tonic-gate * lists and the Host Controller (HC) processes one interrupt QH list in 14507c478bd9Sstevel@tonic-gate * every frame. The Host Controller traverses the periodic schedule by 14517c478bd9Sstevel@tonic-gate * constructing an array offset reference from the Periodic List Base Address 14527c478bd9Sstevel@tonic-gate * register and bits 12 to 3 of Frame Index register. It fetches the element 14537c478bd9Sstevel@tonic-gate * and begins traversing the graph of linked schedule data structures. 14547c478bd9Sstevel@tonic-gate */ 14557c478bd9Sstevel@tonic-gate static void 14567c478bd9Sstevel@tonic-gate ehci_build_interrupt_lattice(ehci_state_t *ehcip) 14577c478bd9Sstevel@tonic-gate { 14587c478bd9Sstevel@tonic-gate ehci_qh_t *list_array = ehcip->ehci_qh_pool_addr; 14597c478bd9Sstevel@tonic-gate ushort_t ehci_index[EHCI_NUM_PERIODIC_FRAME_LISTS]; 14607c478bd9Sstevel@tonic-gate ehci_periodic_frame_list_t *periodic_frame_list = 14617c478bd9Sstevel@tonic-gate ehcip->ehci_periodic_frame_list_tablep; 14627c478bd9Sstevel@tonic-gate ushort_t *temp, num_of_nodes; 14637c478bd9Sstevel@tonic-gate uintptr_t addr; 14647c478bd9Sstevel@tonic-gate int i, j, k; 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 14677c478bd9Sstevel@tonic-gate "ehci_build_interrupt_lattice:"); 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate /* 14707c478bd9Sstevel@tonic-gate * Reserve the first 63 Endpoint Descriptor (QH) structures 14717c478bd9Sstevel@tonic-gate * in the pool as static endpoints & these are required for 14727c478bd9Sstevel@tonic-gate * constructing interrupt lattice tree. 14737c478bd9Sstevel@tonic-gate */ 14747c478bd9Sstevel@tonic-gate for (i = 0; i < EHCI_NUM_STATIC_NODES; i++) { 14757c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_state, EHCI_QH_STATIC); 14767c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_status, EHCI_QH_STS_HALTED); 14777c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_next_qtd, EHCI_QH_NEXT_QTD_PTR_VALID); 14787c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_alt_next_qtd, 14797c478bd9Sstevel@tonic-gate EHCI_QH_ALT_NEXT_QTD_PTR_VALID); 14807c478bd9Sstevel@tonic-gate } 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate /* 14837c478bd9Sstevel@tonic-gate * Make sure that last Endpoint on the periodic frame list terminates 14847c478bd9Sstevel@tonic-gate * periodic schedule. 14857c478bd9Sstevel@tonic-gate */ 14867c478bd9Sstevel@tonic-gate Set_QH(list_array[0].qh_link_ptr, EHCI_QH_LINK_PTR_VALID); 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate /* Build the interrupt lattice tree */ 14897c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_STATIC_NODES / 2); i++) { 14907c478bd9Sstevel@tonic-gate /* 14917c478bd9Sstevel@tonic-gate * The next pointer in the host controller endpoint 14927c478bd9Sstevel@tonic-gate * descriptor must contain an iommu address. Calculate 14937c478bd9Sstevel@tonic-gate * the offset into the cpu address and add this to the 14947c478bd9Sstevel@tonic-gate * starting iommu address. 14957c478bd9Sstevel@tonic-gate */ 14967c478bd9Sstevel@tonic-gate addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *)&list_array[i]); 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate Set_QH(list_array[2*i + 1].qh_link_ptr, 14997c478bd9Sstevel@tonic-gate addr | EHCI_QH_LINK_REF_QH); 15007c478bd9Sstevel@tonic-gate Set_QH(list_array[2*i + 2].qh_link_ptr, 15017c478bd9Sstevel@tonic-gate addr | EHCI_QH_LINK_REF_QH); 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate /* Build the tree bottom */ 15057c478bd9Sstevel@tonic-gate temp = (unsigned short *) 15067c478bd9Sstevel@tonic-gate kmem_zalloc(EHCI_NUM_PERIODIC_FRAME_LISTS * 2, KM_SLEEP); 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate num_of_nodes = 1; 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate /* 15117c478bd9Sstevel@tonic-gate * Initialize the values which are used for setting up head pointers 15127c478bd9Sstevel@tonic-gate * for the 32ms scheduling lists which starts from the Periodic Frame 15137c478bd9Sstevel@tonic-gate * List. 15147c478bd9Sstevel@tonic-gate */ 15157c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_log_2(EHCI_NUM_PERIODIC_FRAME_LISTS); i++) { 15167c478bd9Sstevel@tonic-gate for (j = 0, k = 0; k < num_of_nodes; k++, j++) { 15177c478bd9Sstevel@tonic-gate ehci_index[j++] = temp[k]; 15187c478bd9Sstevel@tonic-gate ehci_index[j] = temp[k] + ehci_pow_2(i); 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate num_of_nodes *= 2; 15227c478bd9Sstevel@tonic-gate for (k = 0; k < num_of_nodes; k++) 15237c478bd9Sstevel@tonic-gate temp[k] = ehci_index[k]; 15247c478bd9Sstevel@tonic-gate } 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate kmem_free((void *)temp, (EHCI_NUM_PERIODIC_FRAME_LISTS * 2)); 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate /* 15297c478bd9Sstevel@tonic-gate * Initialize the interrupt list in the Periodic Frame List Table 15307c478bd9Sstevel@tonic-gate * so that it points to the bottom of the tree. 15317c478bd9Sstevel@tonic-gate */ 15327c478bd9Sstevel@tonic-gate for (i = 0, j = 0; i < ehci_pow_2(TREE_HEIGHT); i++) { 15337c478bd9Sstevel@tonic-gate addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *) 15347c478bd9Sstevel@tonic-gate (&list_array[((EHCI_NUM_STATIC_NODES + 1) / 2) + i - 1])); 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate ASSERT(addr); 15377c478bd9Sstevel@tonic-gate 15387c478bd9Sstevel@tonic-gate for (k = 0; k < ehci_pow_2(TREE_HEIGHT); k++) { 15397c478bd9Sstevel@tonic-gate Set_PFLT(periodic_frame_list-> 15407c478bd9Sstevel@tonic-gate ehci_periodic_frame_list_table[ehci_index[j++]], 15417c478bd9Sstevel@tonic-gate (uint32_t)(addr | EHCI_QH_LINK_REF_QH)); 15427c478bd9Sstevel@tonic-gate } 15437c478bd9Sstevel@tonic-gate } 15447c478bd9Sstevel@tonic-gate } 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate /* 15487c478bd9Sstevel@tonic-gate * ehci_alloc_hcdi_ops: 15497c478bd9Sstevel@tonic-gate * 15507c478bd9Sstevel@tonic-gate * The HCDI interfaces or entry points are the software interfaces used by 15517c478bd9Sstevel@tonic-gate * the Universal Serial Bus Driver (USBA) to access the services of the 15527c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD). During HCD initialization, inform USBA 15537c478bd9Sstevel@tonic-gate * about all available HCDI interfaces or entry points. 15547c478bd9Sstevel@tonic-gate */ 15557c478bd9Sstevel@tonic-gate usba_hcdi_ops_t * 15567c478bd9Sstevel@tonic-gate ehci_alloc_hcdi_ops(ehci_state_t *ehcip) 15577c478bd9Sstevel@tonic-gate { 15587c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *usba_hcdi_ops; 15597c478bd9Sstevel@tonic-gate 15607c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 15617c478bd9Sstevel@tonic-gate "ehci_alloc_hcdi_ops:"); 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate usba_hcdi_ops = usba_alloc_hcdi_ops(); 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_ops_version = HCDI_OPS_VERSION; 15667c478bd9Sstevel@tonic-gate 15674610e4a0Sfrits usba_hcdi_ops->usba_hcdi_pm_support = ehci_hcdi_pm_support; 15687c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_open = ehci_hcdi_pipe_open; 15697c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_close = ehci_hcdi_pipe_close; 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_reset = ehci_hcdi_pipe_reset; 15727c478bd9Sstevel@tonic-gate 15737c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_ctrl_xfer = ehci_hcdi_pipe_ctrl_xfer; 15747c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_bulk_xfer = ehci_hcdi_pipe_bulk_xfer; 15757c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_intr_xfer = ehci_hcdi_pipe_intr_xfer; 15767c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_isoc_xfer = ehci_hcdi_pipe_isoc_xfer; 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_bulk_transfer_size = 15797c478bd9Sstevel@tonic-gate ehci_hcdi_bulk_transfer_size; 15807c478bd9Sstevel@tonic-gate 15817c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_intr_polling = 15827c478bd9Sstevel@tonic-gate ehci_hcdi_pipe_stop_intr_polling; 15837c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_isoc_polling = 15847c478bd9Sstevel@tonic-gate ehci_hcdi_pipe_stop_isoc_polling; 15857c478bd9Sstevel@tonic-gate 15867c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_current_frame_number = 15877c478bd9Sstevel@tonic-gate ehci_hcdi_get_current_frame_number; 15887c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_max_isoc_pkts = 15897c478bd9Sstevel@tonic-gate ehci_hcdi_get_max_isoc_pkts; 15907c478bd9Sstevel@tonic-gate 15917c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_init = 15927c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_init; 15937c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_enter = 15947c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_enter; 15957c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_read = 15967c478bd9Sstevel@tonic-gate ehci_hcdi_polled_read; 15977c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_exit = 15987c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_exit; 15997c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_fini = 16007c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_fini; 16017c478bd9Sstevel@tonic-gate return (usba_hcdi_ops); 16027c478bd9Sstevel@tonic-gate } 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate 16057c478bd9Sstevel@tonic-gate /* 16067c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) deinitialization functions 16077c478bd9Sstevel@tonic-gate */ 16087c478bd9Sstevel@tonic-gate 16097c478bd9Sstevel@tonic-gate /* 16107c478bd9Sstevel@tonic-gate * ehci_cleanup: 16117c478bd9Sstevel@tonic-gate * 16127c478bd9Sstevel@tonic-gate * Cleanup on attach failure or detach 16137c478bd9Sstevel@tonic-gate */ 16147c478bd9Sstevel@tonic-gate int 16157c478bd9Sstevel@tonic-gate ehci_cleanup(ehci_state_t *ehcip) 16167c478bd9Sstevel@tonic-gate { 16177c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw; 16187c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; 16197c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd; 16207c478bd9Sstevel@tonic-gate int i, ctrl, rval; 16217c478bd9Sstevel@tonic-gate int flags = ehcip->ehci_flags; 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_cleanup:"); 16247c478bd9Sstevel@tonic-gate 16257c478bd9Sstevel@tonic-gate if (flags & EHCI_RHREG) { 16267c478bd9Sstevel@tonic-gate /* Unload the root hub driver */ 16277c478bd9Sstevel@tonic-gate if (ehci_unload_root_hub_driver(ehcip) != USB_SUCCESS) { 16287c478bd9Sstevel@tonic-gate 16297c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 16307c478bd9Sstevel@tonic-gate } 16317c478bd9Sstevel@tonic-gate } 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate if (flags & EHCI_USBAREG) { 16347c478bd9Sstevel@tonic-gate /* Unregister this HCD instance with USBA */ 16357c478bd9Sstevel@tonic-gate usba_hcdi_unregister(ehcip->ehci_dip); 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate if (flags & EHCI_INTR) { 16397c478bd9Sstevel@tonic-gate 16407c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate /* Disable all EHCI QH list processing */ 16437c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) & 16447c478bd9Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | 16457c478bd9Sstevel@tonic-gate EHCI_CMD_PERIODIC_SCHED_ENABLE))); 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate /* Disable all EHCI interrupts */ 16487c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0); 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate /* wait for the next SOF */ 16517c478bd9Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip); 16527c478bd9Sstevel@tonic-gate 16534610e4a0Sfrits /* Route all Root hub ports to Classic host controller */ 16544610e4a0Sfrits Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC); 16554610e4a0Sfrits 16567c478bd9Sstevel@tonic-gate /* Stop the EHCI host controller */ 16577c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 16587c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN); 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate /* Wait for sometime */ 16617c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_TIMEWAIT); 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 16647c478bd9Sstevel@tonic-gate 1665*9c75c6bfSgovinda ehci_rem_intrs(ehcip); 16667c478bd9Sstevel@tonic-gate } 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate /* Unmap the EHCI registers */ 16697c478bd9Sstevel@tonic-gate if (ehcip->ehci_caps_handle) { 16707c478bd9Sstevel@tonic-gate ddi_regs_map_free(&ehcip->ehci_caps_handle); 16717c478bd9Sstevel@tonic-gate } 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate if (ehcip->ehci_config_handle) { 16747c478bd9Sstevel@tonic-gate pci_config_teardown(&ehcip->ehci_config_handle); 16757c478bd9Sstevel@tonic-gate } 16767c478bd9Sstevel@tonic-gate 16777c478bd9Sstevel@tonic-gate /* Free all the buffers */ 16787c478bd9Sstevel@tonic-gate if (ehcip->ehci_qtd_pool_addr && ehcip->ehci_qtd_pool_mem_handle) { 16797c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_qtd_pool_size; i ++) { 16807c478bd9Sstevel@tonic-gate qtd = &ehcip->ehci_qtd_pool_addr[i]; 16817c478bd9Sstevel@tonic-gate ctrl = Get_QTD(ehcip-> 16827c478bd9Sstevel@tonic-gate ehci_qtd_pool_addr[i].qtd_state); 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate if ((ctrl != EHCI_QTD_FREE) && 16857c478bd9Sstevel@tonic-gate (ctrl != EHCI_QTD_DUMMY) && 16867c478bd9Sstevel@tonic-gate (qtd->qtd_trans_wrapper)) { 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate tw = (ehci_trans_wrapper_t *) 16917c478bd9Sstevel@tonic-gate EHCI_LOOKUP_ID((uint32_t) 16927c478bd9Sstevel@tonic-gate Get_QTD(qtd->qtd_trans_wrapper)); 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 16957c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 16967c478bd9Sstevel@tonic-gate 16977c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */ 16987c478bd9Sstevel@tonic-gate ehci_stop_xfer_timer(ehcip, tw, 16997c478bd9Sstevel@tonic-gate EHCI_REMOVE_XFER_ALWAYS); 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate ehci_deallocate_tw(ehcip, pp, tw); 17027c478bd9Sstevel@tonic-gate 17037c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate } 17067c478bd9Sstevel@tonic-gate 17077c478bd9Sstevel@tonic-gate /* 17087c478bd9Sstevel@tonic-gate * If EHCI_QTD_POOL_BOUND flag is set, then unbind 17097c478bd9Sstevel@tonic-gate * the handle for QTD pools. 17107c478bd9Sstevel@tonic-gate */ 17117c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 17127c478bd9Sstevel@tonic-gate EHCI_QTD_POOL_BOUND) == EHCI_QTD_POOL_BOUND) { 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 17157c478bd9Sstevel@tonic-gate ehcip->ehci_qtd_pool_dma_handle); 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 17187c478bd9Sstevel@tonic-gate } 17197c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_qtd_pool_mem_handle); 17207c478bd9Sstevel@tonic-gate } 17217c478bd9Sstevel@tonic-gate 17227c478bd9Sstevel@tonic-gate /* Free the QTD pool */ 17237c478bd9Sstevel@tonic-gate if (ehcip->ehci_qtd_pool_dma_handle) { 17247c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_qtd_pool_dma_handle); 17257c478bd9Sstevel@tonic-gate } 17267c478bd9Sstevel@tonic-gate 17277c478bd9Sstevel@tonic-gate if (ehcip->ehci_qh_pool_addr && ehcip->ehci_qh_pool_mem_handle) { 17287c478bd9Sstevel@tonic-gate /* 17297c478bd9Sstevel@tonic-gate * If EHCI_QH_POOL_BOUND flag is set, then unbind 17307c478bd9Sstevel@tonic-gate * the handle for QH pools. 17317c478bd9Sstevel@tonic-gate */ 17327c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 17337c478bd9Sstevel@tonic-gate EHCI_QH_POOL_BOUND) == EHCI_QH_POOL_BOUND) { 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 17367c478bd9Sstevel@tonic-gate ehcip->ehci_qh_pool_dma_handle); 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 17397c478bd9Sstevel@tonic-gate } 17407c478bd9Sstevel@tonic-gate 17417c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_qh_pool_mem_handle); 17427c478bd9Sstevel@tonic-gate } 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate /* Free the QH pool */ 17457c478bd9Sstevel@tonic-gate if (ehcip->ehci_qh_pool_dma_handle) { 17467c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_qh_pool_dma_handle); 17477c478bd9Sstevel@tonic-gate } 17487c478bd9Sstevel@tonic-gate 17497c478bd9Sstevel@tonic-gate /* Free the Periodic frame list table (PFLT) area */ 17507c478bd9Sstevel@tonic-gate if (ehcip->ehci_periodic_frame_list_tablep && 17517c478bd9Sstevel@tonic-gate ehcip->ehci_pflt_mem_handle) { 17527c478bd9Sstevel@tonic-gate /* 17537c478bd9Sstevel@tonic-gate * If EHCI_PFLT_DMA_BOUND flag is set, then unbind 17547c478bd9Sstevel@tonic-gate * the handle for PFLT. 17557c478bd9Sstevel@tonic-gate */ 17567c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 17577c478bd9Sstevel@tonic-gate EHCI_PFLT_DMA_BOUND) == EHCI_PFLT_DMA_BOUND) { 17587c478bd9Sstevel@tonic-gate 17597c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 17607c478bd9Sstevel@tonic-gate ehcip->ehci_pflt_dma_handle); 17617c478bd9Sstevel@tonic-gate 17627c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 17637c478bd9Sstevel@tonic-gate } 17647c478bd9Sstevel@tonic-gate 17657c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_pflt_mem_handle); 17667c478bd9Sstevel@tonic-gate } 17677c478bd9Sstevel@tonic-gate 17687c478bd9Sstevel@tonic-gate (void) ehci_isoc_cleanup(ehcip); 17697c478bd9Sstevel@tonic-gate 17707c478bd9Sstevel@tonic-gate if (ehcip->ehci_pflt_dma_handle) { 17717c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_pflt_dma_handle); 17727c478bd9Sstevel@tonic-gate } 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate if (flags & EHCI_INTR) { 17757c478bd9Sstevel@tonic-gate /* Destroy the mutex */ 17767c478bd9Sstevel@tonic-gate mutex_destroy(&ehcip->ehci_int_mutex); 17777c478bd9Sstevel@tonic-gate 17787c478bd9Sstevel@tonic-gate /* Destroy the async schedule advance condition variable */ 17797c478bd9Sstevel@tonic-gate cv_destroy(&ehcip->ehci_async_schedule_advance_cv); 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate /* clean up kstat structs */ 17837c478bd9Sstevel@tonic-gate ehci_destroy_stats(ehcip); 17847c478bd9Sstevel@tonic-gate 17857c478bd9Sstevel@tonic-gate /* Free ehci hcdi ops */ 17867c478bd9Sstevel@tonic-gate if (ehcip->ehci_hcdi_ops) { 17877c478bd9Sstevel@tonic-gate usba_free_hcdi_ops(ehcip->ehci_hcdi_ops); 17887c478bd9Sstevel@tonic-gate } 17897c478bd9Sstevel@tonic-gate 17907c478bd9Sstevel@tonic-gate if (flags & EHCI_ZALLOC) { 17917c478bd9Sstevel@tonic-gate 17927c478bd9Sstevel@tonic-gate usb_free_log_hdl(ehcip->ehci_log_hdl); 17937c478bd9Sstevel@tonic-gate 17947c478bd9Sstevel@tonic-gate /* Remove all properties that might have been created */ 17957c478bd9Sstevel@tonic-gate ddi_prop_remove_all(ehcip->ehci_dip); 17967c478bd9Sstevel@tonic-gate 17977c478bd9Sstevel@tonic-gate /* Free the soft state */ 17987c478bd9Sstevel@tonic-gate ddi_soft_state_free(ehci_statep, 17997c478bd9Sstevel@tonic-gate ddi_get_instance(ehcip->ehci_dip)); 18007c478bd9Sstevel@tonic-gate } 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 18037c478bd9Sstevel@tonic-gate } 18047c478bd9Sstevel@tonic-gate 18057c478bd9Sstevel@tonic-gate 1806*9c75c6bfSgovinda /* 1807*9c75c6bfSgovinda * ehci_rem_intrs: 1808*9c75c6bfSgovinda * 1809*9c75c6bfSgovinda * Unregister FIXED or MSI interrupts 1810*9c75c6bfSgovinda */ 1811*9c75c6bfSgovinda static void 1812*9c75c6bfSgovinda ehci_rem_intrs(ehci_state_t *ehcip) 1813*9c75c6bfSgovinda { 1814*9c75c6bfSgovinda int i; 1815*9c75c6bfSgovinda 1816*9c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1817*9c75c6bfSgovinda "ehci_rem_intrs: interrupt type 0x%x", ehcip->ehci_intr_type); 1818*9c75c6bfSgovinda 1819*9c75c6bfSgovinda /* Disable all interrupts */ 1820*9c75c6bfSgovinda if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) { 1821*9c75c6bfSgovinda (void) ddi_intr_block_disable(ehcip->ehci_htable, 1822*9c75c6bfSgovinda ehcip->ehci_intr_cnt); 1823*9c75c6bfSgovinda } else { 1824*9c75c6bfSgovinda for (i = 0; i < ehcip->ehci_intr_cnt; i++) { 1825*9c75c6bfSgovinda (void) ddi_intr_disable(ehcip->ehci_htable[i]); 1826*9c75c6bfSgovinda } 1827*9c75c6bfSgovinda } 1828*9c75c6bfSgovinda 1829*9c75c6bfSgovinda /* Call ddi_intr_remove_handler() */ 1830*9c75c6bfSgovinda for (i = 0; i < ehcip->ehci_intr_cnt; i++) { 1831*9c75c6bfSgovinda (void) ddi_intr_remove_handler(ehcip->ehci_htable[i]); 1832*9c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 1833*9c75c6bfSgovinda } 1834*9c75c6bfSgovinda 1835*9c75c6bfSgovinda kmem_free(ehcip->ehci_htable, 1836*9c75c6bfSgovinda ehcip->ehci_intr_cnt * sizeof (ddi_intr_handle_t)); 1837*9c75c6bfSgovinda } 1838*9c75c6bfSgovinda 1839*9c75c6bfSgovinda 18407c478bd9Sstevel@tonic-gate /* 18417c478bd9Sstevel@tonic-gate * ehci_cpr_suspend 18427c478bd9Sstevel@tonic-gate */ 18437c478bd9Sstevel@tonic-gate int 18447c478bd9Sstevel@tonic-gate ehci_cpr_suspend(ehci_state_t *ehcip) 18457c478bd9Sstevel@tonic-gate { 18467c478bd9Sstevel@tonic-gate int i; 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 18497c478bd9Sstevel@tonic-gate "ehci_cpr_suspend:"); 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate /* Call into the root hub and suspend it */ 18527c478bd9Sstevel@tonic-gate if (usba_hubdi_detach(ehcip->ehci_dip, DDI_SUSPEND) != DDI_SUCCESS) { 18537c478bd9Sstevel@tonic-gate 18547c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 18557c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: root hub fails to suspend"); 18567c478bd9Sstevel@tonic-gate 18577c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 18587c478bd9Sstevel@tonic-gate } 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate /* Only root hub's intr pipe should be open at this time */ 18617c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 18627c478bd9Sstevel@tonic-gate 18637c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_open_pipe_count == 0); 18647c478bd9Sstevel@tonic-gate 18657c478bd9Sstevel@tonic-gate /* Just wait till all resources are reclaimed */ 18667c478bd9Sstevel@tonic-gate i = 0; 18677c478bd9Sstevel@tonic-gate while ((ehcip->ehci_reclaim_list != NULL) && (i++ < 3)) { 18687c478bd9Sstevel@tonic-gate ehci_handle_endpoint_reclaimation(ehcip); 18697c478bd9Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip); 18707c478bd9Sstevel@tonic-gate } 18717c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_reclaim_list == NULL); 18727c478bd9Sstevel@tonic-gate 18737c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 18747c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: Disable HC QH list processing"); 18757c478bd9Sstevel@tonic-gate 18767c478bd9Sstevel@tonic-gate /* Disable all EHCI QH list processing */ 18777c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) & 18787c478bd9Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE))); 18797c478bd9Sstevel@tonic-gate 18807c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 18817c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: Disable HC interrupts"); 18827c478bd9Sstevel@tonic-gate 18837c478bd9Sstevel@tonic-gate /* Disable all EHCI interrupts */ 18847c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0); 18857c478bd9Sstevel@tonic-gate 18867c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 18877c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: Wait for the next SOF"); 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate /* Wait for the next SOF */ 18907c478bd9Sstevel@tonic-gate if (ehci_wait_for_sof(ehcip) != USB_SUCCESS) { 18917c478bd9Sstevel@tonic-gate 18927c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 18937c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: ehci host controller suspend failed"); 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 18967c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 18977c478bd9Sstevel@tonic-gate } 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate /* 19007c478bd9Sstevel@tonic-gate * Stop the ehci host controller 19017c478bd9Sstevel@tonic-gate * if usb keyboard is not connected. 19027c478bd9Sstevel@tonic-gate */ 19037c478bd9Sstevel@tonic-gate if (ehcip->ehci_polled_kbd_count == 0) { 19047c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 19057c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN); 19067c478bd9Sstevel@tonic-gate } 19077c478bd9Sstevel@tonic-gate 19087c478bd9Sstevel@tonic-gate /* Set host controller soft state to suspend */ 19097c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_SUSPEND_STATE; 19107c478bd9Sstevel@tonic-gate 19117c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 19127c478bd9Sstevel@tonic-gate 19137c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 19147c478bd9Sstevel@tonic-gate } 19157c478bd9Sstevel@tonic-gate 19167c478bd9Sstevel@tonic-gate 19177c478bd9Sstevel@tonic-gate /* 19187c478bd9Sstevel@tonic-gate * ehci_cpr_resume 19197c478bd9Sstevel@tonic-gate */ 19207c478bd9Sstevel@tonic-gate int 19217c478bd9Sstevel@tonic-gate ehci_cpr_resume(ehci_state_t *ehcip) 19227c478bd9Sstevel@tonic-gate { 19237c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 19247c478bd9Sstevel@tonic-gate 19257c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19267c478bd9Sstevel@tonic-gate "ehci_cpr_resume: Restart the controller"); 19277c478bd9Sstevel@tonic-gate 19287c478bd9Sstevel@tonic-gate /* Cleanup ehci specific information across cpr */ 19297c478bd9Sstevel@tonic-gate ehci_cpr_cleanup(ehcip); 19307c478bd9Sstevel@tonic-gate 19317c478bd9Sstevel@tonic-gate /* Restart the controller */ 19327c478bd9Sstevel@tonic-gate if (ehci_init_ctlr(ehcip) != DDI_SUCCESS) { 19337c478bd9Sstevel@tonic-gate 19347c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19357c478bd9Sstevel@tonic-gate "ehci_cpr_resume: ehci host controller resume failed "); 19367c478bd9Sstevel@tonic-gate 19377c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 19387c478bd9Sstevel@tonic-gate 19397c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 19407c478bd9Sstevel@tonic-gate } 19417c478bd9Sstevel@tonic-gate 19427c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 19437c478bd9Sstevel@tonic-gate 19447c478bd9Sstevel@tonic-gate /* Now resume the root hub */ 19457c478bd9Sstevel@tonic-gate if (usba_hubdi_attach(ehcip->ehci_dip, DDI_RESUME) != DDI_SUCCESS) { 19467c478bd9Sstevel@tonic-gate 19477c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 19487c478bd9Sstevel@tonic-gate } 19497c478bd9Sstevel@tonic-gate 19507c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 19517c478bd9Sstevel@tonic-gate } 19527c478bd9Sstevel@tonic-gate 19537c478bd9Sstevel@tonic-gate 19547c478bd9Sstevel@tonic-gate /* 19557c478bd9Sstevel@tonic-gate * Bandwidth Allocation functions 19567c478bd9Sstevel@tonic-gate */ 19577c478bd9Sstevel@tonic-gate 19587c478bd9Sstevel@tonic-gate /* 19597c478bd9Sstevel@tonic-gate * ehci_allocate_bandwidth: 19607c478bd9Sstevel@tonic-gate * 19617c478bd9Sstevel@tonic-gate * Figure out whether or not this interval may be supported. Return the index 19627c478bd9Sstevel@tonic-gate * into the lattice if it can be supported. Return allocation failure if it 19637c478bd9Sstevel@tonic-gate * can not be supported. 19647c478bd9Sstevel@tonic-gate */ 19657c478bd9Sstevel@tonic-gate int 19667c478bd9Sstevel@tonic-gate ehci_allocate_bandwidth( 19677c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 19687c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 19697c478bd9Sstevel@tonic-gate uint_t *pnode, 19707c478bd9Sstevel@tonic-gate uchar_t *smask, 19717c478bd9Sstevel@tonic-gate uchar_t *cmask) 19727c478bd9Sstevel@tonic-gate { 19737c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 19747c478bd9Sstevel@tonic-gate 19757c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 19767c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 19777c478bd9Sstevel@tonic-gate 19787c478bd9Sstevel@tonic-gate /* Reset the pnode to the last checked pnode */ 19797c478bd9Sstevel@tonic-gate *pnode = 0; 19807c478bd9Sstevel@tonic-gate 19817c478bd9Sstevel@tonic-gate /* Allocate high speed bandwidth */ 19827c478bd9Sstevel@tonic-gate if ((error = ehci_allocate_high_speed_bandwidth(ehcip, 19837c478bd9Sstevel@tonic-gate ph, pnode, smask, cmask)) != USB_SUCCESS) { 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate return (error); 19867c478bd9Sstevel@tonic-gate } 19877c478bd9Sstevel@tonic-gate 19887c478bd9Sstevel@tonic-gate /* 19897c478bd9Sstevel@tonic-gate * For low/full speed usb devices, allocate classic TT bandwidth 19907c478bd9Sstevel@tonic-gate * in additional to high speed bandwidth. 19917c478bd9Sstevel@tonic-gate */ 19927c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) { 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate /* Allocate classic TT bandwidth */ 19957c478bd9Sstevel@tonic-gate if ((error = ehci_allocate_classic_tt_bandwidth( 19967c478bd9Sstevel@tonic-gate ehcip, ph, *pnode)) != USB_SUCCESS) { 19977c478bd9Sstevel@tonic-gate 19987c478bd9Sstevel@tonic-gate /* Deallocate high speed bandwidth */ 19997c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth( 20007c478bd9Sstevel@tonic-gate ehcip, ph, *pnode, *smask, *cmask); 20017c478bd9Sstevel@tonic-gate } 20027c478bd9Sstevel@tonic-gate } 20037c478bd9Sstevel@tonic-gate 20047c478bd9Sstevel@tonic-gate return (error); 20057c478bd9Sstevel@tonic-gate } 20067c478bd9Sstevel@tonic-gate 20077c478bd9Sstevel@tonic-gate 20087c478bd9Sstevel@tonic-gate /* 20097c478bd9Sstevel@tonic-gate * ehci_allocate_high_speed_bandwidth: 20107c478bd9Sstevel@tonic-gate * 20117c478bd9Sstevel@tonic-gate * Allocate high speed bandwidth for the low/full/high speed interrupt and 20127c478bd9Sstevel@tonic-gate * isochronous endpoints. 20137c478bd9Sstevel@tonic-gate */ 20147c478bd9Sstevel@tonic-gate static int 20157c478bd9Sstevel@tonic-gate ehci_allocate_high_speed_bandwidth( 20167c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 20177c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 20187c478bd9Sstevel@tonic-gate uint_t *pnode, 20197c478bd9Sstevel@tonic-gate uchar_t *smask, 20207c478bd9Sstevel@tonic-gate uchar_t *cmask) 20217c478bd9Sstevel@tonic-gate { 20227c478bd9Sstevel@tonic-gate uint_t sbandwidth, cbandwidth; 20237c478bd9Sstevel@tonic-gate int interval; 20247c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 20257c478bd9Sstevel@tonic-gate usba_device_t *child_ud; 20267c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 20277c478bd9Sstevel@tonic-gate int error; 20287c478bd9Sstevel@tonic-gate 20297c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 20307c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 20317c478bd9Sstevel@tonic-gate 20327c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 20337c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 20347c478bd9Sstevel@tonic-gate 20357c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 20367c478bd9Sstevel@tonic-gate 20377c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 20387c478bd9Sstevel@tonic-gate port_status = ph->p_usba_device->usb_port_status; 20397c478bd9Sstevel@tonic-gate 20407c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 20417c478bd9Sstevel@tonic-gate 20427c478bd9Sstevel@tonic-gate /* 20437c478bd9Sstevel@tonic-gate * Calculate the length in bytes of a transaction on this 20447c478bd9Sstevel@tonic-gate * periodic endpoint. Return failure if maximum packet is 20457c478bd9Sstevel@tonic-gate * zero. 20467c478bd9Sstevel@tonic-gate */ 20477c478bd9Sstevel@tonic-gate error = ehci_compute_high_speed_bandwidth(ehcip, endpoint, 20487c478bd9Sstevel@tonic-gate port_status, &sbandwidth, &cbandwidth); 20497c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 20507c478bd9Sstevel@tonic-gate 20517c478bd9Sstevel@tonic-gate return (error); 20527c478bd9Sstevel@tonic-gate } 20537c478bd9Sstevel@tonic-gate 20547c478bd9Sstevel@tonic-gate /* 20557c478bd9Sstevel@tonic-gate * Adjust polling interval to be a power of 2. 20567c478bd9Sstevel@tonic-gate * If this interval can't be supported, return 20577c478bd9Sstevel@tonic-gate * allocation failure. 20587c478bd9Sstevel@tonic-gate */ 20597c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 20607c478bd9Sstevel@tonic-gate if (interval == USB_FAILURE) { 20617c478bd9Sstevel@tonic-gate 20627c478bd9Sstevel@tonic-gate return (USB_FAILURE); 20637c478bd9Sstevel@tonic-gate } 20647c478bd9Sstevel@tonic-gate 20657c478bd9Sstevel@tonic-gate if (port_status == USBA_HIGH_SPEED_DEV) { 20667c478bd9Sstevel@tonic-gate /* Allocate bandwidth for high speed devices, except ITD */ 20677c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_hs_mask(ehcip, smask, pnode, 20687c478bd9Sstevel@tonic-gate endpoint, sbandwidth, interval); 20697c478bd9Sstevel@tonic-gate *cmask = 0x00; 20707c478bd9Sstevel@tonic-gate 20717c478bd9Sstevel@tonic-gate } else { 20727c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) == 20737c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR) { 20747c478bd9Sstevel@tonic-gate 20757c478bd9Sstevel@tonic-gate /* Allocate bandwidth for low speed interrupt */ 20767c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_ls_intr_mask(ehcip, 20777c478bd9Sstevel@tonic-gate smask, cmask, pnode, sbandwidth, cbandwidth, 20787c478bd9Sstevel@tonic-gate interval); 20797c478bd9Sstevel@tonic-gate } else { 20807c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 20817c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate /* Allocate bandwidth for sitd in */ 20847c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_sitd_in_mask(ehcip, 20857c478bd9Sstevel@tonic-gate smask, cmask, pnode, sbandwidth, cbandwidth, 20867c478bd9Sstevel@tonic-gate interval); 20877c478bd9Sstevel@tonic-gate } else { 20887c478bd9Sstevel@tonic-gate 20897c478bd9Sstevel@tonic-gate /* Allocate bandwidth for sitd out */ 20907c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_sitd_out_mask(ehcip, 20917c478bd9Sstevel@tonic-gate smask, pnode, sbandwidth, interval); 20927c478bd9Sstevel@tonic-gate *cmask = 0x00; 20937c478bd9Sstevel@tonic-gate } 20947c478bd9Sstevel@tonic-gate } 20957c478bd9Sstevel@tonic-gate } 20967c478bd9Sstevel@tonic-gate 20977c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 20987c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 20997c478bd9Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: Reached maximum " 21007c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth for a " 21017c478bd9Sstevel@tonic-gate "given high-speed periodic endpoint"); 21027c478bd9Sstevel@tonic-gate 21037c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 21047c478bd9Sstevel@tonic-gate } 21057c478bd9Sstevel@tonic-gate 21067c478bd9Sstevel@tonic-gate return (error); 21077c478bd9Sstevel@tonic-gate } 21087c478bd9Sstevel@tonic-gate 21097c478bd9Sstevel@tonic-gate 21107c478bd9Sstevel@tonic-gate /* 21117c478bd9Sstevel@tonic-gate * ehci_allocate_classic_tt_speed_bandwidth: 21127c478bd9Sstevel@tonic-gate * 21137c478bd9Sstevel@tonic-gate * Allocate classic TT bandwidth for the low/full speed interrupt and 21147c478bd9Sstevel@tonic-gate * isochronous endpoints. 21157c478bd9Sstevel@tonic-gate */ 21167c478bd9Sstevel@tonic-gate static int 21177c478bd9Sstevel@tonic-gate ehci_allocate_classic_tt_bandwidth( 21187c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 21197c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 21207c478bd9Sstevel@tonic-gate uint_t pnode) 21217c478bd9Sstevel@tonic-gate { 21227c478bd9Sstevel@tonic-gate uint_t bandwidth, min; 21237c478bd9Sstevel@tonic-gate uint_t height, leftmost, list; 21247c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 21257c478bd9Sstevel@tonic-gate usba_device_t *child_ud, *parent_ud; 21267c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 21277c478bd9Sstevel@tonic-gate int i, interval; 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 21307c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 21317c478bd9Sstevel@tonic-gate 21327c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 21337c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 21347c478bd9Sstevel@tonic-gate 21357c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 21367c478bd9Sstevel@tonic-gate 21377c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 21387c478bd9Sstevel@tonic-gate port_status = child_ud->usb_port_status; 21397c478bd9Sstevel@tonic-gate 21407c478bd9Sstevel@tonic-gate /* Get the parent high speed hub's usba device structure */ 21417c478bd9Sstevel@tonic-gate parent_ud = child_ud->usb_hs_hub_usba_dev; 21427c478bd9Sstevel@tonic-gate 21437c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 21447c478bd9Sstevel@tonic-gate 21457c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 21467c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: " 21477c478bd9Sstevel@tonic-gate "child_ud 0x%p parent_ud 0x%p", child_ud, parent_ud); 21487c478bd9Sstevel@tonic-gate 21497c478bd9Sstevel@tonic-gate /* 21507c478bd9Sstevel@tonic-gate * Calculate the length in bytes of a transaction on this 21517c478bd9Sstevel@tonic-gate * periodic endpoint. Return failure if maximum packet is 21527c478bd9Sstevel@tonic-gate * zero. 21537c478bd9Sstevel@tonic-gate */ 21547c478bd9Sstevel@tonic-gate if (ehci_compute_classic_bandwidth(endpoint, 21557c478bd9Sstevel@tonic-gate port_status, &bandwidth) != USB_SUCCESS) { 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 21587c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Periodic endpoint " 21597c478bd9Sstevel@tonic-gate "with zero endpoint maximum packet size is not supported"); 21607c478bd9Sstevel@tonic-gate 21617c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 21627c478bd9Sstevel@tonic-gate } 21637c478bd9Sstevel@tonic-gate 21647c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 21657c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: bandwidth %d", bandwidth); 21667c478bd9Sstevel@tonic-gate 21677c478bd9Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex); 21687c478bd9Sstevel@tonic-gate 21697c478bd9Sstevel@tonic-gate /* 21707c478bd9Sstevel@tonic-gate * If the length in bytes plus the allocated bandwidth exceeds 21717c478bd9Sstevel@tonic-gate * the maximum, return bandwidth allocation failure. 21727c478bd9Sstevel@tonic-gate */ 21737c478bd9Sstevel@tonic-gate if ((parent_ud->usb_hs_hub_min_bandwidth + bandwidth) > 21747c478bd9Sstevel@tonic-gate FS_PERIODIC_BANDWIDTH) { 21757c478bd9Sstevel@tonic-gate 21767c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 21777c478bd9Sstevel@tonic-gate 21787c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 21797c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Reached maximum " 21807c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth for a " 21817c478bd9Sstevel@tonic-gate "given low/full speed periodic endpoint"); 21827c478bd9Sstevel@tonic-gate 21837c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 21847c478bd9Sstevel@tonic-gate } 21857c478bd9Sstevel@tonic-gate 21867c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 21877c478bd9Sstevel@tonic-gate 21887c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 21897c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 21907c478bd9Sstevel@tonic-gate 21917c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 21927c478bd9Sstevel@tonic-gate height = ehci_lattice_height(interval); 21937c478bd9Sstevel@tonic-gate 21947c478bd9Sstevel@tonic-gate /* Find the leftmost leaf in the subtree specified by the node. */ 21957c478bd9Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height); 21967c478bd9Sstevel@tonic-gate 21977c478bd9Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex); 21987c478bd9Sstevel@tonic-gate 21997c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) { 22007c478bd9Sstevel@tonic-gate list = ehci_index[leftmost + i]; 22017c478bd9Sstevel@tonic-gate 22027c478bd9Sstevel@tonic-gate if ((parent_ud->usb_hs_hub_bandwidth[list] + 22037c478bd9Sstevel@tonic-gate bandwidth) > FS_PERIODIC_BANDWIDTH) { 22047c478bd9Sstevel@tonic-gate 22057c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 22067c478bd9Sstevel@tonic-gate 22077c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 22087c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Reached " 22097c478bd9Sstevel@tonic-gate "maximum bandwidth value and cannot allocate " 22107c478bd9Sstevel@tonic-gate "bandwidth for low/full periodic endpoint"); 22117c478bd9Sstevel@tonic-gate 22127c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 22137c478bd9Sstevel@tonic-gate } 22147c478bd9Sstevel@tonic-gate } 22157c478bd9Sstevel@tonic-gate 22167c478bd9Sstevel@tonic-gate /* 22177c478bd9Sstevel@tonic-gate * All the leaves for this node must be updated with the bandwidth. 22187c478bd9Sstevel@tonic-gate */ 22197c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) { 22207c478bd9Sstevel@tonic-gate list = ehci_index[leftmost + i]; 22217c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_bandwidth[list] += bandwidth; 22227c478bd9Sstevel@tonic-gate } 22237c478bd9Sstevel@tonic-gate 22247c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */ 22257c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[0]; 22267c478bd9Sstevel@tonic-gate 22277c478bd9Sstevel@tonic-gate for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) { 22287c478bd9Sstevel@tonic-gate if (parent_ud->usb_hs_hub_bandwidth[i] < min) { 22297c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[i]; 22307c478bd9Sstevel@tonic-gate } 22317c478bd9Sstevel@tonic-gate } 22327c478bd9Sstevel@tonic-gate 22337c478bd9Sstevel@tonic-gate /* Save the minimum for later use */ 22347c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_min_bandwidth = min; 22357c478bd9Sstevel@tonic-gate 22367c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 22377c478bd9Sstevel@tonic-gate 22387c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 22397c478bd9Sstevel@tonic-gate } 22407c478bd9Sstevel@tonic-gate 22417c478bd9Sstevel@tonic-gate 22427c478bd9Sstevel@tonic-gate /* 22437c478bd9Sstevel@tonic-gate * ehci_deallocate_bandwidth: 22447c478bd9Sstevel@tonic-gate * 22457c478bd9Sstevel@tonic-gate * Deallocate bandwidth for the given node in the lattice and the length 22467c478bd9Sstevel@tonic-gate * of transfer. 22477c478bd9Sstevel@tonic-gate */ 22487c478bd9Sstevel@tonic-gate void 22497c478bd9Sstevel@tonic-gate ehci_deallocate_bandwidth( 22507c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 22517c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 22527c478bd9Sstevel@tonic-gate uint_t pnode, 22537c478bd9Sstevel@tonic-gate uchar_t smask, 22547c478bd9Sstevel@tonic-gate uchar_t cmask) 22557c478bd9Sstevel@tonic-gate { 22567c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 22577c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 22587c478bd9Sstevel@tonic-gate 22597c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth(ehcip, ph, pnode, smask, cmask); 22607c478bd9Sstevel@tonic-gate 22617c478bd9Sstevel@tonic-gate /* 22627c478bd9Sstevel@tonic-gate * For low/full speed usb devices, deallocate classic TT bandwidth 22637c478bd9Sstevel@tonic-gate * in additional to high speed bandwidth. 22647c478bd9Sstevel@tonic-gate */ 22657c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) { 22667c478bd9Sstevel@tonic-gate 22677c478bd9Sstevel@tonic-gate /* Deallocate classic TT bandwidth */ 22687c478bd9Sstevel@tonic-gate ehci_deallocate_classic_tt_bandwidth(ehcip, ph, pnode); 22697c478bd9Sstevel@tonic-gate } 22707c478bd9Sstevel@tonic-gate } 22717c478bd9Sstevel@tonic-gate 22727c478bd9Sstevel@tonic-gate 22737c478bd9Sstevel@tonic-gate /* 22747c478bd9Sstevel@tonic-gate * ehci_deallocate_high_speed_bandwidth: 22757c478bd9Sstevel@tonic-gate * 22767c478bd9Sstevel@tonic-gate * Deallocate high speed bandwidth of a interrupt or isochronous endpoint. 22777c478bd9Sstevel@tonic-gate */ 22787c478bd9Sstevel@tonic-gate static void 22797c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth( 22807c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 22817c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 22827c478bd9Sstevel@tonic-gate uint_t pnode, 22837c478bd9Sstevel@tonic-gate uchar_t smask, 22847c478bd9Sstevel@tonic-gate uchar_t cmask) 22857c478bd9Sstevel@tonic-gate { 22867c478bd9Sstevel@tonic-gate uint_t height, leftmost; 22877c478bd9Sstevel@tonic-gate uint_t list_count; 22887c478bd9Sstevel@tonic-gate uint_t sbandwidth, cbandwidth; 22897c478bd9Sstevel@tonic-gate int interval; 22907c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 22917c478bd9Sstevel@tonic-gate usba_device_t *child_ud; 22927c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 22937c478bd9Sstevel@tonic-gate 22947c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 22957c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 22967c478bd9Sstevel@tonic-gate 22977c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 22987c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 22997c478bd9Sstevel@tonic-gate 23007c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 23017c478bd9Sstevel@tonic-gate 23027c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 23037c478bd9Sstevel@tonic-gate port_status = ph->p_usba_device->usb_port_status; 23047c478bd9Sstevel@tonic-gate 23057c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 23067c478bd9Sstevel@tonic-gate 23077c478bd9Sstevel@tonic-gate (void) ehci_compute_high_speed_bandwidth(ehcip, endpoint, 23087c478bd9Sstevel@tonic-gate port_status, &sbandwidth, &cbandwidth); 23097c478bd9Sstevel@tonic-gate 23107c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 23117c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 23127c478bd9Sstevel@tonic-gate 23137c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 23147c478bd9Sstevel@tonic-gate height = ehci_lattice_height(interval); 23157c478bd9Sstevel@tonic-gate 23167c478bd9Sstevel@tonic-gate /* 23177c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node 23187c478bd9Sstevel@tonic-gate */ 23197c478bd9Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height); 23207c478bd9Sstevel@tonic-gate 23217c478bd9Sstevel@tonic-gate list_count = EHCI_NUM_INTR_QH_LISTS/interval; 23227c478bd9Sstevel@tonic-gate 23237c478bd9Sstevel@tonic-gate /* Delete the bandwidth from the appropriate lists */ 23247c478bd9Sstevel@tonic-gate if (port_status == USBA_HIGH_SPEED_DEV) { 23257c478bd9Sstevel@tonic-gate 23267c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth, 23277c478bd9Sstevel@tonic-gate leftmost, list_count, smask); 23287c478bd9Sstevel@tonic-gate } else { 23297c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) == 23307c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR) { 23317c478bd9Sstevel@tonic-gate 23327c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth, 23337c478bd9Sstevel@tonic-gate leftmost, list_count, smask); 23347c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -cbandwidth, 23357c478bd9Sstevel@tonic-gate leftmost, list_count, cmask); 23367c478bd9Sstevel@tonic-gate } else { 23377c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 23387c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 23397c478bd9Sstevel@tonic-gate 23407c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth, 23417c478bd9Sstevel@tonic-gate leftmost, list_count, smask); 23427c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, 23437c478bd9Sstevel@tonic-gate -MAX_UFRAME_SITD_XFER, leftmost, 23447c478bd9Sstevel@tonic-gate list_count, cmask); 23457c478bd9Sstevel@tonic-gate } else { 23467c478bd9Sstevel@tonic-gate 23477c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, 23487c478bd9Sstevel@tonic-gate -MAX_UFRAME_SITD_XFER, leftmost, 23497c478bd9Sstevel@tonic-gate list_count, smask); 23507c478bd9Sstevel@tonic-gate } 23517c478bd9Sstevel@tonic-gate } 23527c478bd9Sstevel@tonic-gate } 23537c478bd9Sstevel@tonic-gate } 23547c478bd9Sstevel@tonic-gate 23557c478bd9Sstevel@tonic-gate /* 23567c478bd9Sstevel@tonic-gate * ehci_deallocate_classic_tt_bandwidth: 23577c478bd9Sstevel@tonic-gate * 23587c478bd9Sstevel@tonic-gate * Deallocate high speed bandwidth of a interrupt or isochronous endpoint. 23597c478bd9Sstevel@tonic-gate */ 23607c478bd9Sstevel@tonic-gate static void 23617c478bd9Sstevel@tonic-gate ehci_deallocate_classic_tt_bandwidth( 23627c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 23637c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 23647c478bd9Sstevel@tonic-gate uint_t pnode) 23657c478bd9Sstevel@tonic-gate { 23667c478bd9Sstevel@tonic-gate uint_t bandwidth, height, leftmost, list, min; 23677c478bd9Sstevel@tonic-gate int i, interval; 23687c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 23697c478bd9Sstevel@tonic-gate usba_device_t *child_ud, *parent_ud; 23707c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 23717c478bd9Sstevel@tonic-gate 23727c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 23737c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 23747c478bd9Sstevel@tonic-gate 23757c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 23767c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 23777c478bd9Sstevel@tonic-gate 23787c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 23797c478bd9Sstevel@tonic-gate 23807c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 23817c478bd9Sstevel@tonic-gate port_status = child_ud->usb_port_status; 23827c478bd9Sstevel@tonic-gate 23837c478bd9Sstevel@tonic-gate /* Get the parent high speed hub's usba device structure */ 23847c478bd9Sstevel@tonic-gate parent_ud = child_ud->usb_hs_hub_usba_dev; 23857c478bd9Sstevel@tonic-gate 23867c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 23877c478bd9Sstevel@tonic-gate 23887c478bd9Sstevel@tonic-gate /* Obtain the bandwidth */ 23897c478bd9Sstevel@tonic-gate (void) ehci_compute_classic_bandwidth(endpoint, 23907c478bd9Sstevel@tonic-gate port_status, &bandwidth); 23917c478bd9Sstevel@tonic-gate 23927c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 23937c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 23947c478bd9Sstevel@tonic-gate 23957c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 23967c478bd9Sstevel@tonic-gate height = ehci_lattice_height(interval); 23977c478bd9Sstevel@tonic-gate 23987c478bd9Sstevel@tonic-gate /* Find the leftmost leaf in the subtree specified by the node */ 23997c478bd9Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height); 24007c478bd9Sstevel@tonic-gate 24017c478bd9Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex); 24027c478bd9Sstevel@tonic-gate 24037c478bd9Sstevel@tonic-gate /* Delete the bandwidth from the appropriate lists */ 24047c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) { 24057c478bd9Sstevel@tonic-gate list = ehci_index[leftmost + i]; 24067c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_bandwidth[list] -= bandwidth; 24077c478bd9Sstevel@tonic-gate } 24087c478bd9Sstevel@tonic-gate 24097c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */ 24107c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[0]; 24117c478bd9Sstevel@tonic-gate 24127c478bd9Sstevel@tonic-gate for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) { 24137c478bd9Sstevel@tonic-gate if (parent_ud->usb_hs_hub_bandwidth[i] < min) { 24147c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[i]; 24157c478bd9Sstevel@tonic-gate } 24167c478bd9Sstevel@tonic-gate } 24177c478bd9Sstevel@tonic-gate 24187c478bd9Sstevel@tonic-gate /* Save the minimum for later use */ 24197c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_min_bandwidth = min; 24207c478bd9Sstevel@tonic-gate 24217c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 24227c478bd9Sstevel@tonic-gate } 24237c478bd9Sstevel@tonic-gate 24247c478bd9Sstevel@tonic-gate 24257c478bd9Sstevel@tonic-gate /* 24267c478bd9Sstevel@tonic-gate * ehci_compute_high_speed_bandwidth: 24277c478bd9Sstevel@tonic-gate * 24287c478bd9Sstevel@tonic-gate * Given a periodic endpoint (interrupt or isochronous) determine the total 24297c478bd9Sstevel@tonic-gate * bandwidth for one transaction. The EHCI host controller traverses the 24307c478bd9Sstevel@tonic-gate * endpoint descriptor lists on a first-come-first-serve basis. When the HC 24317c478bd9Sstevel@tonic-gate * services an endpoint, only a single transaction attempt is made. The HC 24327c478bd9Sstevel@tonic-gate * moves to the next Endpoint Descriptor after the first transaction attempt 24337c478bd9Sstevel@tonic-gate * rather than finishing the entire Transfer Descriptor. Therefore, when a 24347c478bd9Sstevel@tonic-gate * Transfer Descriptor is inserted into the lattice, we will only count the 24357c478bd9Sstevel@tonic-gate * number of bytes for one transaction. 24367c478bd9Sstevel@tonic-gate * 24377c478bd9Sstevel@tonic-gate * The following are the formulas used for calculating bandwidth in terms 24387c478bd9Sstevel@tonic-gate * bytes and it is for the single USB high speed transaction. The protocol 24397c478bd9Sstevel@tonic-gate * overheads will be different for each of type of USB transfer & all these 24407c478bd9Sstevel@tonic-gate * formulas & protocol overheads are derived from the 5.11.3 section of the 24417c478bd9Sstevel@tonic-gate * USB 2.0 Specification. 24427c478bd9Sstevel@tonic-gate * 24437c478bd9Sstevel@tonic-gate * High-Speed: 24447c478bd9Sstevel@tonic-gate * Protocol overhead + ((MaxPktSz * 7)/6) + Host_Delay 24457c478bd9Sstevel@tonic-gate * 24467c478bd9Sstevel@tonic-gate * Split Transaction: (Low/Full speed devices connected behind usb2.0 hub) 24477c478bd9Sstevel@tonic-gate * 24487c478bd9Sstevel@tonic-gate * Protocol overhead + Split transaction overhead + 24497c478bd9Sstevel@tonic-gate * ((MaxPktSz * 7)/6) + Host_Delay; 24507c478bd9Sstevel@tonic-gate */ 24517c478bd9Sstevel@tonic-gate /* ARGSUSED */ 24527c478bd9Sstevel@tonic-gate static int 24537c478bd9Sstevel@tonic-gate ehci_compute_high_speed_bandwidth( 24547c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 24557c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 24567c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 24577c478bd9Sstevel@tonic-gate uint_t *sbandwidth, 24587c478bd9Sstevel@tonic-gate uint_t *cbandwidth) 24597c478bd9Sstevel@tonic-gate { 24607c478bd9Sstevel@tonic-gate ushort_t maxpacketsize = endpoint->wMaxPacketSize; 24617c478bd9Sstevel@tonic-gate 24627c478bd9Sstevel@tonic-gate /* Return failure if endpoint maximum packet is zero */ 24637c478bd9Sstevel@tonic-gate if (maxpacketsize == 0) { 24647c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 24657c478bd9Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: Periodic endpoint " 24667c478bd9Sstevel@tonic-gate "with zero endpoint maximum packet size is not supported"); 24677c478bd9Sstevel@tonic-gate 24687c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 24697c478bd9Sstevel@tonic-gate } 24707c478bd9Sstevel@tonic-gate 24717c478bd9Sstevel@tonic-gate /* Add bit-stuffing overhead */ 24727c478bd9Sstevel@tonic-gate maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6); 24737c478bd9Sstevel@tonic-gate 24747c478bd9Sstevel@tonic-gate /* Add Host Controller specific delay to required bandwidth */ 24757c478bd9Sstevel@tonic-gate *sbandwidth = EHCI_HOST_CONTROLLER_DELAY; 24767c478bd9Sstevel@tonic-gate 24777c478bd9Sstevel@tonic-gate /* Add xfer specific protocol overheads */ 24787c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 24797c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) { 24807c478bd9Sstevel@tonic-gate /* High speed interrupt transaction */ 24817c478bd9Sstevel@tonic-gate *sbandwidth += HS_NON_ISOC_PROTO_OVERHEAD; 24827c478bd9Sstevel@tonic-gate } else { 24837c478bd9Sstevel@tonic-gate /* Isochronous transaction */ 24847c478bd9Sstevel@tonic-gate *sbandwidth += HS_ISOC_PROTO_OVERHEAD; 24857c478bd9Sstevel@tonic-gate } 24867c478bd9Sstevel@tonic-gate 24877c478bd9Sstevel@tonic-gate /* 24887c478bd9Sstevel@tonic-gate * For low/full speed devices, add split transaction specific 24897c478bd9Sstevel@tonic-gate * overheads. 24907c478bd9Sstevel@tonic-gate */ 24917c478bd9Sstevel@tonic-gate if (port_status != USBA_HIGH_SPEED_DEV) { 24927c478bd9Sstevel@tonic-gate /* 24937c478bd9Sstevel@tonic-gate * Add start and complete split transaction 24947c478bd9Sstevel@tonic-gate * tokens overheads. 24957c478bd9Sstevel@tonic-gate */ 24967c478bd9Sstevel@tonic-gate *cbandwidth = *sbandwidth + COMPLETE_SPLIT_OVERHEAD; 24977c478bd9Sstevel@tonic-gate *sbandwidth += START_SPLIT_OVERHEAD; 24987c478bd9Sstevel@tonic-gate 24997c478bd9Sstevel@tonic-gate /* Add data overhead depending on data direction */ 25007c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 25017c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 25027c478bd9Sstevel@tonic-gate *cbandwidth += maxpacketsize; 25037c478bd9Sstevel@tonic-gate } else { 25047c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 25057c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) { 25067c478bd9Sstevel@tonic-gate /* There is no compete splits for out */ 25077c478bd9Sstevel@tonic-gate *cbandwidth = 0; 25087c478bd9Sstevel@tonic-gate } 25097c478bd9Sstevel@tonic-gate *sbandwidth += maxpacketsize; 25107c478bd9Sstevel@tonic-gate } 25117c478bd9Sstevel@tonic-gate } else { 25127c478bd9Sstevel@tonic-gate uint_t xactions; 25137c478bd9Sstevel@tonic-gate 25147c478bd9Sstevel@tonic-gate /* Get the max transactions per microframe */ 25157c478bd9Sstevel@tonic-gate xactions = ((maxpacketsize & USB_EP_MAX_XACTS_MASK) >> 25167c478bd9Sstevel@tonic-gate USB_EP_MAX_XACTS_SHIFT) + 1; 25177c478bd9Sstevel@tonic-gate 25187c478bd9Sstevel@tonic-gate /* High speed transaction */ 25197c478bd9Sstevel@tonic-gate *sbandwidth += maxpacketsize; 25207c478bd9Sstevel@tonic-gate 25217c478bd9Sstevel@tonic-gate /* Calculate bandwidth per micro-frame */ 25227c478bd9Sstevel@tonic-gate *sbandwidth *= xactions; 25237c478bd9Sstevel@tonic-gate 25247c478bd9Sstevel@tonic-gate *cbandwidth = 0; 25257c478bd9Sstevel@tonic-gate } 25267c478bd9Sstevel@tonic-gate 25277c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 25287c478bd9Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: " 25297c478bd9Sstevel@tonic-gate "Start split bandwidth %d Complete split bandwidth %d", 25307c478bd9Sstevel@tonic-gate *sbandwidth, *cbandwidth); 25317c478bd9Sstevel@tonic-gate 25327c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 25337c478bd9Sstevel@tonic-gate } 25347c478bd9Sstevel@tonic-gate 25357c478bd9Sstevel@tonic-gate 25367c478bd9Sstevel@tonic-gate /* 25377c478bd9Sstevel@tonic-gate * ehci_compute_classic_bandwidth: 25387c478bd9Sstevel@tonic-gate * 25397c478bd9Sstevel@tonic-gate * Given a periodic endpoint (interrupt or isochronous) determine the total 25407c478bd9Sstevel@tonic-gate * bandwidth for one transaction. The EHCI host controller traverses the 25417c478bd9Sstevel@tonic-gate * endpoint descriptor lists on a first-come-first-serve basis. When the HC 25427c478bd9Sstevel@tonic-gate * services an endpoint, only a single transaction attempt is made. The HC 25437c478bd9Sstevel@tonic-gate * moves to the next Endpoint Descriptor after the first transaction attempt 25447c478bd9Sstevel@tonic-gate * rather than finishing the entire Transfer Descriptor. Therefore, when a 25457c478bd9Sstevel@tonic-gate * Transfer Descriptor is inserted into the lattice, we will only count the 25467c478bd9Sstevel@tonic-gate * number of bytes for one transaction. 25477c478bd9Sstevel@tonic-gate * 25487c478bd9Sstevel@tonic-gate * The following are the formulas used for calculating bandwidth in terms 25497c478bd9Sstevel@tonic-gate * bytes and it is for the single USB high speed transaction. The protocol 25507c478bd9Sstevel@tonic-gate * overheads will be different for each of type of USB transfer & all these 25517c478bd9Sstevel@tonic-gate * formulas & protocol overheads are derived from the 5.11.3 section of the 25527c478bd9Sstevel@tonic-gate * USB 2.0 Specification. 25537c478bd9Sstevel@tonic-gate * 25547c478bd9Sstevel@tonic-gate * Low-Speed: 25557c478bd9Sstevel@tonic-gate * Protocol overhead + Hub LS overhead + 25567c478bd9Sstevel@tonic-gate * (Low Speed clock * ((MaxPktSz * 7)/6)) + TT_Delay 25577c478bd9Sstevel@tonic-gate * 25587c478bd9Sstevel@tonic-gate * Full-Speed: 25597c478bd9Sstevel@tonic-gate * Protocol overhead + ((MaxPktSz * 7)/6) + TT_Delay 25607c478bd9Sstevel@tonic-gate */ 25617c478bd9Sstevel@tonic-gate /* ARGSUSED */ 25627c478bd9Sstevel@tonic-gate static int 25637c478bd9Sstevel@tonic-gate ehci_compute_classic_bandwidth( 25647c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 25657c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 25667c478bd9Sstevel@tonic-gate uint_t *bandwidth) 25677c478bd9Sstevel@tonic-gate { 25687c478bd9Sstevel@tonic-gate ushort_t maxpacketsize = endpoint->wMaxPacketSize; 25697c478bd9Sstevel@tonic-gate 25707c478bd9Sstevel@tonic-gate /* 25717c478bd9Sstevel@tonic-gate * If endpoint maximum packet is zero, then return immediately. 25727c478bd9Sstevel@tonic-gate */ 25737c478bd9Sstevel@tonic-gate if (maxpacketsize == 0) { 25747c478bd9Sstevel@tonic-gate 25757c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 25767c478bd9Sstevel@tonic-gate } 25777c478bd9Sstevel@tonic-gate 25787c478bd9Sstevel@tonic-gate /* Add TT delay to required bandwidth */ 25797c478bd9Sstevel@tonic-gate *bandwidth = TT_DELAY; 25807c478bd9Sstevel@tonic-gate 25817c478bd9Sstevel@tonic-gate /* Add bit-stuffing overhead */ 25827c478bd9Sstevel@tonic-gate maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6); 25837c478bd9Sstevel@tonic-gate 25847c478bd9Sstevel@tonic-gate switch (port_status) { 25857c478bd9Sstevel@tonic-gate case USBA_LOW_SPEED_DEV: 25867c478bd9Sstevel@tonic-gate /* Low speed interrupt transaction */ 25877c478bd9Sstevel@tonic-gate *bandwidth += (LOW_SPEED_PROTO_OVERHEAD + 25887c478bd9Sstevel@tonic-gate HUB_LOW_SPEED_PROTO_OVERHEAD + 25897c478bd9Sstevel@tonic-gate (LOW_SPEED_CLOCK * maxpacketsize)); 25907c478bd9Sstevel@tonic-gate break; 25917c478bd9Sstevel@tonic-gate case USBA_FULL_SPEED_DEV: 25927c478bd9Sstevel@tonic-gate /* Full speed transaction */ 25937c478bd9Sstevel@tonic-gate *bandwidth += maxpacketsize; 25947c478bd9Sstevel@tonic-gate 25957c478bd9Sstevel@tonic-gate /* Add xfer specific protocol overheads */ 25967c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 25977c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) { 25987c478bd9Sstevel@tonic-gate /* Full speed interrupt transaction */ 25997c478bd9Sstevel@tonic-gate *bandwidth += FS_NON_ISOC_PROTO_OVERHEAD; 26007c478bd9Sstevel@tonic-gate } else { 26017c478bd9Sstevel@tonic-gate /* Isochronous and input transaction */ 26027c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 26037c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 26047c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_INPUT_PROTO_OVERHEAD; 26057c478bd9Sstevel@tonic-gate } else { 26067c478bd9Sstevel@tonic-gate /* Isochronous and output transaction */ 26077c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_OUTPUT_PROTO_OVERHEAD; 26087c478bd9Sstevel@tonic-gate } 26097c478bd9Sstevel@tonic-gate } 26107c478bd9Sstevel@tonic-gate break; 26117c478bd9Sstevel@tonic-gate } 26127c478bd9Sstevel@tonic-gate 26137c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 26147c478bd9Sstevel@tonic-gate } 26157c478bd9Sstevel@tonic-gate 26167c478bd9Sstevel@tonic-gate 26177c478bd9Sstevel@tonic-gate /* 26187c478bd9Sstevel@tonic-gate * ehci_adjust_polling_interval: 26197c478bd9Sstevel@tonic-gate * 26207c478bd9Sstevel@tonic-gate * Adjust bandwidth according usb device speed. 26217c478bd9Sstevel@tonic-gate */ 26227c478bd9Sstevel@tonic-gate /* ARGSUSED */ 26237c478bd9Sstevel@tonic-gate int 26247c478bd9Sstevel@tonic-gate ehci_adjust_polling_interval( 26257c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 26267c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 26277c478bd9Sstevel@tonic-gate usb_port_status_t port_status) 26287c478bd9Sstevel@tonic-gate { 26297c478bd9Sstevel@tonic-gate uint_t interval; 26307c478bd9Sstevel@tonic-gate int i = 0; 26317c478bd9Sstevel@tonic-gate 26327c478bd9Sstevel@tonic-gate /* Get the polling interval */ 26337c478bd9Sstevel@tonic-gate interval = endpoint->bInterval; 26347c478bd9Sstevel@tonic-gate 26357c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 26367c478bd9Sstevel@tonic-gate "ehci_adjust_polling_interval: Polling interval 0x%x", interval); 26377c478bd9Sstevel@tonic-gate 26387c478bd9Sstevel@tonic-gate /* 26397c478bd9Sstevel@tonic-gate * According USB 2.0 Specifications, a high-speed endpoint's 26407c478bd9Sstevel@tonic-gate * polling intervals are specified interms of 125us or micro 26417c478bd9Sstevel@tonic-gate * frame, where as full/low endpoint's polling intervals are 26427c478bd9Sstevel@tonic-gate * specified in milliseconds. 26437c478bd9Sstevel@tonic-gate * 26447c478bd9Sstevel@tonic-gate * A high speed interrupt/isochronous endpoints can specify 26457c478bd9Sstevel@tonic-gate * desired polling interval between 1 to 16 micro-frames, 26467c478bd9Sstevel@tonic-gate * where as full/low endpoints can specify between 1 to 255 26477c478bd9Sstevel@tonic-gate * milliseconds. 26487c478bd9Sstevel@tonic-gate */ 26497c478bd9Sstevel@tonic-gate switch (port_status) { 26507c478bd9Sstevel@tonic-gate case USBA_LOW_SPEED_DEV: 26517c478bd9Sstevel@tonic-gate /* 26527c478bd9Sstevel@tonic-gate * Low speed endpoints are limited to specifying 26537c478bd9Sstevel@tonic-gate * only 8ms to 255ms in this driver. If a device 26547c478bd9Sstevel@tonic-gate * reports a polling interval that is less than 8ms, 26557c478bd9Sstevel@tonic-gate * it will use 8 ms instead. 26567c478bd9Sstevel@tonic-gate */ 26577c478bd9Sstevel@tonic-gate if (interval < LS_MIN_POLL_INTERVAL) { 26587c478bd9Sstevel@tonic-gate 26597c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 26607c478bd9Sstevel@tonic-gate "Low speed endpoint's poll interval of %d ms " 26617c478bd9Sstevel@tonic-gate "is below threshold. Rounding up to %d ms", 26627c478bd9Sstevel@tonic-gate interval, LS_MIN_POLL_INTERVAL); 26637c478bd9Sstevel@tonic-gate 26647c478bd9Sstevel@tonic-gate interval = LS_MIN_POLL_INTERVAL; 26657c478bd9Sstevel@tonic-gate } 26667c478bd9Sstevel@tonic-gate 26677c478bd9Sstevel@tonic-gate /* 26687c478bd9Sstevel@tonic-gate * Return an error if the polling interval is greater 26697c478bd9Sstevel@tonic-gate * than 255ms. 26707c478bd9Sstevel@tonic-gate */ 26717c478bd9Sstevel@tonic-gate if (interval > LS_MAX_POLL_INTERVAL) { 26727c478bd9Sstevel@tonic-gate 26737c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 26747c478bd9Sstevel@tonic-gate "Low speed endpoint's poll interval is " 26757c478bd9Sstevel@tonic-gate "greater than %d ms", LS_MAX_POLL_INTERVAL); 26767c478bd9Sstevel@tonic-gate 26777c478bd9Sstevel@tonic-gate return (USB_FAILURE); 26787c478bd9Sstevel@tonic-gate } 26797c478bd9Sstevel@tonic-gate break; 26807c478bd9Sstevel@tonic-gate 26817c478bd9Sstevel@tonic-gate case USBA_FULL_SPEED_DEV: 26827c478bd9Sstevel@tonic-gate /* 26837c478bd9Sstevel@tonic-gate * Return an error if the polling interval is less 26847c478bd9Sstevel@tonic-gate * than 1ms and greater than 255ms. 26857c478bd9Sstevel@tonic-gate */ 26867c478bd9Sstevel@tonic-gate if ((interval < FS_MIN_POLL_INTERVAL) && 26877c478bd9Sstevel@tonic-gate (interval > FS_MAX_POLL_INTERVAL)) { 26887c478bd9Sstevel@tonic-gate 26897c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 26907c478bd9Sstevel@tonic-gate "Full speed endpoint's poll interval must " 26917c478bd9Sstevel@tonic-gate "be between %d and %d ms", FS_MIN_POLL_INTERVAL, 26927c478bd9Sstevel@tonic-gate FS_MAX_POLL_INTERVAL); 26937c478bd9Sstevel@tonic-gate 26947c478bd9Sstevel@tonic-gate return (USB_FAILURE); 26957c478bd9Sstevel@tonic-gate } 26967c478bd9Sstevel@tonic-gate break; 26977c478bd9Sstevel@tonic-gate case USBA_HIGH_SPEED_DEV: 26987c478bd9Sstevel@tonic-gate /* 26997c478bd9Sstevel@tonic-gate * Return an error if the polling interval is less 1 27007c478bd9Sstevel@tonic-gate * and greater than 16. Convert this value to 125us 27017c478bd9Sstevel@tonic-gate * units using 2^(bInterval -1). refer usb 2.0 spec 27027c478bd9Sstevel@tonic-gate * page 51 for details. 27037c478bd9Sstevel@tonic-gate */ 27047c478bd9Sstevel@tonic-gate if ((interval < HS_MIN_POLL_INTERVAL) && 27057c478bd9Sstevel@tonic-gate (interval > HS_MAX_POLL_INTERVAL)) { 27067c478bd9Sstevel@tonic-gate 27077c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 27087c478bd9Sstevel@tonic-gate "High speed endpoint's poll interval " 27097c478bd9Sstevel@tonic-gate "must be between %d and %d units", 27107c478bd9Sstevel@tonic-gate HS_MIN_POLL_INTERVAL, HS_MAX_POLL_INTERVAL); 27117c478bd9Sstevel@tonic-gate 27127c478bd9Sstevel@tonic-gate return (USB_FAILURE); 27137c478bd9Sstevel@tonic-gate } 27147c478bd9Sstevel@tonic-gate 27157c478bd9Sstevel@tonic-gate /* Adjust high speed device polling interval */ 27167c478bd9Sstevel@tonic-gate interval = 27177c478bd9Sstevel@tonic-gate ehci_adjust_high_speed_polling_interval(ehcip, endpoint); 27187c478bd9Sstevel@tonic-gate 27197c478bd9Sstevel@tonic-gate break; 27207c478bd9Sstevel@tonic-gate } 27217c478bd9Sstevel@tonic-gate 27227c478bd9Sstevel@tonic-gate /* 27237c478bd9Sstevel@tonic-gate * If polling interval is greater than 32ms, 27247c478bd9Sstevel@tonic-gate * adjust polling interval equal to 32ms. 27257c478bd9Sstevel@tonic-gate */ 27267c478bd9Sstevel@tonic-gate if (interval > EHCI_NUM_INTR_QH_LISTS) { 27277c478bd9Sstevel@tonic-gate interval = EHCI_NUM_INTR_QH_LISTS; 27287c478bd9Sstevel@tonic-gate } 27297c478bd9Sstevel@tonic-gate 27307c478bd9Sstevel@tonic-gate /* 27317c478bd9Sstevel@tonic-gate * Find the nearest power of 2 that's less 27327c478bd9Sstevel@tonic-gate * than interval. 27337c478bd9Sstevel@tonic-gate */ 27347c478bd9Sstevel@tonic-gate while ((ehci_pow_2(i)) <= interval) { 27357c478bd9Sstevel@tonic-gate i++; 27367c478bd9Sstevel@tonic-gate } 27377c478bd9Sstevel@tonic-gate 27387c478bd9Sstevel@tonic-gate return (ehci_pow_2((i - 1))); 27397c478bd9Sstevel@tonic-gate } 27407c478bd9Sstevel@tonic-gate 27417c478bd9Sstevel@tonic-gate 27427c478bd9Sstevel@tonic-gate /* 27437c478bd9Sstevel@tonic-gate * ehci_adjust_high_speed_polling_interval: 27447c478bd9Sstevel@tonic-gate */ 27457c478bd9Sstevel@tonic-gate /* ARGSUSED */ 27467c478bd9Sstevel@tonic-gate static int 27477c478bd9Sstevel@tonic-gate ehci_adjust_high_speed_polling_interval( 27487c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 27497c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint) 27507c478bd9Sstevel@tonic-gate { 27517c478bd9Sstevel@tonic-gate uint_t interval; 27527c478bd9Sstevel@tonic-gate 27537c478bd9Sstevel@tonic-gate /* Get the polling interval */ 27547c478bd9Sstevel@tonic-gate interval = ehci_pow_2(endpoint->bInterval - 1); 27557c478bd9Sstevel@tonic-gate 27567c478bd9Sstevel@tonic-gate /* 27577c478bd9Sstevel@tonic-gate * Convert polling interval from micro seconds 27587c478bd9Sstevel@tonic-gate * to milli seconds. 27597c478bd9Sstevel@tonic-gate */ 27607c478bd9Sstevel@tonic-gate if (interval <= EHCI_MAX_UFRAMES) { 27617c478bd9Sstevel@tonic-gate interval = 1; 27627c478bd9Sstevel@tonic-gate } else { 27637c478bd9Sstevel@tonic-gate interval = interval/EHCI_MAX_UFRAMES; 27647c478bd9Sstevel@tonic-gate } 27657c478bd9Sstevel@tonic-gate 27667c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 27677c478bd9Sstevel@tonic-gate "ehci_adjust_high_speed_polling_interval: " 27687c478bd9Sstevel@tonic-gate "High speed adjusted interval 0x%x", interval); 27697c478bd9Sstevel@tonic-gate 27707c478bd9Sstevel@tonic-gate return (interval); 27717c478bd9Sstevel@tonic-gate } 27727c478bd9Sstevel@tonic-gate 27737c478bd9Sstevel@tonic-gate 27747c478bd9Sstevel@tonic-gate /* 27757c478bd9Sstevel@tonic-gate * ehci_lattice_height: 27767c478bd9Sstevel@tonic-gate * 27777c478bd9Sstevel@tonic-gate * Given the requested bandwidth, find the height in the tree at which the 27787c478bd9Sstevel@tonic-gate * nodes for this bandwidth fall. The height is measured as the number of 27797c478bd9Sstevel@tonic-gate * nodes from the leaf to the level specified by bandwidth The root of the 27807c478bd9Sstevel@tonic-gate * tree is at height TREE_HEIGHT. 27817c478bd9Sstevel@tonic-gate */ 27827c478bd9Sstevel@tonic-gate static uint_t 27837c478bd9Sstevel@tonic-gate ehci_lattice_height(uint_t interval) 27847c478bd9Sstevel@tonic-gate { 27857c478bd9Sstevel@tonic-gate return (TREE_HEIGHT - (ehci_log_2(interval))); 27867c478bd9Sstevel@tonic-gate } 27877c478bd9Sstevel@tonic-gate 27887c478bd9Sstevel@tonic-gate 27897c478bd9Sstevel@tonic-gate /* 27907c478bd9Sstevel@tonic-gate * ehci_lattice_parent: 27917c478bd9Sstevel@tonic-gate * 27927c478bd9Sstevel@tonic-gate * Given a node in the lattice, find the index of the parent node 27937c478bd9Sstevel@tonic-gate */ 27947c478bd9Sstevel@tonic-gate static uint_t 27957c478bd9Sstevel@tonic-gate ehci_lattice_parent(uint_t node) 27967c478bd9Sstevel@tonic-gate { 27977c478bd9Sstevel@tonic-gate if ((node % 2) == 0) { 27987c478bd9Sstevel@tonic-gate 27997c478bd9Sstevel@tonic-gate return ((node/2) - 1); 28007c478bd9Sstevel@tonic-gate } else { 28017c478bd9Sstevel@tonic-gate 28027c478bd9Sstevel@tonic-gate return ((node + 1)/2 - 1); 28037c478bd9Sstevel@tonic-gate } 28047c478bd9Sstevel@tonic-gate } 28057c478bd9Sstevel@tonic-gate 28067c478bd9Sstevel@tonic-gate 28077c478bd9Sstevel@tonic-gate /* 28087c478bd9Sstevel@tonic-gate * ehci_find_periodic_node: 28097c478bd9Sstevel@tonic-gate * 28107c478bd9Sstevel@tonic-gate * Based on the "real" array leaf node and interval, get the periodic node. 28117c478bd9Sstevel@tonic-gate */ 28127c478bd9Sstevel@tonic-gate static uint_t 28137c478bd9Sstevel@tonic-gate ehci_find_periodic_node(uint_t leaf, int interval) { 28147c478bd9Sstevel@tonic-gate uint_t lattice_leaf; 28157c478bd9Sstevel@tonic-gate uint_t height = ehci_lattice_height(interval); 28167c478bd9Sstevel@tonic-gate uint_t pnode; 28177c478bd9Sstevel@tonic-gate int i; 28187c478bd9Sstevel@tonic-gate 28197c478bd9Sstevel@tonic-gate /* Get the leaf number in the lattice */ 28207c478bd9Sstevel@tonic-gate lattice_leaf = leaf + EHCI_NUM_INTR_QH_LISTS - 1; 28217c478bd9Sstevel@tonic-gate 28227c478bd9Sstevel@tonic-gate /* Get the node in the lattice based on the height and leaf */ 28237c478bd9Sstevel@tonic-gate pnode = lattice_leaf; 28247c478bd9Sstevel@tonic-gate for (i = 0; i < height; i++) { 28257c478bd9Sstevel@tonic-gate pnode = ehci_lattice_parent(pnode); 28267c478bd9Sstevel@tonic-gate } 28277c478bd9Sstevel@tonic-gate 28287c478bd9Sstevel@tonic-gate return (pnode); 28297c478bd9Sstevel@tonic-gate } 28307c478bd9Sstevel@tonic-gate 28317c478bd9Sstevel@tonic-gate 28327c478bd9Sstevel@tonic-gate /* 28337c478bd9Sstevel@tonic-gate * ehci_leftmost_leaf: 28347c478bd9Sstevel@tonic-gate * 28357c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node. Height refers 28367c478bd9Sstevel@tonic-gate * to number of nodes from the bottom of the tree to the node, including the 28377c478bd9Sstevel@tonic-gate * node. 28387c478bd9Sstevel@tonic-gate * 28397c478bd9Sstevel@tonic-gate * The formula for a zero based tree is: 28407c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1 28417c478bd9Sstevel@tonic-gate * The leaf of the tree is an array, convert the number for the array. 28427c478bd9Sstevel@tonic-gate * Subtract the size of nodes not in the array 28437c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1 - (EHCI_NUM_INTR_QH_LISTS - 1) = 28447c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - EHCI_NUM_INTR_QH_LISTS = 28457c478bd9Sstevel@tonic-gate * 2^H * (Node + 1) - EHCI_NUM_INTR_QH_LISTS 28467c478bd9Sstevel@tonic-gate * 0 28477c478bd9Sstevel@tonic-gate * 1 2 28487c478bd9Sstevel@tonic-gate * 0 1 2 3 28497c478bd9Sstevel@tonic-gate */ 28507c478bd9Sstevel@tonic-gate static uint_t 28517c478bd9Sstevel@tonic-gate ehci_leftmost_leaf( 28527c478bd9Sstevel@tonic-gate uint_t node, 28537c478bd9Sstevel@tonic-gate uint_t height) 28547c478bd9Sstevel@tonic-gate { 28557c478bd9Sstevel@tonic-gate return ((ehci_pow_2(height) * (node + 1)) - EHCI_NUM_INTR_QH_LISTS); 28567c478bd9Sstevel@tonic-gate } 28577c478bd9Sstevel@tonic-gate 28587c478bd9Sstevel@tonic-gate 28597c478bd9Sstevel@tonic-gate /* 28607c478bd9Sstevel@tonic-gate * ehci_pow_2: 28617c478bd9Sstevel@tonic-gate * 28627c478bd9Sstevel@tonic-gate * Compute 2 to the power 28637c478bd9Sstevel@tonic-gate */ 28647c478bd9Sstevel@tonic-gate static uint_t 28657c478bd9Sstevel@tonic-gate ehci_pow_2(uint_t x) 28667c478bd9Sstevel@tonic-gate { 28677c478bd9Sstevel@tonic-gate if (x == 0) { 28687c478bd9Sstevel@tonic-gate 28697c478bd9Sstevel@tonic-gate return (1); 28707c478bd9Sstevel@tonic-gate } else { 28717c478bd9Sstevel@tonic-gate 28727c478bd9Sstevel@tonic-gate return (2 << (x - 1)); 28737c478bd9Sstevel@tonic-gate } 28747c478bd9Sstevel@tonic-gate } 28757c478bd9Sstevel@tonic-gate 28767c478bd9Sstevel@tonic-gate 28777c478bd9Sstevel@tonic-gate /* 28787c478bd9Sstevel@tonic-gate * ehci_log_2: 28797c478bd9Sstevel@tonic-gate * 28807c478bd9Sstevel@tonic-gate * Compute log base 2 of x 28817c478bd9Sstevel@tonic-gate */ 28827c478bd9Sstevel@tonic-gate static uint_t 28837c478bd9Sstevel@tonic-gate ehci_log_2(uint_t x) 28847c478bd9Sstevel@tonic-gate { 28857c478bd9Sstevel@tonic-gate int i = 0; 28867c478bd9Sstevel@tonic-gate 28877c478bd9Sstevel@tonic-gate while (x != 1) { 28887c478bd9Sstevel@tonic-gate x = x >> 1; 28897c478bd9Sstevel@tonic-gate i++; 28907c478bd9Sstevel@tonic-gate } 28917c478bd9Sstevel@tonic-gate 28927c478bd9Sstevel@tonic-gate return (i); 28937c478bd9Sstevel@tonic-gate } 28947c478bd9Sstevel@tonic-gate 28957c478bd9Sstevel@tonic-gate 28967c478bd9Sstevel@tonic-gate /* 28977c478bd9Sstevel@tonic-gate * ehci_find_bestfit_hs_mask: 28987c478bd9Sstevel@tonic-gate * 28997c478bd9Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation, and update the 29007c478bd9Sstevel@tonic-gate * bandwidth allocation. 29017c478bd9Sstevel@tonic-gate */ 29027c478bd9Sstevel@tonic-gate static int 29037c478bd9Sstevel@tonic-gate ehci_find_bestfit_hs_mask( 29047c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 29057c478bd9Sstevel@tonic-gate uchar_t *smask, 29067c478bd9Sstevel@tonic-gate uint_t *pnode, 29077c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 29087c478bd9Sstevel@tonic-gate uint_t bandwidth, 29097c478bd9Sstevel@tonic-gate int interval) 29107c478bd9Sstevel@tonic-gate { 29117c478bd9Sstevel@tonic-gate int i; 29127c478bd9Sstevel@tonic-gate uint_t elements, index; 29137c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 29147c478bd9Sstevel@tonic-gate uint_t node_bandwidth, best_node_bandwidth; 29157c478bd9Sstevel@tonic-gate uint_t leaf_count; 29167c478bd9Sstevel@tonic-gate uchar_t bw_mask; 29177c478bd9Sstevel@tonic-gate uchar_t best_smask; 29187c478bd9Sstevel@tonic-gate 29197c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 29207c478bd9Sstevel@tonic-gate "ehci_find_bestfit_hs_mask: "); 29217c478bd9Sstevel@tonic-gate 29227c478bd9Sstevel@tonic-gate /* Get all the valid smasks */ 29237c478bd9Sstevel@tonic-gate switch (ehci_pow_2(endpoint->bInterval - 1)) { 29247c478bd9Sstevel@tonic-gate case EHCI_INTR_1US_POLL: 29257c478bd9Sstevel@tonic-gate index = EHCI_1US_MASK_INDEX; 29267c478bd9Sstevel@tonic-gate elements = EHCI_INTR_1US_POLL; 29277c478bd9Sstevel@tonic-gate break; 29287c478bd9Sstevel@tonic-gate case EHCI_INTR_2US_POLL: 29297c478bd9Sstevel@tonic-gate index = EHCI_2US_MASK_INDEX; 29307c478bd9Sstevel@tonic-gate elements = EHCI_INTR_2US_POLL; 29317c478bd9Sstevel@tonic-gate break; 29327c478bd9Sstevel@tonic-gate case EHCI_INTR_4US_POLL: 29337c478bd9Sstevel@tonic-gate index = EHCI_4US_MASK_INDEX; 29347c478bd9Sstevel@tonic-gate elements = EHCI_INTR_4US_POLL; 29357c478bd9Sstevel@tonic-gate break; 29367c478bd9Sstevel@tonic-gate case EHCI_INTR_XUS_POLL: 29377c478bd9Sstevel@tonic-gate default: 29387c478bd9Sstevel@tonic-gate index = EHCI_XUS_MASK_INDEX; 29397c478bd9Sstevel@tonic-gate elements = EHCI_INTR_XUS_POLL; 29407c478bd9Sstevel@tonic-gate break; 29417c478bd9Sstevel@tonic-gate } 29427c478bd9Sstevel@tonic-gate 29437c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 29447c478bd9Sstevel@tonic-gate 29457c478bd9Sstevel@tonic-gate /* 29467c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 29477c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 29487c478bd9Sstevel@tonic-gate */ 29497c478bd9Sstevel@tonic-gate best_smask = 0x00; 29507c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 29517c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 29527c478bd9Sstevel@tonic-gate /* Find the bandwidth mask */ 29537c478bd9Sstevel@tonic-gate node_bandwidth = ehci_calculate_bw_availability_mask(ehcip, 29547c478bd9Sstevel@tonic-gate bandwidth, ehci_index[array_leaf], leaf_count, &bw_mask); 29557c478bd9Sstevel@tonic-gate 29567c478bd9Sstevel@tonic-gate /* 29577c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 29587c478bd9Sstevel@tonic-gate * next leaf. 29597c478bd9Sstevel@tonic-gate */ 29607c478bd9Sstevel@tonic-gate if (bw_mask == 0x00) { 29617c478bd9Sstevel@tonic-gate continue; 29627c478bd9Sstevel@tonic-gate } 29637c478bd9Sstevel@tonic-gate 29647c478bd9Sstevel@tonic-gate /* 29657c478bd9Sstevel@tonic-gate * Now make sure our bandwidth requirements can be 29667c478bd9Sstevel@tonic-gate * satisfied with one of smasks in this node. 29677c478bd9Sstevel@tonic-gate */ 29687c478bd9Sstevel@tonic-gate *smask = 0x00; 29697c478bd9Sstevel@tonic-gate for (i = index; i < (index + elements); i++) { 29707c478bd9Sstevel@tonic-gate /* Check the start split mask value */ 29717c478bd9Sstevel@tonic-gate if (ehci_start_split_mask[index] & bw_mask) { 29727c478bd9Sstevel@tonic-gate *smask = ehci_start_split_mask[index]; 29737c478bd9Sstevel@tonic-gate break; 29747c478bd9Sstevel@tonic-gate } 29757c478bd9Sstevel@tonic-gate } 29767c478bd9Sstevel@tonic-gate 29777c478bd9Sstevel@tonic-gate /* 29787c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 29797c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 29807c478bd9Sstevel@tonic-gate * - or - 29817c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 29827c478bd9Sstevel@tonic-gate */ 29837c478bd9Sstevel@tonic-gate if ((*smask != 0x00) && 29847c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 29857c478bd9Sstevel@tonic-gate (best_node_bandwidth > node_bandwidth))) { 29867c478bd9Sstevel@tonic-gate 29877c478bd9Sstevel@tonic-gate best_node_bandwidth = node_bandwidth; 29887c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 29897c478bd9Sstevel@tonic-gate best_smask = *smask; 29907c478bd9Sstevel@tonic-gate } 29917c478bd9Sstevel@tonic-gate } 29927c478bd9Sstevel@tonic-gate 29937c478bd9Sstevel@tonic-gate /* 29947c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 29957c478bd9Sstevel@tonic-gate * appropriate variables and return success. 29967c478bd9Sstevel@tonic-gate */ 29977c478bd9Sstevel@tonic-gate if (best_smask) { 29987c478bd9Sstevel@tonic-gate *smask = best_smask; 29997c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 30007c478bd9Sstevel@tonic-gate interval); 30017c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, bandwidth, 30027c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 30037c478bd9Sstevel@tonic-gate 30047c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 30057c478bd9Sstevel@tonic-gate } 30067c478bd9Sstevel@tonic-gate 30077c478bd9Sstevel@tonic-gate return (USB_FAILURE); 30087c478bd9Sstevel@tonic-gate } 30097c478bd9Sstevel@tonic-gate 30107c478bd9Sstevel@tonic-gate 30117c478bd9Sstevel@tonic-gate /* 30127c478bd9Sstevel@tonic-gate * ehci_find_bestfit_ls_intr_mask: 30137c478bd9Sstevel@tonic-gate * 30147c478bd9Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation. 30157c478bd9Sstevel@tonic-gate */ 30167c478bd9Sstevel@tonic-gate static int 30177c478bd9Sstevel@tonic-gate ehci_find_bestfit_ls_intr_mask( 30187c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 30197c478bd9Sstevel@tonic-gate uchar_t *smask, 30207c478bd9Sstevel@tonic-gate uchar_t *cmask, 30217c478bd9Sstevel@tonic-gate uint_t *pnode, 30227c478bd9Sstevel@tonic-gate uint_t sbandwidth, 30237c478bd9Sstevel@tonic-gate uint_t cbandwidth, 30247c478bd9Sstevel@tonic-gate int interval) 30257c478bd9Sstevel@tonic-gate { 30267c478bd9Sstevel@tonic-gate int i; 30277c478bd9Sstevel@tonic-gate uint_t elements, index; 30287c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 30297c478bd9Sstevel@tonic-gate uint_t node_sbandwidth, node_cbandwidth; 30307c478bd9Sstevel@tonic-gate uint_t best_node_bandwidth; 30317c478bd9Sstevel@tonic-gate uint_t leaf_count; 30327c478bd9Sstevel@tonic-gate uchar_t bw_smask, bw_cmask; 30337c478bd9Sstevel@tonic-gate uchar_t best_smask, best_cmask; 30347c478bd9Sstevel@tonic-gate 30357c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 30367c478bd9Sstevel@tonic-gate "ehci_find_bestfit_ls_intr_mask: "); 30377c478bd9Sstevel@tonic-gate 30387c478bd9Sstevel@tonic-gate /* For low and full speed devices */ 30397c478bd9Sstevel@tonic-gate index = EHCI_XUS_MASK_INDEX; 30407c478bd9Sstevel@tonic-gate elements = EHCI_INTR_4MS_POLL; 30417c478bd9Sstevel@tonic-gate 30427c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 30437c478bd9Sstevel@tonic-gate 30447c478bd9Sstevel@tonic-gate /* 30457c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 30467c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 30477c478bd9Sstevel@tonic-gate */ 30487c478bd9Sstevel@tonic-gate best_smask = 0x00; 30497c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 30507c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 30517c478bd9Sstevel@tonic-gate /* Find the bandwidth mask */ 30527c478bd9Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip, 30537c478bd9Sstevel@tonic-gate sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask); 30547c478bd9Sstevel@tonic-gate node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip, 30557c478bd9Sstevel@tonic-gate cbandwidth, ehci_index[array_leaf], leaf_count, &bw_cmask); 30567c478bd9Sstevel@tonic-gate 30577c478bd9Sstevel@tonic-gate /* 30587c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 30597c478bd9Sstevel@tonic-gate * next leaf. 30607c478bd9Sstevel@tonic-gate */ 30617c478bd9Sstevel@tonic-gate if ((bw_smask == 0x00) || (bw_cmask == 0x00)) { 30627c478bd9Sstevel@tonic-gate continue; 30637c478bd9Sstevel@tonic-gate } 30647c478bd9Sstevel@tonic-gate 30657c478bd9Sstevel@tonic-gate /* 30667c478bd9Sstevel@tonic-gate * Now make sure our bandwidth requirements can be 30677c478bd9Sstevel@tonic-gate * satisfied with one of smasks in this node. 30687c478bd9Sstevel@tonic-gate */ 30697c478bd9Sstevel@tonic-gate *smask = 0x00; 30707c478bd9Sstevel@tonic-gate *cmask = 0x00; 30717c478bd9Sstevel@tonic-gate for (i = index; i < (index + elements); i++) { 30727c478bd9Sstevel@tonic-gate /* Check the start split mask value */ 30737c478bd9Sstevel@tonic-gate if ((ehci_start_split_mask[index] & bw_smask) && 30747c478bd9Sstevel@tonic-gate (ehci_intr_complete_split_mask[index] & bw_cmask)) { 30757c478bd9Sstevel@tonic-gate *smask = ehci_start_split_mask[index]; 30767c478bd9Sstevel@tonic-gate *cmask = ehci_intr_complete_split_mask[index]; 30777c478bd9Sstevel@tonic-gate break; 30787c478bd9Sstevel@tonic-gate } 30797c478bd9Sstevel@tonic-gate } 30807c478bd9Sstevel@tonic-gate 30817c478bd9Sstevel@tonic-gate /* 30827c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 30837c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 30847c478bd9Sstevel@tonic-gate * - or - 30857c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 30867c478bd9Sstevel@tonic-gate */ 30877c478bd9Sstevel@tonic-gate if ((*smask != 0x00) && 30887c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 30897c478bd9Sstevel@tonic-gate (best_node_bandwidth > 30907c478bd9Sstevel@tonic-gate (node_sbandwidth + node_cbandwidth)))) { 30917c478bd9Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth + node_cbandwidth; 30927c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 30937c478bd9Sstevel@tonic-gate best_smask = *smask; 30947c478bd9Sstevel@tonic-gate best_cmask = *cmask; 30957c478bd9Sstevel@tonic-gate } 30967c478bd9Sstevel@tonic-gate } 30977c478bd9Sstevel@tonic-gate 30987c478bd9Sstevel@tonic-gate /* 30997c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 31007c478bd9Sstevel@tonic-gate * appropriate variables and return success. 31017c478bd9Sstevel@tonic-gate */ 31027c478bd9Sstevel@tonic-gate if (best_smask) { 31037c478bd9Sstevel@tonic-gate *smask = best_smask; 31047c478bd9Sstevel@tonic-gate *cmask = best_cmask; 31057c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 31067c478bd9Sstevel@tonic-gate interval); 31077c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, sbandwidth, 31087c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 31097c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, cbandwidth, 31107c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_cmask); 31117c478bd9Sstevel@tonic-gate 31127c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 31137c478bd9Sstevel@tonic-gate } 31147c478bd9Sstevel@tonic-gate 31157c478bd9Sstevel@tonic-gate return (USB_FAILURE); 31167c478bd9Sstevel@tonic-gate } 31177c478bd9Sstevel@tonic-gate 31187c478bd9Sstevel@tonic-gate 31197c478bd9Sstevel@tonic-gate /* 31207c478bd9Sstevel@tonic-gate * ehci_find_bestfit_sitd_in_mask: 31217c478bd9Sstevel@tonic-gate * 31227c478bd9Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation. 31237c478bd9Sstevel@tonic-gate */ 31247c478bd9Sstevel@tonic-gate static int 31257c478bd9Sstevel@tonic-gate ehci_find_bestfit_sitd_in_mask( 31267c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 31277c478bd9Sstevel@tonic-gate uchar_t *smask, 31287c478bd9Sstevel@tonic-gate uchar_t *cmask, 31297c478bd9Sstevel@tonic-gate uint_t *pnode, 31307c478bd9Sstevel@tonic-gate uint_t sbandwidth, 31317c478bd9Sstevel@tonic-gate uint_t cbandwidth, 31327c478bd9Sstevel@tonic-gate int interval) 31337c478bd9Sstevel@tonic-gate { 31347c478bd9Sstevel@tonic-gate int i, uFrames, found; 31357c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 31367c478bd9Sstevel@tonic-gate uint_t node_sbandwidth, node_cbandwidth; 31377c478bd9Sstevel@tonic-gate uint_t best_node_bandwidth; 31387c478bd9Sstevel@tonic-gate uint_t leaf_count; 31397c478bd9Sstevel@tonic-gate uchar_t bw_smask, bw_cmask; 31407c478bd9Sstevel@tonic-gate uchar_t best_smask, best_cmask; 31417c478bd9Sstevel@tonic-gate 31427c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 31437c478bd9Sstevel@tonic-gate "ehci_find_bestfit_sitd_in_mask: "); 31447c478bd9Sstevel@tonic-gate 31457c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 31467c478bd9Sstevel@tonic-gate 31477c478bd9Sstevel@tonic-gate /* 31487c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 31497c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 31507c478bd9Sstevel@tonic-gate * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame. 31517c478bd9Sstevel@tonic-gate */ 31527c478bd9Sstevel@tonic-gate /* 31537c478bd9Sstevel@tonic-gate * Need to add an additional 2 uFrames, if the "L"ast 31547c478bd9Sstevel@tonic-gate * complete split is before uFrame 6. See section 31557c478bd9Sstevel@tonic-gate * 11.8.4 in USB 2.0 Spec. Currently we do not support 31567c478bd9Sstevel@tonic-gate * the "Back Ptr" which means we support on IN of 31577c478bd9Sstevel@tonic-gate * ~4*MAX_UFRAME_SITD_XFER bandwidth/ 31587c478bd9Sstevel@tonic-gate */ 31597c478bd9Sstevel@tonic-gate uFrames = (cbandwidth / MAX_UFRAME_SITD_XFER) + 2; 31607c478bd9Sstevel@tonic-gate if (cbandwidth % MAX_UFRAME_SITD_XFER) { 31617c478bd9Sstevel@tonic-gate uFrames++; 31627c478bd9Sstevel@tonic-gate } 31637c478bd9Sstevel@tonic-gate if (uFrames > 6) { 31647c478bd9Sstevel@tonic-gate 31657c478bd9Sstevel@tonic-gate return (USB_FAILURE); 31667c478bd9Sstevel@tonic-gate } 31677c478bd9Sstevel@tonic-gate *smask = 0x1; 31687c478bd9Sstevel@tonic-gate *cmask = 0x00; 31697c478bd9Sstevel@tonic-gate for (i = 0; i < uFrames; i++) { 31707c478bd9Sstevel@tonic-gate *cmask = *cmask << 1; 31717c478bd9Sstevel@tonic-gate *cmask |= 0x1; 31727c478bd9Sstevel@tonic-gate } 31737c478bd9Sstevel@tonic-gate /* cmask must start 2 frames after the smask */ 31747c478bd9Sstevel@tonic-gate *cmask = *cmask << 2; 31757c478bd9Sstevel@tonic-gate 31767c478bd9Sstevel@tonic-gate found = 0; 31777c478bd9Sstevel@tonic-gate best_smask = 0x00; 31787c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 31797c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 31807c478bd9Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip, 31817c478bd9Sstevel@tonic-gate sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask); 31827c478bd9Sstevel@tonic-gate node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip, 31837c478bd9Sstevel@tonic-gate MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count, 31847c478bd9Sstevel@tonic-gate &bw_cmask); 31857c478bd9Sstevel@tonic-gate 31867c478bd9Sstevel@tonic-gate /* 31877c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 31887c478bd9Sstevel@tonic-gate * next leaf. 31897c478bd9Sstevel@tonic-gate */ 31907c478bd9Sstevel@tonic-gate if ((bw_smask == 0x00) || (bw_cmask == 0x00)) { 31917c478bd9Sstevel@tonic-gate continue; 31927c478bd9Sstevel@tonic-gate } 31937c478bd9Sstevel@tonic-gate 31947c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_MAX_UFRAMES - uFrames - 2); i++) { 31957c478bd9Sstevel@tonic-gate if ((*smask & bw_smask) && (*cmask & bw_cmask)) { 31967c478bd9Sstevel@tonic-gate found = 1; 31977c478bd9Sstevel@tonic-gate break; 31987c478bd9Sstevel@tonic-gate } 31997c478bd9Sstevel@tonic-gate *smask = *smask << 1; 32007c478bd9Sstevel@tonic-gate *cmask = *cmask << 1; 32017c478bd9Sstevel@tonic-gate } 32027c478bd9Sstevel@tonic-gate 32037c478bd9Sstevel@tonic-gate /* 32047c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 32057c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 32067c478bd9Sstevel@tonic-gate * - or - 32077c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 32087c478bd9Sstevel@tonic-gate */ 32097c478bd9Sstevel@tonic-gate if (found && 32107c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 32117c478bd9Sstevel@tonic-gate (best_node_bandwidth > 32127c478bd9Sstevel@tonic-gate (node_sbandwidth + node_cbandwidth)))) { 32137c478bd9Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth + node_cbandwidth; 32147c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 32157c478bd9Sstevel@tonic-gate best_smask = *smask; 32167c478bd9Sstevel@tonic-gate best_cmask = *cmask; 32177c478bd9Sstevel@tonic-gate } 32187c478bd9Sstevel@tonic-gate } 32197c478bd9Sstevel@tonic-gate 32207c478bd9Sstevel@tonic-gate /* 32217c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 32227c478bd9Sstevel@tonic-gate * appropriate variables and return success. 32237c478bd9Sstevel@tonic-gate */ 32247c478bd9Sstevel@tonic-gate if (best_smask) { 32257c478bd9Sstevel@tonic-gate *smask = best_smask; 32267c478bd9Sstevel@tonic-gate *cmask = best_cmask; 32277c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 32287c478bd9Sstevel@tonic-gate interval); 32297c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, sbandwidth, 32307c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 32317c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER, 32327c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_cmask); 32337c478bd9Sstevel@tonic-gate 32347c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 32357c478bd9Sstevel@tonic-gate } 32367c478bd9Sstevel@tonic-gate 32377c478bd9Sstevel@tonic-gate return (USB_FAILURE); 32387c478bd9Sstevel@tonic-gate } 32397c478bd9Sstevel@tonic-gate 32407c478bd9Sstevel@tonic-gate 32417c478bd9Sstevel@tonic-gate /* 32427c478bd9Sstevel@tonic-gate * ehci_find_bestfit_sitd_out_mask: 32437c478bd9Sstevel@tonic-gate * 32447c478bd9Sstevel@tonic-gate * Find the smask in the bandwidth allocation. 32457c478bd9Sstevel@tonic-gate */ 32467c478bd9Sstevel@tonic-gate static int 32477c478bd9Sstevel@tonic-gate ehci_find_bestfit_sitd_out_mask( 32487c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 32497c478bd9Sstevel@tonic-gate uchar_t *smask, 32507c478bd9Sstevel@tonic-gate uint_t *pnode, 32517c478bd9Sstevel@tonic-gate uint_t sbandwidth, 32527c478bd9Sstevel@tonic-gate int interval) 32537c478bd9Sstevel@tonic-gate { 32547c478bd9Sstevel@tonic-gate int i, uFrames, found; 32557c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 32567c478bd9Sstevel@tonic-gate uint_t node_sbandwidth; 32577c478bd9Sstevel@tonic-gate uint_t best_node_bandwidth; 32587c478bd9Sstevel@tonic-gate uint_t leaf_count; 32597c478bd9Sstevel@tonic-gate uchar_t bw_smask; 32607c478bd9Sstevel@tonic-gate uchar_t best_smask; 32617c478bd9Sstevel@tonic-gate 32627c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 32637c478bd9Sstevel@tonic-gate "ehci_find_bestfit_sitd_out_mask: "); 32647c478bd9Sstevel@tonic-gate 32657c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 32667c478bd9Sstevel@tonic-gate 32677c478bd9Sstevel@tonic-gate /* 32687c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 32697c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 32707c478bd9Sstevel@tonic-gate * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame. 32717c478bd9Sstevel@tonic-gate */ 32727c478bd9Sstevel@tonic-gate *smask = 0x00; 32737c478bd9Sstevel@tonic-gate uFrames = sbandwidth / MAX_UFRAME_SITD_XFER; 32747c478bd9Sstevel@tonic-gate if (sbandwidth % MAX_UFRAME_SITD_XFER) { 32757c478bd9Sstevel@tonic-gate uFrames++; 32767c478bd9Sstevel@tonic-gate } 32777c478bd9Sstevel@tonic-gate for (i = 0; i < uFrames; i++) { 32787c478bd9Sstevel@tonic-gate *smask = *smask << 1; 32797c478bd9Sstevel@tonic-gate *smask |= 0x1; 32807c478bd9Sstevel@tonic-gate } 32817c478bd9Sstevel@tonic-gate 32827c478bd9Sstevel@tonic-gate found = 0; 32837c478bd9Sstevel@tonic-gate best_smask = 0x00; 32847c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 32857c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 32867c478bd9Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip, 32877c478bd9Sstevel@tonic-gate MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count, 32887c478bd9Sstevel@tonic-gate &bw_smask); 32897c478bd9Sstevel@tonic-gate 32907c478bd9Sstevel@tonic-gate /* 32917c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 32927c478bd9Sstevel@tonic-gate * next leaf. 32937c478bd9Sstevel@tonic-gate */ 32947c478bd9Sstevel@tonic-gate if (bw_smask == 0x00) { 32957c478bd9Sstevel@tonic-gate continue; 32967c478bd9Sstevel@tonic-gate } 32977c478bd9Sstevel@tonic-gate 32987c478bd9Sstevel@tonic-gate /* You cannot have a start split on the 8th uFrame */ 32997c478bd9Sstevel@tonic-gate for (i = 0; (*smask & 0x80) == 0; i++) { 33007c478bd9Sstevel@tonic-gate if (*smask & bw_smask) { 33017c478bd9Sstevel@tonic-gate found = 1; 33027c478bd9Sstevel@tonic-gate break; 33037c478bd9Sstevel@tonic-gate } 33047c478bd9Sstevel@tonic-gate *smask = *smask << 1; 33057c478bd9Sstevel@tonic-gate } 33067c478bd9Sstevel@tonic-gate 33077c478bd9Sstevel@tonic-gate /* 33087c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 33097c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 33107c478bd9Sstevel@tonic-gate * - or - 33117c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 33127c478bd9Sstevel@tonic-gate */ 33137c478bd9Sstevel@tonic-gate if (found && 33147c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 33157c478bd9Sstevel@tonic-gate (best_node_bandwidth > node_sbandwidth))) { 33167c478bd9Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth; 33177c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 33187c478bd9Sstevel@tonic-gate best_smask = *smask; 33197c478bd9Sstevel@tonic-gate } 33207c478bd9Sstevel@tonic-gate } 33217c478bd9Sstevel@tonic-gate 33227c478bd9Sstevel@tonic-gate /* 33237c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 33247c478bd9Sstevel@tonic-gate * appropriate variables and return success. 33257c478bd9Sstevel@tonic-gate */ 33267c478bd9Sstevel@tonic-gate if (best_smask) { 33277c478bd9Sstevel@tonic-gate *smask = best_smask; 33287c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 33297c478bd9Sstevel@tonic-gate interval); 33307c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER, 33317c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 33327c478bd9Sstevel@tonic-gate 33337c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 33347c478bd9Sstevel@tonic-gate } 33357c478bd9Sstevel@tonic-gate 33367c478bd9Sstevel@tonic-gate return (USB_FAILURE); 33377c478bd9Sstevel@tonic-gate } 33387c478bd9Sstevel@tonic-gate 33397c478bd9Sstevel@tonic-gate 33407c478bd9Sstevel@tonic-gate /* 33417c478bd9Sstevel@tonic-gate * ehci_calculate_bw_availability_mask: 33427c478bd9Sstevel@tonic-gate * 33437c478bd9Sstevel@tonic-gate * Returns the "total bandwidth used" in this node. 33447c478bd9Sstevel@tonic-gate * Populates bw_mask with the uFrames that can support the bandwidth. 33457c478bd9Sstevel@tonic-gate * 33467c478bd9Sstevel@tonic-gate * If all the Frames cannot support this bandwidth, then bw_mask 33477c478bd9Sstevel@tonic-gate * will return 0x00 and the "total bandwidth used" will be invalid. 33487c478bd9Sstevel@tonic-gate */ 33497c478bd9Sstevel@tonic-gate static uint_t 33507c478bd9Sstevel@tonic-gate ehci_calculate_bw_availability_mask( 33517c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 33527c478bd9Sstevel@tonic-gate uint_t bandwidth, 33537c478bd9Sstevel@tonic-gate int leaf, 33547c478bd9Sstevel@tonic-gate int leaf_count, 33557c478bd9Sstevel@tonic-gate uchar_t *bw_mask) 33567c478bd9Sstevel@tonic-gate { 33577c478bd9Sstevel@tonic-gate int i, j; 33587c478bd9Sstevel@tonic-gate uchar_t bw_uframe; 33597c478bd9Sstevel@tonic-gate int uframe_total; 33607c478bd9Sstevel@tonic-gate ehci_frame_bandwidth_t *fbp; 33617c478bd9Sstevel@tonic-gate uint_t total_bandwidth = 0; 33627c478bd9Sstevel@tonic-gate 33637c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 33647c478bd9Sstevel@tonic-gate "ehci_calculate_bw_availability_mask: leaf %d leaf count %d", 33657c478bd9Sstevel@tonic-gate leaf, leaf_count); 33667c478bd9Sstevel@tonic-gate 33677c478bd9Sstevel@tonic-gate /* Start by saying all uFrames are available */ 33687c478bd9Sstevel@tonic-gate *bw_mask = 0xFF; 33697c478bd9Sstevel@tonic-gate 33707c478bd9Sstevel@tonic-gate for (i = 0; (i < leaf_count) || (*bw_mask == 0x00); i++) { 33717c478bd9Sstevel@tonic-gate fbp = &ehcip->ehci_frame_bandwidth[leaf + i]; 33727c478bd9Sstevel@tonic-gate 33737c478bd9Sstevel@tonic-gate total_bandwidth += fbp->ehci_allocated_frame_bandwidth; 33747c478bd9Sstevel@tonic-gate 33757c478bd9Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) { 33767c478bd9Sstevel@tonic-gate /* 33777c478bd9Sstevel@tonic-gate * If the uFrame in bw_mask is available check to see if 33787c478bd9Sstevel@tonic-gate * it can support the additional bandwidth. 33797c478bd9Sstevel@tonic-gate */ 33807c478bd9Sstevel@tonic-gate bw_uframe = (*bw_mask & (0x1 << j)); 33817c478bd9Sstevel@tonic-gate uframe_total = 33827c478bd9Sstevel@tonic-gate fbp->ehci_micro_frame_bandwidth[j] + 33837c478bd9Sstevel@tonic-gate bandwidth; 33847c478bd9Sstevel@tonic-gate if ((bw_uframe) && 33857c478bd9Sstevel@tonic-gate (uframe_total > HS_PERIODIC_BANDWIDTH)) { 33867c478bd9Sstevel@tonic-gate *bw_mask = *bw_mask & ~bw_uframe; 33877c478bd9Sstevel@tonic-gate } 33887c478bd9Sstevel@tonic-gate } 33897c478bd9Sstevel@tonic-gate } 33907c478bd9Sstevel@tonic-gate 33917c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 33927c478bd9Sstevel@tonic-gate "ehci_calculate_bw_availability_mask: bandwidth mask 0x%x", 33937c478bd9Sstevel@tonic-gate *bw_mask); 33947c478bd9Sstevel@tonic-gate 33957c478bd9Sstevel@tonic-gate return (total_bandwidth); 33967c478bd9Sstevel@tonic-gate } 33977c478bd9Sstevel@tonic-gate 33987c478bd9Sstevel@tonic-gate 33997c478bd9Sstevel@tonic-gate /* 34007c478bd9Sstevel@tonic-gate * ehci_update_bw_availability: 34017c478bd9Sstevel@tonic-gate * 34027c478bd9Sstevel@tonic-gate * The leftmost leaf needs to be in terms of array position and 34037c478bd9Sstevel@tonic-gate * not the actual lattice position. 34047c478bd9Sstevel@tonic-gate */ 34057c478bd9Sstevel@tonic-gate static void 34067c478bd9Sstevel@tonic-gate ehci_update_bw_availability( 34077c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 34087c478bd9Sstevel@tonic-gate int bandwidth, 34097c478bd9Sstevel@tonic-gate int leftmost_leaf, 34107c478bd9Sstevel@tonic-gate int leaf_count, 34117c478bd9Sstevel@tonic-gate uchar_t mask) 34127c478bd9Sstevel@tonic-gate { 34137c478bd9Sstevel@tonic-gate int i, j; 34147c478bd9Sstevel@tonic-gate ehci_frame_bandwidth_t *fbp; 34157c478bd9Sstevel@tonic-gate int uFrame_bandwidth[8]; 34167c478bd9Sstevel@tonic-gate 34177c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 34187c478bd9Sstevel@tonic-gate "ehci_update_bw_availability: " 34197c478bd9Sstevel@tonic-gate "leaf %d count %d bandwidth 0x%x mask 0x%x", 34207c478bd9Sstevel@tonic-gate leftmost_leaf, leaf_count, bandwidth, mask); 34217c478bd9Sstevel@tonic-gate 34227c478bd9Sstevel@tonic-gate ASSERT(leftmost_leaf < 32); 34237c478bd9Sstevel@tonic-gate ASSERT(leftmost_leaf >= 0); 34247c478bd9Sstevel@tonic-gate 34257c478bd9Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) { 34267c478bd9Sstevel@tonic-gate if (mask & 0x1) { 34277c478bd9Sstevel@tonic-gate uFrame_bandwidth[j] = bandwidth; 34287c478bd9Sstevel@tonic-gate } else { 34297c478bd9Sstevel@tonic-gate uFrame_bandwidth[j] = 0; 34307c478bd9Sstevel@tonic-gate } 34317c478bd9Sstevel@tonic-gate 34327c478bd9Sstevel@tonic-gate mask = mask >> 1; 34337c478bd9Sstevel@tonic-gate } 34347c478bd9Sstevel@tonic-gate 34357c478bd9Sstevel@tonic-gate /* Updated all the effected leafs with the bandwidth */ 34367c478bd9Sstevel@tonic-gate for (i = 0; i < leaf_count; i++) { 34377c478bd9Sstevel@tonic-gate fbp = &ehcip->ehci_frame_bandwidth[leftmost_leaf + i]; 34387c478bd9Sstevel@tonic-gate 34397c478bd9Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) { 34407c478bd9Sstevel@tonic-gate fbp->ehci_micro_frame_bandwidth[j] += 34417c478bd9Sstevel@tonic-gate uFrame_bandwidth[j]; 34427c478bd9Sstevel@tonic-gate fbp->ehci_allocated_frame_bandwidth += 34437c478bd9Sstevel@tonic-gate uFrame_bandwidth[j]; 34447c478bd9Sstevel@tonic-gate } 34457c478bd9Sstevel@tonic-gate } 34467c478bd9Sstevel@tonic-gate } 34477c478bd9Sstevel@tonic-gate 34487c478bd9Sstevel@tonic-gate /* 34497c478bd9Sstevel@tonic-gate * Miscellaneous functions 34507c478bd9Sstevel@tonic-gate */ 34517c478bd9Sstevel@tonic-gate 34527c478bd9Sstevel@tonic-gate /* 34537c478bd9Sstevel@tonic-gate * ehci_obtain_state: 34547c478bd9Sstevel@tonic-gate * 34557c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 34567c478bd9Sstevel@tonic-gate */ 34577c478bd9Sstevel@tonic-gate ehci_state_t * 34587c478bd9Sstevel@tonic-gate ehci_obtain_state(dev_info_t *dip) 34597c478bd9Sstevel@tonic-gate { 34607c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 34617c478bd9Sstevel@tonic-gate 34627c478bd9Sstevel@tonic-gate ehci_state_t *state = ddi_get_soft_state(ehci_statep, instance); 34637c478bd9Sstevel@tonic-gate 34647c478bd9Sstevel@tonic-gate ASSERT(state != NULL); 34657c478bd9Sstevel@tonic-gate 34667c478bd9Sstevel@tonic-gate return (state); 34677c478bd9Sstevel@tonic-gate } 34687c478bd9Sstevel@tonic-gate 34697c478bd9Sstevel@tonic-gate 34707c478bd9Sstevel@tonic-gate /* 34717c478bd9Sstevel@tonic-gate * ehci_state_is_operational: 34727c478bd9Sstevel@tonic-gate * 34737c478bd9Sstevel@tonic-gate * Check the Host controller state and return proper values. 34747c478bd9Sstevel@tonic-gate */ 34757c478bd9Sstevel@tonic-gate int 34767c478bd9Sstevel@tonic-gate ehci_state_is_operational(ehci_state_t *ehcip) 34777c478bd9Sstevel@tonic-gate { 34787c478bd9Sstevel@tonic-gate int val; 34797c478bd9Sstevel@tonic-gate 34807c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 34817c478bd9Sstevel@tonic-gate 34827c478bd9Sstevel@tonic-gate switch (ehcip->ehci_hc_soft_state) { 34837c478bd9Sstevel@tonic-gate case EHCI_CTLR_INIT_STATE: 34847c478bd9Sstevel@tonic-gate case EHCI_CTLR_SUSPEND_STATE: 34857c478bd9Sstevel@tonic-gate val = USB_FAILURE; 34867c478bd9Sstevel@tonic-gate break; 34877c478bd9Sstevel@tonic-gate case EHCI_CTLR_OPERATIONAL_STATE: 34887c478bd9Sstevel@tonic-gate val = USB_SUCCESS; 34897c478bd9Sstevel@tonic-gate break; 34907c478bd9Sstevel@tonic-gate case EHCI_CTLR_ERROR_STATE: 34917c478bd9Sstevel@tonic-gate val = USB_HC_HARDWARE_ERROR; 34927c478bd9Sstevel@tonic-gate break; 34937c478bd9Sstevel@tonic-gate default: 34947c478bd9Sstevel@tonic-gate val = USB_FAILURE; 34957c478bd9Sstevel@tonic-gate break; 34967c478bd9Sstevel@tonic-gate } 34977c478bd9Sstevel@tonic-gate 34987c478bd9Sstevel@tonic-gate return (val); 34997c478bd9Sstevel@tonic-gate } 35007c478bd9Sstevel@tonic-gate 35017c478bd9Sstevel@tonic-gate 35027c478bd9Sstevel@tonic-gate /* 35037c478bd9Sstevel@tonic-gate * ehci_do_soft_reset 35047c478bd9Sstevel@tonic-gate * 35057c478bd9Sstevel@tonic-gate * Do soft reset of ehci host controller. 35067c478bd9Sstevel@tonic-gate */ 35077c478bd9Sstevel@tonic-gate int 35087c478bd9Sstevel@tonic-gate ehci_do_soft_reset(ehci_state_t *ehcip) 35097c478bd9Sstevel@tonic-gate { 35107c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 35117c478bd9Sstevel@tonic-gate ehci_regs_t *ehci_save_regs; 35127c478bd9Sstevel@tonic-gate 35137c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 35147c478bd9Sstevel@tonic-gate 35157c478bd9Sstevel@tonic-gate /* Increment host controller error count */ 35167c478bd9Sstevel@tonic-gate ehcip->ehci_hc_error++; 35177c478bd9Sstevel@tonic-gate 35187c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 35197c478bd9Sstevel@tonic-gate "ehci_do_soft_reset:" 35207c478bd9Sstevel@tonic-gate "Reset ehci host controller 0x%x", ehcip->ehci_hc_error); 35217c478bd9Sstevel@tonic-gate 35227c478bd9Sstevel@tonic-gate /* 35237c478bd9Sstevel@tonic-gate * Allocate space for saving current Host Controller 35247c478bd9Sstevel@tonic-gate * registers. Don't do any recovery if allocation 35257c478bd9Sstevel@tonic-gate * fails. 35267c478bd9Sstevel@tonic-gate */ 35277c478bd9Sstevel@tonic-gate ehci_save_regs = (ehci_regs_t *) 35287c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (ehci_regs_t), KM_NOSLEEP); 35297c478bd9Sstevel@tonic-gate 35307c478bd9Sstevel@tonic-gate if (ehci_save_regs == NULL) { 35317c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 35327c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: kmem_zalloc failed"); 35337c478bd9Sstevel@tonic-gate 35347c478bd9Sstevel@tonic-gate return (USB_FAILURE); 35357c478bd9Sstevel@tonic-gate } 35367c478bd9Sstevel@tonic-gate 35377c478bd9Sstevel@tonic-gate /* Save current ehci registers */ 35387c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_command = Get_OpReg(ehci_command); 35397c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_interrupt = Get_OpReg(ehci_interrupt); 35407c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_ctrl_segment = Get_OpReg(ehci_ctrl_segment); 35417c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_async_list_addr = Get_OpReg(ehci_async_list_addr); 35427c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_config_flag = Get_OpReg(ehci_config_flag); 35437c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_periodic_list_base = 35447c478bd9Sstevel@tonic-gate Get_OpReg(ehci_periodic_list_base); 35457c478bd9Sstevel@tonic-gate 35467c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 35477c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Save reg = 0x%p", ehci_save_regs); 35487c478bd9Sstevel@tonic-gate 35497c478bd9Sstevel@tonic-gate /* Disable all list processing and interrupts */ 35507c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, Get_OpReg(ehci_command) & 35517c478bd9Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE)); 35527c478bd9Sstevel@tonic-gate 35537c478bd9Sstevel@tonic-gate /* Disable all EHCI interrupts */ 35547c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0); 35557c478bd9Sstevel@tonic-gate 35567c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 35577c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_SOF_TIMEWAIT); 35587c478bd9Sstevel@tonic-gate 35597c478bd9Sstevel@tonic-gate /* Do light soft reset of ehci host controller */ 35607c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 35617c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) | EHCI_CMD_LIGHT_HC_RESET); 35627c478bd9Sstevel@tonic-gate 35637c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 35647c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Reset in progress"); 35657c478bd9Sstevel@tonic-gate 35667c478bd9Sstevel@tonic-gate /* Wait for reset to complete */ 35677c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT); 35687c478bd9Sstevel@tonic-gate 35697c478bd9Sstevel@tonic-gate /* 35707c478bd9Sstevel@tonic-gate * Restore previous saved EHCI register value 35717c478bd9Sstevel@tonic-gate * into the current EHCI registers. 35727c478bd9Sstevel@tonic-gate */ 35737c478bd9Sstevel@tonic-gate Set_OpReg(ehci_ctrl_segment, (uint32_t) 35747c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_ctrl_segment); 35757c478bd9Sstevel@tonic-gate 35767c478bd9Sstevel@tonic-gate Set_OpReg(ehci_periodic_list_base, (uint32_t) 35777c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_periodic_list_base); 35787c478bd9Sstevel@tonic-gate 35797c478bd9Sstevel@tonic-gate Set_OpReg(ehci_async_list_addr, (uint32_t) 35807c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_async_list_addr); 35817c478bd9Sstevel@tonic-gate 35827c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, (uint32_t) 35837c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_config_flag); 35847c478bd9Sstevel@tonic-gate 35857c478bd9Sstevel@tonic-gate /* Enable both Asynchronous and Periodic Schedule if necessary */ 35867c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehcip); 35877c478bd9Sstevel@tonic-gate 35887c478bd9Sstevel@tonic-gate /* 35897c478bd9Sstevel@tonic-gate * Set ehci_interrupt to enable all interrupts except Root 35907c478bd9Sstevel@tonic-gate * Hub Status change and frame list rollover interrupts. 35917c478bd9Sstevel@tonic-gate */ 35927c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR | 35937c478bd9Sstevel@tonic-gate EHCI_INTR_FRAME_LIST_ROLLOVER | 35947c478bd9Sstevel@tonic-gate EHCI_INTR_USB_ERROR | 35957c478bd9Sstevel@tonic-gate EHCI_INTR_USB); 35967c478bd9Sstevel@tonic-gate 35977c478bd9Sstevel@tonic-gate /* 35987c478bd9Sstevel@tonic-gate * Deallocate the space that allocated for saving 35997c478bd9Sstevel@tonic-gate * HC registers. 36007c478bd9Sstevel@tonic-gate */ 36017c478bd9Sstevel@tonic-gate kmem_free((void *) ehci_save_regs, sizeof (ehci_regs_t)); 36027c478bd9Sstevel@tonic-gate 36037c478bd9Sstevel@tonic-gate /* 36047c478bd9Sstevel@tonic-gate * Set the desired interrupt threshold, frame list size (if 36057c478bd9Sstevel@tonic-gate * applicable) and turn EHCI host controller. 36067c478bd9Sstevel@tonic-gate */ 36077c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, ((Get_OpReg(ehci_command) & 36087c478bd9Sstevel@tonic-gate ~EHCI_CMD_INTR_THRESHOLD) | 36097c478bd9Sstevel@tonic-gate (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN))); 36107c478bd9Sstevel@tonic-gate 36117c478bd9Sstevel@tonic-gate /* Wait 10ms for EHCI to start sending SOF */ 36127c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT); 36137c478bd9Sstevel@tonic-gate 36147c478bd9Sstevel@tonic-gate /* 36157c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for 36167c478bd9Sstevel@tonic-gate * few milliseconds. 36177c478bd9Sstevel@tonic-gate */ 36187c478bd9Sstevel@tonic-gate before_frame_number = ehci_get_current_frame_number(ehcip); 36197c478bd9Sstevel@tonic-gate 36207c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 36217c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_SOF_TIMEWAIT); 36227c478bd9Sstevel@tonic-gate 36237c478bd9Sstevel@tonic-gate /* 36247c478bd9Sstevel@tonic-gate * Get the current usb frame number after waiting for 36257c478bd9Sstevel@tonic-gate * few milliseconds. 36267c478bd9Sstevel@tonic-gate */ 36277c478bd9Sstevel@tonic-gate after_frame_number = ehci_get_current_frame_number(ehcip); 36287c478bd9Sstevel@tonic-gate 36297c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 36307c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Before Frame Number 0x%llx " 36317c478bd9Sstevel@tonic-gate "After Frame Number 0x%llx", 36327c478bd9Sstevel@tonic-gate before_frame_number, after_frame_number); 36337c478bd9Sstevel@tonic-gate 36347c478bd9Sstevel@tonic-gate if ((after_frame_number <= before_frame_number) && 36357c478bd9Sstevel@tonic-gate (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) { 36367c478bd9Sstevel@tonic-gate 36377c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 36387c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Soft reset failed"); 36397c478bd9Sstevel@tonic-gate 36407c478bd9Sstevel@tonic-gate return (USB_FAILURE); 36417c478bd9Sstevel@tonic-gate } 36427c478bd9Sstevel@tonic-gate 36437c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 36447c478bd9Sstevel@tonic-gate } 36457c478bd9Sstevel@tonic-gate 36467c478bd9Sstevel@tonic-gate 36477c478bd9Sstevel@tonic-gate /* 36487c478bd9Sstevel@tonic-gate * ehci_get_xfer_attrs: 36497c478bd9Sstevel@tonic-gate * 36507c478bd9Sstevel@tonic-gate * Get the attributes of a particular xfer. 36517c478bd9Sstevel@tonic-gate * 36527c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 36537c478bd9Sstevel@tonic-gate */ 36547c478bd9Sstevel@tonic-gate usb_req_attrs_t 36557c478bd9Sstevel@tonic-gate ehci_get_xfer_attrs( 36567c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 36577c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 36587c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 36597c478bd9Sstevel@tonic-gate { 36607c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep; 36617c478bd9Sstevel@tonic-gate usb_req_attrs_t attrs = USB_ATTRS_NONE; 36627c478bd9Sstevel@tonic-gate 36637c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 36647c478bd9Sstevel@tonic-gate "ehci_get_xfer_attrs:"); 36657c478bd9Sstevel@tonic-gate 36667c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 36677c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 36687c478bd9Sstevel@tonic-gate attrs = ((usb_ctrl_req_t *) 36697c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->ctrl_attributes; 36707c478bd9Sstevel@tonic-gate break; 36717c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 36727c478bd9Sstevel@tonic-gate attrs = ((usb_bulk_req_t *) 36737c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->bulk_attributes; 36747c478bd9Sstevel@tonic-gate break; 36757c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 36767c478bd9Sstevel@tonic-gate attrs = ((usb_intr_req_t *) 36777c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->intr_attributes; 36787c478bd9Sstevel@tonic-gate break; 36797c478bd9Sstevel@tonic-gate } 36807c478bd9Sstevel@tonic-gate 36817c478bd9Sstevel@tonic-gate return (attrs); 36827c478bd9Sstevel@tonic-gate } 36837c478bd9Sstevel@tonic-gate 36847c478bd9Sstevel@tonic-gate 36857c478bd9Sstevel@tonic-gate /* 36867c478bd9Sstevel@tonic-gate * ehci_get_current_frame_number: 36877c478bd9Sstevel@tonic-gate * 36887c478bd9Sstevel@tonic-gate * Get the current software based usb frame number. 36897c478bd9Sstevel@tonic-gate */ 36907c478bd9Sstevel@tonic-gate usb_frame_number_t 36917c478bd9Sstevel@tonic-gate ehci_get_current_frame_number(ehci_state_t *ehcip) 36927c478bd9Sstevel@tonic-gate { 36937c478bd9Sstevel@tonic-gate usb_frame_number_t usb_frame_number; 36947c478bd9Sstevel@tonic-gate usb_frame_number_t ehci_fno, micro_frame_number; 36957c478bd9Sstevel@tonic-gate 36967c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 36977c478bd9Sstevel@tonic-gate 36987c478bd9Sstevel@tonic-gate ehci_fno = ehcip->ehci_fno; 36997c478bd9Sstevel@tonic-gate micro_frame_number = Get_OpReg(ehci_frame_index) & 0x3FFF; 37007c478bd9Sstevel@tonic-gate 37017c478bd9Sstevel@tonic-gate /* 37027c478bd9Sstevel@tonic-gate * Calculate current software based usb frame number. 37037c478bd9Sstevel@tonic-gate * 37047c478bd9Sstevel@tonic-gate * This code accounts for the fact that frame number is 37057c478bd9Sstevel@tonic-gate * updated by the Host Controller before the ehci driver 37067c478bd9Sstevel@tonic-gate * gets an FrameListRollover interrupt that will adjust 37077c478bd9Sstevel@tonic-gate * Frame higher part. 37087c478bd9Sstevel@tonic-gate * 37097c478bd9Sstevel@tonic-gate * Refer ehci specification 1.0, section 2.3.2, page 21. 37107c478bd9Sstevel@tonic-gate */ 37117c478bd9Sstevel@tonic-gate micro_frame_number = ((micro_frame_number & 0x1FFF) | 37127c478bd9Sstevel@tonic-gate ehci_fno) + (((micro_frame_number & 0x3FFF) ^ 37137c478bd9Sstevel@tonic-gate ehci_fno) & 0x2000); 37147c478bd9Sstevel@tonic-gate 37157c478bd9Sstevel@tonic-gate /* 37167c478bd9Sstevel@tonic-gate * Micro Frame number is equivalent to 125 usec. Eight 37177c478bd9Sstevel@tonic-gate * Micro Frame numbers are equivalent to one millsecond 37187c478bd9Sstevel@tonic-gate * or one usb frame number. 37197c478bd9Sstevel@tonic-gate */ 37207c478bd9Sstevel@tonic-gate usb_frame_number = micro_frame_number >> 37217c478bd9Sstevel@tonic-gate EHCI_uFRAMES_PER_USB_FRAME_SHIFT; 37227c478bd9Sstevel@tonic-gate 37237c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 37247c478bd9Sstevel@tonic-gate "ehci_get_current_frame_number: " 37257c478bd9Sstevel@tonic-gate "Current usb uframe number = 0x%llx " 37267c478bd9Sstevel@tonic-gate "Current usb frame number = 0x%llx", 37277c478bd9Sstevel@tonic-gate micro_frame_number, usb_frame_number); 37287c478bd9Sstevel@tonic-gate 37297c478bd9Sstevel@tonic-gate return (usb_frame_number); 37307c478bd9Sstevel@tonic-gate } 37317c478bd9Sstevel@tonic-gate 37327c478bd9Sstevel@tonic-gate 37337c478bd9Sstevel@tonic-gate /* 37347c478bd9Sstevel@tonic-gate * ehci_cpr_cleanup: 37357c478bd9Sstevel@tonic-gate * 37367c478bd9Sstevel@tonic-gate * Cleanup ehci state and other ehci specific informations across 37377c478bd9Sstevel@tonic-gate * Check Point Resume (CPR). 37387c478bd9Sstevel@tonic-gate */ 37397c478bd9Sstevel@tonic-gate static void 37407c478bd9Sstevel@tonic-gate ehci_cpr_cleanup(ehci_state_t *ehcip) 37417c478bd9Sstevel@tonic-gate { 37427c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 37437c478bd9Sstevel@tonic-gate 37447c478bd9Sstevel@tonic-gate /* Reset software part of usb frame number */ 37457c478bd9Sstevel@tonic-gate ehcip->ehci_fno = 0; 37467c478bd9Sstevel@tonic-gate } 37477c478bd9Sstevel@tonic-gate 37487c478bd9Sstevel@tonic-gate 37497c478bd9Sstevel@tonic-gate /* 37507c478bd9Sstevel@tonic-gate * ehci_wait_for_sof: 37517c478bd9Sstevel@tonic-gate * 37527c478bd9Sstevel@tonic-gate * Wait for couple of SOF interrupts 37537c478bd9Sstevel@tonic-gate */ 37547c478bd9Sstevel@tonic-gate int 37557c478bd9Sstevel@tonic-gate ehci_wait_for_sof(ehci_state_t *ehcip) 37567c478bd9Sstevel@tonic-gate { 37577c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 37587c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 37597c478bd9Sstevel@tonic-gate 37607c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, 37617c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, "ehci_wait_for_sof"); 37627c478bd9Sstevel@tonic-gate 37637c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 37647c478bd9Sstevel@tonic-gate 37657c478bd9Sstevel@tonic-gate error = ehci_state_is_operational(ehcip); 37667c478bd9Sstevel@tonic-gate 37677c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 37687c478bd9Sstevel@tonic-gate 37697c478bd9Sstevel@tonic-gate return (error); 37707c478bd9Sstevel@tonic-gate } 37717c478bd9Sstevel@tonic-gate 37727c478bd9Sstevel@tonic-gate /* Get the current usb frame number before waiting for two SOFs */ 37737c478bd9Sstevel@tonic-gate before_frame_number = ehci_get_current_frame_number(ehcip); 37747c478bd9Sstevel@tonic-gate 37757c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 37767c478bd9Sstevel@tonic-gate 37777c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 37787c478bd9Sstevel@tonic-gate delay(drv_usectohz(EHCI_SOF_TIMEWAIT)); 37797c478bd9Sstevel@tonic-gate 37807c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 37817c478bd9Sstevel@tonic-gate 37827c478bd9Sstevel@tonic-gate /* Get the current usb frame number after woken up */ 37837c478bd9Sstevel@tonic-gate after_frame_number = ehci_get_current_frame_number(ehcip); 37847c478bd9Sstevel@tonic-gate 37857c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 37867c478bd9Sstevel@tonic-gate "ehci_wait_for_sof: framenumber: before 0x%llx " 37877c478bd9Sstevel@tonic-gate "after 0x%llx", before_frame_number, after_frame_number); 37887c478bd9Sstevel@tonic-gate 37897c478bd9Sstevel@tonic-gate /* Return failure, if usb frame number has not been changed */ 37907c478bd9Sstevel@tonic-gate if (after_frame_number <= before_frame_number) { 37917c478bd9Sstevel@tonic-gate 37927c478bd9Sstevel@tonic-gate if ((ehci_do_soft_reset(ehcip)) != USB_SUCCESS) { 37937c478bd9Sstevel@tonic-gate 37947c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_LISTS, 37957c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, "No SOF interrupts"); 37967c478bd9Sstevel@tonic-gate 37977c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */ 37987c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE; 37997c478bd9Sstevel@tonic-gate 38007c478bd9Sstevel@tonic-gate return (USB_FAILURE); 38017c478bd9Sstevel@tonic-gate } 38027c478bd9Sstevel@tonic-gate 38037c478bd9Sstevel@tonic-gate /* Get new usb frame number */ 38047c478bd9Sstevel@tonic-gate after_frame_number = before_frame_number = 38057c478bd9Sstevel@tonic-gate ehci_get_current_frame_number(ehcip); 38067c478bd9Sstevel@tonic-gate } 38077c478bd9Sstevel@tonic-gate 38087c478bd9Sstevel@tonic-gate ASSERT(after_frame_number > before_frame_number); 38097c478bd9Sstevel@tonic-gate 38107c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 38117c478bd9Sstevel@tonic-gate } 38127c478bd9Sstevel@tonic-gate 38137c478bd9Sstevel@tonic-gate 38147c478bd9Sstevel@tonic-gate /* 38157c478bd9Sstevel@tonic-gate * ehci_toggle_scheduler: 38167c478bd9Sstevel@tonic-gate * 38177c478bd9Sstevel@tonic-gate * Turn scheduler based on pipe open count. 38187c478bd9Sstevel@tonic-gate */ 38197c478bd9Sstevel@tonic-gate void 38207c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehci_state_t *ehcip) { 38217c478bd9Sstevel@tonic-gate uint_t temp_reg, cmd_reg; 38227c478bd9Sstevel@tonic-gate 38237c478bd9Sstevel@tonic-gate cmd_reg = Get_OpReg(ehci_command); 38247c478bd9Sstevel@tonic-gate temp_reg = cmd_reg; 38257c478bd9Sstevel@tonic-gate 38267c478bd9Sstevel@tonic-gate /* 38277c478bd9Sstevel@tonic-gate * Enable/Disable asynchronous scheduler, and 38287c478bd9Sstevel@tonic-gate * turn on/off async list door bell 38297c478bd9Sstevel@tonic-gate */ 38307c478bd9Sstevel@tonic-gate if (ehcip->ehci_open_async_count) { 38317c478bd9Sstevel@tonic-gate if (!(cmd_reg & EHCI_CMD_ASYNC_SCHED_ENABLE)) { 38327c478bd9Sstevel@tonic-gate /* 38337c478bd9Sstevel@tonic-gate * For some reason this address might get nulled out by 38347c478bd9Sstevel@tonic-gate * the ehci chip. Set it here just in case it is null. 38357c478bd9Sstevel@tonic-gate */ 38367c478bd9Sstevel@tonic-gate Set_OpReg(ehci_async_list_addr, 38377c478bd9Sstevel@tonic-gate ehci_qh_cpu_to_iommu(ehcip, 38387c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list)); 38397c478bd9Sstevel@tonic-gate } 38407c478bd9Sstevel@tonic-gate cmd_reg |= EHCI_CMD_ASYNC_SCHED_ENABLE; 38417c478bd9Sstevel@tonic-gate } else { 38427c478bd9Sstevel@tonic-gate cmd_reg &= ~EHCI_CMD_ASYNC_SCHED_ENABLE; 38437c478bd9Sstevel@tonic-gate } 38447c478bd9Sstevel@tonic-gate 38457c478bd9Sstevel@tonic-gate if (ehcip->ehci_open_periodic_count) { 38467c478bd9Sstevel@tonic-gate if (!(cmd_reg & EHCI_CMD_PERIODIC_SCHED_ENABLE)) { 38477c478bd9Sstevel@tonic-gate /* 38487c478bd9Sstevel@tonic-gate * For some reason this address get's nulled out by 38497c478bd9Sstevel@tonic-gate * the ehci chip. Set it here just in case it is null. 38507c478bd9Sstevel@tonic-gate */ 38517c478bd9Sstevel@tonic-gate Set_OpReg(ehci_periodic_list_base, 38527c478bd9Sstevel@tonic-gate (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address & 38537c478bd9Sstevel@tonic-gate 0xFFFFF000)); 38547c478bd9Sstevel@tonic-gate } 38557c478bd9Sstevel@tonic-gate cmd_reg |= EHCI_CMD_PERIODIC_SCHED_ENABLE; 38567c478bd9Sstevel@tonic-gate } else { 38577c478bd9Sstevel@tonic-gate cmd_reg &= ~EHCI_CMD_PERIODIC_SCHED_ENABLE; 38587c478bd9Sstevel@tonic-gate } 38597c478bd9Sstevel@tonic-gate 38607c478bd9Sstevel@tonic-gate /* Just an optimization */ 38617c478bd9Sstevel@tonic-gate if (temp_reg != cmd_reg) { 38627c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, cmd_reg); 38637c478bd9Sstevel@tonic-gate } 38647c478bd9Sstevel@tonic-gate } 38657c478bd9Sstevel@tonic-gate 38667c478bd9Sstevel@tonic-gate /* 38677c478bd9Sstevel@tonic-gate * ehci print functions 38687c478bd9Sstevel@tonic-gate */ 38697c478bd9Sstevel@tonic-gate 38707c478bd9Sstevel@tonic-gate /* 38717c478bd9Sstevel@tonic-gate * ehci_print_caps: 38727c478bd9Sstevel@tonic-gate */ 38737c478bd9Sstevel@tonic-gate void 38747c478bd9Sstevel@tonic-gate ehci_print_caps(ehci_state_t *ehcip) 38757c478bd9Sstevel@tonic-gate { 38767c478bd9Sstevel@tonic-gate uint_t i; 38777c478bd9Sstevel@tonic-gate 38787c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 38797c478bd9Sstevel@tonic-gate "\n\tUSB 2.0 Host Controller Characteristics\n"); 38807c478bd9Sstevel@tonic-gate 38817c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 38827c478bd9Sstevel@tonic-gate "Caps Length: 0x%x Version: 0x%x\n", 38837c478bd9Sstevel@tonic-gate Get_8Cap(ehci_caps_length), Get_16Cap(ehci_version)); 38847c478bd9Sstevel@tonic-gate 38857c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 38867c478bd9Sstevel@tonic-gate "Structural Parameters\n"); 38877c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 38887c478bd9Sstevel@tonic-gate "Port indicators: %s", (Get_Cap(ehci_hcs_params) & 38897c478bd9Sstevel@tonic-gate EHCI_HCS_PORT_INDICATOR) ? "Yes" : "No"); 38907c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 38917c478bd9Sstevel@tonic-gate "No of Classic host controllers: 0x%x", 38927c478bd9Sstevel@tonic-gate (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_COMP_CTRLS) 38937c478bd9Sstevel@tonic-gate >> EHCI_HCS_NUM_COMP_CTRL_SHIFT); 38947c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 38957c478bd9Sstevel@tonic-gate "No of ports per Classic host controller: 0x%x", 38967c478bd9Sstevel@tonic-gate (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS_CC) 38977c478bd9Sstevel@tonic-gate >> EHCI_HCS_NUM_PORTS_CC_SHIFT); 38987c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 38997c478bd9Sstevel@tonic-gate "Port routing rules: %s", (Get_Cap(ehci_hcs_params) & 39007c478bd9Sstevel@tonic-gate EHCI_HCS_PORT_ROUTING_RULES) ? "Yes" : "No"); 39017c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39027c478bd9Sstevel@tonic-gate "Port power control: %s", (Get_Cap(ehci_hcs_params) & 39037c478bd9Sstevel@tonic-gate EHCI_HCS_PORT_POWER_CONTROL) ? "Yes" : "No"); 39047c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39057c478bd9Sstevel@tonic-gate "No of root hub ports: 0x%x\n", 39067c478bd9Sstevel@tonic-gate Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); 39077c478bd9Sstevel@tonic-gate 39087c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39097c478bd9Sstevel@tonic-gate "Capability Parameters\n"); 39107c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39117c478bd9Sstevel@tonic-gate "EHCI extended capability: %s", (Get_Cap(ehci_hcc_params) & 39127c478bd9Sstevel@tonic-gate EHCI_HCC_EECP) ? "Yes" : "No"); 39137c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39147c478bd9Sstevel@tonic-gate "Isoch schedule threshold: 0x%x", 39157c478bd9Sstevel@tonic-gate Get_Cap(ehci_hcc_params) & EHCI_HCC_ISOCH_SCHED_THRESHOLD); 39167c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39177c478bd9Sstevel@tonic-gate "Async schedule park capability: %s", (Get_Cap(ehci_hcc_params) & 39187c478bd9Sstevel@tonic-gate EHCI_HCC_ASYNC_SCHED_PARK_CAP) ? "Yes" : "No"); 39197c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39207c478bd9Sstevel@tonic-gate "Programmable frame list flag: %s", (Get_Cap(ehci_hcc_params) & 39217c478bd9Sstevel@tonic-gate EHCI_HCC_PROG_FRAME_LIST_FLAG) ? "256/512/1024" : "1024"); 39227c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39237c478bd9Sstevel@tonic-gate "64bit addressing capability: %s\n", (Get_Cap(ehci_hcc_params) & 39247c478bd9Sstevel@tonic-gate EHCI_HCC_64BIT_ADDR_CAP) ? "Yes" : "No"); 39257c478bd9Sstevel@tonic-gate 39267c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39277c478bd9Sstevel@tonic-gate "Classic Port Route Description"); 39287c478bd9Sstevel@tonic-gate 39297c478bd9Sstevel@tonic-gate for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) { 39307c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39317c478bd9Sstevel@tonic-gate "\tPort Route 0x%x: 0x%x", i, Get_8Cap(ehci_port_route[i])); 39327c478bd9Sstevel@tonic-gate } 39337c478bd9Sstevel@tonic-gate } 39347c478bd9Sstevel@tonic-gate 39357c478bd9Sstevel@tonic-gate 39367c478bd9Sstevel@tonic-gate /* 39377c478bd9Sstevel@tonic-gate * ehci_print_regs: 39387c478bd9Sstevel@tonic-gate */ 39397c478bd9Sstevel@tonic-gate void 39407c478bd9Sstevel@tonic-gate ehci_print_regs(ehci_state_t *ehcip) 39417c478bd9Sstevel@tonic-gate { 39427c478bd9Sstevel@tonic-gate uint_t i; 39437c478bd9Sstevel@tonic-gate 39447c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39457c478bd9Sstevel@tonic-gate "\n\tEHCI%d Operational Registers\n", 39467c478bd9Sstevel@tonic-gate ddi_get_instance(ehcip->ehci_dip)); 39477c478bd9Sstevel@tonic-gate 39487c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39497c478bd9Sstevel@tonic-gate "Command: 0x%x Status: 0x%x", 39507c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command), Get_OpReg(ehci_status)); 39517c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39527c478bd9Sstevel@tonic-gate "Interrupt: 0x%x Frame Index: 0x%x", 39537c478bd9Sstevel@tonic-gate Get_OpReg(ehci_interrupt), Get_OpReg(ehci_frame_index)); 39547c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39557c478bd9Sstevel@tonic-gate "Control Segment: 0x%x Periodic List Base: 0x%x", 39567c478bd9Sstevel@tonic-gate Get_OpReg(ehci_ctrl_segment), Get_OpReg(ehci_periodic_list_base)); 39577c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39587c478bd9Sstevel@tonic-gate "Async List Addr: 0x%x Config Flag: 0x%x", 39597c478bd9Sstevel@tonic-gate Get_OpReg(ehci_async_list_addr), Get_OpReg(ehci_config_flag)); 39607c478bd9Sstevel@tonic-gate 39617c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39627c478bd9Sstevel@tonic-gate "Root Hub Port Status"); 39637c478bd9Sstevel@tonic-gate 39647c478bd9Sstevel@tonic-gate for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) { 39657c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39667c478bd9Sstevel@tonic-gate "\tPort Status 0x%x: 0x%x ", i, 39677c478bd9Sstevel@tonic-gate Get_OpReg(ehci_rh_port_status[i])); 39687c478bd9Sstevel@tonic-gate } 39697c478bd9Sstevel@tonic-gate } 39707c478bd9Sstevel@tonic-gate 39717c478bd9Sstevel@tonic-gate 39727c478bd9Sstevel@tonic-gate /* 39737c478bd9Sstevel@tonic-gate * ehci_print_qh: 39747c478bd9Sstevel@tonic-gate */ 39757c478bd9Sstevel@tonic-gate void 39767c478bd9Sstevel@tonic-gate ehci_print_qh( 39777c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 39787c478bd9Sstevel@tonic-gate ehci_qh_t *qh) 39797c478bd9Sstevel@tonic-gate { 39807c478bd9Sstevel@tonic-gate uint_t i; 39817c478bd9Sstevel@tonic-gate 39827c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 39837c478bd9Sstevel@tonic-gate "ehci_print_qh: qh = 0x%p", (void *)qh); 39847c478bd9Sstevel@tonic-gate 39857c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 39867c478bd9Sstevel@tonic-gate "\tqh_link_ptr: 0x%x ", Get_QH(qh->qh_link_ptr)); 39877c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 39887c478bd9Sstevel@tonic-gate "\tqh_ctrl: 0x%x ", Get_QH(qh->qh_ctrl)); 39897c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 39907c478bd9Sstevel@tonic-gate "\tqh_split_ctrl: 0x%x ", Get_QH(qh->qh_split_ctrl)); 39917c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 39927c478bd9Sstevel@tonic-gate "\tqh_curr_qtd: 0x%x ", Get_QH(qh->qh_curr_qtd)); 39937c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 39947c478bd9Sstevel@tonic-gate "\tqh_next_qtd: 0x%x ", Get_QH(qh->qh_next_qtd)); 39957c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 39967c478bd9Sstevel@tonic-gate "\tqh_alt_next_qtd: 0x%x ", Get_QH(qh->qh_alt_next_qtd)); 39977c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 39987c478bd9Sstevel@tonic-gate "\tqh_status: 0x%x ", Get_QH(qh->qh_status)); 39997c478bd9Sstevel@tonic-gate 40007c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 40017c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40027c478bd9Sstevel@tonic-gate "\tqh_buf[%d]: 0x%x ", i, Get_QH(qh->qh_buf[i])); 40037c478bd9Sstevel@tonic-gate } 40047c478bd9Sstevel@tonic-gate 40057c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 40067c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40077c478bd9Sstevel@tonic-gate "\tqh_buf_high[%d]: 0x%x ", 40087c478bd9Sstevel@tonic-gate i, Get_QH(qh->qh_buf_high[i])); 40097c478bd9Sstevel@tonic-gate } 40107c478bd9Sstevel@tonic-gate 40117c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40127c478bd9Sstevel@tonic-gate "\tqh_dummy_qtd: 0x%x ", Get_QH(qh->qh_dummy_qtd)); 40137c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40147c478bd9Sstevel@tonic-gate "\tqh_prev: 0x%x ", Get_QH(qh->qh_prev)); 40157c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40167c478bd9Sstevel@tonic-gate "\tqh_state: 0x%x ", Get_QH(qh->qh_state)); 40177c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40187c478bd9Sstevel@tonic-gate "\tqh_reclaim_next: 0x%x ", Get_QH(qh->qh_reclaim_next)); 40197c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40207c478bd9Sstevel@tonic-gate "\tqh_reclaim_frame: 0x%x ", Get_QH(qh->qh_reclaim_frame)); 40217c478bd9Sstevel@tonic-gate } 40227c478bd9Sstevel@tonic-gate 40237c478bd9Sstevel@tonic-gate 40247c478bd9Sstevel@tonic-gate /* 40257c478bd9Sstevel@tonic-gate * ehci_print_qtd: 40267c478bd9Sstevel@tonic-gate */ 40277c478bd9Sstevel@tonic-gate void 40287c478bd9Sstevel@tonic-gate ehci_print_qtd( 40297c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 40307c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd) 40317c478bd9Sstevel@tonic-gate { 40327c478bd9Sstevel@tonic-gate uint_t i; 40337c478bd9Sstevel@tonic-gate 40347c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40357c478bd9Sstevel@tonic-gate "ehci_print_qtd: qtd = 0x%p", (void *)qtd); 40367c478bd9Sstevel@tonic-gate 40377c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40387c478bd9Sstevel@tonic-gate "\tqtd_next_qtd: 0x%x ", Get_QTD(qtd->qtd_next_qtd)); 40397c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40407c478bd9Sstevel@tonic-gate "\tqtd_alt_next_qtd: 0x%x ", Get_QTD(qtd->qtd_alt_next_qtd)); 40417c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40427c478bd9Sstevel@tonic-gate "\tqtd_ctrl: 0x%x ", Get_QTD(qtd->qtd_ctrl)); 40437c478bd9Sstevel@tonic-gate 40447c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 40457c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40467c478bd9Sstevel@tonic-gate "\tqtd_buf[%d]: 0x%x ", i, Get_QTD(qtd->qtd_buf[i])); 40477c478bd9Sstevel@tonic-gate } 40487c478bd9Sstevel@tonic-gate 40497c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 40507c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40517c478bd9Sstevel@tonic-gate "\tqtd_buf_high[%d]: 0x%x ", 40527c478bd9Sstevel@tonic-gate i, Get_QTD(qtd->qtd_buf_high[i])); 40537c478bd9Sstevel@tonic-gate } 40547c478bd9Sstevel@tonic-gate 40557c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40567c478bd9Sstevel@tonic-gate "\tqtd_trans_wrapper: 0x%x ", Get_QTD(qtd->qtd_trans_wrapper)); 40577c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40587c478bd9Sstevel@tonic-gate "\tqtd_tw_next_qtd: 0x%x ", Get_QTD(qtd->qtd_tw_next_qtd)); 40597c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40607c478bd9Sstevel@tonic-gate "\tqtd_active_qtd_next: 0x%x ", Get_QTD(qtd->qtd_active_qtd_next)); 40617c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40627c478bd9Sstevel@tonic-gate "\tqtd_active_qtd_prev: 0x%x ", Get_QTD(qtd->qtd_active_qtd_prev)); 40637c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40647c478bd9Sstevel@tonic-gate "\tqtd_state: 0x%x ", Get_QTD(qtd->qtd_state)); 40657c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40667c478bd9Sstevel@tonic-gate "\tqtd_ctrl_phase: 0x%x ", Get_QTD(qtd->qtd_ctrl_phase)); 40677c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40687c478bd9Sstevel@tonic-gate "\tqtd_xfer_addr: 0x%x ", Get_QTD(qtd->qtd_xfer_addr)); 40697c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40707c478bd9Sstevel@tonic-gate "\tqtd_xfer_len: 0x%x ", Get_QTD(qtd->qtd_xfer_len)); 40717c478bd9Sstevel@tonic-gate } 40727c478bd9Sstevel@tonic-gate 40737c478bd9Sstevel@tonic-gate /* 40747c478bd9Sstevel@tonic-gate * ehci kstat functions 40757c478bd9Sstevel@tonic-gate */ 40767c478bd9Sstevel@tonic-gate 40777c478bd9Sstevel@tonic-gate /* 40787c478bd9Sstevel@tonic-gate * ehci_create_stats: 40797c478bd9Sstevel@tonic-gate * 40807c478bd9Sstevel@tonic-gate * Allocate and initialize the ehci kstat structures 40817c478bd9Sstevel@tonic-gate */ 40827c478bd9Sstevel@tonic-gate void 40837c478bd9Sstevel@tonic-gate ehci_create_stats(ehci_state_t *ehcip) 40847c478bd9Sstevel@tonic-gate { 40857c478bd9Sstevel@tonic-gate char kstatname[KSTAT_STRLEN]; 40867c478bd9Sstevel@tonic-gate const char *dname = ddi_driver_name(ehcip->ehci_dip); 40877c478bd9Sstevel@tonic-gate char *usbtypes[USB_N_COUNT_KSTATS] = 40887c478bd9Sstevel@tonic-gate {"ctrl", "isoch", "bulk", "intr"}; 40897c478bd9Sstevel@tonic-gate uint_t instance = ehcip->ehci_instance; 40907c478bd9Sstevel@tonic-gate ehci_intrs_stats_t *isp; 40917c478bd9Sstevel@tonic-gate int i; 40927c478bd9Sstevel@tonic-gate 40937c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip) == NULL) { 40947c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,intrs", 40957c478bd9Sstevel@tonic-gate dname, instance); 40967c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip) = kstat_create("usba", instance, 40977c478bd9Sstevel@tonic-gate kstatname, "usb_interrupts", KSTAT_TYPE_NAMED, 40987c478bd9Sstevel@tonic-gate sizeof (ehci_intrs_stats_t) / sizeof (kstat_named_t), 40997c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 41007c478bd9Sstevel@tonic-gate 41017c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) { 41027c478bd9Sstevel@tonic-gate isp = EHCI_INTRS_STATS_DATA(ehcip); 41037c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_total, 41047c478bd9Sstevel@tonic-gate "Interrupts Total", KSTAT_DATA_UINT64); 41057c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_not_claimed, 41067c478bd9Sstevel@tonic-gate "Not Claimed", KSTAT_DATA_UINT64); 41077c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_async_sched_status, 41087c478bd9Sstevel@tonic-gate "Async schedule status", KSTAT_DATA_UINT64); 41097c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_periodic_sched_status, 41107c478bd9Sstevel@tonic-gate "Periodic sched status", KSTAT_DATA_UINT64); 41117c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_empty_async_schedule, 41127c478bd9Sstevel@tonic-gate "Empty async schedule", KSTAT_DATA_UINT64); 41137c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_host_ctrl_halted, 41147c478bd9Sstevel@tonic-gate "Host controller Halted", KSTAT_DATA_UINT64); 41157c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_async_advance_intr, 41167c478bd9Sstevel@tonic-gate "Intr on async advance", KSTAT_DATA_UINT64); 41177c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_host_system_error_intr, 41187c478bd9Sstevel@tonic-gate "Host system error", KSTAT_DATA_UINT64); 41197c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_frm_list_rollover_intr, 41207c478bd9Sstevel@tonic-gate "Frame list rollover", KSTAT_DATA_UINT64); 41217c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_rh_port_change_intr, 41227c478bd9Sstevel@tonic-gate "Port change detect", KSTAT_DATA_UINT64); 41237c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_usb_error_intr, 41247c478bd9Sstevel@tonic-gate "USB error interrupt", KSTAT_DATA_UINT64); 41257c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_usb_intr, 41267c478bd9Sstevel@tonic-gate "USB interrupt", KSTAT_DATA_UINT64); 41277c478bd9Sstevel@tonic-gate 41287c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip)->ks_private = ehcip; 41297c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip)->ks_update = nulldev; 41307c478bd9Sstevel@tonic-gate kstat_install(EHCI_INTRS_STATS(ehcip)); 41317c478bd9Sstevel@tonic-gate } 41327c478bd9Sstevel@tonic-gate } 41337c478bd9Sstevel@tonic-gate 41347c478bd9Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip) == NULL) { 41357c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,total", 41367c478bd9Sstevel@tonic-gate dname, instance); 41377c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS(ehcip) = kstat_create("usba", instance, 41387c478bd9Sstevel@tonic-gate kstatname, "usb_byte_count", KSTAT_TYPE_IO, 1, 41397c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 41407c478bd9Sstevel@tonic-gate 41417c478bd9Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip)) { 41427c478bd9Sstevel@tonic-gate kstat_install(EHCI_TOTAL_STATS(ehcip)); 41437c478bd9Sstevel@tonic-gate } 41447c478bd9Sstevel@tonic-gate } 41457c478bd9Sstevel@tonic-gate 41467c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) { 41477c478bd9Sstevel@tonic-gate if (ehcip->ehci_count_stats[i] == NULL) { 41487c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,%s", 41497c478bd9Sstevel@tonic-gate dname, instance, usbtypes[i]); 41507c478bd9Sstevel@tonic-gate ehcip->ehci_count_stats[i] = kstat_create("usba", 41517c478bd9Sstevel@tonic-gate instance, kstatname, "usb_byte_count", 41527c478bd9Sstevel@tonic-gate KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT); 41537c478bd9Sstevel@tonic-gate 41547c478bd9Sstevel@tonic-gate if (ehcip->ehci_count_stats[i]) { 41557c478bd9Sstevel@tonic-gate kstat_install(ehcip->ehci_count_stats[i]); 41567c478bd9Sstevel@tonic-gate } 41577c478bd9Sstevel@tonic-gate } 41587c478bd9Sstevel@tonic-gate } 41597c478bd9Sstevel@tonic-gate } 41607c478bd9Sstevel@tonic-gate 41617c478bd9Sstevel@tonic-gate 41627c478bd9Sstevel@tonic-gate /* 41637c478bd9Sstevel@tonic-gate * ehci_destroy_stats: 41647c478bd9Sstevel@tonic-gate * 41657c478bd9Sstevel@tonic-gate * Clean up ehci kstat structures 41667c478bd9Sstevel@tonic-gate */ 41677c478bd9Sstevel@tonic-gate void 41687c478bd9Sstevel@tonic-gate ehci_destroy_stats(ehci_state_t *ehcip) 41697c478bd9Sstevel@tonic-gate { 41707c478bd9Sstevel@tonic-gate int i; 41717c478bd9Sstevel@tonic-gate 41727c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) { 41737c478bd9Sstevel@tonic-gate kstat_delete(EHCI_INTRS_STATS(ehcip)); 41747c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip) = NULL; 41757c478bd9Sstevel@tonic-gate } 41767c478bd9Sstevel@tonic-gate 41777c478bd9Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip)) { 41787c478bd9Sstevel@tonic-gate kstat_delete(EHCI_TOTAL_STATS(ehcip)); 41797c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS(ehcip) = NULL; 41807c478bd9Sstevel@tonic-gate } 41817c478bd9Sstevel@tonic-gate 41827c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) { 41837c478bd9Sstevel@tonic-gate if (ehcip->ehci_count_stats[i]) { 41847c478bd9Sstevel@tonic-gate kstat_delete(ehcip->ehci_count_stats[i]); 41857c478bd9Sstevel@tonic-gate ehcip->ehci_count_stats[i] = NULL; 41867c478bd9Sstevel@tonic-gate } 41877c478bd9Sstevel@tonic-gate } 41887c478bd9Sstevel@tonic-gate } 41897c478bd9Sstevel@tonic-gate 41907c478bd9Sstevel@tonic-gate 41917c478bd9Sstevel@tonic-gate /* 41927c478bd9Sstevel@tonic-gate * ehci_do_intrs_stats: 41937c478bd9Sstevel@tonic-gate * 41947c478bd9Sstevel@tonic-gate * ehci status information 41957c478bd9Sstevel@tonic-gate */ 41967c478bd9Sstevel@tonic-gate void 41977c478bd9Sstevel@tonic-gate ehci_do_intrs_stats( 41987c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 41997c478bd9Sstevel@tonic-gate int val) 42007c478bd9Sstevel@tonic-gate { 42017c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) { 42027c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->ehci_sts_total.value.ui64++; 42037c478bd9Sstevel@tonic-gate switch (val) { 42047c478bd9Sstevel@tonic-gate case EHCI_STS_ASYNC_SCHED_STATUS: 42057c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 42067c478bd9Sstevel@tonic-gate ehci_sts_async_sched_status.value.ui64++; 42077c478bd9Sstevel@tonic-gate break; 42087c478bd9Sstevel@tonic-gate case EHCI_STS_PERIODIC_SCHED_STATUS: 42097c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 42107c478bd9Sstevel@tonic-gate ehci_sts_periodic_sched_status.value.ui64++; 42117c478bd9Sstevel@tonic-gate break; 42127c478bd9Sstevel@tonic-gate case EHCI_STS_EMPTY_ASYNC_SCHEDULE: 42137c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 42147c478bd9Sstevel@tonic-gate ehci_sts_empty_async_schedule.value.ui64++; 42157c478bd9Sstevel@tonic-gate break; 42167c478bd9Sstevel@tonic-gate case EHCI_STS_HOST_CTRL_HALTED: 42177c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 42187c478bd9Sstevel@tonic-gate ehci_sts_host_ctrl_halted.value.ui64++; 42197c478bd9Sstevel@tonic-gate break; 42207c478bd9Sstevel@tonic-gate case EHCI_STS_ASYNC_ADVANCE_INTR: 42217c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 42227c478bd9Sstevel@tonic-gate ehci_sts_async_advance_intr.value.ui64++; 42237c478bd9Sstevel@tonic-gate break; 42247c478bd9Sstevel@tonic-gate case EHCI_STS_HOST_SYSTEM_ERROR_INTR: 42257c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 42267c478bd9Sstevel@tonic-gate ehci_sts_host_system_error_intr.value.ui64++; 42277c478bd9Sstevel@tonic-gate break; 42287c478bd9Sstevel@tonic-gate case EHCI_STS_FRM_LIST_ROLLOVER_INTR: 42297c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 42307c478bd9Sstevel@tonic-gate ehci_sts_frm_list_rollover_intr.value.ui64++; 42317c478bd9Sstevel@tonic-gate break; 42327c478bd9Sstevel@tonic-gate case EHCI_STS_RH_PORT_CHANGE_INTR: 42337c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 42347c478bd9Sstevel@tonic-gate ehci_sts_rh_port_change_intr.value.ui64++; 42357c478bd9Sstevel@tonic-gate break; 42367c478bd9Sstevel@tonic-gate case EHCI_STS_USB_ERROR_INTR: 42377c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 42387c478bd9Sstevel@tonic-gate ehci_sts_usb_error_intr.value.ui64++; 42397c478bd9Sstevel@tonic-gate break; 42407c478bd9Sstevel@tonic-gate case EHCI_STS_USB_INTR: 42417c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 42427c478bd9Sstevel@tonic-gate ehci_sts_usb_intr.value.ui64++; 42437c478bd9Sstevel@tonic-gate break; 42447c478bd9Sstevel@tonic-gate default: 42457c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 42467c478bd9Sstevel@tonic-gate ehci_sts_not_claimed.value.ui64++; 42477c478bd9Sstevel@tonic-gate break; 42487c478bd9Sstevel@tonic-gate } 42497c478bd9Sstevel@tonic-gate } 42507c478bd9Sstevel@tonic-gate } 42517c478bd9Sstevel@tonic-gate 42527c478bd9Sstevel@tonic-gate 42537c478bd9Sstevel@tonic-gate /* 42547c478bd9Sstevel@tonic-gate * ehci_do_byte_stats: 42557c478bd9Sstevel@tonic-gate * 42567c478bd9Sstevel@tonic-gate * ehci data xfer information 42577c478bd9Sstevel@tonic-gate */ 42587c478bd9Sstevel@tonic-gate void 42597c478bd9Sstevel@tonic-gate ehci_do_byte_stats( 42607c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 42617c478bd9Sstevel@tonic-gate size_t len, 42627c478bd9Sstevel@tonic-gate uint8_t attr, 42637c478bd9Sstevel@tonic-gate uint8_t addr) 42647c478bd9Sstevel@tonic-gate { 42657c478bd9Sstevel@tonic-gate uint8_t type = attr & USB_EP_ATTR_MASK; 42667c478bd9Sstevel@tonic-gate uint8_t dir = addr & USB_EP_DIR_MASK; 42677c478bd9Sstevel@tonic-gate 42687c478bd9Sstevel@tonic-gate if (dir == USB_EP_DIR_IN) { 42697c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->reads++; 42707c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->nread += len; 42717c478bd9Sstevel@tonic-gate switch (type) { 42727c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 42737c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->reads++; 42747c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->nread += len; 42757c478bd9Sstevel@tonic-gate break; 42767c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 42777c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->reads++; 42787c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->nread += len; 42797c478bd9Sstevel@tonic-gate break; 42807c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 42817c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->reads++; 42827c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->nread += len; 42837c478bd9Sstevel@tonic-gate break; 42847c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 42857c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->reads++; 42867c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->nread += len; 42877c478bd9Sstevel@tonic-gate break; 42887c478bd9Sstevel@tonic-gate } 42897c478bd9Sstevel@tonic-gate } else if (dir == USB_EP_DIR_OUT) { 42907c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->writes++; 42917c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->nwritten += len; 42927c478bd9Sstevel@tonic-gate switch (type) { 42937c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 42947c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->writes++; 42957c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->nwritten += len; 42967c478bd9Sstevel@tonic-gate break; 42977c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 42987c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->writes++; 42997c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->nwritten += len; 43007c478bd9Sstevel@tonic-gate break; 43017c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 43027c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->writes++; 43037c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->nwritten += len; 43047c478bd9Sstevel@tonic-gate break; 43057c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 43067c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->writes++; 43077c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->nwritten += len; 43087c478bd9Sstevel@tonic-gate break; 43097c478bd9Sstevel@tonic-gate } 43107c478bd9Sstevel@tonic-gate } 43117c478bd9Sstevel@tonic-gate } 4312