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 53b00f311Syq * Common Development and Distribution License (the "License"). 63b00f311Syq * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 2229aca3ebSlc * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * EHCI Host Controller Driver (EHCI) 297c478bd9Sstevel@tonic-gate * 307c478bd9Sstevel@tonic-gate * The EHCI driver is a software driver which interfaces to the Universal 317c478bd9Sstevel@tonic-gate * Serial Bus layer (USBA) and the Host Controller (HC). The interface to 327c478bd9Sstevel@tonic-gate * the Host Controller is defined by the EHCI Host Controller Interface. 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * This module contains the main EHCI driver code which handles all USB 357c478bd9Sstevel@tonic-gate * transfers, bandwidth allocations and other general functionalities. 367c478bd9Sstevel@tonic-gate */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h> 397c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_isoch.h> 407c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h> 417c478bd9Sstevel@tonic-gate 429c75c6bfSgovinda /* 439c75c6bfSgovinda * EHCI MSI tunable: 449c75c6bfSgovinda * 459c75c6bfSgovinda * By default MSI is enabled on all supported platforms except for the 469c75c6bfSgovinda * EHCI controller of ULI1575 South bridge. 479c75c6bfSgovinda */ 489c75c6bfSgovinda boolean_t ehci_enable_msi = B_TRUE; 499c75c6bfSgovinda 507c478bd9Sstevel@tonic-gate /* Pointer to the state structure */ 517c478bd9Sstevel@tonic-gate extern void *ehci_statep; 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate extern void ehci_handle_endpoint_reclaimation(ehci_state_t *); 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate extern uint_t ehci_vt62x2_workaround; 562df1fe9cSrandyf extern int force_ehci_off; 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* Adjustable variables for the size of the pools */ 597c478bd9Sstevel@tonic-gate int ehci_qh_pool_size = EHCI_QH_POOL_SIZE; 607c478bd9Sstevel@tonic-gate int ehci_qtd_pool_size = EHCI_QTD_POOL_SIZE; 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate /* 637c478bd9Sstevel@tonic-gate * Initialize the values which the order of 32ms intr qh are executed 647c478bd9Sstevel@tonic-gate * by the host controller in the lattice tree. 657c478bd9Sstevel@tonic-gate */ 667c478bd9Sstevel@tonic-gate static uchar_t ehci_index[EHCI_NUM_INTR_QH_LISTS] = 677c478bd9Sstevel@tonic-gate {0x00, 0x10, 0x08, 0x18, 687c478bd9Sstevel@tonic-gate 0x04, 0x14, 0x0c, 0x1c, 697c478bd9Sstevel@tonic-gate 0x02, 0x12, 0x0a, 0x1a, 707c478bd9Sstevel@tonic-gate 0x06, 0x16, 0x0e, 0x1e, 717c478bd9Sstevel@tonic-gate 0x01, 0x11, 0x09, 0x19, 727c478bd9Sstevel@tonic-gate 0x05, 0x15, 0x0d, 0x1d, 737c478bd9Sstevel@tonic-gate 0x03, 0x13, 0x0b, 0x1b, 747c478bd9Sstevel@tonic-gate 0x07, 0x17, 0x0f, 0x1f}; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate /* 777c478bd9Sstevel@tonic-gate * Initialize the values which are used to calculate start split mask 787c478bd9Sstevel@tonic-gate * for the low/full/high speed interrupt and isochronous endpoints. 797c478bd9Sstevel@tonic-gate */ 807c478bd9Sstevel@tonic-gate static uint_t ehci_start_split_mask[15] = { 817c478bd9Sstevel@tonic-gate /* 827c478bd9Sstevel@tonic-gate * For high/full/low speed usb devices. For high speed 837c478bd9Sstevel@tonic-gate * device with polling interval greater than or equal 847c478bd9Sstevel@tonic-gate * to 8us (125us). 857c478bd9Sstevel@tonic-gate */ 867c478bd9Sstevel@tonic-gate 0x01, /* 00000001 */ 877c478bd9Sstevel@tonic-gate 0x02, /* 00000010 */ 887c478bd9Sstevel@tonic-gate 0x04, /* 00000100 */ 897c478bd9Sstevel@tonic-gate 0x08, /* 00001000 */ 907c478bd9Sstevel@tonic-gate 0x10, /* 00010000 */ 917c478bd9Sstevel@tonic-gate 0x20, /* 00100000 */ 927c478bd9Sstevel@tonic-gate 0x40, /* 01000000 */ 937c478bd9Sstevel@tonic-gate 0x80, /* 10000000 */ 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* Only for high speed devices with polling interval 4us */ 967c478bd9Sstevel@tonic-gate 0x11, /* 00010001 */ 977c478bd9Sstevel@tonic-gate 0x22, /* 00100010 */ 987c478bd9Sstevel@tonic-gate 0x44, /* 01000100 */ 997c478bd9Sstevel@tonic-gate 0x88, /* 10001000 */ 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* Only for high speed devices with polling interval 2us */ 1027c478bd9Sstevel@tonic-gate 0x55, /* 01010101 */ 1037c478bd9Sstevel@tonic-gate 0xaa, /* 10101010 */ 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate /* Only for high speed devices with polling interval 1us */ 1067c478bd9Sstevel@tonic-gate 0xff /* 11111111 */ 1077c478bd9Sstevel@tonic-gate }; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate /* 1107c478bd9Sstevel@tonic-gate * Initialize the values which are used to calculate complete split mask 1117c478bd9Sstevel@tonic-gate * for the low/full speed interrupt and isochronous endpoints. 1127c478bd9Sstevel@tonic-gate */ 1137c478bd9Sstevel@tonic-gate static uint_t ehci_intr_complete_split_mask[7] = { 1147c478bd9Sstevel@tonic-gate /* Only full/low speed devices */ 1157c478bd9Sstevel@tonic-gate 0x1c, /* 00011100 */ 1167c478bd9Sstevel@tonic-gate 0x38, /* 00111000 */ 1177c478bd9Sstevel@tonic-gate 0x70, /* 01110000 */ 1187c478bd9Sstevel@tonic-gate 0xe0, /* 11100000 */ 1197c478bd9Sstevel@tonic-gate 0x00, /* Need FSTN feature */ 1207c478bd9Sstevel@tonic-gate 0x00, /* Need FSTN feature */ 1217c478bd9Sstevel@tonic-gate 0x00 /* Need FSTN feature */ 1227c478bd9Sstevel@tonic-gate }; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate /* 1267c478bd9Sstevel@tonic-gate * EHCI Internal Function Prototypes 1277c478bd9Sstevel@tonic-gate */ 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) initialization functions */ 1307c478bd9Sstevel@tonic-gate void ehci_set_dma_attributes(ehci_state_t *ehcip); 1317c478bd9Sstevel@tonic-gate int ehci_allocate_pools(ehci_state_t *ehcip); 1327c478bd9Sstevel@tonic-gate void ehci_decode_ddi_dma_addr_bind_handle_result( 1337c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1347c478bd9Sstevel@tonic-gate int result); 1357c478bd9Sstevel@tonic-gate int ehci_map_regs(ehci_state_t *ehcip); 1367c478bd9Sstevel@tonic-gate int ehci_register_intrs_and_init_mutex( 1377c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 1389c75c6bfSgovinda static int ehci_add_intrs(ehci_state_t *ehcip, 1399c75c6bfSgovinda int intr_type); 1403b00f311Syq int ehci_init_ctlr(ehci_state_t *ehcip, 1413b00f311Syq int init_type); 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); 1519c75c6bfSgovinda 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, 29429aca3ebSlc 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 3103ceb94daSbc void 3113ceb94daSbc ehci_dma_attr_workaround(ehci_state_t *ehcip) 3123ceb94daSbc { 3133ceb94daSbc /* 3143ceb94daSbc * Some Nvidia chips can not handle qh dma address above 2G. 3153ceb94daSbc * The bit 31 of the dma address might be omitted and it will 3163ceb94daSbc * cause system crash or other unpredicable result. So force 3173ceb94daSbc * the dma address allocated below 2G to make ehci work. 3183ceb94daSbc */ 3193ceb94daSbc if (PCI_VENDOR_NVIDIA == ehcip->ehci_vendor_id) { 3203ceb94daSbc switch (ehcip->ehci_device_id) { 3213ceb94daSbc case PCI_DEVICE_NVIDIA_CK804: 322*2259743eSbinzi cao - Sun Microsystems - Beijing China case PCI_DEVICE_NVIDIA_MCP04: 3233ceb94daSbc USB_DPRINTF_L2(PRINT_MASK_ATTA, 3243ceb94daSbc ehcip->ehci_log_hdl, 3253ceb94daSbc "ehci_dma_attr_workaround: NVIDIA dma " 3263ceb94daSbc "workaround enabled, force dma address " 3273ceb94daSbc "to be allocated below 2G"); 3283ceb94daSbc ehcip->ehci_dma_attr.dma_attr_addr_hi = 3293ceb94daSbc 0x7fffffffull; 3303ceb94daSbc break; 3313ceb94daSbc default: 3323ceb94daSbc break; 3333ceb94daSbc 3343ceb94daSbc } 3353ceb94daSbc } 3363ceb94daSbc } 3374610e4a0Sfrits 3387c478bd9Sstevel@tonic-gate /* 3397c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) initialization functions 3407c478bd9Sstevel@tonic-gate */ 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate /* 3437c478bd9Sstevel@tonic-gate * ehci_set_dma_attributes: 3447c478bd9Sstevel@tonic-gate * 3457c478bd9Sstevel@tonic-gate * Set the limits in the DMA attributes structure. Most of the values used 3467c478bd9Sstevel@tonic-gate * in the DMA limit structures are the default values as specified by the 3477c478bd9Sstevel@tonic-gate * Writing PCI device drivers document. 3487c478bd9Sstevel@tonic-gate */ 3497c478bd9Sstevel@tonic-gate void 3507c478bd9Sstevel@tonic-gate ehci_set_dma_attributes(ehci_state_t *ehcip) 3517c478bd9Sstevel@tonic-gate { 3527c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3537c478bd9Sstevel@tonic-gate "ehci_set_dma_attributes:"); 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate /* Initialize the DMA attributes */ 3567c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_version = DMA_ATTR_V0; 3577c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_addr_lo = 0x00000000ull; 3587c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_addr_hi = 0xfffffffeull; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* 32 bit addressing */ 3617c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_count_max = EHCI_DMA_ATTR_COUNT_MAX; 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate /* Byte alignment */ 3647c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate /* 3677c478bd9Sstevel@tonic-gate * Since PCI specification is byte alignment, the 3687c478bd9Sstevel@tonic-gate * burst size field should be set to 1 for PCI devices. 3697c478bd9Sstevel@tonic-gate */ 3707c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_burstsizes = 0x1; 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_minxfer = 0x1; 3737c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_maxxfer = EHCI_DMA_ATTR_MAX_XFER; 3747c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_seg = 0xffffffffull; 3757c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_sgllen = 1; 3767c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_granular = EHCI_DMA_ATTR_GRANULAR; 3777c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_flags = 0; 3783ceb94daSbc ehci_dma_attr_workaround(ehcip); 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate /* 3837c478bd9Sstevel@tonic-gate * ehci_allocate_pools: 3847c478bd9Sstevel@tonic-gate * 3857c478bd9Sstevel@tonic-gate * Allocate the system memory for the Endpoint Descriptor (QH) and for the 3867c478bd9Sstevel@tonic-gate * Transfer Descriptor (QTD) pools. Both QH and QTD structures must be aligned 3877c478bd9Sstevel@tonic-gate * to a 16 byte boundary. 3887c478bd9Sstevel@tonic-gate */ 3897c478bd9Sstevel@tonic-gate int 3907c478bd9Sstevel@tonic-gate ehci_allocate_pools(ehci_state_t *ehcip) 3917c478bd9Sstevel@tonic-gate { 3927c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 3937c478bd9Sstevel@tonic-gate size_t real_length; 3947c478bd9Sstevel@tonic-gate int result; 3957c478bd9Sstevel@tonic-gate uint_t ccount; 3967c478bd9Sstevel@tonic-gate int i; 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3997c478bd9Sstevel@tonic-gate "ehci_allocate_pools:"); 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 4027c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 4037c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 4047c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate /* Byte alignment */ 4077c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_TD_QH_ALIGNMENT; 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate /* Allocate the QTD pool DMA handle */ 4107c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr, 41129aca3ebSlc DDI_DMA_SLEEP, 0, 41229aca3ebSlc &ehcip->ehci_qtd_pool_dma_handle) != DDI_SUCCESS) { 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate goto failure; 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* Allocate the memory for the QTD pool */ 4187c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_qtd_pool_dma_handle, 41929aca3ebSlc ehci_qtd_pool_size * sizeof (ehci_qtd_t), 42029aca3ebSlc &dev_attr, 42129aca3ebSlc DDI_DMA_CONSISTENT, 42229aca3ebSlc DDI_DMA_SLEEP, 42329aca3ebSlc 0, 42429aca3ebSlc (caddr_t *)&ehcip->ehci_qtd_pool_addr, 42529aca3ebSlc &real_length, 42629aca3ebSlc &ehcip->ehci_qtd_pool_mem_handle)) { 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate goto failure; 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate /* Map the QTD pool into the I/O address space */ 4327c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle( 43329aca3ebSlc ehcip->ehci_qtd_pool_dma_handle, 43429aca3ebSlc NULL, 43529aca3ebSlc (caddr_t)ehcip->ehci_qtd_pool_addr, 43629aca3ebSlc real_length, 43729aca3ebSlc DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 43829aca3ebSlc DDI_DMA_SLEEP, 43929aca3ebSlc NULL, 44029aca3ebSlc &ehcip->ehci_qtd_pool_cookie, 44129aca3ebSlc &ccount); 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate bzero((void *)ehcip->ehci_qtd_pool_addr, 44429aca3ebSlc ehci_qtd_pool_size * sizeof (ehci_qtd_t)); 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* Process the result */ 4477c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 4487c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 4497c478bd9Sstevel@tonic-gate if (ccount != 1) { 4507c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 4517c478bd9Sstevel@tonic-gate "ehci_allocate_pools: More than 1 cookie"); 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate goto failure; 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate } else { 4567c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 4577c478bd9Sstevel@tonic-gate "ehci_allocate_pools: Result = %d", result); 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result); 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate goto failure; 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate /* 4657c478bd9Sstevel@tonic-gate * DMA addresses for QTD pools are bound 4667c478bd9Sstevel@tonic-gate */ 4677c478bd9Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_QTD_POOL_BOUND; 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate /* Initialize the QTD pool */ 4707c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_qtd_pool_size; i ++) { 4717c478bd9Sstevel@tonic-gate Set_QTD(ehcip->ehci_qtd_pool_addr[i]. 4727c478bd9Sstevel@tonic-gate qtd_state, EHCI_QTD_FREE); 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate /* Allocate the QTD pool DMA handle */ 4767c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip, 47729aca3ebSlc &ehcip->ehci_dma_attr, 47829aca3ebSlc DDI_DMA_SLEEP, 47929aca3ebSlc 0, 48029aca3ebSlc &ehcip->ehci_qh_pool_dma_handle) != DDI_SUCCESS) { 4813ceb94daSbc USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 4823ceb94daSbc "ehci_allocate_pools: ddi_dma_alloc_handle failed"); 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate goto failure; 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate /* Allocate the memory for the QH pool */ 4887c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_qh_pool_dma_handle, 48929aca3ebSlc ehci_qh_pool_size * sizeof (ehci_qh_t), 49029aca3ebSlc &dev_attr, 49129aca3ebSlc DDI_DMA_CONSISTENT, 49229aca3ebSlc DDI_DMA_SLEEP, 49329aca3ebSlc 0, 49429aca3ebSlc (caddr_t *)&ehcip->ehci_qh_pool_addr, 49529aca3ebSlc &real_length, 49629aca3ebSlc &ehcip->ehci_qh_pool_mem_handle) != DDI_SUCCESS) { 4973ceb94daSbc USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 4983ceb94daSbc "ehci_allocate_pools: ddi_dma_mem_alloc failed"); 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate goto failure; 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ehcip->ehci_qh_pool_dma_handle, 50429aca3ebSlc NULL, 50529aca3ebSlc (caddr_t)ehcip->ehci_qh_pool_addr, 50629aca3ebSlc real_length, 50729aca3ebSlc DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 50829aca3ebSlc DDI_DMA_SLEEP, 50929aca3ebSlc NULL, 51029aca3ebSlc &ehcip->ehci_qh_pool_cookie, 51129aca3ebSlc &ccount); 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate bzero((void *)ehcip->ehci_qh_pool_addr, 51429aca3ebSlc ehci_qh_pool_size * sizeof (ehci_qh_t)); 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate /* Process the result */ 5177c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 5187c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 5197c478bd9Sstevel@tonic-gate if (ccount != 1) { 5207c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 5217c478bd9Sstevel@tonic-gate "ehci_allocate_pools: More than 1 cookie"); 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate goto failure; 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate } else { 5267c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result); 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate goto failure; 5297c478bd9Sstevel@tonic-gate } 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate /* 5327c478bd9Sstevel@tonic-gate * DMA addresses for QH pools are bound 5337c478bd9Sstevel@tonic-gate */ 5347c478bd9Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_QH_POOL_BOUND; 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate /* Initialize the QH pool */ 5377c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_qh_pool_size; i ++) { 5387c478bd9Sstevel@tonic-gate Set_QH(ehcip->ehci_qh_pool_addr[i].qh_state, EHCI_QH_FREE); 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate /* Byte alignment */ 5427c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate failure: 5477c478bd9Sstevel@tonic-gate /* Byte alignment */ 5487c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5517c478bd9Sstevel@tonic-gate } 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate /* 5557c478bd9Sstevel@tonic-gate * ehci_decode_ddi_dma_addr_bind_handle_result: 5567c478bd9Sstevel@tonic-gate * 5577c478bd9Sstevel@tonic-gate * Process the return values of ddi_dma_addr_bind_handle() 5587c478bd9Sstevel@tonic-gate */ 5597c478bd9Sstevel@tonic-gate void 5607c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result( 5617c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 5627c478bd9Sstevel@tonic-gate int result) 5637c478bd9Sstevel@tonic-gate { 5647c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 5657c478bd9Sstevel@tonic-gate "ehci_decode_ddi_dma_addr_bind_handle_result:"); 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate switch (result) { 5687c478bd9Sstevel@tonic-gate case DDI_DMA_PARTIAL_MAP: 5697c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5707c478bd9Sstevel@tonic-gate "Partial transfers not allowed"); 5717c478bd9Sstevel@tonic-gate break; 5727c478bd9Sstevel@tonic-gate case DDI_DMA_INUSE: 5737c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5747c478bd9Sstevel@tonic-gate "Handle is in use"); 5757c478bd9Sstevel@tonic-gate break; 5767c478bd9Sstevel@tonic-gate case DDI_DMA_NORESOURCES: 5777c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5787c478bd9Sstevel@tonic-gate "No resources"); 5797c478bd9Sstevel@tonic-gate break; 5807c478bd9Sstevel@tonic-gate case DDI_DMA_NOMAPPING: 5817c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5827c478bd9Sstevel@tonic-gate "No mapping"); 5837c478bd9Sstevel@tonic-gate break; 5847c478bd9Sstevel@tonic-gate case DDI_DMA_TOOBIG: 5857c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5867c478bd9Sstevel@tonic-gate "Object is too big"); 5877c478bd9Sstevel@tonic-gate break; 5887c478bd9Sstevel@tonic-gate default: 5897c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5907c478bd9Sstevel@tonic-gate "Unknown dma error"); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate /* 5967c478bd9Sstevel@tonic-gate * ehci_map_regs: 5977c478bd9Sstevel@tonic-gate * 5987c478bd9Sstevel@tonic-gate * The Host Controller (HC) contains a set of on-chip operational registers 5997c478bd9Sstevel@tonic-gate * and which should be mapped into a non-cacheable portion of the system 6007c478bd9Sstevel@tonic-gate * addressable space. 6017c478bd9Sstevel@tonic-gate */ 6027c478bd9Sstevel@tonic-gate int 6037c478bd9Sstevel@tonic-gate ehci_map_regs(ehci_state_t *ehcip) 6047c478bd9Sstevel@tonic-gate { 6057c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 6067c478bd9Sstevel@tonic-gate uint16_t cmd_reg; 6077c478bd9Sstevel@tonic-gate uint_t length; 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_map_regs:"); 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate /* Check to make sure we have memory access */ 6127c478bd9Sstevel@tonic-gate if (pci_config_setup(ehcip->ehci_dip, 61329aca3ebSlc &ehcip->ehci_config_handle) != DDI_SUCCESS) { 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 6167c478bd9Sstevel@tonic-gate "ehci_map_regs: Config error"); 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate /* Make sure Memory Access Enable is set */ 6227c478bd9Sstevel@tonic-gate cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM); 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate if (!(cmd_reg & PCI_COMM_MAE)) { 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 6277c478bd9Sstevel@tonic-gate "ehci_map_regs: Memory base address access disabled"); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 6337c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 6347c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 6357c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate /* Map in EHCI Capability registers */ 6387c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(ehcip->ehci_dip, 1, 6397c478bd9Sstevel@tonic-gate (caddr_t *)&ehcip->ehci_capsp, 0, 6407c478bd9Sstevel@tonic-gate sizeof (ehci_caps_t), &attr, 6417c478bd9Sstevel@tonic-gate &ehcip->ehci_caps_handle) != DDI_SUCCESS) { 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 6447c478bd9Sstevel@tonic-gate "ehci_map_regs: Map setup error"); 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate length = ddi_get8(ehcip->ehci_caps_handle, 6507c478bd9Sstevel@tonic-gate (uint8_t *)&ehcip->ehci_capsp->ehci_caps_length); 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate /* Free the original mapping */ 6537c478bd9Sstevel@tonic-gate ddi_regs_map_free(&ehcip->ehci_caps_handle); 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate /* Re-map in EHCI Capability and Operational registers */ 6567c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(ehcip->ehci_dip, 1, 6577c478bd9Sstevel@tonic-gate (caddr_t *)&ehcip->ehci_capsp, 0, 6587c478bd9Sstevel@tonic-gate length + sizeof (ehci_regs_t), &attr, 6597c478bd9Sstevel@tonic-gate &ehcip->ehci_caps_handle) != DDI_SUCCESS) { 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 6627c478bd9Sstevel@tonic-gate "ehci_map_regs: Map setup error"); 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate /* Get the pointer to EHCI Operational Register */ 6687c478bd9Sstevel@tonic-gate ehcip->ehci_regsp = (ehci_regs_t *) 6697c478bd9Sstevel@tonic-gate ((uintptr_t)ehcip->ehci_capsp + length); 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 6727c478bd9Sstevel@tonic-gate "ehci_map_regs: Capsp 0x%p Regsp 0x%p\n", 673112116d8Sfb (void *)ehcip->ehci_capsp, (void *)ehcip->ehci_regsp); 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate 67828cdc3d7Sszhou /* 67928cdc3d7Sszhou * The following simulated polling is for debugging purposes only. 68028cdc3d7Sszhou * It is activated on x86 by setting usb-polling=true in GRUB or ehci.conf. 68128cdc3d7Sszhou */ 68228cdc3d7Sszhou static int 68328cdc3d7Sszhou ehci_is_polled(dev_info_t *dip) 68428cdc3d7Sszhou { 68528cdc3d7Sszhou int ret; 68628cdc3d7Sszhou char *propval; 68728cdc3d7Sszhou 68828cdc3d7Sszhou if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, 68928cdc3d7Sszhou "usb-polling", &propval) != DDI_SUCCESS) 69028cdc3d7Sszhou 69128cdc3d7Sszhou return (0); 69228cdc3d7Sszhou 69328cdc3d7Sszhou ret = (strcmp(propval, "true") == 0); 69428cdc3d7Sszhou ddi_prop_free(propval); 69528cdc3d7Sszhou 69628cdc3d7Sszhou return (ret); 69728cdc3d7Sszhou } 69828cdc3d7Sszhou 69928cdc3d7Sszhou static void 70028cdc3d7Sszhou ehci_poll_intr(void *arg) 70128cdc3d7Sszhou { 70228cdc3d7Sszhou /* poll every msec */ 70328cdc3d7Sszhou for (;;) { 70428cdc3d7Sszhou (void) ehci_intr(arg, NULL); 70528cdc3d7Sszhou delay(drv_usectohz(1000)); 70628cdc3d7Sszhou } 70728cdc3d7Sszhou } 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate /* 7107c478bd9Sstevel@tonic-gate * ehci_register_intrs_and_init_mutex: 7117c478bd9Sstevel@tonic-gate * 7127c478bd9Sstevel@tonic-gate * Register interrupts and initialize each mutex and condition variables 7137c478bd9Sstevel@tonic-gate */ 7147c478bd9Sstevel@tonic-gate int 7157c478bd9Sstevel@tonic-gate ehci_register_intrs_and_init_mutex(ehci_state_t *ehcip) 7167c478bd9Sstevel@tonic-gate { 7179c75c6bfSgovinda int intr_types; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate #if defined(__x86) 7207c478bd9Sstevel@tonic-gate uint8_t iline; 7217c478bd9Sstevel@tonic-gate #endif 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7247c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex:"); 7257c478bd9Sstevel@tonic-gate 7269c75c6bfSgovinda /* 7279c75c6bfSgovinda * There is a known MSI hardware bug with the EHCI controller 7289c75c6bfSgovinda * of ULI1575 southbridge. Hence MSI is disabled for this chip. 7299c75c6bfSgovinda */ 7309c75c6bfSgovinda if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) && 7319c75c6bfSgovinda (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) { 7329c75c6bfSgovinda ehcip->ehci_msi_enabled = B_FALSE; 7339c75c6bfSgovinda } else { 7349c75c6bfSgovinda /* Set the MSI enable flag from the global EHCI MSI tunable */ 7359c75c6bfSgovinda ehcip->ehci_msi_enabled = ehci_enable_msi; 7369c75c6bfSgovinda } 7379c75c6bfSgovinda 73828cdc3d7Sszhou /* launch polling thread instead of enabling pci interrupt */ 73928cdc3d7Sszhou if (ehci_is_polled(ehcip->ehci_dip)) { 74028cdc3d7Sszhou extern pri_t maxclsyspri; 74128cdc3d7Sszhou 7428668df41Slg USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 74328cdc3d7Sszhou "ehci_register_intrs_and_init_mutex: " 74428cdc3d7Sszhou "running in simulated polled mode"); 74528cdc3d7Sszhou 74628cdc3d7Sszhou (void) thread_create(NULL, 0, ehci_poll_intr, ehcip, 0, &p0, 74728cdc3d7Sszhou TS_RUN, maxclsyspri); 74828cdc3d7Sszhou 74928cdc3d7Sszhou goto skip_intr; 75028cdc3d7Sszhou } 75128cdc3d7Sszhou 7527c478bd9Sstevel@tonic-gate #if defined(__x86) 7537c478bd9Sstevel@tonic-gate /* 7547c478bd9Sstevel@tonic-gate * Make sure that the interrupt pin is connected to the 7557c478bd9Sstevel@tonic-gate * interrupt controller on x86. Interrupt line 255 means 7567c478bd9Sstevel@tonic-gate * "unknown" or "not connected" (PCI spec 6.2.4, footnote 43). 7574610e4a0Sfrits * If we would return failure when interrupt line equals 255, then 758f87a10b6Syq * high speed devices will be routed to companion host controllers. 7594610e4a0Sfrits * However, it is not necessary to return failure here, and 7604610e4a0Sfrits * o/uhci codes don't check the interrupt line either. 7614610e4a0Sfrits * But it's good to log a message here for debug purposes. 7627c478bd9Sstevel@tonic-gate */ 7637c478bd9Sstevel@tonic-gate iline = pci_config_get8(ehcip->ehci_config_handle, 7647c478bd9Sstevel@tonic-gate PCI_CONF_ILINE); 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate if (iline == 255) { 7677c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7687c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 7697c478bd9Sstevel@tonic-gate "interrupt line value out of range (%d)", 7707c478bd9Sstevel@tonic-gate iline); 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate #endif /* __x86 */ 7737c478bd9Sstevel@tonic-gate 7749c75c6bfSgovinda /* Get supported interrupt types */ 7759c75c6bfSgovinda if (ddi_intr_get_supported_types(ehcip->ehci_dip, 7769c75c6bfSgovinda &intr_types) != DDI_SUCCESS) { 7777c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7787c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 7799c75c6bfSgovinda "ddi_intr_get_supported_types failed"); 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate 7849c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7859c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: " 7869c75c6bfSgovinda "supported interrupt types 0x%x", intr_types); 7879c75c6bfSgovinda 7889c75c6bfSgovinda if ((intr_types & DDI_INTR_TYPE_MSI) && ehcip->ehci_msi_enabled) { 7899c75c6bfSgovinda if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_MSI) 7909c75c6bfSgovinda != DDI_SUCCESS) { 7919c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7929c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: MSI " 7939c75c6bfSgovinda "registration failed, trying FIXED interrupt \n"); 7949c75c6bfSgovinda } else { 7959c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7969c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: " 7979c75c6bfSgovinda "Using MSI interrupt type\n"); 7989c75c6bfSgovinda 7999c75c6bfSgovinda ehcip->ehci_intr_type = DDI_INTR_TYPE_MSI; 8009c75c6bfSgovinda ehcip->ehci_flags |= EHCI_INTR; 8019c75c6bfSgovinda } 8029c75c6bfSgovinda } 8037c478bd9Sstevel@tonic-gate 8049c75c6bfSgovinda if ((!(ehcip->ehci_flags & EHCI_INTR)) && 8059c75c6bfSgovinda (intr_types & DDI_INTR_TYPE_FIXED)) { 8069c75c6bfSgovinda if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_FIXED) 8079c75c6bfSgovinda != DDI_SUCCESS) { 8089c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8099c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: " 8109c75c6bfSgovinda "FIXED interrupt registration failed\n"); 8119c75c6bfSgovinda 8129c75c6bfSgovinda return (DDI_FAILURE); 8139c75c6bfSgovinda } 8149c75c6bfSgovinda 8159c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8167c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 8179c75c6bfSgovinda "Using FIXED interrupt type\n"); 8189c75c6bfSgovinda 8199c75c6bfSgovinda ehcip->ehci_intr_type = DDI_INTR_TYPE_FIXED; 8209c75c6bfSgovinda ehcip->ehci_flags |= EHCI_INTR; 8219c75c6bfSgovinda } 8229c75c6bfSgovinda 82328cdc3d7Sszhou skip_intr: 8249c75c6bfSgovinda /* Create prototype for advance on async schedule */ 8259c75c6bfSgovinda cv_init(&ehcip->ehci_async_schedule_advance_cv, 8269c75c6bfSgovinda NULL, CV_DRIVER, NULL); 8279c75c6bfSgovinda 8289c75c6bfSgovinda return (DDI_SUCCESS); 8299c75c6bfSgovinda } 8309c75c6bfSgovinda 8319c75c6bfSgovinda 8329c75c6bfSgovinda /* 8339c75c6bfSgovinda * ehci_add_intrs: 8349c75c6bfSgovinda * 8359c75c6bfSgovinda * Register FIXED or MSI interrupts. 8369c75c6bfSgovinda */ 8379c75c6bfSgovinda static int 8389c75c6bfSgovinda ehci_add_intrs(ehci_state_t *ehcip, 8399c75c6bfSgovinda int intr_type) 8409c75c6bfSgovinda { 8419c75c6bfSgovinda int actual, avail, intr_size, count = 0; 84229aca3ebSlc int i, flag, ret; 8439c75c6bfSgovinda 8449c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8459c75c6bfSgovinda "ehci_add_intrs: interrupt type 0x%x", intr_type); 8469c75c6bfSgovinda 8479c75c6bfSgovinda /* Get number of interrupts */ 8489c75c6bfSgovinda ret = ddi_intr_get_nintrs(ehcip->ehci_dip, intr_type, &count); 8499c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (count == 0)) { 8509c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8519c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_nintrs() failure, " 8529c75c6bfSgovinda "ret: %d, count: %d", ret, count); 8539c75c6bfSgovinda 8549c75c6bfSgovinda return (DDI_FAILURE); 8559c75c6bfSgovinda } 8569c75c6bfSgovinda 8579c75c6bfSgovinda /* Get number of available interrupts */ 8589c75c6bfSgovinda ret = ddi_intr_get_navail(ehcip->ehci_dip, intr_type, &avail); 8599c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (avail == 0)) { 8609c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8619c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_navail() failure, " 8629c75c6bfSgovinda "ret: %d, count: %d", ret, count); 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate 8679c75c6bfSgovinda if (avail < count) { 8689c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8699c75c6bfSgovinda "ehci_add_intrs: ehci_add_intrs: nintrs () " 8709c75c6bfSgovinda "returned %d, navail returned %d\n", count, avail); 8719c75c6bfSgovinda } 8729c75c6bfSgovinda 8739c75c6bfSgovinda /* Allocate an array of interrupt handles */ 8749c75c6bfSgovinda intr_size = count * sizeof (ddi_intr_handle_t); 8759c75c6bfSgovinda ehcip->ehci_htable = kmem_zalloc(intr_size, KM_SLEEP); 8769c75c6bfSgovinda 8779c75c6bfSgovinda flag = (intr_type == DDI_INTR_TYPE_MSI) ? 8789c75c6bfSgovinda DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL; 8799c75c6bfSgovinda 8809c75c6bfSgovinda /* call ddi_intr_alloc() */ 8817c478bd9Sstevel@tonic-gate ret = ddi_intr_alloc(ehcip->ehci_dip, ehcip->ehci_htable, 8829c75c6bfSgovinda intr_type, 0, count, &actual, flag); 8837c478bd9Sstevel@tonic-gate 8849c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (actual == 0)) { 8857c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8869c75c6bfSgovinda "ehci_add_intrs: ddi_intr_alloc() failed %d", ret); 8877c478bd9Sstevel@tonic-gate 8889c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate 8939c75c6bfSgovinda if (actual < count) { 8949c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8959c75c6bfSgovinda "ehci_add_intrs: Requested: %d, Received: %d\n", 8969c75c6bfSgovinda count, actual); 8979c75c6bfSgovinda 8989c75c6bfSgovinda for (i = 0; i < actual; i++) 8999c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 9009c75c6bfSgovinda 9019c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 9029c75c6bfSgovinda 9039c75c6bfSgovinda return (DDI_FAILURE); 9049c75c6bfSgovinda } 9057c478bd9Sstevel@tonic-gate 9069c75c6bfSgovinda ehcip->ehci_intr_cnt = actual; 9079c75c6bfSgovinda 9089c75c6bfSgovinda if ((ret = ddi_intr_get_pri(ehcip->ehci_htable[0], 9099c75c6bfSgovinda &ehcip->ehci_intr_pri)) != DDI_SUCCESS) { 9107c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9119c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_pri() failed %d", ret); 9129c75c6bfSgovinda 9139c75c6bfSgovinda for (i = 0; i < actual; i++) 9149c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 9157c478bd9Sstevel@tonic-gate 9169c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9197c478bd9Sstevel@tonic-gate } 9207c478bd9Sstevel@tonic-gate 9219c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9229c75c6bfSgovinda "ehci_add_intrs: Supported Interrupt priority 0x%x", 9239c75c6bfSgovinda ehcip->ehci_intr_pri); 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate /* Test for high level mutex */ 9267c478bd9Sstevel@tonic-gate if (ehcip->ehci_intr_pri >= ddi_intr_get_hilevel_pri()) { 9277c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9289c75c6bfSgovinda "ehci_add_intrs: Hi level interrupt not supported"); 9299c75c6bfSgovinda 9309c75c6bfSgovinda for (i = 0; i < actual; i++) 9319c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 9327c478bd9Sstevel@tonic-gate 9339c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9367c478bd9Sstevel@tonic-gate } 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate /* Initialize the mutex */ 9397c478bd9Sstevel@tonic-gate mutex_init(&ehcip->ehci_int_mutex, NULL, MUTEX_DRIVER, 940a195726fSgovinda DDI_INTR_PRI(ehcip->ehci_intr_pri)); 9417c478bd9Sstevel@tonic-gate 9429c75c6bfSgovinda /* Call ddi_intr_add_handler() */ 9439c75c6bfSgovinda for (i = 0; i < actual; i++) { 9449c75c6bfSgovinda if ((ret = ddi_intr_add_handler(ehcip->ehci_htable[i], 9459c75c6bfSgovinda ehci_intr, (caddr_t)ehcip, 9469c75c6bfSgovinda (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 9479c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9489c75c6bfSgovinda "ehci_add_intrs:ddi_intr_add_handler() " 9499c75c6bfSgovinda "failed %d", ret); 9507c478bd9Sstevel@tonic-gate 9519c75c6bfSgovinda for (i = 0; i < actual; i++) 9529c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 9537c478bd9Sstevel@tonic-gate 9549c75c6bfSgovinda mutex_destroy(&ehcip->ehci_int_mutex); 9559c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 9569c75c6bfSgovinda 9579c75c6bfSgovinda return (DDI_FAILURE); 9589c75c6bfSgovinda } 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate 9619c75c6bfSgovinda if ((ret = ddi_intr_get_cap(ehcip->ehci_htable[0], 9629c75c6bfSgovinda &ehcip->ehci_intr_cap)) != DDI_SUCCESS) { 9637c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9649c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_cap() failed %d", ret); 9659c75c6bfSgovinda 9669c75c6bfSgovinda for (i = 0; i < actual; i++) { 9679c75c6bfSgovinda (void) ddi_intr_remove_handler(ehcip->ehci_htable[i]); 9689c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 9699c75c6bfSgovinda } 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate mutex_destroy(&ehcip->ehci_int_mutex); 9729c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate 9779c75c6bfSgovinda /* Enable all interrupts */ 9789c75c6bfSgovinda if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) { 9799c75c6bfSgovinda /* Call ddi_intr_block_enable() for MSI interrupts */ 9809c75c6bfSgovinda (void) ddi_intr_block_enable(ehcip->ehci_htable, 9819c75c6bfSgovinda ehcip->ehci_intr_cnt); 9829c75c6bfSgovinda } else { 9839c75c6bfSgovinda /* Call ddi_intr_enable for MSI or FIXED interrupts */ 9849c75c6bfSgovinda for (i = 0; i < ehcip->ehci_intr_cnt; i++) 9859c75c6bfSgovinda (void) ddi_intr_enable(ehcip->ehci_htable[i]); 9869c75c6bfSgovinda } 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate /* 9933b00f311Syq * ehci_init_hardware 9947c478bd9Sstevel@tonic-gate * 9953b00f311Syq * take control from BIOS, reset EHCI host controller, and check version, etc. 9967c478bd9Sstevel@tonic-gate */ 9977c478bd9Sstevel@tonic-gate int 9983b00f311Syq ehci_init_hardware(ehci_state_t *ehcip) 9997c478bd9Sstevel@tonic-gate { 10007c478bd9Sstevel@tonic-gate int revision; 10017c478bd9Sstevel@tonic-gate uint16_t cmd_reg; 10027c478bd9Sstevel@tonic-gate int abort_on_BIOS_take_over_failure; 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate /* Take control from the BIOS */ 10057c478bd9Sstevel@tonic-gate if (ehci_take_control(ehcip) != USB_SUCCESS) { 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate /* read .conf file properties */ 10087c478bd9Sstevel@tonic-gate abort_on_BIOS_take_over_failure = 100929aca3ebSlc ddi_prop_get_int(DDI_DEV_T_ANY, 101029aca3ebSlc ehcip->ehci_dip, DDI_PROP_DONTPASS, 101129aca3ebSlc "abort-on-BIOS-take-over-failure", 0); 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate if (abort_on_BIOS_take_over_failure) { 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 10167c478bd9Sstevel@tonic-gate "Unable to take control from BIOS."); 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 10227c478bd9Sstevel@tonic-gate "Unable to take control from BIOS. Failure is ignored."); 10237c478bd9Sstevel@tonic-gate } 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate /* set Memory Master Enable */ 10267c478bd9Sstevel@tonic-gate cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM); 10277c478bd9Sstevel@tonic-gate cmd_reg |= (PCI_COMM_MAE | PCI_COMM_ME); 10287c478bd9Sstevel@tonic-gate pci_config_put16(ehcip->ehci_config_handle, PCI_CONF_COMM, cmd_reg); 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate /* Reset the EHCI host controller */ 10317c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 10327c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) | EHCI_CMD_HOST_CTRL_RESET); 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate /* Wait 10ms for reset to complete */ 10357c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT); 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED); 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate /* Verify the version number */ 10407c478bd9Sstevel@tonic-gate revision = Get_16Cap(ehci_version); 10417c478bd9Sstevel@tonic-gate 10423b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 10433b00f311Syq "ehci_init_hardware: Revision 0x%x", revision); 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate /* 10467c478bd9Sstevel@tonic-gate * EHCI driver supports EHCI host controllers compliant to 10477c478bd9Sstevel@tonic-gate * 0.95 and higher revisions of EHCI specifications. 10487c478bd9Sstevel@tonic-gate */ 10497c478bd9Sstevel@tonic-gate if (revision < EHCI_REVISION_0_95) { 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 10527c478bd9Sstevel@tonic-gate "Revision 0x%x is not supported", revision); 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10557c478bd9Sstevel@tonic-gate } 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate if (ehcip->ehci_hc_soft_state == EHCI_CTLR_INIT_STATE) { 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate /* Initialize the Frame list base address area */ 10607c478bd9Sstevel@tonic-gate if (ehci_init_periodic_frame_lst_table(ehcip) != DDI_SUCCESS) { 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10637c478bd9Sstevel@tonic-gate } 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate /* 10667c478bd9Sstevel@tonic-gate * For performance reasons, do not insert anything into the 10677c478bd9Sstevel@tonic-gate * asynchronous list or activate the asynch list schedule until 10687c478bd9Sstevel@tonic-gate * there is a valid QH. 10697c478bd9Sstevel@tonic-gate */ 10707c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list = NULL; 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) && 10737c478bd9Sstevel@tonic-gate (ehci_vt62x2_workaround & EHCI_VIA_ASYNC_SCHEDULE)) { 10747c478bd9Sstevel@tonic-gate /* 10757c478bd9Sstevel@tonic-gate * The driver is unable to reliably stop the asynch 10767c478bd9Sstevel@tonic-gate * list schedule on VIA VT6202 controllers, so we 10777c478bd9Sstevel@tonic-gate * always keep a dummy QH on the list. 10787c478bd9Sstevel@tonic-gate */ 10797c478bd9Sstevel@tonic-gate ehci_qh_t *dummy_async_qh = 10807c478bd9Sstevel@tonic-gate ehci_alloc_qh(ehcip, NULL, NULL); 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_link_ptr, 10837c478bd9Sstevel@tonic-gate ((ehci_qh_cpu_to_iommu(ehcip, dummy_async_qh) & 10847c478bd9Sstevel@tonic-gate EHCI_QH_LINK_PTR) | EHCI_QH_LINK_REF_QH)); 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate /* Set this QH to be the "head" of the circular list */ 10877c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_ctrl, 10887c478bd9Sstevel@tonic-gate Get_QH(dummy_async_qh->qh_ctrl) | 10897c478bd9Sstevel@tonic-gate EHCI_QH_CTRL_RECLAIM_HEAD); 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_next_qtd, 10927c478bd9Sstevel@tonic-gate EHCI_QH_NEXT_QTD_PTR_VALID); 10937c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_alt_next_qtd, 10947c478bd9Sstevel@tonic-gate EHCI_QH_ALT_NEXT_QTD_PTR_VALID); 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list = dummy_async_qh; 10977c478bd9Sstevel@tonic-gate ehcip->ehci_open_async_count++; 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate 11013b00f311Syq return (DDI_SUCCESS); 11023b00f311Syq } 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate 11053b00f311Syq /* 11063b00f311Syq * ehci_init_workaround 11073b00f311Syq * 11083b00f311Syq * some workarounds during initializing ehci 11093b00f311Syq */ 11103b00f311Syq int 11113b00f311Syq ehci_init_workaround(ehci_state_t *ehcip) 11123b00f311Syq { 11137c478bd9Sstevel@tonic-gate /* 11147c478bd9Sstevel@tonic-gate * Acer Labs Inc. M5273 EHCI controller does not send 11157c478bd9Sstevel@tonic-gate * interrupts unless the Root hub ports are routed to the EHCI 11167c478bd9Sstevel@tonic-gate * host controller; so route the ports now, before we test for 11177c478bd9Sstevel@tonic-gate * the presence of SOFs interrupts. 11187c478bd9Sstevel@tonic-gate */ 11197c478bd9Sstevel@tonic-gate if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) { 112029aca3ebSlc /* Route all Root hub ports to EHCI host controller */ 112129aca3ebSlc Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI); 11227c478bd9Sstevel@tonic-gate } 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate /* 11257c478bd9Sstevel@tonic-gate * VIA chips have some issues and may not work reliably. 1126677739beShx * Revisions >= 0x80 are part of a southbridge and appear 1127677739beShx * to be reliable with the workaround. 11284610e4a0Sfrits * For revisions < 0x80, if we were bound using class 1129677739beShx * complain, else proceed. This will allow the user to 1130677739beShx * bind ehci specifically to this chip and not have the 1131677739beShx * warnings 11327c478bd9Sstevel@tonic-gate */ 1133677739beShx if (ehcip->ehci_vendor_id == PCI_VENDOR_VIA) { 1134677739beShx 113529aca3ebSlc if (ehcip->ehci_rev_id >= PCI_VIA_REVISION_6212) { 1136677739beShx 1137fffe0b30Sqz USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1138fffe0b30Sqz "ehci_init_workaround: Applying VIA workarounds " 1139fffe0b30Sqz "for the 6212 chip."); 1140677739beShx 114129aca3ebSlc } else if (strcmp(DEVI(ehcip->ehci_dip)->devi_binding_name, 1142fffe0b30Sqz "pciclass,0c0320") == 0) { 1143677739beShx 1144fffe0b30Sqz USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1145fffe0b30Sqz "Due to recently discovered incompatibilities"); 1146fffe0b30Sqz USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1147fffe0b30Sqz "with this USB controller, USB2.x transfer"); 1148fffe0b30Sqz USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1149fffe0b30Sqz "support has been disabled. This device will"); 1150fffe0b30Sqz USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1151fffe0b30Sqz "continue to function as a USB1.x controller."); 1152fffe0b30Sqz USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1153fffe0b30Sqz "If you are interested in enabling USB2.x"); 1154fffe0b30Sqz USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1155fffe0b30Sqz "support please, refer to the ehci(7D) man page."); 1156fffe0b30Sqz USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1157fffe0b30Sqz "Please also refer to www.sun.com/io for"); 1158fffe0b30Sqz USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1159fffe0b30Sqz "Solaris Ready products and to"); 1160fffe0b30Sqz USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1161fffe0b30Sqz "www.sun.com/bigadmin/hcl for additional"); 1162fffe0b30Sqz USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1163fffe0b30Sqz "compatible USB products."); 11647c478bd9Sstevel@tonic-gate 1165fffe0b30Sqz return (DDI_FAILURE); 1166677739beShx 1167fffe0b30Sqz } else if (ehci_vt62x2_workaround) { 1168677739beShx 1169fffe0b30Sqz USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1170fffe0b30Sqz "Applying VIA workarounds"); 117129aca3ebSlc } 11727c478bd9Sstevel@tonic-gate } 11737c478bd9Sstevel@tonic-gate 11743b00f311Syq return (DDI_SUCCESS); 11753b00f311Syq } 11763b00f311Syq 11773b00f311Syq 11783b00f311Syq /* 11793b00f311Syq * ehci_init_check_status 11803b00f311Syq * 11813b00f311Syq * Check if EHCI host controller is running 11823b00f311Syq */ 11833b00f311Syq int 11843b00f311Syq ehci_init_check_status(ehci_state_t *ehcip) 11853b00f311Syq { 11863b00f311Syq clock_t sof_time_wait; 11873b00f311Syq 11887c478bd9Sstevel@tonic-gate /* 11897c478bd9Sstevel@tonic-gate * Get the number of clock ticks to wait. 11907c478bd9Sstevel@tonic-gate * This is based on the maximum time it takes for a frame list rollover 11917c478bd9Sstevel@tonic-gate * and maximum time wait for SOFs to begin. 11927c478bd9Sstevel@tonic-gate */ 11937c478bd9Sstevel@tonic-gate sof_time_wait = drv_usectohz((EHCI_NUM_PERIODIC_FRAME_LISTS * 1000) + 11947c478bd9Sstevel@tonic-gate EHCI_SOF_TIMEWAIT); 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate /* Tell the ISR to broadcast ehci_async_schedule_advance_cv */ 11977c478bd9Sstevel@tonic-gate ehcip->ehci_flags |= EHCI_CV_INTR; 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate /* We need to add a delay to allow the chip time to start running */ 12007c478bd9Sstevel@tonic-gate (void) cv_timedwait(&ehcip->ehci_async_schedule_advance_cv, 12017c478bd9Sstevel@tonic-gate &ehcip->ehci_int_mutex, ddi_get_lbolt() + sof_time_wait); 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate /* 12047c478bd9Sstevel@tonic-gate * Check EHCI host controller is running, otherwise return failure. 12057c478bd9Sstevel@tonic-gate */ 12067c478bd9Sstevel@tonic-gate if ((ehcip->ehci_flags & EHCI_CV_INTR) || 12077c478bd9Sstevel@tonic-gate (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) { 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 12107c478bd9Sstevel@tonic-gate "No SOF interrupts have been received, this USB EHCI host" 12117c478bd9Sstevel@tonic-gate "controller is unusable"); 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate /* 12147c478bd9Sstevel@tonic-gate * Route all Root hub ports to Classic host 12157c478bd9Sstevel@tonic-gate * controller, in case this is an unusable ALI M5273 12167c478bd9Sstevel@tonic-gate * EHCI controller. 12177c478bd9Sstevel@tonic-gate */ 12187c478bd9Sstevel@tonic-gate if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) { 12197c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC); 12207c478bd9Sstevel@tonic-gate } 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 12237c478bd9Sstevel@tonic-gate } 12247c478bd9Sstevel@tonic-gate 12253b00f311Syq return (DDI_SUCCESS); 12263b00f311Syq } 12273b00f311Syq 12283b00f311Syq 12293b00f311Syq /* 12303b00f311Syq * ehci_init_ctlr: 12313b00f311Syq * 12323b00f311Syq * Initialize the Host Controller (HC). 12333b00f311Syq */ 12343b00f311Syq int 12353b00f311Syq ehci_init_ctlr(ehci_state_t *ehcip, 12363b00f311Syq int init_type) 12373b00f311Syq { 12383b00f311Syq USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_init_ctlr:"); 12393b00f311Syq 12403b00f311Syq if (init_type == EHCI_NORMAL_INITIALIZATION) { 12413b00f311Syq 12423b00f311Syq if (ehci_init_hardware(ehcip) != DDI_SUCCESS) { 12433b00f311Syq 12443b00f311Syq return (DDI_FAILURE); 12453b00f311Syq } 12463b00f311Syq } 12473b00f311Syq 12483b00f311Syq /* 12493b00f311Syq * Check for Asynchronous schedule park capability feature. If this 12503b00f311Syq * feature is supported, then, program ehci command register with 12513b00f311Syq * appropriate values.. 12523b00f311Syq */ 12533b00f311Syq if (Get_Cap(ehci_hcc_params) & EHCI_HCC_ASYNC_SCHED_PARK_CAP) { 12543b00f311Syq 12553b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 12563b00f311Syq "ehci_init_ctlr: Async park mode is supported"); 12573b00f311Syq 12583b00f311Syq Set_OpReg(ehci_command, (Get_OpReg(ehci_command) | 12593b00f311Syq (EHCI_CMD_ASYNC_PARK_ENABLE | 12603b00f311Syq EHCI_CMD_ASYNC_PARK_COUNT_3))); 12613b00f311Syq } 12623b00f311Syq 12633b00f311Syq /* 12643b00f311Syq * Check for programmable periodic frame list feature. If this 12653b00f311Syq * feature is supported, then, program ehci command register with 12663b00f311Syq * 1024 frame list value. 12673b00f311Syq */ 12683b00f311Syq if (Get_Cap(ehci_hcc_params) & EHCI_HCC_PROG_FRAME_LIST_FLAG) { 12693b00f311Syq 12703b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 12713b00f311Syq "ehci_init_ctlr: Variable programmable periodic " 12723b00f311Syq "frame list is supported"); 12733b00f311Syq 12743b00f311Syq Set_OpReg(ehci_command, (Get_OpReg(ehci_command) | 12753b00f311Syq EHCI_CMD_FRAME_1024_SIZE)); 12763b00f311Syq } 12773b00f311Syq 12783b00f311Syq /* 12793b00f311Syq * Currently EHCI driver doesn't support 64 bit addressing. 12803b00f311Syq * 12813b00f311Syq * If we are using 64 bit addressing capability, then, program 12823b00f311Syq * ehci_ctrl_segment register with 4 Gigabyte segment where all 12833b00f311Syq * of the interface data structures are allocated. 12843b00f311Syq */ 12853b00f311Syq if (Get_Cap(ehci_hcc_params) & EHCI_HCC_64BIT_ADDR_CAP) { 12863b00f311Syq 12873b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 12883b00f311Syq "ehci_init_ctlr: EHCI driver doesn't support " 12893b00f311Syq "64 bit addressing"); 12903b00f311Syq } 12913b00f311Syq 12923b00f311Syq /* 64 bit addressing is not support */ 12933b00f311Syq Set_OpReg(ehci_ctrl_segment, 0x00000000); 12943b00f311Syq 12953b00f311Syq /* Turn on/off the schedulers */ 12963b00f311Syq ehci_toggle_scheduler(ehcip); 12973b00f311Syq 1298fffe0b30Sqz /* Set host controller soft state to operational */ 1299fffe0b30Sqz ehcip->ehci_hc_soft_state = EHCI_CTLR_OPERATIONAL_STATE; 1300fffe0b30Sqz 13013b00f311Syq /* 13023b00f311Syq * Set the Periodic Frame List Base Address register with the 13033b00f311Syq * starting physical address of the Periodic Frame List. 13043b00f311Syq */ 13053b00f311Syq Set_OpReg(ehci_periodic_list_base, 13063b00f311Syq (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address & 130729aca3ebSlc EHCI_PERIODIC_LIST_BASE)); 13083b00f311Syq 13093b00f311Syq /* 13103b00f311Syq * Set ehci_interrupt to enable all interrupts except Root 13113b00f311Syq * Hub Status change interrupt. 13123b00f311Syq */ 13133b00f311Syq Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR | 13143b00f311Syq EHCI_INTR_FRAME_LIST_ROLLOVER | EHCI_INTR_USB_ERROR | 13153b00f311Syq EHCI_INTR_USB); 13163b00f311Syq 13173b00f311Syq /* 13183b00f311Syq * Set the desired interrupt threshold and turn on EHCI host controller. 13193b00f311Syq */ 13203b00f311Syq Set_OpReg(ehci_command, 13213b00f311Syq ((Get_OpReg(ehci_command) & ~EHCI_CMD_INTR_THRESHOLD) | 132229aca3ebSlc (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN))); 13233b00f311Syq 13243b00f311Syq ASSERT(Get_OpReg(ehci_command) & EHCI_CMD_HOST_CTRL_RUN); 13253b00f311Syq 13263b00f311Syq if (init_type == EHCI_NORMAL_INITIALIZATION) { 13273b00f311Syq 13283b00f311Syq if (ehci_init_workaround(ehcip) != DDI_SUCCESS) { 13293b00f311Syq 1330fffe0b30Sqz /* Set host controller soft state to error */ 1331fffe0b30Sqz ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE; 1332fffe0b30Sqz 13333b00f311Syq return (DDI_FAILURE); 13343b00f311Syq } 13353b00f311Syq 13363b00f311Syq if (ehci_init_check_status(ehcip) != DDI_SUCCESS) { 13373b00f311Syq 1338fffe0b30Sqz /* Set host controller soft state to error */ 1339fffe0b30Sqz ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE; 1340fffe0b30Sqz 13413b00f311Syq return (DDI_FAILURE); 13423b00f311Syq } 13433b00f311Syq 13443b00f311Syq USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 13453b00f311Syq "ehci_init_ctlr: SOF's have started"); 13463b00f311Syq } 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate /* Route all Root hub ports to EHCI host controller */ 13497c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI); 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 13527c478bd9Sstevel@tonic-gate } 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate /* 13557c478bd9Sstevel@tonic-gate * ehci_take_control: 13567c478bd9Sstevel@tonic-gate * 13577c478bd9Sstevel@tonic-gate * Handshake to take EHCI control from BIOS if necessary. Its only valid for 13587c478bd9Sstevel@tonic-gate * x86 machines, because sparc doesn't have a BIOS. 13597c478bd9Sstevel@tonic-gate * On x86 machine, the take control process includes 13607c478bd9Sstevel@tonic-gate * o get the base address of the extended capability list 13617c478bd9Sstevel@tonic-gate * o find out the capability for handoff synchronization in the list. 13627c478bd9Sstevel@tonic-gate * o check if BIOS has owned the host controller. 13637c478bd9Sstevel@tonic-gate * o set the OS Owned semaphore bit, ask the BIOS to release the ownership. 13647c478bd9Sstevel@tonic-gate * o wait for a constant time and check if BIOS has relinquished control. 13657c478bd9Sstevel@tonic-gate */ 13667c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13677c478bd9Sstevel@tonic-gate static int 13687c478bd9Sstevel@tonic-gate ehci_take_control(ehci_state_t *ehcip) 13697c478bd9Sstevel@tonic-gate { 13707c478bd9Sstevel@tonic-gate #if defined(__x86) 13717c478bd9Sstevel@tonic-gate uint32_t extended_cap; 13727c478bd9Sstevel@tonic-gate uint32_t extended_cap_offset; 13737c478bd9Sstevel@tonic-gate uint32_t extended_cap_id; 13747c478bd9Sstevel@tonic-gate uint_t retry; 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 13777c478bd9Sstevel@tonic-gate "ehci_take_control:"); 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate /* 13807c478bd9Sstevel@tonic-gate * According EHCI Spec 2.2.4, get EECP base address from HCCPARAMS 13817c478bd9Sstevel@tonic-gate * register. 13827c478bd9Sstevel@tonic-gate */ 13837c478bd9Sstevel@tonic-gate extended_cap_offset = (Get_Cap(ehci_hcc_params) & EHCI_HCC_EECP) >> 13847c478bd9Sstevel@tonic-gate EHCI_HCC_EECP_SHIFT; 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate /* 13877c478bd9Sstevel@tonic-gate * According EHCI Spec 2.2.4, if the extended capability offset is 13887c478bd9Sstevel@tonic-gate * less than 40h then its not valid. This means we don't need to 13897c478bd9Sstevel@tonic-gate * worry about BIOS handoff. 13907c478bd9Sstevel@tonic-gate */ 13917c478bd9Sstevel@tonic-gate if (extended_cap_offset < EHCI_HCC_EECP_MIN_OFFSET) { 13927c478bd9Sstevel@tonic-gate 13937c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 13947c478bd9Sstevel@tonic-gate "ehci_take_control: Hardware doesn't support legacy."); 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate goto success; 13977c478bd9Sstevel@tonic-gate } 13987c478bd9Sstevel@tonic-gate 13997c478bd9Sstevel@tonic-gate /* 14007c478bd9Sstevel@tonic-gate * According EHCI Spec 2.1.7, A zero offset indicates the 14017c478bd9Sstevel@tonic-gate * end of the extended capability list. 14027c478bd9Sstevel@tonic-gate */ 14037c478bd9Sstevel@tonic-gate while (extended_cap_offset) { 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate /* Get the extended capability value. */ 14067c478bd9Sstevel@tonic-gate extended_cap = pci_config_get32(ehcip->ehci_config_handle, 14077c478bd9Sstevel@tonic-gate extended_cap_offset); 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate /* Get the capability ID */ 14107c478bd9Sstevel@tonic-gate extended_cap_id = (extended_cap & EHCI_EX_CAP_ID) >> 14117c478bd9Sstevel@tonic-gate EHCI_EX_CAP_ID_SHIFT; 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate /* Check if the card support legacy */ 14147c478bd9Sstevel@tonic-gate if (extended_cap_id == EHCI_EX_CAP_ID_BIOS_HANDOFF) { 14157c478bd9Sstevel@tonic-gate break; 14167c478bd9Sstevel@tonic-gate } 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate /* Get the offset of the next capability */ 14197c478bd9Sstevel@tonic-gate extended_cap_offset = (extended_cap & EHCI_EX_CAP_NEXT_PTR) >> 14207c478bd9Sstevel@tonic-gate EHCI_EX_CAP_NEXT_PTR_SHIFT; 14217c478bd9Sstevel@tonic-gate } 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate /* 14247c478bd9Sstevel@tonic-gate * Unable to find legacy support in hardware's extended capability list. 14257c478bd9Sstevel@tonic-gate * This means we don't need to worry about BIOS handoff. 14267c478bd9Sstevel@tonic-gate */ 14277c478bd9Sstevel@tonic-gate if (extended_cap_id != EHCI_EX_CAP_ID_BIOS_HANDOFF) { 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 14307c478bd9Sstevel@tonic-gate "ehci_take_control: Hardware doesn't support legacy"); 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate goto success; 14337c478bd9Sstevel@tonic-gate } 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate /* Check if BIOS has owned it. */ 14367c478bd9Sstevel@tonic-gate if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) { 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 14397c478bd9Sstevel@tonic-gate "ehci_take_control: BIOS does not own EHCI"); 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate goto success; 14427c478bd9Sstevel@tonic-gate } 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate /* 14457c478bd9Sstevel@tonic-gate * According EHCI Spec 5.1, The OS driver initiates an ownership 14467c478bd9Sstevel@tonic-gate * request by setting the OS Owned semaphore to a one. The OS 14477c478bd9Sstevel@tonic-gate * waits for the BIOS Owned bit to go to a zero before attempting 14487c478bd9Sstevel@tonic-gate * to use the EHCI controller. The time that OS must wait for BIOS 14497c478bd9Sstevel@tonic-gate * to respond to the request for ownership is beyond the scope of 14507c478bd9Sstevel@tonic-gate * this specification. 14517c478bd9Sstevel@tonic-gate * It waits up to EHCI_TAKEOVER_WAIT_COUNT*EHCI_TAKEOVER_DELAY ms 14527c478bd9Sstevel@tonic-gate * for BIOS to release the ownership. 14537c478bd9Sstevel@tonic-gate */ 14547c478bd9Sstevel@tonic-gate extended_cap |= EHCI_LEGSUP_OS_OWNED_SEM; 14557c478bd9Sstevel@tonic-gate pci_config_put32(ehcip->ehci_config_handle, extended_cap_offset, 14567c478bd9Sstevel@tonic-gate extended_cap); 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate for (retry = 0; retry < EHCI_TAKEOVER_WAIT_COUNT; retry++) { 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate /* wait a special interval */ 14614ebb14b2Sfrits #ifndef __lock_lint 14627c478bd9Sstevel@tonic-gate delay(drv_usectohz(EHCI_TAKEOVER_DELAY)); 14634ebb14b2Sfrits #endif 14647c478bd9Sstevel@tonic-gate /* Check to see if the BIOS has released the ownership */ 14657c478bd9Sstevel@tonic-gate extended_cap = pci_config_get32( 14667c478bd9Sstevel@tonic-gate ehcip->ehci_config_handle, extended_cap_offset); 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) { 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, 14717c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 14727c478bd9Sstevel@tonic-gate "ehci_take_control: BIOS has released " 14737c478bd9Sstevel@tonic-gate "the ownership. retry = %d", retry); 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate goto success; 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate } 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 14817c478bd9Sstevel@tonic-gate "ehci_take_control: take control from BIOS failed."); 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate return (USB_FAILURE); 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate success: 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate #endif /* __x86 */ 14887c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 14897c478bd9Sstevel@tonic-gate } 14907c478bd9Sstevel@tonic-gate 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate /* 14937c478bd9Sstevel@tonic-gate * ehci_init_periodic_frame_list_table : 14947c478bd9Sstevel@tonic-gate * 14957c478bd9Sstevel@tonic-gate * Allocate the system memory and initialize Host Controller 14967c478bd9Sstevel@tonic-gate * Periodic Frame List table area. The starting of the Periodic 14977c478bd9Sstevel@tonic-gate * Frame List Table area must be 4096 byte aligned. 14987c478bd9Sstevel@tonic-gate */ 14997c478bd9Sstevel@tonic-gate static int 15007c478bd9Sstevel@tonic-gate ehci_init_periodic_frame_lst_table(ehci_state_t *ehcip) 15017c478bd9Sstevel@tonic-gate { 15027c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 15037c478bd9Sstevel@tonic-gate size_t real_length; 15047c478bd9Sstevel@tonic-gate uint_t ccount; 15057c478bd9Sstevel@tonic-gate int result; 15067c478bd9Sstevel@tonic-gate 15077c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 15087c478bd9Sstevel@tonic-gate 15097c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 15107c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table:"); 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 15137c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 15147c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 15157c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 15167c478bd9Sstevel@tonic-gate 15177c478bd9Sstevel@tonic-gate /* Force the required 4K restrictive alignment */ 15187c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_PFL_ALIGNMENT; 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate /* Create space for the Periodic Frame List */ 15217c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr, 15227c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 0, &ehcip->ehci_pflt_dma_handle) != DDI_SUCCESS) { 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate goto failure; 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_pflt_dma_handle, 15287c478bd9Sstevel@tonic-gate sizeof (ehci_periodic_frame_list_t), 15297c478bd9Sstevel@tonic-gate &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 15307c478bd9Sstevel@tonic-gate 0, (caddr_t *)&ehcip->ehci_periodic_frame_list_tablep, 15317c478bd9Sstevel@tonic-gate &real_length, &ehcip->ehci_pflt_mem_handle)) { 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate goto failure; 15347c478bd9Sstevel@tonic-gate } 15357c478bd9Sstevel@tonic-gate 15363b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 15377c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: " 15387c478bd9Sstevel@tonic-gate "Real length %lu", real_length); 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate /* Map the whole Periodic Frame List into the I/O address space */ 15417c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ehcip->ehci_pflt_dma_handle, 15427c478bd9Sstevel@tonic-gate NULL, (caddr_t)ehcip->ehci_periodic_frame_list_tablep, 15437c478bd9Sstevel@tonic-gate real_length, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 15447c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, &ehcip->ehci_pflt_cookie, &ccount); 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 15477c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 15487c478bd9Sstevel@tonic-gate if (ccount != 1) { 15497c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 15507c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: " 15517c478bd9Sstevel@tonic-gate "More than 1 cookie"); 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate goto failure; 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate } else { 15567c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result); 15577c478bd9Sstevel@tonic-gate 15587c478bd9Sstevel@tonic-gate goto failure; 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 15627c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: virtual 0x%p physical 0x%x", 15637c478bd9Sstevel@tonic-gate (void *)ehcip->ehci_periodic_frame_list_tablep, 15647c478bd9Sstevel@tonic-gate ehcip->ehci_pflt_cookie.dmac_address); 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate /* 15677c478bd9Sstevel@tonic-gate * DMA addresses for Periodic Frame List are bound. 15687c478bd9Sstevel@tonic-gate */ 15697c478bd9Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_PFLT_DMA_BOUND; 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate bzero((void *)ehcip->ehci_periodic_frame_list_tablep, real_length); 15727c478bd9Sstevel@tonic-gate 15737c478bd9Sstevel@tonic-gate /* Initialize the Periodic Frame List */ 15747c478bd9Sstevel@tonic-gate ehci_build_interrupt_lattice(ehcip); 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate /* Reset Byte Alignment to Default */ 15777c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 15787c478bd9Sstevel@tonic-gate 15797c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 15807c478bd9Sstevel@tonic-gate failure: 15817c478bd9Sstevel@tonic-gate /* Byte alignment */ 15827c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15857c478bd9Sstevel@tonic-gate } 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate 15887c478bd9Sstevel@tonic-gate /* 15897c478bd9Sstevel@tonic-gate * ehci_build_interrupt_lattice: 15907c478bd9Sstevel@tonic-gate * 15917c478bd9Sstevel@tonic-gate * Construct the interrupt lattice tree using static Endpoint Descriptors 15927c478bd9Sstevel@tonic-gate * (QH). This interrupt lattice tree will have total of 32 interrupt QH 15937c478bd9Sstevel@tonic-gate * lists and the Host Controller (HC) processes one interrupt QH list in 15947c478bd9Sstevel@tonic-gate * every frame. The Host Controller traverses the periodic schedule by 15957c478bd9Sstevel@tonic-gate * constructing an array offset reference from the Periodic List Base Address 15967c478bd9Sstevel@tonic-gate * register and bits 12 to 3 of Frame Index register. It fetches the element 15977c478bd9Sstevel@tonic-gate * and begins traversing the graph of linked schedule data structures. 15987c478bd9Sstevel@tonic-gate */ 15997c478bd9Sstevel@tonic-gate static void 16007c478bd9Sstevel@tonic-gate ehci_build_interrupt_lattice(ehci_state_t *ehcip) 16017c478bd9Sstevel@tonic-gate { 16027c478bd9Sstevel@tonic-gate ehci_qh_t *list_array = ehcip->ehci_qh_pool_addr; 16037c478bd9Sstevel@tonic-gate ushort_t ehci_index[EHCI_NUM_PERIODIC_FRAME_LISTS]; 16047c478bd9Sstevel@tonic-gate ehci_periodic_frame_list_t *periodic_frame_list = 160529aca3ebSlc ehcip->ehci_periodic_frame_list_tablep; 16067c478bd9Sstevel@tonic-gate ushort_t *temp, num_of_nodes; 16077c478bd9Sstevel@tonic-gate uintptr_t addr; 16087c478bd9Sstevel@tonic-gate int i, j, k; 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 16117c478bd9Sstevel@tonic-gate "ehci_build_interrupt_lattice:"); 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate /* 16147c478bd9Sstevel@tonic-gate * Reserve the first 63 Endpoint Descriptor (QH) structures 16157c478bd9Sstevel@tonic-gate * in the pool as static endpoints & these are required for 16167c478bd9Sstevel@tonic-gate * constructing interrupt lattice tree. 16177c478bd9Sstevel@tonic-gate */ 16187c478bd9Sstevel@tonic-gate for (i = 0; i < EHCI_NUM_STATIC_NODES; i++) { 16197c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_state, EHCI_QH_STATIC); 16207c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_status, EHCI_QH_STS_HALTED); 16217c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_next_qtd, EHCI_QH_NEXT_QTD_PTR_VALID); 16227c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_alt_next_qtd, 16237c478bd9Sstevel@tonic-gate EHCI_QH_ALT_NEXT_QTD_PTR_VALID); 16247c478bd9Sstevel@tonic-gate } 16257c478bd9Sstevel@tonic-gate 16267c478bd9Sstevel@tonic-gate /* 16277c478bd9Sstevel@tonic-gate * Make sure that last Endpoint on the periodic frame list terminates 16287c478bd9Sstevel@tonic-gate * periodic schedule. 16297c478bd9Sstevel@tonic-gate */ 16307c478bd9Sstevel@tonic-gate Set_QH(list_array[0].qh_link_ptr, EHCI_QH_LINK_PTR_VALID); 16317c478bd9Sstevel@tonic-gate 16327c478bd9Sstevel@tonic-gate /* Build the interrupt lattice tree */ 16337c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_STATIC_NODES / 2); i++) { 16347c478bd9Sstevel@tonic-gate /* 16357c478bd9Sstevel@tonic-gate * The next pointer in the host controller endpoint 16367c478bd9Sstevel@tonic-gate * descriptor must contain an iommu address. Calculate 16377c478bd9Sstevel@tonic-gate * the offset into the cpu address and add this to the 16387c478bd9Sstevel@tonic-gate * starting iommu address. 16397c478bd9Sstevel@tonic-gate */ 16407c478bd9Sstevel@tonic-gate addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *)&list_array[i]); 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate Set_QH(list_array[2*i + 1].qh_link_ptr, 16437c478bd9Sstevel@tonic-gate addr | EHCI_QH_LINK_REF_QH); 16447c478bd9Sstevel@tonic-gate Set_QH(list_array[2*i + 2].qh_link_ptr, 16457c478bd9Sstevel@tonic-gate addr | EHCI_QH_LINK_REF_QH); 16467c478bd9Sstevel@tonic-gate } 16477c478bd9Sstevel@tonic-gate 16487c478bd9Sstevel@tonic-gate /* Build the tree bottom */ 16497c478bd9Sstevel@tonic-gate temp = (unsigned short *) 16507c478bd9Sstevel@tonic-gate kmem_zalloc(EHCI_NUM_PERIODIC_FRAME_LISTS * 2, KM_SLEEP); 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate num_of_nodes = 1; 16537c478bd9Sstevel@tonic-gate 16547c478bd9Sstevel@tonic-gate /* 16557c478bd9Sstevel@tonic-gate * Initialize the values which are used for setting up head pointers 16567c478bd9Sstevel@tonic-gate * for the 32ms scheduling lists which starts from the Periodic Frame 16577c478bd9Sstevel@tonic-gate * List. 16587c478bd9Sstevel@tonic-gate */ 16597c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_log_2(EHCI_NUM_PERIODIC_FRAME_LISTS); i++) { 16607c478bd9Sstevel@tonic-gate for (j = 0, k = 0; k < num_of_nodes; k++, j++) { 16617c478bd9Sstevel@tonic-gate ehci_index[j++] = temp[k]; 16627c478bd9Sstevel@tonic-gate ehci_index[j] = temp[k] + ehci_pow_2(i); 16637c478bd9Sstevel@tonic-gate } 16647c478bd9Sstevel@tonic-gate 16657c478bd9Sstevel@tonic-gate num_of_nodes *= 2; 16667c478bd9Sstevel@tonic-gate for (k = 0; k < num_of_nodes; k++) 16677c478bd9Sstevel@tonic-gate temp[k] = ehci_index[k]; 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate kmem_free((void *)temp, (EHCI_NUM_PERIODIC_FRAME_LISTS * 2)); 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate /* 16737c478bd9Sstevel@tonic-gate * Initialize the interrupt list in the Periodic Frame List Table 16747c478bd9Sstevel@tonic-gate * so that it points to the bottom of the tree. 16757c478bd9Sstevel@tonic-gate */ 16767c478bd9Sstevel@tonic-gate for (i = 0, j = 0; i < ehci_pow_2(TREE_HEIGHT); i++) { 16777c478bd9Sstevel@tonic-gate addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *) 16787c478bd9Sstevel@tonic-gate (&list_array[((EHCI_NUM_STATIC_NODES + 1) / 2) + i - 1])); 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate ASSERT(addr); 16817c478bd9Sstevel@tonic-gate 16827c478bd9Sstevel@tonic-gate for (k = 0; k < ehci_pow_2(TREE_HEIGHT); k++) { 16837c478bd9Sstevel@tonic-gate Set_PFLT(periodic_frame_list-> 16847c478bd9Sstevel@tonic-gate ehci_periodic_frame_list_table[ehci_index[j++]], 16857c478bd9Sstevel@tonic-gate (uint32_t)(addr | EHCI_QH_LINK_REF_QH)); 16867c478bd9Sstevel@tonic-gate } 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate } 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate /* 16927c478bd9Sstevel@tonic-gate * ehci_alloc_hcdi_ops: 16937c478bd9Sstevel@tonic-gate * 16947c478bd9Sstevel@tonic-gate * The HCDI interfaces or entry points are the software interfaces used by 16957c478bd9Sstevel@tonic-gate * the Universal Serial Bus Driver (USBA) to access the services of the 16967c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD). During HCD initialization, inform USBA 16977c478bd9Sstevel@tonic-gate * about all available HCDI interfaces or entry points. 16987c478bd9Sstevel@tonic-gate */ 16997c478bd9Sstevel@tonic-gate usba_hcdi_ops_t * 17007c478bd9Sstevel@tonic-gate ehci_alloc_hcdi_ops(ehci_state_t *ehcip) 17017c478bd9Sstevel@tonic-gate { 17027c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *usba_hcdi_ops; 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 17057c478bd9Sstevel@tonic-gate "ehci_alloc_hcdi_ops:"); 17067c478bd9Sstevel@tonic-gate 17077c478bd9Sstevel@tonic-gate usba_hcdi_ops = usba_alloc_hcdi_ops(); 17087c478bd9Sstevel@tonic-gate 17097c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_ops_version = HCDI_OPS_VERSION; 17107c478bd9Sstevel@tonic-gate 17114610e4a0Sfrits usba_hcdi_ops->usba_hcdi_pm_support = ehci_hcdi_pm_support; 17127c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_open = ehci_hcdi_pipe_open; 17137c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_close = ehci_hcdi_pipe_close; 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_reset = ehci_hcdi_pipe_reset; 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_ctrl_xfer = ehci_hcdi_pipe_ctrl_xfer; 17187c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_bulk_xfer = ehci_hcdi_pipe_bulk_xfer; 17197c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_intr_xfer = ehci_hcdi_pipe_intr_xfer; 17207c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_isoc_xfer = ehci_hcdi_pipe_isoc_xfer; 17217c478bd9Sstevel@tonic-gate 17227c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_bulk_transfer_size = 172329aca3ebSlc ehci_hcdi_bulk_transfer_size; 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_intr_polling = 172629aca3ebSlc ehci_hcdi_pipe_stop_intr_polling; 17277c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_isoc_polling = 172829aca3ebSlc ehci_hcdi_pipe_stop_isoc_polling; 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_current_frame_number = 173129aca3ebSlc ehci_hcdi_get_current_frame_number; 17327c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_max_isoc_pkts = 173329aca3ebSlc ehci_hcdi_get_max_isoc_pkts; 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_init = 173629aca3ebSlc ehci_hcdi_polled_input_init; 17377c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_enter = 173829aca3ebSlc ehci_hcdi_polled_input_enter; 17397c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_read = 174029aca3ebSlc ehci_hcdi_polled_read; 17417c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_exit = 174229aca3ebSlc ehci_hcdi_polled_input_exit; 17437c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_fini = 174429aca3ebSlc ehci_hcdi_polled_input_fini; 17457c478bd9Sstevel@tonic-gate return (usba_hcdi_ops); 17467c478bd9Sstevel@tonic-gate } 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate 17497c478bd9Sstevel@tonic-gate /* 17507c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) deinitialization functions 17517c478bd9Sstevel@tonic-gate */ 17527c478bd9Sstevel@tonic-gate 17537c478bd9Sstevel@tonic-gate /* 17547c478bd9Sstevel@tonic-gate * ehci_cleanup: 17557c478bd9Sstevel@tonic-gate * 17567c478bd9Sstevel@tonic-gate * Cleanup on attach failure or detach 17577c478bd9Sstevel@tonic-gate */ 17587c478bd9Sstevel@tonic-gate int 17597c478bd9Sstevel@tonic-gate ehci_cleanup(ehci_state_t *ehcip) 17607c478bd9Sstevel@tonic-gate { 17617c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw; 17627c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; 17637c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd; 17647c478bd9Sstevel@tonic-gate int i, ctrl, rval; 17657c478bd9Sstevel@tonic-gate int flags = ehcip->ehci_flags; 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_cleanup:"); 17687c478bd9Sstevel@tonic-gate 17697c478bd9Sstevel@tonic-gate if (flags & EHCI_RHREG) { 17707c478bd9Sstevel@tonic-gate /* Unload the root hub driver */ 17717c478bd9Sstevel@tonic-gate if (ehci_unload_root_hub_driver(ehcip) != USB_SUCCESS) { 17727c478bd9Sstevel@tonic-gate 17737c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 17747c478bd9Sstevel@tonic-gate } 17757c478bd9Sstevel@tonic-gate } 17767c478bd9Sstevel@tonic-gate 17777c478bd9Sstevel@tonic-gate if (flags & EHCI_USBAREG) { 17787c478bd9Sstevel@tonic-gate /* Unregister this HCD instance with USBA */ 17797c478bd9Sstevel@tonic-gate usba_hcdi_unregister(ehcip->ehci_dip); 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate if (flags & EHCI_INTR) { 17837c478bd9Sstevel@tonic-gate 17847c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 17857c478bd9Sstevel@tonic-gate 17867c478bd9Sstevel@tonic-gate /* Disable all EHCI QH list processing */ 17877c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) & 17887c478bd9Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | 17897c478bd9Sstevel@tonic-gate EHCI_CMD_PERIODIC_SCHED_ENABLE))); 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate /* Disable all EHCI interrupts */ 17927c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0); 17937c478bd9Sstevel@tonic-gate 17947c478bd9Sstevel@tonic-gate /* wait for the next SOF */ 17957c478bd9Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip); 17967c478bd9Sstevel@tonic-gate 17974610e4a0Sfrits /* Route all Root hub ports to Classic host controller */ 17984610e4a0Sfrits Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC); 17994610e4a0Sfrits 18007c478bd9Sstevel@tonic-gate /* Stop the EHCI host controller */ 18017c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 18027c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN); 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 18057c478bd9Sstevel@tonic-gate 180629aca3ebSlc /* Wait for sometime */ 180729aca3ebSlc delay(drv_usectohz(EHCI_TIMEWAIT)); 180829aca3ebSlc 18099c75c6bfSgovinda ehci_rem_intrs(ehcip); 18107c478bd9Sstevel@tonic-gate } 18117c478bd9Sstevel@tonic-gate 18127c478bd9Sstevel@tonic-gate /* Unmap the EHCI registers */ 18137c478bd9Sstevel@tonic-gate if (ehcip->ehci_caps_handle) { 18147c478bd9Sstevel@tonic-gate ddi_regs_map_free(&ehcip->ehci_caps_handle); 18157c478bd9Sstevel@tonic-gate } 18167c478bd9Sstevel@tonic-gate 18177c478bd9Sstevel@tonic-gate if (ehcip->ehci_config_handle) { 18187c478bd9Sstevel@tonic-gate pci_config_teardown(&ehcip->ehci_config_handle); 18197c478bd9Sstevel@tonic-gate } 18207c478bd9Sstevel@tonic-gate 18217c478bd9Sstevel@tonic-gate /* Free all the buffers */ 18227c478bd9Sstevel@tonic-gate if (ehcip->ehci_qtd_pool_addr && ehcip->ehci_qtd_pool_mem_handle) { 18237c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_qtd_pool_size; i ++) { 18247c478bd9Sstevel@tonic-gate qtd = &ehcip->ehci_qtd_pool_addr[i]; 18257c478bd9Sstevel@tonic-gate ctrl = Get_QTD(ehcip-> 18267c478bd9Sstevel@tonic-gate ehci_qtd_pool_addr[i].qtd_state); 18277c478bd9Sstevel@tonic-gate 18287c478bd9Sstevel@tonic-gate if ((ctrl != EHCI_QTD_FREE) && 18297c478bd9Sstevel@tonic-gate (ctrl != EHCI_QTD_DUMMY) && 18307c478bd9Sstevel@tonic-gate (qtd->qtd_trans_wrapper)) { 18317c478bd9Sstevel@tonic-gate 18327c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 18337c478bd9Sstevel@tonic-gate 18347c478bd9Sstevel@tonic-gate tw = (ehci_trans_wrapper_t *) 183529aca3ebSlc EHCI_LOOKUP_ID((uint32_t) 183629aca3ebSlc Get_QTD(qtd->qtd_trans_wrapper)); 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 18397c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */ 18427c478bd9Sstevel@tonic-gate ehci_stop_xfer_timer(ehcip, tw, 184329aca3ebSlc EHCI_REMOVE_XFER_ALWAYS); 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate ehci_deallocate_tw(ehcip, pp, tw); 18467c478bd9Sstevel@tonic-gate 18477c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 18487c478bd9Sstevel@tonic-gate } 18497c478bd9Sstevel@tonic-gate } 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate /* 18527c478bd9Sstevel@tonic-gate * If EHCI_QTD_POOL_BOUND flag is set, then unbind 18537c478bd9Sstevel@tonic-gate * the handle for QTD pools. 18547c478bd9Sstevel@tonic-gate */ 18557c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 18567c478bd9Sstevel@tonic-gate EHCI_QTD_POOL_BOUND) == EHCI_QTD_POOL_BOUND) { 18577c478bd9Sstevel@tonic-gate 18587c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 18597c478bd9Sstevel@tonic-gate ehcip->ehci_qtd_pool_dma_handle); 18607c478bd9Sstevel@tonic-gate 18617c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 18627c478bd9Sstevel@tonic-gate } 18637c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_qtd_pool_mem_handle); 18647c478bd9Sstevel@tonic-gate } 18657c478bd9Sstevel@tonic-gate 18667c478bd9Sstevel@tonic-gate /* Free the QTD pool */ 18677c478bd9Sstevel@tonic-gate if (ehcip->ehci_qtd_pool_dma_handle) { 18687c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_qtd_pool_dma_handle); 18697c478bd9Sstevel@tonic-gate } 18707c478bd9Sstevel@tonic-gate 18717c478bd9Sstevel@tonic-gate if (ehcip->ehci_qh_pool_addr && ehcip->ehci_qh_pool_mem_handle) { 18727c478bd9Sstevel@tonic-gate /* 18737c478bd9Sstevel@tonic-gate * If EHCI_QH_POOL_BOUND flag is set, then unbind 18747c478bd9Sstevel@tonic-gate * the handle for QH pools. 18757c478bd9Sstevel@tonic-gate */ 18767c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 18777c478bd9Sstevel@tonic-gate EHCI_QH_POOL_BOUND) == EHCI_QH_POOL_BOUND) { 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 18807c478bd9Sstevel@tonic-gate ehcip->ehci_qh_pool_dma_handle); 18817c478bd9Sstevel@tonic-gate 18827c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 18837c478bd9Sstevel@tonic-gate } 18847c478bd9Sstevel@tonic-gate 18857c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_qh_pool_mem_handle); 18867c478bd9Sstevel@tonic-gate } 18877c478bd9Sstevel@tonic-gate 18887c478bd9Sstevel@tonic-gate /* Free the QH pool */ 18897c478bd9Sstevel@tonic-gate if (ehcip->ehci_qh_pool_dma_handle) { 18907c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_qh_pool_dma_handle); 18917c478bd9Sstevel@tonic-gate } 18927c478bd9Sstevel@tonic-gate 18937c478bd9Sstevel@tonic-gate /* Free the Periodic frame list table (PFLT) area */ 18947c478bd9Sstevel@tonic-gate if (ehcip->ehci_periodic_frame_list_tablep && 18957c478bd9Sstevel@tonic-gate ehcip->ehci_pflt_mem_handle) { 18967c478bd9Sstevel@tonic-gate /* 18977c478bd9Sstevel@tonic-gate * If EHCI_PFLT_DMA_BOUND flag is set, then unbind 18987c478bd9Sstevel@tonic-gate * the handle for PFLT. 18997c478bd9Sstevel@tonic-gate */ 19007c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 19017c478bd9Sstevel@tonic-gate EHCI_PFLT_DMA_BOUND) == EHCI_PFLT_DMA_BOUND) { 19027c478bd9Sstevel@tonic-gate 19037c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 19047c478bd9Sstevel@tonic-gate ehcip->ehci_pflt_dma_handle); 19057c478bd9Sstevel@tonic-gate 19067c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 19077c478bd9Sstevel@tonic-gate } 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_pflt_mem_handle); 19107c478bd9Sstevel@tonic-gate } 19117c478bd9Sstevel@tonic-gate 19127c478bd9Sstevel@tonic-gate (void) ehci_isoc_cleanup(ehcip); 19137c478bd9Sstevel@tonic-gate 19147c478bd9Sstevel@tonic-gate if (ehcip->ehci_pflt_dma_handle) { 19157c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_pflt_dma_handle); 19167c478bd9Sstevel@tonic-gate } 19177c478bd9Sstevel@tonic-gate 19187c478bd9Sstevel@tonic-gate if (flags & EHCI_INTR) { 19197c478bd9Sstevel@tonic-gate /* Destroy the mutex */ 19207c478bd9Sstevel@tonic-gate mutex_destroy(&ehcip->ehci_int_mutex); 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate /* Destroy the async schedule advance condition variable */ 19237c478bd9Sstevel@tonic-gate cv_destroy(&ehcip->ehci_async_schedule_advance_cv); 19247c478bd9Sstevel@tonic-gate } 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate /* clean up kstat structs */ 19277c478bd9Sstevel@tonic-gate ehci_destroy_stats(ehcip); 19287c478bd9Sstevel@tonic-gate 19297c478bd9Sstevel@tonic-gate /* Free ehci hcdi ops */ 19307c478bd9Sstevel@tonic-gate if (ehcip->ehci_hcdi_ops) { 19317c478bd9Sstevel@tonic-gate usba_free_hcdi_ops(ehcip->ehci_hcdi_ops); 19327c478bd9Sstevel@tonic-gate } 19337c478bd9Sstevel@tonic-gate 19347c478bd9Sstevel@tonic-gate if (flags & EHCI_ZALLOC) { 19357c478bd9Sstevel@tonic-gate 19367c478bd9Sstevel@tonic-gate usb_free_log_hdl(ehcip->ehci_log_hdl); 19377c478bd9Sstevel@tonic-gate 19387c478bd9Sstevel@tonic-gate /* Remove all properties that might have been created */ 19397c478bd9Sstevel@tonic-gate ddi_prop_remove_all(ehcip->ehci_dip); 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate /* Free the soft state */ 19427c478bd9Sstevel@tonic-gate ddi_soft_state_free(ehci_statep, 194329aca3ebSlc ddi_get_instance(ehcip->ehci_dip)); 19447c478bd9Sstevel@tonic-gate } 19457c478bd9Sstevel@tonic-gate 19467c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 19477c478bd9Sstevel@tonic-gate } 19487c478bd9Sstevel@tonic-gate 19497c478bd9Sstevel@tonic-gate 19509c75c6bfSgovinda /* 19519c75c6bfSgovinda * ehci_rem_intrs: 19529c75c6bfSgovinda * 19539c75c6bfSgovinda * Unregister FIXED or MSI interrupts 19549c75c6bfSgovinda */ 19559c75c6bfSgovinda static void 19569c75c6bfSgovinda ehci_rem_intrs(ehci_state_t *ehcip) 19579c75c6bfSgovinda { 19589c75c6bfSgovinda int i; 19599c75c6bfSgovinda 19609c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19619c75c6bfSgovinda "ehci_rem_intrs: interrupt type 0x%x", ehcip->ehci_intr_type); 19629c75c6bfSgovinda 19639c75c6bfSgovinda /* Disable all interrupts */ 19649c75c6bfSgovinda if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) { 19659c75c6bfSgovinda (void) ddi_intr_block_disable(ehcip->ehci_htable, 19669c75c6bfSgovinda ehcip->ehci_intr_cnt); 19679c75c6bfSgovinda } else { 19689c75c6bfSgovinda for (i = 0; i < ehcip->ehci_intr_cnt; i++) { 19699c75c6bfSgovinda (void) ddi_intr_disable(ehcip->ehci_htable[i]); 19709c75c6bfSgovinda } 19719c75c6bfSgovinda } 19729c75c6bfSgovinda 19739c75c6bfSgovinda /* Call ddi_intr_remove_handler() */ 19749c75c6bfSgovinda for (i = 0; i < ehcip->ehci_intr_cnt; i++) { 19759c75c6bfSgovinda (void) ddi_intr_remove_handler(ehcip->ehci_htable[i]); 19769c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 19779c75c6bfSgovinda } 19789c75c6bfSgovinda 19799c75c6bfSgovinda kmem_free(ehcip->ehci_htable, 19809c75c6bfSgovinda ehcip->ehci_intr_cnt * sizeof (ddi_intr_handle_t)); 19819c75c6bfSgovinda } 19829c75c6bfSgovinda 19839c75c6bfSgovinda 19847c478bd9Sstevel@tonic-gate /* 19857c478bd9Sstevel@tonic-gate * ehci_cpr_suspend 19867c478bd9Sstevel@tonic-gate */ 19877c478bd9Sstevel@tonic-gate int 19887c478bd9Sstevel@tonic-gate ehci_cpr_suspend(ehci_state_t *ehcip) 19897c478bd9Sstevel@tonic-gate { 19907c478bd9Sstevel@tonic-gate int i; 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19937c478bd9Sstevel@tonic-gate "ehci_cpr_suspend:"); 19947c478bd9Sstevel@tonic-gate 19957c478bd9Sstevel@tonic-gate /* Call into the root hub and suspend it */ 19967c478bd9Sstevel@tonic-gate if (usba_hubdi_detach(ehcip->ehci_dip, DDI_SUSPEND) != DDI_SUCCESS) { 19977c478bd9Sstevel@tonic-gate 19987c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 199929aca3ebSlc "ehci_cpr_suspend: root hub fails to suspend"); 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 20027c478bd9Sstevel@tonic-gate } 20037c478bd9Sstevel@tonic-gate 20047c478bd9Sstevel@tonic-gate /* Only root hub's intr pipe should be open at this time */ 20057c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 20067c478bd9Sstevel@tonic-gate 20077c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_open_pipe_count == 0); 20087c478bd9Sstevel@tonic-gate 20097c478bd9Sstevel@tonic-gate /* Just wait till all resources are reclaimed */ 20107c478bd9Sstevel@tonic-gate i = 0; 20117c478bd9Sstevel@tonic-gate while ((ehcip->ehci_reclaim_list != NULL) && (i++ < 3)) { 20127c478bd9Sstevel@tonic-gate ehci_handle_endpoint_reclaimation(ehcip); 20137c478bd9Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip); 20147c478bd9Sstevel@tonic-gate } 20157c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_reclaim_list == NULL); 20167c478bd9Sstevel@tonic-gate 20173b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 20187c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: Disable HC QH list processing"); 20197c478bd9Sstevel@tonic-gate 20207c478bd9Sstevel@tonic-gate /* Disable all EHCI QH list processing */ 20217c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) & 20227c478bd9Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE))); 20237c478bd9Sstevel@tonic-gate 20243b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 20257c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: Disable HC interrupts"); 20267c478bd9Sstevel@tonic-gate 20277c478bd9Sstevel@tonic-gate /* Disable all EHCI interrupts */ 20287c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0); 20297c478bd9Sstevel@tonic-gate 20303b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 20317c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: Wait for the next SOF"); 20327c478bd9Sstevel@tonic-gate 20337c478bd9Sstevel@tonic-gate /* Wait for the next SOF */ 20347c478bd9Sstevel@tonic-gate if (ehci_wait_for_sof(ehcip) != USB_SUCCESS) { 20357c478bd9Sstevel@tonic-gate 20367c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 20377c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: ehci host controller suspend failed"); 20387c478bd9Sstevel@tonic-gate 20397c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 20407c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 20417c478bd9Sstevel@tonic-gate } 20427c478bd9Sstevel@tonic-gate 20437c478bd9Sstevel@tonic-gate /* 20447c478bd9Sstevel@tonic-gate * Stop the ehci host controller 20457c478bd9Sstevel@tonic-gate * if usb keyboard is not connected. 20467c478bd9Sstevel@tonic-gate */ 20472df1fe9cSrandyf if (ehcip->ehci_polled_kbd_count == 0 || force_ehci_off != 0) { 20487c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 20497c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN); 20507c478bd9Sstevel@tonic-gate } 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate /* Set host controller soft state to suspend */ 20537c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_SUSPEND_STATE; 20547c478bd9Sstevel@tonic-gate 20557c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 20567c478bd9Sstevel@tonic-gate 20577c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 20587c478bd9Sstevel@tonic-gate } 20597c478bd9Sstevel@tonic-gate 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate /* 20627c478bd9Sstevel@tonic-gate * ehci_cpr_resume 20637c478bd9Sstevel@tonic-gate */ 20647c478bd9Sstevel@tonic-gate int 20657c478bd9Sstevel@tonic-gate ehci_cpr_resume(ehci_state_t *ehcip) 20667c478bd9Sstevel@tonic-gate { 20677c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 20687c478bd9Sstevel@tonic-gate 20697c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 20707c478bd9Sstevel@tonic-gate "ehci_cpr_resume: Restart the controller"); 20717c478bd9Sstevel@tonic-gate 20727c478bd9Sstevel@tonic-gate /* Cleanup ehci specific information across cpr */ 20737c478bd9Sstevel@tonic-gate ehci_cpr_cleanup(ehcip); 20747c478bd9Sstevel@tonic-gate 20757c478bd9Sstevel@tonic-gate /* Restart the controller */ 20763b00f311Syq if (ehci_init_ctlr(ehcip, EHCI_NORMAL_INITIALIZATION) != DDI_SUCCESS) { 20777c478bd9Sstevel@tonic-gate 20787c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 20797c478bd9Sstevel@tonic-gate "ehci_cpr_resume: ehci host controller resume failed "); 20807c478bd9Sstevel@tonic-gate 20817c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 20847c478bd9Sstevel@tonic-gate } 20857c478bd9Sstevel@tonic-gate 20867c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 20877c478bd9Sstevel@tonic-gate 20887c478bd9Sstevel@tonic-gate /* Now resume the root hub */ 20897c478bd9Sstevel@tonic-gate if (usba_hubdi_attach(ehcip->ehci_dip, DDI_RESUME) != DDI_SUCCESS) { 20907c478bd9Sstevel@tonic-gate 20917c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 20927c478bd9Sstevel@tonic-gate } 20937c478bd9Sstevel@tonic-gate 20947c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 20957c478bd9Sstevel@tonic-gate } 20967c478bd9Sstevel@tonic-gate 20977c478bd9Sstevel@tonic-gate 20987c478bd9Sstevel@tonic-gate /* 20997c478bd9Sstevel@tonic-gate * Bandwidth Allocation functions 21007c478bd9Sstevel@tonic-gate */ 21017c478bd9Sstevel@tonic-gate 21027c478bd9Sstevel@tonic-gate /* 21037c478bd9Sstevel@tonic-gate * ehci_allocate_bandwidth: 21047c478bd9Sstevel@tonic-gate * 21057c478bd9Sstevel@tonic-gate * Figure out whether or not this interval may be supported. Return the index 21067c478bd9Sstevel@tonic-gate * into the lattice if it can be supported. Return allocation failure if it 21077c478bd9Sstevel@tonic-gate * can not be supported. 21087c478bd9Sstevel@tonic-gate */ 21097c478bd9Sstevel@tonic-gate int 21107c478bd9Sstevel@tonic-gate ehci_allocate_bandwidth( 21117c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 21127c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 21137c478bd9Sstevel@tonic-gate uint_t *pnode, 21147c478bd9Sstevel@tonic-gate uchar_t *smask, 21157c478bd9Sstevel@tonic-gate uchar_t *cmask) 21167c478bd9Sstevel@tonic-gate { 21177c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 21187c478bd9Sstevel@tonic-gate 21197c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 21207c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 21217c478bd9Sstevel@tonic-gate 21227c478bd9Sstevel@tonic-gate /* Reset the pnode to the last checked pnode */ 21237c478bd9Sstevel@tonic-gate *pnode = 0; 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate /* Allocate high speed bandwidth */ 21267c478bd9Sstevel@tonic-gate if ((error = ehci_allocate_high_speed_bandwidth(ehcip, 21277c478bd9Sstevel@tonic-gate ph, pnode, smask, cmask)) != USB_SUCCESS) { 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate return (error); 21307c478bd9Sstevel@tonic-gate } 21317c478bd9Sstevel@tonic-gate 21327c478bd9Sstevel@tonic-gate /* 21337c478bd9Sstevel@tonic-gate * For low/full speed usb devices, allocate classic TT bandwidth 21347c478bd9Sstevel@tonic-gate * in additional to high speed bandwidth. 21357c478bd9Sstevel@tonic-gate */ 21367c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) { 21377c478bd9Sstevel@tonic-gate 21387c478bd9Sstevel@tonic-gate /* Allocate classic TT bandwidth */ 21397c478bd9Sstevel@tonic-gate if ((error = ehci_allocate_classic_tt_bandwidth( 21407c478bd9Sstevel@tonic-gate ehcip, ph, *pnode)) != USB_SUCCESS) { 21417c478bd9Sstevel@tonic-gate 21427c478bd9Sstevel@tonic-gate /* Deallocate high speed bandwidth */ 21437c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth( 21447c478bd9Sstevel@tonic-gate ehcip, ph, *pnode, *smask, *cmask); 21457c478bd9Sstevel@tonic-gate } 21467c478bd9Sstevel@tonic-gate } 21477c478bd9Sstevel@tonic-gate 21487c478bd9Sstevel@tonic-gate return (error); 21497c478bd9Sstevel@tonic-gate } 21507c478bd9Sstevel@tonic-gate 21517c478bd9Sstevel@tonic-gate 21527c478bd9Sstevel@tonic-gate /* 21537c478bd9Sstevel@tonic-gate * ehci_allocate_high_speed_bandwidth: 21547c478bd9Sstevel@tonic-gate * 21557c478bd9Sstevel@tonic-gate * Allocate high speed bandwidth for the low/full/high speed interrupt and 21567c478bd9Sstevel@tonic-gate * isochronous endpoints. 21577c478bd9Sstevel@tonic-gate */ 21587c478bd9Sstevel@tonic-gate static int 21597c478bd9Sstevel@tonic-gate ehci_allocate_high_speed_bandwidth( 21607c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 21617c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 21627c478bd9Sstevel@tonic-gate uint_t *pnode, 21637c478bd9Sstevel@tonic-gate uchar_t *smask, 21647c478bd9Sstevel@tonic-gate uchar_t *cmask) 21657c478bd9Sstevel@tonic-gate { 21667c478bd9Sstevel@tonic-gate uint_t sbandwidth, cbandwidth; 21677c478bd9Sstevel@tonic-gate int interval; 21687c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 21697c478bd9Sstevel@tonic-gate usba_device_t *child_ud; 21707c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 21717c478bd9Sstevel@tonic-gate int error; 21727c478bd9Sstevel@tonic-gate 21737c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 21747c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 21757c478bd9Sstevel@tonic-gate 21767c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 21777c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 21787c478bd9Sstevel@tonic-gate 21797c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 21807c478bd9Sstevel@tonic-gate 21817c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 21827c478bd9Sstevel@tonic-gate port_status = ph->p_usba_device->usb_port_status; 21837c478bd9Sstevel@tonic-gate 21847c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 21857c478bd9Sstevel@tonic-gate 21867c478bd9Sstevel@tonic-gate /* 21877c478bd9Sstevel@tonic-gate * Calculate the length in bytes of a transaction on this 21887c478bd9Sstevel@tonic-gate * periodic endpoint. Return failure if maximum packet is 21897c478bd9Sstevel@tonic-gate * zero. 21907c478bd9Sstevel@tonic-gate */ 21917c478bd9Sstevel@tonic-gate error = ehci_compute_high_speed_bandwidth(ehcip, endpoint, 21927c478bd9Sstevel@tonic-gate port_status, &sbandwidth, &cbandwidth); 21937c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 21947c478bd9Sstevel@tonic-gate 21957c478bd9Sstevel@tonic-gate return (error); 21967c478bd9Sstevel@tonic-gate } 21977c478bd9Sstevel@tonic-gate 21987c478bd9Sstevel@tonic-gate /* 21997c478bd9Sstevel@tonic-gate * Adjust polling interval to be a power of 2. 22007c478bd9Sstevel@tonic-gate * If this interval can't be supported, return 22017c478bd9Sstevel@tonic-gate * allocation failure. 22027c478bd9Sstevel@tonic-gate */ 22037c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 22047c478bd9Sstevel@tonic-gate if (interval == USB_FAILURE) { 22057c478bd9Sstevel@tonic-gate 22067c478bd9Sstevel@tonic-gate return (USB_FAILURE); 22077c478bd9Sstevel@tonic-gate } 22087c478bd9Sstevel@tonic-gate 22097c478bd9Sstevel@tonic-gate if (port_status == USBA_HIGH_SPEED_DEV) { 2210b3001defSlg /* Allocate bandwidth for high speed devices */ 2211b3001defSlg if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) == 2212b3001defSlg USB_EP_ATTR_ISOCH) { 2213b3001defSlg error = USB_SUCCESS; 2214b3001defSlg } else { 2215b3001defSlg 2216b3001defSlg error = ehci_find_bestfit_hs_mask(ehcip, smask, pnode, 2217b3001defSlg endpoint, sbandwidth, interval); 2218b3001defSlg } 2219b3001defSlg 22207c478bd9Sstevel@tonic-gate *cmask = 0x00; 22217c478bd9Sstevel@tonic-gate 22227c478bd9Sstevel@tonic-gate } else { 22237c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) == 22247c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR) { 22257c478bd9Sstevel@tonic-gate 22267c478bd9Sstevel@tonic-gate /* Allocate bandwidth for low speed interrupt */ 22277c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_ls_intr_mask(ehcip, 22287c478bd9Sstevel@tonic-gate smask, cmask, pnode, sbandwidth, cbandwidth, 22297c478bd9Sstevel@tonic-gate interval); 22307c478bd9Sstevel@tonic-gate } else { 22317c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 22327c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 22337c478bd9Sstevel@tonic-gate 22347c478bd9Sstevel@tonic-gate /* Allocate bandwidth for sitd in */ 22357c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_sitd_in_mask(ehcip, 22367c478bd9Sstevel@tonic-gate smask, cmask, pnode, sbandwidth, cbandwidth, 22377c478bd9Sstevel@tonic-gate interval); 22387c478bd9Sstevel@tonic-gate } else { 22397c478bd9Sstevel@tonic-gate 22407c478bd9Sstevel@tonic-gate /* Allocate bandwidth for sitd out */ 22417c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_sitd_out_mask(ehcip, 22427c478bd9Sstevel@tonic-gate smask, pnode, sbandwidth, interval); 22437c478bd9Sstevel@tonic-gate *cmask = 0x00; 22447c478bd9Sstevel@tonic-gate } 22457c478bd9Sstevel@tonic-gate } 22467c478bd9Sstevel@tonic-gate } 22477c478bd9Sstevel@tonic-gate 22487c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 22497c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 22507c478bd9Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: Reached maximum " 22517c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth for a " 22527c478bd9Sstevel@tonic-gate "given high-speed periodic endpoint"); 22537c478bd9Sstevel@tonic-gate 22547c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 22557c478bd9Sstevel@tonic-gate } 22567c478bd9Sstevel@tonic-gate 22577c478bd9Sstevel@tonic-gate return (error); 22587c478bd9Sstevel@tonic-gate } 22597c478bd9Sstevel@tonic-gate 22607c478bd9Sstevel@tonic-gate 22617c478bd9Sstevel@tonic-gate /* 22627c478bd9Sstevel@tonic-gate * ehci_allocate_classic_tt_speed_bandwidth: 22637c478bd9Sstevel@tonic-gate * 22647c478bd9Sstevel@tonic-gate * Allocate classic TT bandwidth for the low/full speed interrupt and 22657c478bd9Sstevel@tonic-gate * isochronous endpoints. 22667c478bd9Sstevel@tonic-gate */ 22677c478bd9Sstevel@tonic-gate static int 22687c478bd9Sstevel@tonic-gate ehci_allocate_classic_tt_bandwidth( 22697c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 22707c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 22717c478bd9Sstevel@tonic-gate uint_t pnode) 22727c478bd9Sstevel@tonic-gate { 22737c478bd9Sstevel@tonic-gate uint_t bandwidth, min; 22747c478bd9Sstevel@tonic-gate uint_t height, leftmost, list; 22757c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 22767c478bd9Sstevel@tonic-gate usba_device_t *child_ud, *parent_ud; 22777c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 22787c478bd9Sstevel@tonic-gate int i, interval; 22797c478bd9Sstevel@tonic-gate 22807c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 22817c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 22827c478bd9Sstevel@tonic-gate 22837c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 22847c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 22857c478bd9Sstevel@tonic-gate 22867c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 22877c478bd9Sstevel@tonic-gate 22887c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 22897c478bd9Sstevel@tonic-gate port_status = child_ud->usb_port_status; 22907c478bd9Sstevel@tonic-gate 22917c478bd9Sstevel@tonic-gate /* Get the parent high speed hub's usba device structure */ 22927c478bd9Sstevel@tonic-gate parent_ud = child_ud->usb_hs_hub_usba_dev; 22937c478bd9Sstevel@tonic-gate 22947c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 22957c478bd9Sstevel@tonic-gate 22963b00f311Syq USB_DPRINTF_L3(PRINT_MASK_BW, ehcip->ehci_log_hdl, 22977c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: " 2298112116d8Sfb "child_ud 0x%p parent_ud 0x%p", 2299112116d8Sfb (void *)child_ud, (void *)parent_ud); 23007c478bd9Sstevel@tonic-gate 23017c478bd9Sstevel@tonic-gate /* 23027c478bd9Sstevel@tonic-gate * Calculate the length in bytes of a transaction on this 23037c478bd9Sstevel@tonic-gate * periodic endpoint. Return failure if maximum packet is 23047c478bd9Sstevel@tonic-gate * zero. 23057c478bd9Sstevel@tonic-gate */ 23067c478bd9Sstevel@tonic-gate if (ehci_compute_classic_bandwidth(endpoint, 23077c478bd9Sstevel@tonic-gate port_status, &bandwidth) != USB_SUCCESS) { 23087c478bd9Sstevel@tonic-gate 23097c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 23107c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Periodic endpoint " 23117c478bd9Sstevel@tonic-gate "with zero endpoint maximum packet size is not supported"); 23127c478bd9Sstevel@tonic-gate 23137c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 23147c478bd9Sstevel@tonic-gate } 23157c478bd9Sstevel@tonic-gate 23163b00f311Syq USB_DPRINTF_L3(PRINT_MASK_BW, ehcip->ehci_log_hdl, 23177c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: bandwidth %d", bandwidth); 23187c478bd9Sstevel@tonic-gate 23197c478bd9Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex); 23207c478bd9Sstevel@tonic-gate 23217c478bd9Sstevel@tonic-gate /* 23227c478bd9Sstevel@tonic-gate * If the length in bytes plus the allocated bandwidth exceeds 23237c478bd9Sstevel@tonic-gate * the maximum, return bandwidth allocation failure. 23247c478bd9Sstevel@tonic-gate */ 23257c478bd9Sstevel@tonic-gate if ((parent_ud->usb_hs_hub_min_bandwidth + bandwidth) > 23267c478bd9Sstevel@tonic-gate FS_PERIODIC_BANDWIDTH) { 23277c478bd9Sstevel@tonic-gate 23287c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 23297c478bd9Sstevel@tonic-gate 23307c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 23317c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Reached maximum " 23327c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth for a " 23337c478bd9Sstevel@tonic-gate "given low/full speed periodic endpoint"); 23347c478bd9Sstevel@tonic-gate 23357c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 23367c478bd9Sstevel@tonic-gate } 23377c478bd9Sstevel@tonic-gate 23387c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 23397c478bd9Sstevel@tonic-gate 23407c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 23417c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 23427c478bd9Sstevel@tonic-gate 23437c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 23447c478bd9Sstevel@tonic-gate height = ehci_lattice_height(interval); 23457c478bd9Sstevel@tonic-gate 23467c478bd9Sstevel@tonic-gate /* Find the leftmost leaf in the subtree specified by the node. */ 23477c478bd9Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height); 23487c478bd9Sstevel@tonic-gate 23497c478bd9Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex); 23507c478bd9Sstevel@tonic-gate 23517c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) { 23527c478bd9Sstevel@tonic-gate list = ehci_index[leftmost + i]; 23537c478bd9Sstevel@tonic-gate 23547c478bd9Sstevel@tonic-gate if ((parent_ud->usb_hs_hub_bandwidth[list] + 23557c478bd9Sstevel@tonic-gate bandwidth) > FS_PERIODIC_BANDWIDTH) { 23567c478bd9Sstevel@tonic-gate 23577c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 23587c478bd9Sstevel@tonic-gate 23597c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 23607c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Reached " 23617c478bd9Sstevel@tonic-gate "maximum bandwidth value and cannot allocate " 23627c478bd9Sstevel@tonic-gate "bandwidth for low/full periodic endpoint"); 23637c478bd9Sstevel@tonic-gate 23647c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 23657c478bd9Sstevel@tonic-gate } 23667c478bd9Sstevel@tonic-gate } 23677c478bd9Sstevel@tonic-gate 23687c478bd9Sstevel@tonic-gate /* 23697c478bd9Sstevel@tonic-gate * All the leaves for this node must be updated with the bandwidth. 23707c478bd9Sstevel@tonic-gate */ 23717c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) { 23727c478bd9Sstevel@tonic-gate list = ehci_index[leftmost + i]; 23737c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_bandwidth[list] += bandwidth; 23747c478bd9Sstevel@tonic-gate } 23757c478bd9Sstevel@tonic-gate 23767c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */ 23777c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[0]; 23787c478bd9Sstevel@tonic-gate 23797c478bd9Sstevel@tonic-gate for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) { 23807c478bd9Sstevel@tonic-gate if (parent_ud->usb_hs_hub_bandwidth[i] < min) { 23817c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[i]; 23827c478bd9Sstevel@tonic-gate } 23837c478bd9Sstevel@tonic-gate } 23847c478bd9Sstevel@tonic-gate 23857c478bd9Sstevel@tonic-gate /* Save the minimum for later use */ 23867c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_min_bandwidth = min; 23877c478bd9Sstevel@tonic-gate 23887c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 23897c478bd9Sstevel@tonic-gate 23907c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 23917c478bd9Sstevel@tonic-gate } 23927c478bd9Sstevel@tonic-gate 23937c478bd9Sstevel@tonic-gate 23947c478bd9Sstevel@tonic-gate /* 23957c478bd9Sstevel@tonic-gate * ehci_deallocate_bandwidth: 23967c478bd9Sstevel@tonic-gate * 23977c478bd9Sstevel@tonic-gate * Deallocate bandwidth for the given node in the lattice and the length 23987c478bd9Sstevel@tonic-gate * of transfer. 23997c478bd9Sstevel@tonic-gate */ 24007c478bd9Sstevel@tonic-gate void 24017c478bd9Sstevel@tonic-gate ehci_deallocate_bandwidth( 24027c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 24037c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 24047c478bd9Sstevel@tonic-gate uint_t pnode, 24057c478bd9Sstevel@tonic-gate uchar_t smask, 24067c478bd9Sstevel@tonic-gate uchar_t cmask) 24077c478bd9Sstevel@tonic-gate { 24087c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 24097c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 24107c478bd9Sstevel@tonic-gate 24117c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth(ehcip, ph, pnode, smask, cmask); 24127c478bd9Sstevel@tonic-gate 24137c478bd9Sstevel@tonic-gate /* 24147c478bd9Sstevel@tonic-gate * For low/full speed usb devices, deallocate classic TT bandwidth 24157c478bd9Sstevel@tonic-gate * in additional to high speed bandwidth. 24167c478bd9Sstevel@tonic-gate */ 24177c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) { 24187c478bd9Sstevel@tonic-gate 24197c478bd9Sstevel@tonic-gate /* Deallocate classic TT bandwidth */ 24207c478bd9Sstevel@tonic-gate ehci_deallocate_classic_tt_bandwidth(ehcip, ph, pnode); 24217c478bd9Sstevel@tonic-gate } 24227c478bd9Sstevel@tonic-gate } 24237c478bd9Sstevel@tonic-gate 24247c478bd9Sstevel@tonic-gate 24257c478bd9Sstevel@tonic-gate /* 24267c478bd9Sstevel@tonic-gate * ehci_deallocate_high_speed_bandwidth: 24277c478bd9Sstevel@tonic-gate * 24287c478bd9Sstevel@tonic-gate * Deallocate high speed bandwidth of a interrupt or isochronous endpoint. 24297c478bd9Sstevel@tonic-gate */ 24307c478bd9Sstevel@tonic-gate static void 24317c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth( 24327c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 24337c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 24347c478bd9Sstevel@tonic-gate uint_t pnode, 24357c478bd9Sstevel@tonic-gate uchar_t smask, 24367c478bd9Sstevel@tonic-gate uchar_t cmask) 24377c478bd9Sstevel@tonic-gate { 24387c478bd9Sstevel@tonic-gate uint_t height, leftmost; 24397c478bd9Sstevel@tonic-gate uint_t list_count; 24407c478bd9Sstevel@tonic-gate uint_t sbandwidth, cbandwidth; 24417c478bd9Sstevel@tonic-gate int interval; 24427c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 24437c478bd9Sstevel@tonic-gate usba_device_t *child_ud; 24447c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 24457c478bd9Sstevel@tonic-gate 24467c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 24477c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 24487c478bd9Sstevel@tonic-gate 24497c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 24507c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 24517c478bd9Sstevel@tonic-gate 24527c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 24537c478bd9Sstevel@tonic-gate 24547c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 24557c478bd9Sstevel@tonic-gate port_status = ph->p_usba_device->usb_port_status; 24567c478bd9Sstevel@tonic-gate 24577c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 24587c478bd9Sstevel@tonic-gate 24597c478bd9Sstevel@tonic-gate (void) ehci_compute_high_speed_bandwidth(ehcip, endpoint, 24607c478bd9Sstevel@tonic-gate port_status, &sbandwidth, &cbandwidth); 24617c478bd9Sstevel@tonic-gate 24627c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 24637c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 24647c478bd9Sstevel@tonic-gate 24657c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 24667c478bd9Sstevel@tonic-gate height = ehci_lattice_height(interval); 24677c478bd9Sstevel@tonic-gate 24687c478bd9Sstevel@tonic-gate /* 24697c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node 24707c478bd9Sstevel@tonic-gate */ 24717c478bd9Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height); 24727c478bd9Sstevel@tonic-gate 24737c478bd9Sstevel@tonic-gate list_count = EHCI_NUM_INTR_QH_LISTS/interval; 24747c478bd9Sstevel@tonic-gate 24757c478bd9Sstevel@tonic-gate /* Delete the bandwidth from the appropriate lists */ 24767c478bd9Sstevel@tonic-gate if (port_status == USBA_HIGH_SPEED_DEV) { 24777c478bd9Sstevel@tonic-gate 24787c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth, 24797c478bd9Sstevel@tonic-gate leftmost, list_count, smask); 24807c478bd9Sstevel@tonic-gate } else { 24817c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) == 24827c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR) { 24837c478bd9Sstevel@tonic-gate 24847c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth, 24857c478bd9Sstevel@tonic-gate leftmost, list_count, smask); 24867c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -cbandwidth, 24877c478bd9Sstevel@tonic-gate leftmost, list_count, cmask); 24887c478bd9Sstevel@tonic-gate } else { 24897c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 24907c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 24917c478bd9Sstevel@tonic-gate 24927c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth, 24937c478bd9Sstevel@tonic-gate leftmost, list_count, smask); 24947c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, 24957c478bd9Sstevel@tonic-gate -MAX_UFRAME_SITD_XFER, leftmost, 24967c478bd9Sstevel@tonic-gate list_count, cmask); 24977c478bd9Sstevel@tonic-gate } else { 24987c478bd9Sstevel@tonic-gate 24997c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, 25007c478bd9Sstevel@tonic-gate -MAX_UFRAME_SITD_XFER, leftmost, 25017c478bd9Sstevel@tonic-gate list_count, smask); 25027c478bd9Sstevel@tonic-gate } 25037c478bd9Sstevel@tonic-gate } 25047c478bd9Sstevel@tonic-gate } 25057c478bd9Sstevel@tonic-gate } 25067c478bd9Sstevel@tonic-gate 25077c478bd9Sstevel@tonic-gate /* 25087c478bd9Sstevel@tonic-gate * ehci_deallocate_classic_tt_bandwidth: 25097c478bd9Sstevel@tonic-gate * 25107c478bd9Sstevel@tonic-gate * Deallocate high speed bandwidth of a interrupt or isochronous endpoint. 25117c478bd9Sstevel@tonic-gate */ 25127c478bd9Sstevel@tonic-gate static void 25137c478bd9Sstevel@tonic-gate ehci_deallocate_classic_tt_bandwidth( 25147c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 25157c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 25167c478bd9Sstevel@tonic-gate uint_t pnode) 25177c478bd9Sstevel@tonic-gate { 25187c478bd9Sstevel@tonic-gate uint_t bandwidth, height, leftmost, list, min; 25197c478bd9Sstevel@tonic-gate int i, interval; 25207c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 25217c478bd9Sstevel@tonic-gate usba_device_t *child_ud, *parent_ud; 25227c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 25237c478bd9Sstevel@tonic-gate 25247c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 25257c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 25267c478bd9Sstevel@tonic-gate 25277c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 25287c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 25297c478bd9Sstevel@tonic-gate 25307c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 25317c478bd9Sstevel@tonic-gate 25327c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 25337c478bd9Sstevel@tonic-gate port_status = child_ud->usb_port_status; 25347c478bd9Sstevel@tonic-gate 25357c478bd9Sstevel@tonic-gate /* Get the parent high speed hub's usba device structure */ 25367c478bd9Sstevel@tonic-gate parent_ud = child_ud->usb_hs_hub_usba_dev; 25377c478bd9Sstevel@tonic-gate 25387c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 25397c478bd9Sstevel@tonic-gate 25407c478bd9Sstevel@tonic-gate /* Obtain the bandwidth */ 25417c478bd9Sstevel@tonic-gate (void) ehci_compute_classic_bandwidth(endpoint, 25427c478bd9Sstevel@tonic-gate port_status, &bandwidth); 25437c478bd9Sstevel@tonic-gate 25447c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 25457c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 25467c478bd9Sstevel@tonic-gate 25477c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 25487c478bd9Sstevel@tonic-gate height = ehci_lattice_height(interval); 25497c478bd9Sstevel@tonic-gate 25507c478bd9Sstevel@tonic-gate /* Find the leftmost leaf in the subtree specified by the node */ 25517c478bd9Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height); 25527c478bd9Sstevel@tonic-gate 25537c478bd9Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex); 25547c478bd9Sstevel@tonic-gate 25557c478bd9Sstevel@tonic-gate /* Delete the bandwidth from the appropriate lists */ 25567c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) { 25577c478bd9Sstevel@tonic-gate list = ehci_index[leftmost + i]; 25587c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_bandwidth[list] -= bandwidth; 25597c478bd9Sstevel@tonic-gate } 25607c478bd9Sstevel@tonic-gate 25617c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */ 25627c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[0]; 25637c478bd9Sstevel@tonic-gate 25647c478bd9Sstevel@tonic-gate for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) { 25657c478bd9Sstevel@tonic-gate if (parent_ud->usb_hs_hub_bandwidth[i] < min) { 25667c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[i]; 25677c478bd9Sstevel@tonic-gate } 25687c478bd9Sstevel@tonic-gate } 25697c478bd9Sstevel@tonic-gate 25707c478bd9Sstevel@tonic-gate /* Save the minimum for later use */ 25717c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_min_bandwidth = min; 25727c478bd9Sstevel@tonic-gate 25737c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 25747c478bd9Sstevel@tonic-gate } 25757c478bd9Sstevel@tonic-gate 25767c478bd9Sstevel@tonic-gate 25777c478bd9Sstevel@tonic-gate /* 25787c478bd9Sstevel@tonic-gate * ehci_compute_high_speed_bandwidth: 25797c478bd9Sstevel@tonic-gate * 25807c478bd9Sstevel@tonic-gate * Given a periodic endpoint (interrupt or isochronous) determine the total 25817c478bd9Sstevel@tonic-gate * bandwidth for one transaction. The EHCI host controller traverses the 25827c478bd9Sstevel@tonic-gate * endpoint descriptor lists on a first-come-first-serve basis. When the HC 25837c478bd9Sstevel@tonic-gate * services an endpoint, only a single transaction attempt is made. The HC 25847c478bd9Sstevel@tonic-gate * moves to the next Endpoint Descriptor after the first transaction attempt 25857c478bd9Sstevel@tonic-gate * rather than finishing the entire Transfer Descriptor. Therefore, when a 25867c478bd9Sstevel@tonic-gate * Transfer Descriptor is inserted into the lattice, we will only count the 25877c478bd9Sstevel@tonic-gate * number of bytes for one transaction. 25887c478bd9Sstevel@tonic-gate * 25897c478bd9Sstevel@tonic-gate * The following are the formulas used for calculating bandwidth in terms 25907c478bd9Sstevel@tonic-gate * bytes and it is for the single USB high speed transaction. The protocol 25917c478bd9Sstevel@tonic-gate * overheads will be different for each of type of USB transfer & all these 25927c478bd9Sstevel@tonic-gate * formulas & protocol overheads are derived from the 5.11.3 section of the 25937c478bd9Sstevel@tonic-gate * USB 2.0 Specification. 25947c478bd9Sstevel@tonic-gate * 25957c478bd9Sstevel@tonic-gate * High-Speed: 25967c478bd9Sstevel@tonic-gate * Protocol overhead + ((MaxPktSz * 7)/6) + Host_Delay 25977c478bd9Sstevel@tonic-gate * 25987c478bd9Sstevel@tonic-gate * Split Transaction: (Low/Full speed devices connected behind usb2.0 hub) 25997c478bd9Sstevel@tonic-gate * 26007c478bd9Sstevel@tonic-gate * Protocol overhead + Split transaction overhead + 26017c478bd9Sstevel@tonic-gate * ((MaxPktSz * 7)/6) + Host_Delay; 26027c478bd9Sstevel@tonic-gate */ 26037c478bd9Sstevel@tonic-gate /* ARGSUSED */ 26047c478bd9Sstevel@tonic-gate static int 26057c478bd9Sstevel@tonic-gate ehci_compute_high_speed_bandwidth( 26067c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 26077c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 26087c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 26097c478bd9Sstevel@tonic-gate uint_t *sbandwidth, 26107c478bd9Sstevel@tonic-gate uint_t *cbandwidth) 26117c478bd9Sstevel@tonic-gate { 26127c478bd9Sstevel@tonic-gate ushort_t maxpacketsize = endpoint->wMaxPacketSize; 26137c478bd9Sstevel@tonic-gate 26147c478bd9Sstevel@tonic-gate /* Return failure if endpoint maximum packet is zero */ 26157c478bd9Sstevel@tonic-gate if (maxpacketsize == 0) { 26167c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 26177c478bd9Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: Periodic endpoint " 26187c478bd9Sstevel@tonic-gate "with zero endpoint maximum packet size is not supported"); 26197c478bd9Sstevel@tonic-gate 26207c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 26217c478bd9Sstevel@tonic-gate } 26227c478bd9Sstevel@tonic-gate 26237c478bd9Sstevel@tonic-gate /* Add bit-stuffing overhead */ 26247c478bd9Sstevel@tonic-gate maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6); 26257c478bd9Sstevel@tonic-gate 26267c478bd9Sstevel@tonic-gate /* Add Host Controller specific delay to required bandwidth */ 26277c478bd9Sstevel@tonic-gate *sbandwidth = EHCI_HOST_CONTROLLER_DELAY; 26287c478bd9Sstevel@tonic-gate 26297c478bd9Sstevel@tonic-gate /* Add xfer specific protocol overheads */ 26307c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 26317c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) { 26327c478bd9Sstevel@tonic-gate /* High speed interrupt transaction */ 26337c478bd9Sstevel@tonic-gate *sbandwidth += HS_NON_ISOC_PROTO_OVERHEAD; 26347c478bd9Sstevel@tonic-gate } else { 26357c478bd9Sstevel@tonic-gate /* Isochronous transaction */ 26367c478bd9Sstevel@tonic-gate *sbandwidth += HS_ISOC_PROTO_OVERHEAD; 26377c478bd9Sstevel@tonic-gate } 26387c478bd9Sstevel@tonic-gate 26397c478bd9Sstevel@tonic-gate /* 26407c478bd9Sstevel@tonic-gate * For low/full speed devices, add split transaction specific 26417c478bd9Sstevel@tonic-gate * overheads. 26427c478bd9Sstevel@tonic-gate */ 26437c478bd9Sstevel@tonic-gate if (port_status != USBA_HIGH_SPEED_DEV) { 26447c478bd9Sstevel@tonic-gate /* 26457c478bd9Sstevel@tonic-gate * Add start and complete split transaction 26467c478bd9Sstevel@tonic-gate * tokens overheads. 26477c478bd9Sstevel@tonic-gate */ 26487c478bd9Sstevel@tonic-gate *cbandwidth = *sbandwidth + COMPLETE_SPLIT_OVERHEAD; 26497c478bd9Sstevel@tonic-gate *sbandwidth += START_SPLIT_OVERHEAD; 26507c478bd9Sstevel@tonic-gate 26517c478bd9Sstevel@tonic-gate /* Add data overhead depending on data direction */ 26527c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 26537c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 26547c478bd9Sstevel@tonic-gate *cbandwidth += maxpacketsize; 26557c478bd9Sstevel@tonic-gate } else { 26567c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 26577c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) { 26587c478bd9Sstevel@tonic-gate /* There is no compete splits for out */ 26597c478bd9Sstevel@tonic-gate *cbandwidth = 0; 26607c478bd9Sstevel@tonic-gate } 26617c478bd9Sstevel@tonic-gate *sbandwidth += maxpacketsize; 26627c478bd9Sstevel@tonic-gate } 26637c478bd9Sstevel@tonic-gate } else { 26647c478bd9Sstevel@tonic-gate uint_t xactions; 26657c478bd9Sstevel@tonic-gate 26667c478bd9Sstevel@tonic-gate /* Get the max transactions per microframe */ 26677c478bd9Sstevel@tonic-gate xactions = ((maxpacketsize & USB_EP_MAX_XACTS_MASK) >> 26687c478bd9Sstevel@tonic-gate USB_EP_MAX_XACTS_SHIFT) + 1; 26697c478bd9Sstevel@tonic-gate 26707c478bd9Sstevel@tonic-gate /* High speed transaction */ 26717c478bd9Sstevel@tonic-gate *sbandwidth += maxpacketsize; 26727c478bd9Sstevel@tonic-gate 26737c478bd9Sstevel@tonic-gate /* Calculate bandwidth per micro-frame */ 26747c478bd9Sstevel@tonic-gate *sbandwidth *= xactions; 26757c478bd9Sstevel@tonic-gate 26767c478bd9Sstevel@tonic-gate *cbandwidth = 0; 26777c478bd9Sstevel@tonic-gate } 26787c478bd9Sstevel@tonic-gate 26797c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 26807c478bd9Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: " 26817c478bd9Sstevel@tonic-gate "Start split bandwidth %d Complete split bandwidth %d", 26827c478bd9Sstevel@tonic-gate *sbandwidth, *cbandwidth); 26837c478bd9Sstevel@tonic-gate 26847c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 26857c478bd9Sstevel@tonic-gate } 26867c478bd9Sstevel@tonic-gate 26877c478bd9Sstevel@tonic-gate 26887c478bd9Sstevel@tonic-gate /* 26897c478bd9Sstevel@tonic-gate * ehci_compute_classic_bandwidth: 26907c478bd9Sstevel@tonic-gate * 26917c478bd9Sstevel@tonic-gate * Given a periodic endpoint (interrupt or isochronous) determine the total 26927c478bd9Sstevel@tonic-gate * bandwidth for one transaction. The EHCI host controller traverses the 26937c478bd9Sstevel@tonic-gate * endpoint descriptor lists on a first-come-first-serve basis. When the HC 26947c478bd9Sstevel@tonic-gate * services an endpoint, only a single transaction attempt is made. The HC 26957c478bd9Sstevel@tonic-gate * moves to the next Endpoint Descriptor after the first transaction attempt 26967c478bd9Sstevel@tonic-gate * rather than finishing the entire Transfer Descriptor. Therefore, when a 26977c478bd9Sstevel@tonic-gate * Transfer Descriptor is inserted into the lattice, we will only count the 26987c478bd9Sstevel@tonic-gate * number of bytes for one transaction. 26997c478bd9Sstevel@tonic-gate * 27007c478bd9Sstevel@tonic-gate * The following are the formulas used for calculating bandwidth in terms 27017c478bd9Sstevel@tonic-gate * bytes and it is for the single USB high speed transaction. The protocol 27027c478bd9Sstevel@tonic-gate * overheads will be different for each of type of USB transfer & all these 27037c478bd9Sstevel@tonic-gate * formulas & protocol overheads are derived from the 5.11.3 section of the 27047c478bd9Sstevel@tonic-gate * USB 2.0 Specification. 27057c478bd9Sstevel@tonic-gate * 27067c478bd9Sstevel@tonic-gate * Low-Speed: 27077c478bd9Sstevel@tonic-gate * Protocol overhead + Hub LS overhead + 27087c478bd9Sstevel@tonic-gate * (Low Speed clock * ((MaxPktSz * 7)/6)) + TT_Delay 27097c478bd9Sstevel@tonic-gate * 27107c478bd9Sstevel@tonic-gate * Full-Speed: 27117c478bd9Sstevel@tonic-gate * Protocol overhead + ((MaxPktSz * 7)/6) + TT_Delay 27127c478bd9Sstevel@tonic-gate */ 27137c478bd9Sstevel@tonic-gate /* ARGSUSED */ 27147c478bd9Sstevel@tonic-gate static int 27157c478bd9Sstevel@tonic-gate ehci_compute_classic_bandwidth( 27167c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 27177c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 27187c478bd9Sstevel@tonic-gate uint_t *bandwidth) 27197c478bd9Sstevel@tonic-gate { 27207c478bd9Sstevel@tonic-gate ushort_t maxpacketsize = endpoint->wMaxPacketSize; 27217c478bd9Sstevel@tonic-gate 27227c478bd9Sstevel@tonic-gate /* 27237c478bd9Sstevel@tonic-gate * If endpoint maximum packet is zero, then return immediately. 27247c478bd9Sstevel@tonic-gate */ 27257c478bd9Sstevel@tonic-gate if (maxpacketsize == 0) { 27267c478bd9Sstevel@tonic-gate 27277c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 27287c478bd9Sstevel@tonic-gate } 27297c478bd9Sstevel@tonic-gate 27307c478bd9Sstevel@tonic-gate /* Add TT delay to required bandwidth */ 27317c478bd9Sstevel@tonic-gate *bandwidth = TT_DELAY; 27327c478bd9Sstevel@tonic-gate 27337c478bd9Sstevel@tonic-gate /* Add bit-stuffing overhead */ 27347c478bd9Sstevel@tonic-gate maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6); 27357c478bd9Sstevel@tonic-gate 27367c478bd9Sstevel@tonic-gate switch (port_status) { 27377c478bd9Sstevel@tonic-gate case USBA_LOW_SPEED_DEV: 27387c478bd9Sstevel@tonic-gate /* Low speed interrupt transaction */ 27397c478bd9Sstevel@tonic-gate *bandwidth += (LOW_SPEED_PROTO_OVERHEAD + 27407c478bd9Sstevel@tonic-gate HUB_LOW_SPEED_PROTO_OVERHEAD + 27417c478bd9Sstevel@tonic-gate (LOW_SPEED_CLOCK * maxpacketsize)); 27427c478bd9Sstevel@tonic-gate break; 27437c478bd9Sstevel@tonic-gate case USBA_FULL_SPEED_DEV: 27447c478bd9Sstevel@tonic-gate /* Full speed transaction */ 27457c478bd9Sstevel@tonic-gate *bandwidth += maxpacketsize; 27467c478bd9Sstevel@tonic-gate 27477c478bd9Sstevel@tonic-gate /* Add xfer specific protocol overheads */ 27487c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 27497c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) { 27507c478bd9Sstevel@tonic-gate /* Full speed interrupt transaction */ 27517c478bd9Sstevel@tonic-gate *bandwidth += FS_NON_ISOC_PROTO_OVERHEAD; 27527c478bd9Sstevel@tonic-gate } else { 27537c478bd9Sstevel@tonic-gate /* Isochronous and input transaction */ 27547c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 27557c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 27567c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_INPUT_PROTO_OVERHEAD; 27577c478bd9Sstevel@tonic-gate } else { 27587c478bd9Sstevel@tonic-gate /* Isochronous and output transaction */ 27597c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_OUTPUT_PROTO_OVERHEAD; 27607c478bd9Sstevel@tonic-gate } 27617c478bd9Sstevel@tonic-gate } 27627c478bd9Sstevel@tonic-gate break; 27637c478bd9Sstevel@tonic-gate } 27647c478bd9Sstevel@tonic-gate 27657c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 27667c478bd9Sstevel@tonic-gate } 27677c478bd9Sstevel@tonic-gate 27687c478bd9Sstevel@tonic-gate 27697c478bd9Sstevel@tonic-gate /* 27707c478bd9Sstevel@tonic-gate * ehci_adjust_polling_interval: 27717c478bd9Sstevel@tonic-gate * 27727c478bd9Sstevel@tonic-gate * Adjust bandwidth according usb device speed. 27737c478bd9Sstevel@tonic-gate */ 27747c478bd9Sstevel@tonic-gate /* ARGSUSED */ 27757c478bd9Sstevel@tonic-gate int 27767c478bd9Sstevel@tonic-gate ehci_adjust_polling_interval( 27777c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 27787c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 27797c478bd9Sstevel@tonic-gate usb_port_status_t port_status) 27807c478bd9Sstevel@tonic-gate { 27817c478bd9Sstevel@tonic-gate uint_t interval; 27827c478bd9Sstevel@tonic-gate int i = 0; 27837c478bd9Sstevel@tonic-gate 27847c478bd9Sstevel@tonic-gate /* Get the polling interval */ 27857c478bd9Sstevel@tonic-gate interval = endpoint->bInterval; 27867c478bd9Sstevel@tonic-gate 27877c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 27887c478bd9Sstevel@tonic-gate "ehci_adjust_polling_interval: Polling interval 0x%x", interval); 27897c478bd9Sstevel@tonic-gate 27907c478bd9Sstevel@tonic-gate /* 27917c478bd9Sstevel@tonic-gate * According USB 2.0 Specifications, a high-speed endpoint's 27927c478bd9Sstevel@tonic-gate * polling intervals are specified interms of 125us or micro 27937c478bd9Sstevel@tonic-gate * frame, where as full/low endpoint's polling intervals are 27947c478bd9Sstevel@tonic-gate * specified in milliseconds. 27957c478bd9Sstevel@tonic-gate * 27967c478bd9Sstevel@tonic-gate * A high speed interrupt/isochronous endpoints can specify 27977c478bd9Sstevel@tonic-gate * desired polling interval between 1 to 16 micro-frames, 27987c478bd9Sstevel@tonic-gate * where as full/low endpoints can specify between 1 to 255 27997c478bd9Sstevel@tonic-gate * milliseconds. 28007c478bd9Sstevel@tonic-gate */ 28017c478bd9Sstevel@tonic-gate switch (port_status) { 28027c478bd9Sstevel@tonic-gate case USBA_LOW_SPEED_DEV: 28037c478bd9Sstevel@tonic-gate /* 28047c478bd9Sstevel@tonic-gate * Low speed endpoints are limited to specifying 28057c478bd9Sstevel@tonic-gate * only 8ms to 255ms in this driver. If a device 28067c478bd9Sstevel@tonic-gate * reports a polling interval that is less than 8ms, 28077c478bd9Sstevel@tonic-gate * it will use 8 ms instead. 28087c478bd9Sstevel@tonic-gate */ 28097c478bd9Sstevel@tonic-gate if (interval < LS_MIN_POLL_INTERVAL) { 28107c478bd9Sstevel@tonic-gate 28117c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 28127c478bd9Sstevel@tonic-gate "Low speed endpoint's poll interval of %d ms " 28137c478bd9Sstevel@tonic-gate "is below threshold. Rounding up to %d ms", 28147c478bd9Sstevel@tonic-gate interval, LS_MIN_POLL_INTERVAL); 28157c478bd9Sstevel@tonic-gate 28167c478bd9Sstevel@tonic-gate interval = LS_MIN_POLL_INTERVAL; 28177c478bd9Sstevel@tonic-gate } 28187c478bd9Sstevel@tonic-gate 28197c478bd9Sstevel@tonic-gate /* 28207c478bd9Sstevel@tonic-gate * Return an error if the polling interval is greater 28217c478bd9Sstevel@tonic-gate * than 255ms. 28227c478bd9Sstevel@tonic-gate */ 28237c478bd9Sstevel@tonic-gate if (interval > LS_MAX_POLL_INTERVAL) { 28247c478bd9Sstevel@tonic-gate 28257c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 28267c478bd9Sstevel@tonic-gate "Low speed endpoint's poll interval is " 28277c478bd9Sstevel@tonic-gate "greater than %d ms", LS_MAX_POLL_INTERVAL); 28287c478bd9Sstevel@tonic-gate 28297c478bd9Sstevel@tonic-gate return (USB_FAILURE); 28307c478bd9Sstevel@tonic-gate } 28317c478bd9Sstevel@tonic-gate break; 28327c478bd9Sstevel@tonic-gate 28337c478bd9Sstevel@tonic-gate case USBA_FULL_SPEED_DEV: 28347c478bd9Sstevel@tonic-gate /* 28357c478bd9Sstevel@tonic-gate * Return an error if the polling interval is less 28367c478bd9Sstevel@tonic-gate * than 1ms and greater than 255ms. 28377c478bd9Sstevel@tonic-gate */ 28387c478bd9Sstevel@tonic-gate if ((interval < FS_MIN_POLL_INTERVAL) && 28397c478bd9Sstevel@tonic-gate (interval > FS_MAX_POLL_INTERVAL)) { 28407c478bd9Sstevel@tonic-gate 28417c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 28427c478bd9Sstevel@tonic-gate "Full speed endpoint's poll interval must " 28437c478bd9Sstevel@tonic-gate "be between %d and %d ms", FS_MIN_POLL_INTERVAL, 28447c478bd9Sstevel@tonic-gate FS_MAX_POLL_INTERVAL); 28457c478bd9Sstevel@tonic-gate 28467c478bd9Sstevel@tonic-gate return (USB_FAILURE); 28477c478bd9Sstevel@tonic-gate } 28487c478bd9Sstevel@tonic-gate break; 28497c478bd9Sstevel@tonic-gate case USBA_HIGH_SPEED_DEV: 28507c478bd9Sstevel@tonic-gate /* 28517c478bd9Sstevel@tonic-gate * Return an error if the polling interval is less 1 28527c478bd9Sstevel@tonic-gate * and greater than 16. Convert this value to 125us 28537c478bd9Sstevel@tonic-gate * units using 2^(bInterval -1). refer usb 2.0 spec 28547c478bd9Sstevel@tonic-gate * page 51 for details. 28557c478bd9Sstevel@tonic-gate */ 28567c478bd9Sstevel@tonic-gate if ((interval < HS_MIN_POLL_INTERVAL) && 28577c478bd9Sstevel@tonic-gate (interval > HS_MAX_POLL_INTERVAL)) { 28587c478bd9Sstevel@tonic-gate 28597c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 28607c478bd9Sstevel@tonic-gate "High speed endpoint's poll interval " 28617c478bd9Sstevel@tonic-gate "must be between %d and %d units", 28627c478bd9Sstevel@tonic-gate HS_MIN_POLL_INTERVAL, HS_MAX_POLL_INTERVAL); 28637c478bd9Sstevel@tonic-gate 28647c478bd9Sstevel@tonic-gate return (USB_FAILURE); 28657c478bd9Sstevel@tonic-gate } 28667c478bd9Sstevel@tonic-gate 28677c478bd9Sstevel@tonic-gate /* Adjust high speed device polling interval */ 28687c478bd9Sstevel@tonic-gate interval = 28697c478bd9Sstevel@tonic-gate ehci_adjust_high_speed_polling_interval(ehcip, endpoint); 28707c478bd9Sstevel@tonic-gate 28717c478bd9Sstevel@tonic-gate break; 28727c478bd9Sstevel@tonic-gate } 28737c478bd9Sstevel@tonic-gate 28747c478bd9Sstevel@tonic-gate /* 28757c478bd9Sstevel@tonic-gate * If polling interval is greater than 32ms, 28767c478bd9Sstevel@tonic-gate * adjust polling interval equal to 32ms. 28777c478bd9Sstevel@tonic-gate */ 28787c478bd9Sstevel@tonic-gate if (interval > EHCI_NUM_INTR_QH_LISTS) { 28797c478bd9Sstevel@tonic-gate interval = EHCI_NUM_INTR_QH_LISTS; 28807c478bd9Sstevel@tonic-gate } 28817c478bd9Sstevel@tonic-gate 28827c478bd9Sstevel@tonic-gate /* 28837c478bd9Sstevel@tonic-gate * Find the nearest power of 2 that's less 28847c478bd9Sstevel@tonic-gate * than interval. 28857c478bd9Sstevel@tonic-gate */ 28867c478bd9Sstevel@tonic-gate while ((ehci_pow_2(i)) <= interval) { 28877c478bd9Sstevel@tonic-gate i++; 28887c478bd9Sstevel@tonic-gate } 28897c478bd9Sstevel@tonic-gate 28907c478bd9Sstevel@tonic-gate return (ehci_pow_2((i - 1))); 28917c478bd9Sstevel@tonic-gate } 28927c478bd9Sstevel@tonic-gate 28937c478bd9Sstevel@tonic-gate 28947c478bd9Sstevel@tonic-gate /* 28957c478bd9Sstevel@tonic-gate * ehci_adjust_high_speed_polling_interval: 28967c478bd9Sstevel@tonic-gate */ 28977c478bd9Sstevel@tonic-gate /* ARGSUSED */ 28987c478bd9Sstevel@tonic-gate static int 28997c478bd9Sstevel@tonic-gate ehci_adjust_high_speed_polling_interval( 29007c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 29017c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint) 29027c478bd9Sstevel@tonic-gate { 29037c478bd9Sstevel@tonic-gate uint_t interval; 29047c478bd9Sstevel@tonic-gate 29057c478bd9Sstevel@tonic-gate /* Get the polling interval */ 29067c478bd9Sstevel@tonic-gate interval = ehci_pow_2(endpoint->bInterval - 1); 29077c478bd9Sstevel@tonic-gate 29087c478bd9Sstevel@tonic-gate /* 29097c478bd9Sstevel@tonic-gate * Convert polling interval from micro seconds 29107c478bd9Sstevel@tonic-gate * to milli seconds. 29117c478bd9Sstevel@tonic-gate */ 29127c478bd9Sstevel@tonic-gate if (interval <= EHCI_MAX_UFRAMES) { 29137c478bd9Sstevel@tonic-gate interval = 1; 29147c478bd9Sstevel@tonic-gate } else { 29157c478bd9Sstevel@tonic-gate interval = interval/EHCI_MAX_UFRAMES; 29167c478bd9Sstevel@tonic-gate } 29177c478bd9Sstevel@tonic-gate 29187c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 29197c478bd9Sstevel@tonic-gate "ehci_adjust_high_speed_polling_interval: " 29207c478bd9Sstevel@tonic-gate "High speed adjusted interval 0x%x", interval); 29217c478bd9Sstevel@tonic-gate 29227c478bd9Sstevel@tonic-gate return (interval); 29237c478bd9Sstevel@tonic-gate } 29247c478bd9Sstevel@tonic-gate 29257c478bd9Sstevel@tonic-gate 29267c478bd9Sstevel@tonic-gate /* 29277c478bd9Sstevel@tonic-gate * ehci_lattice_height: 29287c478bd9Sstevel@tonic-gate * 29297c478bd9Sstevel@tonic-gate * Given the requested bandwidth, find the height in the tree at which the 29307c478bd9Sstevel@tonic-gate * nodes for this bandwidth fall. The height is measured as the number of 29317c478bd9Sstevel@tonic-gate * nodes from the leaf to the level specified by bandwidth The root of the 29327c478bd9Sstevel@tonic-gate * tree is at height TREE_HEIGHT. 29337c478bd9Sstevel@tonic-gate */ 29347c478bd9Sstevel@tonic-gate static uint_t 29357c478bd9Sstevel@tonic-gate ehci_lattice_height(uint_t interval) 29367c478bd9Sstevel@tonic-gate { 29377c478bd9Sstevel@tonic-gate return (TREE_HEIGHT - (ehci_log_2(interval))); 29387c478bd9Sstevel@tonic-gate } 29397c478bd9Sstevel@tonic-gate 29407c478bd9Sstevel@tonic-gate 29417c478bd9Sstevel@tonic-gate /* 29427c478bd9Sstevel@tonic-gate * ehci_lattice_parent: 29437c478bd9Sstevel@tonic-gate * 29447c478bd9Sstevel@tonic-gate * Given a node in the lattice, find the index of the parent node 29457c478bd9Sstevel@tonic-gate */ 29467c478bd9Sstevel@tonic-gate static uint_t 29477c478bd9Sstevel@tonic-gate ehci_lattice_parent(uint_t node) 29487c478bd9Sstevel@tonic-gate { 29497c478bd9Sstevel@tonic-gate if ((node % 2) == 0) { 29507c478bd9Sstevel@tonic-gate 29517c478bd9Sstevel@tonic-gate return ((node/2) - 1); 29527c478bd9Sstevel@tonic-gate } else { 29537c478bd9Sstevel@tonic-gate 29547c478bd9Sstevel@tonic-gate return ((node + 1)/2 - 1); 29557c478bd9Sstevel@tonic-gate } 29567c478bd9Sstevel@tonic-gate } 29577c478bd9Sstevel@tonic-gate 29587c478bd9Sstevel@tonic-gate 29597c478bd9Sstevel@tonic-gate /* 29607c478bd9Sstevel@tonic-gate * ehci_find_periodic_node: 29617c478bd9Sstevel@tonic-gate * 29627c478bd9Sstevel@tonic-gate * Based on the "real" array leaf node and interval, get the periodic node. 29637c478bd9Sstevel@tonic-gate */ 29647c478bd9Sstevel@tonic-gate static uint_t 29657c478bd9Sstevel@tonic-gate ehci_find_periodic_node(uint_t leaf, int interval) { 29667c478bd9Sstevel@tonic-gate uint_t lattice_leaf; 29677c478bd9Sstevel@tonic-gate uint_t height = ehci_lattice_height(interval); 29687c478bd9Sstevel@tonic-gate uint_t pnode; 29697c478bd9Sstevel@tonic-gate int i; 29707c478bd9Sstevel@tonic-gate 29717c478bd9Sstevel@tonic-gate /* Get the leaf number in the lattice */ 29727c478bd9Sstevel@tonic-gate lattice_leaf = leaf + EHCI_NUM_INTR_QH_LISTS - 1; 29737c478bd9Sstevel@tonic-gate 29747c478bd9Sstevel@tonic-gate /* Get the node in the lattice based on the height and leaf */ 29757c478bd9Sstevel@tonic-gate pnode = lattice_leaf; 29767c478bd9Sstevel@tonic-gate for (i = 0; i < height; i++) { 29777c478bd9Sstevel@tonic-gate pnode = ehci_lattice_parent(pnode); 29787c478bd9Sstevel@tonic-gate } 29797c478bd9Sstevel@tonic-gate 29807c478bd9Sstevel@tonic-gate return (pnode); 29817c478bd9Sstevel@tonic-gate } 29827c478bd9Sstevel@tonic-gate 29837c478bd9Sstevel@tonic-gate 29847c478bd9Sstevel@tonic-gate /* 29857c478bd9Sstevel@tonic-gate * ehci_leftmost_leaf: 29867c478bd9Sstevel@tonic-gate * 29877c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node. Height refers 29887c478bd9Sstevel@tonic-gate * to number of nodes from the bottom of the tree to the node, including the 29897c478bd9Sstevel@tonic-gate * node. 29907c478bd9Sstevel@tonic-gate * 29917c478bd9Sstevel@tonic-gate * The formula for a zero based tree is: 29927c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1 29937c478bd9Sstevel@tonic-gate * The leaf of the tree is an array, convert the number for the array. 29947c478bd9Sstevel@tonic-gate * Subtract the size of nodes not in the array 29957c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1 - (EHCI_NUM_INTR_QH_LISTS - 1) = 29967c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - EHCI_NUM_INTR_QH_LISTS = 29977c478bd9Sstevel@tonic-gate * 2^H * (Node + 1) - EHCI_NUM_INTR_QH_LISTS 29987c478bd9Sstevel@tonic-gate * 0 29997c478bd9Sstevel@tonic-gate * 1 2 30007c478bd9Sstevel@tonic-gate * 0 1 2 3 30017c478bd9Sstevel@tonic-gate */ 30027c478bd9Sstevel@tonic-gate static uint_t 30037c478bd9Sstevel@tonic-gate ehci_leftmost_leaf( 30047c478bd9Sstevel@tonic-gate uint_t node, 30057c478bd9Sstevel@tonic-gate uint_t height) 30067c478bd9Sstevel@tonic-gate { 30077c478bd9Sstevel@tonic-gate return ((ehci_pow_2(height) * (node + 1)) - EHCI_NUM_INTR_QH_LISTS); 30087c478bd9Sstevel@tonic-gate } 30097c478bd9Sstevel@tonic-gate 30107c478bd9Sstevel@tonic-gate 30117c478bd9Sstevel@tonic-gate /* 30127c478bd9Sstevel@tonic-gate * ehci_pow_2: 30137c478bd9Sstevel@tonic-gate * 30147c478bd9Sstevel@tonic-gate * Compute 2 to the power 30157c478bd9Sstevel@tonic-gate */ 30167c478bd9Sstevel@tonic-gate static uint_t 30177c478bd9Sstevel@tonic-gate ehci_pow_2(uint_t x) 30187c478bd9Sstevel@tonic-gate { 30197c478bd9Sstevel@tonic-gate if (x == 0) { 30207c478bd9Sstevel@tonic-gate 30217c478bd9Sstevel@tonic-gate return (1); 30227c478bd9Sstevel@tonic-gate } else { 30237c478bd9Sstevel@tonic-gate 30247c478bd9Sstevel@tonic-gate return (2 << (x - 1)); 30257c478bd9Sstevel@tonic-gate } 30267c478bd9Sstevel@tonic-gate } 30277c478bd9Sstevel@tonic-gate 30287c478bd9Sstevel@tonic-gate 30297c478bd9Sstevel@tonic-gate /* 30307c478bd9Sstevel@tonic-gate * ehci_log_2: 30317c478bd9Sstevel@tonic-gate * 30327c478bd9Sstevel@tonic-gate * Compute log base 2 of x 30337c478bd9Sstevel@tonic-gate */ 30347c478bd9Sstevel@tonic-gate static uint_t 30357c478bd9Sstevel@tonic-gate ehci_log_2(uint_t x) 30367c478bd9Sstevel@tonic-gate { 30377c478bd9Sstevel@tonic-gate int i = 0; 30387c478bd9Sstevel@tonic-gate 30397c478bd9Sstevel@tonic-gate while (x != 1) { 30407c478bd9Sstevel@tonic-gate x = x >> 1; 30417c478bd9Sstevel@tonic-gate i++; 30427c478bd9Sstevel@tonic-gate } 30437c478bd9Sstevel@tonic-gate 30447c478bd9Sstevel@tonic-gate return (i); 30457c478bd9Sstevel@tonic-gate } 30467c478bd9Sstevel@tonic-gate 30477c478bd9Sstevel@tonic-gate 30487c478bd9Sstevel@tonic-gate /* 30497c478bd9Sstevel@tonic-gate * ehci_find_bestfit_hs_mask: 30507c478bd9Sstevel@tonic-gate * 30517c478bd9Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation, and update the 30527c478bd9Sstevel@tonic-gate * bandwidth allocation. 30537c478bd9Sstevel@tonic-gate */ 30547c478bd9Sstevel@tonic-gate static int 30557c478bd9Sstevel@tonic-gate ehci_find_bestfit_hs_mask( 30567c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 30577c478bd9Sstevel@tonic-gate uchar_t *smask, 30587c478bd9Sstevel@tonic-gate uint_t *pnode, 30597c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 30607c478bd9Sstevel@tonic-gate uint_t bandwidth, 30617c478bd9Sstevel@tonic-gate int interval) 30627c478bd9Sstevel@tonic-gate { 30637c478bd9Sstevel@tonic-gate int i; 30647c478bd9Sstevel@tonic-gate uint_t elements, index; 30657c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 30667c478bd9Sstevel@tonic-gate uint_t node_bandwidth, best_node_bandwidth; 30677c478bd9Sstevel@tonic-gate uint_t leaf_count; 30687c478bd9Sstevel@tonic-gate uchar_t bw_mask; 30697c478bd9Sstevel@tonic-gate uchar_t best_smask; 30707c478bd9Sstevel@tonic-gate 30717c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 30727c478bd9Sstevel@tonic-gate "ehci_find_bestfit_hs_mask: "); 30737c478bd9Sstevel@tonic-gate 30747c478bd9Sstevel@tonic-gate /* Get all the valid smasks */ 30757c478bd9Sstevel@tonic-gate switch (ehci_pow_2(endpoint->bInterval - 1)) { 30767c478bd9Sstevel@tonic-gate case EHCI_INTR_1US_POLL: 30777c478bd9Sstevel@tonic-gate index = EHCI_1US_MASK_INDEX; 30787c478bd9Sstevel@tonic-gate elements = EHCI_INTR_1US_POLL; 30797c478bd9Sstevel@tonic-gate break; 30807c478bd9Sstevel@tonic-gate case EHCI_INTR_2US_POLL: 30817c478bd9Sstevel@tonic-gate index = EHCI_2US_MASK_INDEX; 30827c478bd9Sstevel@tonic-gate elements = EHCI_INTR_2US_POLL; 30837c478bd9Sstevel@tonic-gate break; 30847c478bd9Sstevel@tonic-gate case EHCI_INTR_4US_POLL: 30857c478bd9Sstevel@tonic-gate index = EHCI_4US_MASK_INDEX; 30867c478bd9Sstevel@tonic-gate elements = EHCI_INTR_4US_POLL; 30877c478bd9Sstevel@tonic-gate break; 30887c478bd9Sstevel@tonic-gate case EHCI_INTR_XUS_POLL: 30897c478bd9Sstevel@tonic-gate default: 30907c478bd9Sstevel@tonic-gate index = EHCI_XUS_MASK_INDEX; 30917c478bd9Sstevel@tonic-gate elements = EHCI_INTR_XUS_POLL; 30927c478bd9Sstevel@tonic-gate break; 30937c478bd9Sstevel@tonic-gate } 30947c478bd9Sstevel@tonic-gate 30957c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 30967c478bd9Sstevel@tonic-gate 30977c478bd9Sstevel@tonic-gate /* 30987c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 30997c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 31007c478bd9Sstevel@tonic-gate */ 31017c478bd9Sstevel@tonic-gate best_smask = 0x00; 31027c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 31037c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 31047c478bd9Sstevel@tonic-gate /* Find the bandwidth mask */ 31057c478bd9Sstevel@tonic-gate node_bandwidth = ehci_calculate_bw_availability_mask(ehcip, 31067c478bd9Sstevel@tonic-gate bandwidth, ehci_index[array_leaf], leaf_count, &bw_mask); 31077c478bd9Sstevel@tonic-gate 31087c478bd9Sstevel@tonic-gate /* 31097c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 31107c478bd9Sstevel@tonic-gate * next leaf. 31117c478bd9Sstevel@tonic-gate */ 31127c478bd9Sstevel@tonic-gate if (bw_mask == 0x00) { 31137c478bd9Sstevel@tonic-gate continue; 31147c478bd9Sstevel@tonic-gate } 31157c478bd9Sstevel@tonic-gate 31167c478bd9Sstevel@tonic-gate /* 31177c478bd9Sstevel@tonic-gate * Now make sure our bandwidth requirements can be 31187c478bd9Sstevel@tonic-gate * satisfied with one of smasks in this node. 31197c478bd9Sstevel@tonic-gate */ 31207c478bd9Sstevel@tonic-gate *smask = 0x00; 31217c478bd9Sstevel@tonic-gate for (i = index; i < (index + elements); i++) { 31227c478bd9Sstevel@tonic-gate /* Check the start split mask value */ 31237c478bd9Sstevel@tonic-gate if (ehci_start_split_mask[index] & bw_mask) { 31247c478bd9Sstevel@tonic-gate *smask = ehci_start_split_mask[index]; 31257c478bd9Sstevel@tonic-gate break; 31267c478bd9Sstevel@tonic-gate } 31277c478bd9Sstevel@tonic-gate } 31287c478bd9Sstevel@tonic-gate 31297c478bd9Sstevel@tonic-gate /* 31307c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 31317c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 31327c478bd9Sstevel@tonic-gate * - or - 31337c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 31347c478bd9Sstevel@tonic-gate */ 31357c478bd9Sstevel@tonic-gate if ((*smask != 0x00) && 31367c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 313729aca3ebSlc (best_node_bandwidth > node_bandwidth))) { 31387c478bd9Sstevel@tonic-gate 31397c478bd9Sstevel@tonic-gate best_node_bandwidth = node_bandwidth; 31407c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 31417c478bd9Sstevel@tonic-gate best_smask = *smask; 31427c478bd9Sstevel@tonic-gate } 31437c478bd9Sstevel@tonic-gate } 31447c478bd9Sstevel@tonic-gate 31457c478bd9Sstevel@tonic-gate /* 31467c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 31477c478bd9Sstevel@tonic-gate * appropriate variables and return success. 31487c478bd9Sstevel@tonic-gate */ 31497c478bd9Sstevel@tonic-gate if (best_smask) { 31507c478bd9Sstevel@tonic-gate *smask = best_smask; 31517c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 31527c478bd9Sstevel@tonic-gate interval); 31537c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, bandwidth, 31547c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 31557c478bd9Sstevel@tonic-gate 31567c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 31577c478bd9Sstevel@tonic-gate } 31587c478bd9Sstevel@tonic-gate 31597c478bd9Sstevel@tonic-gate return (USB_FAILURE); 31607c478bd9Sstevel@tonic-gate } 31617c478bd9Sstevel@tonic-gate 31627c478bd9Sstevel@tonic-gate 31637c478bd9Sstevel@tonic-gate /* 31647c478bd9Sstevel@tonic-gate * ehci_find_bestfit_ls_intr_mask: 31657c478bd9Sstevel@tonic-gate * 31667c478bd9Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation. 31677c478bd9Sstevel@tonic-gate */ 31687c478bd9Sstevel@tonic-gate static int 31697c478bd9Sstevel@tonic-gate ehci_find_bestfit_ls_intr_mask( 31707c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 31717c478bd9Sstevel@tonic-gate uchar_t *smask, 31727c478bd9Sstevel@tonic-gate uchar_t *cmask, 31737c478bd9Sstevel@tonic-gate uint_t *pnode, 31747c478bd9Sstevel@tonic-gate uint_t sbandwidth, 31757c478bd9Sstevel@tonic-gate uint_t cbandwidth, 31767c478bd9Sstevel@tonic-gate int interval) 31777c478bd9Sstevel@tonic-gate { 31787c478bd9Sstevel@tonic-gate int i; 31797c478bd9Sstevel@tonic-gate uint_t elements, index; 31807c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 31817c478bd9Sstevel@tonic-gate uint_t node_sbandwidth, node_cbandwidth; 31827c478bd9Sstevel@tonic-gate uint_t best_node_bandwidth; 31837c478bd9Sstevel@tonic-gate uint_t leaf_count; 31847c478bd9Sstevel@tonic-gate uchar_t bw_smask, bw_cmask; 31857c478bd9Sstevel@tonic-gate uchar_t best_smask, best_cmask; 31867c478bd9Sstevel@tonic-gate 31877c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 31887c478bd9Sstevel@tonic-gate "ehci_find_bestfit_ls_intr_mask: "); 31897c478bd9Sstevel@tonic-gate 31907c478bd9Sstevel@tonic-gate /* For low and full speed devices */ 31917c478bd9Sstevel@tonic-gate index = EHCI_XUS_MASK_INDEX; 31927c478bd9Sstevel@tonic-gate elements = EHCI_INTR_4MS_POLL; 31937c478bd9Sstevel@tonic-gate 31947c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 31957c478bd9Sstevel@tonic-gate 31967c478bd9Sstevel@tonic-gate /* 31977c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 31987c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 31997c478bd9Sstevel@tonic-gate */ 32007c478bd9Sstevel@tonic-gate best_smask = 0x00; 32017c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 32027c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 32037c478bd9Sstevel@tonic-gate /* Find the bandwidth mask */ 32047c478bd9Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip, 32057c478bd9Sstevel@tonic-gate sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask); 32067c478bd9Sstevel@tonic-gate node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip, 32077c478bd9Sstevel@tonic-gate cbandwidth, ehci_index[array_leaf], leaf_count, &bw_cmask); 32087c478bd9Sstevel@tonic-gate 32097c478bd9Sstevel@tonic-gate /* 32107c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 32117c478bd9Sstevel@tonic-gate * next leaf. 32127c478bd9Sstevel@tonic-gate */ 32137c478bd9Sstevel@tonic-gate if ((bw_smask == 0x00) || (bw_cmask == 0x00)) { 32147c478bd9Sstevel@tonic-gate continue; 32157c478bd9Sstevel@tonic-gate } 32167c478bd9Sstevel@tonic-gate 32177c478bd9Sstevel@tonic-gate /* 32187c478bd9Sstevel@tonic-gate * Now make sure our bandwidth requirements can be 32197c478bd9Sstevel@tonic-gate * satisfied with one of smasks in this node. 32207c478bd9Sstevel@tonic-gate */ 32217c478bd9Sstevel@tonic-gate *smask = 0x00; 32227c478bd9Sstevel@tonic-gate *cmask = 0x00; 32237c478bd9Sstevel@tonic-gate for (i = index; i < (index + elements); i++) { 32247c478bd9Sstevel@tonic-gate /* Check the start split mask value */ 32257c478bd9Sstevel@tonic-gate if ((ehci_start_split_mask[index] & bw_smask) && 32267c478bd9Sstevel@tonic-gate (ehci_intr_complete_split_mask[index] & bw_cmask)) { 32277c478bd9Sstevel@tonic-gate *smask = ehci_start_split_mask[index]; 32287c478bd9Sstevel@tonic-gate *cmask = ehci_intr_complete_split_mask[index]; 32297c478bd9Sstevel@tonic-gate break; 32307c478bd9Sstevel@tonic-gate } 32317c478bd9Sstevel@tonic-gate } 32327c478bd9Sstevel@tonic-gate 32337c478bd9Sstevel@tonic-gate /* 32347c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 32357c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 32367c478bd9Sstevel@tonic-gate * - or - 32377c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 32387c478bd9Sstevel@tonic-gate */ 32397c478bd9Sstevel@tonic-gate if ((*smask != 0x00) && 32407c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 324129aca3ebSlc (best_node_bandwidth > 324229aca3ebSlc (node_sbandwidth + node_cbandwidth)))) { 32437c478bd9Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth + node_cbandwidth; 32447c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 32457c478bd9Sstevel@tonic-gate best_smask = *smask; 32467c478bd9Sstevel@tonic-gate best_cmask = *cmask; 32477c478bd9Sstevel@tonic-gate } 32487c478bd9Sstevel@tonic-gate } 32497c478bd9Sstevel@tonic-gate 32507c478bd9Sstevel@tonic-gate /* 32517c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 32527c478bd9Sstevel@tonic-gate * appropriate variables and return success. 32537c478bd9Sstevel@tonic-gate */ 32547c478bd9Sstevel@tonic-gate if (best_smask) { 32557c478bd9Sstevel@tonic-gate *smask = best_smask; 32567c478bd9Sstevel@tonic-gate *cmask = best_cmask; 32577c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 32587c478bd9Sstevel@tonic-gate interval); 32597c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, sbandwidth, 32607c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 32617c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, cbandwidth, 32627c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_cmask); 32637c478bd9Sstevel@tonic-gate 32647c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 32657c478bd9Sstevel@tonic-gate } 32667c478bd9Sstevel@tonic-gate 32677c478bd9Sstevel@tonic-gate return (USB_FAILURE); 32687c478bd9Sstevel@tonic-gate } 32697c478bd9Sstevel@tonic-gate 32707c478bd9Sstevel@tonic-gate 32717c478bd9Sstevel@tonic-gate /* 32727c478bd9Sstevel@tonic-gate * ehci_find_bestfit_sitd_in_mask: 32737c478bd9Sstevel@tonic-gate * 32747c478bd9Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation. 32757c478bd9Sstevel@tonic-gate */ 32767c478bd9Sstevel@tonic-gate static int 32777c478bd9Sstevel@tonic-gate ehci_find_bestfit_sitd_in_mask( 32787c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 32797c478bd9Sstevel@tonic-gate uchar_t *smask, 32807c478bd9Sstevel@tonic-gate uchar_t *cmask, 32817c478bd9Sstevel@tonic-gate uint_t *pnode, 32827c478bd9Sstevel@tonic-gate uint_t sbandwidth, 32837c478bd9Sstevel@tonic-gate uint_t cbandwidth, 32847c478bd9Sstevel@tonic-gate int interval) 32857c478bd9Sstevel@tonic-gate { 32867c478bd9Sstevel@tonic-gate int i, uFrames, found; 32877c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 32887c478bd9Sstevel@tonic-gate uint_t node_sbandwidth, node_cbandwidth; 32897c478bd9Sstevel@tonic-gate uint_t best_node_bandwidth; 32907c478bd9Sstevel@tonic-gate uint_t leaf_count; 32917c478bd9Sstevel@tonic-gate uchar_t bw_smask, bw_cmask; 32927c478bd9Sstevel@tonic-gate uchar_t best_smask, best_cmask; 32937c478bd9Sstevel@tonic-gate 32947c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 32957c478bd9Sstevel@tonic-gate "ehci_find_bestfit_sitd_in_mask: "); 32967c478bd9Sstevel@tonic-gate 32977c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 32987c478bd9Sstevel@tonic-gate 32997c478bd9Sstevel@tonic-gate /* 33007c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 33017c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 33027c478bd9Sstevel@tonic-gate * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame. 33037c478bd9Sstevel@tonic-gate */ 33047c478bd9Sstevel@tonic-gate /* 33057c478bd9Sstevel@tonic-gate * Need to add an additional 2 uFrames, if the "L"ast 33067c478bd9Sstevel@tonic-gate * complete split is before uFrame 6. See section 33077c478bd9Sstevel@tonic-gate * 11.8.4 in USB 2.0 Spec. Currently we do not support 33087c478bd9Sstevel@tonic-gate * the "Back Ptr" which means we support on IN of 33097c478bd9Sstevel@tonic-gate * ~4*MAX_UFRAME_SITD_XFER bandwidth/ 33107c478bd9Sstevel@tonic-gate */ 33117c478bd9Sstevel@tonic-gate uFrames = (cbandwidth / MAX_UFRAME_SITD_XFER) + 2; 33127c478bd9Sstevel@tonic-gate if (cbandwidth % MAX_UFRAME_SITD_XFER) { 33137c478bd9Sstevel@tonic-gate uFrames++; 33147c478bd9Sstevel@tonic-gate } 33157c478bd9Sstevel@tonic-gate if (uFrames > 6) { 33167c478bd9Sstevel@tonic-gate 33177c478bd9Sstevel@tonic-gate return (USB_FAILURE); 33187c478bd9Sstevel@tonic-gate } 33197c478bd9Sstevel@tonic-gate *smask = 0x1; 33207c478bd9Sstevel@tonic-gate *cmask = 0x00; 33217c478bd9Sstevel@tonic-gate for (i = 0; i < uFrames; i++) { 33227c478bd9Sstevel@tonic-gate *cmask = *cmask << 1; 33237c478bd9Sstevel@tonic-gate *cmask |= 0x1; 33247c478bd9Sstevel@tonic-gate } 33257c478bd9Sstevel@tonic-gate /* cmask must start 2 frames after the smask */ 33267c478bd9Sstevel@tonic-gate *cmask = *cmask << 2; 33277c478bd9Sstevel@tonic-gate 33287c478bd9Sstevel@tonic-gate found = 0; 33297c478bd9Sstevel@tonic-gate best_smask = 0x00; 33307c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 33317c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 33327c478bd9Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip, 33337c478bd9Sstevel@tonic-gate sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask); 33347c478bd9Sstevel@tonic-gate node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip, 33357c478bd9Sstevel@tonic-gate MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count, 33367c478bd9Sstevel@tonic-gate &bw_cmask); 33377c478bd9Sstevel@tonic-gate 33387c478bd9Sstevel@tonic-gate /* 33397c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 33407c478bd9Sstevel@tonic-gate * next leaf. 33417c478bd9Sstevel@tonic-gate */ 33427c478bd9Sstevel@tonic-gate if ((bw_smask == 0x00) || (bw_cmask == 0x00)) { 33437c478bd9Sstevel@tonic-gate continue; 33447c478bd9Sstevel@tonic-gate } 33457c478bd9Sstevel@tonic-gate 33467c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_MAX_UFRAMES - uFrames - 2); i++) { 33477c478bd9Sstevel@tonic-gate if ((*smask & bw_smask) && (*cmask & bw_cmask)) { 33487c478bd9Sstevel@tonic-gate found = 1; 33497c478bd9Sstevel@tonic-gate break; 33507c478bd9Sstevel@tonic-gate } 33517c478bd9Sstevel@tonic-gate *smask = *smask << 1; 33527c478bd9Sstevel@tonic-gate *cmask = *cmask << 1; 33537c478bd9Sstevel@tonic-gate } 33547c478bd9Sstevel@tonic-gate 33557c478bd9Sstevel@tonic-gate /* 33567c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 33577c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 33587c478bd9Sstevel@tonic-gate * - or - 33597c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 33607c478bd9Sstevel@tonic-gate */ 33617c478bd9Sstevel@tonic-gate if (found && 33627c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 336329aca3ebSlc (best_node_bandwidth > 336429aca3ebSlc (node_sbandwidth + node_cbandwidth)))) { 33657c478bd9Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth + node_cbandwidth; 33667c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 33677c478bd9Sstevel@tonic-gate best_smask = *smask; 33687c478bd9Sstevel@tonic-gate best_cmask = *cmask; 33697c478bd9Sstevel@tonic-gate } 33707c478bd9Sstevel@tonic-gate } 33717c478bd9Sstevel@tonic-gate 33727c478bd9Sstevel@tonic-gate /* 33737c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 33747c478bd9Sstevel@tonic-gate * appropriate variables and return success. 33757c478bd9Sstevel@tonic-gate */ 33767c478bd9Sstevel@tonic-gate if (best_smask) { 33777c478bd9Sstevel@tonic-gate *smask = best_smask; 33787c478bd9Sstevel@tonic-gate *cmask = best_cmask; 33797c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 33807c478bd9Sstevel@tonic-gate interval); 33817c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, sbandwidth, 33827c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 33837c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER, 33847c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_cmask); 33857c478bd9Sstevel@tonic-gate 33867c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 33877c478bd9Sstevel@tonic-gate } 33887c478bd9Sstevel@tonic-gate 33897c478bd9Sstevel@tonic-gate return (USB_FAILURE); 33907c478bd9Sstevel@tonic-gate } 33917c478bd9Sstevel@tonic-gate 33927c478bd9Sstevel@tonic-gate 33937c478bd9Sstevel@tonic-gate /* 33947c478bd9Sstevel@tonic-gate * ehci_find_bestfit_sitd_out_mask: 33957c478bd9Sstevel@tonic-gate * 33967c478bd9Sstevel@tonic-gate * Find the smask in the bandwidth allocation. 33977c478bd9Sstevel@tonic-gate */ 33987c478bd9Sstevel@tonic-gate static int 33997c478bd9Sstevel@tonic-gate ehci_find_bestfit_sitd_out_mask( 34007c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 34017c478bd9Sstevel@tonic-gate uchar_t *smask, 34027c478bd9Sstevel@tonic-gate uint_t *pnode, 34037c478bd9Sstevel@tonic-gate uint_t sbandwidth, 34047c478bd9Sstevel@tonic-gate int interval) 34057c478bd9Sstevel@tonic-gate { 34067c478bd9Sstevel@tonic-gate int i, uFrames, found; 34077c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 34087c478bd9Sstevel@tonic-gate uint_t node_sbandwidth; 34097c478bd9Sstevel@tonic-gate uint_t best_node_bandwidth; 34107c478bd9Sstevel@tonic-gate uint_t leaf_count; 34117c478bd9Sstevel@tonic-gate uchar_t bw_smask; 34127c478bd9Sstevel@tonic-gate uchar_t best_smask; 34137c478bd9Sstevel@tonic-gate 34147c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 34157c478bd9Sstevel@tonic-gate "ehci_find_bestfit_sitd_out_mask: "); 34167c478bd9Sstevel@tonic-gate 34177c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 34187c478bd9Sstevel@tonic-gate 34197c478bd9Sstevel@tonic-gate /* 34207c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 34217c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 34227c478bd9Sstevel@tonic-gate * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame. 34237c478bd9Sstevel@tonic-gate */ 34247c478bd9Sstevel@tonic-gate *smask = 0x00; 34257c478bd9Sstevel@tonic-gate uFrames = sbandwidth / MAX_UFRAME_SITD_XFER; 34267c478bd9Sstevel@tonic-gate if (sbandwidth % MAX_UFRAME_SITD_XFER) { 34277c478bd9Sstevel@tonic-gate uFrames++; 34287c478bd9Sstevel@tonic-gate } 34297c478bd9Sstevel@tonic-gate for (i = 0; i < uFrames; i++) { 34307c478bd9Sstevel@tonic-gate *smask = *smask << 1; 34317c478bd9Sstevel@tonic-gate *smask |= 0x1; 34327c478bd9Sstevel@tonic-gate } 34337c478bd9Sstevel@tonic-gate 34347c478bd9Sstevel@tonic-gate found = 0; 34357c478bd9Sstevel@tonic-gate best_smask = 0x00; 34367c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 34377c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 34387c478bd9Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip, 34397c478bd9Sstevel@tonic-gate MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count, 34407c478bd9Sstevel@tonic-gate &bw_smask); 34417c478bd9Sstevel@tonic-gate 34427c478bd9Sstevel@tonic-gate /* 34437c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 34447c478bd9Sstevel@tonic-gate * next leaf. 34457c478bd9Sstevel@tonic-gate */ 34467c478bd9Sstevel@tonic-gate if (bw_smask == 0x00) { 34477c478bd9Sstevel@tonic-gate continue; 34487c478bd9Sstevel@tonic-gate } 34497c478bd9Sstevel@tonic-gate 34507c478bd9Sstevel@tonic-gate /* You cannot have a start split on the 8th uFrame */ 34517c478bd9Sstevel@tonic-gate for (i = 0; (*smask & 0x80) == 0; i++) { 34527c478bd9Sstevel@tonic-gate if (*smask & bw_smask) { 34537c478bd9Sstevel@tonic-gate found = 1; 34547c478bd9Sstevel@tonic-gate break; 34557c478bd9Sstevel@tonic-gate } 34567c478bd9Sstevel@tonic-gate *smask = *smask << 1; 34577c478bd9Sstevel@tonic-gate } 34587c478bd9Sstevel@tonic-gate 34597c478bd9Sstevel@tonic-gate /* 34607c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 34617c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 34627c478bd9Sstevel@tonic-gate * - or - 34637c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 34647c478bd9Sstevel@tonic-gate */ 34657c478bd9Sstevel@tonic-gate if (found && 34667c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 346729aca3ebSlc (best_node_bandwidth > node_sbandwidth))) { 34687c478bd9Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth; 34697c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 34707c478bd9Sstevel@tonic-gate best_smask = *smask; 34717c478bd9Sstevel@tonic-gate } 34727c478bd9Sstevel@tonic-gate } 34737c478bd9Sstevel@tonic-gate 34747c478bd9Sstevel@tonic-gate /* 34757c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 34767c478bd9Sstevel@tonic-gate * appropriate variables and return success. 34777c478bd9Sstevel@tonic-gate */ 34787c478bd9Sstevel@tonic-gate if (best_smask) { 34797c478bd9Sstevel@tonic-gate *smask = best_smask; 34807c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 34817c478bd9Sstevel@tonic-gate interval); 34827c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER, 34837c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 34847c478bd9Sstevel@tonic-gate 34857c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 34867c478bd9Sstevel@tonic-gate } 34877c478bd9Sstevel@tonic-gate 34887c478bd9Sstevel@tonic-gate return (USB_FAILURE); 34897c478bd9Sstevel@tonic-gate } 34907c478bd9Sstevel@tonic-gate 34917c478bd9Sstevel@tonic-gate 34927c478bd9Sstevel@tonic-gate /* 34937c478bd9Sstevel@tonic-gate * ehci_calculate_bw_availability_mask: 34947c478bd9Sstevel@tonic-gate * 34957c478bd9Sstevel@tonic-gate * Returns the "total bandwidth used" in this node. 34967c478bd9Sstevel@tonic-gate * Populates bw_mask with the uFrames that can support the bandwidth. 34977c478bd9Sstevel@tonic-gate * 34987c478bd9Sstevel@tonic-gate * If all the Frames cannot support this bandwidth, then bw_mask 34997c478bd9Sstevel@tonic-gate * will return 0x00 and the "total bandwidth used" will be invalid. 35007c478bd9Sstevel@tonic-gate */ 35017c478bd9Sstevel@tonic-gate static uint_t 35027c478bd9Sstevel@tonic-gate ehci_calculate_bw_availability_mask( 35037c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 35047c478bd9Sstevel@tonic-gate uint_t bandwidth, 35057c478bd9Sstevel@tonic-gate int leaf, 35067c478bd9Sstevel@tonic-gate int leaf_count, 35077c478bd9Sstevel@tonic-gate uchar_t *bw_mask) 35087c478bd9Sstevel@tonic-gate { 35097c478bd9Sstevel@tonic-gate int i, j; 35107c478bd9Sstevel@tonic-gate uchar_t bw_uframe; 35117c478bd9Sstevel@tonic-gate int uframe_total; 35127c478bd9Sstevel@tonic-gate ehci_frame_bandwidth_t *fbp; 35137c478bd9Sstevel@tonic-gate uint_t total_bandwidth = 0; 35147c478bd9Sstevel@tonic-gate 35157c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 35167c478bd9Sstevel@tonic-gate "ehci_calculate_bw_availability_mask: leaf %d leaf count %d", 35177c478bd9Sstevel@tonic-gate leaf, leaf_count); 35187c478bd9Sstevel@tonic-gate 35197c478bd9Sstevel@tonic-gate /* Start by saying all uFrames are available */ 35207c478bd9Sstevel@tonic-gate *bw_mask = 0xFF; 35217c478bd9Sstevel@tonic-gate 35227c478bd9Sstevel@tonic-gate for (i = 0; (i < leaf_count) || (*bw_mask == 0x00); i++) { 35237c478bd9Sstevel@tonic-gate fbp = &ehcip->ehci_frame_bandwidth[leaf + i]; 35247c478bd9Sstevel@tonic-gate 35257c478bd9Sstevel@tonic-gate total_bandwidth += fbp->ehci_allocated_frame_bandwidth; 35267c478bd9Sstevel@tonic-gate 35277c478bd9Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) { 35287c478bd9Sstevel@tonic-gate /* 35297c478bd9Sstevel@tonic-gate * If the uFrame in bw_mask is available check to see if 35307c478bd9Sstevel@tonic-gate * it can support the additional bandwidth. 35317c478bd9Sstevel@tonic-gate */ 35327c478bd9Sstevel@tonic-gate bw_uframe = (*bw_mask & (0x1 << j)); 35337c478bd9Sstevel@tonic-gate uframe_total = 35347c478bd9Sstevel@tonic-gate fbp->ehci_micro_frame_bandwidth[j] + 35357c478bd9Sstevel@tonic-gate bandwidth; 35367c478bd9Sstevel@tonic-gate if ((bw_uframe) && 35377c478bd9Sstevel@tonic-gate (uframe_total > HS_PERIODIC_BANDWIDTH)) { 35387c478bd9Sstevel@tonic-gate *bw_mask = *bw_mask & ~bw_uframe; 35397c478bd9Sstevel@tonic-gate } 35407c478bd9Sstevel@tonic-gate } 35417c478bd9Sstevel@tonic-gate } 35427c478bd9Sstevel@tonic-gate 35437c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 35447c478bd9Sstevel@tonic-gate "ehci_calculate_bw_availability_mask: bandwidth mask 0x%x", 35457c478bd9Sstevel@tonic-gate *bw_mask); 35467c478bd9Sstevel@tonic-gate 35477c478bd9Sstevel@tonic-gate return (total_bandwidth); 35487c478bd9Sstevel@tonic-gate } 35497c478bd9Sstevel@tonic-gate 35507c478bd9Sstevel@tonic-gate 35517c478bd9Sstevel@tonic-gate /* 35527c478bd9Sstevel@tonic-gate * ehci_update_bw_availability: 35537c478bd9Sstevel@tonic-gate * 35547c478bd9Sstevel@tonic-gate * The leftmost leaf needs to be in terms of array position and 35557c478bd9Sstevel@tonic-gate * not the actual lattice position. 35567c478bd9Sstevel@tonic-gate */ 35577c478bd9Sstevel@tonic-gate static void 35587c478bd9Sstevel@tonic-gate ehci_update_bw_availability( 35597c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 35607c478bd9Sstevel@tonic-gate int bandwidth, 35617c478bd9Sstevel@tonic-gate int leftmost_leaf, 35627c478bd9Sstevel@tonic-gate int leaf_count, 35637c478bd9Sstevel@tonic-gate uchar_t mask) 35647c478bd9Sstevel@tonic-gate { 35657c478bd9Sstevel@tonic-gate int i, j; 35667c478bd9Sstevel@tonic-gate ehci_frame_bandwidth_t *fbp; 35677c478bd9Sstevel@tonic-gate int uFrame_bandwidth[8]; 35687c478bd9Sstevel@tonic-gate 35697c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 35707c478bd9Sstevel@tonic-gate "ehci_update_bw_availability: " 35717c478bd9Sstevel@tonic-gate "leaf %d count %d bandwidth 0x%x mask 0x%x", 35727c478bd9Sstevel@tonic-gate leftmost_leaf, leaf_count, bandwidth, mask); 35737c478bd9Sstevel@tonic-gate 35747c478bd9Sstevel@tonic-gate ASSERT(leftmost_leaf < 32); 35757c478bd9Sstevel@tonic-gate ASSERT(leftmost_leaf >= 0); 35767c478bd9Sstevel@tonic-gate 35777c478bd9Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) { 35787c478bd9Sstevel@tonic-gate if (mask & 0x1) { 35797c478bd9Sstevel@tonic-gate uFrame_bandwidth[j] = bandwidth; 35807c478bd9Sstevel@tonic-gate } else { 35817c478bd9Sstevel@tonic-gate uFrame_bandwidth[j] = 0; 35827c478bd9Sstevel@tonic-gate } 35837c478bd9Sstevel@tonic-gate 35847c478bd9Sstevel@tonic-gate mask = mask >> 1; 35857c478bd9Sstevel@tonic-gate } 35867c478bd9Sstevel@tonic-gate 35877c478bd9Sstevel@tonic-gate /* Updated all the effected leafs with the bandwidth */ 35887c478bd9Sstevel@tonic-gate for (i = 0; i < leaf_count; i++) { 35897c478bd9Sstevel@tonic-gate fbp = &ehcip->ehci_frame_bandwidth[leftmost_leaf + i]; 35907c478bd9Sstevel@tonic-gate 35917c478bd9Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) { 35927c478bd9Sstevel@tonic-gate fbp->ehci_micro_frame_bandwidth[j] += 35937c478bd9Sstevel@tonic-gate uFrame_bandwidth[j]; 35947c478bd9Sstevel@tonic-gate fbp->ehci_allocated_frame_bandwidth += 35957c478bd9Sstevel@tonic-gate uFrame_bandwidth[j]; 35967c478bd9Sstevel@tonic-gate } 35977c478bd9Sstevel@tonic-gate } 35987c478bd9Sstevel@tonic-gate } 35997c478bd9Sstevel@tonic-gate 36007c478bd9Sstevel@tonic-gate /* 36017c478bd9Sstevel@tonic-gate * Miscellaneous functions 36027c478bd9Sstevel@tonic-gate */ 36037c478bd9Sstevel@tonic-gate 36047c478bd9Sstevel@tonic-gate /* 36057c478bd9Sstevel@tonic-gate * ehci_obtain_state: 36067c478bd9Sstevel@tonic-gate * 36077c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 36087c478bd9Sstevel@tonic-gate */ 36097c478bd9Sstevel@tonic-gate ehci_state_t * 36107c478bd9Sstevel@tonic-gate ehci_obtain_state(dev_info_t *dip) 36117c478bd9Sstevel@tonic-gate { 36127c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 36137c478bd9Sstevel@tonic-gate 36147c478bd9Sstevel@tonic-gate ehci_state_t *state = ddi_get_soft_state(ehci_statep, instance); 36157c478bd9Sstevel@tonic-gate 36167c478bd9Sstevel@tonic-gate ASSERT(state != NULL); 36177c478bd9Sstevel@tonic-gate 36187c478bd9Sstevel@tonic-gate return (state); 36197c478bd9Sstevel@tonic-gate } 36207c478bd9Sstevel@tonic-gate 36217c478bd9Sstevel@tonic-gate 36227c478bd9Sstevel@tonic-gate /* 36237c478bd9Sstevel@tonic-gate * ehci_state_is_operational: 36247c478bd9Sstevel@tonic-gate * 36257c478bd9Sstevel@tonic-gate * Check the Host controller state and return proper values. 36267c478bd9Sstevel@tonic-gate */ 36277c478bd9Sstevel@tonic-gate int 36287c478bd9Sstevel@tonic-gate ehci_state_is_operational(ehci_state_t *ehcip) 36297c478bd9Sstevel@tonic-gate { 36307c478bd9Sstevel@tonic-gate int val; 36317c478bd9Sstevel@tonic-gate 36327c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 36337c478bd9Sstevel@tonic-gate 36347c478bd9Sstevel@tonic-gate switch (ehcip->ehci_hc_soft_state) { 36357c478bd9Sstevel@tonic-gate case EHCI_CTLR_INIT_STATE: 36367c478bd9Sstevel@tonic-gate case EHCI_CTLR_SUSPEND_STATE: 36377c478bd9Sstevel@tonic-gate val = USB_FAILURE; 36387c478bd9Sstevel@tonic-gate break; 36397c478bd9Sstevel@tonic-gate case EHCI_CTLR_OPERATIONAL_STATE: 36407c478bd9Sstevel@tonic-gate val = USB_SUCCESS; 36417c478bd9Sstevel@tonic-gate break; 36427c478bd9Sstevel@tonic-gate case EHCI_CTLR_ERROR_STATE: 36437c478bd9Sstevel@tonic-gate val = USB_HC_HARDWARE_ERROR; 36447c478bd9Sstevel@tonic-gate break; 36457c478bd9Sstevel@tonic-gate default: 36467c478bd9Sstevel@tonic-gate val = USB_FAILURE; 36477c478bd9Sstevel@tonic-gate break; 36487c478bd9Sstevel@tonic-gate } 36497c478bd9Sstevel@tonic-gate 36507c478bd9Sstevel@tonic-gate return (val); 36517c478bd9Sstevel@tonic-gate } 36527c478bd9Sstevel@tonic-gate 36537c478bd9Sstevel@tonic-gate 36547c478bd9Sstevel@tonic-gate /* 36557c478bd9Sstevel@tonic-gate * ehci_do_soft_reset 36567c478bd9Sstevel@tonic-gate * 36577c478bd9Sstevel@tonic-gate * Do soft reset of ehci host controller. 36587c478bd9Sstevel@tonic-gate */ 36597c478bd9Sstevel@tonic-gate int 36607c478bd9Sstevel@tonic-gate ehci_do_soft_reset(ehci_state_t *ehcip) 36617c478bd9Sstevel@tonic-gate { 36627c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 36637c478bd9Sstevel@tonic-gate ehci_regs_t *ehci_save_regs; 36647c478bd9Sstevel@tonic-gate 36657c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 36667c478bd9Sstevel@tonic-gate 36677c478bd9Sstevel@tonic-gate /* Increment host controller error count */ 36687c478bd9Sstevel@tonic-gate ehcip->ehci_hc_error++; 36697c478bd9Sstevel@tonic-gate 36707c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 36717c478bd9Sstevel@tonic-gate "ehci_do_soft_reset:" 36727c478bd9Sstevel@tonic-gate "Reset ehci host controller 0x%x", ehcip->ehci_hc_error); 36737c478bd9Sstevel@tonic-gate 36747c478bd9Sstevel@tonic-gate /* 36757c478bd9Sstevel@tonic-gate * Allocate space for saving current Host Controller 36767c478bd9Sstevel@tonic-gate * registers. Don't do any recovery if allocation 36777c478bd9Sstevel@tonic-gate * fails. 36787c478bd9Sstevel@tonic-gate */ 36797c478bd9Sstevel@tonic-gate ehci_save_regs = (ehci_regs_t *) 36807c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (ehci_regs_t), KM_NOSLEEP); 36817c478bd9Sstevel@tonic-gate 36827c478bd9Sstevel@tonic-gate if (ehci_save_regs == NULL) { 36837c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 36847c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: kmem_zalloc failed"); 36857c478bd9Sstevel@tonic-gate 36867c478bd9Sstevel@tonic-gate return (USB_FAILURE); 36877c478bd9Sstevel@tonic-gate } 36887c478bd9Sstevel@tonic-gate 36897c478bd9Sstevel@tonic-gate /* Save current ehci registers */ 36907c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_command = Get_OpReg(ehci_command); 36917c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_interrupt = Get_OpReg(ehci_interrupt); 36927c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_ctrl_segment = Get_OpReg(ehci_ctrl_segment); 36937c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_async_list_addr = Get_OpReg(ehci_async_list_addr); 36947c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_config_flag = Get_OpReg(ehci_config_flag); 36957c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_periodic_list_base = 36967c478bd9Sstevel@tonic-gate Get_OpReg(ehci_periodic_list_base); 36977c478bd9Sstevel@tonic-gate 36983b00f311Syq USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 3699112116d8Sfb "ehci_do_soft_reset: Save reg = 0x%p", (void *)ehci_save_regs); 37007c478bd9Sstevel@tonic-gate 37017c478bd9Sstevel@tonic-gate /* Disable all list processing and interrupts */ 37027c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, Get_OpReg(ehci_command) & 37037c478bd9Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE)); 37047c478bd9Sstevel@tonic-gate 37057c478bd9Sstevel@tonic-gate /* Disable all EHCI interrupts */ 37067c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0); 37077c478bd9Sstevel@tonic-gate 37087c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 37097c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_SOF_TIMEWAIT); 37107c478bd9Sstevel@tonic-gate 37117c478bd9Sstevel@tonic-gate /* Do light soft reset of ehci host controller */ 37127c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 37137c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) | EHCI_CMD_LIGHT_HC_RESET); 37147c478bd9Sstevel@tonic-gate 37153b00f311Syq USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 37167c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Reset in progress"); 37177c478bd9Sstevel@tonic-gate 37187c478bd9Sstevel@tonic-gate /* Wait for reset to complete */ 37197c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT); 37207c478bd9Sstevel@tonic-gate 37217c478bd9Sstevel@tonic-gate /* 37227c478bd9Sstevel@tonic-gate * Restore previous saved EHCI register value 37237c478bd9Sstevel@tonic-gate * into the current EHCI registers. 37247c478bd9Sstevel@tonic-gate */ 37257c478bd9Sstevel@tonic-gate Set_OpReg(ehci_ctrl_segment, (uint32_t) 372629aca3ebSlc ehci_save_regs->ehci_ctrl_segment); 37277c478bd9Sstevel@tonic-gate 37287c478bd9Sstevel@tonic-gate Set_OpReg(ehci_periodic_list_base, (uint32_t) 372929aca3ebSlc ehci_save_regs->ehci_periodic_list_base); 37307c478bd9Sstevel@tonic-gate 37317c478bd9Sstevel@tonic-gate Set_OpReg(ehci_async_list_addr, (uint32_t) 373229aca3ebSlc ehci_save_regs->ehci_async_list_addr); 37337c478bd9Sstevel@tonic-gate 3734921cd50dSgk /* 3735921cd50dSgk * For some reason this register might get nulled out by 3736921cd50dSgk * the Uli M1575 South Bridge. To workaround the hardware 3737921cd50dSgk * problem, check the value after write and retry if the 3738921cd50dSgk * last write fails. 3739921cd50dSgk */ 3740921cd50dSgk if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) && 3741921cd50dSgk (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) && 3742921cd50dSgk (ehci_save_regs->ehci_async_list_addr != 3743921cd50dSgk Get_OpReg(ehci_async_list_addr))) { 3744921cd50dSgk int retry = 0; 3745921cd50dSgk 3746921cd50dSgk Set_OpRegRetry(ehci_async_list_addr, (uint32_t) 374729aca3ebSlc ehci_save_regs->ehci_async_list_addr, retry); 3748921cd50dSgk if (retry >= EHCI_MAX_RETRY) { 37498668df41Slg USB_DPRINTF_L2(PRINT_MASK_ATTA, 3750921cd50dSgk ehcip->ehci_log_hdl, "ehci_do_soft_reset:" 3751921cd50dSgk " ASYNCLISTADDR write failed."); 3752921cd50dSgk 3753921cd50dSgk return (USB_FAILURE); 3754921cd50dSgk } 3755921cd50dSgk USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3756921cd50dSgk "ehci_do_soft_reset: ASYNCLISTADDR " 375729aca3ebSlc "write failed, retry=%d", retry); 3758921cd50dSgk } 3759921cd50dSgk 37607c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, (uint32_t) 376129aca3ebSlc ehci_save_regs->ehci_config_flag); 37627c478bd9Sstevel@tonic-gate 37637c478bd9Sstevel@tonic-gate /* Enable both Asynchronous and Periodic Schedule if necessary */ 37647c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehcip); 37657c478bd9Sstevel@tonic-gate 37667c478bd9Sstevel@tonic-gate /* 37677c478bd9Sstevel@tonic-gate * Set ehci_interrupt to enable all interrupts except Root 37687c478bd9Sstevel@tonic-gate * Hub Status change and frame list rollover interrupts. 37697c478bd9Sstevel@tonic-gate */ 37707c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR | 37717c478bd9Sstevel@tonic-gate EHCI_INTR_FRAME_LIST_ROLLOVER | 37727c478bd9Sstevel@tonic-gate EHCI_INTR_USB_ERROR | 37737c478bd9Sstevel@tonic-gate EHCI_INTR_USB); 37747c478bd9Sstevel@tonic-gate 37757c478bd9Sstevel@tonic-gate /* 37767c478bd9Sstevel@tonic-gate * Deallocate the space that allocated for saving 37777c478bd9Sstevel@tonic-gate * HC registers. 37787c478bd9Sstevel@tonic-gate */ 37797c478bd9Sstevel@tonic-gate kmem_free((void *) ehci_save_regs, sizeof (ehci_regs_t)); 37807c478bd9Sstevel@tonic-gate 37817c478bd9Sstevel@tonic-gate /* 37827c478bd9Sstevel@tonic-gate * Set the desired interrupt threshold, frame list size (if 37837c478bd9Sstevel@tonic-gate * applicable) and turn EHCI host controller. 37847c478bd9Sstevel@tonic-gate */ 37857c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, ((Get_OpReg(ehci_command) & 37867c478bd9Sstevel@tonic-gate ~EHCI_CMD_INTR_THRESHOLD) | 37877c478bd9Sstevel@tonic-gate (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN))); 37887c478bd9Sstevel@tonic-gate 37897c478bd9Sstevel@tonic-gate /* Wait 10ms for EHCI to start sending SOF */ 37907c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT); 37917c478bd9Sstevel@tonic-gate 37927c478bd9Sstevel@tonic-gate /* 37937c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for 37947c478bd9Sstevel@tonic-gate * few milliseconds. 37957c478bd9Sstevel@tonic-gate */ 37967c478bd9Sstevel@tonic-gate before_frame_number = ehci_get_current_frame_number(ehcip); 37977c478bd9Sstevel@tonic-gate 37987c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 37997c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_SOF_TIMEWAIT); 38007c478bd9Sstevel@tonic-gate 38017c478bd9Sstevel@tonic-gate /* 38027c478bd9Sstevel@tonic-gate * Get the current usb frame number after waiting for 38037c478bd9Sstevel@tonic-gate * few milliseconds. 38047c478bd9Sstevel@tonic-gate */ 38057c478bd9Sstevel@tonic-gate after_frame_number = ehci_get_current_frame_number(ehcip); 38067c478bd9Sstevel@tonic-gate 38077c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 38087c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Before Frame Number 0x%llx " 38097c478bd9Sstevel@tonic-gate "After Frame Number 0x%llx", 3810112116d8Sfb (unsigned long long)before_frame_number, 3811112116d8Sfb (unsigned long long)after_frame_number); 38127c478bd9Sstevel@tonic-gate 38137c478bd9Sstevel@tonic-gate if ((after_frame_number <= before_frame_number) && 38147c478bd9Sstevel@tonic-gate (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) { 38157c478bd9Sstevel@tonic-gate 38167c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 38177c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Soft reset failed"); 38187c478bd9Sstevel@tonic-gate 38197c478bd9Sstevel@tonic-gate return (USB_FAILURE); 38207c478bd9Sstevel@tonic-gate } 38217c478bd9Sstevel@tonic-gate 38227c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 38237c478bd9Sstevel@tonic-gate } 38247c478bd9Sstevel@tonic-gate 38257c478bd9Sstevel@tonic-gate 38267c478bd9Sstevel@tonic-gate /* 38277c478bd9Sstevel@tonic-gate * ehci_get_xfer_attrs: 38287c478bd9Sstevel@tonic-gate * 38297c478bd9Sstevel@tonic-gate * Get the attributes of a particular xfer. 38307c478bd9Sstevel@tonic-gate * 38317c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 38327c478bd9Sstevel@tonic-gate */ 38337c478bd9Sstevel@tonic-gate usb_req_attrs_t 38347c478bd9Sstevel@tonic-gate ehci_get_xfer_attrs( 38357c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 38367c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 38377c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 38387c478bd9Sstevel@tonic-gate { 38397c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep; 38407c478bd9Sstevel@tonic-gate usb_req_attrs_t attrs = USB_ATTRS_NONE; 38417c478bd9Sstevel@tonic-gate 38427c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 38437c478bd9Sstevel@tonic-gate "ehci_get_xfer_attrs:"); 38447c478bd9Sstevel@tonic-gate 38457c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 38467c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 38477c478bd9Sstevel@tonic-gate attrs = ((usb_ctrl_req_t *) 38487c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->ctrl_attributes; 38497c478bd9Sstevel@tonic-gate break; 38507c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 38517c478bd9Sstevel@tonic-gate attrs = ((usb_bulk_req_t *) 38527c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->bulk_attributes; 38537c478bd9Sstevel@tonic-gate break; 38547c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 38557c478bd9Sstevel@tonic-gate attrs = ((usb_intr_req_t *) 38567c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->intr_attributes; 38577c478bd9Sstevel@tonic-gate break; 38587c478bd9Sstevel@tonic-gate } 38597c478bd9Sstevel@tonic-gate 38607c478bd9Sstevel@tonic-gate return (attrs); 38617c478bd9Sstevel@tonic-gate } 38627c478bd9Sstevel@tonic-gate 38637c478bd9Sstevel@tonic-gate 38647c478bd9Sstevel@tonic-gate /* 38657c478bd9Sstevel@tonic-gate * ehci_get_current_frame_number: 38667c478bd9Sstevel@tonic-gate * 38677c478bd9Sstevel@tonic-gate * Get the current software based usb frame number. 38687c478bd9Sstevel@tonic-gate */ 38697c478bd9Sstevel@tonic-gate usb_frame_number_t 38707c478bd9Sstevel@tonic-gate ehci_get_current_frame_number(ehci_state_t *ehcip) 38717c478bd9Sstevel@tonic-gate { 38727c478bd9Sstevel@tonic-gate usb_frame_number_t usb_frame_number; 38737c478bd9Sstevel@tonic-gate usb_frame_number_t ehci_fno, micro_frame_number; 38747c478bd9Sstevel@tonic-gate 38757c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 38767c478bd9Sstevel@tonic-gate 38777c478bd9Sstevel@tonic-gate ehci_fno = ehcip->ehci_fno; 38787c478bd9Sstevel@tonic-gate micro_frame_number = Get_OpReg(ehci_frame_index) & 0x3FFF; 38797c478bd9Sstevel@tonic-gate 38807c478bd9Sstevel@tonic-gate /* 38817c478bd9Sstevel@tonic-gate * Calculate current software based usb frame number. 38827c478bd9Sstevel@tonic-gate * 38837c478bd9Sstevel@tonic-gate * This code accounts for the fact that frame number is 38847c478bd9Sstevel@tonic-gate * updated by the Host Controller before the ehci driver 38857c478bd9Sstevel@tonic-gate * gets an FrameListRollover interrupt that will adjust 38867c478bd9Sstevel@tonic-gate * Frame higher part. 38877c478bd9Sstevel@tonic-gate * 38887c478bd9Sstevel@tonic-gate * Refer ehci specification 1.0, section 2.3.2, page 21. 38897c478bd9Sstevel@tonic-gate */ 38907c478bd9Sstevel@tonic-gate micro_frame_number = ((micro_frame_number & 0x1FFF) | 38917c478bd9Sstevel@tonic-gate ehci_fno) + (((micro_frame_number & 0x3FFF) ^ 38927c478bd9Sstevel@tonic-gate ehci_fno) & 0x2000); 38937c478bd9Sstevel@tonic-gate 38947c478bd9Sstevel@tonic-gate /* 38957c478bd9Sstevel@tonic-gate * Micro Frame number is equivalent to 125 usec. Eight 38967c478bd9Sstevel@tonic-gate * Micro Frame numbers are equivalent to one millsecond 38977c478bd9Sstevel@tonic-gate * or one usb frame number. 38987c478bd9Sstevel@tonic-gate */ 38997c478bd9Sstevel@tonic-gate usb_frame_number = micro_frame_number >> 39007c478bd9Sstevel@tonic-gate EHCI_uFRAMES_PER_USB_FRAME_SHIFT; 39017c478bd9Sstevel@tonic-gate 39027c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 39037c478bd9Sstevel@tonic-gate "ehci_get_current_frame_number: " 39047c478bd9Sstevel@tonic-gate "Current usb uframe number = 0x%llx " 39057c478bd9Sstevel@tonic-gate "Current usb frame number = 0x%llx", 3906112116d8Sfb (unsigned long long)micro_frame_number, 3907112116d8Sfb (unsigned long long)usb_frame_number); 39087c478bd9Sstevel@tonic-gate 39097c478bd9Sstevel@tonic-gate return (usb_frame_number); 39107c478bd9Sstevel@tonic-gate } 39117c478bd9Sstevel@tonic-gate 39127c478bd9Sstevel@tonic-gate 39137c478bd9Sstevel@tonic-gate /* 39147c478bd9Sstevel@tonic-gate * ehci_cpr_cleanup: 39157c478bd9Sstevel@tonic-gate * 39167c478bd9Sstevel@tonic-gate * Cleanup ehci state and other ehci specific informations across 39177c478bd9Sstevel@tonic-gate * Check Point Resume (CPR). 39187c478bd9Sstevel@tonic-gate */ 39197c478bd9Sstevel@tonic-gate static void 39207c478bd9Sstevel@tonic-gate ehci_cpr_cleanup(ehci_state_t *ehcip) 39217c478bd9Sstevel@tonic-gate { 39227c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 39237c478bd9Sstevel@tonic-gate 39247c478bd9Sstevel@tonic-gate /* Reset software part of usb frame number */ 39257c478bd9Sstevel@tonic-gate ehcip->ehci_fno = 0; 39267c478bd9Sstevel@tonic-gate } 39277c478bd9Sstevel@tonic-gate 39287c478bd9Sstevel@tonic-gate 39297c478bd9Sstevel@tonic-gate /* 39307c478bd9Sstevel@tonic-gate * ehci_wait_for_sof: 39317c478bd9Sstevel@tonic-gate * 39327c478bd9Sstevel@tonic-gate * Wait for couple of SOF interrupts 39337c478bd9Sstevel@tonic-gate */ 39347c478bd9Sstevel@tonic-gate int 39357c478bd9Sstevel@tonic-gate ehci_wait_for_sof(ehci_state_t *ehcip) 39367c478bd9Sstevel@tonic-gate { 39377c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 39387c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 39397c478bd9Sstevel@tonic-gate 39407c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, 39417c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, "ehci_wait_for_sof"); 39427c478bd9Sstevel@tonic-gate 39437c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 39447c478bd9Sstevel@tonic-gate 39457c478bd9Sstevel@tonic-gate error = ehci_state_is_operational(ehcip); 39467c478bd9Sstevel@tonic-gate 39477c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 39487c478bd9Sstevel@tonic-gate 39497c478bd9Sstevel@tonic-gate return (error); 39507c478bd9Sstevel@tonic-gate } 39517c478bd9Sstevel@tonic-gate 39527c478bd9Sstevel@tonic-gate /* Get the current usb frame number before waiting for two SOFs */ 39537c478bd9Sstevel@tonic-gate before_frame_number = ehci_get_current_frame_number(ehcip); 39547c478bd9Sstevel@tonic-gate 39557c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 39567c478bd9Sstevel@tonic-gate 39577c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 39587c478bd9Sstevel@tonic-gate delay(drv_usectohz(EHCI_SOF_TIMEWAIT)); 39597c478bd9Sstevel@tonic-gate 39607c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 39617c478bd9Sstevel@tonic-gate 39627c478bd9Sstevel@tonic-gate /* Get the current usb frame number after woken up */ 39637c478bd9Sstevel@tonic-gate after_frame_number = ehci_get_current_frame_number(ehcip); 39647c478bd9Sstevel@tonic-gate 39657c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 39667c478bd9Sstevel@tonic-gate "ehci_wait_for_sof: framenumber: before 0x%llx " 3967112116d8Sfb "after 0x%llx", 3968112116d8Sfb (unsigned long long)before_frame_number, 3969112116d8Sfb (unsigned long long)after_frame_number); 39707c478bd9Sstevel@tonic-gate 39717c478bd9Sstevel@tonic-gate /* Return failure, if usb frame number has not been changed */ 39727c478bd9Sstevel@tonic-gate if (after_frame_number <= before_frame_number) { 39737c478bd9Sstevel@tonic-gate 39747c478bd9Sstevel@tonic-gate if ((ehci_do_soft_reset(ehcip)) != USB_SUCCESS) { 39757c478bd9Sstevel@tonic-gate 39767c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_LISTS, 39777c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, "No SOF interrupts"); 39787c478bd9Sstevel@tonic-gate 39797c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */ 39807c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE; 39817c478bd9Sstevel@tonic-gate 39827c478bd9Sstevel@tonic-gate return (USB_FAILURE); 39837c478bd9Sstevel@tonic-gate } 39847c478bd9Sstevel@tonic-gate 39857c478bd9Sstevel@tonic-gate } 39867c478bd9Sstevel@tonic-gate 39877c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 39887c478bd9Sstevel@tonic-gate } 39897c478bd9Sstevel@tonic-gate 39907c478bd9Sstevel@tonic-gate 39917c478bd9Sstevel@tonic-gate /* 39927c478bd9Sstevel@tonic-gate * ehci_toggle_scheduler: 39937c478bd9Sstevel@tonic-gate * 39947c478bd9Sstevel@tonic-gate * Turn scheduler based on pipe open count. 39957c478bd9Sstevel@tonic-gate */ 39967c478bd9Sstevel@tonic-gate void 39977c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehci_state_t *ehcip) { 39987c478bd9Sstevel@tonic-gate uint_t temp_reg, cmd_reg; 39997c478bd9Sstevel@tonic-gate 40007c478bd9Sstevel@tonic-gate cmd_reg = Get_OpReg(ehci_command); 40017c478bd9Sstevel@tonic-gate temp_reg = cmd_reg; 40027c478bd9Sstevel@tonic-gate 40037c478bd9Sstevel@tonic-gate /* 40047c478bd9Sstevel@tonic-gate * Enable/Disable asynchronous scheduler, and 40057c478bd9Sstevel@tonic-gate * turn on/off async list door bell 40067c478bd9Sstevel@tonic-gate */ 40077c478bd9Sstevel@tonic-gate if (ehcip->ehci_open_async_count) { 40087c478bd9Sstevel@tonic-gate if (!(cmd_reg & EHCI_CMD_ASYNC_SCHED_ENABLE)) { 40097c478bd9Sstevel@tonic-gate /* 40107c478bd9Sstevel@tonic-gate * For some reason this address might get nulled out by 40117c478bd9Sstevel@tonic-gate * the ehci chip. Set it here just in case it is null. 40127c478bd9Sstevel@tonic-gate */ 40137c478bd9Sstevel@tonic-gate Set_OpReg(ehci_async_list_addr, 40147c478bd9Sstevel@tonic-gate ehci_qh_cpu_to_iommu(ehcip, 40157c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list)); 4016921cd50dSgk 4017921cd50dSgk /* 4018921cd50dSgk * For some reason this register might get nulled out by 4019921cd50dSgk * the Uli M1575 Southbridge. To workaround the HW 4020921cd50dSgk * problem, check the value after write and retry if the 4021921cd50dSgk * last write fails. 4022921cd50dSgk * 4023921cd50dSgk * If the ASYNCLISTADDR remains "stuck" after 4024921cd50dSgk * EHCI_MAX_RETRY retries, then the M1575 is broken 4025921cd50dSgk * and is stuck in an inconsistent state and is about 4026921cd50dSgk * to crash the machine with a trn_oor panic when it 4027921cd50dSgk * does a DMA read from 0x0. It is better to panic 4028921cd50dSgk * now rather than wait for the trn_oor crash; this 4029921cd50dSgk * way Customer Service will have a clean signature 4030921cd50dSgk * that indicts the M1575 chip rather than a 4031921cd50dSgk * mysterious and hard-to-diagnose trn_oor panic. 4032921cd50dSgk */ 4033921cd50dSgk if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) && 4034921cd50dSgk (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) && 4035921cd50dSgk (ehci_qh_cpu_to_iommu(ehcip, 4036921cd50dSgk ehcip->ehci_head_of_async_sched_list) != 4037921cd50dSgk Get_OpReg(ehci_async_list_addr))) { 4038921cd50dSgk int retry = 0; 4039921cd50dSgk 4040921cd50dSgk Set_OpRegRetry(ehci_async_list_addr, 4041921cd50dSgk ehci_qh_cpu_to_iommu(ehcip, 4042921cd50dSgk ehcip->ehci_head_of_async_sched_list), 4043921cd50dSgk retry); 4044921cd50dSgk if (retry >= EHCI_MAX_RETRY) 4045921cd50dSgk cmn_err(CE_PANIC, 4046921cd50dSgk "ehci_toggle_scheduler: " 4047921cd50dSgk "ASYNCLISTADDR write failed."); 4048921cd50dSgk 4049921cd50dSgk USB_DPRINTF_L2(PRINT_MASK_ATTA, 4050921cd50dSgk ehcip->ehci_log_hdl, 4051921cd50dSgk "ehci_toggle_scheduler: ASYNCLISTADDR " 4052921cd50dSgk "write failed, retry=%d", retry); 4053921cd50dSgk } 40547c478bd9Sstevel@tonic-gate } 40557c478bd9Sstevel@tonic-gate cmd_reg |= EHCI_CMD_ASYNC_SCHED_ENABLE; 40567c478bd9Sstevel@tonic-gate } else { 40577c478bd9Sstevel@tonic-gate cmd_reg &= ~EHCI_CMD_ASYNC_SCHED_ENABLE; 40587c478bd9Sstevel@tonic-gate } 40597c478bd9Sstevel@tonic-gate 40607c478bd9Sstevel@tonic-gate if (ehcip->ehci_open_periodic_count) { 40617c478bd9Sstevel@tonic-gate if (!(cmd_reg & EHCI_CMD_PERIODIC_SCHED_ENABLE)) { 40627c478bd9Sstevel@tonic-gate /* 40637c478bd9Sstevel@tonic-gate * For some reason this address get's nulled out by 40647c478bd9Sstevel@tonic-gate * the ehci chip. Set it here just in case it is null. 40657c478bd9Sstevel@tonic-gate */ 40667c478bd9Sstevel@tonic-gate Set_OpReg(ehci_periodic_list_base, 40677c478bd9Sstevel@tonic-gate (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address & 40687c478bd9Sstevel@tonic-gate 0xFFFFF000)); 40697c478bd9Sstevel@tonic-gate } 40707c478bd9Sstevel@tonic-gate cmd_reg |= EHCI_CMD_PERIODIC_SCHED_ENABLE; 40717c478bd9Sstevel@tonic-gate } else { 40727c478bd9Sstevel@tonic-gate cmd_reg &= ~EHCI_CMD_PERIODIC_SCHED_ENABLE; 40737c478bd9Sstevel@tonic-gate } 40747c478bd9Sstevel@tonic-gate 40757c478bd9Sstevel@tonic-gate /* Just an optimization */ 40767c478bd9Sstevel@tonic-gate if (temp_reg != cmd_reg) { 40777c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, cmd_reg); 40787c478bd9Sstevel@tonic-gate } 40797c478bd9Sstevel@tonic-gate } 40807c478bd9Sstevel@tonic-gate 40817c478bd9Sstevel@tonic-gate /* 40827c478bd9Sstevel@tonic-gate * ehci print functions 40837c478bd9Sstevel@tonic-gate */ 40847c478bd9Sstevel@tonic-gate 40857c478bd9Sstevel@tonic-gate /* 40867c478bd9Sstevel@tonic-gate * ehci_print_caps: 40877c478bd9Sstevel@tonic-gate */ 40887c478bd9Sstevel@tonic-gate void 40897c478bd9Sstevel@tonic-gate ehci_print_caps(ehci_state_t *ehcip) 40907c478bd9Sstevel@tonic-gate { 40917c478bd9Sstevel@tonic-gate uint_t i; 40927c478bd9Sstevel@tonic-gate 40937c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40947c478bd9Sstevel@tonic-gate "\n\tUSB 2.0 Host Controller Characteristics\n"); 40957c478bd9Sstevel@tonic-gate 40967c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40977c478bd9Sstevel@tonic-gate "Caps Length: 0x%x Version: 0x%x\n", 40987c478bd9Sstevel@tonic-gate Get_8Cap(ehci_caps_length), Get_16Cap(ehci_version)); 40997c478bd9Sstevel@tonic-gate 41007c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41017c478bd9Sstevel@tonic-gate "Structural Parameters\n"); 41027c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41037c478bd9Sstevel@tonic-gate "Port indicators: %s", (Get_Cap(ehci_hcs_params) & 41047c478bd9Sstevel@tonic-gate EHCI_HCS_PORT_INDICATOR) ? "Yes" : "No"); 41057c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41067c478bd9Sstevel@tonic-gate "No of Classic host controllers: 0x%x", 41077c478bd9Sstevel@tonic-gate (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_COMP_CTRLS) 41087c478bd9Sstevel@tonic-gate >> EHCI_HCS_NUM_COMP_CTRL_SHIFT); 41097c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41107c478bd9Sstevel@tonic-gate "No of ports per Classic host controller: 0x%x", 41117c478bd9Sstevel@tonic-gate (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS_CC) 41127c478bd9Sstevel@tonic-gate >> EHCI_HCS_NUM_PORTS_CC_SHIFT); 41137c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41147c478bd9Sstevel@tonic-gate "Port routing rules: %s", (Get_Cap(ehci_hcs_params) & 41157c478bd9Sstevel@tonic-gate EHCI_HCS_PORT_ROUTING_RULES) ? "Yes" : "No"); 41167c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41177c478bd9Sstevel@tonic-gate "Port power control: %s", (Get_Cap(ehci_hcs_params) & 41187c478bd9Sstevel@tonic-gate EHCI_HCS_PORT_POWER_CONTROL) ? "Yes" : "No"); 41197c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41207c478bd9Sstevel@tonic-gate "No of root hub ports: 0x%x\n", 41217c478bd9Sstevel@tonic-gate Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); 41227c478bd9Sstevel@tonic-gate 41237c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41247c478bd9Sstevel@tonic-gate "Capability Parameters\n"); 41257c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41267c478bd9Sstevel@tonic-gate "EHCI extended capability: %s", (Get_Cap(ehci_hcc_params) & 41277c478bd9Sstevel@tonic-gate EHCI_HCC_EECP) ? "Yes" : "No"); 41287c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41297c478bd9Sstevel@tonic-gate "Isoch schedule threshold: 0x%x", 41307c478bd9Sstevel@tonic-gate Get_Cap(ehci_hcc_params) & EHCI_HCC_ISOCH_SCHED_THRESHOLD); 41317c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41327c478bd9Sstevel@tonic-gate "Async schedule park capability: %s", (Get_Cap(ehci_hcc_params) & 41337c478bd9Sstevel@tonic-gate EHCI_HCC_ASYNC_SCHED_PARK_CAP) ? "Yes" : "No"); 41347c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41357c478bd9Sstevel@tonic-gate "Programmable frame list flag: %s", (Get_Cap(ehci_hcc_params) & 41367c478bd9Sstevel@tonic-gate EHCI_HCC_PROG_FRAME_LIST_FLAG) ? "256/512/1024" : "1024"); 41377c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41387c478bd9Sstevel@tonic-gate "64bit addressing capability: %s\n", (Get_Cap(ehci_hcc_params) & 41397c478bd9Sstevel@tonic-gate EHCI_HCC_64BIT_ADDR_CAP) ? "Yes" : "No"); 41407c478bd9Sstevel@tonic-gate 41417c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41427c478bd9Sstevel@tonic-gate "Classic Port Route Description"); 41437c478bd9Sstevel@tonic-gate 41447c478bd9Sstevel@tonic-gate for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) { 41457c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41467c478bd9Sstevel@tonic-gate "\tPort Route 0x%x: 0x%x", i, Get_8Cap(ehci_port_route[i])); 41477c478bd9Sstevel@tonic-gate } 41487c478bd9Sstevel@tonic-gate } 41497c478bd9Sstevel@tonic-gate 41507c478bd9Sstevel@tonic-gate 41517c478bd9Sstevel@tonic-gate /* 41527c478bd9Sstevel@tonic-gate * ehci_print_regs: 41537c478bd9Sstevel@tonic-gate */ 41547c478bd9Sstevel@tonic-gate void 41557c478bd9Sstevel@tonic-gate ehci_print_regs(ehci_state_t *ehcip) 41567c478bd9Sstevel@tonic-gate { 41577c478bd9Sstevel@tonic-gate uint_t i; 41587c478bd9Sstevel@tonic-gate 41597c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41607c478bd9Sstevel@tonic-gate "\n\tEHCI%d Operational Registers\n", 41617c478bd9Sstevel@tonic-gate ddi_get_instance(ehcip->ehci_dip)); 41627c478bd9Sstevel@tonic-gate 41637c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41647c478bd9Sstevel@tonic-gate "Command: 0x%x Status: 0x%x", 41657c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command), Get_OpReg(ehci_status)); 41667c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41677c478bd9Sstevel@tonic-gate "Interrupt: 0x%x Frame Index: 0x%x", 41687c478bd9Sstevel@tonic-gate Get_OpReg(ehci_interrupt), Get_OpReg(ehci_frame_index)); 41697c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41707c478bd9Sstevel@tonic-gate "Control Segment: 0x%x Periodic List Base: 0x%x", 41717c478bd9Sstevel@tonic-gate Get_OpReg(ehci_ctrl_segment), Get_OpReg(ehci_periodic_list_base)); 41727c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41737c478bd9Sstevel@tonic-gate "Async List Addr: 0x%x Config Flag: 0x%x", 41747c478bd9Sstevel@tonic-gate Get_OpReg(ehci_async_list_addr), Get_OpReg(ehci_config_flag)); 41757c478bd9Sstevel@tonic-gate 41767c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41777c478bd9Sstevel@tonic-gate "Root Hub Port Status"); 41787c478bd9Sstevel@tonic-gate 41797c478bd9Sstevel@tonic-gate for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) { 41807c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41817c478bd9Sstevel@tonic-gate "\tPort Status 0x%x: 0x%x ", i, 41827c478bd9Sstevel@tonic-gate Get_OpReg(ehci_rh_port_status[i])); 41837c478bd9Sstevel@tonic-gate } 41847c478bd9Sstevel@tonic-gate } 41857c478bd9Sstevel@tonic-gate 41867c478bd9Sstevel@tonic-gate 41877c478bd9Sstevel@tonic-gate /* 41887c478bd9Sstevel@tonic-gate * ehci_print_qh: 41897c478bd9Sstevel@tonic-gate */ 41907c478bd9Sstevel@tonic-gate void 41917c478bd9Sstevel@tonic-gate ehci_print_qh( 41927c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 41937c478bd9Sstevel@tonic-gate ehci_qh_t *qh) 41947c478bd9Sstevel@tonic-gate { 41957c478bd9Sstevel@tonic-gate uint_t i; 41967c478bd9Sstevel@tonic-gate 41977c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41987c478bd9Sstevel@tonic-gate "ehci_print_qh: qh = 0x%p", (void *)qh); 41997c478bd9Sstevel@tonic-gate 42007c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42017c478bd9Sstevel@tonic-gate "\tqh_link_ptr: 0x%x ", Get_QH(qh->qh_link_ptr)); 42027c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42037c478bd9Sstevel@tonic-gate "\tqh_ctrl: 0x%x ", Get_QH(qh->qh_ctrl)); 42047c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42057c478bd9Sstevel@tonic-gate "\tqh_split_ctrl: 0x%x ", Get_QH(qh->qh_split_ctrl)); 42067c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42077c478bd9Sstevel@tonic-gate "\tqh_curr_qtd: 0x%x ", Get_QH(qh->qh_curr_qtd)); 42087c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42097c478bd9Sstevel@tonic-gate "\tqh_next_qtd: 0x%x ", Get_QH(qh->qh_next_qtd)); 42107c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42117c478bd9Sstevel@tonic-gate "\tqh_alt_next_qtd: 0x%x ", Get_QH(qh->qh_alt_next_qtd)); 42127c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42137c478bd9Sstevel@tonic-gate "\tqh_status: 0x%x ", Get_QH(qh->qh_status)); 42147c478bd9Sstevel@tonic-gate 42157c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 42167c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42177c478bd9Sstevel@tonic-gate "\tqh_buf[%d]: 0x%x ", i, Get_QH(qh->qh_buf[i])); 42187c478bd9Sstevel@tonic-gate } 42197c478bd9Sstevel@tonic-gate 42207c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 42217c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42227c478bd9Sstevel@tonic-gate "\tqh_buf_high[%d]: 0x%x ", 42237c478bd9Sstevel@tonic-gate i, Get_QH(qh->qh_buf_high[i])); 42247c478bd9Sstevel@tonic-gate } 42257c478bd9Sstevel@tonic-gate 42267c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42277c478bd9Sstevel@tonic-gate "\tqh_dummy_qtd: 0x%x ", Get_QH(qh->qh_dummy_qtd)); 42287c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42297c478bd9Sstevel@tonic-gate "\tqh_prev: 0x%x ", Get_QH(qh->qh_prev)); 42307c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42317c478bd9Sstevel@tonic-gate "\tqh_state: 0x%x ", Get_QH(qh->qh_state)); 42327c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42337c478bd9Sstevel@tonic-gate "\tqh_reclaim_next: 0x%x ", Get_QH(qh->qh_reclaim_next)); 42347c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42357c478bd9Sstevel@tonic-gate "\tqh_reclaim_frame: 0x%x ", Get_QH(qh->qh_reclaim_frame)); 42367c478bd9Sstevel@tonic-gate } 42377c478bd9Sstevel@tonic-gate 42387c478bd9Sstevel@tonic-gate 42397c478bd9Sstevel@tonic-gate /* 42407c478bd9Sstevel@tonic-gate * ehci_print_qtd: 42417c478bd9Sstevel@tonic-gate */ 42427c478bd9Sstevel@tonic-gate void 42437c478bd9Sstevel@tonic-gate ehci_print_qtd( 42447c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 42457c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd) 42467c478bd9Sstevel@tonic-gate { 42477c478bd9Sstevel@tonic-gate uint_t i; 42487c478bd9Sstevel@tonic-gate 42497c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42507c478bd9Sstevel@tonic-gate "ehci_print_qtd: qtd = 0x%p", (void *)qtd); 42517c478bd9Sstevel@tonic-gate 42527c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42537c478bd9Sstevel@tonic-gate "\tqtd_next_qtd: 0x%x ", Get_QTD(qtd->qtd_next_qtd)); 42547c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42557c478bd9Sstevel@tonic-gate "\tqtd_alt_next_qtd: 0x%x ", Get_QTD(qtd->qtd_alt_next_qtd)); 42567c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42577c478bd9Sstevel@tonic-gate "\tqtd_ctrl: 0x%x ", Get_QTD(qtd->qtd_ctrl)); 42587c478bd9Sstevel@tonic-gate 42597c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 42607c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42617c478bd9Sstevel@tonic-gate "\tqtd_buf[%d]: 0x%x ", i, Get_QTD(qtd->qtd_buf[i])); 42627c478bd9Sstevel@tonic-gate } 42637c478bd9Sstevel@tonic-gate 42647c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 42657c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42667c478bd9Sstevel@tonic-gate "\tqtd_buf_high[%d]: 0x%x ", 42677c478bd9Sstevel@tonic-gate i, Get_QTD(qtd->qtd_buf_high[i])); 42687c478bd9Sstevel@tonic-gate } 42697c478bd9Sstevel@tonic-gate 42707c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42717c478bd9Sstevel@tonic-gate "\tqtd_trans_wrapper: 0x%x ", Get_QTD(qtd->qtd_trans_wrapper)); 42727c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42737c478bd9Sstevel@tonic-gate "\tqtd_tw_next_qtd: 0x%x ", Get_QTD(qtd->qtd_tw_next_qtd)); 42747c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42757c478bd9Sstevel@tonic-gate "\tqtd_active_qtd_next: 0x%x ", Get_QTD(qtd->qtd_active_qtd_next)); 42767c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42777c478bd9Sstevel@tonic-gate "\tqtd_active_qtd_prev: 0x%x ", Get_QTD(qtd->qtd_active_qtd_prev)); 42787c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42797c478bd9Sstevel@tonic-gate "\tqtd_state: 0x%x ", Get_QTD(qtd->qtd_state)); 42807c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42817c478bd9Sstevel@tonic-gate "\tqtd_ctrl_phase: 0x%x ", Get_QTD(qtd->qtd_ctrl_phase)); 42827c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42833304303fSsl "\tqtd_xfer_offs: 0x%x ", Get_QTD(qtd->qtd_xfer_offs)); 42847c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42857c478bd9Sstevel@tonic-gate "\tqtd_xfer_len: 0x%x ", Get_QTD(qtd->qtd_xfer_len)); 42867c478bd9Sstevel@tonic-gate } 42877c478bd9Sstevel@tonic-gate 42887c478bd9Sstevel@tonic-gate /* 42897c478bd9Sstevel@tonic-gate * ehci kstat functions 42907c478bd9Sstevel@tonic-gate */ 42917c478bd9Sstevel@tonic-gate 42927c478bd9Sstevel@tonic-gate /* 42937c478bd9Sstevel@tonic-gate * ehci_create_stats: 42947c478bd9Sstevel@tonic-gate * 42957c478bd9Sstevel@tonic-gate * Allocate and initialize the ehci kstat structures 42967c478bd9Sstevel@tonic-gate */ 42977c478bd9Sstevel@tonic-gate void 42987c478bd9Sstevel@tonic-gate ehci_create_stats(ehci_state_t *ehcip) 42997c478bd9Sstevel@tonic-gate { 43007c478bd9Sstevel@tonic-gate char kstatname[KSTAT_STRLEN]; 43017c478bd9Sstevel@tonic-gate const char *dname = ddi_driver_name(ehcip->ehci_dip); 43027c478bd9Sstevel@tonic-gate char *usbtypes[USB_N_COUNT_KSTATS] = 430329aca3ebSlc {"ctrl", "isoch", "bulk", "intr"}; 43047c478bd9Sstevel@tonic-gate uint_t instance = ehcip->ehci_instance; 43057c478bd9Sstevel@tonic-gate ehci_intrs_stats_t *isp; 43067c478bd9Sstevel@tonic-gate int i; 43077c478bd9Sstevel@tonic-gate 43087c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip) == NULL) { 43097c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,intrs", 43107c478bd9Sstevel@tonic-gate dname, instance); 43117c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip) = kstat_create("usba", instance, 43127c478bd9Sstevel@tonic-gate kstatname, "usb_interrupts", KSTAT_TYPE_NAMED, 43137c478bd9Sstevel@tonic-gate sizeof (ehci_intrs_stats_t) / sizeof (kstat_named_t), 43147c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 43157c478bd9Sstevel@tonic-gate 43167c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) { 43177c478bd9Sstevel@tonic-gate isp = EHCI_INTRS_STATS_DATA(ehcip); 43187c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_total, 43197c478bd9Sstevel@tonic-gate "Interrupts Total", KSTAT_DATA_UINT64); 43207c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_not_claimed, 43217c478bd9Sstevel@tonic-gate "Not Claimed", KSTAT_DATA_UINT64); 43227c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_async_sched_status, 43237c478bd9Sstevel@tonic-gate "Async schedule status", KSTAT_DATA_UINT64); 43247c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_periodic_sched_status, 43257c478bd9Sstevel@tonic-gate "Periodic sched status", KSTAT_DATA_UINT64); 43267c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_empty_async_schedule, 43277c478bd9Sstevel@tonic-gate "Empty async schedule", KSTAT_DATA_UINT64); 43287c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_host_ctrl_halted, 43297c478bd9Sstevel@tonic-gate "Host controller Halted", KSTAT_DATA_UINT64); 43307c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_async_advance_intr, 43317c478bd9Sstevel@tonic-gate "Intr on async advance", KSTAT_DATA_UINT64); 43327c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_host_system_error_intr, 43337c478bd9Sstevel@tonic-gate "Host system error", KSTAT_DATA_UINT64); 43347c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_frm_list_rollover_intr, 43357c478bd9Sstevel@tonic-gate "Frame list rollover", KSTAT_DATA_UINT64); 43367c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_rh_port_change_intr, 43377c478bd9Sstevel@tonic-gate "Port change detect", KSTAT_DATA_UINT64); 43387c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_usb_error_intr, 43397c478bd9Sstevel@tonic-gate "USB error interrupt", KSTAT_DATA_UINT64); 43407c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_usb_intr, 43417c478bd9Sstevel@tonic-gate "USB interrupt", KSTAT_DATA_UINT64); 43427c478bd9Sstevel@tonic-gate 43437c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip)->ks_private = ehcip; 43447c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip)->ks_update = nulldev; 43457c478bd9Sstevel@tonic-gate kstat_install(EHCI_INTRS_STATS(ehcip)); 43467c478bd9Sstevel@tonic-gate } 43477c478bd9Sstevel@tonic-gate } 43487c478bd9Sstevel@tonic-gate 43497c478bd9Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip) == NULL) { 43507c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,total", 43517c478bd9Sstevel@tonic-gate dname, instance); 43527c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS(ehcip) = kstat_create("usba", instance, 43537c478bd9Sstevel@tonic-gate kstatname, "usb_byte_count", KSTAT_TYPE_IO, 1, 43547c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 43557c478bd9Sstevel@tonic-gate 43567c478bd9Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip)) { 43577c478bd9Sstevel@tonic-gate kstat_install(EHCI_TOTAL_STATS(ehcip)); 43587c478bd9Sstevel@tonic-gate } 43597c478bd9Sstevel@tonic-gate } 43607c478bd9Sstevel@tonic-gate 43617c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) { 43627c478bd9Sstevel@tonic-gate if (ehcip->ehci_count_stats[i] == NULL) { 43637c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,%s", 43647c478bd9Sstevel@tonic-gate dname, instance, usbtypes[i]); 43657c478bd9Sstevel@tonic-gate ehcip->ehci_count_stats[i] = kstat_create("usba", 43667c478bd9Sstevel@tonic-gate instance, kstatname, "usb_byte_count", 43677c478bd9Sstevel@tonic-gate KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT); 43687c478bd9Sstevel@tonic-gate 43697c478bd9Sstevel@tonic-gate if (ehcip->ehci_count_stats[i]) { 43707c478bd9Sstevel@tonic-gate kstat_install(ehcip->ehci_count_stats[i]); 43717c478bd9Sstevel@tonic-gate } 43727c478bd9Sstevel@tonic-gate } 43737c478bd9Sstevel@tonic-gate } 43747c478bd9Sstevel@tonic-gate } 43757c478bd9Sstevel@tonic-gate 43767c478bd9Sstevel@tonic-gate 43777c478bd9Sstevel@tonic-gate /* 43787c478bd9Sstevel@tonic-gate * ehci_destroy_stats: 43797c478bd9Sstevel@tonic-gate * 43807c478bd9Sstevel@tonic-gate * Clean up ehci kstat structures 43817c478bd9Sstevel@tonic-gate */ 43827c478bd9Sstevel@tonic-gate void 43837c478bd9Sstevel@tonic-gate ehci_destroy_stats(ehci_state_t *ehcip) 43847c478bd9Sstevel@tonic-gate { 43857c478bd9Sstevel@tonic-gate int i; 43867c478bd9Sstevel@tonic-gate 43877c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) { 43887c478bd9Sstevel@tonic-gate kstat_delete(EHCI_INTRS_STATS(ehcip)); 43897c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip) = NULL; 43907c478bd9Sstevel@tonic-gate } 43917c478bd9Sstevel@tonic-gate 43927c478bd9Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip)) { 43937c478bd9Sstevel@tonic-gate kstat_delete(EHCI_TOTAL_STATS(ehcip)); 43947c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS(ehcip) = NULL; 43957c478bd9Sstevel@tonic-gate } 43967c478bd9Sstevel@tonic-gate 43977c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) { 43987c478bd9Sstevel@tonic-gate if (ehcip->ehci_count_stats[i]) { 43997c478bd9Sstevel@tonic-gate kstat_delete(ehcip->ehci_count_stats[i]); 44007c478bd9Sstevel@tonic-gate ehcip->ehci_count_stats[i] = NULL; 44017c478bd9Sstevel@tonic-gate } 44027c478bd9Sstevel@tonic-gate } 44037c478bd9Sstevel@tonic-gate } 44047c478bd9Sstevel@tonic-gate 44057c478bd9Sstevel@tonic-gate 44067c478bd9Sstevel@tonic-gate /* 44077c478bd9Sstevel@tonic-gate * ehci_do_intrs_stats: 44087c478bd9Sstevel@tonic-gate * 44097c478bd9Sstevel@tonic-gate * ehci status information 44107c478bd9Sstevel@tonic-gate */ 44117c478bd9Sstevel@tonic-gate void 44127c478bd9Sstevel@tonic-gate ehci_do_intrs_stats( 44137c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 44147c478bd9Sstevel@tonic-gate int val) 44157c478bd9Sstevel@tonic-gate { 44167c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) { 44177c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->ehci_sts_total.value.ui64++; 44187c478bd9Sstevel@tonic-gate switch (val) { 44197c478bd9Sstevel@tonic-gate case EHCI_STS_ASYNC_SCHED_STATUS: 44207c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44217c478bd9Sstevel@tonic-gate ehci_sts_async_sched_status.value.ui64++; 44227c478bd9Sstevel@tonic-gate break; 44237c478bd9Sstevel@tonic-gate case EHCI_STS_PERIODIC_SCHED_STATUS: 44247c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44257c478bd9Sstevel@tonic-gate ehci_sts_periodic_sched_status.value.ui64++; 44267c478bd9Sstevel@tonic-gate break; 44277c478bd9Sstevel@tonic-gate case EHCI_STS_EMPTY_ASYNC_SCHEDULE: 44287c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44297c478bd9Sstevel@tonic-gate ehci_sts_empty_async_schedule.value.ui64++; 44307c478bd9Sstevel@tonic-gate break; 44317c478bd9Sstevel@tonic-gate case EHCI_STS_HOST_CTRL_HALTED: 44327c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44337c478bd9Sstevel@tonic-gate ehci_sts_host_ctrl_halted.value.ui64++; 44347c478bd9Sstevel@tonic-gate break; 44357c478bd9Sstevel@tonic-gate case EHCI_STS_ASYNC_ADVANCE_INTR: 44367c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44377c478bd9Sstevel@tonic-gate ehci_sts_async_advance_intr.value.ui64++; 44387c478bd9Sstevel@tonic-gate break; 44397c478bd9Sstevel@tonic-gate case EHCI_STS_HOST_SYSTEM_ERROR_INTR: 44407c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44417c478bd9Sstevel@tonic-gate ehci_sts_host_system_error_intr.value.ui64++; 44427c478bd9Sstevel@tonic-gate break; 44437c478bd9Sstevel@tonic-gate case EHCI_STS_FRM_LIST_ROLLOVER_INTR: 44447c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44457c478bd9Sstevel@tonic-gate ehci_sts_frm_list_rollover_intr.value.ui64++; 44467c478bd9Sstevel@tonic-gate break; 44477c478bd9Sstevel@tonic-gate case EHCI_STS_RH_PORT_CHANGE_INTR: 44487c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44497c478bd9Sstevel@tonic-gate ehci_sts_rh_port_change_intr.value.ui64++; 44507c478bd9Sstevel@tonic-gate break; 44517c478bd9Sstevel@tonic-gate case EHCI_STS_USB_ERROR_INTR: 44527c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44537c478bd9Sstevel@tonic-gate ehci_sts_usb_error_intr.value.ui64++; 44547c478bd9Sstevel@tonic-gate break; 44557c478bd9Sstevel@tonic-gate case EHCI_STS_USB_INTR: 44567c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44577c478bd9Sstevel@tonic-gate ehci_sts_usb_intr.value.ui64++; 44587c478bd9Sstevel@tonic-gate break; 44597c478bd9Sstevel@tonic-gate default: 44607c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44617c478bd9Sstevel@tonic-gate ehci_sts_not_claimed.value.ui64++; 44627c478bd9Sstevel@tonic-gate break; 44637c478bd9Sstevel@tonic-gate } 44647c478bd9Sstevel@tonic-gate } 44657c478bd9Sstevel@tonic-gate } 44667c478bd9Sstevel@tonic-gate 44677c478bd9Sstevel@tonic-gate 44687c478bd9Sstevel@tonic-gate /* 44697c478bd9Sstevel@tonic-gate * ehci_do_byte_stats: 44707c478bd9Sstevel@tonic-gate * 44717c478bd9Sstevel@tonic-gate * ehci data xfer information 44727c478bd9Sstevel@tonic-gate */ 44737c478bd9Sstevel@tonic-gate void 44747c478bd9Sstevel@tonic-gate ehci_do_byte_stats( 44757c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 44767c478bd9Sstevel@tonic-gate size_t len, 44777c478bd9Sstevel@tonic-gate uint8_t attr, 44787c478bd9Sstevel@tonic-gate uint8_t addr) 44797c478bd9Sstevel@tonic-gate { 44807c478bd9Sstevel@tonic-gate uint8_t type = attr & USB_EP_ATTR_MASK; 44817c478bd9Sstevel@tonic-gate uint8_t dir = addr & USB_EP_DIR_MASK; 44827c478bd9Sstevel@tonic-gate 44837c478bd9Sstevel@tonic-gate if (dir == USB_EP_DIR_IN) { 44847c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->reads++; 44857c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->nread += len; 44867c478bd9Sstevel@tonic-gate switch (type) { 44877c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 44887c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->reads++; 44897c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->nread += len; 44907c478bd9Sstevel@tonic-gate break; 44917c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 44927c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->reads++; 44937c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->nread += len; 44947c478bd9Sstevel@tonic-gate break; 44957c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 44967c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->reads++; 44977c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->nread += len; 44987c478bd9Sstevel@tonic-gate break; 44997c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 45007c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->reads++; 45017c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->nread += len; 45027c478bd9Sstevel@tonic-gate break; 45037c478bd9Sstevel@tonic-gate } 45047c478bd9Sstevel@tonic-gate } else if (dir == USB_EP_DIR_OUT) { 45057c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->writes++; 45067c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->nwritten += len; 45077c478bd9Sstevel@tonic-gate switch (type) { 45087c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 45097c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->writes++; 45107c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->nwritten += len; 45117c478bd9Sstevel@tonic-gate break; 45127c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 45137c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->writes++; 45147c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->nwritten += len; 45157c478bd9Sstevel@tonic-gate break; 45167c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 45177c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->writes++; 45187c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->nwritten += len; 45197c478bd9Sstevel@tonic-gate break; 45207c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 45217c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->writes++; 45227c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->nwritten += len; 45237c478bd9Sstevel@tonic-gate break; 45247c478bd9Sstevel@tonic-gate } 45257c478bd9Sstevel@tonic-gate } 45267c478bd9Sstevel@tonic-gate } 4527