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