17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 53b00f311Syq * Common Development and Distribution License (the "License"). 63b00f311Syq * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 223b00f311Syq * 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); 1403b00f311Syq int ehci_init_ctlr(ehci_state_t *ehcip, 1413b00f311Syq int init_type); 1427c478bd9Sstevel@tonic-gate static int ehci_take_control(ehci_state_t *ehcip); 1437c478bd9Sstevel@tonic-gate static int ehci_init_periodic_frame_lst_table( 1447c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 1457c478bd9Sstevel@tonic-gate static void ehci_build_interrupt_lattice( 1467c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 1477c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *ehci_alloc_hcdi_ops(ehci_state_t *ehcip); 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) deinitialization functions */ 1507c478bd9Sstevel@tonic-gate int ehci_cleanup(ehci_state_t *ehcip); 1519c75c6bfSgovinda static void ehci_rem_intrs(ehci_state_t *ehcip); 1527c478bd9Sstevel@tonic-gate int ehci_cpr_suspend(ehci_state_t *ehcip); 1537c478bd9Sstevel@tonic-gate int ehci_cpr_resume(ehci_state_t *ehcip); 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate /* Bandwidth Allocation functions */ 1567c478bd9Sstevel@tonic-gate int ehci_allocate_bandwidth(ehci_state_t *ehcip, 1577c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1587c478bd9Sstevel@tonic-gate uint_t *pnode, 1597c478bd9Sstevel@tonic-gate uchar_t *smask, 1607c478bd9Sstevel@tonic-gate uchar_t *cmask); 1617c478bd9Sstevel@tonic-gate static int ehci_allocate_high_speed_bandwidth( 1627c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1637c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1647c478bd9Sstevel@tonic-gate uint_t *hnode, 1657c478bd9Sstevel@tonic-gate uchar_t *smask, 1667c478bd9Sstevel@tonic-gate uchar_t *cmask); 1677c478bd9Sstevel@tonic-gate static int ehci_allocate_classic_tt_bandwidth( 1687c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1697c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1707c478bd9Sstevel@tonic-gate uint_t pnode); 1717c478bd9Sstevel@tonic-gate void ehci_deallocate_bandwidth(ehci_state_t *ehcip, 1727c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1737c478bd9Sstevel@tonic-gate uint_t pnode, 1747c478bd9Sstevel@tonic-gate uchar_t smask, 1757c478bd9Sstevel@tonic-gate uchar_t cmask); 1767c478bd9Sstevel@tonic-gate static void ehci_deallocate_high_speed_bandwidth( 1777c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1787c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1797c478bd9Sstevel@tonic-gate uint_t hnode, 1807c478bd9Sstevel@tonic-gate uchar_t smask, 1817c478bd9Sstevel@tonic-gate uchar_t cmask); 1827c478bd9Sstevel@tonic-gate static void ehci_deallocate_classic_tt_bandwidth( 1837c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1847c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1857c478bd9Sstevel@tonic-gate uint_t pnode); 1867c478bd9Sstevel@tonic-gate static int ehci_compute_high_speed_bandwidth( 1877c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1887c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 1897c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 1907c478bd9Sstevel@tonic-gate uint_t *sbandwidth, 1917c478bd9Sstevel@tonic-gate uint_t *cbandwidth); 1927c478bd9Sstevel@tonic-gate static int ehci_compute_classic_bandwidth( 1937c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 1947c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 1957c478bd9Sstevel@tonic-gate uint_t *bandwidth); 1967c478bd9Sstevel@tonic-gate int ehci_adjust_polling_interval( 1977c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1987c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 1997c478bd9Sstevel@tonic-gate usb_port_status_t port_status); 2007c478bd9Sstevel@tonic-gate static int ehci_adjust_high_speed_polling_interval( 2017c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2027c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint); 2037c478bd9Sstevel@tonic-gate static uint_t ehci_lattice_height(uint_t interval); 2047c478bd9Sstevel@tonic-gate static uint_t ehci_lattice_parent(uint_t node); 2057c478bd9Sstevel@tonic-gate static uint_t ehci_find_periodic_node( 2067c478bd9Sstevel@tonic-gate uint_t leaf, 2077c478bd9Sstevel@tonic-gate int interval); 2087c478bd9Sstevel@tonic-gate static uint_t ehci_leftmost_leaf(uint_t node, 2097c478bd9Sstevel@tonic-gate uint_t height); 2107c478bd9Sstevel@tonic-gate static uint_t ehci_pow_2(uint_t x); 2117c478bd9Sstevel@tonic-gate static uint_t ehci_log_2(uint_t x); 2127c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_hs_mask( 2137c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2147c478bd9Sstevel@tonic-gate uchar_t *smask, 2157c478bd9Sstevel@tonic-gate uint_t *pnode, 2167c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 2177c478bd9Sstevel@tonic-gate uint_t bandwidth, 2187c478bd9Sstevel@tonic-gate int interval); 2197c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_ls_intr_mask( 2207c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2217c478bd9Sstevel@tonic-gate uchar_t *smask, 2227c478bd9Sstevel@tonic-gate uchar_t *cmask, 2237c478bd9Sstevel@tonic-gate uint_t *pnode, 2247c478bd9Sstevel@tonic-gate uint_t sbandwidth, 2257c478bd9Sstevel@tonic-gate uint_t cbandwidth, 2267c478bd9Sstevel@tonic-gate int interval); 2277c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_sitd_in_mask( 2287c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2297c478bd9Sstevel@tonic-gate uchar_t *smask, 2307c478bd9Sstevel@tonic-gate uchar_t *cmask, 2317c478bd9Sstevel@tonic-gate uint_t *pnode, 2327c478bd9Sstevel@tonic-gate uint_t sbandwidth, 2337c478bd9Sstevel@tonic-gate uint_t cbandwidth, 2347c478bd9Sstevel@tonic-gate int interval); 2357c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_sitd_out_mask( 2367c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2377c478bd9Sstevel@tonic-gate uchar_t *smask, 2387c478bd9Sstevel@tonic-gate uint_t *pnode, 2397c478bd9Sstevel@tonic-gate uint_t sbandwidth, 2407c478bd9Sstevel@tonic-gate int interval); 2417c478bd9Sstevel@tonic-gate static uint_t ehci_calculate_bw_availability_mask( 2427c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2437c478bd9Sstevel@tonic-gate uint_t bandwidth, 2447c478bd9Sstevel@tonic-gate int leaf, 2457c478bd9Sstevel@tonic-gate int leaf_count, 2467c478bd9Sstevel@tonic-gate uchar_t *bw_mask); 2477c478bd9Sstevel@tonic-gate static void ehci_update_bw_availability( 2487c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2497c478bd9Sstevel@tonic-gate int bandwidth, 2507c478bd9Sstevel@tonic-gate int leftmost_leaf, 2517c478bd9Sstevel@tonic-gate int leaf_count, 2527c478bd9Sstevel@tonic-gate uchar_t mask); 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate /* Miscellaneous functions */ 2557c478bd9Sstevel@tonic-gate ehci_state_t *ehci_obtain_state( 2567c478bd9Sstevel@tonic-gate dev_info_t *dip); 2577c478bd9Sstevel@tonic-gate int ehci_state_is_operational( 2587c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2597c478bd9Sstevel@tonic-gate int ehci_do_soft_reset( 2607c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2617c478bd9Sstevel@tonic-gate usb_req_attrs_t ehci_get_xfer_attrs(ehci_state_t *ehcip, 2627c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 2637c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 2647c478bd9Sstevel@tonic-gate usb_frame_number_t ehci_get_current_frame_number( 2657c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2667c478bd9Sstevel@tonic-gate static void ehci_cpr_cleanup( 2677c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2687c478bd9Sstevel@tonic-gate int ehci_wait_for_sof( 2697c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2707c478bd9Sstevel@tonic-gate void ehci_toggle_scheduler( 2717c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2727c478bd9Sstevel@tonic-gate void ehci_print_caps(ehci_state_t *ehcip); 2737c478bd9Sstevel@tonic-gate void ehci_print_regs(ehci_state_t *ehcip); 2747c478bd9Sstevel@tonic-gate void ehci_print_qh(ehci_state_t *ehcip, 2757c478bd9Sstevel@tonic-gate ehci_qh_t *qh); 2767c478bd9Sstevel@tonic-gate void ehci_print_qtd(ehci_state_t *ehcip, 2777c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd); 2787c478bd9Sstevel@tonic-gate void ehci_create_stats(ehci_state_t *ehcip); 2797c478bd9Sstevel@tonic-gate void ehci_destroy_stats(ehci_state_t *ehcip); 2807c478bd9Sstevel@tonic-gate void ehci_do_intrs_stats(ehci_state_t *ehcip, 2817c478bd9Sstevel@tonic-gate int val); 2827c478bd9Sstevel@tonic-gate void ehci_do_byte_stats(ehci_state_t *ehcip, 2837c478bd9Sstevel@tonic-gate size_t len, 2847c478bd9Sstevel@tonic-gate uint8_t attr, 2857c478bd9Sstevel@tonic-gate uint8_t addr); 2867c478bd9Sstevel@tonic-gate 2874610e4a0Sfrits /* 2884610e4a0Sfrits * check if this ehci controller can support PM 2894610e4a0Sfrits */ 2904610e4a0Sfrits int 2914610e4a0Sfrits ehci_hcdi_pm_support(dev_info_t *dip) 2924610e4a0Sfrits { 2934610e4a0Sfrits ehci_state_t *ehcip = ddi_get_soft_state(ehci_statep, 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 646*28cdc3d7Sszhou /* 647*28cdc3d7Sszhou * The following simulated polling is for debugging purposes only. 648*28cdc3d7Sszhou * It is activated on x86 by setting usb-polling=true in GRUB or ehci.conf. 649*28cdc3d7Sszhou */ 650*28cdc3d7Sszhou static int 651*28cdc3d7Sszhou ehci_is_polled(dev_info_t *dip) 652*28cdc3d7Sszhou { 653*28cdc3d7Sszhou int ret; 654*28cdc3d7Sszhou char *propval; 655*28cdc3d7Sszhou 656*28cdc3d7Sszhou if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, 657*28cdc3d7Sszhou "usb-polling", &propval) != DDI_SUCCESS) 658*28cdc3d7Sszhou 659*28cdc3d7Sszhou return (0); 660*28cdc3d7Sszhou 661*28cdc3d7Sszhou ret = (strcmp(propval, "true") == 0); 662*28cdc3d7Sszhou ddi_prop_free(propval); 663*28cdc3d7Sszhou 664*28cdc3d7Sszhou return (ret); 665*28cdc3d7Sszhou } 666*28cdc3d7Sszhou 667*28cdc3d7Sszhou static void 668*28cdc3d7Sszhou ehci_poll_intr(void *arg) 669*28cdc3d7Sszhou { 670*28cdc3d7Sszhou /* poll every msec */ 671*28cdc3d7Sszhou for (;;) { 672*28cdc3d7Sszhou (void) ehci_intr(arg, NULL); 673*28cdc3d7Sszhou delay(drv_usectohz(1000)); 674*28cdc3d7Sszhou } 675*28cdc3d7Sszhou } 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate /* 6787c478bd9Sstevel@tonic-gate * ehci_register_intrs_and_init_mutex: 6797c478bd9Sstevel@tonic-gate * 6807c478bd9Sstevel@tonic-gate * Register interrupts and initialize each mutex and condition variables 6817c478bd9Sstevel@tonic-gate */ 6827c478bd9Sstevel@tonic-gate int 6837c478bd9Sstevel@tonic-gate ehci_register_intrs_and_init_mutex(ehci_state_t *ehcip) 6847c478bd9Sstevel@tonic-gate { 6859c75c6bfSgovinda int intr_types; 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate #if defined(__x86) 6887c478bd9Sstevel@tonic-gate uint8_t iline; 6897c478bd9Sstevel@tonic-gate #endif 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 6927c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex:"); 6937c478bd9Sstevel@tonic-gate 6949c75c6bfSgovinda /* 6959c75c6bfSgovinda * There is a known MSI hardware bug with the EHCI controller 6969c75c6bfSgovinda * of ULI1575 southbridge. Hence MSI is disabled for this chip. 6979c75c6bfSgovinda */ 6989c75c6bfSgovinda if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) && 6999c75c6bfSgovinda (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) { 7009c75c6bfSgovinda ehcip->ehci_msi_enabled = B_FALSE; 7019c75c6bfSgovinda } else { 7029c75c6bfSgovinda /* Set the MSI enable flag from the global EHCI MSI tunable */ 7039c75c6bfSgovinda ehcip->ehci_msi_enabled = ehci_enable_msi; 7049c75c6bfSgovinda } 7059c75c6bfSgovinda 706*28cdc3d7Sszhou /* launch polling thread instead of enabling pci interrupt */ 707*28cdc3d7Sszhou if (ehci_is_polled(ehcip->ehci_dip)) { 708*28cdc3d7Sszhou extern pri_t maxclsyspri; 709*28cdc3d7Sszhou 710*28cdc3d7Sszhou USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 711*28cdc3d7Sszhou "ehci_register_intrs_and_init_mutex: " 712*28cdc3d7Sszhou "running in simulated polled mode"); 713*28cdc3d7Sszhou 714*28cdc3d7Sszhou (void) thread_create(NULL, 0, ehci_poll_intr, ehcip, 0, &p0, 715*28cdc3d7Sszhou TS_RUN, maxclsyspri); 716*28cdc3d7Sszhou 717*28cdc3d7Sszhou goto skip_intr; 718*28cdc3d7Sszhou } 719*28cdc3d7Sszhou 7207c478bd9Sstevel@tonic-gate #if defined(__x86) 7217c478bd9Sstevel@tonic-gate /* 7227c478bd9Sstevel@tonic-gate * Make sure that the interrupt pin is connected to the 7237c478bd9Sstevel@tonic-gate * interrupt controller on x86. Interrupt line 255 means 7247c478bd9Sstevel@tonic-gate * "unknown" or "not connected" (PCI spec 6.2.4, footnote 43). 7254610e4a0Sfrits * If we would return failure when interrupt line equals 255, then 726f87a10b6Syq * high speed devices will be routed to companion host controllers. 7274610e4a0Sfrits * However, it is not necessary to return failure here, and 7284610e4a0Sfrits * o/uhci codes don't check the interrupt line either. 7294610e4a0Sfrits * But it's good to log a message here for debug purposes. 7307c478bd9Sstevel@tonic-gate */ 7317c478bd9Sstevel@tonic-gate iline = pci_config_get8(ehcip->ehci_config_handle, 7327c478bd9Sstevel@tonic-gate PCI_CONF_ILINE); 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate if (iline == 255) { 7357c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7367c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 7377c478bd9Sstevel@tonic-gate "interrupt line value out of range (%d)", 7387c478bd9Sstevel@tonic-gate iline); 7397c478bd9Sstevel@tonic-gate } 7407c478bd9Sstevel@tonic-gate #endif /* __x86 */ 7417c478bd9Sstevel@tonic-gate 7429c75c6bfSgovinda /* Get supported interrupt types */ 7439c75c6bfSgovinda if (ddi_intr_get_supported_types(ehcip->ehci_dip, 7449c75c6bfSgovinda &intr_types) != DDI_SUCCESS) { 7457c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7467c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 7479c75c6bfSgovinda "ddi_intr_get_supported_types failed"); 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate 7529c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7539c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: " 7549c75c6bfSgovinda "supported interrupt types 0x%x", intr_types); 7559c75c6bfSgovinda 7569c75c6bfSgovinda if ((intr_types & DDI_INTR_TYPE_MSI) && ehcip->ehci_msi_enabled) { 7579c75c6bfSgovinda if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_MSI) 7589c75c6bfSgovinda != DDI_SUCCESS) { 7599c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7609c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: MSI " 7619c75c6bfSgovinda "registration failed, trying FIXED interrupt \n"); 7629c75c6bfSgovinda } else { 7639c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7649c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: " 7659c75c6bfSgovinda "Using MSI interrupt type\n"); 7669c75c6bfSgovinda 7679c75c6bfSgovinda ehcip->ehci_intr_type = DDI_INTR_TYPE_MSI; 7689c75c6bfSgovinda ehcip->ehci_flags |= EHCI_INTR; 7699c75c6bfSgovinda } 7709c75c6bfSgovinda } 7717c478bd9Sstevel@tonic-gate 7729c75c6bfSgovinda if ((!(ehcip->ehci_flags & EHCI_INTR)) && 7739c75c6bfSgovinda (intr_types & DDI_INTR_TYPE_FIXED)) { 7749c75c6bfSgovinda if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_FIXED) 7759c75c6bfSgovinda != DDI_SUCCESS) { 7769c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7779c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: " 7789c75c6bfSgovinda "FIXED interrupt registration failed\n"); 7799c75c6bfSgovinda 7809c75c6bfSgovinda return (DDI_FAILURE); 7819c75c6bfSgovinda } 7829c75c6bfSgovinda 7839c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7847c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 7859c75c6bfSgovinda "Using FIXED interrupt type\n"); 7869c75c6bfSgovinda 7879c75c6bfSgovinda ehcip->ehci_intr_type = DDI_INTR_TYPE_FIXED; 7889c75c6bfSgovinda ehcip->ehci_flags |= EHCI_INTR; 7899c75c6bfSgovinda } 7909c75c6bfSgovinda 791*28cdc3d7Sszhou skip_intr: 7929c75c6bfSgovinda /* Create prototype for advance on async schedule */ 7939c75c6bfSgovinda cv_init(&ehcip->ehci_async_schedule_advance_cv, 7949c75c6bfSgovinda NULL, CV_DRIVER, NULL); 7959c75c6bfSgovinda 7969c75c6bfSgovinda return (DDI_SUCCESS); 7979c75c6bfSgovinda } 7989c75c6bfSgovinda 7999c75c6bfSgovinda 8009c75c6bfSgovinda /* 8019c75c6bfSgovinda * ehci_add_intrs: 8029c75c6bfSgovinda * 8039c75c6bfSgovinda * Register FIXED or MSI interrupts. 8049c75c6bfSgovinda */ 8059c75c6bfSgovinda static int 8069c75c6bfSgovinda ehci_add_intrs(ehci_state_t *ehcip, 8079c75c6bfSgovinda int intr_type) 8089c75c6bfSgovinda { 8099c75c6bfSgovinda int actual, avail, intr_size, count = 0; 8109c75c6bfSgovinda int i, flag, ret; 8119c75c6bfSgovinda 8129c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8139c75c6bfSgovinda "ehci_add_intrs: interrupt type 0x%x", intr_type); 8149c75c6bfSgovinda 8159c75c6bfSgovinda /* Get number of interrupts */ 8169c75c6bfSgovinda ret = ddi_intr_get_nintrs(ehcip->ehci_dip, intr_type, &count); 8179c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (count == 0)) { 8189c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8199c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_nintrs() failure, " 8209c75c6bfSgovinda "ret: %d, count: %d", ret, count); 8219c75c6bfSgovinda 8229c75c6bfSgovinda return (DDI_FAILURE); 8239c75c6bfSgovinda } 8249c75c6bfSgovinda 8259c75c6bfSgovinda /* Get number of available interrupts */ 8269c75c6bfSgovinda ret = ddi_intr_get_navail(ehcip->ehci_dip, intr_type, &avail); 8279c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (avail == 0)) { 8289c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8299c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_navail() failure, " 8309c75c6bfSgovinda "ret: %d, count: %d", ret, count); 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate 8359c75c6bfSgovinda if (avail < count) { 8369c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8379c75c6bfSgovinda "ehci_add_intrs: ehci_add_intrs: nintrs () " 8389c75c6bfSgovinda "returned %d, navail returned %d\n", count, avail); 8399c75c6bfSgovinda } 8409c75c6bfSgovinda 8419c75c6bfSgovinda /* Allocate an array of interrupt handles */ 8429c75c6bfSgovinda intr_size = count * sizeof (ddi_intr_handle_t); 8439c75c6bfSgovinda ehcip->ehci_htable = kmem_zalloc(intr_size, KM_SLEEP); 8449c75c6bfSgovinda 8459c75c6bfSgovinda flag = (intr_type == DDI_INTR_TYPE_MSI) ? 8469c75c6bfSgovinda DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL; 8479c75c6bfSgovinda 8489c75c6bfSgovinda /* call ddi_intr_alloc() */ 8497c478bd9Sstevel@tonic-gate ret = ddi_intr_alloc(ehcip->ehci_dip, ehcip->ehci_htable, 8509c75c6bfSgovinda intr_type, 0, count, &actual, flag); 8517c478bd9Sstevel@tonic-gate 8529c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (actual == 0)) { 8537c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8549c75c6bfSgovinda "ehci_add_intrs: ddi_intr_alloc() failed %d", ret); 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 8619c75c6bfSgovinda if (actual < count) { 8629c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8639c75c6bfSgovinda "ehci_add_intrs: Requested: %d, Received: %d\n", 8649c75c6bfSgovinda count, actual); 8659c75c6bfSgovinda 8669c75c6bfSgovinda for (i = 0; i < actual; i++) 8679c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 8689c75c6bfSgovinda 8699c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 8709c75c6bfSgovinda 8719c75c6bfSgovinda return (DDI_FAILURE); 8729c75c6bfSgovinda } 8737c478bd9Sstevel@tonic-gate 8749c75c6bfSgovinda ehcip->ehci_intr_cnt = actual; 8759c75c6bfSgovinda 8769c75c6bfSgovinda if ((ret = ddi_intr_get_pri(ehcip->ehci_htable[0], 8779c75c6bfSgovinda &ehcip->ehci_intr_pri)) != DDI_SUCCESS) { 8787c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8799c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_pri() failed %d", ret); 8809c75c6bfSgovinda 8819c75c6bfSgovinda for (i = 0; i < actual; i++) 8829c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 8837c478bd9Sstevel@tonic-gate 8849c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate 8899c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8909c75c6bfSgovinda "ehci_add_intrs: Supported Interrupt priority 0x%x", 8919c75c6bfSgovinda ehcip->ehci_intr_pri); 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate /* Test for high level mutex */ 8947c478bd9Sstevel@tonic-gate if (ehcip->ehci_intr_pri >= ddi_intr_get_hilevel_pri()) { 8957c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8969c75c6bfSgovinda "ehci_add_intrs: Hi level interrupt not supported"); 8979c75c6bfSgovinda 8989c75c6bfSgovinda for (i = 0; i < actual; i++) 8999c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 9007c478bd9Sstevel@tonic-gate 9019c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate /* Initialize the mutex */ 9077c478bd9Sstevel@tonic-gate mutex_init(&ehcip->ehci_int_mutex, NULL, MUTEX_DRIVER, 908a195726fSgovinda DDI_INTR_PRI(ehcip->ehci_intr_pri)); 9097c478bd9Sstevel@tonic-gate 9109c75c6bfSgovinda /* Call ddi_intr_add_handler() */ 9119c75c6bfSgovinda for (i = 0; i < actual; i++) { 9129c75c6bfSgovinda if ((ret = ddi_intr_add_handler(ehcip->ehci_htable[i], 9139c75c6bfSgovinda ehci_intr, (caddr_t)ehcip, 9149c75c6bfSgovinda (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 9159c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9169c75c6bfSgovinda "ehci_add_intrs:ddi_intr_add_handler() " 9179c75c6bfSgovinda "failed %d", ret); 9187c478bd9Sstevel@tonic-gate 9199c75c6bfSgovinda for (i = 0; i < actual; i++) 9209c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 9217c478bd9Sstevel@tonic-gate 9229c75c6bfSgovinda mutex_destroy(&ehcip->ehci_int_mutex); 9239c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 9249c75c6bfSgovinda 9259c75c6bfSgovinda return (DDI_FAILURE); 9269c75c6bfSgovinda } 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate 9299c75c6bfSgovinda if ((ret = ddi_intr_get_cap(ehcip->ehci_htable[0], 9309c75c6bfSgovinda &ehcip->ehci_intr_cap)) != DDI_SUCCESS) { 9317c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9329c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_cap() failed %d", ret); 9339c75c6bfSgovinda 9349c75c6bfSgovinda for (i = 0; i < actual; i++) { 9359c75c6bfSgovinda (void) ddi_intr_remove_handler(ehcip->ehci_htable[i]); 9369c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 9379c75c6bfSgovinda } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate mutex_destroy(&ehcip->ehci_int_mutex); 9409c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate 9459c75c6bfSgovinda /* Enable all interrupts */ 9469c75c6bfSgovinda if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) { 9479c75c6bfSgovinda /* Call ddi_intr_block_enable() for MSI interrupts */ 9489c75c6bfSgovinda (void) ddi_intr_block_enable(ehcip->ehci_htable, 9499c75c6bfSgovinda ehcip->ehci_intr_cnt); 9509c75c6bfSgovinda } else { 9519c75c6bfSgovinda /* Call ddi_intr_enable for MSI or FIXED interrupts */ 9529c75c6bfSgovinda for (i = 0; i < ehcip->ehci_intr_cnt; i++) 9539c75c6bfSgovinda (void) ddi_intr_enable(ehcip->ehci_htable[i]); 9549c75c6bfSgovinda } 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 9577c478bd9Sstevel@tonic-gate } 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate /* 9613b00f311Syq * ehci_init_hardware 9627c478bd9Sstevel@tonic-gate * 9633b00f311Syq * take control from BIOS, reset EHCI host controller, and check version, etc. 9647c478bd9Sstevel@tonic-gate */ 9657c478bd9Sstevel@tonic-gate int 9663b00f311Syq ehci_init_hardware(ehci_state_t *ehcip) 9677c478bd9Sstevel@tonic-gate { 9687c478bd9Sstevel@tonic-gate int revision; 9697c478bd9Sstevel@tonic-gate uint16_t cmd_reg; 9707c478bd9Sstevel@tonic-gate int abort_on_BIOS_take_over_failure; 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate /* Take control from the BIOS */ 9737c478bd9Sstevel@tonic-gate if (ehci_take_control(ehcip) != USB_SUCCESS) { 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate /* read .conf file properties */ 9767c478bd9Sstevel@tonic-gate abort_on_BIOS_take_over_failure = 9777c478bd9Sstevel@tonic-gate ddi_prop_get_int(DDI_DEV_T_ANY, 9787c478bd9Sstevel@tonic-gate ehcip->ehci_dip, DDI_PROP_DONTPASS, 9797c478bd9Sstevel@tonic-gate "abort-on-BIOS-take-over-failure", 0); 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate if (abort_on_BIOS_take_over_failure) { 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9847c478bd9Sstevel@tonic-gate "Unable to take control from BIOS."); 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9877c478bd9Sstevel@tonic-gate } 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9907c478bd9Sstevel@tonic-gate "Unable to take control from BIOS. Failure is ignored."); 9917c478bd9Sstevel@tonic-gate } 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate /* set Memory Master Enable */ 9947c478bd9Sstevel@tonic-gate cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM); 9957c478bd9Sstevel@tonic-gate cmd_reg |= (PCI_COMM_MAE | PCI_COMM_ME); 9967c478bd9Sstevel@tonic-gate pci_config_put16(ehcip->ehci_config_handle, PCI_CONF_COMM, cmd_reg); 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate /* Reset the EHCI host controller */ 9997c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 10007c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) | EHCI_CMD_HOST_CTRL_RESET); 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate /* Wait 10ms for reset to complete */ 10037c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT); 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED); 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate /* Verify the version number */ 10087c478bd9Sstevel@tonic-gate revision = Get_16Cap(ehci_version); 10097c478bd9Sstevel@tonic-gate 10103b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 10113b00f311Syq "ehci_init_hardware: Revision 0x%x", revision); 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate /* 10147c478bd9Sstevel@tonic-gate * EHCI driver supports EHCI host controllers compliant to 10157c478bd9Sstevel@tonic-gate * 0.95 and higher revisions of EHCI specifications. 10167c478bd9Sstevel@tonic-gate */ 10177c478bd9Sstevel@tonic-gate if (revision < EHCI_REVISION_0_95) { 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 10207c478bd9Sstevel@tonic-gate "Revision 0x%x is not supported", revision); 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10237c478bd9Sstevel@tonic-gate } 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate if (ehcip->ehci_hc_soft_state == EHCI_CTLR_INIT_STATE) { 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate /* Initialize the Frame list base address area */ 10287c478bd9Sstevel@tonic-gate if (ehci_init_periodic_frame_lst_table(ehcip) != DDI_SUCCESS) { 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate /* 10347c478bd9Sstevel@tonic-gate * For performance reasons, do not insert anything into the 10357c478bd9Sstevel@tonic-gate * asynchronous list or activate the asynch list schedule until 10367c478bd9Sstevel@tonic-gate * there is a valid QH. 10377c478bd9Sstevel@tonic-gate */ 10387c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list = NULL; 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) && 10417c478bd9Sstevel@tonic-gate (ehci_vt62x2_workaround & EHCI_VIA_ASYNC_SCHEDULE)) { 10427c478bd9Sstevel@tonic-gate /* 10437c478bd9Sstevel@tonic-gate * The driver is unable to reliably stop the asynch 10447c478bd9Sstevel@tonic-gate * list schedule on VIA VT6202 controllers, so we 10457c478bd9Sstevel@tonic-gate * always keep a dummy QH on the list. 10467c478bd9Sstevel@tonic-gate */ 10477c478bd9Sstevel@tonic-gate ehci_qh_t *dummy_async_qh = 10487c478bd9Sstevel@tonic-gate ehci_alloc_qh(ehcip, NULL, NULL); 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_link_ptr, 10517c478bd9Sstevel@tonic-gate ((ehci_qh_cpu_to_iommu(ehcip, dummy_async_qh) & 10527c478bd9Sstevel@tonic-gate EHCI_QH_LINK_PTR) | EHCI_QH_LINK_REF_QH)); 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate /* Set this QH to be the "head" of the circular list */ 10557c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_ctrl, 10567c478bd9Sstevel@tonic-gate Get_QH(dummy_async_qh->qh_ctrl) | 10577c478bd9Sstevel@tonic-gate EHCI_QH_CTRL_RECLAIM_HEAD); 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_next_qtd, 10607c478bd9Sstevel@tonic-gate EHCI_QH_NEXT_QTD_PTR_VALID); 10617c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_alt_next_qtd, 10627c478bd9Sstevel@tonic-gate EHCI_QH_ALT_NEXT_QTD_PTR_VALID); 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list = dummy_async_qh; 10657c478bd9Sstevel@tonic-gate ehcip->ehci_open_async_count++; 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate } 10687c478bd9Sstevel@tonic-gate 10693b00f311Syq return (DDI_SUCCESS); 10703b00f311Syq } 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate 10733b00f311Syq /* 10743b00f311Syq * ehci_init_workaround 10753b00f311Syq * 10763b00f311Syq * some workarounds during initializing ehci 10773b00f311Syq */ 10783b00f311Syq int 10793b00f311Syq ehci_init_workaround(ehci_state_t *ehcip) 10803b00f311Syq { 10817c478bd9Sstevel@tonic-gate /* 10827c478bd9Sstevel@tonic-gate * Acer Labs Inc. M5273 EHCI controller does not send 10837c478bd9Sstevel@tonic-gate * interrupts unless the Root hub ports are routed to the EHCI 10847c478bd9Sstevel@tonic-gate * host controller; so route the ports now, before we test for 10857c478bd9Sstevel@tonic-gate * the presence of SOFs interrupts. 10867c478bd9Sstevel@tonic-gate */ 10877c478bd9Sstevel@tonic-gate if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) { 10887c478bd9Sstevel@tonic-gate /* Route all Root hub ports to EHCI host controller */ 10897c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI); 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate /* 10937c478bd9Sstevel@tonic-gate * VIA chips have some issues and may not work reliably. 1094677739beShx * Revisions >= 0x80 are part of a southbridge and appear 1095677739beShx * to be reliable with the workaround. 10964610e4a0Sfrits * For revisions < 0x80, if we were bound using class 1097677739beShx * complain, else proceed. This will allow the user to 1098677739beShx * bind ehci specifically to this chip and not have the 1099677739beShx * warnings 11007c478bd9Sstevel@tonic-gate */ 1101677739beShx if (ehcip->ehci_vendor_id == PCI_VENDOR_VIA) { 1102677739beShx 1103677739beShx if (ehcip->ehci_rev_id >= PCI_VIA_REVISION_6212) { 1104677739beShx 1105677739beShx USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11063b00f311Syq "ehci_init_workaround: Applying VIA workarounds " 11073b00f311Syq "for the 6212 chip."); 1108677739beShx 1109677739beShx } else if (strcmp(DEVI(ehcip->ehci_dip)->devi_binding_name, 1110677739beShx "pciclass,0c0320") == 0) { 1111677739beShx 11127c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11137c478bd9Sstevel@tonic-gate "Due to recently discovered incompatibilities"); 11147c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11157c478bd9Sstevel@tonic-gate "with this USB controller, USB2.x transfer"); 11167c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11177c478bd9Sstevel@tonic-gate "support has been disabled. This device will"); 11187c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11197c478bd9Sstevel@tonic-gate "continue to function as a USB1.x controller."); 11207c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11217c478bd9Sstevel@tonic-gate "If you are interested in enabling USB2.x"); 11227c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11237c478bd9Sstevel@tonic-gate "support please, refer to the ehci(7D) man page."); 11247c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11257c478bd9Sstevel@tonic-gate "Please also refer to www.sun.com/io for"); 11267c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11277c478bd9Sstevel@tonic-gate "Solaris Ready products and to"); 11287c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11297c478bd9Sstevel@tonic-gate "www.sun.com/bigadmin/hcl for additional"); 11307c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11317c478bd9Sstevel@tonic-gate "compatible USB products."); 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1134677739beShx 1135677739beShx } else if (ehci_vt62x2_workaround) { 1136677739beShx 11377c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11387c478bd9Sstevel@tonic-gate "Applying VIA workarounds"); 1139677739beShx } 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate 11423b00f311Syq return (DDI_SUCCESS); 11433b00f311Syq } 11443b00f311Syq 11453b00f311Syq 11463b00f311Syq /* 11473b00f311Syq * ehci_init_check_status 11483b00f311Syq * 11493b00f311Syq * Check if EHCI host controller is running 11503b00f311Syq */ 11513b00f311Syq int 11523b00f311Syq ehci_init_check_status(ehci_state_t *ehcip) 11533b00f311Syq { 11543b00f311Syq clock_t sof_time_wait; 11553b00f311Syq 11567c478bd9Sstevel@tonic-gate /* 11577c478bd9Sstevel@tonic-gate * Get the number of clock ticks to wait. 11587c478bd9Sstevel@tonic-gate * This is based on the maximum time it takes for a frame list rollover 11597c478bd9Sstevel@tonic-gate * and maximum time wait for SOFs to begin. 11607c478bd9Sstevel@tonic-gate */ 11617c478bd9Sstevel@tonic-gate sof_time_wait = drv_usectohz((EHCI_NUM_PERIODIC_FRAME_LISTS * 1000) + 11627c478bd9Sstevel@tonic-gate EHCI_SOF_TIMEWAIT); 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate /* Tell the ISR to broadcast ehci_async_schedule_advance_cv */ 11657c478bd9Sstevel@tonic-gate ehcip->ehci_flags |= EHCI_CV_INTR; 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate /* We need to add a delay to allow the chip time to start running */ 11687c478bd9Sstevel@tonic-gate (void) cv_timedwait(&ehcip->ehci_async_schedule_advance_cv, 11697c478bd9Sstevel@tonic-gate &ehcip->ehci_int_mutex, ddi_get_lbolt() + sof_time_wait); 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate /* 11727c478bd9Sstevel@tonic-gate * Check EHCI host controller is running, otherwise return failure. 11737c478bd9Sstevel@tonic-gate */ 11747c478bd9Sstevel@tonic-gate if ((ehcip->ehci_flags & EHCI_CV_INTR) || 11757c478bd9Sstevel@tonic-gate (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) { 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11787c478bd9Sstevel@tonic-gate "No SOF interrupts have been received, this USB EHCI host" 11797c478bd9Sstevel@tonic-gate "controller is unusable"); 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate /* 11827c478bd9Sstevel@tonic-gate * Route all Root hub ports to Classic host 11837c478bd9Sstevel@tonic-gate * controller, in case this is an unusable ALI M5273 11847c478bd9Sstevel@tonic-gate * EHCI controller. 11857c478bd9Sstevel@tonic-gate */ 11867c478bd9Sstevel@tonic-gate if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) { 11877c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC); 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11917c478bd9Sstevel@tonic-gate } 11927c478bd9Sstevel@tonic-gate 11933b00f311Syq return (DDI_SUCCESS); 11943b00f311Syq } 11953b00f311Syq 11963b00f311Syq 11973b00f311Syq /* 11983b00f311Syq * ehci_init_ctlr: 11993b00f311Syq * 12003b00f311Syq * Initialize the Host Controller (HC). 12013b00f311Syq */ 12023b00f311Syq int 12033b00f311Syq ehci_init_ctlr(ehci_state_t *ehcip, 12043b00f311Syq int init_type) 12053b00f311Syq { 12063b00f311Syq USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_init_ctlr:"); 12073b00f311Syq 12083b00f311Syq if (init_type == EHCI_NORMAL_INITIALIZATION) { 12093b00f311Syq 12103b00f311Syq if (ehci_init_hardware(ehcip) != DDI_SUCCESS) { 12113b00f311Syq 12123b00f311Syq return (DDI_FAILURE); 12133b00f311Syq } 12143b00f311Syq } 12153b00f311Syq 12163b00f311Syq /* 12173b00f311Syq * Check for Asynchronous schedule park capability feature. If this 12183b00f311Syq * feature is supported, then, program ehci command register with 12193b00f311Syq * appropriate values.. 12203b00f311Syq */ 12213b00f311Syq if (Get_Cap(ehci_hcc_params) & EHCI_HCC_ASYNC_SCHED_PARK_CAP) { 12223b00f311Syq 12233b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 12243b00f311Syq "ehci_init_ctlr: Async park mode is supported"); 12253b00f311Syq 12263b00f311Syq Set_OpReg(ehci_command, (Get_OpReg(ehci_command) | 12273b00f311Syq (EHCI_CMD_ASYNC_PARK_ENABLE | 12283b00f311Syq EHCI_CMD_ASYNC_PARK_COUNT_3))); 12293b00f311Syq } 12303b00f311Syq 12313b00f311Syq /* 12323b00f311Syq * Check for programmable periodic frame list feature. If this 12333b00f311Syq * feature is supported, then, program ehci command register with 12343b00f311Syq * 1024 frame list value. 12353b00f311Syq */ 12363b00f311Syq if (Get_Cap(ehci_hcc_params) & EHCI_HCC_PROG_FRAME_LIST_FLAG) { 12373b00f311Syq 12383b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 12393b00f311Syq "ehci_init_ctlr: Variable programmable periodic " 12403b00f311Syq "frame list is supported"); 12413b00f311Syq 12423b00f311Syq Set_OpReg(ehci_command, (Get_OpReg(ehci_command) | 12433b00f311Syq EHCI_CMD_FRAME_1024_SIZE)); 12443b00f311Syq } 12453b00f311Syq 12463b00f311Syq /* 12473b00f311Syq * Currently EHCI driver doesn't support 64 bit addressing. 12483b00f311Syq * 12493b00f311Syq * If we are using 64 bit addressing capability, then, program 12503b00f311Syq * ehci_ctrl_segment register with 4 Gigabyte segment where all 12513b00f311Syq * of the interface data structures are allocated. 12523b00f311Syq */ 12533b00f311Syq if (Get_Cap(ehci_hcc_params) & EHCI_HCC_64BIT_ADDR_CAP) { 12543b00f311Syq 12553b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 12563b00f311Syq "ehci_init_ctlr: EHCI driver doesn't support " 12573b00f311Syq "64 bit addressing"); 12583b00f311Syq } 12593b00f311Syq 12603b00f311Syq /* 64 bit addressing is not support */ 12613b00f311Syq Set_OpReg(ehci_ctrl_segment, 0x00000000); 12623b00f311Syq 12633b00f311Syq /* Turn on/off the schedulers */ 12643b00f311Syq ehci_toggle_scheduler(ehcip); 12653b00f311Syq 12663b00f311Syq /* 12673b00f311Syq * Set the Periodic Frame List Base Address register with the 12683b00f311Syq * starting physical address of the Periodic Frame List. 12693b00f311Syq */ 12703b00f311Syq Set_OpReg(ehci_periodic_list_base, 12713b00f311Syq (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address & 12723b00f311Syq EHCI_PERIODIC_LIST_BASE)); 12733b00f311Syq 12743b00f311Syq /* 12753b00f311Syq * Set ehci_interrupt to enable all interrupts except Root 12763b00f311Syq * Hub Status change interrupt. 12773b00f311Syq */ 12783b00f311Syq Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR | 12793b00f311Syq EHCI_INTR_FRAME_LIST_ROLLOVER | EHCI_INTR_USB_ERROR | 12803b00f311Syq EHCI_INTR_USB); 12813b00f311Syq 12823b00f311Syq /* 12833b00f311Syq * Set the desired interrupt threshold and turn on EHCI host controller. 12843b00f311Syq */ 12853b00f311Syq Set_OpReg(ehci_command, 12863b00f311Syq ((Get_OpReg(ehci_command) & ~EHCI_CMD_INTR_THRESHOLD) | 12873b00f311Syq (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN))); 12883b00f311Syq 12893b00f311Syq ASSERT(Get_OpReg(ehci_command) & EHCI_CMD_HOST_CTRL_RUN); 12903b00f311Syq 12913b00f311Syq if (init_type == EHCI_NORMAL_INITIALIZATION) { 12923b00f311Syq 12933b00f311Syq if (ehci_init_workaround(ehcip) != DDI_SUCCESS) { 12943b00f311Syq 12953b00f311Syq return (DDI_FAILURE); 12963b00f311Syq } 12973b00f311Syq 12983b00f311Syq if (ehci_init_check_status(ehcip) != DDI_SUCCESS) { 12993b00f311Syq 13003b00f311Syq return (DDI_FAILURE); 13013b00f311Syq } 13023b00f311Syq 13033b00f311Syq USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 13043b00f311Syq "ehci_init_ctlr: SOF's have started"); 13053b00f311Syq } 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate /* Route all Root hub ports to EHCI host controller */ 13087c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI); 13097c478bd9Sstevel@tonic-gate 13107c478bd9Sstevel@tonic-gate /* Set host controller soft state to operational */ 13117c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_OPERATIONAL_STATE; 13127c478bd9Sstevel@tonic-gate 13137c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 13147c478bd9Sstevel@tonic-gate } 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate /* 13177c478bd9Sstevel@tonic-gate * ehci_take_control: 13187c478bd9Sstevel@tonic-gate * 13197c478bd9Sstevel@tonic-gate * Handshake to take EHCI control from BIOS if necessary. Its only valid for 13207c478bd9Sstevel@tonic-gate * x86 machines, because sparc doesn't have a BIOS. 13217c478bd9Sstevel@tonic-gate * On x86 machine, the take control process includes 13227c478bd9Sstevel@tonic-gate * o get the base address of the extended capability list 13237c478bd9Sstevel@tonic-gate * o find out the capability for handoff synchronization in the list. 13247c478bd9Sstevel@tonic-gate * o check if BIOS has owned the host controller. 13257c478bd9Sstevel@tonic-gate * o set the OS Owned semaphore bit, ask the BIOS to release the ownership. 13267c478bd9Sstevel@tonic-gate * o wait for a constant time and check if BIOS has relinquished control. 13277c478bd9Sstevel@tonic-gate */ 13287c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13297c478bd9Sstevel@tonic-gate static int 13307c478bd9Sstevel@tonic-gate ehci_take_control(ehci_state_t *ehcip) 13317c478bd9Sstevel@tonic-gate { 13327c478bd9Sstevel@tonic-gate #if defined(__x86) 13337c478bd9Sstevel@tonic-gate uint32_t extended_cap; 13347c478bd9Sstevel@tonic-gate uint32_t extended_cap_offset; 13357c478bd9Sstevel@tonic-gate uint32_t extended_cap_id; 13367c478bd9Sstevel@tonic-gate uint_t retry; 13377c478bd9Sstevel@tonic-gate 13387c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 13397c478bd9Sstevel@tonic-gate "ehci_take_control:"); 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate /* 13427c478bd9Sstevel@tonic-gate * According EHCI Spec 2.2.4, get EECP base address from HCCPARAMS 13437c478bd9Sstevel@tonic-gate * register. 13447c478bd9Sstevel@tonic-gate */ 13457c478bd9Sstevel@tonic-gate extended_cap_offset = (Get_Cap(ehci_hcc_params) & EHCI_HCC_EECP) >> 13467c478bd9Sstevel@tonic-gate EHCI_HCC_EECP_SHIFT; 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate /* 13497c478bd9Sstevel@tonic-gate * According EHCI Spec 2.2.4, if the extended capability offset is 13507c478bd9Sstevel@tonic-gate * less than 40h then its not valid. This means we don't need to 13517c478bd9Sstevel@tonic-gate * worry about BIOS handoff. 13527c478bd9Sstevel@tonic-gate */ 13537c478bd9Sstevel@tonic-gate if (extended_cap_offset < EHCI_HCC_EECP_MIN_OFFSET) { 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 13567c478bd9Sstevel@tonic-gate "ehci_take_control: Hardware doesn't support legacy."); 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate goto success; 13597c478bd9Sstevel@tonic-gate } 13607c478bd9Sstevel@tonic-gate 13617c478bd9Sstevel@tonic-gate /* 13627c478bd9Sstevel@tonic-gate * According EHCI Spec 2.1.7, A zero offset indicates the 13637c478bd9Sstevel@tonic-gate * end of the extended capability list. 13647c478bd9Sstevel@tonic-gate */ 13657c478bd9Sstevel@tonic-gate while (extended_cap_offset) { 13667c478bd9Sstevel@tonic-gate 13677c478bd9Sstevel@tonic-gate /* Get the extended capability value. */ 13687c478bd9Sstevel@tonic-gate extended_cap = pci_config_get32(ehcip->ehci_config_handle, 13697c478bd9Sstevel@tonic-gate extended_cap_offset); 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate /* Get the capability ID */ 13727c478bd9Sstevel@tonic-gate extended_cap_id = (extended_cap & EHCI_EX_CAP_ID) >> 13737c478bd9Sstevel@tonic-gate EHCI_EX_CAP_ID_SHIFT; 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate /* Check if the card support legacy */ 13767c478bd9Sstevel@tonic-gate if (extended_cap_id == EHCI_EX_CAP_ID_BIOS_HANDOFF) { 13777c478bd9Sstevel@tonic-gate break; 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate /* Get the offset of the next capability */ 13817c478bd9Sstevel@tonic-gate extended_cap_offset = (extended_cap & EHCI_EX_CAP_NEXT_PTR) >> 13827c478bd9Sstevel@tonic-gate EHCI_EX_CAP_NEXT_PTR_SHIFT; 13837c478bd9Sstevel@tonic-gate } 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate /* 13867c478bd9Sstevel@tonic-gate * Unable to find legacy support in hardware's extended capability list. 13877c478bd9Sstevel@tonic-gate * This means we don't need to worry about BIOS handoff. 13887c478bd9Sstevel@tonic-gate */ 13897c478bd9Sstevel@tonic-gate if (extended_cap_id != EHCI_EX_CAP_ID_BIOS_HANDOFF) { 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 13927c478bd9Sstevel@tonic-gate "ehci_take_control: Hardware doesn't support legacy"); 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate goto success; 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate /* Check if BIOS has owned it. */ 13987c478bd9Sstevel@tonic-gate if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) { 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 14017c478bd9Sstevel@tonic-gate "ehci_take_control: BIOS does not own EHCI"); 14027c478bd9Sstevel@tonic-gate 14037c478bd9Sstevel@tonic-gate goto success; 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate /* 14077c478bd9Sstevel@tonic-gate * According EHCI Spec 5.1, The OS driver initiates an ownership 14087c478bd9Sstevel@tonic-gate * request by setting the OS Owned semaphore to a one. The OS 14097c478bd9Sstevel@tonic-gate * waits for the BIOS Owned bit to go to a zero before attempting 14107c478bd9Sstevel@tonic-gate * to use the EHCI controller. The time that OS must wait for BIOS 14117c478bd9Sstevel@tonic-gate * to respond to the request for ownership is beyond the scope of 14127c478bd9Sstevel@tonic-gate * this specification. 14137c478bd9Sstevel@tonic-gate * It waits up to EHCI_TAKEOVER_WAIT_COUNT*EHCI_TAKEOVER_DELAY ms 14147c478bd9Sstevel@tonic-gate * for BIOS to release the ownership. 14157c478bd9Sstevel@tonic-gate */ 14167c478bd9Sstevel@tonic-gate extended_cap |= EHCI_LEGSUP_OS_OWNED_SEM; 14177c478bd9Sstevel@tonic-gate pci_config_put32(ehcip->ehci_config_handle, extended_cap_offset, 14187c478bd9Sstevel@tonic-gate extended_cap); 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate for (retry = 0; retry < EHCI_TAKEOVER_WAIT_COUNT; retry++) { 14217c478bd9Sstevel@tonic-gate 14227c478bd9Sstevel@tonic-gate /* wait a special interval */ 14237c478bd9Sstevel@tonic-gate delay(drv_usectohz(EHCI_TAKEOVER_DELAY)); 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate /* Check to see if the BIOS has released the ownership */ 14267c478bd9Sstevel@tonic-gate extended_cap = pci_config_get32( 14277c478bd9Sstevel@tonic-gate ehcip->ehci_config_handle, extended_cap_offset); 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) { 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, 14327c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 14337c478bd9Sstevel@tonic-gate "ehci_take_control: BIOS has released " 14347c478bd9Sstevel@tonic-gate "the ownership. retry = %d", retry); 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate goto success; 14377c478bd9Sstevel@tonic-gate } 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate } 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 14427c478bd9Sstevel@tonic-gate "ehci_take_control: take control from BIOS failed."); 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate return (USB_FAILURE); 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate success: 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate #endif /* __x86 */ 14497c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 14507c478bd9Sstevel@tonic-gate } 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate /* 14547c478bd9Sstevel@tonic-gate * ehci_init_periodic_frame_list_table : 14557c478bd9Sstevel@tonic-gate * 14567c478bd9Sstevel@tonic-gate * Allocate the system memory and initialize Host Controller 14577c478bd9Sstevel@tonic-gate * Periodic Frame List table area. The starting of the Periodic 14587c478bd9Sstevel@tonic-gate * Frame List Table area must be 4096 byte aligned. 14597c478bd9Sstevel@tonic-gate */ 14607c478bd9Sstevel@tonic-gate static int 14617c478bd9Sstevel@tonic-gate ehci_init_periodic_frame_lst_table(ehci_state_t *ehcip) 14627c478bd9Sstevel@tonic-gate { 14637c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 14647c478bd9Sstevel@tonic-gate size_t real_length; 14657c478bd9Sstevel@tonic-gate uint_t ccount; 14667c478bd9Sstevel@tonic-gate int result; 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 14717c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table:"); 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 14747c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 14757c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 14767c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate /* Force the required 4K restrictive alignment */ 14797c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_PFL_ALIGNMENT; 14807c478bd9Sstevel@tonic-gate 14817c478bd9Sstevel@tonic-gate /* Create space for the Periodic Frame List */ 14827c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr, 14837c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 0, &ehcip->ehci_pflt_dma_handle) != DDI_SUCCESS) { 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate goto failure; 14867c478bd9Sstevel@tonic-gate } 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_pflt_dma_handle, 14897c478bd9Sstevel@tonic-gate sizeof (ehci_periodic_frame_list_t), 14907c478bd9Sstevel@tonic-gate &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 14917c478bd9Sstevel@tonic-gate 0, (caddr_t *)&ehcip->ehci_periodic_frame_list_tablep, 14927c478bd9Sstevel@tonic-gate &real_length, &ehcip->ehci_pflt_mem_handle)) { 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate goto failure; 14957c478bd9Sstevel@tonic-gate } 14967c478bd9Sstevel@tonic-gate 14973b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 14987c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: " 14997c478bd9Sstevel@tonic-gate "Real length %lu", real_length); 15007c478bd9Sstevel@tonic-gate 15017c478bd9Sstevel@tonic-gate /* Map the whole Periodic Frame List into the I/O address space */ 15027c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ehcip->ehci_pflt_dma_handle, 15037c478bd9Sstevel@tonic-gate NULL, (caddr_t)ehcip->ehci_periodic_frame_list_tablep, 15047c478bd9Sstevel@tonic-gate real_length, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 15057c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, &ehcip->ehci_pflt_cookie, &ccount); 15067c478bd9Sstevel@tonic-gate 15077c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 15087c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 15097c478bd9Sstevel@tonic-gate if (ccount != 1) { 15107c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 15117c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: " 15127c478bd9Sstevel@tonic-gate "More than 1 cookie"); 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate goto failure; 15157c478bd9Sstevel@tonic-gate } 15167c478bd9Sstevel@tonic-gate } else { 15177c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result); 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate goto failure; 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate 15227c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 15237c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: virtual 0x%p physical 0x%x", 15247c478bd9Sstevel@tonic-gate (void *)ehcip->ehci_periodic_frame_list_tablep, 15257c478bd9Sstevel@tonic-gate ehcip->ehci_pflt_cookie.dmac_address); 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate /* 15287c478bd9Sstevel@tonic-gate * DMA addresses for Periodic Frame List are bound. 15297c478bd9Sstevel@tonic-gate */ 15307c478bd9Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_PFLT_DMA_BOUND; 15317c478bd9Sstevel@tonic-gate 15327c478bd9Sstevel@tonic-gate bzero((void *)ehcip->ehci_periodic_frame_list_tablep, real_length); 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate /* Initialize the Periodic Frame List */ 15357c478bd9Sstevel@tonic-gate ehci_build_interrupt_lattice(ehcip); 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate /* Reset Byte Alignment to Default */ 15387c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 15417c478bd9Sstevel@tonic-gate failure: 15427c478bd9Sstevel@tonic-gate /* Byte alignment */ 15437c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 15447c478bd9Sstevel@tonic-gate 15457c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15467c478bd9Sstevel@tonic-gate } 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate /* 15507c478bd9Sstevel@tonic-gate * ehci_build_interrupt_lattice: 15517c478bd9Sstevel@tonic-gate * 15527c478bd9Sstevel@tonic-gate * Construct the interrupt lattice tree using static Endpoint Descriptors 15537c478bd9Sstevel@tonic-gate * (QH). This interrupt lattice tree will have total of 32 interrupt QH 15547c478bd9Sstevel@tonic-gate * lists and the Host Controller (HC) processes one interrupt QH list in 15557c478bd9Sstevel@tonic-gate * every frame. The Host Controller traverses the periodic schedule by 15567c478bd9Sstevel@tonic-gate * constructing an array offset reference from the Periodic List Base Address 15577c478bd9Sstevel@tonic-gate * register and bits 12 to 3 of Frame Index register. It fetches the element 15587c478bd9Sstevel@tonic-gate * and begins traversing the graph of linked schedule data structures. 15597c478bd9Sstevel@tonic-gate */ 15607c478bd9Sstevel@tonic-gate static void 15617c478bd9Sstevel@tonic-gate ehci_build_interrupt_lattice(ehci_state_t *ehcip) 15627c478bd9Sstevel@tonic-gate { 15637c478bd9Sstevel@tonic-gate ehci_qh_t *list_array = ehcip->ehci_qh_pool_addr; 15647c478bd9Sstevel@tonic-gate ushort_t ehci_index[EHCI_NUM_PERIODIC_FRAME_LISTS]; 15657c478bd9Sstevel@tonic-gate ehci_periodic_frame_list_t *periodic_frame_list = 15667c478bd9Sstevel@tonic-gate ehcip->ehci_periodic_frame_list_tablep; 15677c478bd9Sstevel@tonic-gate ushort_t *temp, num_of_nodes; 15687c478bd9Sstevel@tonic-gate uintptr_t addr; 15697c478bd9Sstevel@tonic-gate int i, j, k; 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 15727c478bd9Sstevel@tonic-gate "ehci_build_interrupt_lattice:"); 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate /* 15757c478bd9Sstevel@tonic-gate * Reserve the first 63 Endpoint Descriptor (QH) structures 15767c478bd9Sstevel@tonic-gate * in the pool as static endpoints & these are required for 15777c478bd9Sstevel@tonic-gate * constructing interrupt lattice tree. 15787c478bd9Sstevel@tonic-gate */ 15797c478bd9Sstevel@tonic-gate for (i = 0; i < EHCI_NUM_STATIC_NODES; i++) { 15807c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_state, EHCI_QH_STATIC); 15817c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_status, EHCI_QH_STS_HALTED); 15827c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_next_qtd, EHCI_QH_NEXT_QTD_PTR_VALID); 15837c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_alt_next_qtd, 15847c478bd9Sstevel@tonic-gate EHCI_QH_ALT_NEXT_QTD_PTR_VALID); 15857c478bd9Sstevel@tonic-gate } 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate /* 15887c478bd9Sstevel@tonic-gate * Make sure that last Endpoint on the periodic frame list terminates 15897c478bd9Sstevel@tonic-gate * periodic schedule. 15907c478bd9Sstevel@tonic-gate */ 15917c478bd9Sstevel@tonic-gate Set_QH(list_array[0].qh_link_ptr, EHCI_QH_LINK_PTR_VALID); 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate /* Build the interrupt lattice tree */ 15947c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_STATIC_NODES / 2); i++) { 15957c478bd9Sstevel@tonic-gate /* 15967c478bd9Sstevel@tonic-gate * The next pointer in the host controller endpoint 15977c478bd9Sstevel@tonic-gate * descriptor must contain an iommu address. Calculate 15987c478bd9Sstevel@tonic-gate * the offset into the cpu address and add this to the 15997c478bd9Sstevel@tonic-gate * starting iommu address. 16007c478bd9Sstevel@tonic-gate */ 16017c478bd9Sstevel@tonic-gate addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *)&list_array[i]); 16027c478bd9Sstevel@tonic-gate 16037c478bd9Sstevel@tonic-gate Set_QH(list_array[2*i + 1].qh_link_ptr, 16047c478bd9Sstevel@tonic-gate addr | EHCI_QH_LINK_REF_QH); 16057c478bd9Sstevel@tonic-gate Set_QH(list_array[2*i + 2].qh_link_ptr, 16067c478bd9Sstevel@tonic-gate addr | EHCI_QH_LINK_REF_QH); 16077c478bd9Sstevel@tonic-gate } 16087c478bd9Sstevel@tonic-gate 16097c478bd9Sstevel@tonic-gate /* Build the tree bottom */ 16107c478bd9Sstevel@tonic-gate temp = (unsigned short *) 16117c478bd9Sstevel@tonic-gate kmem_zalloc(EHCI_NUM_PERIODIC_FRAME_LISTS * 2, KM_SLEEP); 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate num_of_nodes = 1; 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate /* 16167c478bd9Sstevel@tonic-gate * Initialize the values which are used for setting up head pointers 16177c478bd9Sstevel@tonic-gate * for the 32ms scheduling lists which starts from the Periodic Frame 16187c478bd9Sstevel@tonic-gate * List. 16197c478bd9Sstevel@tonic-gate */ 16207c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_log_2(EHCI_NUM_PERIODIC_FRAME_LISTS); i++) { 16217c478bd9Sstevel@tonic-gate for (j = 0, k = 0; k < num_of_nodes; k++, j++) { 16227c478bd9Sstevel@tonic-gate ehci_index[j++] = temp[k]; 16237c478bd9Sstevel@tonic-gate ehci_index[j] = temp[k] + ehci_pow_2(i); 16247c478bd9Sstevel@tonic-gate } 16257c478bd9Sstevel@tonic-gate 16267c478bd9Sstevel@tonic-gate num_of_nodes *= 2; 16277c478bd9Sstevel@tonic-gate for (k = 0; k < num_of_nodes; k++) 16287c478bd9Sstevel@tonic-gate temp[k] = ehci_index[k]; 16297c478bd9Sstevel@tonic-gate } 16307c478bd9Sstevel@tonic-gate 16317c478bd9Sstevel@tonic-gate kmem_free((void *)temp, (EHCI_NUM_PERIODIC_FRAME_LISTS * 2)); 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate /* 16347c478bd9Sstevel@tonic-gate * Initialize the interrupt list in the Periodic Frame List Table 16357c478bd9Sstevel@tonic-gate * so that it points to the bottom of the tree. 16367c478bd9Sstevel@tonic-gate */ 16377c478bd9Sstevel@tonic-gate for (i = 0, j = 0; i < ehci_pow_2(TREE_HEIGHT); i++) { 16387c478bd9Sstevel@tonic-gate addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *) 16397c478bd9Sstevel@tonic-gate (&list_array[((EHCI_NUM_STATIC_NODES + 1) / 2) + i - 1])); 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate ASSERT(addr); 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate for (k = 0; k < ehci_pow_2(TREE_HEIGHT); k++) { 16447c478bd9Sstevel@tonic-gate Set_PFLT(periodic_frame_list-> 16457c478bd9Sstevel@tonic-gate ehci_periodic_frame_list_table[ehci_index[j++]], 16467c478bd9Sstevel@tonic-gate (uint32_t)(addr | EHCI_QH_LINK_REF_QH)); 16477c478bd9Sstevel@tonic-gate } 16487c478bd9Sstevel@tonic-gate } 16497c478bd9Sstevel@tonic-gate } 16507c478bd9Sstevel@tonic-gate 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate /* 16537c478bd9Sstevel@tonic-gate * ehci_alloc_hcdi_ops: 16547c478bd9Sstevel@tonic-gate * 16557c478bd9Sstevel@tonic-gate * The HCDI interfaces or entry points are the software interfaces used by 16567c478bd9Sstevel@tonic-gate * the Universal Serial Bus Driver (USBA) to access the services of the 16577c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD). During HCD initialization, inform USBA 16587c478bd9Sstevel@tonic-gate * about all available HCDI interfaces or entry points. 16597c478bd9Sstevel@tonic-gate */ 16607c478bd9Sstevel@tonic-gate usba_hcdi_ops_t * 16617c478bd9Sstevel@tonic-gate ehci_alloc_hcdi_ops(ehci_state_t *ehcip) 16627c478bd9Sstevel@tonic-gate { 16637c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *usba_hcdi_ops; 16647c478bd9Sstevel@tonic-gate 16657c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 16667c478bd9Sstevel@tonic-gate "ehci_alloc_hcdi_ops:"); 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate usba_hcdi_ops = usba_alloc_hcdi_ops(); 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_ops_version = HCDI_OPS_VERSION; 16717c478bd9Sstevel@tonic-gate 16724610e4a0Sfrits usba_hcdi_ops->usba_hcdi_pm_support = ehci_hcdi_pm_support; 16737c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_open = ehci_hcdi_pipe_open; 16747c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_close = ehci_hcdi_pipe_close; 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_reset = ehci_hcdi_pipe_reset; 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_ctrl_xfer = ehci_hcdi_pipe_ctrl_xfer; 16797c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_bulk_xfer = ehci_hcdi_pipe_bulk_xfer; 16807c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_intr_xfer = ehci_hcdi_pipe_intr_xfer; 16817c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_isoc_xfer = ehci_hcdi_pipe_isoc_xfer; 16827c478bd9Sstevel@tonic-gate 16837c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_bulk_transfer_size = 16847c478bd9Sstevel@tonic-gate ehci_hcdi_bulk_transfer_size; 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_intr_polling = 16877c478bd9Sstevel@tonic-gate ehci_hcdi_pipe_stop_intr_polling; 16887c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_isoc_polling = 16897c478bd9Sstevel@tonic-gate ehci_hcdi_pipe_stop_isoc_polling; 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_current_frame_number = 16927c478bd9Sstevel@tonic-gate ehci_hcdi_get_current_frame_number; 16937c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_max_isoc_pkts = 16947c478bd9Sstevel@tonic-gate ehci_hcdi_get_max_isoc_pkts; 16957c478bd9Sstevel@tonic-gate 16967c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_init = 16977c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_init; 16987c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_enter = 16997c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_enter; 17007c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_read = 17017c478bd9Sstevel@tonic-gate ehci_hcdi_polled_read; 17027c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_exit = 17037c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_exit; 17047c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_fini = 17057c478bd9Sstevel@tonic-gate ehci_hcdi_polled_input_fini; 17067c478bd9Sstevel@tonic-gate return (usba_hcdi_ops); 17077c478bd9Sstevel@tonic-gate } 17087c478bd9Sstevel@tonic-gate 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate /* 17117c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) deinitialization functions 17127c478bd9Sstevel@tonic-gate */ 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate /* 17157c478bd9Sstevel@tonic-gate * ehci_cleanup: 17167c478bd9Sstevel@tonic-gate * 17177c478bd9Sstevel@tonic-gate * Cleanup on attach failure or detach 17187c478bd9Sstevel@tonic-gate */ 17197c478bd9Sstevel@tonic-gate int 17207c478bd9Sstevel@tonic-gate ehci_cleanup(ehci_state_t *ehcip) 17217c478bd9Sstevel@tonic-gate { 17227c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw; 17237c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; 17247c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd; 17257c478bd9Sstevel@tonic-gate int i, ctrl, rval; 17267c478bd9Sstevel@tonic-gate int flags = ehcip->ehci_flags; 17277c478bd9Sstevel@tonic-gate 17287c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_cleanup:"); 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate if (flags & EHCI_RHREG) { 17317c478bd9Sstevel@tonic-gate /* Unload the root hub driver */ 17327c478bd9Sstevel@tonic-gate if (ehci_unload_root_hub_driver(ehcip) != USB_SUCCESS) { 17337c478bd9Sstevel@tonic-gate 17347c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 17357c478bd9Sstevel@tonic-gate } 17367c478bd9Sstevel@tonic-gate } 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate if (flags & EHCI_USBAREG) { 17397c478bd9Sstevel@tonic-gate /* Unregister this HCD instance with USBA */ 17407c478bd9Sstevel@tonic-gate usba_hcdi_unregister(ehcip->ehci_dip); 17417c478bd9Sstevel@tonic-gate } 17427c478bd9Sstevel@tonic-gate 17437c478bd9Sstevel@tonic-gate if (flags & EHCI_INTR) { 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate /* Disable all EHCI QH list processing */ 17487c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) & 17497c478bd9Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | 17507c478bd9Sstevel@tonic-gate EHCI_CMD_PERIODIC_SCHED_ENABLE))); 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate /* Disable all EHCI interrupts */ 17537c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0); 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate /* wait for the next SOF */ 17567c478bd9Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip); 17577c478bd9Sstevel@tonic-gate 17584610e4a0Sfrits /* Route all Root hub ports to Classic host controller */ 17594610e4a0Sfrits Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC); 17604610e4a0Sfrits 17617c478bd9Sstevel@tonic-gate /* Stop the EHCI host controller */ 17627c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 17637c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN); 17647c478bd9Sstevel@tonic-gate 17657c478bd9Sstevel@tonic-gate /* Wait for sometime */ 17667c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_TIMEWAIT); 17677c478bd9Sstevel@tonic-gate 17687c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 17697c478bd9Sstevel@tonic-gate 17709c75c6bfSgovinda ehci_rem_intrs(ehcip); 17717c478bd9Sstevel@tonic-gate } 17727c478bd9Sstevel@tonic-gate 17737c478bd9Sstevel@tonic-gate /* Unmap the EHCI registers */ 17747c478bd9Sstevel@tonic-gate if (ehcip->ehci_caps_handle) { 17757c478bd9Sstevel@tonic-gate ddi_regs_map_free(&ehcip->ehci_caps_handle); 17767c478bd9Sstevel@tonic-gate } 17777c478bd9Sstevel@tonic-gate 17787c478bd9Sstevel@tonic-gate if (ehcip->ehci_config_handle) { 17797c478bd9Sstevel@tonic-gate pci_config_teardown(&ehcip->ehci_config_handle); 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate /* Free all the buffers */ 17837c478bd9Sstevel@tonic-gate if (ehcip->ehci_qtd_pool_addr && ehcip->ehci_qtd_pool_mem_handle) { 17847c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_qtd_pool_size; i ++) { 17857c478bd9Sstevel@tonic-gate qtd = &ehcip->ehci_qtd_pool_addr[i]; 17867c478bd9Sstevel@tonic-gate ctrl = Get_QTD(ehcip-> 17877c478bd9Sstevel@tonic-gate ehci_qtd_pool_addr[i].qtd_state); 17887c478bd9Sstevel@tonic-gate 17897c478bd9Sstevel@tonic-gate if ((ctrl != EHCI_QTD_FREE) && 17907c478bd9Sstevel@tonic-gate (ctrl != EHCI_QTD_DUMMY) && 17917c478bd9Sstevel@tonic-gate (qtd->qtd_trans_wrapper)) { 17927c478bd9Sstevel@tonic-gate 17937c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 17947c478bd9Sstevel@tonic-gate 17957c478bd9Sstevel@tonic-gate tw = (ehci_trans_wrapper_t *) 17967c478bd9Sstevel@tonic-gate EHCI_LOOKUP_ID((uint32_t) 17977c478bd9Sstevel@tonic-gate Get_QTD(qtd->qtd_trans_wrapper)); 17987c478bd9Sstevel@tonic-gate 17997c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 18007c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */ 18037c478bd9Sstevel@tonic-gate ehci_stop_xfer_timer(ehcip, tw, 18047c478bd9Sstevel@tonic-gate EHCI_REMOVE_XFER_ALWAYS); 18057c478bd9Sstevel@tonic-gate 18067c478bd9Sstevel@tonic-gate ehci_deallocate_tw(ehcip, pp, tw); 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 18097c478bd9Sstevel@tonic-gate } 18107c478bd9Sstevel@tonic-gate } 18117c478bd9Sstevel@tonic-gate 18127c478bd9Sstevel@tonic-gate /* 18137c478bd9Sstevel@tonic-gate * If EHCI_QTD_POOL_BOUND flag is set, then unbind 18147c478bd9Sstevel@tonic-gate * the handle for QTD pools. 18157c478bd9Sstevel@tonic-gate */ 18167c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 18177c478bd9Sstevel@tonic-gate EHCI_QTD_POOL_BOUND) == EHCI_QTD_POOL_BOUND) { 18187c478bd9Sstevel@tonic-gate 18197c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 18207c478bd9Sstevel@tonic-gate ehcip->ehci_qtd_pool_dma_handle); 18217c478bd9Sstevel@tonic-gate 18227c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 18237c478bd9Sstevel@tonic-gate } 18247c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_qtd_pool_mem_handle); 18257c478bd9Sstevel@tonic-gate } 18267c478bd9Sstevel@tonic-gate 18277c478bd9Sstevel@tonic-gate /* Free the QTD pool */ 18287c478bd9Sstevel@tonic-gate if (ehcip->ehci_qtd_pool_dma_handle) { 18297c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_qtd_pool_dma_handle); 18307c478bd9Sstevel@tonic-gate } 18317c478bd9Sstevel@tonic-gate 18327c478bd9Sstevel@tonic-gate if (ehcip->ehci_qh_pool_addr && ehcip->ehci_qh_pool_mem_handle) { 18337c478bd9Sstevel@tonic-gate /* 18347c478bd9Sstevel@tonic-gate * If EHCI_QH_POOL_BOUND flag is set, then unbind 18357c478bd9Sstevel@tonic-gate * the handle for QH pools. 18367c478bd9Sstevel@tonic-gate */ 18377c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 18387c478bd9Sstevel@tonic-gate EHCI_QH_POOL_BOUND) == EHCI_QH_POOL_BOUND) { 18397c478bd9Sstevel@tonic-gate 18407c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 18417c478bd9Sstevel@tonic-gate ehcip->ehci_qh_pool_dma_handle); 18427c478bd9Sstevel@tonic-gate 18437c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 18447c478bd9Sstevel@tonic-gate } 18457c478bd9Sstevel@tonic-gate 18467c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_qh_pool_mem_handle); 18477c478bd9Sstevel@tonic-gate } 18487c478bd9Sstevel@tonic-gate 18497c478bd9Sstevel@tonic-gate /* Free the QH pool */ 18507c478bd9Sstevel@tonic-gate if (ehcip->ehci_qh_pool_dma_handle) { 18517c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_qh_pool_dma_handle); 18527c478bd9Sstevel@tonic-gate } 18537c478bd9Sstevel@tonic-gate 18547c478bd9Sstevel@tonic-gate /* Free the Periodic frame list table (PFLT) area */ 18557c478bd9Sstevel@tonic-gate if (ehcip->ehci_periodic_frame_list_tablep && 18567c478bd9Sstevel@tonic-gate ehcip->ehci_pflt_mem_handle) { 18577c478bd9Sstevel@tonic-gate /* 18587c478bd9Sstevel@tonic-gate * If EHCI_PFLT_DMA_BOUND flag is set, then unbind 18597c478bd9Sstevel@tonic-gate * the handle for PFLT. 18607c478bd9Sstevel@tonic-gate */ 18617c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 18627c478bd9Sstevel@tonic-gate EHCI_PFLT_DMA_BOUND) == EHCI_PFLT_DMA_BOUND) { 18637c478bd9Sstevel@tonic-gate 18647c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 18657c478bd9Sstevel@tonic-gate ehcip->ehci_pflt_dma_handle); 18667c478bd9Sstevel@tonic-gate 18677c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 18687c478bd9Sstevel@tonic-gate } 18697c478bd9Sstevel@tonic-gate 18707c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_pflt_mem_handle); 18717c478bd9Sstevel@tonic-gate } 18727c478bd9Sstevel@tonic-gate 18737c478bd9Sstevel@tonic-gate (void) ehci_isoc_cleanup(ehcip); 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate if (ehcip->ehci_pflt_dma_handle) { 18767c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_pflt_dma_handle); 18777c478bd9Sstevel@tonic-gate } 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate if (flags & EHCI_INTR) { 18807c478bd9Sstevel@tonic-gate /* Destroy the mutex */ 18817c478bd9Sstevel@tonic-gate mutex_destroy(&ehcip->ehci_int_mutex); 18827c478bd9Sstevel@tonic-gate 18837c478bd9Sstevel@tonic-gate /* Destroy the async schedule advance condition variable */ 18847c478bd9Sstevel@tonic-gate cv_destroy(&ehcip->ehci_async_schedule_advance_cv); 18857c478bd9Sstevel@tonic-gate } 18867c478bd9Sstevel@tonic-gate 18877c478bd9Sstevel@tonic-gate /* clean up kstat structs */ 18887c478bd9Sstevel@tonic-gate ehci_destroy_stats(ehcip); 18897c478bd9Sstevel@tonic-gate 18907c478bd9Sstevel@tonic-gate /* Free ehci hcdi ops */ 18917c478bd9Sstevel@tonic-gate if (ehcip->ehci_hcdi_ops) { 18927c478bd9Sstevel@tonic-gate usba_free_hcdi_ops(ehcip->ehci_hcdi_ops); 18937c478bd9Sstevel@tonic-gate } 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate if (flags & EHCI_ZALLOC) { 18967c478bd9Sstevel@tonic-gate 18977c478bd9Sstevel@tonic-gate usb_free_log_hdl(ehcip->ehci_log_hdl); 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate /* Remove all properties that might have been created */ 19007c478bd9Sstevel@tonic-gate ddi_prop_remove_all(ehcip->ehci_dip); 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate /* Free the soft state */ 19037c478bd9Sstevel@tonic-gate ddi_soft_state_free(ehci_statep, 19047c478bd9Sstevel@tonic-gate ddi_get_instance(ehcip->ehci_dip)); 19057c478bd9Sstevel@tonic-gate } 19067c478bd9Sstevel@tonic-gate 19077c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 19087c478bd9Sstevel@tonic-gate } 19097c478bd9Sstevel@tonic-gate 19107c478bd9Sstevel@tonic-gate 19119c75c6bfSgovinda /* 19129c75c6bfSgovinda * ehci_rem_intrs: 19139c75c6bfSgovinda * 19149c75c6bfSgovinda * Unregister FIXED or MSI interrupts 19159c75c6bfSgovinda */ 19169c75c6bfSgovinda static void 19179c75c6bfSgovinda ehci_rem_intrs(ehci_state_t *ehcip) 19189c75c6bfSgovinda { 19199c75c6bfSgovinda int i; 19209c75c6bfSgovinda 19219c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19229c75c6bfSgovinda "ehci_rem_intrs: interrupt type 0x%x", ehcip->ehci_intr_type); 19239c75c6bfSgovinda 19249c75c6bfSgovinda /* Disable all interrupts */ 19259c75c6bfSgovinda if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) { 19269c75c6bfSgovinda (void) ddi_intr_block_disable(ehcip->ehci_htable, 19279c75c6bfSgovinda ehcip->ehci_intr_cnt); 19289c75c6bfSgovinda } else { 19299c75c6bfSgovinda for (i = 0; i < ehcip->ehci_intr_cnt; i++) { 19309c75c6bfSgovinda (void) ddi_intr_disable(ehcip->ehci_htable[i]); 19319c75c6bfSgovinda } 19329c75c6bfSgovinda } 19339c75c6bfSgovinda 19349c75c6bfSgovinda /* Call ddi_intr_remove_handler() */ 19359c75c6bfSgovinda for (i = 0; i < ehcip->ehci_intr_cnt; i++) { 19369c75c6bfSgovinda (void) ddi_intr_remove_handler(ehcip->ehci_htable[i]); 19379c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 19389c75c6bfSgovinda } 19399c75c6bfSgovinda 19409c75c6bfSgovinda kmem_free(ehcip->ehci_htable, 19419c75c6bfSgovinda ehcip->ehci_intr_cnt * sizeof (ddi_intr_handle_t)); 19429c75c6bfSgovinda } 19439c75c6bfSgovinda 19449c75c6bfSgovinda 19457c478bd9Sstevel@tonic-gate /* 19467c478bd9Sstevel@tonic-gate * ehci_cpr_suspend 19477c478bd9Sstevel@tonic-gate */ 19487c478bd9Sstevel@tonic-gate int 19497c478bd9Sstevel@tonic-gate ehci_cpr_suspend(ehci_state_t *ehcip) 19507c478bd9Sstevel@tonic-gate { 19517c478bd9Sstevel@tonic-gate int i; 19527c478bd9Sstevel@tonic-gate 19537c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19547c478bd9Sstevel@tonic-gate "ehci_cpr_suspend:"); 19557c478bd9Sstevel@tonic-gate 19567c478bd9Sstevel@tonic-gate /* Call into the root hub and suspend it */ 19577c478bd9Sstevel@tonic-gate if (usba_hubdi_detach(ehcip->ehci_dip, DDI_SUSPEND) != DDI_SUCCESS) { 19587c478bd9Sstevel@tonic-gate 19597c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19607c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: root hub fails to suspend"); 19617c478bd9Sstevel@tonic-gate 19627c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 19637c478bd9Sstevel@tonic-gate } 19647c478bd9Sstevel@tonic-gate 19657c478bd9Sstevel@tonic-gate /* Only root hub's intr pipe should be open at this time */ 19667c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 19677c478bd9Sstevel@tonic-gate 19687c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_open_pipe_count == 0); 19697c478bd9Sstevel@tonic-gate 19707c478bd9Sstevel@tonic-gate /* Just wait till all resources are reclaimed */ 19717c478bd9Sstevel@tonic-gate i = 0; 19727c478bd9Sstevel@tonic-gate while ((ehcip->ehci_reclaim_list != NULL) && (i++ < 3)) { 19737c478bd9Sstevel@tonic-gate ehci_handle_endpoint_reclaimation(ehcip); 19747c478bd9Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip); 19757c478bd9Sstevel@tonic-gate } 19767c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_reclaim_list == NULL); 19777c478bd9Sstevel@tonic-gate 19783b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19797c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: Disable HC QH list processing"); 19807c478bd9Sstevel@tonic-gate 19817c478bd9Sstevel@tonic-gate /* Disable all EHCI QH list processing */ 19827c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) & 19837c478bd9Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE))); 19847c478bd9Sstevel@tonic-gate 19853b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19867c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: Disable HC interrupts"); 19877c478bd9Sstevel@tonic-gate 19887c478bd9Sstevel@tonic-gate /* Disable all EHCI interrupts */ 19897c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0); 19907c478bd9Sstevel@tonic-gate 19913b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19927c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: Wait for the next SOF"); 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate /* Wait for the next SOF */ 19957c478bd9Sstevel@tonic-gate if (ehci_wait_for_sof(ehcip) != USB_SUCCESS) { 19967c478bd9Sstevel@tonic-gate 19977c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19987c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: ehci host controller suspend failed"); 19997c478bd9Sstevel@tonic-gate 20007c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 20017c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 20027c478bd9Sstevel@tonic-gate } 20037c478bd9Sstevel@tonic-gate 20047c478bd9Sstevel@tonic-gate /* 20057c478bd9Sstevel@tonic-gate * Stop the ehci host controller 20067c478bd9Sstevel@tonic-gate * if usb keyboard is not connected. 20077c478bd9Sstevel@tonic-gate */ 20087c478bd9Sstevel@tonic-gate if (ehcip->ehci_polled_kbd_count == 0) { 20097c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 20107c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN); 20117c478bd9Sstevel@tonic-gate } 20127c478bd9Sstevel@tonic-gate 20137c478bd9Sstevel@tonic-gate /* Set host controller soft state to suspend */ 20147c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_SUSPEND_STATE; 20157c478bd9Sstevel@tonic-gate 20167c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 20177c478bd9Sstevel@tonic-gate 20187c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 20197c478bd9Sstevel@tonic-gate } 20207c478bd9Sstevel@tonic-gate 20217c478bd9Sstevel@tonic-gate 20227c478bd9Sstevel@tonic-gate /* 20237c478bd9Sstevel@tonic-gate * ehci_cpr_resume 20247c478bd9Sstevel@tonic-gate */ 20257c478bd9Sstevel@tonic-gate int 20267c478bd9Sstevel@tonic-gate ehci_cpr_resume(ehci_state_t *ehcip) 20277c478bd9Sstevel@tonic-gate { 20287c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 20297c478bd9Sstevel@tonic-gate 20307c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 20317c478bd9Sstevel@tonic-gate "ehci_cpr_resume: Restart the controller"); 20327c478bd9Sstevel@tonic-gate 20337c478bd9Sstevel@tonic-gate /* Cleanup ehci specific information across cpr */ 20347c478bd9Sstevel@tonic-gate ehci_cpr_cleanup(ehcip); 20357c478bd9Sstevel@tonic-gate 20367c478bd9Sstevel@tonic-gate /* Restart the controller */ 20373b00f311Syq if (ehci_init_ctlr(ehcip, EHCI_NORMAL_INITIALIZATION) != DDI_SUCCESS) { 20387c478bd9Sstevel@tonic-gate 20397c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 20407c478bd9Sstevel@tonic-gate "ehci_cpr_resume: ehci host controller resume failed "); 20417c478bd9Sstevel@tonic-gate 20427c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 20437c478bd9Sstevel@tonic-gate 20447c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 20457c478bd9Sstevel@tonic-gate } 20467c478bd9Sstevel@tonic-gate 20477c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 20487c478bd9Sstevel@tonic-gate 20497c478bd9Sstevel@tonic-gate /* Now resume the root hub */ 20507c478bd9Sstevel@tonic-gate if (usba_hubdi_attach(ehcip->ehci_dip, DDI_RESUME) != DDI_SUCCESS) { 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 20537c478bd9Sstevel@tonic-gate } 20547c478bd9Sstevel@tonic-gate 20557c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 20567c478bd9Sstevel@tonic-gate } 20577c478bd9Sstevel@tonic-gate 20587c478bd9Sstevel@tonic-gate 20597c478bd9Sstevel@tonic-gate /* 20607c478bd9Sstevel@tonic-gate * Bandwidth Allocation functions 20617c478bd9Sstevel@tonic-gate */ 20627c478bd9Sstevel@tonic-gate 20637c478bd9Sstevel@tonic-gate /* 20647c478bd9Sstevel@tonic-gate * ehci_allocate_bandwidth: 20657c478bd9Sstevel@tonic-gate * 20667c478bd9Sstevel@tonic-gate * Figure out whether or not this interval may be supported. Return the index 20677c478bd9Sstevel@tonic-gate * into the lattice if it can be supported. Return allocation failure if it 20687c478bd9Sstevel@tonic-gate * can not be supported. 20697c478bd9Sstevel@tonic-gate */ 20707c478bd9Sstevel@tonic-gate int 20717c478bd9Sstevel@tonic-gate ehci_allocate_bandwidth( 20727c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 20737c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 20747c478bd9Sstevel@tonic-gate uint_t *pnode, 20757c478bd9Sstevel@tonic-gate uchar_t *smask, 20767c478bd9Sstevel@tonic-gate uchar_t *cmask) 20777c478bd9Sstevel@tonic-gate { 20787c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 20797c478bd9Sstevel@tonic-gate 20807c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 20817c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate /* Reset the pnode to the last checked pnode */ 20847c478bd9Sstevel@tonic-gate *pnode = 0; 20857c478bd9Sstevel@tonic-gate 20867c478bd9Sstevel@tonic-gate /* Allocate high speed bandwidth */ 20877c478bd9Sstevel@tonic-gate if ((error = ehci_allocate_high_speed_bandwidth(ehcip, 20887c478bd9Sstevel@tonic-gate ph, pnode, smask, cmask)) != USB_SUCCESS) { 20897c478bd9Sstevel@tonic-gate 20907c478bd9Sstevel@tonic-gate return (error); 20917c478bd9Sstevel@tonic-gate } 20927c478bd9Sstevel@tonic-gate 20937c478bd9Sstevel@tonic-gate /* 20947c478bd9Sstevel@tonic-gate * For low/full speed usb devices, allocate classic TT bandwidth 20957c478bd9Sstevel@tonic-gate * in additional to high speed bandwidth. 20967c478bd9Sstevel@tonic-gate */ 20977c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) { 20987c478bd9Sstevel@tonic-gate 20997c478bd9Sstevel@tonic-gate /* Allocate classic TT bandwidth */ 21007c478bd9Sstevel@tonic-gate if ((error = ehci_allocate_classic_tt_bandwidth( 21017c478bd9Sstevel@tonic-gate ehcip, ph, *pnode)) != USB_SUCCESS) { 21027c478bd9Sstevel@tonic-gate 21037c478bd9Sstevel@tonic-gate /* Deallocate high speed bandwidth */ 21047c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth( 21057c478bd9Sstevel@tonic-gate ehcip, ph, *pnode, *smask, *cmask); 21067c478bd9Sstevel@tonic-gate } 21077c478bd9Sstevel@tonic-gate } 21087c478bd9Sstevel@tonic-gate 21097c478bd9Sstevel@tonic-gate return (error); 21107c478bd9Sstevel@tonic-gate } 21117c478bd9Sstevel@tonic-gate 21127c478bd9Sstevel@tonic-gate 21137c478bd9Sstevel@tonic-gate /* 21147c478bd9Sstevel@tonic-gate * ehci_allocate_high_speed_bandwidth: 21157c478bd9Sstevel@tonic-gate * 21167c478bd9Sstevel@tonic-gate * Allocate high speed bandwidth for the low/full/high speed interrupt and 21177c478bd9Sstevel@tonic-gate * isochronous endpoints. 21187c478bd9Sstevel@tonic-gate */ 21197c478bd9Sstevel@tonic-gate static int 21207c478bd9Sstevel@tonic-gate ehci_allocate_high_speed_bandwidth( 21217c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 21227c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 21237c478bd9Sstevel@tonic-gate uint_t *pnode, 21247c478bd9Sstevel@tonic-gate uchar_t *smask, 21257c478bd9Sstevel@tonic-gate uchar_t *cmask) 21267c478bd9Sstevel@tonic-gate { 21277c478bd9Sstevel@tonic-gate uint_t sbandwidth, cbandwidth; 21287c478bd9Sstevel@tonic-gate int interval; 21297c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 21307c478bd9Sstevel@tonic-gate usba_device_t *child_ud; 21317c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 21327c478bd9Sstevel@tonic-gate int error; 21337c478bd9Sstevel@tonic-gate 21347c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 21357c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 21367c478bd9Sstevel@tonic-gate 21377c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 21387c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 21397c478bd9Sstevel@tonic-gate 21407c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 21417c478bd9Sstevel@tonic-gate 21427c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 21437c478bd9Sstevel@tonic-gate port_status = ph->p_usba_device->usb_port_status; 21447c478bd9Sstevel@tonic-gate 21457c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 21467c478bd9Sstevel@tonic-gate 21477c478bd9Sstevel@tonic-gate /* 21487c478bd9Sstevel@tonic-gate * Calculate the length in bytes of a transaction on this 21497c478bd9Sstevel@tonic-gate * periodic endpoint. Return failure if maximum packet is 21507c478bd9Sstevel@tonic-gate * zero. 21517c478bd9Sstevel@tonic-gate */ 21527c478bd9Sstevel@tonic-gate error = ehci_compute_high_speed_bandwidth(ehcip, endpoint, 21537c478bd9Sstevel@tonic-gate port_status, &sbandwidth, &cbandwidth); 21547c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 21557c478bd9Sstevel@tonic-gate 21567c478bd9Sstevel@tonic-gate return (error); 21577c478bd9Sstevel@tonic-gate } 21587c478bd9Sstevel@tonic-gate 21597c478bd9Sstevel@tonic-gate /* 21607c478bd9Sstevel@tonic-gate * Adjust polling interval to be a power of 2. 21617c478bd9Sstevel@tonic-gate * If this interval can't be supported, return 21627c478bd9Sstevel@tonic-gate * allocation failure. 21637c478bd9Sstevel@tonic-gate */ 21647c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 21657c478bd9Sstevel@tonic-gate if (interval == USB_FAILURE) { 21667c478bd9Sstevel@tonic-gate 21677c478bd9Sstevel@tonic-gate return (USB_FAILURE); 21687c478bd9Sstevel@tonic-gate } 21697c478bd9Sstevel@tonic-gate 21707c478bd9Sstevel@tonic-gate if (port_status == USBA_HIGH_SPEED_DEV) { 21717c478bd9Sstevel@tonic-gate /* Allocate bandwidth for high speed devices, except ITD */ 21727c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_hs_mask(ehcip, smask, pnode, 21737c478bd9Sstevel@tonic-gate endpoint, sbandwidth, interval); 21747c478bd9Sstevel@tonic-gate *cmask = 0x00; 21757c478bd9Sstevel@tonic-gate 21767c478bd9Sstevel@tonic-gate } else { 21777c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) == 21787c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR) { 21797c478bd9Sstevel@tonic-gate 21807c478bd9Sstevel@tonic-gate /* Allocate bandwidth for low speed interrupt */ 21817c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_ls_intr_mask(ehcip, 21827c478bd9Sstevel@tonic-gate smask, cmask, pnode, sbandwidth, cbandwidth, 21837c478bd9Sstevel@tonic-gate interval); 21847c478bd9Sstevel@tonic-gate } else { 21857c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 21867c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 21877c478bd9Sstevel@tonic-gate 21887c478bd9Sstevel@tonic-gate /* Allocate bandwidth for sitd in */ 21897c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_sitd_in_mask(ehcip, 21907c478bd9Sstevel@tonic-gate smask, cmask, pnode, sbandwidth, cbandwidth, 21917c478bd9Sstevel@tonic-gate interval); 21927c478bd9Sstevel@tonic-gate } else { 21937c478bd9Sstevel@tonic-gate 21947c478bd9Sstevel@tonic-gate /* Allocate bandwidth for sitd out */ 21957c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_sitd_out_mask(ehcip, 21967c478bd9Sstevel@tonic-gate smask, pnode, sbandwidth, interval); 21977c478bd9Sstevel@tonic-gate *cmask = 0x00; 21987c478bd9Sstevel@tonic-gate } 21997c478bd9Sstevel@tonic-gate } 22007c478bd9Sstevel@tonic-gate } 22017c478bd9Sstevel@tonic-gate 22027c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 22037c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 22047c478bd9Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: Reached maximum " 22057c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth for a " 22067c478bd9Sstevel@tonic-gate "given high-speed periodic endpoint"); 22077c478bd9Sstevel@tonic-gate 22087c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 22097c478bd9Sstevel@tonic-gate } 22107c478bd9Sstevel@tonic-gate 22117c478bd9Sstevel@tonic-gate return (error); 22127c478bd9Sstevel@tonic-gate } 22137c478bd9Sstevel@tonic-gate 22147c478bd9Sstevel@tonic-gate 22157c478bd9Sstevel@tonic-gate /* 22167c478bd9Sstevel@tonic-gate * ehci_allocate_classic_tt_speed_bandwidth: 22177c478bd9Sstevel@tonic-gate * 22187c478bd9Sstevel@tonic-gate * Allocate classic TT bandwidth for the low/full speed interrupt and 22197c478bd9Sstevel@tonic-gate * isochronous endpoints. 22207c478bd9Sstevel@tonic-gate */ 22217c478bd9Sstevel@tonic-gate static int 22227c478bd9Sstevel@tonic-gate ehci_allocate_classic_tt_bandwidth( 22237c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 22247c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 22257c478bd9Sstevel@tonic-gate uint_t pnode) 22267c478bd9Sstevel@tonic-gate { 22277c478bd9Sstevel@tonic-gate uint_t bandwidth, min; 22287c478bd9Sstevel@tonic-gate uint_t height, leftmost, list; 22297c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 22307c478bd9Sstevel@tonic-gate usba_device_t *child_ud, *parent_ud; 22317c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 22327c478bd9Sstevel@tonic-gate int i, interval; 22337c478bd9Sstevel@tonic-gate 22347c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 22357c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 22367c478bd9Sstevel@tonic-gate 22377c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 22387c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 22397c478bd9Sstevel@tonic-gate 22407c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 22417c478bd9Sstevel@tonic-gate 22427c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 22437c478bd9Sstevel@tonic-gate port_status = child_ud->usb_port_status; 22447c478bd9Sstevel@tonic-gate 22457c478bd9Sstevel@tonic-gate /* Get the parent high speed hub's usba device structure */ 22467c478bd9Sstevel@tonic-gate parent_ud = child_ud->usb_hs_hub_usba_dev; 22477c478bd9Sstevel@tonic-gate 22487c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 22497c478bd9Sstevel@tonic-gate 22503b00f311Syq USB_DPRINTF_L3(PRINT_MASK_BW, ehcip->ehci_log_hdl, 22517c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: " 22527c478bd9Sstevel@tonic-gate "child_ud 0x%p parent_ud 0x%p", child_ud, parent_ud); 22537c478bd9Sstevel@tonic-gate 22547c478bd9Sstevel@tonic-gate /* 22557c478bd9Sstevel@tonic-gate * Calculate the length in bytes of a transaction on this 22567c478bd9Sstevel@tonic-gate * periodic endpoint. Return failure if maximum packet is 22577c478bd9Sstevel@tonic-gate * zero. 22587c478bd9Sstevel@tonic-gate */ 22597c478bd9Sstevel@tonic-gate if (ehci_compute_classic_bandwidth(endpoint, 22607c478bd9Sstevel@tonic-gate port_status, &bandwidth) != USB_SUCCESS) { 22617c478bd9Sstevel@tonic-gate 22627c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 22637c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Periodic endpoint " 22647c478bd9Sstevel@tonic-gate "with zero endpoint maximum packet size is not supported"); 22657c478bd9Sstevel@tonic-gate 22667c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 22677c478bd9Sstevel@tonic-gate } 22687c478bd9Sstevel@tonic-gate 22693b00f311Syq USB_DPRINTF_L3(PRINT_MASK_BW, ehcip->ehci_log_hdl, 22707c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: bandwidth %d", bandwidth); 22717c478bd9Sstevel@tonic-gate 22727c478bd9Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex); 22737c478bd9Sstevel@tonic-gate 22747c478bd9Sstevel@tonic-gate /* 22757c478bd9Sstevel@tonic-gate * If the length in bytes plus the allocated bandwidth exceeds 22767c478bd9Sstevel@tonic-gate * the maximum, return bandwidth allocation failure. 22777c478bd9Sstevel@tonic-gate */ 22787c478bd9Sstevel@tonic-gate if ((parent_ud->usb_hs_hub_min_bandwidth + bandwidth) > 22797c478bd9Sstevel@tonic-gate FS_PERIODIC_BANDWIDTH) { 22807c478bd9Sstevel@tonic-gate 22817c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 22827c478bd9Sstevel@tonic-gate 22837c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 22847c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Reached maximum " 22857c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth for a " 22867c478bd9Sstevel@tonic-gate "given low/full speed periodic endpoint"); 22877c478bd9Sstevel@tonic-gate 22887c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 22897c478bd9Sstevel@tonic-gate } 22907c478bd9Sstevel@tonic-gate 22917c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 22927c478bd9Sstevel@tonic-gate 22937c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 22947c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 22957c478bd9Sstevel@tonic-gate 22967c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 22977c478bd9Sstevel@tonic-gate height = ehci_lattice_height(interval); 22987c478bd9Sstevel@tonic-gate 22997c478bd9Sstevel@tonic-gate /* Find the leftmost leaf in the subtree specified by the node. */ 23007c478bd9Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height); 23017c478bd9Sstevel@tonic-gate 23027c478bd9Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex); 23037c478bd9Sstevel@tonic-gate 23047c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) { 23057c478bd9Sstevel@tonic-gate list = ehci_index[leftmost + i]; 23067c478bd9Sstevel@tonic-gate 23077c478bd9Sstevel@tonic-gate if ((parent_ud->usb_hs_hub_bandwidth[list] + 23087c478bd9Sstevel@tonic-gate bandwidth) > FS_PERIODIC_BANDWIDTH) { 23097c478bd9Sstevel@tonic-gate 23107c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 23117c478bd9Sstevel@tonic-gate 23127c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 23137c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Reached " 23147c478bd9Sstevel@tonic-gate "maximum bandwidth value and cannot allocate " 23157c478bd9Sstevel@tonic-gate "bandwidth for low/full periodic endpoint"); 23167c478bd9Sstevel@tonic-gate 23177c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 23187c478bd9Sstevel@tonic-gate } 23197c478bd9Sstevel@tonic-gate } 23207c478bd9Sstevel@tonic-gate 23217c478bd9Sstevel@tonic-gate /* 23227c478bd9Sstevel@tonic-gate * All the leaves for this node must be updated with the bandwidth. 23237c478bd9Sstevel@tonic-gate */ 23247c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) { 23257c478bd9Sstevel@tonic-gate list = ehci_index[leftmost + i]; 23267c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_bandwidth[list] += bandwidth; 23277c478bd9Sstevel@tonic-gate } 23287c478bd9Sstevel@tonic-gate 23297c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */ 23307c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[0]; 23317c478bd9Sstevel@tonic-gate 23327c478bd9Sstevel@tonic-gate for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) { 23337c478bd9Sstevel@tonic-gate if (parent_ud->usb_hs_hub_bandwidth[i] < min) { 23347c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[i]; 23357c478bd9Sstevel@tonic-gate } 23367c478bd9Sstevel@tonic-gate } 23377c478bd9Sstevel@tonic-gate 23387c478bd9Sstevel@tonic-gate /* Save the minimum for later use */ 23397c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_min_bandwidth = min; 23407c478bd9Sstevel@tonic-gate 23417c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 23427c478bd9Sstevel@tonic-gate 23437c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 23447c478bd9Sstevel@tonic-gate } 23457c478bd9Sstevel@tonic-gate 23467c478bd9Sstevel@tonic-gate 23477c478bd9Sstevel@tonic-gate /* 23487c478bd9Sstevel@tonic-gate * ehci_deallocate_bandwidth: 23497c478bd9Sstevel@tonic-gate * 23507c478bd9Sstevel@tonic-gate * Deallocate bandwidth for the given node in the lattice and the length 23517c478bd9Sstevel@tonic-gate * of transfer. 23527c478bd9Sstevel@tonic-gate */ 23537c478bd9Sstevel@tonic-gate void 23547c478bd9Sstevel@tonic-gate ehci_deallocate_bandwidth( 23557c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 23567c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 23577c478bd9Sstevel@tonic-gate uint_t pnode, 23587c478bd9Sstevel@tonic-gate uchar_t smask, 23597c478bd9Sstevel@tonic-gate uchar_t cmask) 23607c478bd9Sstevel@tonic-gate { 23617c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 23627c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 23637c478bd9Sstevel@tonic-gate 23647c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth(ehcip, ph, pnode, smask, cmask); 23657c478bd9Sstevel@tonic-gate 23667c478bd9Sstevel@tonic-gate /* 23677c478bd9Sstevel@tonic-gate * For low/full speed usb devices, deallocate classic TT bandwidth 23687c478bd9Sstevel@tonic-gate * in additional to high speed bandwidth. 23697c478bd9Sstevel@tonic-gate */ 23707c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) { 23717c478bd9Sstevel@tonic-gate 23727c478bd9Sstevel@tonic-gate /* Deallocate classic TT bandwidth */ 23737c478bd9Sstevel@tonic-gate ehci_deallocate_classic_tt_bandwidth(ehcip, ph, pnode); 23747c478bd9Sstevel@tonic-gate } 23757c478bd9Sstevel@tonic-gate } 23767c478bd9Sstevel@tonic-gate 23777c478bd9Sstevel@tonic-gate 23787c478bd9Sstevel@tonic-gate /* 23797c478bd9Sstevel@tonic-gate * ehci_deallocate_high_speed_bandwidth: 23807c478bd9Sstevel@tonic-gate * 23817c478bd9Sstevel@tonic-gate * Deallocate high speed bandwidth of a interrupt or isochronous endpoint. 23827c478bd9Sstevel@tonic-gate */ 23837c478bd9Sstevel@tonic-gate static void 23847c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth( 23857c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 23867c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 23877c478bd9Sstevel@tonic-gate uint_t pnode, 23887c478bd9Sstevel@tonic-gate uchar_t smask, 23897c478bd9Sstevel@tonic-gate uchar_t cmask) 23907c478bd9Sstevel@tonic-gate { 23917c478bd9Sstevel@tonic-gate uint_t height, leftmost; 23927c478bd9Sstevel@tonic-gate uint_t list_count; 23937c478bd9Sstevel@tonic-gate uint_t sbandwidth, cbandwidth; 23947c478bd9Sstevel@tonic-gate int interval; 23957c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 23967c478bd9Sstevel@tonic-gate usba_device_t *child_ud; 23977c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 23987c478bd9Sstevel@tonic-gate 23997c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 24007c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 24017c478bd9Sstevel@tonic-gate 24027c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 24037c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 24047c478bd9Sstevel@tonic-gate 24057c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 24067c478bd9Sstevel@tonic-gate 24077c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 24087c478bd9Sstevel@tonic-gate port_status = ph->p_usba_device->usb_port_status; 24097c478bd9Sstevel@tonic-gate 24107c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 24117c478bd9Sstevel@tonic-gate 24127c478bd9Sstevel@tonic-gate (void) ehci_compute_high_speed_bandwidth(ehcip, endpoint, 24137c478bd9Sstevel@tonic-gate port_status, &sbandwidth, &cbandwidth); 24147c478bd9Sstevel@tonic-gate 24157c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 24167c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 24177c478bd9Sstevel@tonic-gate 24187c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 24197c478bd9Sstevel@tonic-gate height = ehci_lattice_height(interval); 24207c478bd9Sstevel@tonic-gate 24217c478bd9Sstevel@tonic-gate /* 24227c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node 24237c478bd9Sstevel@tonic-gate */ 24247c478bd9Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height); 24257c478bd9Sstevel@tonic-gate 24267c478bd9Sstevel@tonic-gate list_count = EHCI_NUM_INTR_QH_LISTS/interval; 24277c478bd9Sstevel@tonic-gate 24287c478bd9Sstevel@tonic-gate /* Delete the bandwidth from the appropriate lists */ 24297c478bd9Sstevel@tonic-gate if (port_status == USBA_HIGH_SPEED_DEV) { 24307c478bd9Sstevel@tonic-gate 24317c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth, 24327c478bd9Sstevel@tonic-gate leftmost, list_count, smask); 24337c478bd9Sstevel@tonic-gate } else { 24347c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) == 24357c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR) { 24367c478bd9Sstevel@tonic-gate 24377c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth, 24387c478bd9Sstevel@tonic-gate leftmost, list_count, smask); 24397c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -cbandwidth, 24407c478bd9Sstevel@tonic-gate leftmost, list_count, cmask); 24417c478bd9Sstevel@tonic-gate } else { 24427c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 24437c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 24447c478bd9Sstevel@tonic-gate 24457c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth, 24467c478bd9Sstevel@tonic-gate leftmost, list_count, smask); 24477c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, 24487c478bd9Sstevel@tonic-gate -MAX_UFRAME_SITD_XFER, leftmost, 24497c478bd9Sstevel@tonic-gate list_count, cmask); 24507c478bd9Sstevel@tonic-gate } else { 24517c478bd9Sstevel@tonic-gate 24527c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, 24537c478bd9Sstevel@tonic-gate -MAX_UFRAME_SITD_XFER, leftmost, 24547c478bd9Sstevel@tonic-gate list_count, smask); 24557c478bd9Sstevel@tonic-gate } 24567c478bd9Sstevel@tonic-gate } 24577c478bd9Sstevel@tonic-gate } 24587c478bd9Sstevel@tonic-gate } 24597c478bd9Sstevel@tonic-gate 24607c478bd9Sstevel@tonic-gate /* 24617c478bd9Sstevel@tonic-gate * ehci_deallocate_classic_tt_bandwidth: 24627c478bd9Sstevel@tonic-gate * 24637c478bd9Sstevel@tonic-gate * Deallocate high speed bandwidth of a interrupt or isochronous endpoint. 24647c478bd9Sstevel@tonic-gate */ 24657c478bd9Sstevel@tonic-gate static void 24667c478bd9Sstevel@tonic-gate ehci_deallocate_classic_tt_bandwidth( 24677c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 24687c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 24697c478bd9Sstevel@tonic-gate uint_t pnode) 24707c478bd9Sstevel@tonic-gate { 24717c478bd9Sstevel@tonic-gate uint_t bandwidth, height, leftmost, list, min; 24727c478bd9Sstevel@tonic-gate int i, interval; 24737c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 24747c478bd9Sstevel@tonic-gate usba_device_t *child_ud, *parent_ud; 24757c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 24767c478bd9Sstevel@tonic-gate 24777c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 24787c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 24797c478bd9Sstevel@tonic-gate 24807c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 24817c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 24827c478bd9Sstevel@tonic-gate 24837c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 24847c478bd9Sstevel@tonic-gate 24857c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 24867c478bd9Sstevel@tonic-gate port_status = child_ud->usb_port_status; 24877c478bd9Sstevel@tonic-gate 24887c478bd9Sstevel@tonic-gate /* Get the parent high speed hub's usba device structure */ 24897c478bd9Sstevel@tonic-gate parent_ud = child_ud->usb_hs_hub_usba_dev; 24907c478bd9Sstevel@tonic-gate 24917c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 24927c478bd9Sstevel@tonic-gate 24937c478bd9Sstevel@tonic-gate /* Obtain the bandwidth */ 24947c478bd9Sstevel@tonic-gate (void) ehci_compute_classic_bandwidth(endpoint, 24957c478bd9Sstevel@tonic-gate port_status, &bandwidth); 24967c478bd9Sstevel@tonic-gate 24977c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 24987c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 24997c478bd9Sstevel@tonic-gate 25007c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 25017c478bd9Sstevel@tonic-gate height = ehci_lattice_height(interval); 25027c478bd9Sstevel@tonic-gate 25037c478bd9Sstevel@tonic-gate /* Find the leftmost leaf in the subtree specified by the node */ 25047c478bd9Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height); 25057c478bd9Sstevel@tonic-gate 25067c478bd9Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex); 25077c478bd9Sstevel@tonic-gate 25087c478bd9Sstevel@tonic-gate /* Delete the bandwidth from the appropriate lists */ 25097c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) { 25107c478bd9Sstevel@tonic-gate list = ehci_index[leftmost + i]; 25117c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_bandwidth[list] -= bandwidth; 25127c478bd9Sstevel@tonic-gate } 25137c478bd9Sstevel@tonic-gate 25147c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */ 25157c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[0]; 25167c478bd9Sstevel@tonic-gate 25177c478bd9Sstevel@tonic-gate for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) { 25187c478bd9Sstevel@tonic-gate if (parent_ud->usb_hs_hub_bandwidth[i] < min) { 25197c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[i]; 25207c478bd9Sstevel@tonic-gate } 25217c478bd9Sstevel@tonic-gate } 25227c478bd9Sstevel@tonic-gate 25237c478bd9Sstevel@tonic-gate /* Save the minimum for later use */ 25247c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_min_bandwidth = min; 25257c478bd9Sstevel@tonic-gate 25267c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 25277c478bd9Sstevel@tonic-gate } 25287c478bd9Sstevel@tonic-gate 25297c478bd9Sstevel@tonic-gate 25307c478bd9Sstevel@tonic-gate /* 25317c478bd9Sstevel@tonic-gate * ehci_compute_high_speed_bandwidth: 25327c478bd9Sstevel@tonic-gate * 25337c478bd9Sstevel@tonic-gate * Given a periodic endpoint (interrupt or isochronous) determine the total 25347c478bd9Sstevel@tonic-gate * bandwidth for one transaction. The EHCI host controller traverses the 25357c478bd9Sstevel@tonic-gate * endpoint descriptor lists on a first-come-first-serve basis. When the HC 25367c478bd9Sstevel@tonic-gate * services an endpoint, only a single transaction attempt is made. The HC 25377c478bd9Sstevel@tonic-gate * moves to the next Endpoint Descriptor after the first transaction attempt 25387c478bd9Sstevel@tonic-gate * rather than finishing the entire Transfer Descriptor. Therefore, when a 25397c478bd9Sstevel@tonic-gate * Transfer Descriptor is inserted into the lattice, we will only count the 25407c478bd9Sstevel@tonic-gate * number of bytes for one transaction. 25417c478bd9Sstevel@tonic-gate * 25427c478bd9Sstevel@tonic-gate * The following are the formulas used for calculating bandwidth in terms 25437c478bd9Sstevel@tonic-gate * bytes and it is for the single USB high speed transaction. The protocol 25447c478bd9Sstevel@tonic-gate * overheads will be different for each of type of USB transfer & all these 25457c478bd9Sstevel@tonic-gate * formulas & protocol overheads are derived from the 5.11.3 section of the 25467c478bd9Sstevel@tonic-gate * USB 2.0 Specification. 25477c478bd9Sstevel@tonic-gate * 25487c478bd9Sstevel@tonic-gate * High-Speed: 25497c478bd9Sstevel@tonic-gate * Protocol overhead + ((MaxPktSz * 7)/6) + Host_Delay 25507c478bd9Sstevel@tonic-gate * 25517c478bd9Sstevel@tonic-gate * Split Transaction: (Low/Full speed devices connected behind usb2.0 hub) 25527c478bd9Sstevel@tonic-gate * 25537c478bd9Sstevel@tonic-gate * Protocol overhead + Split transaction overhead + 25547c478bd9Sstevel@tonic-gate * ((MaxPktSz * 7)/6) + Host_Delay; 25557c478bd9Sstevel@tonic-gate */ 25567c478bd9Sstevel@tonic-gate /* ARGSUSED */ 25577c478bd9Sstevel@tonic-gate static int 25587c478bd9Sstevel@tonic-gate ehci_compute_high_speed_bandwidth( 25597c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 25607c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 25617c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 25627c478bd9Sstevel@tonic-gate uint_t *sbandwidth, 25637c478bd9Sstevel@tonic-gate uint_t *cbandwidth) 25647c478bd9Sstevel@tonic-gate { 25657c478bd9Sstevel@tonic-gate ushort_t maxpacketsize = endpoint->wMaxPacketSize; 25667c478bd9Sstevel@tonic-gate 25677c478bd9Sstevel@tonic-gate /* Return failure if endpoint maximum packet is zero */ 25687c478bd9Sstevel@tonic-gate if (maxpacketsize == 0) { 25697c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 25707c478bd9Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: Periodic endpoint " 25717c478bd9Sstevel@tonic-gate "with zero endpoint maximum packet size is not supported"); 25727c478bd9Sstevel@tonic-gate 25737c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 25747c478bd9Sstevel@tonic-gate } 25757c478bd9Sstevel@tonic-gate 25767c478bd9Sstevel@tonic-gate /* Add bit-stuffing overhead */ 25777c478bd9Sstevel@tonic-gate maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6); 25787c478bd9Sstevel@tonic-gate 25797c478bd9Sstevel@tonic-gate /* Add Host Controller specific delay to required bandwidth */ 25807c478bd9Sstevel@tonic-gate *sbandwidth = EHCI_HOST_CONTROLLER_DELAY; 25817c478bd9Sstevel@tonic-gate 25827c478bd9Sstevel@tonic-gate /* Add xfer specific protocol overheads */ 25837c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 25847c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) { 25857c478bd9Sstevel@tonic-gate /* High speed interrupt transaction */ 25867c478bd9Sstevel@tonic-gate *sbandwidth += HS_NON_ISOC_PROTO_OVERHEAD; 25877c478bd9Sstevel@tonic-gate } else { 25887c478bd9Sstevel@tonic-gate /* Isochronous transaction */ 25897c478bd9Sstevel@tonic-gate *sbandwidth += HS_ISOC_PROTO_OVERHEAD; 25907c478bd9Sstevel@tonic-gate } 25917c478bd9Sstevel@tonic-gate 25927c478bd9Sstevel@tonic-gate /* 25937c478bd9Sstevel@tonic-gate * For low/full speed devices, add split transaction specific 25947c478bd9Sstevel@tonic-gate * overheads. 25957c478bd9Sstevel@tonic-gate */ 25967c478bd9Sstevel@tonic-gate if (port_status != USBA_HIGH_SPEED_DEV) { 25977c478bd9Sstevel@tonic-gate /* 25987c478bd9Sstevel@tonic-gate * Add start and complete split transaction 25997c478bd9Sstevel@tonic-gate * tokens overheads. 26007c478bd9Sstevel@tonic-gate */ 26017c478bd9Sstevel@tonic-gate *cbandwidth = *sbandwidth + COMPLETE_SPLIT_OVERHEAD; 26027c478bd9Sstevel@tonic-gate *sbandwidth += START_SPLIT_OVERHEAD; 26037c478bd9Sstevel@tonic-gate 26047c478bd9Sstevel@tonic-gate /* Add data overhead depending on data direction */ 26057c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 26067c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 26077c478bd9Sstevel@tonic-gate *cbandwidth += maxpacketsize; 26087c478bd9Sstevel@tonic-gate } else { 26097c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 26107c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) { 26117c478bd9Sstevel@tonic-gate /* There is no compete splits for out */ 26127c478bd9Sstevel@tonic-gate *cbandwidth = 0; 26137c478bd9Sstevel@tonic-gate } 26147c478bd9Sstevel@tonic-gate *sbandwidth += maxpacketsize; 26157c478bd9Sstevel@tonic-gate } 26167c478bd9Sstevel@tonic-gate } else { 26177c478bd9Sstevel@tonic-gate uint_t xactions; 26187c478bd9Sstevel@tonic-gate 26197c478bd9Sstevel@tonic-gate /* Get the max transactions per microframe */ 26207c478bd9Sstevel@tonic-gate xactions = ((maxpacketsize & USB_EP_MAX_XACTS_MASK) >> 26217c478bd9Sstevel@tonic-gate USB_EP_MAX_XACTS_SHIFT) + 1; 26227c478bd9Sstevel@tonic-gate 26237c478bd9Sstevel@tonic-gate /* High speed transaction */ 26247c478bd9Sstevel@tonic-gate *sbandwidth += maxpacketsize; 26257c478bd9Sstevel@tonic-gate 26267c478bd9Sstevel@tonic-gate /* Calculate bandwidth per micro-frame */ 26277c478bd9Sstevel@tonic-gate *sbandwidth *= xactions; 26287c478bd9Sstevel@tonic-gate 26297c478bd9Sstevel@tonic-gate *cbandwidth = 0; 26307c478bd9Sstevel@tonic-gate } 26317c478bd9Sstevel@tonic-gate 26327c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 26337c478bd9Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: " 26347c478bd9Sstevel@tonic-gate "Start split bandwidth %d Complete split bandwidth %d", 26357c478bd9Sstevel@tonic-gate *sbandwidth, *cbandwidth); 26367c478bd9Sstevel@tonic-gate 26377c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 26387c478bd9Sstevel@tonic-gate } 26397c478bd9Sstevel@tonic-gate 26407c478bd9Sstevel@tonic-gate 26417c478bd9Sstevel@tonic-gate /* 26427c478bd9Sstevel@tonic-gate * ehci_compute_classic_bandwidth: 26437c478bd9Sstevel@tonic-gate * 26447c478bd9Sstevel@tonic-gate * Given a periodic endpoint (interrupt or isochronous) determine the total 26457c478bd9Sstevel@tonic-gate * bandwidth for one transaction. The EHCI host controller traverses the 26467c478bd9Sstevel@tonic-gate * endpoint descriptor lists on a first-come-first-serve basis. When the HC 26477c478bd9Sstevel@tonic-gate * services an endpoint, only a single transaction attempt is made. The HC 26487c478bd9Sstevel@tonic-gate * moves to the next Endpoint Descriptor after the first transaction attempt 26497c478bd9Sstevel@tonic-gate * rather than finishing the entire Transfer Descriptor. Therefore, when a 26507c478bd9Sstevel@tonic-gate * Transfer Descriptor is inserted into the lattice, we will only count the 26517c478bd9Sstevel@tonic-gate * number of bytes for one transaction. 26527c478bd9Sstevel@tonic-gate * 26537c478bd9Sstevel@tonic-gate * The following are the formulas used for calculating bandwidth in terms 26547c478bd9Sstevel@tonic-gate * bytes and it is for the single USB high speed transaction. The protocol 26557c478bd9Sstevel@tonic-gate * overheads will be different for each of type of USB transfer & all these 26567c478bd9Sstevel@tonic-gate * formulas & protocol overheads are derived from the 5.11.3 section of the 26577c478bd9Sstevel@tonic-gate * USB 2.0 Specification. 26587c478bd9Sstevel@tonic-gate * 26597c478bd9Sstevel@tonic-gate * Low-Speed: 26607c478bd9Sstevel@tonic-gate * Protocol overhead + Hub LS overhead + 26617c478bd9Sstevel@tonic-gate * (Low Speed clock * ((MaxPktSz * 7)/6)) + TT_Delay 26627c478bd9Sstevel@tonic-gate * 26637c478bd9Sstevel@tonic-gate * Full-Speed: 26647c478bd9Sstevel@tonic-gate * Protocol overhead + ((MaxPktSz * 7)/6) + TT_Delay 26657c478bd9Sstevel@tonic-gate */ 26667c478bd9Sstevel@tonic-gate /* ARGSUSED */ 26677c478bd9Sstevel@tonic-gate static int 26687c478bd9Sstevel@tonic-gate ehci_compute_classic_bandwidth( 26697c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 26707c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 26717c478bd9Sstevel@tonic-gate uint_t *bandwidth) 26727c478bd9Sstevel@tonic-gate { 26737c478bd9Sstevel@tonic-gate ushort_t maxpacketsize = endpoint->wMaxPacketSize; 26747c478bd9Sstevel@tonic-gate 26757c478bd9Sstevel@tonic-gate /* 26767c478bd9Sstevel@tonic-gate * If endpoint maximum packet is zero, then return immediately. 26777c478bd9Sstevel@tonic-gate */ 26787c478bd9Sstevel@tonic-gate if (maxpacketsize == 0) { 26797c478bd9Sstevel@tonic-gate 26807c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 26817c478bd9Sstevel@tonic-gate } 26827c478bd9Sstevel@tonic-gate 26837c478bd9Sstevel@tonic-gate /* Add TT delay to required bandwidth */ 26847c478bd9Sstevel@tonic-gate *bandwidth = TT_DELAY; 26857c478bd9Sstevel@tonic-gate 26867c478bd9Sstevel@tonic-gate /* Add bit-stuffing overhead */ 26877c478bd9Sstevel@tonic-gate maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6); 26887c478bd9Sstevel@tonic-gate 26897c478bd9Sstevel@tonic-gate switch (port_status) { 26907c478bd9Sstevel@tonic-gate case USBA_LOW_SPEED_DEV: 26917c478bd9Sstevel@tonic-gate /* Low speed interrupt transaction */ 26927c478bd9Sstevel@tonic-gate *bandwidth += (LOW_SPEED_PROTO_OVERHEAD + 26937c478bd9Sstevel@tonic-gate HUB_LOW_SPEED_PROTO_OVERHEAD + 26947c478bd9Sstevel@tonic-gate (LOW_SPEED_CLOCK * maxpacketsize)); 26957c478bd9Sstevel@tonic-gate break; 26967c478bd9Sstevel@tonic-gate case USBA_FULL_SPEED_DEV: 26977c478bd9Sstevel@tonic-gate /* Full speed transaction */ 26987c478bd9Sstevel@tonic-gate *bandwidth += maxpacketsize; 26997c478bd9Sstevel@tonic-gate 27007c478bd9Sstevel@tonic-gate /* Add xfer specific protocol overheads */ 27017c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 27027c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) { 27037c478bd9Sstevel@tonic-gate /* Full speed interrupt transaction */ 27047c478bd9Sstevel@tonic-gate *bandwidth += FS_NON_ISOC_PROTO_OVERHEAD; 27057c478bd9Sstevel@tonic-gate } else { 27067c478bd9Sstevel@tonic-gate /* Isochronous and input transaction */ 27077c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 27087c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 27097c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_INPUT_PROTO_OVERHEAD; 27107c478bd9Sstevel@tonic-gate } else { 27117c478bd9Sstevel@tonic-gate /* Isochronous and output transaction */ 27127c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_OUTPUT_PROTO_OVERHEAD; 27137c478bd9Sstevel@tonic-gate } 27147c478bd9Sstevel@tonic-gate } 27157c478bd9Sstevel@tonic-gate break; 27167c478bd9Sstevel@tonic-gate } 27177c478bd9Sstevel@tonic-gate 27187c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 27197c478bd9Sstevel@tonic-gate } 27207c478bd9Sstevel@tonic-gate 27217c478bd9Sstevel@tonic-gate 27227c478bd9Sstevel@tonic-gate /* 27237c478bd9Sstevel@tonic-gate * ehci_adjust_polling_interval: 27247c478bd9Sstevel@tonic-gate * 27257c478bd9Sstevel@tonic-gate * Adjust bandwidth according usb device speed. 27267c478bd9Sstevel@tonic-gate */ 27277c478bd9Sstevel@tonic-gate /* ARGSUSED */ 27287c478bd9Sstevel@tonic-gate int 27297c478bd9Sstevel@tonic-gate ehci_adjust_polling_interval( 27307c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 27317c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 27327c478bd9Sstevel@tonic-gate usb_port_status_t port_status) 27337c478bd9Sstevel@tonic-gate { 27347c478bd9Sstevel@tonic-gate uint_t interval; 27357c478bd9Sstevel@tonic-gate int i = 0; 27367c478bd9Sstevel@tonic-gate 27377c478bd9Sstevel@tonic-gate /* Get the polling interval */ 27387c478bd9Sstevel@tonic-gate interval = endpoint->bInterval; 27397c478bd9Sstevel@tonic-gate 27407c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 27417c478bd9Sstevel@tonic-gate "ehci_adjust_polling_interval: Polling interval 0x%x", interval); 27427c478bd9Sstevel@tonic-gate 27437c478bd9Sstevel@tonic-gate /* 27447c478bd9Sstevel@tonic-gate * According USB 2.0 Specifications, a high-speed endpoint's 27457c478bd9Sstevel@tonic-gate * polling intervals are specified interms of 125us or micro 27467c478bd9Sstevel@tonic-gate * frame, where as full/low endpoint's polling intervals are 27477c478bd9Sstevel@tonic-gate * specified in milliseconds. 27487c478bd9Sstevel@tonic-gate * 27497c478bd9Sstevel@tonic-gate * A high speed interrupt/isochronous endpoints can specify 27507c478bd9Sstevel@tonic-gate * desired polling interval between 1 to 16 micro-frames, 27517c478bd9Sstevel@tonic-gate * where as full/low endpoints can specify between 1 to 255 27527c478bd9Sstevel@tonic-gate * milliseconds. 27537c478bd9Sstevel@tonic-gate */ 27547c478bd9Sstevel@tonic-gate switch (port_status) { 27557c478bd9Sstevel@tonic-gate case USBA_LOW_SPEED_DEV: 27567c478bd9Sstevel@tonic-gate /* 27577c478bd9Sstevel@tonic-gate * Low speed endpoints are limited to specifying 27587c478bd9Sstevel@tonic-gate * only 8ms to 255ms in this driver. If a device 27597c478bd9Sstevel@tonic-gate * reports a polling interval that is less than 8ms, 27607c478bd9Sstevel@tonic-gate * it will use 8 ms instead. 27617c478bd9Sstevel@tonic-gate */ 27627c478bd9Sstevel@tonic-gate if (interval < LS_MIN_POLL_INTERVAL) { 27637c478bd9Sstevel@tonic-gate 27647c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 27657c478bd9Sstevel@tonic-gate "Low speed endpoint's poll interval of %d ms " 27667c478bd9Sstevel@tonic-gate "is below threshold. Rounding up to %d ms", 27677c478bd9Sstevel@tonic-gate interval, LS_MIN_POLL_INTERVAL); 27687c478bd9Sstevel@tonic-gate 27697c478bd9Sstevel@tonic-gate interval = LS_MIN_POLL_INTERVAL; 27707c478bd9Sstevel@tonic-gate } 27717c478bd9Sstevel@tonic-gate 27727c478bd9Sstevel@tonic-gate /* 27737c478bd9Sstevel@tonic-gate * Return an error if the polling interval is greater 27747c478bd9Sstevel@tonic-gate * than 255ms. 27757c478bd9Sstevel@tonic-gate */ 27767c478bd9Sstevel@tonic-gate if (interval > LS_MAX_POLL_INTERVAL) { 27777c478bd9Sstevel@tonic-gate 27787c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 27797c478bd9Sstevel@tonic-gate "Low speed endpoint's poll interval is " 27807c478bd9Sstevel@tonic-gate "greater than %d ms", LS_MAX_POLL_INTERVAL); 27817c478bd9Sstevel@tonic-gate 27827c478bd9Sstevel@tonic-gate return (USB_FAILURE); 27837c478bd9Sstevel@tonic-gate } 27847c478bd9Sstevel@tonic-gate break; 27857c478bd9Sstevel@tonic-gate 27867c478bd9Sstevel@tonic-gate case USBA_FULL_SPEED_DEV: 27877c478bd9Sstevel@tonic-gate /* 27887c478bd9Sstevel@tonic-gate * Return an error if the polling interval is less 27897c478bd9Sstevel@tonic-gate * than 1ms and greater than 255ms. 27907c478bd9Sstevel@tonic-gate */ 27917c478bd9Sstevel@tonic-gate if ((interval < FS_MIN_POLL_INTERVAL) && 27927c478bd9Sstevel@tonic-gate (interval > FS_MAX_POLL_INTERVAL)) { 27937c478bd9Sstevel@tonic-gate 27947c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 27957c478bd9Sstevel@tonic-gate "Full speed endpoint's poll interval must " 27967c478bd9Sstevel@tonic-gate "be between %d and %d ms", FS_MIN_POLL_INTERVAL, 27977c478bd9Sstevel@tonic-gate FS_MAX_POLL_INTERVAL); 27987c478bd9Sstevel@tonic-gate 27997c478bd9Sstevel@tonic-gate return (USB_FAILURE); 28007c478bd9Sstevel@tonic-gate } 28017c478bd9Sstevel@tonic-gate break; 28027c478bd9Sstevel@tonic-gate case USBA_HIGH_SPEED_DEV: 28037c478bd9Sstevel@tonic-gate /* 28047c478bd9Sstevel@tonic-gate * Return an error if the polling interval is less 1 28057c478bd9Sstevel@tonic-gate * and greater than 16. Convert this value to 125us 28067c478bd9Sstevel@tonic-gate * units using 2^(bInterval -1). refer usb 2.0 spec 28077c478bd9Sstevel@tonic-gate * page 51 for details. 28087c478bd9Sstevel@tonic-gate */ 28097c478bd9Sstevel@tonic-gate if ((interval < HS_MIN_POLL_INTERVAL) && 28107c478bd9Sstevel@tonic-gate (interval > HS_MAX_POLL_INTERVAL)) { 28117c478bd9Sstevel@tonic-gate 28127c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 28137c478bd9Sstevel@tonic-gate "High speed endpoint's poll interval " 28147c478bd9Sstevel@tonic-gate "must be between %d and %d units", 28157c478bd9Sstevel@tonic-gate HS_MIN_POLL_INTERVAL, HS_MAX_POLL_INTERVAL); 28167c478bd9Sstevel@tonic-gate 28177c478bd9Sstevel@tonic-gate return (USB_FAILURE); 28187c478bd9Sstevel@tonic-gate } 28197c478bd9Sstevel@tonic-gate 28207c478bd9Sstevel@tonic-gate /* Adjust high speed device polling interval */ 28217c478bd9Sstevel@tonic-gate interval = 28227c478bd9Sstevel@tonic-gate ehci_adjust_high_speed_polling_interval(ehcip, endpoint); 28237c478bd9Sstevel@tonic-gate 28247c478bd9Sstevel@tonic-gate break; 28257c478bd9Sstevel@tonic-gate } 28267c478bd9Sstevel@tonic-gate 28277c478bd9Sstevel@tonic-gate /* 28287c478bd9Sstevel@tonic-gate * If polling interval is greater than 32ms, 28297c478bd9Sstevel@tonic-gate * adjust polling interval equal to 32ms. 28307c478bd9Sstevel@tonic-gate */ 28317c478bd9Sstevel@tonic-gate if (interval > EHCI_NUM_INTR_QH_LISTS) { 28327c478bd9Sstevel@tonic-gate interval = EHCI_NUM_INTR_QH_LISTS; 28337c478bd9Sstevel@tonic-gate } 28347c478bd9Sstevel@tonic-gate 28357c478bd9Sstevel@tonic-gate /* 28367c478bd9Sstevel@tonic-gate * Find the nearest power of 2 that's less 28377c478bd9Sstevel@tonic-gate * than interval. 28387c478bd9Sstevel@tonic-gate */ 28397c478bd9Sstevel@tonic-gate while ((ehci_pow_2(i)) <= interval) { 28407c478bd9Sstevel@tonic-gate i++; 28417c478bd9Sstevel@tonic-gate } 28427c478bd9Sstevel@tonic-gate 28437c478bd9Sstevel@tonic-gate return (ehci_pow_2((i - 1))); 28447c478bd9Sstevel@tonic-gate } 28457c478bd9Sstevel@tonic-gate 28467c478bd9Sstevel@tonic-gate 28477c478bd9Sstevel@tonic-gate /* 28487c478bd9Sstevel@tonic-gate * ehci_adjust_high_speed_polling_interval: 28497c478bd9Sstevel@tonic-gate */ 28507c478bd9Sstevel@tonic-gate /* ARGSUSED */ 28517c478bd9Sstevel@tonic-gate static int 28527c478bd9Sstevel@tonic-gate ehci_adjust_high_speed_polling_interval( 28537c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 28547c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint) 28557c478bd9Sstevel@tonic-gate { 28567c478bd9Sstevel@tonic-gate uint_t interval; 28577c478bd9Sstevel@tonic-gate 28587c478bd9Sstevel@tonic-gate /* Get the polling interval */ 28597c478bd9Sstevel@tonic-gate interval = ehci_pow_2(endpoint->bInterval - 1); 28607c478bd9Sstevel@tonic-gate 28617c478bd9Sstevel@tonic-gate /* 28627c478bd9Sstevel@tonic-gate * Convert polling interval from micro seconds 28637c478bd9Sstevel@tonic-gate * to milli seconds. 28647c478bd9Sstevel@tonic-gate */ 28657c478bd9Sstevel@tonic-gate if (interval <= EHCI_MAX_UFRAMES) { 28667c478bd9Sstevel@tonic-gate interval = 1; 28677c478bd9Sstevel@tonic-gate } else { 28687c478bd9Sstevel@tonic-gate interval = interval/EHCI_MAX_UFRAMES; 28697c478bd9Sstevel@tonic-gate } 28707c478bd9Sstevel@tonic-gate 28717c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 28727c478bd9Sstevel@tonic-gate "ehci_adjust_high_speed_polling_interval: " 28737c478bd9Sstevel@tonic-gate "High speed adjusted interval 0x%x", interval); 28747c478bd9Sstevel@tonic-gate 28757c478bd9Sstevel@tonic-gate return (interval); 28767c478bd9Sstevel@tonic-gate } 28777c478bd9Sstevel@tonic-gate 28787c478bd9Sstevel@tonic-gate 28797c478bd9Sstevel@tonic-gate /* 28807c478bd9Sstevel@tonic-gate * ehci_lattice_height: 28817c478bd9Sstevel@tonic-gate * 28827c478bd9Sstevel@tonic-gate * Given the requested bandwidth, find the height in the tree at which the 28837c478bd9Sstevel@tonic-gate * nodes for this bandwidth fall. The height is measured as the number of 28847c478bd9Sstevel@tonic-gate * nodes from the leaf to the level specified by bandwidth The root of the 28857c478bd9Sstevel@tonic-gate * tree is at height TREE_HEIGHT. 28867c478bd9Sstevel@tonic-gate */ 28877c478bd9Sstevel@tonic-gate static uint_t 28887c478bd9Sstevel@tonic-gate ehci_lattice_height(uint_t interval) 28897c478bd9Sstevel@tonic-gate { 28907c478bd9Sstevel@tonic-gate return (TREE_HEIGHT - (ehci_log_2(interval))); 28917c478bd9Sstevel@tonic-gate } 28927c478bd9Sstevel@tonic-gate 28937c478bd9Sstevel@tonic-gate 28947c478bd9Sstevel@tonic-gate /* 28957c478bd9Sstevel@tonic-gate * ehci_lattice_parent: 28967c478bd9Sstevel@tonic-gate * 28977c478bd9Sstevel@tonic-gate * Given a node in the lattice, find the index of the parent node 28987c478bd9Sstevel@tonic-gate */ 28997c478bd9Sstevel@tonic-gate static uint_t 29007c478bd9Sstevel@tonic-gate ehci_lattice_parent(uint_t node) 29017c478bd9Sstevel@tonic-gate { 29027c478bd9Sstevel@tonic-gate if ((node % 2) == 0) { 29037c478bd9Sstevel@tonic-gate 29047c478bd9Sstevel@tonic-gate return ((node/2) - 1); 29057c478bd9Sstevel@tonic-gate } else { 29067c478bd9Sstevel@tonic-gate 29077c478bd9Sstevel@tonic-gate return ((node + 1)/2 - 1); 29087c478bd9Sstevel@tonic-gate } 29097c478bd9Sstevel@tonic-gate } 29107c478bd9Sstevel@tonic-gate 29117c478bd9Sstevel@tonic-gate 29127c478bd9Sstevel@tonic-gate /* 29137c478bd9Sstevel@tonic-gate * ehci_find_periodic_node: 29147c478bd9Sstevel@tonic-gate * 29157c478bd9Sstevel@tonic-gate * Based on the "real" array leaf node and interval, get the periodic node. 29167c478bd9Sstevel@tonic-gate */ 29177c478bd9Sstevel@tonic-gate static uint_t 29187c478bd9Sstevel@tonic-gate ehci_find_periodic_node(uint_t leaf, int interval) { 29197c478bd9Sstevel@tonic-gate uint_t lattice_leaf; 29207c478bd9Sstevel@tonic-gate uint_t height = ehci_lattice_height(interval); 29217c478bd9Sstevel@tonic-gate uint_t pnode; 29227c478bd9Sstevel@tonic-gate int i; 29237c478bd9Sstevel@tonic-gate 29247c478bd9Sstevel@tonic-gate /* Get the leaf number in the lattice */ 29257c478bd9Sstevel@tonic-gate lattice_leaf = leaf + EHCI_NUM_INTR_QH_LISTS - 1; 29267c478bd9Sstevel@tonic-gate 29277c478bd9Sstevel@tonic-gate /* Get the node in the lattice based on the height and leaf */ 29287c478bd9Sstevel@tonic-gate pnode = lattice_leaf; 29297c478bd9Sstevel@tonic-gate for (i = 0; i < height; i++) { 29307c478bd9Sstevel@tonic-gate pnode = ehci_lattice_parent(pnode); 29317c478bd9Sstevel@tonic-gate } 29327c478bd9Sstevel@tonic-gate 29337c478bd9Sstevel@tonic-gate return (pnode); 29347c478bd9Sstevel@tonic-gate } 29357c478bd9Sstevel@tonic-gate 29367c478bd9Sstevel@tonic-gate 29377c478bd9Sstevel@tonic-gate /* 29387c478bd9Sstevel@tonic-gate * ehci_leftmost_leaf: 29397c478bd9Sstevel@tonic-gate * 29407c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node. Height refers 29417c478bd9Sstevel@tonic-gate * to number of nodes from the bottom of the tree to the node, including the 29427c478bd9Sstevel@tonic-gate * node. 29437c478bd9Sstevel@tonic-gate * 29447c478bd9Sstevel@tonic-gate * The formula for a zero based tree is: 29457c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1 29467c478bd9Sstevel@tonic-gate * The leaf of the tree is an array, convert the number for the array. 29477c478bd9Sstevel@tonic-gate * Subtract the size of nodes not in the array 29487c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1 - (EHCI_NUM_INTR_QH_LISTS - 1) = 29497c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - EHCI_NUM_INTR_QH_LISTS = 29507c478bd9Sstevel@tonic-gate * 2^H * (Node + 1) - EHCI_NUM_INTR_QH_LISTS 29517c478bd9Sstevel@tonic-gate * 0 29527c478bd9Sstevel@tonic-gate * 1 2 29537c478bd9Sstevel@tonic-gate * 0 1 2 3 29547c478bd9Sstevel@tonic-gate */ 29557c478bd9Sstevel@tonic-gate static uint_t 29567c478bd9Sstevel@tonic-gate ehci_leftmost_leaf( 29577c478bd9Sstevel@tonic-gate uint_t node, 29587c478bd9Sstevel@tonic-gate uint_t height) 29597c478bd9Sstevel@tonic-gate { 29607c478bd9Sstevel@tonic-gate return ((ehci_pow_2(height) * (node + 1)) - EHCI_NUM_INTR_QH_LISTS); 29617c478bd9Sstevel@tonic-gate } 29627c478bd9Sstevel@tonic-gate 29637c478bd9Sstevel@tonic-gate 29647c478bd9Sstevel@tonic-gate /* 29657c478bd9Sstevel@tonic-gate * ehci_pow_2: 29667c478bd9Sstevel@tonic-gate * 29677c478bd9Sstevel@tonic-gate * Compute 2 to the power 29687c478bd9Sstevel@tonic-gate */ 29697c478bd9Sstevel@tonic-gate static uint_t 29707c478bd9Sstevel@tonic-gate ehci_pow_2(uint_t x) 29717c478bd9Sstevel@tonic-gate { 29727c478bd9Sstevel@tonic-gate if (x == 0) { 29737c478bd9Sstevel@tonic-gate 29747c478bd9Sstevel@tonic-gate return (1); 29757c478bd9Sstevel@tonic-gate } else { 29767c478bd9Sstevel@tonic-gate 29777c478bd9Sstevel@tonic-gate return (2 << (x - 1)); 29787c478bd9Sstevel@tonic-gate } 29797c478bd9Sstevel@tonic-gate } 29807c478bd9Sstevel@tonic-gate 29817c478bd9Sstevel@tonic-gate 29827c478bd9Sstevel@tonic-gate /* 29837c478bd9Sstevel@tonic-gate * ehci_log_2: 29847c478bd9Sstevel@tonic-gate * 29857c478bd9Sstevel@tonic-gate * Compute log base 2 of x 29867c478bd9Sstevel@tonic-gate */ 29877c478bd9Sstevel@tonic-gate static uint_t 29887c478bd9Sstevel@tonic-gate ehci_log_2(uint_t x) 29897c478bd9Sstevel@tonic-gate { 29907c478bd9Sstevel@tonic-gate int i = 0; 29917c478bd9Sstevel@tonic-gate 29927c478bd9Sstevel@tonic-gate while (x != 1) { 29937c478bd9Sstevel@tonic-gate x = x >> 1; 29947c478bd9Sstevel@tonic-gate i++; 29957c478bd9Sstevel@tonic-gate } 29967c478bd9Sstevel@tonic-gate 29977c478bd9Sstevel@tonic-gate return (i); 29987c478bd9Sstevel@tonic-gate } 29997c478bd9Sstevel@tonic-gate 30007c478bd9Sstevel@tonic-gate 30017c478bd9Sstevel@tonic-gate /* 30027c478bd9Sstevel@tonic-gate * ehci_find_bestfit_hs_mask: 30037c478bd9Sstevel@tonic-gate * 30047c478bd9Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation, and update the 30057c478bd9Sstevel@tonic-gate * bandwidth allocation. 30067c478bd9Sstevel@tonic-gate */ 30077c478bd9Sstevel@tonic-gate static int 30087c478bd9Sstevel@tonic-gate ehci_find_bestfit_hs_mask( 30097c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 30107c478bd9Sstevel@tonic-gate uchar_t *smask, 30117c478bd9Sstevel@tonic-gate uint_t *pnode, 30127c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 30137c478bd9Sstevel@tonic-gate uint_t bandwidth, 30147c478bd9Sstevel@tonic-gate int interval) 30157c478bd9Sstevel@tonic-gate { 30167c478bd9Sstevel@tonic-gate int i; 30177c478bd9Sstevel@tonic-gate uint_t elements, index; 30187c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 30197c478bd9Sstevel@tonic-gate uint_t node_bandwidth, best_node_bandwidth; 30207c478bd9Sstevel@tonic-gate uint_t leaf_count; 30217c478bd9Sstevel@tonic-gate uchar_t bw_mask; 30227c478bd9Sstevel@tonic-gate uchar_t best_smask; 30237c478bd9Sstevel@tonic-gate 30247c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 30257c478bd9Sstevel@tonic-gate "ehci_find_bestfit_hs_mask: "); 30267c478bd9Sstevel@tonic-gate 30277c478bd9Sstevel@tonic-gate /* Get all the valid smasks */ 30287c478bd9Sstevel@tonic-gate switch (ehci_pow_2(endpoint->bInterval - 1)) { 30297c478bd9Sstevel@tonic-gate case EHCI_INTR_1US_POLL: 30307c478bd9Sstevel@tonic-gate index = EHCI_1US_MASK_INDEX; 30317c478bd9Sstevel@tonic-gate elements = EHCI_INTR_1US_POLL; 30327c478bd9Sstevel@tonic-gate break; 30337c478bd9Sstevel@tonic-gate case EHCI_INTR_2US_POLL: 30347c478bd9Sstevel@tonic-gate index = EHCI_2US_MASK_INDEX; 30357c478bd9Sstevel@tonic-gate elements = EHCI_INTR_2US_POLL; 30367c478bd9Sstevel@tonic-gate break; 30377c478bd9Sstevel@tonic-gate case EHCI_INTR_4US_POLL: 30387c478bd9Sstevel@tonic-gate index = EHCI_4US_MASK_INDEX; 30397c478bd9Sstevel@tonic-gate elements = EHCI_INTR_4US_POLL; 30407c478bd9Sstevel@tonic-gate break; 30417c478bd9Sstevel@tonic-gate case EHCI_INTR_XUS_POLL: 30427c478bd9Sstevel@tonic-gate default: 30437c478bd9Sstevel@tonic-gate index = EHCI_XUS_MASK_INDEX; 30447c478bd9Sstevel@tonic-gate elements = EHCI_INTR_XUS_POLL; 30457c478bd9Sstevel@tonic-gate break; 30467c478bd9Sstevel@tonic-gate } 30477c478bd9Sstevel@tonic-gate 30487c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 30497c478bd9Sstevel@tonic-gate 30507c478bd9Sstevel@tonic-gate /* 30517c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 30527c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 30537c478bd9Sstevel@tonic-gate */ 30547c478bd9Sstevel@tonic-gate best_smask = 0x00; 30557c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 30567c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 30577c478bd9Sstevel@tonic-gate /* Find the bandwidth mask */ 30587c478bd9Sstevel@tonic-gate node_bandwidth = ehci_calculate_bw_availability_mask(ehcip, 30597c478bd9Sstevel@tonic-gate bandwidth, ehci_index[array_leaf], leaf_count, &bw_mask); 30607c478bd9Sstevel@tonic-gate 30617c478bd9Sstevel@tonic-gate /* 30627c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 30637c478bd9Sstevel@tonic-gate * next leaf. 30647c478bd9Sstevel@tonic-gate */ 30657c478bd9Sstevel@tonic-gate if (bw_mask == 0x00) { 30667c478bd9Sstevel@tonic-gate continue; 30677c478bd9Sstevel@tonic-gate } 30687c478bd9Sstevel@tonic-gate 30697c478bd9Sstevel@tonic-gate /* 30707c478bd9Sstevel@tonic-gate * Now make sure our bandwidth requirements can be 30717c478bd9Sstevel@tonic-gate * satisfied with one of smasks in this node. 30727c478bd9Sstevel@tonic-gate */ 30737c478bd9Sstevel@tonic-gate *smask = 0x00; 30747c478bd9Sstevel@tonic-gate for (i = index; i < (index + elements); i++) { 30757c478bd9Sstevel@tonic-gate /* Check the start split mask value */ 30767c478bd9Sstevel@tonic-gate if (ehci_start_split_mask[index] & bw_mask) { 30777c478bd9Sstevel@tonic-gate *smask = ehci_start_split_mask[index]; 30787c478bd9Sstevel@tonic-gate break; 30797c478bd9Sstevel@tonic-gate } 30807c478bd9Sstevel@tonic-gate } 30817c478bd9Sstevel@tonic-gate 30827c478bd9Sstevel@tonic-gate /* 30837c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 30847c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 30857c478bd9Sstevel@tonic-gate * - or - 30867c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 30877c478bd9Sstevel@tonic-gate */ 30887c478bd9Sstevel@tonic-gate if ((*smask != 0x00) && 30897c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 30907c478bd9Sstevel@tonic-gate (best_node_bandwidth > node_bandwidth))) { 30917c478bd9Sstevel@tonic-gate 30927c478bd9Sstevel@tonic-gate best_node_bandwidth = node_bandwidth; 30937c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 30947c478bd9Sstevel@tonic-gate best_smask = *smask; 30957c478bd9Sstevel@tonic-gate } 30967c478bd9Sstevel@tonic-gate } 30977c478bd9Sstevel@tonic-gate 30987c478bd9Sstevel@tonic-gate /* 30997c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 31007c478bd9Sstevel@tonic-gate * appropriate variables and return success. 31017c478bd9Sstevel@tonic-gate */ 31027c478bd9Sstevel@tonic-gate if (best_smask) { 31037c478bd9Sstevel@tonic-gate *smask = best_smask; 31047c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 31057c478bd9Sstevel@tonic-gate interval); 31067c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, bandwidth, 31077c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 31087c478bd9Sstevel@tonic-gate 31097c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 31107c478bd9Sstevel@tonic-gate } 31117c478bd9Sstevel@tonic-gate 31127c478bd9Sstevel@tonic-gate return (USB_FAILURE); 31137c478bd9Sstevel@tonic-gate } 31147c478bd9Sstevel@tonic-gate 31157c478bd9Sstevel@tonic-gate 31167c478bd9Sstevel@tonic-gate /* 31177c478bd9Sstevel@tonic-gate * ehci_find_bestfit_ls_intr_mask: 31187c478bd9Sstevel@tonic-gate * 31197c478bd9Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation. 31207c478bd9Sstevel@tonic-gate */ 31217c478bd9Sstevel@tonic-gate static int 31227c478bd9Sstevel@tonic-gate ehci_find_bestfit_ls_intr_mask( 31237c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 31247c478bd9Sstevel@tonic-gate uchar_t *smask, 31257c478bd9Sstevel@tonic-gate uchar_t *cmask, 31267c478bd9Sstevel@tonic-gate uint_t *pnode, 31277c478bd9Sstevel@tonic-gate uint_t sbandwidth, 31287c478bd9Sstevel@tonic-gate uint_t cbandwidth, 31297c478bd9Sstevel@tonic-gate int interval) 31307c478bd9Sstevel@tonic-gate { 31317c478bd9Sstevel@tonic-gate int i; 31327c478bd9Sstevel@tonic-gate uint_t elements, index; 31337c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 31347c478bd9Sstevel@tonic-gate uint_t node_sbandwidth, node_cbandwidth; 31357c478bd9Sstevel@tonic-gate uint_t best_node_bandwidth; 31367c478bd9Sstevel@tonic-gate uint_t leaf_count; 31377c478bd9Sstevel@tonic-gate uchar_t bw_smask, bw_cmask; 31387c478bd9Sstevel@tonic-gate uchar_t best_smask, best_cmask; 31397c478bd9Sstevel@tonic-gate 31407c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 31417c478bd9Sstevel@tonic-gate "ehci_find_bestfit_ls_intr_mask: "); 31427c478bd9Sstevel@tonic-gate 31437c478bd9Sstevel@tonic-gate /* For low and full speed devices */ 31447c478bd9Sstevel@tonic-gate index = EHCI_XUS_MASK_INDEX; 31457c478bd9Sstevel@tonic-gate elements = EHCI_INTR_4MS_POLL; 31467c478bd9Sstevel@tonic-gate 31477c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 31487c478bd9Sstevel@tonic-gate 31497c478bd9Sstevel@tonic-gate /* 31507c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 31517c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 31527c478bd9Sstevel@tonic-gate */ 31537c478bd9Sstevel@tonic-gate best_smask = 0x00; 31547c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 31557c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 31567c478bd9Sstevel@tonic-gate /* Find the bandwidth mask */ 31577c478bd9Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip, 31587c478bd9Sstevel@tonic-gate sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask); 31597c478bd9Sstevel@tonic-gate node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip, 31607c478bd9Sstevel@tonic-gate cbandwidth, ehci_index[array_leaf], leaf_count, &bw_cmask); 31617c478bd9Sstevel@tonic-gate 31627c478bd9Sstevel@tonic-gate /* 31637c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 31647c478bd9Sstevel@tonic-gate * next leaf. 31657c478bd9Sstevel@tonic-gate */ 31667c478bd9Sstevel@tonic-gate if ((bw_smask == 0x00) || (bw_cmask == 0x00)) { 31677c478bd9Sstevel@tonic-gate continue; 31687c478bd9Sstevel@tonic-gate } 31697c478bd9Sstevel@tonic-gate 31707c478bd9Sstevel@tonic-gate /* 31717c478bd9Sstevel@tonic-gate * Now make sure our bandwidth requirements can be 31727c478bd9Sstevel@tonic-gate * satisfied with one of smasks in this node. 31737c478bd9Sstevel@tonic-gate */ 31747c478bd9Sstevel@tonic-gate *smask = 0x00; 31757c478bd9Sstevel@tonic-gate *cmask = 0x00; 31767c478bd9Sstevel@tonic-gate for (i = index; i < (index + elements); i++) { 31777c478bd9Sstevel@tonic-gate /* Check the start split mask value */ 31787c478bd9Sstevel@tonic-gate if ((ehci_start_split_mask[index] & bw_smask) && 31797c478bd9Sstevel@tonic-gate (ehci_intr_complete_split_mask[index] & bw_cmask)) { 31807c478bd9Sstevel@tonic-gate *smask = ehci_start_split_mask[index]; 31817c478bd9Sstevel@tonic-gate *cmask = ehci_intr_complete_split_mask[index]; 31827c478bd9Sstevel@tonic-gate break; 31837c478bd9Sstevel@tonic-gate } 31847c478bd9Sstevel@tonic-gate } 31857c478bd9Sstevel@tonic-gate 31867c478bd9Sstevel@tonic-gate /* 31877c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 31887c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 31897c478bd9Sstevel@tonic-gate * - or - 31907c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 31917c478bd9Sstevel@tonic-gate */ 31927c478bd9Sstevel@tonic-gate if ((*smask != 0x00) && 31937c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 31947c478bd9Sstevel@tonic-gate (best_node_bandwidth > 31957c478bd9Sstevel@tonic-gate (node_sbandwidth + node_cbandwidth)))) { 31967c478bd9Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth + node_cbandwidth; 31977c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 31987c478bd9Sstevel@tonic-gate best_smask = *smask; 31997c478bd9Sstevel@tonic-gate best_cmask = *cmask; 32007c478bd9Sstevel@tonic-gate } 32017c478bd9Sstevel@tonic-gate } 32027c478bd9Sstevel@tonic-gate 32037c478bd9Sstevel@tonic-gate /* 32047c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 32057c478bd9Sstevel@tonic-gate * appropriate variables and return success. 32067c478bd9Sstevel@tonic-gate */ 32077c478bd9Sstevel@tonic-gate if (best_smask) { 32087c478bd9Sstevel@tonic-gate *smask = best_smask; 32097c478bd9Sstevel@tonic-gate *cmask = best_cmask; 32107c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 32117c478bd9Sstevel@tonic-gate interval); 32127c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, sbandwidth, 32137c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 32147c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, cbandwidth, 32157c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_cmask); 32167c478bd9Sstevel@tonic-gate 32177c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 32187c478bd9Sstevel@tonic-gate } 32197c478bd9Sstevel@tonic-gate 32207c478bd9Sstevel@tonic-gate return (USB_FAILURE); 32217c478bd9Sstevel@tonic-gate } 32227c478bd9Sstevel@tonic-gate 32237c478bd9Sstevel@tonic-gate 32247c478bd9Sstevel@tonic-gate /* 32257c478bd9Sstevel@tonic-gate * ehci_find_bestfit_sitd_in_mask: 32267c478bd9Sstevel@tonic-gate * 32277c478bd9Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation. 32287c478bd9Sstevel@tonic-gate */ 32297c478bd9Sstevel@tonic-gate static int 32307c478bd9Sstevel@tonic-gate ehci_find_bestfit_sitd_in_mask( 32317c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 32327c478bd9Sstevel@tonic-gate uchar_t *smask, 32337c478bd9Sstevel@tonic-gate uchar_t *cmask, 32347c478bd9Sstevel@tonic-gate uint_t *pnode, 32357c478bd9Sstevel@tonic-gate uint_t sbandwidth, 32367c478bd9Sstevel@tonic-gate uint_t cbandwidth, 32377c478bd9Sstevel@tonic-gate int interval) 32387c478bd9Sstevel@tonic-gate { 32397c478bd9Sstevel@tonic-gate int i, uFrames, found; 32407c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 32417c478bd9Sstevel@tonic-gate uint_t node_sbandwidth, node_cbandwidth; 32427c478bd9Sstevel@tonic-gate uint_t best_node_bandwidth; 32437c478bd9Sstevel@tonic-gate uint_t leaf_count; 32447c478bd9Sstevel@tonic-gate uchar_t bw_smask, bw_cmask; 32457c478bd9Sstevel@tonic-gate uchar_t best_smask, best_cmask; 32467c478bd9Sstevel@tonic-gate 32477c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 32487c478bd9Sstevel@tonic-gate "ehci_find_bestfit_sitd_in_mask: "); 32497c478bd9Sstevel@tonic-gate 32507c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 32517c478bd9Sstevel@tonic-gate 32527c478bd9Sstevel@tonic-gate /* 32537c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 32547c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 32557c478bd9Sstevel@tonic-gate * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame. 32567c478bd9Sstevel@tonic-gate */ 32577c478bd9Sstevel@tonic-gate /* 32587c478bd9Sstevel@tonic-gate * Need to add an additional 2 uFrames, if the "L"ast 32597c478bd9Sstevel@tonic-gate * complete split is before uFrame 6. See section 32607c478bd9Sstevel@tonic-gate * 11.8.4 in USB 2.0 Spec. Currently we do not support 32617c478bd9Sstevel@tonic-gate * the "Back Ptr" which means we support on IN of 32627c478bd9Sstevel@tonic-gate * ~4*MAX_UFRAME_SITD_XFER bandwidth/ 32637c478bd9Sstevel@tonic-gate */ 32647c478bd9Sstevel@tonic-gate uFrames = (cbandwidth / MAX_UFRAME_SITD_XFER) + 2; 32657c478bd9Sstevel@tonic-gate if (cbandwidth % MAX_UFRAME_SITD_XFER) { 32667c478bd9Sstevel@tonic-gate uFrames++; 32677c478bd9Sstevel@tonic-gate } 32687c478bd9Sstevel@tonic-gate if (uFrames > 6) { 32697c478bd9Sstevel@tonic-gate 32707c478bd9Sstevel@tonic-gate return (USB_FAILURE); 32717c478bd9Sstevel@tonic-gate } 32727c478bd9Sstevel@tonic-gate *smask = 0x1; 32737c478bd9Sstevel@tonic-gate *cmask = 0x00; 32747c478bd9Sstevel@tonic-gate for (i = 0; i < uFrames; i++) { 32757c478bd9Sstevel@tonic-gate *cmask = *cmask << 1; 32767c478bd9Sstevel@tonic-gate *cmask |= 0x1; 32777c478bd9Sstevel@tonic-gate } 32787c478bd9Sstevel@tonic-gate /* cmask must start 2 frames after the smask */ 32797c478bd9Sstevel@tonic-gate *cmask = *cmask << 2; 32807c478bd9Sstevel@tonic-gate 32817c478bd9Sstevel@tonic-gate found = 0; 32827c478bd9Sstevel@tonic-gate best_smask = 0x00; 32837c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 32847c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 32857c478bd9Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip, 32867c478bd9Sstevel@tonic-gate sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask); 32877c478bd9Sstevel@tonic-gate node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip, 32887c478bd9Sstevel@tonic-gate MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count, 32897c478bd9Sstevel@tonic-gate &bw_cmask); 32907c478bd9Sstevel@tonic-gate 32917c478bd9Sstevel@tonic-gate /* 32927c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 32937c478bd9Sstevel@tonic-gate * next leaf. 32947c478bd9Sstevel@tonic-gate */ 32957c478bd9Sstevel@tonic-gate if ((bw_smask == 0x00) || (bw_cmask == 0x00)) { 32967c478bd9Sstevel@tonic-gate continue; 32977c478bd9Sstevel@tonic-gate } 32987c478bd9Sstevel@tonic-gate 32997c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_MAX_UFRAMES - uFrames - 2); i++) { 33007c478bd9Sstevel@tonic-gate if ((*smask & bw_smask) && (*cmask & bw_cmask)) { 33017c478bd9Sstevel@tonic-gate found = 1; 33027c478bd9Sstevel@tonic-gate break; 33037c478bd9Sstevel@tonic-gate } 33047c478bd9Sstevel@tonic-gate *smask = *smask << 1; 33057c478bd9Sstevel@tonic-gate *cmask = *cmask << 1; 33067c478bd9Sstevel@tonic-gate } 33077c478bd9Sstevel@tonic-gate 33087c478bd9Sstevel@tonic-gate /* 33097c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 33107c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 33117c478bd9Sstevel@tonic-gate * - or - 33127c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 33137c478bd9Sstevel@tonic-gate */ 33147c478bd9Sstevel@tonic-gate if (found && 33157c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 33167c478bd9Sstevel@tonic-gate (best_node_bandwidth > 33177c478bd9Sstevel@tonic-gate (node_sbandwidth + node_cbandwidth)))) { 33187c478bd9Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth + node_cbandwidth; 33197c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 33207c478bd9Sstevel@tonic-gate best_smask = *smask; 33217c478bd9Sstevel@tonic-gate best_cmask = *cmask; 33227c478bd9Sstevel@tonic-gate } 33237c478bd9Sstevel@tonic-gate } 33247c478bd9Sstevel@tonic-gate 33257c478bd9Sstevel@tonic-gate /* 33267c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 33277c478bd9Sstevel@tonic-gate * appropriate variables and return success. 33287c478bd9Sstevel@tonic-gate */ 33297c478bd9Sstevel@tonic-gate if (best_smask) { 33307c478bd9Sstevel@tonic-gate *smask = best_smask; 33317c478bd9Sstevel@tonic-gate *cmask = best_cmask; 33327c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 33337c478bd9Sstevel@tonic-gate interval); 33347c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, sbandwidth, 33357c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 33367c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER, 33377c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_cmask); 33387c478bd9Sstevel@tonic-gate 33397c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 33407c478bd9Sstevel@tonic-gate } 33417c478bd9Sstevel@tonic-gate 33427c478bd9Sstevel@tonic-gate return (USB_FAILURE); 33437c478bd9Sstevel@tonic-gate } 33447c478bd9Sstevel@tonic-gate 33457c478bd9Sstevel@tonic-gate 33467c478bd9Sstevel@tonic-gate /* 33477c478bd9Sstevel@tonic-gate * ehci_find_bestfit_sitd_out_mask: 33487c478bd9Sstevel@tonic-gate * 33497c478bd9Sstevel@tonic-gate * Find the smask in the bandwidth allocation. 33507c478bd9Sstevel@tonic-gate */ 33517c478bd9Sstevel@tonic-gate static int 33527c478bd9Sstevel@tonic-gate ehci_find_bestfit_sitd_out_mask( 33537c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 33547c478bd9Sstevel@tonic-gate uchar_t *smask, 33557c478bd9Sstevel@tonic-gate uint_t *pnode, 33567c478bd9Sstevel@tonic-gate uint_t sbandwidth, 33577c478bd9Sstevel@tonic-gate int interval) 33587c478bd9Sstevel@tonic-gate { 33597c478bd9Sstevel@tonic-gate int i, uFrames, found; 33607c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 33617c478bd9Sstevel@tonic-gate uint_t node_sbandwidth; 33627c478bd9Sstevel@tonic-gate uint_t best_node_bandwidth; 33637c478bd9Sstevel@tonic-gate uint_t leaf_count; 33647c478bd9Sstevel@tonic-gate uchar_t bw_smask; 33657c478bd9Sstevel@tonic-gate uchar_t best_smask; 33667c478bd9Sstevel@tonic-gate 33677c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 33687c478bd9Sstevel@tonic-gate "ehci_find_bestfit_sitd_out_mask: "); 33697c478bd9Sstevel@tonic-gate 33707c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 33717c478bd9Sstevel@tonic-gate 33727c478bd9Sstevel@tonic-gate /* 33737c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 33747c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 33757c478bd9Sstevel@tonic-gate * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame. 33767c478bd9Sstevel@tonic-gate */ 33777c478bd9Sstevel@tonic-gate *smask = 0x00; 33787c478bd9Sstevel@tonic-gate uFrames = sbandwidth / MAX_UFRAME_SITD_XFER; 33797c478bd9Sstevel@tonic-gate if (sbandwidth % MAX_UFRAME_SITD_XFER) { 33807c478bd9Sstevel@tonic-gate uFrames++; 33817c478bd9Sstevel@tonic-gate } 33827c478bd9Sstevel@tonic-gate for (i = 0; i < uFrames; i++) { 33837c478bd9Sstevel@tonic-gate *smask = *smask << 1; 33847c478bd9Sstevel@tonic-gate *smask |= 0x1; 33857c478bd9Sstevel@tonic-gate } 33867c478bd9Sstevel@tonic-gate 33877c478bd9Sstevel@tonic-gate found = 0; 33887c478bd9Sstevel@tonic-gate best_smask = 0x00; 33897c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 33907c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 33917c478bd9Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip, 33927c478bd9Sstevel@tonic-gate MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count, 33937c478bd9Sstevel@tonic-gate &bw_smask); 33947c478bd9Sstevel@tonic-gate 33957c478bd9Sstevel@tonic-gate /* 33967c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 33977c478bd9Sstevel@tonic-gate * next leaf. 33987c478bd9Sstevel@tonic-gate */ 33997c478bd9Sstevel@tonic-gate if (bw_smask == 0x00) { 34007c478bd9Sstevel@tonic-gate continue; 34017c478bd9Sstevel@tonic-gate } 34027c478bd9Sstevel@tonic-gate 34037c478bd9Sstevel@tonic-gate /* You cannot have a start split on the 8th uFrame */ 34047c478bd9Sstevel@tonic-gate for (i = 0; (*smask & 0x80) == 0; i++) { 34057c478bd9Sstevel@tonic-gate if (*smask & bw_smask) { 34067c478bd9Sstevel@tonic-gate found = 1; 34077c478bd9Sstevel@tonic-gate break; 34087c478bd9Sstevel@tonic-gate } 34097c478bd9Sstevel@tonic-gate *smask = *smask << 1; 34107c478bd9Sstevel@tonic-gate } 34117c478bd9Sstevel@tonic-gate 34127c478bd9Sstevel@tonic-gate /* 34137c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 34147c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 34157c478bd9Sstevel@tonic-gate * - or - 34167c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 34177c478bd9Sstevel@tonic-gate */ 34187c478bd9Sstevel@tonic-gate if (found && 34197c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 34207c478bd9Sstevel@tonic-gate (best_node_bandwidth > node_sbandwidth))) { 34217c478bd9Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth; 34227c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 34237c478bd9Sstevel@tonic-gate best_smask = *smask; 34247c478bd9Sstevel@tonic-gate } 34257c478bd9Sstevel@tonic-gate } 34267c478bd9Sstevel@tonic-gate 34277c478bd9Sstevel@tonic-gate /* 34287c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 34297c478bd9Sstevel@tonic-gate * appropriate variables and return success. 34307c478bd9Sstevel@tonic-gate */ 34317c478bd9Sstevel@tonic-gate if (best_smask) { 34327c478bd9Sstevel@tonic-gate *smask = best_smask; 34337c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 34347c478bd9Sstevel@tonic-gate interval); 34357c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER, 34367c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 34377c478bd9Sstevel@tonic-gate 34387c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 34397c478bd9Sstevel@tonic-gate } 34407c478bd9Sstevel@tonic-gate 34417c478bd9Sstevel@tonic-gate return (USB_FAILURE); 34427c478bd9Sstevel@tonic-gate } 34437c478bd9Sstevel@tonic-gate 34447c478bd9Sstevel@tonic-gate 34457c478bd9Sstevel@tonic-gate /* 34467c478bd9Sstevel@tonic-gate * ehci_calculate_bw_availability_mask: 34477c478bd9Sstevel@tonic-gate * 34487c478bd9Sstevel@tonic-gate * Returns the "total bandwidth used" in this node. 34497c478bd9Sstevel@tonic-gate * Populates bw_mask with the uFrames that can support the bandwidth. 34507c478bd9Sstevel@tonic-gate * 34517c478bd9Sstevel@tonic-gate * If all the Frames cannot support this bandwidth, then bw_mask 34527c478bd9Sstevel@tonic-gate * will return 0x00 and the "total bandwidth used" will be invalid. 34537c478bd9Sstevel@tonic-gate */ 34547c478bd9Sstevel@tonic-gate static uint_t 34557c478bd9Sstevel@tonic-gate ehci_calculate_bw_availability_mask( 34567c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 34577c478bd9Sstevel@tonic-gate uint_t bandwidth, 34587c478bd9Sstevel@tonic-gate int leaf, 34597c478bd9Sstevel@tonic-gate int leaf_count, 34607c478bd9Sstevel@tonic-gate uchar_t *bw_mask) 34617c478bd9Sstevel@tonic-gate { 34627c478bd9Sstevel@tonic-gate int i, j; 34637c478bd9Sstevel@tonic-gate uchar_t bw_uframe; 34647c478bd9Sstevel@tonic-gate int uframe_total; 34657c478bd9Sstevel@tonic-gate ehci_frame_bandwidth_t *fbp; 34667c478bd9Sstevel@tonic-gate uint_t total_bandwidth = 0; 34677c478bd9Sstevel@tonic-gate 34687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 34697c478bd9Sstevel@tonic-gate "ehci_calculate_bw_availability_mask: leaf %d leaf count %d", 34707c478bd9Sstevel@tonic-gate leaf, leaf_count); 34717c478bd9Sstevel@tonic-gate 34727c478bd9Sstevel@tonic-gate /* Start by saying all uFrames are available */ 34737c478bd9Sstevel@tonic-gate *bw_mask = 0xFF; 34747c478bd9Sstevel@tonic-gate 34757c478bd9Sstevel@tonic-gate for (i = 0; (i < leaf_count) || (*bw_mask == 0x00); i++) { 34767c478bd9Sstevel@tonic-gate fbp = &ehcip->ehci_frame_bandwidth[leaf + i]; 34777c478bd9Sstevel@tonic-gate 34787c478bd9Sstevel@tonic-gate total_bandwidth += fbp->ehci_allocated_frame_bandwidth; 34797c478bd9Sstevel@tonic-gate 34807c478bd9Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) { 34817c478bd9Sstevel@tonic-gate /* 34827c478bd9Sstevel@tonic-gate * If the uFrame in bw_mask is available check to see if 34837c478bd9Sstevel@tonic-gate * it can support the additional bandwidth. 34847c478bd9Sstevel@tonic-gate */ 34857c478bd9Sstevel@tonic-gate bw_uframe = (*bw_mask & (0x1 << j)); 34867c478bd9Sstevel@tonic-gate uframe_total = 34877c478bd9Sstevel@tonic-gate fbp->ehci_micro_frame_bandwidth[j] + 34887c478bd9Sstevel@tonic-gate bandwidth; 34897c478bd9Sstevel@tonic-gate if ((bw_uframe) && 34907c478bd9Sstevel@tonic-gate (uframe_total > HS_PERIODIC_BANDWIDTH)) { 34917c478bd9Sstevel@tonic-gate *bw_mask = *bw_mask & ~bw_uframe; 34927c478bd9Sstevel@tonic-gate } 34937c478bd9Sstevel@tonic-gate } 34947c478bd9Sstevel@tonic-gate } 34957c478bd9Sstevel@tonic-gate 34967c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 34977c478bd9Sstevel@tonic-gate "ehci_calculate_bw_availability_mask: bandwidth mask 0x%x", 34987c478bd9Sstevel@tonic-gate *bw_mask); 34997c478bd9Sstevel@tonic-gate 35007c478bd9Sstevel@tonic-gate return (total_bandwidth); 35017c478bd9Sstevel@tonic-gate } 35027c478bd9Sstevel@tonic-gate 35037c478bd9Sstevel@tonic-gate 35047c478bd9Sstevel@tonic-gate /* 35057c478bd9Sstevel@tonic-gate * ehci_update_bw_availability: 35067c478bd9Sstevel@tonic-gate * 35077c478bd9Sstevel@tonic-gate * The leftmost leaf needs to be in terms of array position and 35087c478bd9Sstevel@tonic-gate * not the actual lattice position. 35097c478bd9Sstevel@tonic-gate */ 35107c478bd9Sstevel@tonic-gate static void 35117c478bd9Sstevel@tonic-gate ehci_update_bw_availability( 35127c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 35137c478bd9Sstevel@tonic-gate int bandwidth, 35147c478bd9Sstevel@tonic-gate int leftmost_leaf, 35157c478bd9Sstevel@tonic-gate int leaf_count, 35167c478bd9Sstevel@tonic-gate uchar_t mask) 35177c478bd9Sstevel@tonic-gate { 35187c478bd9Sstevel@tonic-gate int i, j; 35197c478bd9Sstevel@tonic-gate ehci_frame_bandwidth_t *fbp; 35207c478bd9Sstevel@tonic-gate int uFrame_bandwidth[8]; 35217c478bd9Sstevel@tonic-gate 35227c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 35237c478bd9Sstevel@tonic-gate "ehci_update_bw_availability: " 35247c478bd9Sstevel@tonic-gate "leaf %d count %d bandwidth 0x%x mask 0x%x", 35257c478bd9Sstevel@tonic-gate leftmost_leaf, leaf_count, bandwidth, mask); 35267c478bd9Sstevel@tonic-gate 35277c478bd9Sstevel@tonic-gate ASSERT(leftmost_leaf < 32); 35287c478bd9Sstevel@tonic-gate ASSERT(leftmost_leaf >= 0); 35297c478bd9Sstevel@tonic-gate 35307c478bd9Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) { 35317c478bd9Sstevel@tonic-gate if (mask & 0x1) { 35327c478bd9Sstevel@tonic-gate uFrame_bandwidth[j] = bandwidth; 35337c478bd9Sstevel@tonic-gate } else { 35347c478bd9Sstevel@tonic-gate uFrame_bandwidth[j] = 0; 35357c478bd9Sstevel@tonic-gate } 35367c478bd9Sstevel@tonic-gate 35377c478bd9Sstevel@tonic-gate mask = mask >> 1; 35387c478bd9Sstevel@tonic-gate } 35397c478bd9Sstevel@tonic-gate 35407c478bd9Sstevel@tonic-gate /* Updated all the effected leafs with the bandwidth */ 35417c478bd9Sstevel@tonic-gate for (i = 0; i < leaf_count; i++) { 35427c478bd9Sstevel@tonic-gate fbp = &ehcip->ehci_frame_bandwidth[leftmost_leaf + i]; 35437c478bd9Sstevel@tonic-gate 35447c478bd9Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) { 35457c478bd9Sstevel@tonic-gate fbp->ehci_micro_frame_bandwidth[j] += 35467c478bd9Sstevel@tonic-gate uFrame_bandwidth[j]; 35477c478bd9Sstevel@tonic-gate fbp->ehci_allocated_frame_bandwidth += 35487c478bd9Sstevel@tonic-gate uFrame_bandwidth[j]; 35497c478bd9Sstevel@tonic-gate } 35507c478bd9Sstevel@tonic-gate } 35517c478bd9Sstevel@tonic-gate } 35527c478bd9Sstevel@tonic-gate 35537c478bd9Sstevel@tonic-gate /* 35547c478bd9Sstevel@tonic-gate * Miscellaneous functions 35557c478bd9Sstevel@tonic-gate */ 35567c478bd9Sstevel@tonic-gate 35577c478bd9Sstevel@tonic-gate /* 35587c478bd9Sstevel@tonic-gate * ehci_obtain_state: 35597c478bd9Sstevel@tonic-gate * 35607c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 35617c478bd9Sstevel@tonic-gate */ 35627c478bd9Sstevel@tonic-gate ehci_state_t * 35637c478bd9Sstevel@tonic-gate ehci_obtain_state(dev_info_t *dip) 35647c478bd9Sstevel@tonic-gate { 35657c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 35667c478bd9Sstevel@tonic-gate 35677c478bd9Sstevel@tonic-gate ehci_state_t *state = ddi_get_soft_state(ehci_statep, instance); 35687c478bd9Sstevel@tonic-gate 35697c478bd9Sstevel@tonic-gate ASSERT(state != NULL); 35707c478bd9Sstevel@tonic-gate 35717c478bd9Sstevel@tonic-gate return (state); 35727c478bd9Sstevel@tonic-gate } 35737c478bd9Sstevel@tonic-gate 35747c478bd9Sstevel@tonic-gate 35757c478bd9Sstevel@tonic-gate /* 35767c478bd9Sstevel@tonic-gate * ehci_state_is_operational: 35777c478bd9Sstevel@tonic-gate * 35787c478bd9Sstevel@tonic-gate * Check the Host controller state and return proper values. 35797c478bd9Sstevel@tonic-gate */ 35807c478bd9Sstevel@tonic-gate int 35817c478bd9Sstevel@tonic-gate ehci_state_is_operational(ehci_state_t *ehcip) 35827c478bd9Sstevel@tonic-gate { 35837c478bd9Sstevel@tonic-gate int val; 35847c478bd9Sstevel@tonic-gate 35857c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 35867c478bd9Sstevel@tonic-gate 35877c478bd9Sstevel@tonic-gate switch (ehcip->ehci_hc_soft_state) { 35887c478bd9Sstevel@tonic-gate case EHCI_CTLR_INIT_STATE: 35897c478bd9Sstevel@tonic-gate case EHCI_CTLR_SUSPEND_STATE: 35907c478bd9Sstevel@tonic-gate val = USB_FAILURE; 35917c478bd9Sstevel@tonic-gate break; 35927c478bd9Sstevel@tonic-gate case EHCI_CTLR_OPERATIONAL_STATE: 35937c478bd9Sstevel@tonic-gate val = USB_SUCCESS; 35947c478bd9Sstevel@tonic-gate break; 35957c478bd9Sstevel@tonic-gate case EHCI_CTLR_ERROR_STATE: 35967c478bd9Sstevel@tonic-gate val = USB_HC_HARDWARE_ERROR; 35977c478bd9Sstevel@tonic-gate break; 35987c478bd9Sstevel@tonic-gate default: 35997c478bd9Sstevel@tonic-gate val = USB_FAILURE; 36007c478bd9Sstevel@tonic-gate break; 36017c478bd9Sstevel@tonic-gate } 36027c478bd9Sstevel@tonic-gate 36037c478bd9Sstevel@tonic-gate return (val); 36047c478bd9Sstevel@tonic-gate } 36057c478bd9Sstevel@tonic-gate 36067c478bd9Sstevel@tonic-gate 36077c478bd9Sstevel@tonic-gate /* 36087c478bd9Sstevel@tonic-gate * ehci_do_soft_reset 36097c478bd9Sstevel@tonic-gate * 36107c478bd9Sstevel@tonic-gate * Do soft reset of ehci host controller. 36117c478bd9Sstevel@tonic-gate */ 36127c478bd9Sstevel@tonic-gate int 36137c478bd9Sstevel@tonic-gate ehci_do_soft_reset(ehci_state_t *ehcip) 36147c478bd9Sstevel@tonic-gate { 36157c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 36167c478bd9Sstevel@tonic-gate ehci_regs_t *ehci_save_regs; 36177c478bd9Sstevel@tonic-gate 36187c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 36197c478bd9Sstevel@tonic-gate 36207c478bd9Sstevel@tonic-gate /* Increment host controller error count */ 36217c478bd9Sstevel@tonic-gate ehcip->ehci_hc_error++; 36227c478bd9Sstevel@tonic-gate 36237c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 36247c478bd9Sstevel@tonic-gate "ehci_do_soft_reset:" 36257c478bd9Sstevel@tonic-gate "Reset ehci host controller 0x%x", ehcip->ehci_hc_error); 36267c478bd9Sstevel@tonic-gate 36277c478bd9Sstevel@tonic-gate /* 36287c478bd9Sstevel@tonic-gate * Allocate space for saving current Host Controller 36297c478bd9Sstevel@tonic-gate * registers. Don't do any recovery if allocation 36307c478bd9Sstevel@tonic-gate * fails. 36317c478bd9Sstevel@tonic-gate */ 36327c478bd9Sstevel@tonic-gate ehci_save_regs = (ehci_regs_t *) 36337c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (ehci_regs_t), KM_NOSLEEP); 36347c478bd9Sstevel@tonic-gate 36357c478bd9Sstevel@tonic-gate if (ehci_save_regs == NULL) { 36367c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 36377c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: kmem_zalloc failed"); 36387c478bd9Sstevel@tonic-gate 36397c478bd9Sstevel@tonic-gate return (USB_FAILURE); 36407c478bd9Sstevel@tonic-gate } 36417c478bd9Sstevel@tonic-gate 36427c478bd9Sstevel@tonic-gate /* Save current ehci registers */ 36437c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_command = Get_OpReg(ehci_command); 36447c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_interrupt = Get_OpReg(ehci_interrupt); 36457c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_ctrl_segment = Get_OpReg(ehci_ctrl_segment); 36467c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_async_list_addr = Get_OpReg(ehci_async_list_addr); 36477c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_config_flag = Get_OpReg(ehci_config_flag); 36487c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_periodic_list_base = 36497c478bd9Sstevel@tonic-gate Get_OpReg(ehci_periodic_list_base); 36507c478bd9Sstevel@tonic-gate 36513b00f311Syq USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 36527c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Save reg = 0x%p", ehci_save_regs); 36537c478bd9Sstevel@tonic-gate 36547c478bd9Sstevel@tonic-gate /* Disable all list processing and interrupts */ 36557c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, Get_OpReg(ehci_command) & 36567c478bd9Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE)); 36577c478bd9Sstevel@tonic-gate 36587c478bd9Sstevel@tonic-gate /* Disable all EHCI interrupts */ 36597c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0); 36607c478bd9Sstevel@tonic-gate 36617c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 36627c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_SOF_TIMEWAIT); 36637c478bd9Sstevel@tonic-gate 36647c478bd9Sstevel@tonic-gate /* Do light soft reset of ehci host controller */ 36657c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 36667c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) | EHCI_CMD_LIGHT_HC_RESET); 36677c478bd9Sstevel@tonic-gate 36683b00f311Syq USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 36697c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Reset in progress"); 36707c478bd9Sstevel@tonic-gate 36717c478bd9Sstevel@tonic-gate /* Wait for reset to complete */ 36727c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT); 36737c478bd9Sstevel@tonic-gate 36747c478bd9Sstevel@tonic-gate /* 36757c478bd9Sstevel@tonic-gate * Restore previous saved EHCI register value 36767c478bd9Sstevel@tonic-gate * into the current EHCI registers. 36777c478bd9Sstevel@tonic-gate */ 36787c478bd9Sstevel@tonic-gate Set_OpReg(ehci_ctrl_segment, (uint32_t) 36797c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_ctrl_segment); 36807c478bd9Sstevel@tonic-gate 36817c478bd9Sstevel@tonic-gate Set_OpReg(ehci_periodic_list_base, (uint32_t) 36827c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_periodic_list_base); 36837c478bd9Sstevel@tonic-gate 36847c478bd9Sstevel@tonic-gate Set_OpReg(ehci_async_list_addr, (uint32_t) 36857c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_async_list_addr); 36867c478bd9Sstevel@tonic-gate 36877c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, (uint32_t) 36887c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_config_flag); 36897c478bd9Sstevel@tonic-gate 36907c478bd9Sstevel@tonic-gate /* Enable both Asynchronous and Periodic Schedule if necessary */ 36917c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehcip); 36927c478bd9Sstevel@tonic-gate 36937c478bd9Sstevel@tonic-gate /* 36947c478bd9Sstevel@tonic-gate * Set ehci_interrupt to enable all interrupts except Root 36957c478bd9Sstevel@tonic-gate * Hub Status change and frame list rollover interrupts. 36967c478bd9Sstevel@tonic-gate */ 36977c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR | 36987c478bd9Sstevel@tonic-gate EHCI_INTR_FRAME_LIST_ROLLOVER | 36997c478bd9Sstevel@tonic-gate EHCI_INTR_USB_ERROR | 37007c478bd9Sstevel@tonic-gate EHCI_INTR_USB); 37017c478bd9Sstevel@tonic-gate 37027c478bd9Sstevel@tonic-gate /* 37037c478bd9Sstevel@tonic-gate * Deallocate the space that allocated for saving 37047c478bd9Sstevel@tonic-gate * HC registers. 37057c478bd9Sstevel@tonic-gate */ 37067c478bd9Sstevel@tonic-gate kmem_free((void *) ehci_save_regs, sizeof (ehci_regs_t)); 37077c478bd9Sstevel@tonic-gate 37087c478bd9Sstevel@tonic-gate /* 37097c478bd9Sstevel@tonic-gate * Set the desired interrupt threshold, frame list size (if 37107c478bd9Sstevel@tonic-gate * applicable) and turn EHCI host controller. 37117c478bd9Sstevel@tonic-gate */ 37127c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, ((Get_OpReg(ehci_command) & 37137c478bd9Sstevel@tonic-gate ~EHCI_CMD_INTR_THRESHOLD) | 37147c478bd9Sstevel@tonic-gate (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN))); 37157c478bd9Sstevel@tonic-gate 37167c478bd9Sstevel@tonic-gate /* Wait 10ms for EHCI to start sending SOF */ 37177c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT); 37187c478bd9Sstevel@tonic-gate 37197c478bd9Sstevel@tonic-gate /* 37207c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for 37217c478bd9Sstevel@tonic-gate * few milliseconds. 37227c478bd9Sstevel@tonic-gate */ 37237c478bd9Sstevel@tonic-gate before_frame_number = ehci_get_current_frame_number(ehcip); 37247c478bd9Sstevel@tonic-gate 37257c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 37267c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_SOF_TIMEWAIT); 37277c478bd9Sstevel@tonic-gate 37287c478bd9Sstevel@tonic-gate /* 37297c478bd9Sstevel@tonic-gate * Get the current usb frame number after waiting for 37307c478bd9Sstevel@tonic-gate * few milliseconds. 37317c478bd9Sstevel@tonic-gate */ 37327c478bd9Sstevel@tonic-gate after_frame_number = ehci_get_current_frame_number(ehcip); 37337c478bd9Sstevel@tonic-gate 37347c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 37357c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Before Frame Number 0x%llx " 37367c478bd9Sstevel@tonic-gate "After Frame Number 0x%llx", 37377c478bd9Sstevel@tonic-gate before_frame_number, after_frame_number); 37387c478bd9Sstevel@tonic-gate 37397c478bd9Sstevel@tonic-gate if ((after_frame_number <= before_frame_number) && 37407c478bd9Sstevel@tonic-gate (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) { 37417c478bd9Sstevel@tonic-gate 37427c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 37437c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Soft reset failed"); 37447c478bd9Sstevel@tonic-gate 37457c478bd9Sstevel@tonic-gate return (USB_FAILURE); 37467c478bd9Sstevel@tonic-gate } 37477c478bd9Sstevel@tonic-gate 37487c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 37497c478bd9Sstevel@tonic-gate } 37507c478bd9Sstevel@tonic-gate 37517c478bd9Sstevel@tonic-gate 37527c478bd9Sstevel@tonic-gate /* 37537c478bd9Sstevel@tonic-gate * ehci_get_xfer_attrs: 37547c478bd9Sstevel@tonic-gate * 37557c478bd9Sstevel@tonic-gate * Get the attributes of a particular xfer. 37567c478bd9Sstevel@tonic-gate * 37577c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 37587c478bd9Sstevel@tonic-gate */ 37597c478bd9Sstevel@tonic-gate usb_req_attrs_t 37607c478bd9Sstevel@tonic-gate ehci_get_xfer_attrs( 37617c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 37627c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 37637c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 37647c478bd9Sstevel@tonic-gate { 37657c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep; 37667c478bd9Sstevel@tonic-gate usb_req_attrs_t attrs = USB_ATTRS_NONE; 37677c478bd9Sstevel@tonic-gate 37687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 37697c478bd9Sstevel@tonic-gate "ehci_get_xfer_attrs:"); 37707c478bd9Sstevel@tonic-gate 37717c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 37727c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 37737c478bd9Sstevel@tonic-gate attrs = ((usb_ctrl_req_t *) 37747c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->ctrl_attributes; 37757c478bd9Sstevel@tonic-gate break; 37767c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 37777c478bd9Sstevel@tonic-gate attrs = ((usb_bulk_req_t *) 37787c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->bulk_attributes; 37797c478bd9Sstevel@tonic-gate break; 37807c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 37817c478bd9Sstevel@tonic-gate attrs = ((usb_intr_req_t *) 37827c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->intr_attributes; 37837c478bd9Sstevel@tonic-gate break; 37847c478bd9Sstevel@tonic-gate } 37857c478bd9Sstevel@tonic-gate 37867c478bd9Sstevel@tonic-gate return (attrs); 37877c478bd9Sstevel@tonic-gate } 37887c478bd9Sstevel@tonic-gate 37897c478bd9Sstevel@tonic-gate 37907c478bd9Sstevel@tonic-gate /* 37917c478bd9Sstevel@tonic-gate * ehci_get_current_frame_number: 37927c478bd9Sstevel@tonic-gate * 37937c478bd9Sstevel@tonic-gate * Get the current software based usb frame number. 37947c478bd9Sstevel@tonic-gate */ 37957c478bd9Sstevel@tonic-gate usb_frame_number_t 37967c478bd9Sstevel@tonic-gate ehci_get_current_frame_number(ehci_state_t *ehcip) 37977c478bd9Sstevel@tonic-gate { 37987c478bd9Sstevel@tonic-gate usb_frame_number_t usb_frame_number; 37997c478bd9Sstevel@tonic-gate usb_frame_number_t ehci_fno, micro_frame_number; 38007c478bd9Sstevel@tonic-gate 38017c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 38027c478bd9Sstevel@tonic-gate 38037c478bd9Sstevel@tonic-gate ehci_fno = ehcip->ehci_fno; 38047c478bd9Sstevel@tonic-gate micro_frame_number = Get_OpReg(ehci_frame_index) & 0x3FFF; 38057c478bd9Sstevel@tonic-gate 38067c478bd9Sstevel@tonic-gate /* 38077c478bd9Sstevel@tonic-gate * Calculate current software based usb frame number. 38087c478bd9Sstevel@tonic-gate * 38097c478bd9Sstevel@tonic-gate * This code accounts for the fact that frame number is 38107c478bd9Sstevel@tonic-gate * updated by the Host Controller before the ehci driver 38117c478bd9Sstevel@tonic-gate * gets an FrameListRollover interrupt that will adjust 38127c478bd9Sstevel@tonic-gate * Frame higher part. 38137c478bd9Sstevel@tonic-gate * 38147c478bd9Sstevel@tonic-gate * Refer ehci specification 1.0, section 2.3.2, page 21. 38157c478bd9Sstevel@tonic-gate */ 38167c478bd9Sstevel@tonic-gate micro_frame_number = ((micro_frame_number & 0x1FFF) | 38177c478bd9Sstevel@tonic-gate ehci_fno) + (((micro_frame_number & 0x3FFF) ^ 38187c478bd9Sstevel@tonic-gate ehci_fno) & 0x2000); 38197c478bd9Sstevel@tonic-gate 38207c478bd9Sstevel@tonic-gate /* 38217c478bd9Sstevel@tonic-gate * Micro Frame number is equivalent to 125 usec. Eight 38227c478bd9Sstevel@tonic-gate * Micro Frame numbers are equivalent to one millsecond 38237c478bd9Sstevel@tonic-gate * or one usb frame number. 38247c478bd9Sstevel@tonic-gate */ 38257c478bd9Sstevel@tonic-gate usb_frame_number = micro_frame_number >> 38267c478bd9Sstevel@tonic-gate EHCI_uFRAMES_PER_USB_FRAME_SHIFT; 38277c478bd9Sstevel@tonic-gate 38287c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 38297c478bd9Sstevel@tonic-gate "ehci_get_current_frame_number: " 38307c478bd9Sstevel@tonic-gate "Current usb uframe number = 0x%llx " 38317c478bd9Sstevel@tonic-gate "Current usb frame number = 0x%llx", 38327c478bd9Sstevel@tonic-gate micro_frame_number, usb_frame_number); 38337c478bd9Sstevel@tonic-gate 38347c478bd9Sstevel@tonic-gate return (usb_frame_number); 38357c478bd9Sstevel@tonic-gate } 38367c478bd9Sstevel@tonic-gate 38377c478bd9Sstevel@tonic-gate 38387c478bd9Sstevel@tonic-gate /* 38397c478bd9Sstevel@tonic-gate * ehci_cpr_cleanup: 38407c478bd9Sstevel@tonic-gate * 38417c478bd9Sstevel@tonic-gate * Cleanup ehci state and other ehci specific informations across 38427c478bd9Sstevel@tonic-gate * Check Point Resume (CPR). 38437c478bd9Sstevel@tonic-gate */ 38447c478bd9Sstevel@tonic-gate static void 38457c478bd9Sstevel@tonic-gate ehci_cpr_cleanup(ehci_state_t *ehcip) 38467c478bd9Sstevel@tonic-gate { 38477c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 38487c478bd9Sstevel@tonic-gate 38497c478bd9Sstevel@tonic-gate /* Reset software part of usb frame number */ 38507c478bd9Sstevel@tonic-gate ehcip->ehci_fno = 0; 38517c478bd9Sstevel@tonic-gate } 38527c478bd9Sstevel@tonic-gate 38537c478bd9Sstevel@tonic-gate 38547c478bd9Sstevel@tonic-gate /* 38557c478bd9Sstevel@tonic-gate * ehci_wait_for_sof: 38567c478bd9Sstevel@tonic-gate * 38577c478bd9Sstevel@tonic-gate * Wait for couple of SOF interrupts 38587c478bd9Sstevel@tonic-gate */ 38597c478bd9Sstevel@tonic-gate int 38607c478bd9Sstevel@tonic-gate ehci_wait_for_sof(ehci_state_t *ehcip) 38617c478bd9Sstevel@tonic-gate { 38627c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 38637c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 38647c478bd9Sstevel@tonic-gate 38657c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, 38667c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, "ehci_wait_for_sof"); 38677c478bd9Sstevel@tonic-gate 38687c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 38697c478bd9Sstevel@tonic-gate 38707c478bd9Sstevel@tonic-gate error = ehci_state_is_operational(ehcip); 38717c478bd9Sstevel@tonic-gate 38727c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 38737c478bd9Sstevel@tonic-gate 38747c478bd9Sstevel@tonic-gate return (error); 38757c478bd9Sstevel@tonic-gate } 38767c478bd9Sstevel@tonic-gate 38777c478bd9Sstevel@tonic-gate /* Get the current usb frame number before waiting for two SOFs */ 38787c478bd9Sstevel@tonic-gate before_frame_number = ehci_get_current_frame_number(ehcip); 38797c478bd9Sstevel@tonic-gate 38807c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 38817c478bd9Sstevel@tonic-gate 38827c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 38837c478bd9Sstevel@tonic-gate delay(drv_usectohz(EHCI_SOF_TIMEWAIT)); 38847c478bd9Sstevel@tonic-gate 38857c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 38867c478bd9Sstevel@tonic-gate 38877c478bd9Sstevel@tonic-gate /* Get the current usb frame number after woken up */ 38887c478bd9Sstevel@tonic-gate after_frame_number = ehci_get_current_frame_number(ehcip); 38897c478bd9Sstevel@tonic-gate 38907c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 38917c478bd9Sstevel@tonic-gate "ehci_wait_for_sof: framenumber: before 0x%llx " 38927c478bd9Sstevel@tonic-gate "after 0x%llx", before_frame_number, after_frame_number); 38937c478bd9Sstevel@tonic-gate 38947c478bd9Sstevel@tonic-gate /* Return failure, if usb frame number has not been changed */ 38957c478bd9Sstevel@tonic-gate if (after_frame_number <= before_frame_number) { 38967c478bd9Sstevel@tonic-gate 38977c478bd9Sstevel@tonic-gate if ((ehci_do_soft_reset(ehcip)) != USB_SUCCESS) { 38987c478bd9Sstevel@tonic-gate 38997c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_LISTS, 39007c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, "No SOF interrupts"); 39017c478bd9Sstevel@tonic-gate 39027c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */ 39037c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE; 39047c478bd9Sstevel@tonic-gate 39057c478bd9Sstevel@tonic-gate return (USB_FAILURE); 39067c478bd9Sstevel@tonic-gate } 39077c478bd9Sstevel@tonic-gate 39087c478bd9Sstevel@tonic-gate /* Get new usb frame number */ 39097c478bd9Sstevel@tonic-gate after_frame_number = before_frame_number = 39107c478bd9Sstevel@tonic-gate ehci_get_current_frame_number(ehcip); 39117c478bd9Sstevel@tonic-gate } 39127c478bd9Sstevel@tonic-gate 39137c478bd9Sstevel@tonic-gate ASSERT(after_frame_number > before_frame_number); 39147c478bd9Sstevel@tonic-gate 39157c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 39167c478bd9Sstevel@tonic-gate } 39177c478bd9Sstevel@tonic-gate 39187c478bd9Sstevel@tonic-gate 39197c478bd9Sstevel@tonic-gate /* 39207c478bd9Sstevel@tonic-gate * ehci_toggle_scheduler: 39217c478bd9Sstevel@tonic-gate * 39227c478bd9Sstevel@tonic-gate * Turn scheduler based on pipe open count. 39237c478bd9Sstevel@tonic-gate */ 39247c478bd9Sstevel@tonic-gate void 39257c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehci_state_t *ehcip) { 39267c478bd9Sstevel@tonic-gate uint_t temp_reg, cmd_reg; 39277c478bd9Sstevel@tonic-gate 39287c478bd9Sstevel@tonic-gate cmd_reg = Get_OpReg(ehci_command); 39297c478bd9Sstevel@tonic-gate temp_reg = cmd_reg; 39307c478bd9Sstevel@tonic-gate 39317c478bd9Sstevel@tonic-gate /* 39327c478bd9Sstevel@tonic-gate * Enable/Disable asynchronous scheduler, and 39337c478bd9Sstevel@tonic-gate * turn on/off async list door bell 39347c478bd9Sstevel@tonic-gate */ 39357c478bd9Sstevel@tonic-gate if (ehcip->ehci_open_async_count) { 39367c478bd9Sstevel@tonic-gate if (!(cmd_reg & EHCI_CMD_ASYNC_SCHED_ENABLE)) { 39377c478bd9Sstevel@tonic-gate /* 39387c478bd9Sstevel@tonic-gate * For some reason this address might get nulled out by 39397c478bd9Sstevel@tonic-gate * the ehci chip. Set it here just in case it is null. 39407c478bd9Sstevel@tonic-gate */ 39417c478bd9Sstevel@tonic-gate Set_OpReg(ehci_async_list_addr, 39427c478bd9Sstevel@tonic-gate ehci_qh_cpu_to_iommu(ehcip, 39437c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list)); 39447c478bd9Sstevel@tonic-gate } 39457c478bd9Sstevel@tonic-gate cmd_reg |= EHCI_CMD_ASYNC_SCHED_ENABLE; 39467c478bd9Sstevel@tonic-gate } else { 39477c478bd9Sstevel@tonic-gate cmd_reg &= ~EHCI_CMD_ASYNC_SCHED_ENABLE; 39487c478bd9Sstevel@tonic-gate } 39497c478bd9Sstevel@tonic-gate 39507c478bd9Sstevel@tonic-gate if (ehcip->ehci_open_periodic_count) { 39517c478bd9Sstevel@tonic-gate if (!(cmd_reg & EHCI_CMD_PERIODIC_SCHED_ENABLE)) { 39527c478bd9Sstevel@tonic-gate /* 39537c478bd9Sstevel@tonic-gate * For some reason this address get's nulled out by 39547c478bd9Sstevel@tonic-gate * the ehci chip. Set it here just in case it is null. 39557c478bd9Sstevel@tonic-gate */ 39567c478bd9Sstevel@tonic-gate Set_OpReg(ehci_periodic_list_base, 39577c478bd9Sstevel@tonic-gate (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address & 39587c478bd9Sstevel@tonic-gate 0xFFFFF000)); 39597c478bd9Sstevel@tonic-gate } 39607c478bd9Sstevel@tonic-gate cmd_reg |= EHCI_CMD_PERIODIC_SCHED_ENABLE; 39617c478bd9Sstevel@tonic-gate } else { 39627c478bd9Sstevel@tonic-gate cmd_reg &= ~EHCI_CMD_PERIODIC_SCHED_ENABLE; 39637c478bd9Sstevel@tonic-gate } 39647c478bd9Sstevel@tonic-gate 39657c478bd9Sstevel@tonic-gate /* Just an optimization */ 39667c478bd9Sstevel@tonic-gate if (temp_reg != cmd_reg) { 39677c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, cmd_reg); 39687c478bd9Sstevel@tonic-gate } 39697c478bd9Sstevel@tonic-gate } 39707c478bd9Sstevel@tonic-gate 39717c478bd9Sstevel@tonic-gate /* 39727c478bd9Sstevel@tonic-gate * ehci print functions 39737c478bd9Sstevel@tonic-gate */ 39747c478bd9Sstevel@tonic-gate 39757c478bd9Sstevel@tonic-gate /* 39767c478bd9Sstevel@tonic-gate * ehci_print_caps: 39777c478bd9Sstevel@tonic-gate */ 39787c478bd9Sstevel@tonic-gate void 39797c478bd9Sstevel@tonic-gate ehci_print_caps(ehci_state_t *ehcip) 39807c478bd9Sstevel@tonic-gate { 39817c478bd9Sstevel@tonic-gate uint_t i; 39827c478bd9Sstevel@tonic-gate 39837c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39847c478bd9Sstevel@tonic-gate "\n\tUSB 2.0 Host Controller Characteristics\n"); 39857c478bd9Sstevel@tonic-gate 39867c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39877c478bd9Sstevel@tonic-gate "Caps Length: 0x%x Version: 0x%x\n", 39887c478bd9Sstevel@tonic-gate Get_8Cap(ehci_caps_length), Get_16Cap(ehci_version)); 39897c478bd9Sstevel@tonic-gate 39907c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39917c478bd9Sstevel@tonic-gate "Structural Parameters\n"); 39927c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39937c478bd9Sstevel@tonic-gate "Port indicators: %s", (Get_Cap(ehci_hcs_params) & 39947c478bd9Sstevel@tonic-gate EHCI_HCS_PORT_INDICATOR) ? "Yes" : "No"); 39957c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 39967c478bd9Sstevel@tonic-gate "No of Classic host controllers: 0x%x", 39977c478bd9Sstevel@tonic-gate (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_COMP_CTRLS) 39987c478bd9Sstevel@tonic-gate >> EHCI_HCS_NUM_COMP_CTRL_SHIFT); 39997c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40007c478bd9Sstevel@tonic-gate "No of ports per Classic host controller: 0x%x", 40017c478bd9Sstevel@tonic-gate (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS_CC) 40027c478bd9Sstevel@tonic-gate >> EHCI_HCS_NUM_PORTS_CC_SHIFT); 40037c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40047c478bd9Sstevel@tonic-gate "Port routing rules: %s", (Get_Cap(ehci_hcs_params) & 40057c478bd9Sstevel@tonic-gate EHCI_HCS_PORT_ROUTING_RULES) ? "Yes" : "No"); 40067c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40077c478bd9Sstevel@tonic-gate "Port power control: %s", (Get_Cap(ehci_hcs_params) & 40087c478bd9Sstevel@tonic-gate EHCI_HCS_PORT_POWER_CONTROL) ? "Yes" : "No"); 40097c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40107c478bd9Sstevel@tonic-gate "No of root hub ports: 0x%x\n", 40117c478bd9Sstevel@tonic-gate Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); 40127c478bd9Sstevel@tonic-gate 40137c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40147c478bd9Sstevel@tonic-gate "Capability Parameters\n"); 40157c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40167c478bd9Sstevel@tonic-gate "EHCI extended capability: %s", (Get_Cap(ehci_hcc_params) & 40177c478bd9Sstevel@tonic-gate EHCI_HCC_EECP) ? "Yes" : "No"); 40187c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40197c478bd9Sstevel@tonic-gate "Isoch schedule threshold: 0x%x", 40207c478bd9Sstevel@tonic-gate Get_Cap(ehci_hcc_params) & EHCI_HCC_ISOCH_SCHED_THRESHOLD); 40217c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40227c478bd9Sstevel@tonic-gate "Async schedule park capability: %s", (Get_Cap(ehci_hcc_params) & 40237c478bd9Sstevel@tonic-gate EHCI_HCC_ASYNC_SCHED_PARK_CAP) ? "Yes" : "No"); 40247c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40257c478bd9Sstevel@tonic-gate "Programmable frame list flag: %s", (Get_Cap(ehci_hcc_params) & 40267c478bd9Sstevel@tonic-gate EHCI_HCC_PROG_FRAME_LIST_FLAG) ? "256/512/1024" : "1024"); 40277c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40287c478bd9Sstevel@tonic-gate "64bit addressing capability: %s\n", (Get_Cap(ehci_hcc_params) & 40297c478bd9Sstevel@tonic-gate EHCI_HCC_64BIT_ADDR_CAP) ? "Yes" : "No"); 40307c478bd9Sstevel@tonic-gate 40317c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40327c478bd9Sstevel@tonic-gate "Classic Port Route Description"); 40337c478bd9Sstevel@tonic-gate 40347c478bd9Sstevel@tonic-gate for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) { 40357c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40367c478bd9Sstevel@tonic-gate "\tPort Route 0x%x: 0x%x", i, Get_8Cap(ehci_port_route[i])); 40377c478bd9Sstevel@tonic-gate } 40387c478bd9Sstevel@tonic-gate } 40397c478bd9Sstevel@tonic-gate 40407c478bd9Sstevel@tonic-gate 40417c478bd9Sstevel@tonic-gate /* 40427c478bd9Sstevel@tonic-gate * ehci_print_regs: 40437c478bd9Sstevel@tonic-gate */ 40447c478bd9Sstevel@tonic-gate void 40457c478bd9Sstevel@tonic-gate ehci_print_regs(ehci_state_t *ehcip) 40467c478bd9Sstevel@tonic-gate { 40477c478bd9Sstevel@tonic-gate uint_t i; 40487c478bd9Sstevel@tonic-gate 40497c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40507c478bd9Sstevel@tonic-gate "\n\tEHCI%d Operational Registers\n", 40517c478bd9Sstevel@tonic-gate ddi_get_instance(ehcip->ehci_dip)); 40527c478bd9Sstevel@tonic-gate 40537c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40547c478bd9Sstevel@tonic-gate "Command: 0x%x Status: 0x%x", 40557c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command), Get_OpReg(ehci_status)); 40567c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40577c478bd9Sstevel@tonic-gate "Interrupt: 0x%x Frame Index: 0x%x", 40587c478bd9Sstevel@tonic-gate Get_OpReg(ehci_interrupt), Get_OpReg(ehci_frame_index)); 40597c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40607c478bd9Sstevel@tonic-gate "Control Segment: 0x%x Periodic List Base: 0x%x", 40617c478bd9Sstevel@tonic-gate Get_OpReg(ehci_ctrl_segment), Get_OpReg(ehci_periodic_list_base)); 40627c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40637c478bd9Sstevel@tonic-gate "Async List Addr: 0x%x Config Flag: 0x%x", 40647c478bd9Sstevel@tonic-gate Get_OpReg(ehci_async_list_addr), Get_OpReg(ehci_config_flag)); 40657c478bd9Sstevel@tonic-gate 40667c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40677c478bd9Sstevel@tonic-gate "Root Hub Port Status"); 40687c478bd9Sstevel@tonic-gate 40697c478bd9Sstevel@tonic-gate for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) { 40707c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40717c478bd9Sstevel@tonic-gate "\tPort Status 0x%x: 0x%x ", i, 40727c478bd9Sstevel@tonic-gate Get_OpReg(ehci_rh_port_status[i])); 40737c478bd9Sstevel@tonic-gate } 40747c478bd9Sstevel@tonic-gate } 40757c478bd9Sstevel@tonic-gate 40767c478bd9Sstevel@tonic-gate 40777c478bd9Sstevel@tonic-gate /* 40787c478bd9Sstevel@tonic-gate * ehci_print_qh: 40797c478bd9Sstevel@tonic-gate */ 40807c478bd9Sstevel@tonic-gate void 40817c478bd9Sstevel@tonic-gate ehci_print_qh( 40827c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 40837c478bd9Sstevel@tonic-gate ehci_qh_t *qh) 40847c478bd9Sstevel@tonic-gate { 40857c478bd9Sstevel@tonic-gate uint_t i; 40867c478bd9Sstevel@tonic-gate 40877c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40887c478bd9Sstevel@tonic-gate "ehci_print_qh: qh = 0x%p", (void *)qh); 40897c478bd9Sstevel@tonic-gate 40907c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40917c478bd9Sstevel@tonic-gate "\tqh_link_ptr: 0x%x ", Get_QH(qh->qh_link_ptr)); 40927c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40937c478bd9Sstevel@tonic-gate "\tqh_ctrl: 0x%x ", Get_QH(qh->qh_ctrl)); 40947c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40957c478bd9Sstevel@tonic-gate "\tqh_split_ctrl: 0x%x ", Get_QH(qh->qh_split_ctrl)); 40967c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40977c478bd9Sstevel@tonic-gate "\tqh_curr_qtd: 0x%x ", Get_QH(qh->qh_curr_qtd)); 40987c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 40997c478bd9Sstevel@tonic-gate "\tqh_next_qtd: 0x%x ", Get_QH(qh->qh_next_qtd)); 41007c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41017c478bd9Sstevel@tonic-gate "\tqh_alt_next_qtd: 0x%x ", Get_QH(qh->qh_alt_next_qtd)); 41027c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41037c478bd9Sstevel@tonic-gate "\tqh_status: 0x%x ", Get_QH(qh->qh_status)); 41047c478bd9Sstevel@tonic-gate 41057c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 41067c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41077c478bd9Sstevel@tonic-gate "\tqh_buf[%d]: 0x%x ", i, Get_QH(qh->qh_buf[i])); 41087c478bd9Sstevel@tonic-gate } 41097c478bd9Sstevel@tonic-gate 41107c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 41117c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41127c478bd9Sstevel@tonic-gate "\tqh_buf_high[%d]: 0x%x ", 41137c478bd9Sstevel@tonic-gate i, Get_QH(qh->qh_buf_high[i])); 41147c478bd9Sstevel@tonic-gate } 41157c478bd9Sstevel@tonic-gate 41167c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41177c478bd9Sstevel@tonic-gate "\tqh_dummy_qtd: 0x%x ", Get_QH(qh->qh_dummy_qtd)); 41187c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41197c478bd9Sstevel@tonic-gate "\tqh_prev: 0x%x ", Get_QH(qh->qh_prev)); 41207c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41217c478bd9Sstevel@tonic-gate "\tqh_state: 0x%x ", Get_QH(qh->qh_state)); 41227c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41237c478bd9Sstevel@tonic-gate "\tqh_reclaim_next: 0x%x ", Get_QH(qh->qh_reclaim_next)); 41247c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41257c478bd9Sstevel@tonic-gate "\tqh_reclaim_frame: 0x%x ", Get_QH(qh->qh_reclaim_frame)); 41267c478bd9Sstevel@tonic-gate } 41277c478bd9Sstevel@tonic-gate 41287c478bd9Sstevel@tonic-gate 41297c478bd9Sstevel@tonic-gate /* 41307c478bd9Sstevel@tonic-gate * ehci_print_qtd: 41317c478bd9Sstevel@tonic-gate */ 41327c478bd9Sstevel@tonic-gate void 41337c478bd9Sstevel@tonic-gate ehci_print_qtd( 41347c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 41357c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd) 41367c478bd9Sstevel@tonic-gate { 41377c478bd9Sstevel@tonic-gate uint_t i; 41387c478bd9Sstevel@tonic-gate 41397c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41407c478bd9Sstevel@tonic-gate "ehci_print_qtd: qtd = 0x%p", (void *)qtd); 41417c478bd9Sstevel@tonic-gate 41427c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41437c478bd9Sstevel@tonic-gate "\tqtd_next_qtd: 0x%x ", Get_QTD(qtd->qtd_next_qtd)); 41447c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41457c478bd9Sstevel@tonic-gate "\tqtd_alt_next_qtd: 0x%x ", Get_QTD(qtd->qtd_alt_next_qtd)); 41467c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41477c478bd9Sstevel@tonic-gate "\tqtd_ctrl: 0x%x ", Get_QTD(qtd->qtd_ctrl)); 41487c478bd9Sstevel@tonic-gate 41497c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 41507c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41517c478bd9Sstevel@tonic-gate "\tqtd_buf[%d]: 0x%x ", i, Get_QTD(qtd->qtd_buf[i])); 41527c478bd9Sstevel@tonic-gate } 41537c478bd9Sstevel@tonic-gate 41547c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 41557c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41567c478bd9Sstevel@tonic-gate "\tqtd_buf_high[%d]: 0x%x ", 41577c478bd9Sstevel@tonic-gate i, Get_QTD(qtd->qtd_buf_high[i])); 41587c478bd9Sstevel@tonic-gate } 41597c478bd9Sstevel@tonic-gate 41607c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41617c478bd9Sstevel@tonic-gate "\tqtd_trans_wrapper: 0x%x ", Get_QTD(qtd->qtd_trans_wrapper)); 41627c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41637c478bd9Sstevel@tonic-gate "\tqtd_tw_next_qtd: 0x%x ", Get_QTD(qtd->qtd_tw_next_qtd)); 41647c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41657c478bd9Sstevel@tonic-gate "\tqtd_active_qtd_next: 0x%x ", Get_QTD(qtd->qtd_active_qtd_next)); 41667c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41677c478bd9Sstevel@tonic-gate "\tqtd_active_qtd_prev: 0x%x ", Get_QTD(qtd->qtd_active_qtd_prev)); 41687c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41697c478bd9Sstevel@tonic-gate "\tqtd_state: 0x%x ", Get_QTD(qtd->qtd_state)); 41707c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41717c478bd9Sstevel@tonic-gate "\tqtd_ctrl_phase: 0x%x ", Get_QTD(qtd->qtd_ctrl_phase)); 41727c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41733304303fSsl "\tqtd_xfer_offs: 0x%x ", Get_QTD(qtd->qtd_xfer_offs)); 41747c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41757c478bd9Sstevel@tonic-gate "\tqtd_xfer_len: 0x%x ", Get_QTD(qtd->qtd_xfer_len)); 41767c478bd9Sstevel@tonic-gate } 41777c478bd9Sstevel@tonic-gate 41787c478bd9Sstevel@tonic-gate /* 41797c478bd9Sstevel@tonic-gate * ehci kstat functions 41807c478bd9Sstevel@tonic-gate */ 41817c478bd9Sstevel@tonic-gate 41827c478bd9Sstevel@tonic-gate /* 41837c478bd9Sstevel@tonic-gate * ehci_create_stats: 41847c478bd9Sstevel@tonic-gate * 41857c478bd9Sstevel@tonic-gate * Allocate and initialize the ehci kstat structures 41867c478bd9Sstevel@tonic-gate */ 41877c478bd9Sstevel@tonic-gate void 41887c478bd9Sstevel@tonic-gate ehci_create_stats(ehci_state_t *ehcip) 41897c478bd9Sstevel@tonic-gate { 41907c478bd9Sstevel@tonic-gate char kstatname[KSTAT_STRLEN]; 41917c478bd9Sstevel@tonic-gate const char *dname = ddi_driver_name(ehcip->ehci_dip); 41927c478bd9Sstevel@tonic-gate char *usbtypes[USB_N_COUNT_KSTATS] = 41937c478bd9Sstevel@tonic-gate {"ctrl", "isoch", "bulk", "intr"}; 41947c478bd9Sstevel@tonic-gate uint_t instance = ehcip->ehci_instance; 41957c478bd9Sstevel@tonic-gate ehci_intrs_stats_t *isp; 41967c478bd9Sstevel@tonic-gate int i; 41977c478bd9Sstevel@tonic-gate 41987c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip) == NULL) { 41997c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,intrs", 42007c478bd9Sstevel@tonic-gate dname, instance); 42017c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip) = kstat_create("usba", instance, 42027c478bd9Sstevel@tonic-gate kstatname, "usb_interrupts", KSTAT_TYPE_NAMED, 42037c478bd9Sstevel@tonic-gate sizeof (ehci_intrs_stats_t) / sizeof (kstat_named_t), 42047c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 42057c478bd9Sstevel@tonic-gate 42067c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) { 42077c478bd9Sstevel@tonic-gate isp = EHCI_INTRS_STATS_DATA(ehcip); 42087c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_total, 42097c478bd9Sstevel@tonic-gate "Interrupts Total", KSTAT_DATA_UINT64); 42107c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_not_claimed, 42117c478bd9Sstevel@tonic-gate "Not Claimed", KSTAT_DATA_UINT64); 42127c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_async_sched_status, 42137c478bd9Sstevel@tonic-gate "Async schedule status", KSTAT_DATA_UINT64); 42147c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_periodic_sched_status, 42157c478bd9Sstevel@tonic-gate "Periodic sched status", KSTAT_DATA_UINT64); 42167c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_empty_async_schedule, 42177c478bd9Sstevel@tonic-gate "Empty async schedule", KSTAT_DATA_UINT64); 42187c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_host_ctrl_halted, 42197c478bd9Sstevel@tonic-gate "Host controller Halted", KSTAT_DATA_UINT64); 42207c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_async_advance_intr, 42217c478bd9Sstevel@tonic-gate "Intr on async advance", KSTAT_DATA_UINT64); 42227c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_host_system_error_intr, 42237c478bd9Sstevel@tonic-gate "Host system error", KSTAT_DATA_UINT64); 42247c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_frm_list_rollover_intr, 42257c478bd9Sstevel@tonic-gate "Frame list rollover", KSTAT_DATA_UINT64); 42267c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_rh_port_change_intr, 42277c478bd9Sstevel@tonic-gate "Port change detect", KSTAT_DATA_UINT64); 42287c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_usb_error_intr, 42297c478bd9Sstevel@tonic-gate "USB error interrupt", KSTAT_DATA_UINT64); 42307c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_usb_intr, 42317c478bd9Sstevel@tonic-gate "USB interrupt", KSTAT_DATA_UINT64); 42327c478bd9Sstevel@tonic-gate 42337c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip)->ks_private = ehcip; 42347c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip)->ks_update = nulldev; 42357c478bd9Sstevel@tonic-gate kstat_install(EHCI_INTRS_STATS(ehcip)); 42367c478bd9Sstevel@tonic-gate } 42377c478bd9Sstevel@tonic-gate } 42387c478bd9Sstevel@tonic-gate 42397c478bd9Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip) == NULL) { 42407c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,total", 42417c478bd9Sstevel@tonic-gate dname, instance); 42427c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS(ehcip) = kstat_create("usba", instance, 42437c478bd9Sstevel@tonic-gate kstatname, "usb_byte_count", KSTAT_TYPE_IO, 1, 42447c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 42457c478bd9Sstevel@tonic-gate 42467c478bd9Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip)) { 42477c478bd9Sstevel@tonic-gate kstat_install(EHCI_TOTAL_STATS(ehcip)); 42487c478bd9Sstevel@tonic-gate } 42497c478bd9Sstevel@tonic-gate } 42507c478bd9Sstevel@tonic-gate 42517c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) { 42527c478bd9Sstevel@tonic-gate if (ehcip->ehci_count_stats[i] == NULL) { 42537c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,%s", 42547c478bd9Sstevel@tonic-gate dname, instance, usbtypes[i]); 42557c478bd9Sstevel@tonic-gate ehcip->ehci_count_stats[i] = kstat_create("usba", 42567c478bd9Sstevel@tonic-gate instance, kstatname, "usb_byte_count", 42577c478bd9Sstevel@tonic-gate KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT); 42587c478bd9Sstevel@tonic-gate 42597c478bd9Sstevel@tonic-gate if (ehcip->ehci_count_stats[i]) { 42607c478bd9Sstevel@tonic-gate kstat_install(ehcip->ehci_count_stats[i]); 42617c478bd9Sstevel@tonic-gate } 42627c478bd9Sstevel@tonic-gate } 42637c478bd9Sstevel@tonic-gate } 42647c478bd9Sstevel@tonic-gate } 42657c478bd9Sstevel@tonic-gate 42667c478bd9Sstevel@tonic-gate 42677c478bd9Sstevel@tonic-gate /* 42687c478bd9Sstevel@tonic-gate * ehci_destroy_stats: 42697c478bd9Sstevel@tonic-gate * 42707c478bd9Sstevel@tonic-gate * Clean up ehci kstat structures 42717c478bd9Sstevel@tonic-gate */ 42727c478bd9Sstevel@tonic-gate void 42737c478bd9Sstevel@tonic-gate ehci_destroy_stats(ehci_state_t *ehcip) 42747c478bd9Sstevel@tonic-gate { 42757c478bd9Sstevel@tonic-gate int i; 42767c478bd9Sstevel@tonic-gate 42777c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) { 42787c478bd9Sstevel@tonic-gate kstat_delete(EHCI_INTRS_STATS(ehcip)); 42797c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip) = NULL; 42807c478bd9Sstevel@tonic-gate } 42817c478bd9Sstevel@tonic-gate 42827c478bd9Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip)) { 42837c478bd9Sstevel@tonic-gate kstat_delete(EHCI_TOTAL_STATS(ehcip)); 42847c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS(ehcip) = NULL; 42857c478bd9Sstevel@tonic-gate } 42867c478bd9Sstevel@tonic-gate 42877c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) { 42887c478bd9Sstevel@tonic-gate if (ehcip->ehci_count_stats[i]) { 42897c478bd9Sstevel@tonic-gate kstat_delete(ehcip->ehci_count_stats[i]); 42907c478bd9Sstevel@tonic-gate ehcip->ehci_count_stats[i] = NULL; 42917c478bd9Sstevel@tonic-gate } 42927c478bd9Sstevel@tonic-gate } 42937c478bd9Sstevel@tonic-gate } 42947c478bd9Sstevel@tonic-gate 42957c478bd9Sstevel@tonic-gate 42967c478bd9Sstevel@tonic-gate /* 42977c478bd9Sstevel@tonic-gate * ehci_do_intrs_stats: 42987c478bd9Sstevel@tonic-gate * 42997c478bd9Sstevel@tonic-gate * ehci status information 43007c478bd9Sstevel@tonic-gate */ 43017c478bd9Sstevel@tonic-gate void 43027c478bd9Sstevel@tonic-gate ehci_do_intrs_stats( 43037c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 43047c478bd9Sstevel@tonic-gate int val) 43057c478bd9Sstevel@tonic-gate { 43067c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) { 43077c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->ehci_sts_total.value.ui64++; 43087c478bd9Sstevel@tonic-gate switch (val) { 43097c478bd9Sstevel@tonic-gate case EHCI_STS_ASYNC_SCHED_STATUS: 43107c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 43117c478bd9Sstevel@tonic-gate ehci_sts_async_sched_status.value.ui64++; 43127c478bd9Sstevel@tonic-gate break; 43137c478bd9Sstevel@tonic-gate case EHCI_STS_PERIODIC_SCHED_STATUS: 43147c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 43157c478bd9Sstevel@tonic-gate ehci_sts_periodic_sched_status.value.ui64++; 43167c478bd9Sstevel@tonic-gate break; 43177c478bd9Sstevel@tonic-gate case EHCI_STS_EMPTY_ASYNC_SCHEDULE: 43187c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 43197c478bd9Sstevel@tonic-gate ehci_sts_empty_async_schedule.value.ui64++; 43207c478bd9Sstevel@tonic-gate break; 43217c478bd9Sstevel@tonic-gate case EHCI_STS_HOST_CTRL_HALTED: 43227c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 43237c478bd9Sstevel@tonic-gate ehci_sts_host_ctrl_halted.value.ui64++; 43247c478bd9Sstevel@tonic-gate break; 43257c478bd9Sstevel@tonic-gate case EHCI_STS_ASYNC_ADVANCE_INTR: 43267c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 43277c478bd9Sstevel@tonic-gate ehci_sts_async_advance_intr.value.ui64++; 43287c478bd9Sstevel@tonic-gate break; 43297c478bd9Sstevel@tonic-gate case EHCI_STS_HOST_SYSTEM_ERROR_INTR: 43307c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 43317c478bd9Sstevel@tonic-gate ehci_sts_host_system_error_intr.value.ui64++; 43327c478bd9Sstevel@tonic-gate break; 43337c478bd9Sstevel@tonic-gate case EHCI_STS_FRM_LIST_ROLLOVER_INTR: 43347c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 43357c478bd9Sstevel@tonic-gate ehci_sts_frm_list_rollover_intr.value.ui64++; 43367c478bd9Sstevel@tonic-gate break; 43377c478bd9Sstevel@tonic-gate case EHCI_STS_RH_PORT_CHANGE_INTR: 43387c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 43397c478bd9Sstevel@tonic-gate ehci_sts_rh_port_change_intr.value.ui64++; 43407c478bd9Sstevel@tonic-gate break; 43417c478bd9Sstevel@tonic-gate case EHCI_STS_USB_ERROR_INTR: 43427c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 43437c478bd9Sstevel@tonic-gate ehci_sts_usb_error_intr.value.ui64++; 43447c478bd9Sstevel@tonic-gate break; 43457c478bd9Sstevel@tonic-gate case EHCI_STS_USB_INTR: 43467c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 43477c478bd9Sstevel@tonic-gate ehci_sts_usb_intr.value.ui64++; 43487c478bd9Sstevel@tonic-gate break; 43497c478bd9Sstevel@tonic-gate default: 43507c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 43517c478bd9Sstevel@tonic-gate ehci_sts_not_claimed.value.ui64++; 43527c478bd9Sstevel@tonic-gate break; 43537c478bd9Sstevel@tonic-gate } 43547c478bd9Sstevel@tonic-gate } 43557c478bd9Sstevel@tonic-gate } 43567c478bd9Sstevel@tonic-gate 43577c478bd9Sstevel@tonic-gate 43587c478bd9Sstevel@tonic-gate /* 43597c478bd9Sstevel@tonic-gate * ehci_do_byte_stats: 43607c478bd9Sstevel@tonic-gate * 43617c478bd9Sstevel@tonic-gate * ehci data xfer information 43627c478bd9Sstevel@tonic-gate */ 43637c478bd9Sstevel@tonic-gate void 43647c478bd9Sstevel@tonic-gate ehci_do_byte_stats( 43657c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 43667c478bd9Sstevel@tonic-gate size_t len, 43677c478bd9Sstevel@tonic-gate uint8_t attr, 43687c478bd9Sstevel@tonic-gate uint8_t addr) 43697c478bd9Sstevel@tonic-gate { 43707c478bd9Sstevel@tonic-gate uint8_t type = attr & USB_EP_ATTR_MASK; 43717c478bd9Sstevel@tonic-gate uint8_t dir = addr & USB_EP_DIR_MASK; 43727c478bd9Sstevel@tonic-gate 43737c478bd9Sstevel@tonic-gate if (dir == USB_EP_DIR_IN) { 43747c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->reads++; 43757c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->nread += len; 43767c478bd9Sstevel@tonic-gate switch (type) { 43777c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 43787c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->reads++; 43797c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->nread += len; 43807c478bd9Sstevel@tonic-gate break; 43817c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 43827c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->reads++; 43837c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->nread += len; 43847c478bd9Sstevel@tonic-gate break; 43857c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 43867c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->reads++; 43877c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->nread += len; 43887c478bd9Sstevel@tonic-gate break; 43897c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 43907c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->reads++; 43917c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->nread += len; 43927c478bd9Sstevel@tonic-gate break; 43937c478bd9Sstevel@tonic-gate } 43947c478bd9Sstevel@tonic-gate } else if (dir == USB_EP_DIR_OUT) { 43957c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->writes++; 43967c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->nwritten += len; 43977c478bd9Sstevel@tonic-gate switch (type) { 43987c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 43997c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->writes++; 44007c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->nwritten += len; 44017c478bd9Sstevel@tonic-gate break; 44027c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 44037c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->writes++; 44047c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->nwritten += len; 44057c478bd9Sstevel@tonic-gate break; 44067c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 44077c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->writes++; 44087c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->nwritten += len; 44097c478bd9Sstevel@tonic-gate break; 44107c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 44117c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->writes++; 44127c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->nwritten += len; 44137c478bd9Sstevel@tonic-gate break; 44147c478bd9Sstevel@tonic-gate } 44157c478bd9Sstevel@tonic-gate } 44167c478bd9Sstevel@tonic-gate } 4417