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 /* 22*29aca3ebSlc * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #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; 572df1fe9cSrandyf extern int force_ehci_off; 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate /* Adjustable variables for the size of the pools */ 607c478bd9Sstevel@tonic-gate int ehci_qh_pool_size = EHCI_QH_POOL_SIZE; 617c478bd9Sstevel@tonic-gate int ehci_qtd_pool_size = EHCI_QTD_POOL_SIZE; 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate /* 647c478bd9Sstevel@tonic-gate * Initialize the values which the order of 32ms intr qh are executed 657c478bd9Sstevel@tonic-gate * by the host controller in the lattice tree. 667c478bd9Sstevel@tonic-gate */ 677c478bd9Sstevel@tonic-gate static uchar_t ehci_index[EHCI_NUM_INTR_QH_LISTS] = 687c478bd9Sstevel@tonic-gate {0x00, 0x10, 0x08, 0x18, 697c478bd9Sstevel@tonic-gate 0x04, 0x14, 0x0c, 0x1c, 707c478bd9Sstevel@tonic-gate 0x02, 0x12, 0x0a, 0x1a, 717c478bd9Sstevel@tonic-gate 0x06, 0x16, 0x0e, 0x1e, 727c478bd9Sstevel@tonic-gate 0x01, 0x11, 0x09, 0x19, 737c478bd9Sstevel@tonic-gate 0x05, 0x15, 0x0d, 0x1d, 747c478bd9Sstevel@tonic-gate 0x03, 0x13, 0x0b, 0x1b, 757c478bd9Sstevel@tonic-gate 0x07, 0x17, 0x0f, 0x1f}; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate /* 787c478bd9Sstevel@tonic-gate * Initialize the values which are used to calculate start split mask 797c478bd9Sstevel@tonic-gate * for the low/full/high speed interrupt and isochronous endpoints. 807c478bd9Sstevel@tonic-gate */ 817c478bd9Sstevel@tonic-gate static uint_t ehci_start_split_mask[15] = { 827c478bd9Sstevel@tonic-gate /* 837c478bd9Sstevel@tonic-gate * For high/full/low speed usb devices. For high speed 847c478bd9Sstevel@tonic-gate * device with polling interval greater than or equal 857c478bd9Sstevel@tonic-gate * to 8us (125us). 867c478bd9Sstevel@tonic-gate */ 877c478bd9Sstevel@tonic-gate 0x01, /* 00000001 */ 887c478bd9Sstevel@tonic-gate 0x02, /* 00000010 */ 897c478bd9Sstevel@tonic-gate 0x04, /* 00000100 */ 907c478bd9Sstevel@tonic-gate 0x08, /* 00001000 */ 917c478bd9Sstevel@tonic-gate 0x10, /* 00010000 */ 927c478bd9Sstevel@tonic-gate 0x20, /* 00100000 */ 937c478bd9Sstevel@tonic-gate 0x40, /* 01000000 */ 947c478bd9Sstevel@tonic-gate 0x80, /* 10000000 */ 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate /* Only for high speed devices with polling interval 4us */ 977c478bd9Sstevel@tonic-gate 0x11, /* 00010001 */ 987c478bd9Sstevel@tonic-gate 0x22, /* 00100010 */ 997c478bd9Sstevel@tonic-gate 0x44, /* 01000100 */ 1007c478bd9Sstevel@tonic-gate 0x88, /* 10001000 */ 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate /* Only for high speed devices with polling interval 2us */ 1037c478bd9Sstevel@tonic-gate 0x55, /* 01010101 */ 1047c478bd9Sstevel@tonic-gate 0xaa, /* 10101010 */ 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /* Only for high speed devices with polling interval 1us */ 1077c478bd9Sstevel@tonic-gate 0xff /* 11111111 */ 1087c478bd9Sstevel@tonic-gate }; 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate /* 1117c478bd9Sstevel@tonic-gate * Initialize the values which are used to calculate complete split mask 1127c478bd9Sstevel@tonic-gate * for the low/full speed interrupt and isochronous endpoints. 1137c478bd9Sstevel@tonic-gate */ 1147c478bd9Sstevel@tonic-gate static uint_t ehci_intr_complete_split_mask[7] = { 1157c478bd9Sstevel@tonic-gate /* Only full/low speed devices */ 1167c478bd9Sstevel@tonic-gate 0x1c, /* 00011100 */ 1177c478bd9Sstevel@tonic-gate 0x38, /* 00111000 */ 1187c478bd9Sstevel@tonic-gate 0x70, /* 01110000 */ 1197c478bd9Sstevel@tonic-gate 0xe0, /* 11100000 */ 1207c478bd9Sstevel@tonic-gate 0x00, /* Need FSTN feature */ 1217c478bd9Sstevel@tonic-gate 0x00, /* Need FSTN feature */ 1227c478bd9Sstevel@tonic-gate 0x00 /* Need FSTN feature */ 1237c478bd9Sstevel@tonic-gate }; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate /* 1277c478bd9Sstevel@tonic-gate * EHCI Internal Function Prototypes 1287c478bd9Sstevel@tonic-gate */ 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) initialization functions */ 1317c478bd9Sstevel@tonic-gate void ehci_set_dma_attributes(ehci_state_t *ehcip); 1327c478bd9Sstevel@tonic-gate int ehci_allocate_pools(ehci_state_t *ehcip); 1337c478bd9Sstevel@tonic-gate void ehci_decode_ddi_dma_addr_bind_handle_result( 1347c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1357c478bd9Sstevel@tonic-gate int result); 1367c478bd9Sstevel@tonic-gate int ehci_map_regs(ehci_state_t *ehcip); 1377c478bd9Sstevel@tonic-gate int ehci_register_intrs_and_init_mutex( 1387c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 1399c75c6bfSgovinda static int ehci_add_intrs(ehci_state_t *ehcip, 1409c75c6bfSgovinda int intr_type); 1413b00f311Syq int ehci_init_ctlr(ehci_state_t *ehcip, 1423b00f311Syq int init_type); 1437c478bd9Sstevel@tonic-gate static int ehci_take_control(ehci_state_t *ehcip); 1447c478bd9Sstevel@tonic-gate static int ehci_init_periodic_frame_lst_table( 1457c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 1467c478bd9Sstevel@tonic-gate static void ehci_build_interrupt_lattice( 1477c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 1487c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *ehci_alloc_hcdi_ops(ehci_state_t *ehcip); 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) deinitialization functions */ 1517c478bd9Sstevel@tonic-gate int ehci_cleanup(ehci_state_t *ehcip); 1529c75c6bfSgovinda static void ehci_rem_intrs(ehci_state_t *ehcip); 1537c478bd9Sstevel@tonic-gate int ehci_cpr_suspend(ehci_state_t *ehcip); 1547c478bd9Sstevel@tonic-gate int ehci_cpr_resume(ehci_state_t *ehcip); 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate /* Bandwidth Allocation functions */ 1577c478bd9Sstevel@tonic-gate int ehci_allocate_bandwidth(ehci_state_t *ehcip, 1587c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1597c478bd9Sstevel@tonic-gate uint_t *pnode, 1607c478bd9Sstevel@tonic-gate uchar_t *smask, 1617c478bd9Sstevel@tonic-gate uchar_t *cmask); 1627c478bd9Sstevel@tonic-gate static int ehci_allocate_high_speed_bandwidth( 1637c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1647c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1657c478bd9Sstevel@tonic-gate uint_t *hnode, 1667c478bd9Sstevel@tonic-gate uchar_t *smask, 1677c478bd9Sstevel@tonic-gate uchar_t *cmask); 1687c478bd9Sstevel@tonic-gate static int ehci_allocate_classic_tt_bandwidth( 1697c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1707c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1717c478bd9Sstevel@tonic-gate uint_t pnode); 1727c478bd9Sstevel@tonic-gate void ehci_deallocate_bandwidth(ehci_state_t *ehcip, 1737c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1747c478bd9Sstevel@tonic-gate uint_t pnode, 1757c478bd9Sstevel@tonic-gate uchar_t smask, 1767c478bd9Sstevel@tonic-gate uchar_t cmask); 1777c478bd9Sstevel@tonic-gate static void ehci_deallocate_high_speed_bandwidth( 1787c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1797c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1807c478bd9Sstevel@tonic-gate uint_t hnode, 1817c478bd9Sstevel@tonic-gate uchar_t smask, 1827c478bd9Sstevel@tonic-gate uchar_t cmask); 1837c478bd9Sstevel@tonic-gate static void ehci_deallocate_classic_tt_bandwidth( 1847c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1857c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 1867c478bd9Sstevel@tonic-gate uint_t pnode); 1877c478bd9Sstevel@tonic-gate static int ehci_compute_high_speed_bandwidth( 1887c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1897c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 1907c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 1917c478bd9Sstevel@tonic-gate uint_t *sbandwidth, 1927c478bd9Sstevel@tonic-gate uint_t *cbandwidth); 1937c478bd9Sstevel@tonic-gate static int ehci_compute_classic_bandwidth( 1947c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 1957c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 1967c478bd9Sstevel@tonic-gate uint_t *bandwidth); 1977c478bd9Sstevel@tonic-gate int ehci_adjust_polling_interval( 1987c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 1997c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 2007c478bd9Sstevel@tonic-gate usb_port_status_t port_status); 2017c478bd9Sstevel@tonic-gate static int ehci_adjust_high_speed_polling_interval( 2027c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2037c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint); 2047c478bd9Sstevel@tonic-gate static uint_t ehci_lattice_height(uint_t interval); 2057c478bd9Sstevel@tonic-gate static uint_t ehci_lattice_parent(uint_t node); 2067c478bd9Sstevel@tonic-gate static uint_t ehci_find_periodic_node( 2077c478bd9Sstevel@tonic-gate uint_t leaf, 2087c478bd9Sstevel@tonic-gate int interval); 2097c478bd9Sstevel@tonic-gate static uint_t ehci_leftmost_leaf(uint_t node, 2107c478bd9Sstevel@tonic-gate uint_t height); 2117c478bd9Sstevel@tonic-gate static uint_t ehci_pow_2(uint_t x); 2127c478bd9Sstevel@tonic-gate static uint_t ehci_log_2(uint_t x); 2137c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_hs_mask( 2147c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2157c478bd9Sstevel@tonic-gate uchar_t *smask, 2167c478bd9Sstevel@tonic-gate uint_t *pnode, 2177c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 2187c478bd9Sstevel@tonic-gate uint_t bandwidth, 2197c478bd9Sstevel@tonic-gate int interval); 2207c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_ls_intr_mask( 2217c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2227c478bd9Sstevel@tonic-gate uchar_t *smask, 2237c478bd9Sstevel@tonic-gate uchar_t *cmask, 2247c478bd9Sstevel@tonic-gate uint_t *pnode, 2257c478bd9Sstevel@tonic-gate uint_t sbandwidth, 2267c478bd9Sstevel@tonic-gate uint_t cbandwidth, 2277c478bd9Sstevel@tonic-gate int interval); 2287c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_sitd_in_mask( 2297c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2307c478bd9Sstevel@tonic-gate uchar_t *smask, 2317c478bd9Sstevel@tonic-gate uchar_t *cmask, 2327c478bd9Sstevel@tonic-gate uint_t *pnode, 2337c478bd9Sstevel@tonic-gate uint_t sbandwidth, 2347c478bd9Sstevel@tonic-gate uint_t cbandwidth, 2357c478bd9Sstevel@tonic-gate int interval); 2367c478bd9Sstevel@tonic-gate static int ehci_find_bestfit_sitd_out_mask( 2377c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2387c478bd9Sstevel@tonic-gate uchar_t *smask, 2397c478bd9Sstevel@tonic-gate uint_t *pnode, 2407c478bd9Sstevel@tonic-gate uint_t sbandwidth, 2417c478bd9Sstevel@tonic-gate int interval); 2427c478bd9Sstevel@tonic-gate static uint_t ehci_calculate_bw_availability_mask( 2437c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2447c478bd9Sstevel@tonic-gate uint_t bandwidth, 2457c478bd9Sstevel@tonic-gate int leaf, 2467c478bd9Sstevel@tonic-gate int leaf_count, 2477c478bd9Sstevel@tonic-gate uchar_t *bw_mask); 2487c478bd9Sstevel@tonic-gate static void ehci_update_bw_availability( 2497c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 2507c478bd9Sstevel@tonic-gate int bandwidth, 2517c478bd9Sstevel@tonic-gate int leftmost_leaf, 2527c478bd9Sstevel@tonic-gate int leaf_count, 2537c478bd9Sstevel@tonic-gate uchar_t mask); 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate /* Miscellaneous functions */ 2567c478bd9Sstevel@tonic-gate ehci_state_t *ehci_obtain_state( 2577c478bd9Sstevel@tonic-gate dev_info_t *dip); 2587c478bd9Sstevel@tonic-gate int ehci_state_is_operational( 2597c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2607c478bd9Sstevel@tonic-gate int ehci_do_soft_reset( 2617c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2627c478bd9Sstevel@tonic-gate usb_req_attrs_t ehci_get_xfer_attrs(ehci_state_t *ehcip, 2637c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 2647c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw); 2657c478bd9Sstevel@tonic-gate usb_frame_number_t ehci_get_current_frame_number( 2667c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2677c478bd9Sstevel@tonic-gate static void ehci_cpr_cleanup( 2687c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2697c478bd9Sstevel@tonic-gate int ehci_wait_for_sof( 2707c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2717c478bd9Sstevel@tonic-gate void ehci_toggle_scheduler( 2727c478bd9Sstevel@tonic-gate ehci_state_t *ehcip); 2737c478bd9Sstevel@tonic-gate void ehci_print_caps(ehci_state_t *ehcip); 2747c478bd9Sstevel@tonic-gate void ehci_print_regs(ehci_state_t *ehcip); 2757c478bd9Sstevel@tonic-gate void ehci_print_qh(ehci_state_t *ehcip, 2767c478bd9Sstevel@tonic-gate ehci_qh_t *qh); 2777c478bd9Sstevel@tonic-gate void ehci_print_qtd(ehci_state_t *ehcip, 2787c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd); 2797c478bd9Sstevel@tonic-gate void ehci_create_stats(ehci_state_t *ehcip); 2807c478bd9Sstevel@tonic-gate void ehci_destroy_stats(ehci_state_t *ehcip); 2817c478bd9Sstevel@tonic-gate void ehci_do_intrs_stats(ehci_state_t *ehcip, 2827c478bd9Sstevel@tonic-gate int val); 2837c478bd9Sstevel@tonic-gate void ehci_do_byte_stats(ehci_state_t *ehcip, 2847c478bd9Sstevel@tonic-gate size_t len, 2857c478bd9Sstevel@tonic-gate uint8_t attr, 2867c478bd9Sstevel@tonic-gate uint8_t addr); 2877c478bd9Sstevel@tonic-gate 2884610e4a0Sfrits /* 2894610e4a0Sfrits * check if this ehci controller can support PM 2904610e4a0Sfrits */ 2914610e4a0Sfrits int 2924610e4a0Sfrits ehci_hcdi_pm_support(dev_info_t *dip) 2934610e4a0Sfrits { 2944610e4a0Sfrits ehci_state_t *ehcip = ddi_get_soft_state(ehci_statep, 295*29aca3ebSlc ddi_get_instance(dip)); 2964610e4a0Sfrits 2974610e4a0Sfrits if (((ehcip->ehci_vendor_id == PCI_VENDOR_NEC_COMBO) && 2984610e4a0Sfrits (ehcip->ehci_device_id == PCI_DEVICE_NEC_COMBO)) || 2994610e4a0Sfrits 3004610e4a0Sfrits ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) && 3014610e4a0Sfrits (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) || 3024610e4a0Sfrits 3034610e4a0Sfrits (ehcip->ehci_vendor_id == PCI_VENDOR_VIA)) { 3044610e4a0Sfrits 3054610e4a0Sfrits return (USB_SUCCESS); 3064610e4a0Sfrits } 3074610e4a0Sfrits 3084610e4a0Sfrits return (USB_FAILURE); 3094610e4a0Sfrits } 3104610e4a0Sfrits 3114610e4a0Sfrits 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) initialization functions 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate /* 3177c478bd9Sstevel@tonic-gate * ehci_set_dma_attributes: 3187c478bd9Sstevel@tonic-gate * 3197c478bd9Sstevel@tonic-gate * Set the limits in the DMA attributes structure. Most of the values used 3207c478bd9Sstevel@tonic-gate * in the DMA limit structures are the default values as specified by the 3217c478bd9Sstevel@tonic-gate * Writing PCI device drivers document. 3227c478bd9Sstevel@tonic-gate */ 3237c478bd9Sstevel@tonic-gate void 3247c478bd9Sstevel@tonic-gate ehci_set_dma_attributes(ehci_state_t *ehcip) 3257c478bd9Sstevel@tonic-gate { 3267c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3277c478bd9Sstevel@tonic-gate "ehci_set_dma_attributes:"); 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* Initialize the DMA attributes */ 3307c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_version = DMA_ATTR_V0; 3317c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_addr_lo = 0x00000000ull; 3327c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_addr_hi = 0xfffffffeull; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate /* 32 bit addressing */ 3357c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_count_max = EHCI_DMA_ATTR_COUNT_MAX; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* Byte alignment */ 3387c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate /* 3417c478bd9Sstevel@tonic-gate * Since PCI specification is byte alignment, the 3427c478bd9Sstevel@tonic-gate * burst size field should be set to 1 for PCI devices. 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_burstsizes = 0x1; 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_minxfer = 0x1; 3477c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_maxxfer = EHCI_DMA_ATTR_MAX_XFER; 3487c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_seg = 0xffffffffull; 3497c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_sgllen = 1; 3507c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_granular = EHCI_DMA_ATTR_GRANULAR; 3517c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_flags = 0; 3527c478bd9Sstevel@tonic-gate } 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate /* 3567c478bd9Sstevel@tonic-gate * ehci_allocate_pools: 3577c478bd9Sstevel@tonic-gate * 3587c478bd9Sstevel@tonic-gate * Allocate the system memory for the Endpoint Descriptor (QH) and for the 3597c478bd9Sstevel@tonic-gate * Transfer Descriptor (QTD) pools. Both QH and QTD structures must be aligned 3607c478bd9Sstevel@tonic-gate * to a 16 byte boundary. 3617c478bd9Sstevel@tonic-gate */ 3627c478bd9Sstevel@tonic-gate int 3637c478bd9Sstevel@tonic-gate ehci_allocate_pools(ehci_state_t *ehcip) 3647c478bd9Sstevel@tonic-gate { 3657c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 3667c478bd9Sstevel@tonic-gate size_t real_length; 3677c478bd9Sstevel@tonic-gate int result; 3687c478bd9Sstevel@tonic-gate uint_t ccount; 3697c478bd9Sstevel@tonic-gate int i; 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3727c478bd9Sstevel@tonic-gate "ehci_allocate_pools:"); 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 3757c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 3767c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 3777c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate /* Byte alignment */ 3807c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_TD_QH_ALIGNMENT; 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate /* Allocate the QTD pool DMA handle */ 3837c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr, 384*29aca3ebSlc DDI_DMA_SLEEP, 0, 385*29aca3ebSlc &ehcip->ehci_qtd_pool_dma_handle) != DDI_SUCCESS) { 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate goto failure; 3887c478bd9Sstevel@tonic-gate } 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate /* Allocate the memory for the QTD pool */ 3917c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_qtd_pool_dma_handle, 392*29aca3ebSlc ehci_qtd_pool_size * sizeof (ehci_qtd_t), 393*29aca3ebSlc &dev_attr, 394*29aca3ebSlc DDI_DMA_CONSISTENT, 395*29aca3ebSlc DDI_DMA_SLEEP, 396*29aca3ebSlc 0, 397*29aca3ebSlc (caddr_t *)&ehcip->ehci_qtd_pool_addr, 398*29aca3ebSlc &real_length, 399*29aca3ebSlc &ehcip->ehci_qtd_pool_mem_handle)) { 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate goto failure; 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate /* Map the QTD pool into the I/O address space */ 4057c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle( 406*29aca3ebSlc ehcip->ehci_qtd_pool_dma_handle, 407*29aca3ebSlc NULL, 408*29aca3ebSlc (caddr_t)ehcip->ehci_qtd_pool_addr, 409*29aca3ebSlc real_length, 410*29aca3ebSlc DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 411*29aca3ebSlc DDI_DMA_SLEEP, 412*29aca3ebSlc NULL, 413*29aca3ebSlc &ehcip->ehci_qtd_pool_cookie, 414*29aca3ebSlc &ccount); 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate bzero((void *)ehcip->ehci_qtd_pool_addr, 417*29aca3ebSlc ehci_qtd_pool_size * sizeof (ehci_qtd_t)); 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate /* Process the result */ 4207c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 4217c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 4227c478bd9Sstevel@tonic-gate if (ccount != 1) { 4237c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 4247c478bd9Sstevel@tonic-gate "ehci_allocate_pools: More than 1 cookie"); 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate goto failure; 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate } else { 4297c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 4307c478bd9Sstevel@tonic-gate "ehci_allocate_pools: Result = %d", result); 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result); 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate goto failure; 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate /* 4387c478bd9Sstevel@tonic-gate * DMA addresses for QTD pools are bound 4397c478bd9Sstevel@tonic-gate */ 4407c478bd9Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_QTD_POOL_BOUND; 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate /* Initialize the QTD pool */ 4437c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_qtd_pool_size; i ++) { 4447c478bd9Sstevel@tonic-gate Set_QTD(ehcip->ehci_qtd_pool_addr[i]. 4457c478bd9Sstevel@tonic-gate qtd_state, EHCI_QTD_FREE); 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate /* Allocate the QTD pool DMA handle */ 4497c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip, 450*29aca3ebSlc &ehcip->ehci_dma_attr, 451*29aca3ebSlc DDI_DMA_SLEEP, 452*29aca3ebSlc 0, 453*29aca3ebSlc &ehcip->ehci_qh_pool_dma_handle) != DDI_SUCCESS) { 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate goto failure; 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate /* Allocate the memory for the QH pool */ 4597c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_qh_pool_dma_handle, 460*29aca3ebSlc ehci_qh_pool_size * sizeof (ehci_qh_t), 461*29aca3ebSlc &dev_attr, 462*29aca3ebSlc DDI_DMA_CONSISTENT, 463*29aca3ebSlc DDI_DMA_SLEEP, 464*29aca3ebSlc 0, 465*29aca3ebSlc (caddr_t *)&ehcip->ehci_qh_pool_addr, 466*29aca3ebSlc &real_length, 467*29aca3ebSlc &ehcip->ehci_qh_pool_mem_handle) != DDI_SUCCESS) { 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate goto failure; 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ehcip->ehci_qh_pool_dma_handle, 473*29aca3ebSlc NULL, 474*29aca3ebSlc (caddr_t)ehcip->ehci_qh_pool_addr, 475*29aca3ebSlc real_length, 476*29aca3ebSlc DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 477*29aca3ebSlc DDI_DMA_SLEEP, 478*29aca3ebSlc NULL, 479*29aca3ebSlc &ehcip->ehci_qh_pool_cookie, 480*29aca3ebSlc &ccount); 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate bzero((void *)ehcip->ehci_qh_pool_addr, 483*29aca3ebSlc ehci_qh_pool_size * sizeof (ehci_qh_t)); 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate /* Process the result */ 4867c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 4877c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 4887c478bd9Sstevel@tonic-gate if (ccount != 1) { 4897c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 4907c478bd9Sstevel@tonic-gate "ehci_allocate_pools: More than 1 cookie"); 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate goto failure; 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate } else { 4957c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result); 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate goto failure; 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate /* 5017c478bd9Sstevel@tonic-gate * DMA addresses for QH pools are bound 5027c478bd9Sstevel@tonic-gate */ 5037c478bd9Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_QH_POOL_BOUND; 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate /* Initialize the QH pool */ 5067c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_qh_pool_size; i ++) { 5077c478bd9Sstevel@tonic-gate Set_QH(ehcip->ehci_qh_pool_addr[i].qh_state, EHCI_QH_FREE); 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* Byte alignment */ 5117c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate failure: 5167c478bd9Sstevel@tonic-gate /* Byte alignment */ 5177c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate /* 5247c478bd9Sstevel@tonic-gate * ehci_decode_ddi_dma_addr_bind_handle_result: 5257c478bd9Sstevel@tonic-gate * 5267c478bd9Sstevel@tonic-gate * Process the return values of ddi_dma_addr_bind_handle() 5277c478bd9Sstevel@tonic-gate */ 5287c478bd9Sstevel@tonic-gate void 5297c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result( 5307c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 5317c478bd9Sstevel@tonic-gate int result) 5327c478bd9Sstevel@tonic-gate { 5337c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl, 5347c478bd9Sstevel@tonic-gate "ehci_decode_ddi_dma_addr_bind_handle_result:"); 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate switch (result) { 5377c478bd9Sstevel@tonic-gate case DDI_DMA_PARTIAL_MAP: 5387c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5397c478bd9Sstevel@tonic-gate "Partial transfers not allowed"); 5407c478bd9Sstevel@tonic-gate break; 5417c478bd9Sstevel@tonic-gate case DDI_DMA_INUSE: 5427c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5437c478bd9Sstevel@tonic-gate "Handle is in use"); 5447c478bd9Sstevel@tonic-gate break; 5457c478bd9Sstevel@tonic-gate case DDI_DMA_NORESOURCES: 5467c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5477c478bd9Sstevel@tonic-gate "No resources"); 5487c478bd9Sstevel@tonic-gate break; 5497c478bd9Sstevel@tonic-gate case DDI_DMA_NOMAPPING: 5507c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5517c478bd9Sstevel@tonic-gate "No mapping"); 5527c478bd9Sstevel@tonic-gate break; 5537c478bd9Sstevel@tonic-gate case DDI_DMA_TOOBIG: 5547c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5557c478bd9Sstevel@tonic-gate "Object is too big"); 5567c478bd9Sstevel@tonic-gate break; 5577c478bd9Sstevel@tonic-gate default: 5587c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl, 5597c478bd9Sstevel@tonic-gate "Unknown dma error"); 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate } 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate /* 5657c478bd9Sstevel@tonic-gate * ehci_map_regs: 5667c478bd9Sstevel@tonic-gate * 5677c478bd9Sstevel@tonic-gate * The Host Controller (HC) contains a set of on-chip operational registers 5687c478bd9Sstevel@tonic-gate * and which should be mapped into a non-cacheable portion of the system 5697c478bd9Sstevel@tonic-gate * addressable space. 5707c478bd9Sstevel@tonic-gate */ 5717c478bd9Sstevel@tonic-gate int 5727c478bd9Sstevel@tonic-gate ehci_map_regs(ehci_state_t *ehcip) 5737c478bd9Sstevel@tonic-gate { 5747c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 5757c478bd9Sstevel@tonic-gate uint16_t cmd_reg; 5767c478bd9Sstevel@tonic-gate uint_t length; 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_map_regs:"); 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate /* Check to make sure we have memory access */ 5817c478bd9Sstevel@tonic-gate if (pci_config_setup(ehcip->ehci_dip, 582*29aca3ebSlc &ehcip->ehci_config_handle) != DDI_SUCCESS) { 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 5857c478bd9Sstevel@tonic-gate "ehci_map_regs: Config error"); 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate /* Make sure Memory Access Enable is set */ 5917c478bd9Sstevel@tonic-gate cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM); 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate if (!(cmd_reg & PCI_COMM_MAE)) { 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 5967c478bd9Sstevel@tonic-gate "ehci_map_regs: Memory base address access disabled"); 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 6027c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 6037c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 6047c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate /* Map in EHCI Capability registers */ 6077c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(ehcip->ehci_dip, 1, 6087c478bd9Sstevel@tonic-gate (caddr_t *)&ehcip->ehci_capsp, 0, 6097c478bd9Sstevel@tonic-gate sizeof (ehci_caps_t), &attr, 6107c478bd9Sstevel@tonic-gate &ehcip->ehci_caps_handle) != DDI_SUCCESS) { 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 6137c478bd9Sstevel@tonic-gate "ehci_map_regs: Map setup error"); 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate length = ddi_get8(ehcip->ehci_caps_handle, 6197c478bd9Sstevel@tonic-gate (uint8_t *)&ehcip->ehci_capsp->ehci_caps_length); 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate /* Free the original mapping */ 6227c478bd9Sstevel@tonic-gate ddi_regs_map_free(&ehcip->ehci_caps_handle); 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* Re-map in EHCI Capability and Operational registers */ 6257c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(ehcip->ehci_dip, 1, 6267c478bd9Sstevel@tonic-gate (caddr_t *)&ehcip->ehci_capsp, 0, 6277c478bd9Sstevel@tonic-gate length + sizeof (ehci_regs_t), &attr, 6287c478bd9Sstevel@tonic-gate &ehcip->ehci_caps_handle) != DDI_SUCCESS) { 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 6317c478bd9Sstevel@tonic-gate "ehci_map_regs: Map setup error"); 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate /* Get the pointer to EHCI Operational Register */ 6377c478bd9Sstevel@tonic-gate ehcip->ehci_regsp = (ehci_regs_t *) 6387c478bd9Sstevel@tonic-gate ((uintptr_t)ehcip->ehci_capsp + length); 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 6417c478bd9Sstevel@tonic-gate "ehci_map_regs: Capsp 0x%p Regsp 0x%p\n", 6427c478bd9Sstevel@tonic-gate ehcip->ehci_capsp, ehcip->ehci_regsp); 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate 64728cdc3d7Sszhou /* 64828cdc3d7Sszhou * The following simulated polling is for debugging purposes only. 64928cdc3d7Sszhou * It is activated on x86 by setting usb-polling=true in GRUB or ehci.conf. 65028cdc3d7Sszhou */ 65128cdc3d7Sszhou static int 65228cdc3d7Sszhou ehci_is_polled(dev_info_t *dip) 65328cdc3d7Sszhou { 65428cdc3d7Sszhou int ret; 65528cdc3d7Sszhou char *propval; 65628cdc3d7Sszhou 65728cdc3d7Sszhou if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, 65828cdc3d7Sszhou "usb-polling", &propval) != DDI_SUCCESS) 65928cdc3d7Sszhou 66028cdc3d7Sszhou return (0); 66128cdc3d7Sszhou 66228cdc3d7Sszhou ret = (strcmp(propval, "true") == 0); 66328cdc3d7Sszhou ddi_prop_free(propval); 66428cdc3d7Sszhou 66528cdc3d7Sszhou return (ret); 66628cdc3d7Sszhou } 66728cdc3d7Sszhou 66828cdc3d7Sszhou static void 66928cdc3d7Sszhou ehci_poll_intr(void *arg) 67028cdc3d7Sszhou { 67128cdc3d7Sszhou /* poll every msec */ 67228cdc3d7Sszhou for (;;) { 67328cdc3d7Sszhou (void) ehci_intr(arg, NULL); 67428cdc3d7Sszhou delay(drv_usectohz(1000)); 67528cdc3d7Sszhou } 67628cdc3d7Sszhou } 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate /* 6797c478bd9Sstevel@tonic-gate * ehci_register_intrs_and_init_mutex: 6807c478bd9Sstevel@tonic-gate * 6817c478bd9Sstevel@tonic-gate * Register interrupts and initialize each mutex and condition variables 6827c478bd9Sstevel@tonic-gate */ 6837c478bd9Sstevel@tonic-gate int 6847c478bd9Sstevel@tonic-gate ehci_register_intrs_and_init_mutex(ehci_state_t *ehcip) 6857c478bd9Sstevel@tonic-gate { 6869c75c6bfSgovinda int intr_types; 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate #if defined(__x86) 6897c478bd9Sstevel@tonic-gate uint8_t iline; 6907c478bd9Sstevel@tonic-gate #endif 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 6937c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex:"); 6947c478bd9Sstevel@tonic-gate 6959c75c6bfSgovinda /* 6969c75c6bfSgovinda * There is a known MSI hardware bug with the EHCI controller 6979c75c6bfSgovinda * of ULI1575 southbridge. Hence MSI is disabled for this chip. 6989c75c6bfSgovinda */ 6999c75c6bfSgovinda if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) && 7009c75c6bfSgovinda (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) { 7019c75c6bfSgovinda ehcip->ehci_msi_enabled = B_FALSE; 7029c75c6bfSgovinda } else { 7039c75c6bfSgovinda /* Set the MSI enable flag from the global EHCI MSI tunable */ 7049c75c6bfSgovinda ehcip->ehci_msi_enabled = ehci_enable_msi; 7059c75c6bfSgovinda } 7069c75c6bfSgovinda 70728cdc3d7Sszhou /* launch polling thread instead of enabling pci interrupt */ 70828cdc3d7Sszhou if (ehci_is_polled(ehcip->ehci_dip)) { 70928cdc3d7Sszhou extern pri_t maxclsyspri; 71028cdc3d7Sszhou 7118668df41Slg USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 71228cdc3d7Sszhou "ehci_register_intrs_and_init_mutex: " 71328cdc3d7Sszhou "running in simulated polled mode"); 71428cdc3d7Sszhou 71528cdc3d7Sszhou (void) thread_create(NULL, 0, ehci_poll_intr, ehcip, 0, &p0, 71628cdc3d7Sszhou TS_RUN, maxclsyspri); 71728cdc3d7Sszhou 71828cdc3d7Sszhou goto skip_intr; 71928cdc3d7Sszhou } 72028cdc3d7Sszhou 7217c478bd9Sstevel@tonic-gate #if defined(__x86) 7227c478bd9Sstevel@tonic-gate /* 7237c478bd9Sstevel@tonic-gate * Make sure that the interrupt pin is connected to the 7247c478bd9Sstevel@tonic-gate * interrupt controller on x86. Interrupt line 255 means 7257c478bd9Sstevel@tonic-gate * "unknown" or "not connected" (PCI spec 6.2.4, footnote 43). 7264610e4a0Sfrits * If we would return failure when interrupt line equals 255, then 727f87a10b6Syq * high speed devices will be routed to companion host controllers. 7284610e4a0Sfrits * However, it is not necessary to return failure here, and 7294610e4a0Sfrits * o/uhci codes don't check the interrupt line either. 7304610e4a0Sfrits * But it's good to log a message here for debug purposes. 7317c478bd9Sstevel@tonic-gate */ 7327c478bd9Sstevel@tonic-gate iline = pci_config_get8(ehcip->ehci_config_handle, 7337c478bd9Sstevel@tonic-gate PCI_CONF_ILINE); 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate if (iline == 255) { 7367c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7377c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 7387c478bd9Sstevel@tonic-gate "interrupt line value out of range (%d)", 7397c478bd9Sstevel@tonic-gate iline); 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate #endif /* __x86 */ 7427c478bd9Sstevel@tonic-gate 7439c75c6bfSgovinda /* Get supported interrupt types */ 7449c75c6bfSgovinda if (ddi_intr_get_supported_types(ehcip->ehci_dip, 7459c75c6bfSgovinda &intr_types) != DDI_SUCCESS) { 7467c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7477c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 7489c75c6bfSgovinda "ddi_intr_get_supported_types failed"); 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate 7539c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7549c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: " 7559c75c6bfSgovinda "supported interrupt types 0x%x", intr_types); 7569c75c6bfSgovinda 7579c75c6bfSgovinda if ((intr_types & DDI_INTR_TYPE_MSI) && ehcip->ehci_msi_enabled) { 7589c75c6bfSgovinda if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_MSI) 7599c75c6bfSgovinda != DDI_SUCCESS) { 7609c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7619c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: MSI " 7629c75c6bfSgovinda "registration failed, trying FIXED interrupt \n"); 7639c75c6bfSgovinda } else { 7649c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7659c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: " 7669c75c6bfSgovinda "Using MSI interrupt type\n"); 7679c75c6bfSgovinda 7689c75c6bfSgovinda ehcip->ehci_intr_type = DDI_INTR_TYPE_MSI; 7699c75c6bfSgovinda ehcip->ehci_flags |= EHCI_INTR; 7709c75c6bfSgovinda } 7719c75c6bfSgovinda } 7727c478bd9Sstevel@tonic-gate 7739c75c6bfSgovinda if ((!(ehcip->ehci_flags & EHCI_INTR)) && 7749c75c6bfSgovinda (intr_types & DDI_INTR_TYPE_FIXED)) { 7759c75c6bfSgovinda if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_FIXED) 7769c75c6bfSgovinda != DDI_SUCCESS) { 7779c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7789c75c6bfSgovinda "ehci_register_intrs_and_init_mutex: " 7799c75c6bfSgovinda "FIXED interrupt registration failed\n"); 7809c75c6bfSgovinda 7819c75c6bfSgovinda return (DDI_FAILURE); 7829c75c6bfSgovinda } 7839c75c6bfSgovinda 7849c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 7857c478bd9Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: " 7869c75c6bfSgovinda "Using FIXED interrupt type\n"); 7879c75c6bfSgovinda 7889c75c6bfSgovinda ehcip->ehci_intr_type = DDI_INTR_TYPE_FIXED; 7899c75c6bfSgovinda ehcip->ehci_flags |= EHCI_INTR; 7909c75c6bfSgovinda } 7919c75c6bfSgovinda 79228cdc3d7Sszhou skip_intr: 7939c75c6bfSgovinda /* Create prototype for advance on async schedule */ 7949c75c6bfSgovinda cv_init(&ehcip->ehci_async_schedule_advance_cv, 7959c75c6bfSgovinda NULL, CV_DRIVER, NULL); 7969c75c6bfSgovinda 7979c75c6bfSgovinda return (DDI_SUCCESS); 7989c75c6bfSgovinda } 7999c75c6bfSgovinda 8009c75c6bfSgovinda 8019c75c6bfSgovinda /* 8029c75c6bfSgovinda * ehci_add_intrs: 8039c75c6bfSgovinda * 8049c75c6bfSgovinda * Register FIXED or MSI interrupts. 8059c75c6bfSgovinda */ 8069c75c6bfSgovinda static int 8079c75c6bfSgovinda ehci_add_intrs(ehci_state_t *ehcip, 8089c75c6bfSgovinda int intr_type) 8099c75c6bfSgovinda { 8109c75c6bfSgovinda int actual, avail, intr_size, count = 0; 811*29aca3ebSlc int i, flag, ret; 8129c75c6bfSgovinda 8139c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8149c75c6bfSgovinda "ehci_add_intrs: interrupt type 0x%x", intr_type); 8159c75c6bfSgovinda 8169c75c6bfSgovinda /* Get number of interrupts */ 8179c75c6bfSgovinda ret = ddi_intr_get_nintrs(ehcip->ehci_dip, intr_type, &count); 8189c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (count == 0)) { 8199c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8209c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_nintrs() failure, " 8219c75c6bfSgovinda "ret: %d, count: %d", ret, count); 8229c75c6bfSgovinda 8239c75c6bfSgovinda return (DDI_FAILURE); 8249c75c6bfSgovinda } 8259c75c6bfSgovinda 8269c75c6bfSgovinda /* Get number of available interrupts */ 8279c75c6bfSgovinda ret = ddi_intr_get_navail(ehcip->ehci_dip, intr_type, &avail); 8289c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (avail == 0)) { 8299c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8309c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_navail() failure, " 8319c75c6bfSgovinda "ret: %d, count: %d", ret, count); 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8347c478bd9Sstevel@tonic-gate } 8357c478bd9Sstevel@tonic-gate 8369c75c6bfSgovinda if (avail < count) { 8379c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8389c75c6bfSgovinda "ehci_add_intrs: ehci_add_intrs: nintrs () " 8399c75c6bfSgovinda "returned %d, navail returned %d\n", count, avail); 8409c75c6bfSgovinda } 8419c75c6bfSgovinda 8429c75c6bfSgovinda /* Allocate an array of interrupt handles */ 8439c75c6bfSgovinda intr_size = count * sizeof (ddi_intr_handle_t); 8449c75c6bfSgovinda ehcip->ehci_htable = kmem_zalloc(intr_size, KM_SLEEP); 8459c75c6bfSgovinda 8469c75c6bfSgovinda flag = (intr_type == DDI_INTR_TYPE_MSI) ? 8479c75c6bfSgovinda DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL; 8489c75c6bfSgovinda 8499c75c6bfSgovinda /* call ddi_intr_alloc() */ 8507c478bd9Sstevel@tonic-gate ret = ddi_intr_alloc(ehcip->ehci_dip, ehcip->ehci_htable, 8519c75c6bfSgovinda intr_type, 0, count, &actual, flag); 8527c478bd9Sstevel@tonic-gate 8539c75c6bfSgovinda if ((ret != DDI_SUCCESS) || (actual == 0)) { 8547c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8559c75c6bfSgovinda "ehci_add_intrs: ddi_intr_alloc() failed %d", ret); 8567c478bd9Sstevel@tonic-gate 8579c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate 8629c75c6bfSgovinda if (actual < count) { 8639c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8649c75c6bfSgovinda "ehci_add_intrs: Requested: %d, Received: %d\n", 8659c75c6bfSgovinda count, actual); 8669c75c6bfSgovinda 8679c75c6bfSgovinda for (i = 0; i < actual; i++) 8689c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 8699c75c6bfSgovinda 8709c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 8719c75c6bfSgovinda 8729c75c6bfSgovinda return (DDI_FAILURE); 8739c75c6bfSgovinda } 8747c478bd9Sstevel@tonic-gate 8759c75c6bfSgovinda ehcip->ehci_intr_cnt = actual; 8769c75c6bfSgovinda 8779c75c6bfSgovinda if ((ret = ddi_intr_get_pri(ehcip->ehci_htable[0], 8789c75c6bfSgovinda &ehcip->ehci_intr_pri)) != DDI_SUCCESS) { 8797c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8809c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_pri() failed %d", ret); 8819c75c6bfSgovinda 8829c75c6bfSgovinda for (i = 0; i < actual; i++) 8839c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 8847c478bd9Sstevel@tonic-gate 8859c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate 8909c75c6bfSgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8919c75c6bfSgovinda "ehci_add_intrs: Supported Interrupt priority 0x%x", 8929c75c6bfSgovinda ehcip->ehci_intr_pri); 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate /* Test for high level mutex */ 8957c478bd9Sstevel@tonic-gate if (ehcip->ehci_intr_pri >= ddi_intr_get_hilevel_pri()) { 8967c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 8979c75c6bfSgovinda "ehci_add_intrs: Hi level interrupt not supported"); 8989c75c6bfSgovinda 8999c75c6bfSgovinda for (i = 0; i < actual; i++) 9009c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 9017c478bd9Sstevel@tonic-gate 9029c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9057c478bd9Sstevel@tonic-gate } 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate /* Initialize the mutex */ 9087c478bd9Sstevel@tonic-gate mutex_init(&ehcip->ehci_int_mutex, NULL, MUTEX_DRIVER, 909a195726fSgovinda DDI_INTR_PRI(ehcip->ehci_intr_pri)); 9107c478bd9Sstevel@tonic-gate 9119c75c6bfSgovinda /* Call ddi_intr_add_handler() */ 9129c75c6bfSgovinda for (i = 0; i < actual; i++) { 9139c75c6bfSgovinda if ((ret = ddi_intr_add_handler(ehcip->ehci_htable[i], 9149c75c6bfSgovinda ehci_intr, (caddr_t)ehcip, 9159c75c6bfSgovinda (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) { 9169c75c6bfSgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9179c75c6bfSgovinda "ehci_add_intrs:ddi_intr_add_handler() " 9189c75c6bfSgovinda "failed %d", ret); 9197c478bd9Sstevel@tonic-gate 9209c75c6bfSgovinda for (i = 0; i < actual; i++) 9219c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 9227c478bd9Sstevel@tonic-gate 9239c75c6bfSgovinda mutex_destroy(&ehcip->ehci_int_mutex); 9249c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 9259c75c6bfSgovinda 9269c75c6bfSgovinda return (DDI_FAILURE); 9279c75c6bfSgovinda } 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate 9309c75c6bfSgovinda if ((ret = ddi_intr_get_cap(ehcip->ehci_htable[0], 9319c75c6bfSgovinda &ehcip->ehci_intr_cap)) != DDI_SUCCESS) { 9327c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9339c75c6bfSgovinda "ehci_add_intrs: ddi_intr_get_cap() failed %d", ret); 9349c75c6bfSgovinda 9359c75c6bfSgovinda for (i = 0; i < actual; i++) { 9369c75c6bfSgovinda (void) ddi_intr_remove_handler(ehcip->ehci_htable[i]); 9379c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 9389c75c6bfSgovinda } 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate mutex_destroy(&ehcip->ehci_int_mutex); 9419c75c6bfSgovinda kmem_free(ehcip->ehci_htable, intr_size); 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate 9469c75c6bfSgovinda /* Enable all interrupts */ 9479c75c6bfSgovinda if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) { 9489c75c6bfSgovinda /* Call ddi_intr_block_enable() for MSI interrupts */ 9499c75c6bfSgovinda (void) ddi_intr_block_enable(ehcip->ehci_htable, 9509c75c6bfSgovinda ehcip->ehci_intr_cnt); 9519c75c6bfSgovinda } else { 9529c75c6bfSgovinda /* Call ddi_intr_enable for MSI or FIXED interrupts */ 9539c75c6bfSgovinda for (i = 0; i < ehcip->ehci_intr_cnt; i++) 9549c75c6bfSgovinda (void) ddi_intr_enable(ehcip->ehci_htable[i]); 9559c75c6bfSgovinda } 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate /* 9623b00f311Syq * ehci_init_hardware 9637c478bd9Sstevel@tonic-gate * 9643b00f311Syq * take control from BIOS, reset EHCI host controller, and check version, etc. 9657c478bd9Sstevel@tonic-gate */ 9667c478bd9Sstevel@tonic-gate int 9673b00f311Syq ehci_init_hardware(ehci_state_t *ehcip) 9687c478bd9Sstevel@tonic-gate { 9697c478bd9Sstevel@tonic-gate int revision; 9707c478bd9Sstevel@tonic-gate uint16_t cmd_reg; 9717c478bd9Sstevel@tonic-gate int abort_on_BIOS_take_over_failure; 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate /* Take control from the BIOS */ 9747c478bd9Sstevel@tonic-gate if (ehci_take_control(ehcip) != USB_SUCCESS) { 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate /* read .conf file properties */ 9777c478bd9Sstevel@tonic-gate abort_on_BIOS_take_over_failure = 978*29aca3ebSlc ddi_prop_get_int(DDI_DEV_T_ANY, 979*29aca3ebSlc ehcip->ehci_dip, DDI_PROP_DONTPASS, 980*29aca3ebSlc "abort-on-BIOS-take-over-failure", 0); 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate if (abort_on_BIOS_take_over_failure) { 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9857c478bd9Sstevel@tonic-gate "Unable to take control from BIOS."); 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 9917c478bd9Sstevel@tonic-gate "Unable to take control from BIOS. Failure is ignored."); 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate /* set Memory Master Enable */ 9957c478bd9Sstevel@tonic-gate cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM); 9967c478bd9Sstevel@tonic-gate cmd_reg |= (PCI_COMM_MAE | PCI_COMM_ME); 9977c478bd9Sstevel@tonic-gate pci_config_put16(ehcip->ehci_config_handle, PCI_CONF_COMM, cmd_reg); 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate /* Reset the EHCI host controller */ 10007c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 10017c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) | EHCI_CMD_HOST_CTRL_RESET); 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate /* Wait 10ms for reset to complete */ 10047c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT); 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate ASSERT(Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED); 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate /* Verify the version number */ 10097c478bd9Sstevel@tonic-gate revision = Get_16Cap(ehci_version); 10107c478bd9Sstevel@tonic-gate 10113b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 10123b00f311Syq "ehci_init_hardware: Revision 0x%x", revision); 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate /* 10157c478bd9Sstevel@tonic-gate * EHCI driver supports EHCI host controllers compliant to 10167c478bd9Sstevel@tonic-gate * 0.95 and higher revisions of EHCI specifications. 10177c478bd9Sstevel@tonic-gate */ 10187c478bd9Sstevel@tonic-gate if (revision < EHCI_REVISION_0_95) { 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 10217c478bd9Sstevel@tonic-gate "Revision 0x%x is not supported", revision); 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate if (ehcip->ehci_hc_soft_state == EHCI_CTLR_INIT_STATE) { 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate /* Initialize the Frame list base address area */ 10297c478bd9Sstevel@tonic-gate if (ehci_init_periodic_frame_lst_table(ehcip) != DDI_SUCCESS) { 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10327c478bd9Sstevel@tonic-gate } 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate /* 10357c478bd9Sstevel@tonic-gate * For performance reasons, do not insert anything into the 10367c478bd9Sstevel@tonic-gate * asynchronous list or activate the asynch list schedule until 10377c478bd9Sstevel@tonic-gate * there is a valid QH. 10387c478bd9Sstevel@tonic-gate */ 10397c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list = NULL; 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) && 10427c478bd9Sstevel@tonic-gate (ehci_vt62x2_workaround & EHCI_VIA_ASYNC_SCHEDULE)) { 10437c478bd9Sstevel@tonic-gate /* 10447c478bd9Sstevel@tonic-gate * The driver is unable to reliably stop the asynch 10457c478bd9Sstevel@tonic-gate * list schedule on VIA VT6202 controllers, so we 10467c478bd9Sstevel@tonic-gate * always keep a dummy QH on the list. 10477c478bd9Sstevel@tonic-gate */ 10487c478bd9Sstevel@tonic-gate ehci_qh_t *dummy_async_qh = 10497c478bd9Sstevel@tonic-gate ehci_alloc_qh(ehcip, NULL, NULL); 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_link_ptr, 10527c478bd9Sstevel@tonic-gate ((ehci_qh_cpu_to_iommu(ehcip, dummy_async_qh) & 10537c478bd9Sstevel@tonic-gate EHCI_QH_LINK_PTR) | EHCI_QH_LINK_REF_QH)); 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate /* Set this QH to be the "head" of the circular list */ 10567c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_ctrl, 10577c478bd9Sstevel@tonic-gate Get_QH(dummy_async_qh->qh_ctrl) | 10587c478bd9Sstevel@tonic-gate EHCI_QH_CTRL_RECLAIM_HEAD); 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_next_qtd, 10617c478bd9Sstevel@tonic-gate EHCI_QH_NEXT_QTD_PTR_VALID); 10627c478bd9Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_alt_next_qtd, 10637c478bd9Sstevel@tonic-gate EHCI_QH_ALT_NEXT_QTD_PTR_VALID); 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list = dummy_async_qh; 10667c478bd9Sstevel@tonic-gate ehcip->ehci_open_async_count++; 10677c478bd9Sstevel@tonic-gate } 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate 10703b00f311Syq return (DDI_SUCCESS); 10713b00f311Syq } 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate 10743b00f311Syq /* 10753b00f311Syq * ehci_init_workaround 10763b00f311Syq * 10773b00f311Syq * some workarounds during initializing ehci 10783b00f311Syq */ 10793b00f311Syq int 10803b00f311Syq ehci_init_workaround(ehci_state_t *ehcip) 10813b00f311Syq { 10827c478bd9Sstevel@tonic-gate /* 10837c478bd9Sstevel@tonic-gate * Acer Labs Inc. M5273 EHCI controller does not send 10847c478bd9Sstevel@tonic-gate * interrupts unless the Root hub ports are routed to the EHCI 10857c478bd9Sstevel@tonic-gate * host controller; so route the ports now, before we test for 10867c478bd9Sstevel@tonic-gate * the presence of SOFs interrupts. 10877c478bd9Sstevel@tonic-gate */ 10887c478bd9Sstevel@tonic-gate if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) { 1089*29aca3ebSlc /* Route all Root hub ports to EHCI host controller */ 1090*29aca3ebSlc Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI); 10917c478bd9Sstevel@tonic-gate } 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate /* 10947c478bd9Sstevel@tonic-gate * VIA chips have some issues and may not work reliably. 1095677739beShx * Revisions >= 0x80 are part of a southbridge and appear 1096677739beShx * to be reliable with the workaround. 10974610e4a0Sfrits * For revisions < 0x80, if we were bound using class 1098677739beShx * complain, else proceed. This will allow the user to 1099677739beShx * bind ehci specifically to this chip and not have the 1100677739beShx * warnings 11017c478bd9Sstevel@tonic-gate */ 1102677739beShx if (ehcip->ehci_vendor_id == PCI_VENDOR_VIA) { 1103677739beShx 1104*29aca3ebSlc if (ehcip->ehci_rev_id >= PCI_VIA_REVISION_6212) { 1105677739beShx 1106677739beShx USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11073b00f311Syq "ehci_init_workaround: Applying VIA workarounds " 11083b00f311Syq "for the 6212 chip."); 1109677739beShx 1110*29aca3ebSlc } else if (strcmp(DEVI(ehcip->ehci_dip)->devi_binding_name, 1111677739beShx "pciclass,0c0320") == 0) { 1112677739beShx 11137c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11147c478bd9Sstevel@tonic-gate "Due to recently discovered incompatibilities"); 11157c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11167c478bd9Sstevel@tonic-gate "with this USB controller, USB2.x transfer"); 11177c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11187c478bd9Sstevel@tonic-gate "support has been disabled. This device will"); 11197c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11207c478bd9Sstevel@tonic-gate "continue to function as a USB1.x controller."); 11217c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11227c478bd9Sstevel@tonic-gate "If you are interested in enabling USB2.x"); 11237c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11247c478bd9Sstevel@tonic-gate "support please, refer to the ehci(7D) man page."); 11257c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11267c478bd9Sstevel@tonic-gate "Please also refer to www.sun.com/io for"); 11277c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11287c478bd9Sstevel@tonic-gate "Solaris Ready products and to"); 11297c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11307c478bd9Sstevel@tonic-gate "www.sun.com/bigadmin/hcl for additional"); 11317c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11327c478bd9Sstevel@tonic-gate "compatible USB products."); 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1135677739beShx 1136*29aca3ebSlc } else if (ehci_vt62x2_workaround) { 1137677739beShx 11387c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11397c478bd9Sstevel@tonic-gate "Applying VIA workarounds"); 1140*29aca3ebSlc } 11417c478bd9Sstevel@tonic-gate } 11427c478bd9Sstevel@tonic-gate 11433b00f311Syq return (DDI_SUCCESS); 11443b00f311Syq } 11453b00f311Syq 11463b00f311Syq 11473b00f311Syq /* 11483b00f311Syq * ehci_init_check_status 11493b00f311Syq * 11503b00f311Syq * Check if EHCI host controller is running 11513b00f311Syq */ 11523b00f311Syq int 11533b00f311Syq ehci_init_check_status(ehci_state_t *ehcip) 11543b00f311Syq { 11553b00f311Syq clock_t sof_time_wait; 11563b00f311Syq 11577c478bd9Sstevel@tonic-gate /* 11587c478bd9Sstevel@tonic-gate * Get the number of clock ticks to wait. 11597c478bd9Sstevel@tonic-gate * This is based on the maximum time it takes for a frame list rollover 11607c478bd9Sstevel@tonic-gate * and maximum time wait for SOFs to begin. 11617c478bd9Sstevel@tonic-gate */ 11627c478bd9Sstevel@tonic-gate sof_time_wait = drv_usectohz((EHCI_NUM_PERIODIC_FRAME_LISTS * 1000) + 11637c478bd9Sstevel@tonic-gate EHCI_SOF_TIMEWAIT); 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate /* Tell the ISR to broadcast ehci_async_schedule_advance_cv */ 11667c478bd9Sstevel@tonic-gate ehcip->ehci_flags |= EHCI_CV_INTR; 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate /* We need to add a delay to allow the chip time to start running */ 11697c478bd9Sstevel@tonic-gate (void) cv_timedwait(&ehcip->ehci_async_schedule_advance_cv, 11707c478bd9Sstevel@tonic-gate &ehcip->ehci_int_mutex, ddi_get_lbolt() + sof_time_wait); 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate /* 11737c478bd9Sstevel@tonic-gate * Check EHCI host controller is running, otherwise return failure. 11747c478bd9Sstevel@tonic-gate */ 11757c478bd9Sstevel@tonic-gate if ((ehcip->ehci_flags & EHCI_CV_INTR) || 11767c478bd9Sstevel@tonic-gate (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) { 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 11797c478bd9Sstevel@tonic-gate "No SOF interrupts have been received, this USB EHCI host" 11807c478bd9Sstevel@tonic-gate "controller is unusable"); 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate /* 11837c478bd9Sstevel@tonic-gate * Route all Root hub ports to Classic host 11847c478bd9Sstevel@tonic-gate * controller, in case this is an unusable ALI M5273 11857c478bd9Sstevel@tonic-gate * EHCI controller. 11867c478bd9Sstevel@tonic-gate */ 11877c478bd9Sstevel@tonic-gate if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) { 11887c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC); 11897c478bd9Sstevel@tonic-gate } 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate 11943b00f311Syq return (DDI_SUCCESS); 11953b00f311Syq } 11963b00f311Syq 11973b00f311Syq 11983b00f311Syq /* 11993b00f311Syq * ehci_init_ctlr: 12003b00f311Syq * 12013b00f311Syq * Initialize the Host Controller (HC). 12023b00f311Syq */ 12033b00f311Syq int 12043b00f311Syq ehci_init_ctlr(ehci_state_t *ehcip, 12053b00f311Syq int init_type) 12063b00f311Syq { 12073b00f311Syq USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_init_ctlr:"); 12083b00f311Syq 12093b00f311Syq if (init_type == EHCI_NORMAL_INITIALIZATION) { 12103b00f311Syq 12113b00f311Syq if (ehci_init_hardware(ehcip) != DDI_SUCCESS) { 12123b00f311Syq 12133b00f311Syq return (DDI_FAILURE); 12143b00f311Syq } 12153b00f311Syq } 12163b00f311Syq 12173b00f311Syq /* 12183b00f311Syq * Check for Asynchronous schedule park capability feature. If this 12193b00f311Syq * feature is supported, then, program ehci command register with 12203b00f311Syq * appropriate values.. 12213b00f311Syq */ 12223b00f311Syq if (Get_Cap(ehci_hcc_params) & EHCI_HCC_ASYNC_SCHED_PARK_CAP) { 12233b00f311Syq 12243b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 12253b00f311Syq "ehci_init_ctlr: Async park mode is supported"); 12263b00f311Syq 12273b00f311Syq Set_OpReg(ehci_command, (Get_OpReg(ehci_command) | 12283b00f311Syq (EHCI_CMD_ASYNC_PARK_ENABLE | 12293b00f311Syq EHCI_CMD_ASYNC_PARK_COUNT_3))); 12303b00f311Syq } 12313b00f311Syq 12323b00f311Syq /* 12333b00f311Syq * Check for programmable periodic frame list feature. If this 12343b00f311Syq * feature is supported, then, program ehci command register with 12353b00f311Syq * 1024 frame list value. 12363b00f311Syq */ 12373b00f311Syq if (Get_Cap(ehci_hcc_params) & EHCI_HCC_PROG_FRAME_LIST_FLAG) { 12383b00f311Syq 12393b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 12403b00f311Syq "ehci_init_ctlr: Variable programmable periodic " 12413b00f311Syq "frame list is supported"); 12423b00f311Syq 12433b00f311Syq Set_OpReg(ehci_command, (Get_OpReg(ehci_command) | 12443b00f311Syq EHCI_CMD_FRAME_1024_SIZE)); 12453b00f311Syq } 12463b00f311Syq 12473b00f311Syq /* 12483b00f311Syq * Currently EHCI driver doesn't support 64 bit addressing. 12493b00f311Syq * 12503b00f311Syq * If we are using 64 bit addressing capability, then, program 12513b00f311Syq * ehci_ctrl_segment register with 4 Gigabyte segment where all 12523b00f311Syq * of the interface data structures are allocated. 12533b00f311Syq */ 12543b00f311Syq if (Get_Cap(ehci_hcc_params) & EHCI_HCC_64BIT_ADDR_CAP) { 12553b00f311Syq 12563b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 12573b00f311Syq "ehci_init_ctlr: EHCI driver doesn't support " 12583b00f311Syq "64 bit addressing"); 12593b00f311Syq } 12603b00f311Syq 12613b00f311Syq /* 64 bit addressing is not support */ 12623b00f311Syq Set_OpReg(ehci_ctrl_segment, 0x00000000); 12633b00f311Syq 12643b00f311Syq /* Turn on/off the schedulers */ 12653b00f311Syq ehci_toggle_scheduler(ehcip); 12663b00f311Syq 12673b00f311Syq /* 12683b00f311Syq * Set the Periodic Frame List Base Address register with the 12693b00f311Syq * starting physical address of the Periodic Frame List. 12703b00f311Syq */ 12713b00f311Syq Set_OpReg(ehci_periodic_list_base, 12723b00f311Syq (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address & 1273*29aca3ebSlc EHCI_PERIODIC_LIST_BASE)); 12743b00f311Syq 12753b00f311Syq /* 12763b00f311Syq * Set ehci_interrupt to enable all interrupts except Root 12773b00f311Syq * Hub Status change interrupt. 12783b00f311Syq */ 12793b00f311Syq Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR | 12803b00f311Syq EHCI_INTR_FRAME_LIST_ROLLOVER | EHCI_INTR_USB_ERROR | 12813b00f311Syq EHCI_INTR_USB); 12823b00f311Syq 12833b00f311Syq /* 12843b00f311Syq * Set the desired interrupt threshold and turn on EHCI host controller. 12853b00f311Syq */ 12863b00f311Syq Set_OpReg(ehci_command, 12873b00f311Syq ((Get_OpReg(ehci_command) & ~EHCI_CMD_INTR_THRESHOLD) | 1288*29aca3ebSlc (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN))); 12893b00f311Syq 12903b00f311Syq ASSERT(Get_OpReg(ehci_command) & EHCI_CMD_HOST_CTRL_RUN); 12913b00f311Syq 12923b00f311Syq if (init_type == EHCI_NORMAL_INITIALIZATION) { 12933b00f311Syq 12943b00f311Syq if (ehci_init_workaround(ehcip) != DDI_SUCCESS) { 12953b00f311Syq 12963b00f311Syq return (DDI_FAILURE); 12973b00f311Syq } 12983b00f311Syq 12993b00f311Syq if (ehci_init_check_status(ehcip) != DDI_SUCCESS) { 13003b00f311Syq 13013b00f311Syq return (DDI_FAILURE); 13023b00f311Syq } 13033b00f311Syq 13043b00f311Syq USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 13053b00f311Syq "ehci_init_ctlr: SOF's have started"); 13063b00f311Syq } 13077c478bd9Sstevel@tonic-gate 13087c478bd9Sstevel@tonic-gate /* Route all Root hub ports to EHCI host controller */ 13097c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI); 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate /* Set host controller soft state to operational */ 13127c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_OPERATIONAL_STATE; 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate /* 13187c478bd9Sstevel@tonic-gate * ehci_take_control: 13197c478bd9Sstevel@tonic-gate * 13207c478bd9Sstevel@tonic-gate * Handshake to take EHCI control from BIOS if necessary. Its only valid for 13217c478bd9Sstevel@tonic-gate * x86 machines, because sparc doesn't have a BIOS. 13227c478bd9Sstevel@tonic-gate * On x86 machine, the take control process includes 13237c478bd9Sstevel@tonic-gate * o get the base address of the extended capability list 13247c478bd9Sstevel@tonic-gate * o find out the capability for handoff synchronization in the list. 13257c478bd9Sstevel@tonic-gate * o check if BIOS has owned the host controller. 13267c478bd9Sstevel@tonic-gate * o set the OS Owned semaphore bit, ask the BIOS to release the ownership. 13277c478bd9Sstevel@tonic-gate * o wait for a constant time and check if BIOS has relinquished control. 13287c478bd9Sstevel@tonic-gate */ 13297c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13307c478bd9Sstevel@tonic-gate static int 13317c478bd9Sstevel@tonic-gate ehci_take_control(ehci_state_t *ehcip) 13327c478bd9Sstevel@tonic-gate { 13337c478bd9Sstevel@tonic-gate #if defined(__x86) 13347c478bd9Sstevel@tonic-gate uint32_t extended_cap; 13357c478bd9Sstevel@tonic-gate uint32_t extended_cap_offset; 13367c478bd9Sstevel@tonic-gate uint32_t extended_cap_id; 13377c478bd9Sstevel@tonic-gate uint_t retry; 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 13407c478bd9Sstevel@tonic-gate "ehci_take_control:"); 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate /* 13437c478bd9Sstevel@tonic-gate * According EHCI Spec 2.2.4, get EECP base address from HCCPARAMS 13447c478bd9Sstevel@tonic-gate * register. 13457c478bd9Sstevel@tonic-gate */ 13467c478bd9Sstevel@tonic-gate extended_cap_offset = (Get_Cap(ehci_hcc_params) & EHCI_HCC_EECP) >> 13477c478bd9Sstevel@tonic-gate EHCI_HCC_EECP_SHIFT; 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate /* 13507c478bd9Sstevel@tonic-gate * According EHCI Spec 2.2.4, if the extended capability offset is 13517c478bd9Sstevel@tonic-gate * less than 40h then its not valid. This means we don't need to 13527c478bd9Sstevel@tonic-gate * worry about BIOS handoff. 13537c478bd9Sstevel@tonic-gate */ 13547c478bd9Sstevel@tonic-gate if (extended_cap_offset < EHCI_HCC_EECP_MIN_OFFSET) { 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 13577c478bd9Sstevel@tonic-gate "ehci_take_control: Hardware doesn't support legacy."); 13587c478bd9Sstevel@tonic-gate 13597c478bd9Sstevel@tonic-gate goto success; 13607c478bd9Sstevel@tonic-gate } 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate /* 13637c478bd9Sstevel@tonic-gate * According EHCI Spec 2.1.7, A zero offset indicates the 13647c478bd9Sstevel@tonic-gate * end of the extended capability list. 13657c478bd9Sstevel@tonic-gate */ 13667c478bd9Sstevel@tonic-gate while (extended_cap_offset) { 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate /* Get the extended capability value. */ 13697c478bd9Sstevel@tonic-gate extended_cap = pci_config_get32(ehcip->ehci_config_handle, 13707c478bd9Sstevel@tonic-gate extended_cap_offset); 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate /* Get the capability ID */ 13737c478bd9Sstevel@tonic-gate extended_cap_id = (extended_cap & EHCI_EX_CAP_ID) >> 13747c478bd9Sstevel@tonic-gate EHCI_EX_CAP_ID_SHIFT; 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate /* Check if the card support legacy */ 13777c478bd9Sstevel@tonic-gate if (extended_cap_id == EHCI_EX_CAP_ID_BIOS_HANDOFF) { 13787c478bd9Sstevel@tonic-gate break; 13797c478bd9Sstevel@tonic-gate } 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate /* Get the offset of the next capability */ 13827c478bd9Sstevel@tonic-gate extended_cap_offset = (extended_cap & EHCI_EX_CAP_NEXT_PTR) >> 13837c478bd9Sstevel@tonic-gate EHCI_EX_CAP_NEXT_PTR_SHIFT; 13847c478bd9Sstevel@tonic-gate } 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate /* 13877c478bd9Sstevel@tonic-gate * Unable to find legacy support in hardware's extended capability list. 13887c478bd9Sstevel@tonic-gate * This means we don't need to worry about BIOS handoff. 13897c478bd9Sstevel@tonic-gate */ 13907c478bd9Sstevel@tonic-gate if (extended_cap_id != EHCI_EX_CAP_ID_BIOS_HANDOFF) { 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 13937c478bd9Sstevel@tonic-gate "ehci_take_control: Hardware doesn't support legacy"); 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate goto success; 13967c478bd9Sstevel@tonic-gate } 13977c478bd9Sstevel@tonic-gate 13987c478bd9Sstevel@tonic-gate /* Check if BIOS has owned it. */ 13997c478bd9Sstevel@tonic-gate if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) { 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 14027c478bd9Sstevel@tonic-gate "ehci_take_control: BIOS does not own EHCI"); 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate goto success; 14057c478bd9Sstevel@tonic-gate } 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate /* 14087c478bd9Sstevel@tonic-gate * According EHCI Spec 5.1, The OS driver initiates an ownership 14097c478bd9Sstevel@tonic-gate * request by setting the OS Owned semaphore to a one. The OS 14107c478bd9Sstevel@tonic-gate * waits for the BIOS Owned bit to go to a zero before attempting 14117c478bd9Sstevel@tonic-gate * to use the EHCI controller. The time that OS must wait for BIOS 14127c478bd9Sstevel@tonic-gate * to respond to the request for ownership is beyond the scope of 14137c478bd9Sstevel@tonic-gate * this specification. 14147c478bd9Sstevel@tonic-gate * It waits up to EHCI_TAKEOVER_WAIT_COUNT*EHCI_TAKEOVER_DELAY ms 14157c478bd9Sstevel@tonic-gate * for BIOS to release the ownership. 14167c478bd9Sstevel@tonic-gate */ 14177c478bd9Sstevel@tonic-gate extended_cap |= EHCI_LEGSUP_OS_OWNED_SEM; 14187c478bd9Sstevel@tonic-gate pci_config_put32(ehcip->ehci_config_handle, extended_cap_offset, 14197c478bd9Sstevel@tonic-gate extended_cap); 14207c478bd9Sstevel@tonic-gate 14217c478bd9Sstevel@tonic-gate for (retry = 0; retry < EHCI_TAKEOVER_WAIT_COUNT; retry++) { 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate /* wait a special interval */ 14244ebb14b2Sfrits #ifndef __lock_lint 14257c478bd9Sstevel@tonic-gate delay(drv_usectohz(EHCI_TAKEOVER_DELAY)); 14264ebb14b2Sfrits #endif 14277c478bd9Sstevel@tonic-gate /* Check to see if the BIOS has released the ownership */ 14287c478bd9Sstevel@tonic-gate extended_cap = pci_config_get32( 14297c478bd9Sstevel@tonic-gate ehcip->ehci_config_handle, extended_cap_offset); 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) { 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, 14347c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, 14357c478bd9Sstevel@tonic-gate "ehci_take_control: BIOS has released " 14367c478bd9Sstevel@tonic-gate "the ownership. retry = %d", retry); 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate goto success; 14397c478bd9Sstevel@tonic-gate } 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate } 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 14447c478bd9Sstevel@tonic-gate "ehci_take_control: take control from BIOS failed."); 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate return (USB_FAILURE); 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate success: 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate #endif /* __x86 */ 14517c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate /* 14567c478bd9Sstevel@tonic-gate * ehci_init_periodic_frame_list_table : 14577c478bd9Sstevel@tonic-gate * 14587c478bd9Sstevel@tonic-gate * Allocate the system memory and initialize Host Controller 14597c478bd9Sstevel@tonic-gate * Periodic Frame List table area. The starting of the Periodic 14607c478bd9Sstevel@tonic-gate * Frame List Table area must be 4096 byte aligned. 14617c478bd9Sstevel@tonic-gate */ 14627c478bd9Sstevel@tonic-gate static int 14637c478bd9Sstevel@tonic-gate ehci_init_periodic_frame_lst_table(ehci_state_t *ehcip) 14647c478bd9Sstevel@tonic-gate { 14657c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 14667c478bd9Sstevel@tonic-gate size_t real_length; 14677c478bd9Sstevel@tonic-gate uint_t ccount; 14687c478bd9Sstevel@tonic-gate int result; 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 14717c478bd9Sstevel@tonic-gate 14727c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 14737c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table:"); 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate /* The host controller will be little endian */ 14767c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 14777c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 14787c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate /* Force the required 4K restrictive alignment */ 14817c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_PFL_ALIGNMENT; 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate /* Create space for the Periodic Frame List */ 14847c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr, 14857c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, 0, &ehcip->ehci_pflt_dma_handle) != DDI_SUCCESS) { 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate goto failure; 14887c478bd9Sstevel@tonic-gate } 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_pflt_dma_handle, 14917c478bd9Sstevel@tonic-gate sizeof (ehci_periodic_frame_list_t), 14927c478bd9Sstevel@tonic-gate &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 14937c478bd9Sstevel@tonic-gate 0, (caddr_t *)&ehcip->ehci_periodic_frame_list_tablep, 14947c478bd9Sstevel@tonic-gate &real_length, &ehcip->ehci_pflt_mem_handle)) { 14957c478bd9Sstevel@tonic-gate 14967c478bd9Sstevel@tonic-gate goto failure; 14977c478bd9Sstevel@tonic-gate } 14987c478bd9Sstevel@tonic-gate 14993b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 15007c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: " 15017c478bd9Sstevel@tonic-gate "Real length %lu", real_length); 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate /* Map the whole Periodic Frame List into the I/O address space */ 15047c478bd9Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ehcip->ehci_pflt_dma_handle, 15057c478bd9Sstevel@tonic-gate NULL, (caddr_t)ehcip->ehci_periodic_frame_list_tablep, 15067c478bd9Sstevel@tonic-gate real_length, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 15077c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, &ehcip->ehci_pflt_cookie, &ccount); 15087c478bd9Sstevel@tonic-gate 15097c478bd9Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) { 15107c478bd9Sstevel@tonic-gate /* The cookie count should be 1 */ 15117c478bd9Sstevel@tonic-gate if (ccount != 1) { 15127c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 15137c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: " 15147c478bd9Sstevel@tonic-gate "More than 1 cookie"); 15157c478bd9Sstevel@tonic-gate 15167c478bd9Sstevel@tonic-gate goto failure; 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate } else { 15197c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result); 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate goto failure; 15227c478bd9Sstevel@tonic-gate } 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 15257c478bd9Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: virtual 0x%p physical 0x%x", 15267c478bd9Sstevel@tonic-gate (void *)ehcip->ehci_periodic_frame_list_tablep, 15277c478bd9Sstevel@tonic-gate ehcip->ehci_pflt_cookie.dmac_address); 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate /* 15307c478bd9Sstevel@tonic-gate * DMA addresses for Periodic Frame List are bound. 15317c478bd9Sstevel@tonic-gate */ 15327c478bd9Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_PFLT_DMA_BOUND; 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate bzero((void *)ehcip->ehci_periodic_frame_list_tablep, real_length); 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate /* Initialize the Periodic Frame List */ 15377c478bd9Sstevel@tonic-gate ehci_build_interrupt_lattice(ehcip); 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate /* Reset Byte Alignment to Default */ 15407c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 15417c478bd9Sstevel@tonic-gate 15427c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 15437c478bd9Sstevel@tonic-gate failure: 15447c478bd9Sstevel@tonic-gate /* Byte alignment */ 15457c478bd9Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT; 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15487c478bd9Sstevel@tonic-gate } 15497c478bd9Sstevel@tonic-gate 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate /* 15527c478bd9Sstevel@tonic-gate * ehci_build_interrupt_lattice: 15537c478bd9Sstevel@tonic-gate * 15547c478bd9Sstevel@tonic-gate * Construct the interrupt lattice tree using static Endpoint Descriptors 15557c478bd9Sstevel@tonic-gate * (QH). This interrupt lattice tree will have total of 32 interrupt QH 15567c478bd9Sstevel@tonic-gate * lists and the Host Controller (HC) processes one interrupt QH list in 15577c478bd9Sstevel@tonic-gate * every frame. The Host Controller traverses the periodic schedule by 15587c478bd9Sstevel@tonic-gate * constructing an array offset reference from the Periodic List Base Address 15597c478bd9Sstevel@tonic-gate * register and bits 12 to 3 of Frame Index register. It fetches the element 15607c478bd9Sstevel@tonic-gate * and begins traversing the graph of linked schedule data structures. 15617c478bd9Sstevel@tonic-gate */ 15627c478bd9Sstevel@tonic-gate static void 15637c478bd9Sstevel@tonic-gate ehci_build_interrupt_lattice(ehci_state_t *ehcip) 15647c478bd9Sstevel@tonic-gate { 15657c478bd9Sstevel@tonic-gate ehci_qh_t *list_array = ehcip->ehci_qh_pool_addr; 15667c478bd9Sstevel@tonic-gate ushort_t ehci_index[EHCI_NUM_PERIODIC_FRAME_LISTS]; 15677c478bd9Sstevel@tonic-gate ehci_periodic_frame_list_t *periodic_frame_list = 1568*29aca3ebSlc ehcip->ehci_periodic_frame_list_tablep; 15697c478bd9Sstevel@tonic-gate ushort_t *temp, num_of_nodes; 15707c478bd9Sstevel@tonic-gate uintptr_t addr; 15717c478bd9Sstevel@tonic-gate int i, j, k; 15727c478bd9Sstevel@tonic-gate 15737c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 15747c478bd9Sstevel@tonic-gate "ehci_build_interrupt_lattice:"); 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate /* 15777c478bd9Sstevel@tonic-gate * Reserve the first 63 Endpoint Descriptor (QH) structures 15787c478bd9Sstevel@tonic-gate * in the pool as static endpoints & these are required for 15797c478bd9Sstevel@tonic-gate * constructing interrupt lattice tree. 15807c478bd9Sstevel@tonic-gate */ 15817c478bd9Sstevel@tonic-gate for (i = 0; i < EHCI_NUM_STATIC_NODES; i++) { 15827c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_state, EHCI_QH_STATIC); 15837c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_status, EHCI_QH_STS_HALTED); 15847c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_next_qtd, EHCI_QH_NEXT_QTD_PTR_VALID); 15857c478bd9Sstevel@tonic-gate Set_QH(list_array[i].qh_alt_next_qtd, 15867c478bd9Sstevel@tonic-gate EHCI_QH_ALT_NEXT_QTD_PTR_VALID); 15877c478bd9Sstevel@tonic-gate } 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate /* 15907c478bd9Sstevel@tonic-gate * Make sure that last Endpoint on the periodic frame list terminates 15917c478bd9Sstevel@tonic-gate * periodic schedule. 15927c478bd9Sstevel@tonic-gate */ 15937c478bd9Sstevel@tonic-gate Set_QH(list_array[0].qh_link_ptr, EHCI_QH_LINK_PTR_VALID); 15947c478bd9Sstevel@tonic-gate 15957c478bd9Sstevel@tonic-gate /* Build the interrupt lattice tree */ 15967c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_STATIC_NODES / 2); i++) { 15977c478bd9Sstevel@tonic-gate /* 15987c478bd9Sstevel@tonic-gate * The next pointer in the host controller endpoint 15997c478bd9Sstevel@tonic-gate * descriptor must contain an iommu address. Calculate 16007c478bd9Sstevel@tonic-gate * the offset into the cpu address and add this to the 16017c478bd9Sstevel@tonic-gate * starting iommu address. 16027c478bd9Sstevel@tonic-gate */ 16037c478bd9Sstevel@tonic-gate addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *)&list_array[i]); 16047c478bd9Sstevel@tonic-gate 16057c478bd9Sstevel@tonic-gate Set_QH(list_array[2*i + 1].qh_link_ptr, 16067c478bd9Sstevel@tonic-gate addr | EHCI_QH_LINK_REF_QH); 16077c478bd9Sstevel@tonic-gate Set_QH(list_array[2*i + 2].qh_link_ptr, 16087c478bd9Sstevel@tonic-gate addr | EHCI_QH_LINK_REF_QH); 16097c478bd9Sstevel@tonic-gate } 16107c478bd9Sstevel@tonic-gate 16117c478bd9Sstevel@tonic-gate /* Build the tree bottom */ 16127c478bd9Sstevel@tonic-gate temp = (unsigned short *) 16137c478bd9Sstevel@tonic-gate kmem_zalloc(EHCI_NUM_PERIODIC_FRAME_LISTS * 2, KM_SLEEP); 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate num_of_nodes = 1; 16167c478bd9Sstevel@tonic-gate 16177c478bd9Sstevel@tonic-gate /* 16187c478bd9Sstevel@tonic-gate * Initialize the values which are used for setting up head pointers 16197c478bd9Sstevel@tonic-gate * for the 32ms scheduling lists which starts from the Periodic Frame 16207c478bd9Sstevel@tonic-gate * List. 16217c478bd9Sstevel@tonic-gate */ 16227c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_log_2(EHCI_NUM_PERIODIC_FRAME_LISTS); i++) { 16237c478bd9Sstevel@tonic-gate for (j = 0, k = 0; k < num_of_nodes; k++, j++) { 16247c478bd9Sstevel@tonic-gate ehci_index[j++] = temp[k]; 16257c478bd9Sstevel@tonic-gate ehci_index[j] = temp[k] + ehci_pow_2(i); 16267c478bd9Sstevel@tonic-gate } 16277c478bd9Sstevel@tonic-gate 16287c478bd9Sstevel@tonic-gate num_of_nodes *= 2; 16297c478bd9Sstevel@tonic-gate for (k = 0; k < num_of_nodes; k++) 16307c478bd9Sstevel@tonic-gate temp[k] = ehci_index[k]; 16317c478bd9Sstevel@tonic-gate } 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate kmem_free((void *)temp, (EHCI_NUM_PERIODIC_FRAME_LISTS * 2)); 16347c478bd9Sstevel@tonic-gate 16357c478bd9Sstevel@tonic-gate /* 16367c478bd9Sstevel@tonic-gate * Initialize the interrupt list in the Periodic Frame List Table 16377c478bd9Sstevel@tonic-gate * so that it points to the bottom of the tree. 16387c478bd9Sstevel@tonic-gate */ 16397c478bd9Sstevel@tonic-gate for (i = 0, j = 0; i < ehci_pow_2(TREE_HEIGHT); i++) { 16407c478bd9Sstevel@tonic-gate addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *) 16417c478bd9Sstevel@tonic-gate (&list_array[((EHCI_NUM_STATIC_NODES + 1) / 2) + i - 1])); 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate ASSERT(addr); 16447c478bd9Sstevel@tonic-gate 16457c478bd9Sstevel@tonic-gate for (k = 0; k < ehci_pow_2(TREE_HEIGHT); k++) { 16467c478bd9Sstevel@tonic-gate Set_PFLT(periodic_frame_list-> 16477c478bd9Sstevel@tonic-gate ehci_periodic_frame_list_table[ehci_index[j++]], 16487c478bd9Sstevel@tonic-gate (uint32_t)(addr | EHCI_QH_LINK_REF_QH)); 16497c478bd9Sstevel@tonic-gate } 16507c478bd9Sstevel@tonic-gate } 16517c478bd9Sstevel@tonic-gate } 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate 16547c478bd9Sstevel@tonic-gate /* 16557c478bd9Sstevel@tonic-gate * ehci_alloc_hcdi_ops: 16567c478bd9Sstevel@tonic-gate * 16577c478bd9Sstevel@tonic-gate * The HCDI interfaces or entry points are the software interfaces used by 16587c478bd9Sstevel@tonic-gate * the Universal Serial Bus Driver (USBA) to access the services of the 16597c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD). During HCD initialization, inform USBA 16607c478bd9Sstevel@tonic-gate * about all available HCDI interfaces or entry points. 16617c478bd9Sstevel@tonic-gate */ 16627c478bd9Sstevel@tonic-gate usba_hcdi_ops_t * 16637c478bd9Sstevel@tonic-gate ehci_alloc_hcdi_ops(ehci_state_t *ehcip) 16647c478bd9Sstevel@tonic-gate { 16657c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *usba_hcdi_ops; 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 16687c478bd9Sstevel@tonic-gate "ehci_alloc_hcdi_ops:"); 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate usba_hcdi_ops = usba_alloc_hcdi_ops(); 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_ops_version = HCDI_OPS_VERSION; 16737c478bd9Sstevel@tonic-gate 16744610e4a0Sfrits usba_hcdi_ops->usba_hcdi_pm_support = ehci_hcdi_pm_support; 16757c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_open = ehci_hcdi_pipe_open; 16767c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_close = ehci_hcdi_pipe_close; 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_reset = ehci_hcdi_pipe_reset; 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_ctrl_xfer = ehci_hcdi_pipe_ctrl_xfer; 16817c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_bulk_xfer = ehci_hcdi_pipe_bulk_xfer; 16827c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_intr_xfer = ehci_hcdi_pipe_intr_xfer; 16837c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_isoc_xfer = ehci_hcdi_pipe_isoc_xfer; 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_bulk_transfer_size = 1686*29aca3ebSlc ehci_hcdi_bulk_transfer_size; 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_intr_polling = 1689*29aca3ebSlc ehci_hcdi_pipe_stop_intr_polling; 16907c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_isoc_polling = 1691*29aca3ebSlc ehci_hcdi_pipe_stop_isoc_polling; 16927c478bd9Sstevel@tonic-gate 16937c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_current_frame_number = 1694*29aca3ebSlc ehci_hcdi_get_current_frame_number; 16957c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_max_isoc_pkts = 1696*29aca3ebSlc ehci_hcdi_get_max_isoc_pkts; 16977c478bd9Sstevel@tonic-gate 16987c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_init = 1699*29aca3ebSlc ehci_hcdi_polled_input_init; 17007c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_enter = 1701*29aca3ebSlc ehci_hcdi_polled_input_enter; 17027c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_read = 1703*29aca3ebSlc ehci_hcdi_polled_read; 17047c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_exit = 1705*29aca3ebSlc ehci_hcdi_polled_input_exit; 17067c478bd9Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_fini = 1707*29aca3ebSlc ehci_hcdi_polled_input_fini; 17087c478bd9Sstevel@tonic-gate return (usba_hcdi_ops); 17097c478bd9Sstevel@tonic-gate } 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate 17127c478bd9Sstevel@tonic-gate /* 17137c478bd9Sstevel@tonic-gate * Host Controller Driver (HCD) deinitialization functions 17147c478bd9Sstevel@tonic-gate */ 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate /* 17177c478bd9Sstevel@tonic-gate * ehci_cleanup: 17187c478bd9Sstevel@tonic-gate * 17197c478bd9Sstevel@tonic-gate * Cleanup on attach failure or detach 17207c478bd9Sstevel@tonic-gate */ 17217c478bd9Sstevel@tonic-gate int 17227c478bd9Sstevel@tonic-gate ehci_cleanup(ehci_state_t *ehcip) 17237c478bd9Sstevel@tonic-gate { 17247c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw; 17257c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp; 17267c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd; 17277c478bd9Sstevel@tonic-gate int i, ctrl, rval; 17287c478bd9Sstevel@tonic-gate int flags = ehcip->ehci_flags; 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_cleanup:"); 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate if (flags & EHCI_RHREG) { 17337c478bd9Sstevel@tonic-gate /* Unload the root hub driver */ 17347c478bd9Sstevel@tonic-gate if (ehci_unload_root_hub_driver(ehcip) != USB_SUCCESS) { 17357c478bd9Sstevel@tonic-gate 17367c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 17377c478bd9Sstevel@tonic-gate } 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate if (flags & EHCI_USBAREG) { 17417c478bd9Sstevel@tonic-gate /* Unregister this HCD instance with USBA */ 17427c478bd9Sstevel@tonic-gate usba_hcdi_unregister(ehcip->ehci_dip); 17437c478bd9Sstevel@tonic-gate } 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate if (flags & EHCI_INTR) { 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 17487c478bd9Sstevel@tonic-gate 17497c478bd9Sstevel@tonic-gate /* Disable all EHCI QH list processing */ 17507c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) & 17517c478bd9Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | 17527c478bd9Sstevel@tonic-gate EHCI_CMD_PERIODIC_SCHED_ENABLE))); 17537c478bd9Sstevel@tonic-gate 17547c478bd9Sstevel@tonic-gate /* Disable all EHCI interrupts */ 17557c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0); 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate /* wait for the next SOF */ 17587c478bd9Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip); 17597c478bd9Sstevel@tonic-gate 17604610e4a0Sfrits /* Route all Root hub ports to Classic host controller */ 17614610e4a0Sfrits Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC); 17624610e4a0Sfrits 17637c478bd9Sstevel@tonic-gate /* Stop the EHCI host controller */ 17647c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 17657c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN); 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 17687c478bd9Sstevel@tonic-gate 1769*29aca3ebSlc /* Wait for sometime */ 1770*29aca3ebSlc delay(drv_usectohz(EHCI_TIMEWAIT)); 1771*29aca3ebSlc 17729c75c6bfSgovinda ehci_rem_intrs(ehcip); 17737c478bd9Sstevel@tonic-gate } 17747c478bd9Sstevel@tonic-gate 17757c478bd9Sstevel@tonic-gate /* Unmap the EHCI registers */ 17767c478bd9Sstevel@tonic-gate if (ehcip->ehci_caps_handle) { 17777c478bd9Sstevel@tonic-gate ddi_regs_map_free(&ehcip->ehci_caps_handle); 17787c478bd9Sstevel@tonic-gate } 17797c478bd9Sstevel@tonic-gate 17807c478bd9Sstevel@tonic-gate if (ehcip->ehci_config_handle) { 17817c478bd9Sstevel@tonic-gate pci_config_teardown(&ehcip->ehci_config_handle); 17827c478bd9Sstevel@tonic-gate } 17837c478bd9Sstevel@tonic-gate 17847c478bd9Sstevel@tonic-gate /* Free all the buffers */ 17857c478bd9Sstevel@tonic-gate if (ehcip->ehci_qtd_pool_addr && ehcip->ehci_qtd_pool_mem_handle) { 17867c478bd9Sstevel@tonic-gate for (i = 0; i < ehci_qtd_pool_size; i ++) { 17877c478bd9Sstevel@tonic-gate qtd = &ehcip->ehci_qtd_pool_addr[i]; 17887c478bd9Sstevel@tonic-gate ctrl = Get_QTD(ehcip-> 17897c478bd9Sstevel@tonic-gate ehci_qtd_pool_addr[i].qtd_state); 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate if ((ctrl != EHCI_QTD_FREE) && 17927c478bd9Sstevel@tonic-gate (ctrl != EHCI_QTD_DUMMY) && 17937c478bd9Sstevel@tonic-gate (qtd->qtd_trans_wrapper)) { 17947c478bd9Sstevel@tonic-gate 17957c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 17967c478bd9Sstevel@tonic-gate 17977c478bd9Sstevel@tonic-gate tw = (ehci_trans_wrapper_t *) 1798*29aca3ebSlc EHCI_LOOKUP_ID((uint32_t) 1799*29aca3ebSlc Get_QTD(qtd->qtd_trans_wrapper)); 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate /* Obtain the pipe private structure */ 18027c478bd9Sstevel@tonic-gate pp = tw->tw_pipe_private; 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate /* Stop the the transfer timer */ 18057c478bd9Sstevel@tonic-gate ehci_stop_xfer_timer(ehcip, tw, 1806*29aca3ebSlc EHCI_REMOVE_XFER_ALWAYS); 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate ehci_deallocate_tw(ehcip, pp, tw); 18097c478bd9Sstevel@tonic-gate 18107c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 18117c478bd9Sstevel@tonic-gate } 18127c478bd9Sstevel@tonic-gate } 18137c478bd9Sstevel@tonic-gate 18147c478bd9Sstevel@tonic-gate /* 18157c478bd9Sstevel@tonic-gate * If EHCI_QTD_POOL_BOUND flag is set, then unbind 18167c478bd9Sstevel@tonic-gate * the handle for QTD pools. 18177c478bd9Sstevel@tonic-gate */ 18187c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 18197c478bd9Sstevel@tonic-gate EHCI_QTD_POOL_BOUND) == EHCI_QTD_POOL_BOUND) { 18207c478bd9Sstevel@tonic-gate 18217c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 18227c478bd9Sstevel@tonic-gate ehcip->ehci_qtd_pool_dma_handle); 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 18257c478bd9Sstevel@tonic-gate } 18267c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_qtd_pool_mem_handle); 18277c478bd9Sstevel@tonic-gate } 18287c478bd9Sstevel@tonic-gate 18297c478bd9Sstevel@tonic-gate /* Free the QTD pool */ 18307c478bd9Sstevel@tonic-gate if (ehcip->ehci_qtd_pool_dma_handle) { 18317c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_qtd_pool_dma_handle); 18327c478bd9Sstevel@tonic-gate } 18337c478bd9Sstevel@tonic-gate 18347c478bd9Sstevel@tonic-gate if (ehcip->ehci_qh_pool_addr && ehcip->ehci_qh_pool_mem_handle) { 18357c478bd9Sstevel@tonic-gate /* 18367c478bd9Sstevel@tonic-gate * If EHCI_QH_POOL_BOUND flag is set, then unbind 18377c478bd9Sstevel@tonic-gate * the handle for QH pools. 18387c478bd9Sstevel@tonic-gate */ 18397c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 18407c478bd9Sstevel@tonic-gate EHCI_QH_POOL_BOUND) == EHCI_QH_POOL_BOUND) { 18417c478bd9Sstevel@tonic-gate 18427c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 18437c478bd9Sstevel@tonic-gate ehcip->ehci_qh_pool_dma_handle); 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 18467c478bd9Sstevel@tonic-gate } 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_qh_pool_mem_handle); 18497c478bd9Sstevel@tonic-gate } 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate /* Free the QH pool */ 18527c478bd9Sstevel@tonic-gate if (ehcip->ehci_qh_pool_dma_handle) { 18537c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_qh_pool_dma_handle); 18547c478bd9Sstevel@tonic-gate } 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate /* Free the Periodic frame list table (PFLT) area */ 18577c478bd9Sstevel@tonic-gate if (ehcip->ehci_periodic_frame_list_tablep && 18587c478bd9Sstevel@tonic-gate ehcip->ehci_pflt_mem_handle) { 18597c478bd9Sstevel@tonic-gate /* 18607c478bd9Sstevel@tonic-gate * If EHCI_PFLT_DMA_BOUND flag is set, then unbind 18617c478bd9Sstevel@tonic-gate * the handle for PFLT. 18627c478bd9Sstevel@tonic-gate */ 18637c478bd9Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag & 18647c478bd9Sstevel@tonic-gate EHCI_PFLT_DMA_BOUND) == EHCI_PFLT_DMA_BOUND) { 18657c478bd9Sstevel@tonic-gate 18667c478bd9Sstevel@tonic-gate rval = ddi_dma_unbind_handle( 18677c478bd9Sstevel@tonic-gate ehcip->ehci_pflt_dma_handle); 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 18707c478bd9Sstevel@tonic-gate } 18717c478bd9Sstevel@tonic-gate 18727c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_pflt_mem_handle); 18737c478bd9Sstevel@tonic-gate } 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate (void) ehci_isoc_cleanup(ehcip); 18767c478bd9Sstevel@tonic-gate 18777c478bd9Sstevel@tonic-gate if (ehcip->ehci_pflt_dma_handle) { 18787c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_pflt_dma_handle); 18797c478bd9Sstevel@tonic-gate } 18807c478bd9Sstevel@tonic-gate 18817c478bd9Sstevel@tonic-gate if (flags & EHCI_INTR) { 18827c478bd9Sstevel@tonic-gate /* Destroy the mutex */ 18837c478bd9Sstevel@tonic-gate mutex_destroy(&ehcip->ehci_int_mutex); 18847c478bd9Sstevel@tonic-gate 18857c478bd9Sstevel@tonic-gate /* Destroy the async schedule advance condition variable */ 18867c478bd9Sstevel@tonic-gate cv_destroy(&ehcip->ehci_async_schedule_advance_cv); 18877c478bd9Sstevel@tonic-gate } 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate /* clean up kstat structs */ 18907c478bd9Sstevel@tonic-gate ehci_destroy_stats(ehcip); 18917c478bd9Sstevel@tonic-gate 18927c478bd9Sstevel@tonic-gate /* Free ehci hcdi ops */ 18937c478bd9Sstevel@tonic-gate if (ehcip->ehci_hcdi_ops) { 18947c478bd9Sstevel@tonic-gate usba_free_hcdi_ops(ehcip->ehci_hcdi_ops); 18957c478bd9Sstevel@tonic-gate } 18967c478bd9Sstevel@tonic-gate 18977c478bd9Sstevel@tonic-gate if (flags & EHCI_ZALLOC) { 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate usb_free_log_hdl(ehcip->ehci_log_hdl); 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate /* Remove all properties that might have been created */ 19027c478bd9Sstevel@tonic-gate ddi_prop_remove_all(ehcip->ehci_dip); 19037c478bd9Sstevel@tonic-gate 19047c478bd9Sstevel@tonic-gate /* Free the soft state */ 19057c478bd9Sstevel@tonic-gate ddi_soft_state_free(ehci_statep, 1906*29aca3ebSlc ddi_get_instance(ehcip->ehci_dip)); 19077c478bd9Sstevel@tonic-gate } 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 19107c478bd9Sstevel@tonic-gate } 19117c478bd9Sstevel@tonic-gate 19127c478bd9Sstevel@tonic-gate 19139c75c6bfSgovinda /* 19149c75c6bfSgovinda * ehci_rem_intrs: 19159c75c6bfSgovinda * 19169c75c6bfSgovinda * Unregister FIXED or MSI interrupts 19179c75c6bfSgovinda */ 19189c75c6bfSgovinda static void 19199c75c6bfSgovinda ehci_rem_intrs(ehci_state_t *ehcip) 19209c75c6bfSgovinda { 19219c75c6bfSgovinda int i; 19229c75c6bfSgovinda 19239c75c6bfSgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19249c75c6bfSgovinda "ehci_rem_intrs: interrupt type 0x%x", ehcip->ehci_intr_type); 19259c75c6bfSgovinda 19269c75c6bfSgovinda /* Disable all interrupts */ 19279c75c6bfSgovinda if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) { 19289c75c6bfSgovinda (void) ddi_intr_block_disable(ehcip->ehci_htable, 19299c75c6bfSgovinda ehcip->ehci_intr_cnt); 19309c75c6bfSgovinda } else { 19319c75c6bfSgovinda for (i = 0; i < ehcip->ehci_intr_cnt; i++) { 19329c75c6bfSgovinda (void) ddi_intr_disable(ehcip->ehci_htable[i]); 19339c75c6bfSgovinda } 19349c75c6bfSgovinda } 19359c75c6bfSgovinda 19369c75c6bfSgovinda /* Call ddi_intr_remove_handler() */ 19379c75c6bfSgovinda for (i = 0; i < ehcip->ehci_intr_cnt; i++) { 19389c75c6bfSgovinda (void) ddi_intr_remove_handler(ehcip->ehci_htable[i]); 19399c75c6bfSgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]); 19409c75c6bfSgovinda } 19419c75c6bfSgovinda 19429c75c6bfSgovinda kmem_free(ehcip->ehci_htable, 19439c75c6bfSgovinda ehcip->ehci_intr_cnt * sizeof (ddi_intr_handle_t)); 19449c75c6bfSgovinda } 19459c75c6bfSgovinda 19469c75c6bfSgovinda 19477c478bd9Sstevel@tonic-gate /* 19487c478bd9Sstevel@tonic-gate * ehci_cpr_suspend 19497c478bd9Sstevel@tonic-gate */ 19507c478bd9Sstevel@tonic-gate int 19517c478bd9Sstevel@tonic-gate ehci_cpr_suspend(ehci_state_t *ehcip) 19527c478bd9Sstevel@tonic-gate { 19537c478bd9Sstevel@tonic-gate int i; 19547c478bd9Sstevel@tonic-gate 19557c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19567c478bd9Sstevel@tonic-gate "ehci_cpr_suspend:"); 19577c478bd9Sstevel@tonic-gate 19587c478bd9Sstevel@tonic-gate /* Call into the root hub and suspend it */ 19597c478bd9Sstevel@tonic-gate if (usba_hubdi_detach(ehcip->ehci_dip, DDI_SUSPEND) != DDI_SUCCESS) { 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 1962*29aca3ebSlc "ehci_cpr_suspend: root hub fails to suspend"); 19637c478bd9Sstevel@tonic-gate 19647c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 19657c478bd9Sstevel@tonic-gate } 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate /* Only root hub's intr pipe should be open at this time */ 19687c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 19697c478bd9Sstevel@tonic-gate 19707c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_open_pipe_count == 0); 19717c478bd9Sstevel@tonic-gate 19727c478bd9Sstevel@tonic-gate /* Just wait till all resources are reclaimed */ 19737c478bd9Sstevel@tonic-gate i = 0; 19747c478bd9Sstevel@tonic-gate while ((ehcip->ehci_reclaim_list != NULL) && (i++ < 3)) { 19757c478bd9Sstevel@tonic-gate ehci_handle_endpoint_reclaimation(ehcip); 19767c478bd9Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip); 19777c478bd9Sstevel@tonic-gate } 19787c478bd9Sstevel@tonic-gate ASSERT(ehcip->ehci_reclaim_list == NULL); 19797c478bd9Sstevel@tonic-gate 19803b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19817c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: Disable HC QH list processing"); 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate /* Disable all EHCI QH list processing */ 19847c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) & 19857c478bd9Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE))); 19867c478bd9Sstevel@tonic-gate 19873b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19887c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: Disable HC interrupts"); 19897c478bd9Sstevel@tonic-gate 19907c478bd9Sstevel@tonic-gate /* Disable all EHCI interrupts */ 19917c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0); 19927c478bd9Sstevel@tonic-gate 19933b00f311Syq USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 19947c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: Wait for the next SOF"); 19957c478bd9Sstevel@tonic-gate 19967c478bd9Sstevel@tonic-gate /* Wait for the next SOF */ 19977c478bd9Sstevel@tonic-gate if (ehci_wait_for_sof(ehcip) != USB_SUCCESS) { 19987c478bd9Sstevel@tonic-gate 19997c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 20007c478bd9Sstevel@tonic-gate "ehci_cpr_suspend: ehci host controller suspend failed"); 20017c478bd9Sstevel@tonic-gate 20027c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 20037c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 20047c478bd9Sstevel@tonic-gate } 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate /* 20077c478bd9Sstevel@tonic-gate * Stop the ehci host controller 20087c478bd9Sstevel@tonic-gate * if usb keyboard is not connected. 20097c478bd9Sstevel@tonic-gate */ 20102df1fe9cSrandyf if (ehcip->ehci_polled_kbd_count == 0 || force_ehci_off != 0) { 20117c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 20127c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN); 20137c478bd9Sstevel@tonic-gate } 20147c478bd9Sstevel@tonic-gate 20157c478bd9Sstevel@tonic-gate /* Set host controller soft state to suspend */ 20167c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_SUSPEND_STATE; 20177c478bd9Sstevel@tonic-gate 20187c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 20197c478bd9Sstevel@tonic-gate 20207c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 20217c478bd9Sstevel@tonic-gate } 20227c478bd9Sstevel@tonic-gate 20237c478bd9Sstevel@tonic-gate 20247c478bd9Sstevel@tonic-gate /* 20257c478bd9Sstevel@tonic-gate * ehci_cpr_resume 20267c478bd9Sstevel@tonic-gate */ 20277c478bd9Sstevel@tonic-gate int 20287c478bd9Sstevel@tonic-gate ehci_cpr_resume(ehci_state_t *ehcip) 20297c478bd9Sstevel@tonic-gate { 20307c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 20317c478bd9Sstevel@tonic-gate 20327c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 20337c478bd9Sstevel@tonic-gate "ehci_cpr_resume: Restart the controller"); 20347c478bd9Sstevel@tonic-gate 20357c478bd9Sstevel@tonic-gate /* Cleanup ehci specific information across cpr */ 20367c478bd9Sstevel@tonic-gate ehci_cpr_cleanup(ehcip); 20377c478bd9Sstevel@tonic-gate 20387c478bd9Sstevel@tonic-gate /* Restart the controller */ 20393b00f311Syq if (ehci_init_ctlr(ehcip, EHCI_NORMAL_INITIALIZATION) != DDI_SUCCESS) { 20407c478bd9Sstevel@tonic-gate 20417c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 20427c478bd9Sstevel@tonic-gate "ehci_cpr_resume: ehci host controller resume failed "); 20437c478bd9Sstevel@tonic-gate 20447c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 20477c478bd9Sstevel@tonic-gate } 20487c478bd9Sstevel@tonic-gate 20497c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 20507c478bd9Sstevel@tonic-gate 20517c478bd9Sstevel@tonic-gate /* Now resume the root hub */ 20527c478bd9Sstevel@tonic-gate if (usba_hubdi_attach(ehcip->ehci_dip, DDI_RESUME) != DDI_SUCCESS) { 20537c478bd9Sstevel@tonic-gate 20547c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 20557c478bd9Sstevel@tonic-gate } 20567c478bd9Sstevel@tonic-gate 20577c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 20587c478bd9Sstevel@tonic-gate } 20597c478bd9Sstevel@tonic-gate 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate /* 20627c478bd9Sstevel@tonic-gate * Bandwidth Allocation functions 20637c478bd9Sstevel@tonic-gate */ 20647c478bd9Sstevel@tonic-gate 20657c478bd9Sstevel@tonic-gate /* 20667c478bd9Sstevel@tonic-gate * ehci_allocate_bandwidth: 20677c478bd9Sstevel@tonic-gate * 20687c478bd9Sstevel@tonic-gate * Figure out whether or not this interval may be supported. Return the index 20697c478bd9Sstevel@tonic-gate * into the lattice if it can be supported. Return allocation failure if it 20707c478bd9Sstevel@tonic-gate * can not be supported. 20717c478bd9Sstevel@tonic-gate */ 20727c478bd9Sstevel@tonic-gate int 20737c478bd9Sstevel@tonic-gate ehci_allocate_bandwidth( 20747c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 20757c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 20767c478bd9Sstevel@tonic-gate uint_t *pnode, 20777c478bd9Sstevel@tonic-gate uchar_t *smask, 20787c478bd9Sstevel@tonic-gate uchar_t *cmask) 20797c478bd9Sstevel@tonic-gate { 20807c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 20817c478bd9Sstevel@tonic-gate 20827c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 20837c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 20847c478bd9Sstevel@tonic-gate 20857c478bd9Sstevel@tonic-gate /* Reset the pnode to the last checked pnode */ 20867c478bd9Sstevel@tonic-gate *pnode = 0; 20877c478bd9Sstevel@tonic-gate 20887c478bd9Sstevel@tonic-gate /* Allocate high speed bandwidth */ 20897c478bd9Sstevel@tonic-gate if ((error = ehci_allocate_high_speed_bandwidth(ehcip, 20907c478bd9Sstevel@tonic-gate ph, pnode, smask, cmask)) != USB_SUCCESS) { 20917c478bd9Sstevel@tonic-gate 20927c478bd9Sstevel@tonic-gate return (error); 20937c478bd9Sstevel@tonic-gate } 20947c478bd9Sstevel@tonic-gate 20957c478bd9Sstevel@tonic-gate /* 20967c478bd9Sstevel@tonic-gate * For low/full speed usb devices, allocate classic TT bandwidth 20977c478bd9Sstevel@tonic-gate * in additional to high speed bandwidth. 20987c478bd9Sstevel@tonic-gate */ 20997c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) { 21007c478bd9Sstevel@tonic-gate 21017c478bd9Sstevel@tonic-gate /* Allocate classic TT bandwidth */ 21027c478bd9Sstevel@tonic-gate if ((error = ehci_allocate_classic_tt_bandwidth( 21037c478bd9Sstevel@tonic-gate ehcip, ph, *pnode)) != USB_SUCCESS) { 21047c478bd9Sstevel@tonic-gate 21057c478bd9Sstevel@tonic-gate /* Deallocate high speed bandwidth */ 21067c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth( 21077c478bd9Sstevel@tonic-gate ehcip, ph, *pnode, *smask, *cmask); 21087c478bd9Sstevel@tonic-gate } 21097c478bd9Sstevel@tonic-gate } 21107c478bd9Sstevel@tonic-gate 21117c478bd9Sstevel@tonic-gate return (error); 21127c478bd9Sstevel@tonic-gate } 21137c478bd9Sstevel@tonic-gate 21147c478bd9Sstevel@tonic-gate 21157c478bd9Sstevel@tonic-gate /* 21167c478bd9Sstevel@tonic-gate * ehci_allocate_high_speed_bandwidth: 21177c478bd9Sstevel@tonic-gate * 21187c478bd9Sstevel@tonic-gate * Allocate high speed bandwidth for the low/full/high speed interrupt and 21197c478bd9Sstevel@tonic-gate * isochronous endpoints. 21207c478bd9Sstevel@tonic-gate */ 21217c478bd9Sstevel@tonic-gate static int 21227c478bd9Sstevel@tonic-gate ehci_allocate_high_speed_bandwidth( 21237c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 21247c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 21257c478bd9Sstevel@tonic-gate uint_t *pnode, 21267c478bd9Sstevel@tonic-gate uchar_t *smask, 21277c478bd9Sstevel@tonic-gate uchar_t *cmask) 21287c478bd9Sstevel@tonic-gate { 21297c478bd9Sstevel@tonic-gate uint_t sbandwidth, cbandwidth; 21307c478bd9Sstevel@tonic-gate int interval; 21317c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 21327c478bd9Sstevel@tonic-gate usba_device_t *child_ud; 21337c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 21347c478bd9Sstevel@tonic-gate int error; 21357c478bd9Sstevel@tonic-gate 21367c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 21377c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 21387c478bd9Sstevel@tonic-gate 21397c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 21407c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 21417c478bd9Sstevel@tonic-gate 21427c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 21437c478bd9Sstevel@tonic-gate 21447c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 21457c478bd9Sstevel@tonic-gate port_status = ph->p_usba_device->usb_port_status; 21467c478bd9Sstevel@tonic-gate 21477c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 21487c478bd9Sstevel@tonic-gate 21497c478bd9Sstevel@tonic-gate /* 21507c478bd9Sstevel@tonic-gate * Calculate the length in bytes of a transaction on this 21517c478bd9Sstevel@tonic-gate * periodic endpoint. Return failure if maximum packet is 21527c478bd9Sstevel@tonic-gate * zero. 21537c478bd9Sstevel@tonic-gate */ 21547c478bd9Sstevel@tonic-gate error = ehci_compute_high_speed_bandwidth(ehcip, endpoint, 21557c478bd9Sstevel@tonic-gate port_status, &sbandwidth, &cbandwidth); 21567c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 21577c478bd9Sstevel@tonic-gate 21587c478bd9Sstevel@tonic-gate return (error); 21597c478bd9Sstevel@tonic-gate } 21607c478bd9Sstevel@tonic-gate 21617c478bd9Sstevel@tonic-gate /* 21627c478bd9Sstevel@tonic-gate * Adjust polling interval to be a power of 2. 21637c478bd9Sstevel@tonic-gate * If this interval can't be supported, return 21647c478bd9Sstevel@tonic-gate * allocation failure. 21657c478bd9Sstevel@tonic-gate */ 21667c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 21677c478bd9Sstevel@tonic-gate if (interval == USB_FAILURE) { 21687c478bd9Sstevel@tonic-gate 21697c478bd9Sstevel@tonic-gate return (USB_FAILURE); 21707c478bd9Sstevel@tonic-gate } 21717c478bd9Sstevel@tonic-gate 21727c478bd9Sstevel@tonic-gate if (port_status == USBA_HIGH_SPEED_DEV) { 2173b3001defSlg /* Allocate bandwidth for high speed devices */ 2174b3001defSlg if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) == 2175b3001defSlg USB_EP_ATTR_ISOCH) { 2176b3001defSlg error = USB_SUCCESS; 2177b3001defSlg } else { 2178b3001defSlg 2179b3001defSlg error = ehci_find_bestfit_hs_mask(ehcip, smask, pnode, 2180b3001defSlg endpoint, sbandwidth, interval); 2181b3001defSlg } 2182b3001defSlg 21837c478bd9Sstevel@tonic-gate *cmask = 0x00; 21847c478bd9Sstevel@tonic-gate 21857c478bd9Sstevel@tonic-gate } else { 21867c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) == 21877c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR) { 21887c478bd9Sstevel@tonic-gate 21897c478bd9Sstevel@tonic-gate /* Allocate bandwidth for low speed interrupt */ 21907c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_ls_intr_mask(ehcip, 21917c478bd9Sstevel@tonic-gate smask, cmask, pnode, sbandwidth, cbandwidth, 21927c478bd9Sstevel@tonic-gate interval); 21937c478bd9Sstevel@tonic-gate } else { 21947c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 21957c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 21967c478bd9Sstevel@tonic-gate 21977c478bd9Sstevel@tonic-gate /* Allocate bandwidth for sitd in */ 21987c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_sitd_in_mask(ehcip, 21997c478bd9Sstevel@tonic-gate smask, cmask, pnode, sbandwidth, cbandwidth, 22007c478bd9Sstevel@tonic-gate interval); 22017c478bd9Sstevel@tonic-gate } else { 22027c478bd9Sstevel@tonic-gate 22037c478bd9Sstevel@tonic-gate /* Allocate bandwidth for sitd out */ 22047c478bd9Sstevel@tonic-gate error = ehci_find_bestfit_sitd_out_mask(ehcip, 22057c478bd9Sstevel@tonic-gate smask, pnode, sbandwidth, interval); 22067c478bd9Sstevel@tonic-gate *cmask = 0x00; 22077c478bd9Sstevel@tonic-gate } 22087c478bd9Sstevel@tonic-gate } 22097c478bd9Sstevel@tonic-gate } 22107c478bd9Sstevel@tonic-gate 22117c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 22127c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 22137c478bd9Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: Reached maximum " 22147c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth for a " 22157c478bd9Sstevel@tonic-gate "given high-speed periodic endpoint"); 22167c478bd9Sstevel@tonic-gate 22177c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 22187c478bd9Sstevel@tonic-gate } 22197c478bd9Sstevel@tonic-gate 22207c478bd9Sstevel@tonic-gate return (error); 22217c478bd9Sstevel@tonic-gate } 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate 22247c478bd9Sstevel@tonic-gate /* 22257c478bd9Sstevel@tonic-gate * ehci_allocate_classic_tt_speed_bandwidth: 22267c478bd9Sstevel@tonic-gate * 22277c478bd9Sstevel@tonic-gate * Allocate classic TT bandwidth for the low/full speed interrupt and 22287c478bd9Sstevel@tonic-gate * isochronous endpoints. 22297c478bd9Sstevel@tonic-gate */ 22307c478bd9Sstevel@tonic-gate static int 22317c478bd9Sstevel@tonic-gate ehci_allocate_classic_tt_bandwidth( 22327c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 22337c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 22347c478bd9Sstevel@tonic-gate uint_t pnode) 22357c478bd9Sstevel@tonic-gate { 22367c478bd9Sstevel@tonic-gate uint_t bandwidth, min; 22377c478bd9Sstevel@tonic-gate uint_t height, leftmost, list; 22387c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 22397c478bd9Sstevel@tonic-gate usba_device_t *child_ud, *parent_ud; 22407c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 22417c478bd9Sstevel@tonic-gate int i, interval; 22427c478bd9Sstevel@tonic-gate 22437c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 22447c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 22457c478bd9Sstevel@tonic-gate 22467c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 22477c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 22487c478bd9Sstevel@tonic-gate 22497c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 22507c478bd9Sstevel@tonic-gate 22517c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 22527c478bd9Sstevel@tonic-gate port_status = child_ud->usb_port_status; 22537c478bd9Sstevel@tonic-gate 22547c478bd9Sstevel@tonic-gate /* Get the parent high speed hub's usba device structure */ 22557c478bd9Sstevel@tonic-gate parent_ud = child_ud->usb_hs_hub_usba_dev; 22567c478bd9Sstevel@tonic-gate 22577c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 22587c478bd9Sstevel@tonic-gate 22593b00f311Syq USB_DPRINTF_L3(PRINT_MASK_BW, ehcip->ehci_log_hdl, 22607c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: " 22617c478bd9Sstevel@tonic-gate "child_ud 0x%p parent_ud 0x%p", child_ud, parent_ud); 22627c478bd9Sstevel@tonic-gate 22637c478bd9Sstevel@tonic-gate /* 22647c478bd9Sstevel@tonic-gate * Calculate the length in bytes of a transaction on this 22657c478bd9Sstevel@tonic-gate * periodic endpoint. Return failure if maximum packet is 22667c478bd9Sstevel@tonic-gate * zero. 22677c478bd9Sstevel@tonic-gate */ 22687c478bd9Sstevel@tonic-gate if (ehci_compute_classic_bandwidth(endpoint, 22697c478bd9Sstevel@tonic-gate port_status, &bandwidth) != USB_SUCCESS) { 22707c478bd9Sstevel@tonic-gate 22717c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 22727c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Periodic endpoint " 22737c478bd9Sstevel@tonic-gate "with zero endpoint maximum packet size is not supported"); 22747c478bd9Sstevel@tonic-gate 22757c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 22767c478bd9Sstevel@tonic-gate } 22777c478bd9Sstevel@tonic-gate 22783b00f311Syq USB_DPRINTF_L3(PRINT_MASK_BW, ehcip->ehci_log_hdl, 22797c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: bandwidth %d", bandwidth); 22807c478bd9Sstevel@tonic-gate 22817c478bd9Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex); 22827c478bd9Sstevel@tonic-gate 22837c478bd9Sstevel@tonic-gate /* 22847c478bd9Sstevel@tonic-gate * If the length in bytes plus the allocated bandwidth exceeds 22857c478bd9Sstevel@tonic-gate * the maximum, return bandwidth allocation failure. 22867c478bd9Sstevel@tonic-gate */ 22877c478bd9Sstevel@tonic-gate if ((parent_ud->usb_hs_hub_min_bandwidth + bandwidth) > 22887c478bd9Sstevel@tonic-gate FS_PERIODIC_BANDWIDTH) { 22897c478bd9Sstevel@tonic-gate 22907c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 22917c478bd9Sstevel@tonic-gate 22927c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 22937c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Reached maximum " 22947c478bd9Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth for a " 22957c478bd9Sstevel@tonic-gate "given low/full speed periodic endpoint"); 22967c478bd9Sstevel@tonic-gate 22977c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 22987c478bd9Sstevel@tonic-gate } 22997c478bd9Sstevel@tonic-gate 23007c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 23017c478bd9Sstevel@tonic-gate 23027c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 23037c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 23047c478bd9Sstevel@tonic-gate 23057c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 23067c478bd9Sstevel@tonic-gate height = ehci_lattice_height(interval); 23077c478bd9Sstevel@tonic-gate 23087c478bd9Sstevel@tonic-gate /* Find the leftmost leaf in the subtree specified by the node. */ 23097c478bd9Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height); 23107c478bd9Sstevel@tonic-gate 23117c478bd9Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex); 23127c478bd9Sstevel@tonic-gate 23137c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) { 23147c478bd9Sstevel@tonic-gate list = ehci_index[leftmost + i]; 23157c478bd9Sstevel@tonic-gate 23167c478bd9Sstevel@tonic-gate if ((parent_ud->usb_hs_hub_bandwidth[list] + 23177c478bd9Sstevel@tonic-gate bandwidth) > FS_PERIODIC_BANDWIDTH) { 23187c478bd9Sstevel@tonic-gate 23197c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 23207c478bd9Sstevel@tonic-gate 23217c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 23227c478bd9Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Reached " 23237c478bd9Sstevel@tonic-gate "maximum bandwidth value and cannot allocate " 23247c478bd9Sstevel@tonic-gate "bandwidth for low/full periodic endpoint"); 23257c478bd9Sstevel@tonic-gate 23267c478bd9Sstevel@tonic-gate return (USB_NO_BANDWIDTH); 23277c478bd9Sstevel@tonic-gate } 23287c478bd9Sstevel@tonic-gate } 23297c478bd9Sstevel@tonic-gate 23307c478bd9Sstevel@tonic-gate /* 23317c478bd9Sstevel@tonic-gate * All the leaves for this node must be updated with the bandwidth. 23327c478bd9Sstevel@tonic-gate */ 23337c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) { 23347c478bd9Sstevel@tonic-gate list = ehci_index[leftmost + i]; 23357c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_bandwidth[list] += bandwidth; 23367c478bd9Sstevel@tonic-gate } 23377c478bd9Sstevel@tonic-gate 23387c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */ 23397c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[0]; 23407c478bd9Sstevel@tonic-gate 23417c478bd9Sstevel@tonic-gate for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) { 23427c478bd9Sstevel@tonic-gate if (parent_ud->usb_hs_hub_bandwidth[i] < min) { 23437c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[i]; 23447c478bd9Sstevel@tonic-gate } 23457c478bd9Sstevel@tonic-gate } 23467c478bd9Sstevel@tonic-gate 23477c478bd9Sstevel@tonic-gate /* Save the minimum for later use */ 23487c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_min_bandwidth = min; 23497c478bd9Sstevel@tonic-gate 23507c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 23517c478bd9Sstevel@tonic-gate 23527c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 23537c478bd9Sstevel@tonic-gate } 23547c478bd9Sstevel@tonic-gate 23557c478bd9Sstevel@tonic-gate 23567c478bd9Sstevel@tonic-gate /* 23577c478bd9Sstevel@tonic-gate * ehci_deallocate_bandwidth: 23587c478bd9Sstevel@tonic-gate * 23597c478bd9Sstevel@tonic-gate * Deallocate bandwidth for the given node in the lattice and the length 23607c478bd9Sstevel@tonic-gate * of transfer. 23617c478bd9Sstevel@tonic-gate */ 23627c478bd9Sstevel@tonic-gate void 23637c478bd9Sstevel@tonic-gate ehci_deallocate_bandwidth( 23647c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 23657c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 23667c478bd9Sstevel@tonic-gate uint_t pnode, 23677c478bd9Sstevel@tonic-gate uchar_t smask, 23687c478bd9Sstevel@tonic-gate uchar_t cmask) 23697c478bd9Sstevel@tonic-gate { 23707c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 23717c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 23727c478bd9Sstevel@tonic-gate 23737c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth(ehcip, ph, pnode, smask, cmask); 23747c478bd9Sstevel@tonic-gate 23757c478bd9Sstevel@tonic-gate /* 23767c478bd9Sstevel@tonic-gate * For low/full speed usb devices, deallocate classic TT bandwidth 23777c478bd9Sstevel@tonic-gate * in additional to high speed bandwidth. 23787c478bd9Sstevel@tonic-gate */ 23797c478bd9Sstevel@tonic-gate if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) { 23807c478bd9Sstevel@tonic-gate 23817c478bd9Sstevel@tonic-gate /* Deallocate classic TT bandwidth */ 23827c478bd9Sstevel@tonic-gate ehci_deallocate_classic_tt_bandwidth(ehcip, ph, pnode); 23837c478bd9Sstevel@tonic-gate } 23847c478bd9Sstevel@tonic-gate } 23857c478bd9Sstevel@tonic-gate 23867c478bd9Sstevel@tonic-gate 23877c478bd9Sstevel@tonic-gate /* 23887c478bd9Sstevel@tonic-gate * ehci_deallocate_high_speed_bandwidth: 23897c478bd9Sstevel@tonic-gate * 23907c478bd9Sstevel@tonic-gate * Deallocate high speed bandwidth of a interrupt or isochronous endpoint. 23917c478bd9Sstevel@tonic-gate */ 23927c478bd9Sstevel@tonic-gate static void 23937c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth( 23947c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 23957c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 23967c478bd9Sstevel@tonic-gate uint_t pnode, 23977c478bd9Sstevel@tonic-gate uchar_t smask, 23987c478bd9Sstevel@tonic-gate uchar_t cmask) 23997c478bd9Sstevel@tonic-gate { 24007c478bd9Sstevel@tonic-gate uint_t height, leftmost; 24017c478bd9Sstevel@tonic-gate uint_t list_count; 24027c478bd9Sstevel@tonic-gate uint_t sbandwidth, cbandwidth; 24037c478bd9Sstevel@tonic-gate int interval; 24047c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 24057c478bd9Sstevel@tonic-gate usba_device_t *child_ud; 24067c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 24077c478bd9Sstevel@tonic-gate 24087c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 24097c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 24107c478bd9Sstevel@tonic-gate 24117c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 24127c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 24137c478bd9Sstevel@tonic-gate 24147c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 24157c478bd9Sstevel@tonic-gate 24167c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 24177c478bd9Sstevel@tonic-gate port_status = ph->p_usba_device->usb_port_status; 24187c478bd9Sstevel@tonic-gate 24197c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 24207c478bd9Sstevel@tonic-gate 24217c478bd9Sstevel@tonic-gate (void) ehci_compute_high_speed_bandwidth(ehcip, endpoint, 24227c478bd9Sstevel@tonic-gate port_status, &sbandwidth, &cbandwidth); 24237c478bd9Sstevel@tonic-gate 24247c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 24257c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 24267c478bd9Sstevel@tonic-gate 24277c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 24287c478bd9Sstevel@tonic-gate height = ehci_lattice_height(interval); 24297c478bd9Sstevel@tonic-gate 24307c478bd9Sstevel@tonic-gate /* 24317c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node 24327c478bd9Sstevel@tonic-gate */ 24337c478bd9Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height); 24347c478bd9Sstevel@tonic-gate 24357c478bd9Sstevel@tonic-gate list_count = EHCI_NUM_INTR_QH_LISTS/interval; 24367c478bd9Sstevel@tonic-gate 24377c478bd9Sstevel@tonic-gate /* Delete the bandwidth from the appropriate lists */ 24387c478bd9Sstevel@tonic-gate if (port_status == USBA_HIGH_SPEED_DEV) { 24397c478bd9Sstevel@tonic-gate 24407c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth, 24417c478bd9Sstevel@tonic-gate leftmost, list_count, smask); 24427c478bd9Sstevel@tonic-gate } else { 24437c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) == 24447c478bd9Sstevel@tonic-gate USB_EP_ATTR_INTR) { 24457c478bd9Sstevel@tonic-gate 24467c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth, 24477c478bd9Sstevel@tonic-gate leftmost, list_count, smask); 24487c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -cbandwidth, 24497c478bd9Sstevel@tonic-gate leftmost, list_count, cmask); 24507c478bd9Sstevel@tonic-gate } else { 24517c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 24527c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 24537c478bd9Sstevel@tonic-gate 24547c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth, 24557c478bd9Sstevel@tonic-gate leftmost, list_count, smask); 24567c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, 24577c478bd9Sstevel@tonic-gate -MAX_UFRAME_SITD_XFER, leftmost, 24587c478bd9Sstevel@tonic-gate list_count, cmask); 24597c478bd9Sstevel@tonic-gate } else { 24607c478bd9Sstevel@tonic-gate 24617c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, 24627c478bd9Sstevel@tonic-gate -MAX_UFRAME_SITD_XFER, leftmost, 24637c478bd9Sstevel@tonic-gate list_count, smask); 24647c478bd9Sstevel@tonic-gate } 24657c478bd9Sstevel@tonic-gate } 24667c478bd9Sstevel@tonic-gate } 24677c478bd9Sstevel@tonic-gate } 24687c478bd9Sstevel@tonic-gate 24697c478bd9Sstevel@tonic-gate /* 24707c478bd9Sstevel@tonic-gate * ehci_deallocate_classic_tt_bandwidth: 24717c478bd9Sstevel@tonic-gate * 24727c478bd9Sstevel@tonic-gate * Deallocate high speed bandwidth of a interrupt or isochronous endpoint. 24737c478bd9Sstevel@tonic-gate */ 24747c478bd9Sstevel@tonic-gate static void 24757c478bd9Sstevel@tonic-gate ehci_deallocate_classic_tt_bandwidth( 24767c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 24777c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph, 24787c478bd9Sstevel@tonic-gate uint_t pnode) 24797c478bd9Sstevel@tonic-gate { 24807c478bd9Sstevel@tonic-gate uint_t bandwidth, height, leftmost, list, min; 24817c478bd9Sstevel@tonic-gate int i, interval; 24827c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep; 24837c478bd9Sstevel@tonic-gate usba_device_t *child_ud, *parent_ud; 24847c478bd9Sstevel@tonic-gate usb_port_status_t port_status; 24857c478bd9Sstevel@tonic-gate 24867c478bd9Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */ 24877c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 24887c478bd9Sstevel@tonic-gate 24897c478bd9Sstevel@tonic-gate /* Get child's usba device structure */ 24907c478bd9Sstevel@tonic-gate child_ud = ph->p_usba_device; 24917c478bd9Sstevel@tonic-gate 24927c478bd9Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex); 24937c478bd9Sstevel@tonic-gate 24947c478bd9Sstevel@tonic-gate /* Get the current usb device's port status */ 24957c478bd9Sstevel@tonic-gate port_status = child_ud->usb_port_status; 24967c478bd9Sstevel@tonic-gate 24977c478bd9Sstevel@tonic-gate /* Get the parent high speed hub's usba device structure */ 24987c478bd9Sstevel@tonic-gate parent_ud = child_ud->usb_hs_hub_usba_dev; 24997c478bd9Sstevel@tonic-gate 25007c478bd9Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex); 25017c478bd9Sstevel@tonic-gate 25027c478bd9Sstevel@tonic-gate /* Obtain the bandwidth */ 25037c478bd9Sstevel@tonic-gate (void) ehci_compute_classic_bandwidth(endpoint, 25047c478bd9Sstevel@tonic-gate port_status, &bandwidth); 25057c478bd9Sstevel@tonic-gate 25067c478bd9Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */ 25077c478bd9Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status); 25087c478bd9Sstevel@tonic-gate 25097c478bd9Sstevel@tonic-gate /* Find the height in the tree */ 25107c478bd9Sstevel@tonic-gate height = ehci_lattice_height(interval); 25117c478bd9Sstevel@tonic-gate 25127c478bd9Sstevel@tonic-gate /* Find the leftmost leaf in the subtree specified by the node */ 25137c478bd9Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height); 25147c478bd9Sstevel@tonic-gate 25157c478bd9Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex); 25167c478bd9Sstevel@tonic-gate 25177c478bd9Sstevel@tonic-gate /* Delete the bandwidth from the appropriate lists */ 25187c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) { 25197c478bd9Sstevel@tonic-gate list = ehci_index[leftmost + i]; 25207c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_bandwidth[list] -= bandwidth; 25217c478bd9Sstevel@tonic-gate } 25227c478bd9Sstevel@tonic-gate 25237c478bd9Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */ 25247c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[0]; 25257c478bd9Sstevel@tonic-gate 25267c478bd9Sstevel@tonic-gate for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) { 25277c478bd9Sstevel@tonic-gate if (parent_ud->usb_hs_hub_bandwidth[i] < min) { 25287c478bd9Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[i]; 25297c478bd9Sstevel@tonic-gate } 25307c478bd9Sstevel@tonic-gate } 25317c478bd9Sstevel@tonic-gate 25327c478bd9Sstevel@tonic-gate /* Save the minimum for later use */ 25337c478bd9Sstevel@tonic-gate parent_ud->usb_hs_hub_min_bandwidth = min; 25347c478bd9Sstevel@tonic-gate 25357c478bd9Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex); 25367c478bd9Sstevel@tonic-gate } 25377c478bd9Sstevel@tonic-gate 25387c478bd9Sstevel@tonic-gate 25397c478bd9Sstevel@tonic-gate /* 25407c478bd9Sstevel@tonic-gate * ehci_compute_high_speed_bandwidth: 25417c478bd9Sstevel@tonic-gate * 25427c478bd9Sstevel@tonic-gate * Given a periodic endpoint (interrupt or isochronous) determine the total 25437c478bd9Sstevel@tonic-gate * bandwidth for one transaction. The EHCI host controller traverses the 25447c478bd9Sstevel@tonic-gate * endpoint descriptor lists on a first-come-first-serve basis. When the HC 25457c478bd9Sstevel@tonic-gate * services an endpoint, only a single transaction attempt is made. The HC 25467c478bd9Sstevel@tonic-gate * moves to the next Endpoint Descriptor after the first transaction attempt 25477c478bd9Sstevel@tonic-gate * rather than finishing the entire Transfer Descriptor. Therefore, when a 25487c478bd9Sstevel@tonic-gate * Transfer Descriptor is inserted into the lattice, we will only count the 25497c478bd9Sstevel@tonic-gate * number of bytes for one transaction. 25507c478bd9Sstevel@tonic-gate * 25517c478bd9Sstevel@tonic-gate * The following are the formulas used for calculating bandwidth in terms 25527c478bd9Sstevel@tonic-gate * bytes and it is for the single USB high speed transaction. The protocol 25537c478bd9Sstevel@tonic-gate * overheads will be different for each of type of USB transfer & all these 25547c478bd9Sstevel@tonic-gate * formulas & protocol overheads are derived from the 5.11.3 section of the 25557c478bd9Sstevel@tonic-gate * USB 2.0 Specification. 25567c478bd9Sstevel@tonic-gate * 25577c478bd9Sstevel@tonic-gate * High-Speed: 25587c478bd9Sstevel@tonic-gate * Protocol overhead + ((MaxPktSz * 7)/6) + Host_Delay 25597c478bd9Sstevel@tonic-gate * 25607c478bd9Sstevel@tonic-gate * Split Transaction: (Low/Full speed devices connected behind usb2.0 hub) 25617c478bd9Sstevel@tonic-gate * 25627c478bd9Sstevel@tonic-gate * Protocol overhead + Split transaction overhead + 25637c478bd9Sstevel@tonic-gate * ((MaxPktSz * 7)/6) + Host_Delay; 25647c478bd9Sstevel@tonic-gate */ 25657c478bd9Sstevel@tonic-gate /* ARGSUSED */ 25667c478bd9Sstevel@tonic-gate static int 25677c478bd9Sstevel@tonic-gate ehci_compute_high_speed_bandwidth( 25687c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 25697c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 25707c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 25717c478bd9Sstevel@tonic-gate uint_t *sbandwidth, 25727c478bd9Sstevel@tonic-gate uint_t *cbandwidth) 25737c478bd9Sstevel@tonic-gate { 25747c478bd9Sstevel@tonic-gate ushort_t maxpacketsize = endpoint->wMaxPacketSize; 25757c478bd9Sstevel@tonic-gate 25767c478bd9Sstevel@tonic-gate /* Return failure if endpoint maximum packet is zero */ 25777c478bd9Sstevel@tonic-gate if (maxpacketsize == 0) { 25787c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl, 25797c478bd9Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: Periodic endpoint " 25807c478bd9Sstevel@tonic-gate "with zero endpoint maximum packet size is not supported"); 25817c478bd9Sstevel@tonic-gate 25827c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 25837c478bd9Sstevel@tonic-gate } 25847c478bd9Sstevel@tonic-gate 25857c478bd9Sstevel@tonic-gate /* Add bit-stuffing overhead */ 25867c478bd9Sstevel@tonic-gate maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6); 25877c478bd9Sstevel@tonic-gate 25887c478bd9Sstevel@tonic-gate /* Add Host Controller specific delay to required bandwidth */ 25897c478bd9Sstevel@tonic-gate *sbandwidth = EHCI_HOST_CONTROLLER_DELAY; 25907c478bd9Sstevel@tonic-gate 25917c478bd9Sstevel@tonic-gate /* Add xfer specific protocol overheads */ 25927c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 25937c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) { 25947c478bd9Sstevel@tonic-gate /* High speed interrupt transaction */ 25957c478bd9Sstevel@tonic-gate *sbandwidth += HS_NON_ISOC_PROTO_OVERHEAD; 25967c478bd9Sstevel@tonic-gate } else { 25977c478bd9Sstevel@tonic-gate /* Isochronous transaction */ 25987c478bd9Sstevel@tonic-gate *sbandwidth += HS_ISOC_PROTO_OVERHEAD; 25997c478bd9Sstevel@tonic-gate } 26007c478bd9Sstevel@tonic-gate 26017c478bd9Sstevel@tonic-gate /* 26027c478bd9Sstevel@tonic-gate * For low/full speed devices, add split transaction specific 26037c478bd9Sstevel@tonic-gate * overheads. 26047c478bd9Sstevel@tonic-gate */ 26057c478bd9Sstevel@tonic-gate if (port_status != USBA_HIGH_SPEED_DEV) { 26067c478bd9Sstevel@tonic-gate /* 26077c478bd9Sstevel@tonic-gate * Add start and complete split transaction 26087c478bd9Sstevel@tonic-gate * tokens overheads. 26097c478bd9Sstevel@tonic-gate */ 26107c478bd9Sstevel@tonic-gate *cbandwidth = *sbandwidth + COMPLETE_SPLIT_OVERHEAD; 26117c478bd9Sstevel@tonic-gate *sbandwidth += START_SPLIT_OVERHEAD; 26127c478bd9Sstevel@tonic-gate 26137c478bd9Sstevel@tonic-gate /* Add data overhead depending on data direction */ 26147c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 26157c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 26167c478bd9Sstevel@tonic-gate *cbandwidth += maxpacketsize; 26177c478bd9Sstevel@tonic-gate } else { 26187c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 26197c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) { 26207c478bd9Sstevel@tonic-gate /* There is no compete splits for out */ 26217c478bd9Sstevel@tonic-gate *cbandwidth = 0; 26227c478bd9Sstevel@tonic-gate } 26237c478bd9Sstevel@tonic-gate *sbandwidth += maxpacketsize; 26247c478bd9Sstevel@tonic-gate } 26257c478bd9Sstevel@tonic-gate } else { 26267c478bd9Sstevel@tonic-gate uint_t xactions; 26277c478bd9Sstevel@tonic-gate 26287c478bd9Sstevel@tonic-gate /* Get the max transactions per microframe */ 26297c478bd9Sstevel@tonic-gate xactions = ((maxpacketsize & USB_EP_MAX_XACTS_MASK) >> 26307c478bd9Sstevel@tonic-gate USB_EP_MAX_XACTS_SHIFT) + 1; 26317c478bd9Sstevel@tonic-gate 26327c478bd9Sstevel@tonic-gate /* High speed transaction */ 26337c478bd9Sstevel@tonic-gate *sbandwidth += maxpacketsize; 26347c478bd9Sstevel@tonic-gate 26357c478bd9Sstevel@tonic-gate /* Calculate bandwidth per micro-frame */ 26367c478bd9Sstevel@tonic-gate *sbandwidth *= xactions; 26377c478bd9Sstevel@tonic-gate 26387c478bd9Sstevel@tonic-gate *cbandwidth = 0; 26397c478bd9Sstevel@tonic-gate } 26407c478bd9Sstevel@tonic-gate 26417c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 26427c478bd9Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: " 26437c478bd9Sstevel@tonic-gate "Start split bandwidth %d Complete split bandwidth %d", 26447c478bd9Sstevel@tonic-gate *sbandwidth, *cbandwidth); 26457c478bd9Sstevel@tonic-gate 26467c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 26477c478bd9Sstevel@tonic-gate } 26487c478bd9Sstevel@tonic-gate 26497c478bd9Sstevel@tonic-gate 26507c478bd9Sstevel@tonic-gate /* 26517c478bd9Sstevel@tonic-gate * ehci_compute_classic_bandwidth: 26527c478bd9Sstevel@tonic-gate * 26537c478bd9Sstevel@tonic-gate * Given a periodic endpoint (interrupt or isochronous) determine the total 26547c478bd9Sstevel@tonic-gate * bandwidth for one transaction. The EHCI host controller traverses the 26557c478bd9Sstevel@tonic-gate * endpoint descriptor lists on a first-come-first-serve basis. When the HC 26567c478bd9Sstevel@tonic-gate * services an endpoint, only a single transaction attempt is made. The HC 26577c478bd9Sstevel@tonic-gate * moves to the next Endpoint Descriptor after the first transaction attempt 26587c478bd9Sstevel@tonic-gate * rather than finishing the entire Transfer Descriptor. Therefore, when a 26597c478bd9Sstevel@tonic-gate * Transfer Descriptor is inserted into the lattice, we will only count the 26607c478bd9Sstevel@tonic-gate * number of bytes for one transaction. 26617c478bd9Sstevel@tonic-gate * 26627c478bd9Sstevel@tonic-gate * The following are the formulas used for calculating bandwidth in terms 26637c478bd9Sstevel@tonic-gate * bytes and it is for the single USB high speed transaction. The protocol 26647c478bd9Sstevel@tonic-gate * overheads will be different for each of type of USB transfer & all these 26657c478bd9Sstevel@tonic-gate * formulas & protocol overheads are derived from the 5.11.3 section of the 26667c478bd9Sstevel@tonic-gate * USB 2.0 Specification. 26677c478bd9Sstevel@tonic-gate * 26687c478bd9Sstevel@tonic-gate * Low-Speed: 26697c478bd9Sstevel@tonic-gate * Protocol overhead + Hub LS overhead + 26707c478bd9Sstevel@tonic-gate * (Low Speed clock * ((MaxPktSz * 7)/6)) + TT_Delay 26717c478bd9Sstevel@tonic-gate * 26727c478bd9Sstevel@tonic-gate * Full-Speed: 26737c478bd9Sstevel@tonic-gate * Protocol overhead + ((MaxPktSz * 7)/6) + TT_Delay 26747c478bd9Sstevel@tonic-gate */ 26757c478bd9Sstevel@tonic-gate /* ARGSUSED */ 26767c478bd9Sstevel@tonic-gate static int 26777c478bd9Sstevel@tonic-gate ehci_compute_classic_bandwidth( 26787c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 26797c478bd9Sstevel@tonic-gate usb_port_status_t port_status, 26807c478bd9Sstevel@tonic-gate uint_t *bandwidth) 26817c478bd9Sstevel@tonic-gate { 26827c478bd9Sstevel@tonic-gate ushort_t maxpacketsize = endpoint->wMaxPacketSize; 26837c478bd9Sstevel@tonic-gate 26847c478bd9Sstevel@tonic-gate /* 26857c478bd9Sstevel@tonic-gate * If endpoint maximum packet is zero, then return immediately. 26867c478bd9Sstevel@tonic-gate */ 26877c478bd9Sstevel@tonic-gate if (maxpacketsize == 0) { 26887c478bd9Sstevel@tonic-gate 26897c478bd9Sstevel@tonic-gate return (USB_NOT_SUPPORTED); 26907c478bd9Sstevel@tonic-gate } 26917c478bd9Sstevel@tonic-gate 26927c478bd9Sstevel@tonic-gate /* Add TT delay to required bandwidth */ 26937c478bd9Sstevel@tonic-gate *bandwidth = TT_DELAY; 26947c478bd9Sstevel@tonic-gate 26957c478bd9Sstevel@tonic-gate /* Add bit-stuffing overhead */ 26967c478bd9Sstevel@tonic-gate maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6); 26977c478bd9Sstevel@tonic-gate 26987c478bd9Sstevel@tonic-gate switch (port_status) { 26997c478bd9Sstevel@tonic-gate case USBA_LOW_SPEED_DEV: 27007c478bd9Sstevel@tonic-gate /* Low speed interrupt transaction */ 27017c478bd9Sstevel@tonic-gate *bandwidth += (LOW_SPEED_PROTO_OVERHEAD + 27027c478bd9Sstevel@tonic-gate HUB_LOW_SPEED_PROTO_OVERHEAD + 27037c478bd9Sstevel@tonic-gate (LOW_SPEED_CLOCK * maxpacketsize)); 27047c478bd9Sstevel@tonic-gate break; 27057c478bd9Sstevel@tonic-gate case USBA_FULL_SPEED_DEV: 27067c478bd9Sstevel@tonic-gate /* Full speed transaction */ 27077c478bd9Sstevel@tonic-gate *bandwidth += maxpacketsize; 27087c478bd9Sstevel@tonic-gate 27097c478bd9Sstevel@tonic-gate /* Add xfer specific protocol overheads */ 27107c478bd9Sstevel@tonic-gate if ((endpoint->bmAttributes & 27117c478bd9Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) { 27127c478bd9Sstevel@tonic-gate /* Full speed interrupt transaction */ 27137c478bd9Sstevel@tonic-gate *bandwidth += FS_NON_ISOC_PROTO_OVERHEAD; 27147c478bd9Sstevel@tonic-gate } else { 27157c478bd9Sstevel@tonic-gate /* Isochronous and input transaction */ 27167c478bd9Sstevel@tonic-gate if ((endpoint->bEndpointAddress & 27177c478bd9Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) { 27187c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_INPUT_PROTO_OVERHEAD; 27197c478bd9Sstevel@tonic-gate } else { 27207c478bd9Sstevel@tonic-gate /* Isochronous and output transaction */ 27217c478bd9Sstevel@tonic-gate *bandwidth += FS_ISOC_OUTPUT_PROTO_OVERHEAD; 27227c478bd9Sstevel@tonic-gate } 27237c478bd9Sstevel@tonic-gate } 27247c478bd9Sstevel@tonic-gate break; 27257c478bd9Sstevel@tonic-gate } 27267c478bd9Sstevel@tonic-gate 27277c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 27287c478bd9Sstevel@tonic-gate } 27297c478bd9Sstevel@tonic-gate 27307c478bd9Sstevel@tonic-gate 27317c478bd9Sstevel@tonic-gate /* 27327c478bd9Sstevel@tonic-gate * ehci_adjust_polling_interval: 27337c478bd9Sstevel@tonic-gate * 27347c478bd9Sstevel@tonic-gate * Adjust bandwidth according usb device speed. 27357c478bd9Sstevel@tonic-gate */ 27367c478bd9Sstevel@tonic-gate /* ARGSUSED */ 27377c478bd9Sstevel@tonic-gate int 27387c478bd9Sstevel@tonic-gate ehci_adjust_polling_interval( 27397c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 27407c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 27417c478bd9Sstevel@tonic-gate usb_port_status_t port_status) 27427c478bd9Sstevel@tonic-gate { 27437c478bd9Sstevel@tonic-gate uint_t interval; 27447c478bd9Sstevel@tonic-gate int i = 0; 27457c478bd9Sstevel@tonic-gate 27467c478bd9Sstevel@tonic-gate /* Get the polling interval */ 27477c478bd9Sstevel@tonic-gate interval = endpoint->bInterval; 27487c478bd9Sstevel@tonic-gate 27497c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 27507c478bd9Sstevel@tonic-gate "ehci_adjust_polling_interval: Polling interval 0x%x", interval); 27517c478bd9Sstevel@tonic-gate 27527c478bd9Sstevel@tonic-gate /* 27537c478bd9Sstevel@tonic-gate * According USB 2.0 Specifications, a high-speed endpoint's 27547c478bd9Sstevel@tonic-gate * polling intervals are specified interms of 125us or micro 27557c478bd9Sstevel@tonic-gate * frame, where as full/low endpoint's polling intervals are 27567c478bd9Sstevel@tonic-gate * specified in milliseconds. 27577c478bd9Sstevel@tonic-gate * 27587c478bd9Sstevel@tonic-gate * A high speed interrupt/isochronous endpoints can specify 27597c478bd9Sstevel@tonic-gate * desired polling interval between 1 to 16 micro-frames, 27607c478bd9Sstevel@tonic-gate * where as full/low endpoints can specify between 1 to 255 27617c478bd9Sstevel@tonic-gate * milliseconds. 27627c478bd9Sstevel@tonic-gate */ 27637c478bd9Sstevel@tonic-gate switch (port_status) { 27647c478bd9Sstevel@tonic-gate case USBA_LOW_SPEED_DEV: 27657c478bd9Sstevel@tonic-gate /* 27667c478bd9Sstevel@tonic-gate * Low speed endpoints are limited to specifying 27677c478bd9Sstevel@tonic-gate * only 8ms to 255ms in this driver. If a device 27687c478bd9Sstevel@tonic-gate * reports a polling interval that is less than 8ms, 27697c478bd9Sstevel@tonic-gate * it will use 8 ms instead. 27707c478bd9Sstevel@tonic-gate */ 27717c478bd9Sstevel@tonic-gate if (interval < LS_MIN_POLL_INTERVAL) { 27727c478bd9Sstevel@tonic-gate 27737c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 27747c478bd9Sstevel@tonic-gate "Low speed endpoint's poll interval of %d ms " 27757c478bd9Sstevel@tonic-gate "is below threshold. Rounding up to %d ms", 27767c478bd9Sstevel@tonic-gate interval, LS_MIN_POLL_INTERVAL); 27777c478bd9Sstevel@tonic-gate 27787c478bd9Sstevel@tonic-gate interval = LS_MIN_POLL_INTERVAL; 27797c478bd9Sstevel@tonic-gate } 27807c478bd9Sstevel@tonic-gate 27817c478bd9Sstevel@tonic-gate /* 27827c478bd9Sstevel@tonic-gate * Return an error if the polling interval is greater 27837c478bd9Sstevel@tonic-gate * than 255ms. 27847c478bd9Sstevel@tonic-gate */ 27857c478bd9Sstevel@tonic-gate if (interval > LS_MAX_POLL_INTERVAL) { 27867c478bd9Sstevel@tonic-gate 27877c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 27887c478bd9Sstevel@tonic-gate "Low speed endpoint's poll interval is " 27897c478bd9Sstevel@tonic-gate "greater than %d ms", LS_MAX_POLL_INTERVAL); 27907c478bd9Sstevel@tonic-gate 27917c478bd9Sstevel@tonic-gate return (USB_FAILURE); 27927c478bd9Sstevel@tonic-gate } 27937c478bd9Sstevel@tonic-gate break; 27947c478bd9Sstevel@tonic-gate 27957c478bd9Sstevel@tonic-gate case USBA_FULL_SPEED_DEV: 27967c478bd9Sstevel@tonic-gate /* 27977c478bd9Sstevel@tonic-gate * Return an error if the polling interval is less 27987c478bd9Sstevel@tonic-gate * than 1ms and greater than 255ms. 27997c478bd9Sstevel@tonic-gate */ 28007c478bd9Sstevel@tonic-gate if ((interval < FS_MIN_POLL_INTERVAL) && 28017c478bd9Sstevel@tonic-gate (interval > FS_MAX_POLL_INTERVAL)) { 28027c478bd9Sstevel@tonic-gate 28037c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 28047c478bd9Sstevel@tonic-gate "Full speed endpoint's poll interval must " 28057c478bd9Sstevel@tonic-gate "be between %d and %d ms", FS_MIN_POLL_INTERVAL, 28067c478bd9Sstevel@tonic-gate FS_MAX_POLL_INTERVAL); 28077c478bd9Sstevel@tonic-gate 28087c478bd9Sstevel@tonic-gate return (USB_FAILURE); 28097c478bd9Sstevel@tonic-gate } 28107c478bd9Sstevel@tonic-gate break; 28117c478bd9Sstevel@tonic-gate case USBA_HIGH_SPEED_DEV: 28127c478bd9Sstevel@tonic-gate /* 28137c478bd9Sstevel@tonic-gate * Return an error if the polling interval is less 1 28147c478bd9Sstevel@tonic-gate * and greater than 16. Convert this value to 125us 28157c478bd9Sstevel@tonic-gate * units using 2^(bInterval -1). refer usb 2.0 spec 28167c478bd9Sstevel@tonic-gate * page 51 for details. 28177c478bd9Sstevel@tonic-gate */ 28187c478bd9Sstevel@tonic-gate if ((interval < HS_MIN_POLL_INTERVAL) && 28197c478bd9Sstevel@tonic-gate (interval > HS_MAX_POLL_INTERVAL)) { 28207c478bd9Sstevel@tonic-gate 28217c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl, 28227c478bd9Sstevel@tonic-gate "High speed endpoint's poll interval " 28237c478bd9Sstevel@tonic-gate "must be between %d and %d units", 28247c478bd9Sstevel@tonic-gate HS_MIN_POLL_INTERVAL, HS_MAX_POLL_INTERVAL); 28257c478bd9Sstevel@tonic-gate 28267c478bd9Sstevel@tonic-gate return (USB_FAILURE); 28277c478bd9Sstevel@tonic-gate } 28287c478bd9Sstevel@tonic-gate 28297c478bd9Sstevel@tonic-gate /* Adjust high speed device polling interval */ 28307c478bd9Sstevel@tonic-gate interval = 28317c478bd9Sstevel@tonic-gate ehci_adjust_high_speed_polling_interval(ehcip, endpoint); 28327c478bd9Sstevel@tonic-gate 28337c478bd9Sstevel@tonic-gate break; 28347c478bd9Sstevel@tonic-gate } 28357c478bd9Sstevel@tonic-gate 28367c478bd9Sstevel@tonic-gate /* 28377c478bd9Sstevel@tonic-gate * If polling interval is greater than 32ms, 28387c478bd9Sstevel@tonic-gate * adjust polling interval equal to 32ms. 28397c478bd9Sstevel@tonic-gate */ 28407c478bd9Sstevel@tonic-gate if (interval > EHCI_NUM_INTR_QH_LISTS) { 28417c478bd9Sstevel@tonic-gate interval = EHCI_NUM_INTR_QH_LISTS; 28427c478bd9Sstevel@tonic-gate } 28437c478bd9Sstevel@tonic-gate 28447c478bd9Sstevel@tonic-gate /* 28457c478bd9Sstevel@tonic-gate * Find the nearest power of 2 that's less 28467c478bd9Sstevel@tonic-gate * than interval. 28477c478bd9Sstevel@tonic-gate */ 28487c478bd9Sstevel@tonic-gate while ((ehci_pow_2(i)) <= interval) { 28497c478bd9Sstevel@tonic-gate i++; 28507c478bd9Sstevel@tonic-gate } 28517c478bd9Sstevel@tonic-gate 28527c478bd9Sstevel@tonic-gate return (ehci_pow_2((i - 1))); 28537c478bd9Sstevel@tonic-gate } 28547c478bd9Sstevel@tonic-gate 28557c478bd9Sstevel@tonic-gate 28567c478bd9Sstevel@tonic-gate /* 28577c478bd9Sstevel@tonic-gate * ehci_adjust_high_speed_polling_interval: 28587c478bd9Sstevel@tonic-gate */ 28597c478bd9Sstevel@tonic-gate /* ARGSUSED */ 28607c478bd9Sstevel@tonic-gate static int 28617c478bd9Sstevel@tonic-gate ehci_adjust_high_speed_polling_interval( 28627c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 28637c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint) 28647c478bd9Sstevel@tonic-gate { 28657c478bd9Sstevel@tonic-gate uint_t interval; 28667c478bd9Sstevel@tonic-gate 28677c478bd9Sstevel@tonic-gate /* Get the polling interval */ 28687c478bd9Sstevel@tonic-gate interval = ehci_pow_2(endpoint->bInterval - 1); 28697c478bd9Sstevel@tonic-gate 28707c478bd9Sstevel@tonic-gate /* 28717c478bd9Sstevel@tonic-gate * Convert polling interval from micro seconds 28727c478bd9Sstevel@tonic-gate * to milli seconds. 28737c478bd9Sstevel@tonic-gate */ 28747c478bd9Sstevel@tonic-gate if (interval <= EHCI_MAX_UFRAMES) { 28757c478bd9Sstevel@tonic-gate interval = 1; 28767c478bd9Sstevel@tonic-gate } else { 28777c478bd9Sstevel@tonic-gate interval = interval/EHCI_MAX_UFRAMES; 28787c478bd9Sstevel@tonic-gate } 28797c478bd9Sstevel@tonic-gate 28807c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 28817c478bd9Sstevel@tonic-gate "ehci_adjust_high_speed_polling_interval: " 28827c478bd9Sstevel@tonic-gate "High speed adjusted interval 0x%x", interval); 28837c478bd9Sstevel@tonic-gate 28847c478bd9Sstevel@tonic-gate return (interval); 28857c478bd9Sstevel@tonic-gate } 28867c478bd9Sstevel@tonic-gate 28877c478bd9Sstevel@tonic-gate 28887c478bd9Sstevel@tonic-gate /* 28897c478bd9Sstevel@tonic-gate * ehci_lattice_height: 28907c478bd9Sstevel@tonic-gate * 28917c478bd9Sstevel@tonic-gate * Given the requested bandwidth, find the height in the tree at which the 28927c478bd9Sstevel@tonic-gate * nodes for this bandwidth fall. The height is measured as the number of 28937c478bd9Sstevel@tonic-gate * nodes from the leaf to the level specified by bandwidth The root of the 28947c478bd9Sstevel@tonic-gate * tree is at height TREE_HEIGHT. 28957c478bd9Sstevel@tonic-gate */ 28967c478bd9Sstevel@tonic-gate static uint_t 28977c478bd9Sstevel@tonic-gate ehci_lattice_height(uint_t interval) 28987c478bd9Sstevel@tonic-gate { 28997c478bd9Sstevel@tonic-gate return (TREE_HEIGHT - (ehci_log_2(interval))); 29007c478bd9Sstevel@tonic-gate } 29017c478bd9Sstevel@tonic-gate 29027c478bd9Sstevel@tonic-gate 29037c478bd9Sstevel@tonic-gate /* 29047c478bd9Sstevel@tonic-gate * ehci_lattice_parent: 29057c478bd9Sstevel@tonic-gate * 29067c478bd9Sstevel@tonic-gate * Given a node in the lattice, find the index of the parent node 29077c478bd9Sstevel@tonic-gate */ 29087c478bd9Sstevel@tonic-gate static uint_t 29097c478bd9Sstevel@tonic-gate ehci_lattice_parent(uint_t node) 29107c478bd9Sstevel@tonic-gate { 29117c478bd9Sstevel@tonic-gate if ((node % 2) == 0) { 29127c478bd9Sstevel@tonic-gate 29137c478bd9Sstevel@tonic-gate return ((node/2) - 1); 29147c478bd9Sstevel@tonic-gate } else { 29157c478bd9Sstevel@tonic-gate 29167c478bd9Sstevel@tonic-gate return ((node + 1)/2 - 1); 29177c478bd9Sstevel@tonic-gate } 29187c478bd9Sstevel@tonic-gate } 29197c478bd9Sstevel@tonic-gate 29207c478bd9Sstevel@tonic-gate 29217c478bd9Sstevel@tonic-gate /* 29227c478bd9Sstevel@tonic-gate * ehci_find_periodic_node: 29237c478bd9Sstevel@tonic-gate * 29247c478bd9Sstevel@tonic-gate * Based on the "real" array leaf node and interval, get the periodic node. 29257c478bd9Sstevel@tonic-gate */ 29267c478bd9Sstevel@tonic-gate static uint_t 29277c478bd9Sstevel@tonic-gate ehci_find_periodic_node(uint_t leaf, int interval) { 29287c478bd9Sstevel@tonic-gate uint_t lattice_leaf; 29297c478bd9Sstevel@tonic-gate uint_t height = ehci_lattice_height(interval); 29307c478bd9Sstevel@tonic-gate uint_t pnode; 29317c478bd9Sstevel@tonic-gate int i; 29327c478bd9Sstevel@tonic-gate 29337c478bd9Sstevel@tonic-gate /* Get the leaf number in the lattice */ 29347c478bd9Sstevel@tonic-gate lattice_leaf = leaf + EHCI_NUM_INTR_QH_LISTS - 1; 29357c478bd9Sstevel@tonic-gate 29367c478bd9Sstevel@tonic-gate /* Get the node in the lattice based on the height and leaf */ 29377c478bd9Sstevel@tonic-gate pnode = lattice_leaf; 29387c478bd9Sstevel@tonic-gate for (i = 0; i < height; i++) { 29397c478bd9Sstevel@tonic-gate pnode = ehci_lattice_parent(pnode); 29407c478bd9Sstevel@tonic-gate } 29417c478bd9Sstevel@tonic-gate 29427c478bd9Sstevel@tonic-gate return (pnode); 29437c478bd9Sstevel@tonic-gate } 29447c478bd9Sstevel@tonic-gate 29457c478bd9Sstevel@tonic-gate 29467c478bd9Sstevel@tonic-gate /* 29477c478bd9Sstevel@tonic-gate * ehci_leftmost_leaf: 29487c478bd9Sstevel@tonic-gate * 29497c478bd9Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node. Height refers 29507c478bd9Sstevel@tonic-gate * to number of nodes from the bottom of the tree to the node, including the 29517c478bd9Sstevel@tonic-gate * node. 29527c478bd9Sstevel@tonic-gate * 29537c478bd9Sstevel@tonic-gate * The formula for a zero based tree is: 29547c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1 29557c478bd9Sstevel@tonic-gate * The leaf of the tree is an array, convert the number for the array. 29567c478bd9Sstevel@tonic-gate * Subtract the size of nodes not in the array 29577c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - 1 - (EHCI_NUM_INTR_QH_LISTS - 1) = 29587c478bd9Sstevel@tonic-gate * 2^H * Node + 2^H - EHCI_NUM_INTR_QH_LISTS = 29597c478bd9Sstevel@tonic-gate * 2^H * (Node + 1) - EHCI_NUM_INTR_QH_LISTS 29607c478bd9Sstevel@tonic-gate * 0 29617c478bd9Sstevel@tonic-gate * 1 2 29627c478bd9Sstevel@tonic-gate * 0 1 2 3 29637c478bd9Sstevel@tonic-gate */ 29647c478bd9Sstevel@tonic-gate static uint_t 29657c478bd9Sstevel@tonic-gate ehci_leftmost_leaf( 29667c478bd9Sstevel@tonic-gate uint_t node, 29677c478bd9Sstevel@tonic-gate uint_t height) 29687c478bd9Sstevel@tonic-gate { 29697c478bd9Sstevel@tonic-gate return ((ehci_pow_2(height) * (node + 1)) - EHCI_NUM_INTR_QH_LISTS); 29707c478bd9Sstevel@tonic-gate } 29717c478bd9Sstevel@tonic-gate 29727c478bd9Sstevel@tonic-gate 29737c478bd9Sstevel@tonic-gate /* 29747c478bd9Sstevel@tonic-gate * ehci_pow_2: 29757c478bd9Sstevel@tonic-gate * 29767c478bd9Sstevel@tonic-gate * Compute 2 to the power 29777c478bd9Sstevel@tonic-gate */ 29787c478bd9Sstevel@tonic-gate static uint_t 29797c478bd9Sstevel@tonic-gate ehci_pow_2(uint_t x) 29807c478bd9Sstevel@tonic-gate { 29817c478bd9Sstevel@tonic-gate if (x == 0) { 29827c478bd9Sstevel@tonic-gate 29837c478bd9Sstevel@tonic-gate return (1); 29847c478bd9Sstevel@tonic-gate } else { 29857c478bd9Sstevel@tonic-gate 29867c478bd9Sstevel@tonic-gate return (2 << (x - 1)); 29877c478bd9Sstevel@tonic-gate } 29887c478bd9Sstevel@tonic-gate } 29897c478bd9Sstevel@tonic-gate 29907c478bd9Sstevel@tonic-gate 29917c478bd9Sstevel@tonic-gate /* 29927c478bd9Sstevel@tonic-gate * ehci_log_2: 29937c478bd9Sstevel@tonic-gate * 29947c478bd9Sstevel@tonic-gate * Compute log base 2 of x 29957c478bd9Sstevel@tonic-gate */ 29967c478bd9Sstevel@tonic-gate static uint_t 29977c478bd9Sstevel@tonic-gate ehci_log_2(uint_t x) 29987c478bd9Sstevel@tonic-gate { 29997c478bd9Sstevel@tonic-gate int i = 0; 30007c478bd9Sstevel@tonic-gate 30017c478bd9Sstevel@tonic-gate while (x != 1) { 30027c478bd9Sstevel@tonic-gate x = x >> 1; 30037c478bd9Sstevel@tonic-gate i++; 30047c478bd9Sstevel@tonic-gate } 30057c478bd9Sstevel@tonic-gate 30067c478bd9Sstevel@tonic-gate return (i); 30077c478bd9Sstevel@tonic-gate } 30087c478bd9Sstevel@tonic-gate 30097c478bd9Sstevel@tonic-gate 30107c478bd9Sstevel@tonic-gate /* 30117c478bd9Sstevel@tonic-gate * ehci_find_bestfit_hs_mask: 30127c478bd9Sstevel@tonic-gate * 30137c478bd9Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation, and update the 30147c478bd9Sstevel@tonic-gate * bandwidth allocation. 30157c478bd9Sstevel@tonic-gate */ 30167c478bd9Sstevel@tonic-gate static int 30177c478bd9Sstevel@tonic-gate ehci_find_bestfit_hs_mask( 30187c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 30197c478bd9Sstevel@tonic-gate uchar_t *smask, 30207c478bd9Sstevel@tonic-gate uint_t *pnode, 30217c478bd9Sstevel@tonic-gate usb_ep_descr_t *endpoint, 30227c478bd9Sstevel@tonic-gate uint_t bandwidth, 30237c478bd9Sstevel@tonic-gate int interval) 30247c478bd9Sstevel@tonic-gate { 30257c478bd9Sstevel@tonic-gate int i; 30267c478bd9Sstevel@tonic-gate uint_t elements, index; 30277c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 30287c478bd9Sstevel@tonic-gate uint_t node_bandwidth, best_node_bandwidth; 30297c478bd9Sstevel@tonic-gate uint_t leaf_count; 30307c478bd9Sstevel@tonic-gate uchar_t bw_mask; 30317c478bd9Sstevel@tonic-gate uchar_t best_smask; 30327c478bd9Sstevel@tonic-gate 30337c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 30347c478bd9Sstevel@tonic-gate "ehci_find_bestfit_hs_mask: "); 30357c478bd9Sstevel@tonic-gate 30367c478bd9Sstevel@tonic-gate /* Get all the valid smasks */ 30377c478bd9Sstevel@tonic-gate switch (ehci_pow_2(endpoint->bInterval - 1)) { 30387c478bd9Sstevel@tonic-gate case EHCI_INTR_1US_POLL: 30397c478bd9Sstevel@tonic-gate index = EHCI_1US_MASK_INDEX; 30407c478bd9Sstevel@tonic-gate elements = EHCI_INTR_1US_POLL; 30417c478bd9Sstevel@tonic-gate break; 30427c478bd9Sstevel@tonic-gate case EHCI_INTR_2US_POLL: 30437c478bd9Sstevel@tonic-gate index = EHCI_2US_MASK_INDEX; 30447c478bd9Sstevel@tonic-gate elements = EHCI_INTR_2US_POLL; 30457c478bd9Sstevel@tonic-gate break; 30467c478bd9Sstevel@tonic-gate case EHCI_INTR_4US_POLL: 30477c478bd9Sstevel@tonic-gate index = EHCI_4US_MASK_INDEX; 30487c478bd9Sstevel@tonic-gate elements = EHCI_INTR_4US_POLL; 30497c478bd9Sstevel@tonic-gate break; 30507c478bd9Sstevel@tonic-gate case EHCI_INTR_XUS_POLL: 30517c478bd9Sstevel@tonic-gate default: 30527c478bd9Sstevel@tonic-gate index = EHCI_XUS_MASK_INDEX; 30537c478bd9Sstevel@tonic-gate elements = EHCI_INTR_XUS_POLL; 30547c478bd9Sstevel@tonic-gate break; 30557c478bd9Sstevel@tonic-gate } 30567c478bd9Sstevel@tonic-gate 30577c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 30587c478bd9Sstevel@tonic-gate 30597c478bd9Sstevel@tonic-gate /* 30607c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 30617c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 30627c478bd9Sstevel@tonic-gate */ 30637c478bd9Sstevel@tonic-gate best_smask = 0x00; 30647c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 30657c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 30667c478bd9Sstevel@tonic-gate /* Find the bandwidth mask */ 30677c478bd9Sstevel@tonic-gate node_bandwidth = ehci_calculate_bw_availability_mask(ehcip, 30687c478bd9Sstevel@tonic-gate bandwidth, ehci_index[array_leaf], leaf_count, &bw_mask); 30697c478bd9Sstevel@tonic-gate 30707c478bd9Sstevel@tonic-gate /* 30717c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 30727c478bd9Sstevel@tonic-gate * next leaf. 30737c478bd9Sstevel@tonic-gate */ 30747c478bd9Sstevel@tonic-gate if (bw_mask == 0x00) { 30757c478bd9Sstevel@tonic-gate continue; 30767c478bd9Sstevel@tonic-gate } 30777c478bd9Sstevel@tonic-gate 30787c478bd9Sstevel@tonic-gate /* 30797c478bd9Sstevel@tonic-gate * Now make sure our bandwidth requirements can be 30807c478bd9Sstevel@tonic-gate * satisfied with one of smasks in this node. 30817c478bd9Sstevel@tonic-gate */ 30827c478bd9Sstevel@tonic-gate *smask = 0x00; 30837c478bd9Sstevel@tonic-gate for (i = index; i < (index + elements); i++) { 30847c478bd9Sstevel@tonic-gate /* Check the start split mask value */ 30857c478bd9Sstevel@tonic-gate if (ehci_start_split_mask[index] & bw_mask) { 30867c478bd9Sstevel@tonic-gate *smask = ehci_start_split_mask[index]; 30877c478bd9Sstevel@tonic-gate break; 30887c478bd9Sstevel@tonic-gate } 30897c478bd9Sstevel@tonic-gate } 30907c478bd9Sstevel@tonic-gate 30917c478bd9Sstevel@tonic-gate /* 30927c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 30937c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 30947c478bd9Sstevel@tonic-gate * - or - 30957c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 30967c478bd9Sstevel@tonic-gate */ 30977c478bd9Sstevel@tonic-gate if ((*smask != 0x00) && 30987c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 3099*29aca3ebSlc (best_node_bandwidth > node_bandwidth))) { 31007c478bd9Sstevel@tonic-gate 31017c478bd9Sstevel@tonic-gate best_node_bandwidth = node_bandwidth; 31027c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 31037c478bd9Sstevel@tonic-gate best_smask = *smask; 31047c478bd9Sstevel@tonic-gate } 31057c478bd9Sstevel@tonic-gate } 31067c478bd9Sstevel@tonic-gate 31077c478bd9Sstevel@tonic-gate /* 31087c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 31097c478bd9Sstevel@tonic-gate * appropriate variables and return success. 31107c478bd9Sstevel@tonic-gate */ 31117c478bd9Sstevel@tonic-gate if (best_smask) { 31127c478bd9Sstevel@tonic-gate *smask = best_smask; 31137c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 31147c478bd9Sstevel@tonic-gate interval); 31157c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, bandwidth, 31167c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 31177c478bd9Sstevel@tonic-gate 31187c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 31197c478bd9Sstevel@tonic-gate } 31207c478bd9Sstevel@tonic-gate 31217c478bd9Sstevel@tonic-gate return (USB_FAILURE); 31227c478bd9Sstevel@tonic-gate } 31237c478bd9Sstevel@tonic-gate 31247c478bd9Sstevel@tonic-gate 31257c478bd9Sstevel@tonic-gate /* 31267c478bd9Sstevel@tonic-gate * ehci_find_bestfit_ls_intr_mask: 31277c478bd9Sstevel@tonic-gate * 31287c478bd9Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation. 31297c478bd9Sstevel@tonic-gate */ 31307c478bd9Sstevel@tonic-gate static int 31317c478bd9Sstevel@tonic-gate ehci_find_bestfit_ls_intr_mask( 31327c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 31337c478bd9Sstevel@tonic-gate uchar_t *smask, 31347c478bd9Sstevel@tonic-gate uchar_t *cmask, 31357c478bd9Sstevel@tonic-gate uint_t *pnode, 31367c478bd9Sstevel@tonic-gate uint_t sbandwidth, 31377c478bd9Sstevel@tonic-gate uint_t cbandwidth, 31387c478bd9Sstevel@tonic-gate int interval) 31397c478bd9Sstevel@tonic-gate { 31407c478bd9Sstevel@tonic-gate int i; 31417c478bd9Sstevel@tonic-gate uint_t elements, index; 31427c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 31437c478bd9Sstevel@tonic-gate uint_t node_sbandwidth, node_cbandwidth; 31447c478bd9Sstevel@tonic-gate uint_t best_node_bandwidth; 31457c478bd9Sstevel@tonic-gate uint_t leaf_count; 31467c478bd9Sstevel@tonic-gate uchar_t bw_smask, bw_cmask; 31477c478bd9Sstevel@tonic-gate uchar_t best_smask, best_cmask; 31487c478bd9Sstevel@tonic-gate 31497c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 31507c478bd9Sstevel@tonic-gate "ehci_find_bestfit_ls_intr_mask: "); 31517c478bd9Sstevel@tonic-gate 31527c478bd9Sstevel@tonic-gate /* For low and full speed devices */ 31537c478bd9Sstevel@tonic-gate index = EHCI_XUS_MASK_INDEX; 31547c478bd9Sstevel@tonic-gate elements = EHCI_INTR_4MS_POLL; 31557c478bd9Sstevel@tonic-gate 31567c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 31577c478bd9Sstevel@tonic-gate 31587c478bd9Sstevel@tonic-gate /* 31597c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 31607c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 31617c478bd9Sstevel@tonic-gate */ 31627c478bd9Sstevel@tonic-gate best_smask = 0x00; 31637c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 31647c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 31657c478bd9Sstevel@tonic-gate /* Find the bandwidth mask */ 31667c478bd9Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip, 31677c478bd9Sstevel@tonic-gate sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask); 31687c478bd9Sstevel@tonic-gate node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip, 31697c478bd9Sstevel@tonic-gate cbandwidth, ehci_index[array_leaf], leaf_count, &bw_cmask); 31707c478bd9Sstevel@tonic-gate 31717c478bd9Sstevel@tonic-gate /* 31727c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 31737c478bd9Sstevel@tonic-gate * next leaf. 31747c478bd9Sstevel@tonic-gate */ 31757c478bd9Sstevel@tonic-gate if ((bw_smask == 0x00) || (bw_cmask == 0x00)) { 31767c478bd9Sstevel@tonic-gate continue; 31777c478bd9Sstevel@tonic-gate } 31787c478bd9Sstevel@tonic-gate 31797c478bd9Sstevel@tonic-gate /* 31807c478bd9Sstevel@tonic-gate * Now make sure our bandwidth requirements can be 31817c478bd9Sstevel@tonic-gate * satisfied with one of smasks in this node. 31827c478bd9Sstevel@tonic-gate */ 31837c478bd9Sstevel@tonic-gate *smask = 0x00; 31847c478bd9Sstevel@tonic-gate *cmask = 0x00; 31857c478bd9Sstevel@tonic-gate for (i = index; i < (index + elements); i++) { 31867c478bd9Sstevel@tonic-gate /* Check the start split mask value */ 31877c478bd9Sstevel@tonic-gate if ((ehci_start_split_mask[index] & bw_smask) && 31887c478bd9Sstevel@tonic-gate (ehci_intr_complete_split_mask[index] & bw_cmask)) { 31897c478bd9Sstevel@tonic-gate *smask = ehci_start_split_mask[index]; 31907c478bd9Sstevel@tonic-gate *cmask = ehci_intr_complete_split_mask[index]; 31917c478bd9Sstevel@tonic-gate break; 31927c478bd9Sstevel@tonic-gate } 31937c478bd9Sstevel@tonic-gate } 31947c478bd9Sstevel@tonic-gate 31957c478bd9Sstevel@tonic-gate /* 31967c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 31977c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 31987c478bd9Sstevel@tonic-gate * - or - 31997c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 32007c478bd9Sstevel@tonic-gate */ 32017c478bd9Sstevel@tonic-gate if ((*smask != 0x00) && 32027c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 3203*29aca3ebSlc (best_node_bandwidth > 3204*29aca3ebSlc (node_sbandwidth + node_cbandwidth)))) { 32057c478bd9Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth + node_cbandwidth; 32067c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 32077c478bd9Sstevel@tonic-gate best_smask = *smask; 32087c478bd9Sstevel@tonic-gate best_cmask = *cmask; 32097c478bd9Sstevel@tonic-gate } 32107c478bd9Sstevel@tonic-gate } 32117c478bd9Sstevel@tonic-gate 32127c478bd9Sstevel@tonic-gate /* 32137c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 32147c478bd9Sstevel@tonic-gate * appropriate variables and return success. 32157c478bd9Sstevel@tonic-gate */ 32167c478bd9Sstevel@tonic-gate if (best_smask) { 32177c478bd9Sstevel@tonic-gate *smask = best_smask; 32187c478bd9Sstevel@tonic-gate *cmask = best_cmask; 32197c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 32207c478bd9Sstevel@tonic-gate interval); 32217c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, sbandwidth, 32227c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 32237c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, cbandwidth, 32247c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_cmask); 32257c478bd9Sstevel@tonic-gate 32267c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 32277c478bd9Sstevel@tonic-gate } 32287c478bd9Sstevel@tonic-gate 32297c478bd9Sstevel@tonic-gate return (USB_FAILURE); 32307c478bd9Sstevel@tonic-gate } 32317c478bd9Sstevel@tonic-gate 32327c478bd9Sstevel@tonic-gate 32337c478bd9Sstevel@tonic-gate /* 32347c478bd9Sstevel@tonic-gate * ehci_find_bestfit_sitd_in_mask: 32357c478bd9Sstevel@tonic-gate * 32367c478bd9Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation. 32377c478bd9Sstevel@tonic-gate */ 32387c478bd9Sstevel@tonic-gate static int 32397c478bd9Sstevel@tonic-gate ehci_find_bestfit_sitd_in_mask( 32407c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 32417c478bd9Sstevel@tonic-gate uchar_t *smask, 32427c478bd9Sstevel@tonic-gate uchar_t *cmask, 32437c478bd9Sstevel@tonic-gate uint_t *pnode, 32447c478bd9Sstevel@tonic-gate uint_t sbandwidth, 32457c478bd9Sstevel@tonic-gate uint_t cbandwidth, 32467c478bd9Sstevel@tonic-gate int interval) 32477c478bd9Sstevel@tonic-gate { 32487c478bd9Sstevel@tonic-gate int i, uFrames, found; 32497c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 32507c478bd9Sstevel@tonic-gate uint_t node_sbandwidth, node_cbandwidth; 32517c478bd9Sstevel@tonic-gate uint_t best_node_bandwidth; 32527c478bd9Sstevel@tonic-gate uint_t leaf_count; 32537c478bd9Sstevel@tonic-gate uchar_t bw_smask, bw_cmask; 32547c478bd9Sstevel@tonic-gate uchar_t best_smask, best_cmask; 32557c478bd9Sstevel@tonic-gate 32567c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 32577c478bd9Sstevel@tonic-gate "ehci_find_bestfit_sitd_in_mask: "); 32587c478bd9Sstevel@tonic-gate 32597c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 32607c478bd9Sstevel@tonic-gate 32617c478bd9Sstevel@tonic-gate /* 32627c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 32637c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 32647c478bd9Sstevel@tonic-gate * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame. 32657c478bd9Sstevel@tonic-gate */ 32667c478bd9Sstevel@tonic-gate /* 32677c478bd9Sstevel@tonic-gate * Need to add an additional 2 uFrames, if the "L"ast 32687c478bd9Sstevel@tonic-gate * complete split is before uFrame 6. See section 32697c478bd9Sstevel@tonic-gate * 11.8.4 in USB 2.0 Spec. Currently we do not support 32707c478bd9Sstevel@tonic-gate * the "Back Ptr" which means we support on IN of 32717c478bd9Sstevel@tonic-gate * ~4*MAX_UFRAME_SITD_XFER bandwidth/ 32727c478bd9Sstevel@tonic-gate */ 32737c478bd9Sstevel@tonic-gate uFrames = (cbandwidth / MAX_UFRAME_SITD_XFER) + 2; 32747c478bd9Sstevel@tonic-gate if (cbandwidth % MAX_UFRAME_SITD_XFER) { 32757c478bd9Sstevel@tonic-gate uFrames++; 32767c478bd9Sstevel@tonic-gate } 32777c478bd9Sstevel@tonic-gate if (uFrames > 6) { 32787c478bd9Sstevel@tonic-gate 32797c478bd9Sstevel@tonic-gate return (USB_FAILURE); 32807c478bd9Sstevel@tonic-gate } 32817c478bd9Sstevel@tonic-gate *smask = 0x1; 32827c478bd9Sstevel@tonic-gate *cmask = 0x00; 32837c478bd9Sstevel@tonic-gate for (i = 0; i < uFrames; i++) { 32847c478bd9Sstevel@tonic-gate *cmask = *cmask << 1; 32857c478bd9Sstevel@tonic-gate *cmask |= 0x1; 32867c478bd9Sstevel@tonic-gate } 32877c478bd9Sstevel@tonic-gate /* cmask must start 2 frames after the smask */ 32887c478bd9Sstevel@tonic-gate *cmask = *cmask << 2; 32897c478bd9Sstevel@tonic-gate 32907c478bd9Sstevel@tonic-gate found = 0; 32917c478bd9Sstevel@tonic-gate best_smask = 0x00; 32927c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 32937c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 32947c478bd9Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip, 32957c478bd9Sstevel@tonic-gate sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask); 32967c478bd9Sstevel@tonic-gate node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip, 32977c478bd9Sstevel@tonic-gate MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count, 32987c478bd9Sstevel@tonic-gate &bw_cmask); 32997c478bd9Sstevel@tonic-gate 33007c478bd9Sstevel@tonic-gate /* 33017c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 33027c478bd9Sstevel@tonic-gate * next leaf. 33037c478bd9Sstevel@tonic-gate */ 33047c478bd9Sstevel@tonic-gate if ((bw_smask == 0x00) || (bw_cmask == 0x00)) { 33057c478bd9Sstevel@tonic-gate continue; 33067c478bd9Sstevel@tonic-gate } 33077c478bd9Sstevel@tonic-gate 33087c478bd9Sstevel@tonic-gate for (i = 0; i < (EHCI_MAX_UFRAMES - uFrames - 2); i++) { 33097c478bd9Sstevel@tonic-gate if ((*smask & bw_smask) && (*cmask & bw_cmask)) { 33107c478bd9Sstevel@tonic-gate found = 1; 33117c478bd9Sstevel@tonic-gate break; 33127c478bd9Sstevel@tonic-gate } 33137c478bd9Sstevel@tonic-gate *smask = *smask << 1; 33147c478bd9Sstevel@tonic-gate *cmask = *cmask << 1; 33157c478bd9Sstevel@tonic-gate } 33167c478bd9Sstevel@tonic-gate 33177c478bd9Sstevel@tonic-gate /* 33187c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 33197c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 33207c478bd9Sstevel@tonic-gate * - or - 33217c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 33227c478bd9Sstevel@tonic-gate */ 33237c478bd9Sstevel@tonic-gate if (found && 33247c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 3325*29aca3ebSlc (best_node_bandwidth > 3326*29aca3ebSlc (node_sbandwidth + node_cbandwidth)))) { 33277c478bd9Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth + node_cbandwidth; 33287c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 33297c478bd9Sstevel@tonic-gate best_smask = *smask; 33307c478bd9Sstevel@tonic-gate best_cmask = *cmask; 33317c478bd9Sstevel@tonic-gate } 33327c478bd9Sstevel@tonic-gate } 33337c478bd9Sstevel@tonic-gate 33347c478bd9Sstevel@tonic-gate /* 33357c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 33367c478bd9Sstevel@tonic-gate * appropriate variables and return success. 33377c478bd9Sstevel@tonic-gate */ 33387c478bd9Sstevel@tonic-gate if (best_smask) { 33397c478bd9Sstevel@tonic-gate *smask = best_smask; 33407c478bd9Sstevel@tonic-gate *cmask = best_cmask; 33417c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 33427c478bd9Sstevel@tonic-gate interval); 33437c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, sbandwidth, 33447c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 33457c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER, 33467c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_cmask); 33477c478bd9Sstevel@tonic-gate 33487c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 33497c478bd9Sstevel@tonic-gate } 33507c478bd9Sstevel@tonic-gate 33517c478bd9Sstevel@tonic-gate return (USB_FAILURE); 33527c478bd9Sstevel@tonic-gate } 33537c478bd9Sstevel@tonic-gate 33547c478bd9Sstevel@tonic-gate 33557c478bd9Sstevel@tonic-gate /* 33567c478bd9Sstevel@tonic-gate * ehci_find_bestfit_sitd_out_mask: 33577c478bd9Sstevel@tonic-gate * 33587c478bd9Sstevel@tonic-gate * Find the smask in the bandwidth allocation. 33597c478bd9Sstevel@tonic-gate */ 33607c478bd9Sstevel@tonic-gate static int 33617c478bd9Sstevel@tonic-gate ehci_find_bestfit_sitd_out_mask( 33627c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 33637c478bd9Sstevel@tonic-gate uchar_t *smask, 33647c478bd9Sstevel@tonic-gate uint_t *pnode, 33657c478bd9Sstevel@tonic-gate uint_t sbandwidth, 33667c478bd9Sstevel@tonic-gate int interval) 33677c478bd9Sstevel@tonic-gate { 33687c478bd9Sstevel@tonic-gate int i, uFrames, found; 33697c478bd9Sstevel@tonic-gate int array_leaf, best_array_leaf; 33707c478bd9Sstevel@tonic-gate uint_t node_sbandwidth; 33717c478bd9Sstevel@tonic-gate uint_t best_node_bandwidth; 33727c478bd9Sstevel@tonic-gate uint_t leaf_count; 33737c478bd9Sstevel@tonic-gate uchar_t bw_smask; 33747c478bd9Sstevel@tonic-gate uchar_t best_smask; 33757c478bd9Sstevel@tonic-gate 33767c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 33777c478bd9Sstevel@tonic-gate "ehci_find_bestfit_sitd_out_mask: "); 33787c478bd9Sstevel@tonic-gate 33797c478bd9Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval; 33807c478bd9Sstevel@tonic-gate 33817c478bd9Sstevel@tonic-gate /* 33827c478bd9Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically 33837c478bd9Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval. 33847c478bd9Sstevel@tonic-gate * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame. 33857c478bd9Sstevel@tonic-gate */ 33867c478bd9Sstevel@tonic-gate *smask = 0x00; 33877c478bd9Sstevel@tonic-gate uFrames = sbandwidth / MAX_UFRAME_SITD_XFER; 33887c478bd9Sstevel@tonic-gate if (sbandwidth % MAX_UFRAME_SITD_XFER) { 33897c478bd9Sstevel@tonic-gate uFrames++; 33907c478bd9Sstevel@tonic-gate } 33917c478bd9Sstevel@tonic-gate for (i = 0; i < uFrames; i++) { 33927c478bd9Sstevel@tonic-gate *smask = *smask << 1; 33937c478bd9Sstevel@tonic-gate *smask |= 0x1; 33947c478bd9Sstevel@tonic-gate } 33957c478bd9Sstevel@tonic-gate 33967c478bd9Sstevel@tonic-gate found = 0; 33977c478bd9Sstevel@tonic-gate best_smask = 0x00; 33987c478bd9Sstevel@tonic-gate best_node_bandwidth = 0; 33997c478bd9Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) { 34007c478bd9Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip, 34017c478bd9Sstevel@tonic-gate MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count, 34027c478bd9Sstevel@tonic-gate &bw_smask); 34037c478bd9Sstevel@tonic-gate 34047c478bd9Sstevel@tonic-gate /* 34057c478bd9Sstevel@tonic-gate * If this node cannot support our requirements skip to the 34067c478bd9Sstevel@tonic-gate * next leaf. 34077c478bd9Sstevel@tonic-gate */ 34087c478bd9Sstevel@tonic-gate if (bw_smask == 0x00) { 34097c478bd9Sstevel@tonic-gate continue; 34107c478bd9Sstevel@tonic-gate } 34117c478bd9Sstevel@tonic-gate 34127c478bd9Sstevel@tonic-gate /* You cannot have a start split on the 8th uFrame */ 34137c478bd9Sstevel@tonic-gate for (i = 0; (*smask & 0x80) == 0; i++) { 34147c478bd9Sstevel@tonic-gate if (*smask & bw_smask) { 34157c478bd9Sstevel@tonic-gate found = 1; 34167c478bd9Sstevel@tonic-gate break; 34177c478bd9Sstevel@tonic-gate } 34187c478bd9Sstevel@tonic-gate *smask = *smask << 1; 34197c478bd9Sstevel@tonic-gate } 34207c478bd9Sstevel@tonic-gate 34217c478bd9Sstevel@tonic-gate /* 34227c478bd9Sstevel@tonic-gate * If an appropriate smask is found save the information if: 34237c478bd9Sstevel@tonic-gate * o best_smask has not been found yet. 34247c478bd9Sstevel@tonic-gate * - or - 34257c478bd9Sstevel@tonic-gate * o This is the node with the least amount of bandwidth 34267c478bd9Sstevel@tonic-gate */ 34277c478bd9Sstevel@tonic-gate if (found && 34287c478bd9Sstevel@tonic-gate ((best_smask == 0x00) || 3429*29aca3ebSlc (best_node_bandwidth > node_sbandwidth))) { 34307c478bd9Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth; 34317c478bd9Sstevel@tonic-gate best_array_leaf = array_leaf; 34327c478bd9Sstevel@tonic-gate best_smask = *smask; 34337c478bd9Sstevel@tonic-gate } 34347c478bd9Sstevel@tonic-gate } 34357c478bd9Sstevel@tonic-gate 34367c478bd9Sstevel@tonic-gate /* 34377c478bd9Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the 34387c478bd9Sstevel@tonic-gate * appropriate variables and return success. 34397c478bd9Sstevel@tonic-gate */ 34407c478bd9Sstevel@tonic-gate if (best_smask) { 34417c478bd9Sstevel@tonic-gate *smask = best_smask; 34427c478bd9Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf], 34437c478bd9Sstevel@tonic-gate interval); 34447c478bd9Sstevel@tonic-gate ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER, 34457c478bd9Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask); 34467c478bd9Sstevel@tonic-gate 34477c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 34487c478bd9Sstevel@tonic-gate } 34497c478bd9Sstevel@tonic-gate 34507c478bd9Sstevel@tonic-gate return (USB_FAILURE); 34517c478bd9Sstevel@tonic-gate } 34527c478bd9Sstevel@tonic-gate 34537c478bd9Sstevel@tonic-gate 34547c478bd9Sstevel@tonic-gate /* 34557c478bd9Sstevel@tonic-gate * ehci_calculate_bw_availability_mask: 34567c478bd9Sstevel@tonic-gate * 34577c478bd9Sstevel@tonic-gate * Returns the "total bandwidth used" in this node. 34587c478bd9Sstevel@tonic-gate * Populates bw_mask with the uFrames that can support the bandwidth. 34597c478bd9Sstevel@tonic-gate * 34607c478bd9Sstevel@tonic-gate * If all the Frames cannot support this bandwidth, then bw_mask 34617c478bd9Sstevel@tonic-gate * will return 0x00 and the "total bandwidth used" will be invalid. 34627c478bd9Sstevel@tonic-gate */ 34637c478bd9Sstevel@tonic-gate static uint_t 34647c478bd9Sstevel@tonic-gate ehci_calculate_bw_availability_mask( 34657c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 34667c478bd9Sstevel@tonic-gate uint_t bandwidth, 34677c478bd9Sstevel@tonic-gate int leaf, 34687c478bd9Sstevel@tonic-gate int leaf_count, 34697c478bd9Sstevel@tonic-gate uchar_t *bw_mask) 34707c478bd9Sstevel@tonic-gate { 34717c478bd9Sstevel@tonic-gate int i, j; 34727c478bd9Sstevel@tonic-gate uchar_t bw_uframe; 34737c478bd9Sstevel@tonic-gate int uframe_total; 34747c478bd9Sstevel@tonic-gate ehci_frame_bandwidth_t *fbp; 34757c478bd9Sstevel@tonic-gate uint_t total_bandwidth = 0; 34767c478bd9Sstevel@tonic-gate 34777c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 34787c478bd9Sstevel@tonic-gate "ehci_calculate_bw_availability_mask: leaf %d leaf count %d", 34797c478bd9Sstevel@tonic-gate leaf, leaf_count); 34807c478bd9Sstevel@tonic-gate 34817c478bd9Sstevel@tonic-gate /* Start by saying all uFrames are available */ 34827c478bd9Sstevel@tonic-gate *bw_mask = 0xFF; 34837c478bd9Sstevel@tonic-gate 34847c478bd9Sstevel@tonic-gate for (i = 0; (i < leaf_count) || (*bw_mask == 0x00); i++) { 34857c478bd9Sstevel@tonic-gate fbp = &ehcip->ehci_frame_bandwidth[leaf + i]; 34867c478bd9Sstevel@tonic-gate 34877c478bd9Sstevel@tonic-gate total_bandwidth += fbp->ehci_allocated_frame_bandwidth; 34887c478bd9Sstevel@tonic-gate 34897c478bd9Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) { 34907c478bd9Sstevel@tonic-gate /* 34917c478bd9Sstevel@tonic-gate * If the uFrame in bw_mask is available check to see if 34927c478bd9Sstevel@tonic-gate * it can support the additional bandwidth. 34937c478bd9Sstevel@tonic-gate */ 34947c478bd9Sstevel@tonic-gate bw_uframe = (*bw_mask & (0x1 << j)); 34957c478bd9Sstevel@tonic-gate uframe_total = 34967c478bd9Sstevel@tonic-gate fbp->ehci_micro_frame_bandwidth[j] + 34977c478bd9Sstevel@tonic-gate bandwidth; 34987c478bd9Sstevel@tonic-gate if ((bw_uframe) && 34997c478bd9Sstevel@tonic-gate (uframe_total > HS_PERIODIC_BANDWIDTH)) { 35007c478bd9Sstevel@tonic-gate *bw_mask = *bw_mask & ~bw_uframe; 35017c478bd9Sstevel@tonic-gate } 35027c478bd9Sstevel@tonic-gate } 35037c478bd9Sstevel@tonic-gate } 35047c478bd9Sstevel@tonic-gate 35057c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl, 35067c478bd9Sstevel@tonic-gate "ehci_calculate_bw_availability_mask: bandwidth mask 0x%x", 35077c478bd9Sstevel@tonic-gate *bw_mask); 35087c478bd9Sstevel@tonic-gate 35097c478bd9Sstevel@tonic-gate return (total_bandwidth); 35107c478bd9Sstevel@tonic-gate } 35117c478bd9Sstevel@tonic-gate 35127c478bd9Sstevel@tonic-gate 35137c478bd9Sstevel@tonic-gate /* 35147c478bd9Sstevel@tonic-gate * ehci_update_bw_availability: 35157c478bd9Sstevel@tonic-gate * 35167c478bd9Sstevel@tonic-gate * The leftmost leaf needs to be in terms of array position and 35177c478bd9Sstevel@tonic-gate * not the actual lattice position. 35187c478bd9Sstevel@tonic-gate */ 35197c478bd9Sstevel@tonic-gate static void 35207c478bd9Sstevel@tonic-gate ehci_update_bw_availability( 35217c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 35227c478bd9Sstevel@tonic-gate int bandwidth, 35237c478bd9Sstevel@tonic-gate int leftmost_leaf, 35247c478bd9Sstevel@tonic-gate int leaf_count, 35257c478bd9Sstevel@tonic-gate uchar_t mask) 35267c478bd9Sstevel@tonic-gate { 35277c478bd9Sstevel@tonic-gate int i, j; 35287c478bd9Sstevel@tonic-gate ehci_frame_bandwidth_t *fbp; 35297c478bd9Sstevel@tonic-gate int uFrame_bandwidth[8]; 35307c478bd9Sstevel@tonic-gate 35317c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 35327c478bd9Sstevel@tonic-gate "ehci_update_bw_availability: " 35337c478bd9Sstevel@tonic-gate "leaf %d count %d bandwidth 0x%x mask 0x%x", 35347c478bd9Sstevel@tonic-gate leftmost_leaf, leaf_count, bandwidth, mask); 35357c478bd9Sstevel@tonic-gate 35367c478bd9Sstevel@tonic-gate ASSERT(leftmost_leaf < 32); 35377c478bd9Sstevel@tonic-gate ASSERT(leftmost_leaf >= 0); 35387c478bd9Sstevel@tonic-gate 35397c478bd9Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) { 35407c478bd9Sstevel@tonic-gate if (mask & 0x1) { 35417c478bd9Sstevel@tonic-gate uFrame_bandwidth[j] = bandwidth; 35427c478bd9Sstevel@tonic-gate } else { 35437c478bd9Sstevel@tonic-gate uFrame_bandwidth[j] = 0; 35447c478bd9Sstevel@tonic-gate } 35457c478bd9Sstevel@tonic-gate 35467c478bd9Sstevel@tonic-gate mask = mask >> 1; 35477c478bd9Sstevel@tonic-gate } 35487c478bd9Sstevel@tonic-gate 35497c478bd9Sstevel@tonic-gate /* Updated all the effected leafs with the bandwidth */ 35507c478bd9Sstevel@tonic-gate for (i = 0; i < leaf_count; i++) { 35517c478bd9Sstevel@tonic-gate fbp = &ehcip->ehci_frame_bandwidth[leftmost_leaf + i]; 35527c478bd9Sstevel@tonic-gate 35537c478bd9Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) { 35547c478bd9Sstevel@tonic-gate fbp->ehci_micro_frame_bandwidth[j] += 35557c478bd9Sstevel@tonic-gate uFrame_bandwidth[j]; 35567c478bd9Sstevel@tonic-gate fbp->ehci_allocated_frame_bandwidth += 35577c478bd9Sstevel@tonic-gate uFrame_bandwidth[j]; 35587c478bd9Sstevel@tonic-gate } 35597c478bd9Sstevel@tonic-gate } 35607c478bd9Sstevel@tonic-gate } 35617c478bd9Sstevel@tonic-gate 35627c478bd9Sstevel@tonic-gate /* 35637c478bd9Sstevel@tonic-gate * Miscellaneous functions 35647c478bd9Sstevel@tonic-gate */ 35657c478bd9Sstevel@tonic-gate 35667c478bd9Sstevel@tonic-gate /* 35677c478bd9Sstevel@tonic-gate * ehci_obtain_state: 35687c478bd9Sstevel@tonic-gate * 35697c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 35707c478bd9Sstevel@tonic-gate */ 35717c478bd9Sstevel@tonic-gate ehci_state_t * 35727c478bd9Sstevel@tonic-gate ehci_obtain_state(dev_info_t *dip) 35737c478bd9Sstevel@tonic-gate { 35747c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 35757c478bd9Sstevel@tonic-gate 35767c478bd9Sstevel@tonic-gate ehci_state_t *state = ddi_get_soft_state(ehci_statep, instance); 35777c478bd9Sstevel@tonic-gate 35787c478bd9Sstevel@tonic-gate ASSERT(state != NULL); 35797c478bd9Sstevel@tonic-gate 35807c478bd9Sstevel@tonic-gate return (state); 35817c478bd9Sstevel@tonic-gate } 35827c478bd9Sstevel@tonic-gate 35837c478bd9Sstevel@tonic-gate 35847c478bd9Sstevel@tonic-gate /* 35857c478bd9Sstevel@tonic-gate * ehci_state_is_operational: 35867c478bd9Sstevel@tonic-gate * 35877c478bd9Sstevel@tonic-gate * Check the Host controller state and return proper values. 35887c478bd9Sstevel@tonic-gate */ 35897c478bd9Sstevel@tonic-gate int 35907c478bd9Sstevel@tonic-gate ehci_state_is_operational(ehci_state_t *ehcip) 35917c478bd9Sstevel@tonic-gate { 35927c478bd9Sstevel@tonic-gate int val; 35937c478bd9Sstevel@tonic-gate 35947c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 35957c478bd9Sstevel@tonic-gate 35967c478bd9Sstevel@tonic-gate switch (ehcip->ehci_hc_soft_state) { 35977c478bd9Sstevel@tonic-gate case EHCI_CTLR_INIT_STATE: 35987c478bd9Sstevel@tonic-gate case EHCI_CTLR_SUSPEND_STATE: 35997c478bd9Sstevel@tonic-gate val = USB_FAILURE; 36007c478bd9Sstevel@tonic-gate break; 36017c478bd9Sstevel@tonic-gate case EHCI_CTLR_OPERATIONAL_STATE: 36027c478bd9Sstevel@tonic-gate val = USB_SUCCESS; 36037c478bd9Sstevel@tonic-gate break; 36047c478bd9Sstevel@tonic-gate case EHCI_CTLR_ERROR_STATE: 36057c478bd9Sstevel@tonic-gate val = USB_HC_HARDWARE_ERROR; 36067c478bd9Sstevel@tonic-gate break; 36077c478bd9Sstevel@tonic-gate default: 36087c478bd9Sstevel@tonic-gate val = USB_FAILURE; 36097c478bd9Sstevel@tonic-gate break; 36107c478bd9Sstevel@tonic-gate } 36117c478bd9Sstevel@tonic-gate 36127c478bd9Sstevel@tonic-gate return (val); 36137c478bd9Sstevel@tonic-gate } 36147c478bd9Sstevel@tonic-gate 36157c478bd9Sstevel@tonic-gate 36167c478bd9Sstevel@tonic-gate /* 36177c478bd9Sstevel@tonic-gate * ehci_do_soft_reset 36187c478bd9Sstevel@tonic-gate * 36197c478bd9Sstevel@tonic-gate * Do soft reset of ehci host controller. 36207c478bd9Sstevel@tonic-gate */ 36217c478bd9Sstevel@tonic-gate int 36227c478bd9Sstevel@tonic-gate ehci_do_soft_reset(ehci_state_t *ehcip) 36237c478bd9Sstevel@tonic-gate { 36247c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 36257c478bd9Sstevel@tonic-gate ehci_regs_t *ehci_save_regs; 36267c478bd9Sstevel@tonic-gate 36277c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 36287c478bd9Sstevel@tonic-gate 36297c478bd9Sstevel@tonic-gate /* Increment host controller error count */ 36307c478bd9Sstevel@tonic-gate ehcip->ehci_hc_error++; 36317c478bd9Sstevel@tonic-gate 36327c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 36337c478bd9Sstevel@tonic-gate "ehci_do_soft_reset:" 36347c478bd9Sstevel@tonic-gate "Reset ehci host controller 0x%x", ehcip->ehci_hc_error); 36357c478bd9Sstevel@tonic-gate 36367c478bd9Sstevel@tonic-gate /* 36377c478bd9Sstevel@tonic-gate * Allocate space for saving current Host Controller 36387c478bd9Sstevel@tonic-gate * registers. Don't do any recovery if allocation 36397c478bd9Sstevel@tonic-gate * fails. 36407c478bd9Sstevel@tonic-gate */ 36417c478bd9Sstevel@tonic-gate ehci_save_regs = (ehci_regs_t *) 36427c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (ehci_regs_t), KM_NOSLEEP); 36437c478bd9Sstevel@tonic-gate 36447c478bd9Sstevel@tonic-gate if (ehci_save_regs == NULL) { 36457c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 36467c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: kmem_zalloc failed"); 36477c478bd9Sstevel@tonic-gate 36487c478bd9Sstevel@tonic-gate return (USB_FAILURE); 36497c478bd9Sstevel@tonic-gate } 36507c478bd9Sstevel@tonic-gate 36517c478bd9Sstevel@tonic-gate /* Save current ehci registers */ 36527c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_command = Get_OpReg(ehci_command); 36537c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_interrupt = Get_OpReg(ehci_interrupt); 36547c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_ctrl_segment = Get_OpReg(ehci_ctrl_segment); 36557c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_async_list_addr = Get_OpReg(ehci_async_list_addr); 36567c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_config_flag = Get_OpReg(ehci_config_flag); 36577c478bd9Sstevel@tonic-gate ehci_save_regs->ehci_periodic_list_base = 36587c478bd9Sstevel@tonic-gate Get_OpReg(ehci_periodic_list_base); 36597c478bd9Sstevel@tonic-gate 36603b00f311Syq USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 36617c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Save reg = 0x%p", ehci_save_regs); 36627c478bd9Sstevel@tonic-gate 36637c478bd9Sstevel@tonic-gate /* Disable all list processing and interrupts */ 36647c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, Get_OpReg(ehci_command) & 36657c478bd9Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE)); 36667c478bd9Sstevel@tonic-gate 36677c478bd9Sstevel@tonic-gate /* Disable all EHCI interrupts */ 36687c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0); 36697c478bd9Sstevel@tonic-gate 36707c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 36717c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_SOF_TIMEWAIT); 36727c478bd9Sstevel@tonic-gate 36737c478bd9Sstevel@tonic-gate /* Do light soft reset of ehci host controller */ 36747c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, 36757c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command) | EHCI_CMD_LIGHT_HC_RESET); 36767c478bd9Sstevel@tonic-gate 36773b00f311Syq USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 36787c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Reset in progress"); 36797c478bd9Sstevel@tonic-gate 36807c478bd9Sstevel@tonic-gate /* Wait for reset to complete */ 36817c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT); 36827c478bd9Sstevel@tonic-gate 36837c478bd9Sstevel@tonic-gate /* 36847c478bd9Sstevel@tonic-gate * Restore previous saved EHCI register value 36857c478bd9Sstevel@tonic-gate * into the current EHCI registers. 36867c478bd9Sstevel@tonic-gate */ 36877c478bd9Sstevel@tonic-gate Set_OpReg(ehci_ctrl_segment, (uint32_t) 3688*29aca3ebSlc ehci_save_regs->ehci_ctrl_segment); 36897c478bd9Sstevel@tonic-gate 36907c478bd9Sstevel@tonic-gate Set_OpReg(ehci_periodic_list_base, (uint32_t) 3691*29aca3ebSlc ehci_save_regs->ehci_periodic_list_base); 36927c478bd9Sstevel@tonic-gate 36937c478bd9Sstevel@tonic-gate Set_OpReg(ehci_async_list_addr, (uint32_t) 3694*29aca3ebSlc ehci_save_regs->ehci_async_list_addr); 36957c478bd9Sstevel@tonic-gate 3696921cd50dSgk /* 3697921cd50dSgk * For some reason this register might get nulled out by 3698921cd50dSgk * the Uli M1575 South Bridge. To workaround the hardware 3699921cd50dSgk * problem, check the value after write and retry if the 3700921cd50dSgk * last write fails. 3701921cd50dSgk */ 3702921cd50dSgk if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) && 3703921cd50dSgk (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) && 3704921cd50dSgk (ehci_save_regs->ehci_async_list_addr != 3705921cd50dSgk Get_OpReg(ehci_async_list_addr))) { 3706921cd50dSgk int retry = 0; 3707921cd50dSgk 3708921cd50dSgk Set_OpRegRetry(ehci_async_list_addr, (uint32_t) 3709*29aca3ebSlc ehci_save_regs->ehci_async_list_addr, retry); 3710921cd50dSgk if (retry >= EHCI_MAX_RETRY) { 37118668df41Slg USB_DPRINTF_L2(PRINT_MASK_ATTA, 3712921cd50dSgk ehcip->ehci_log_hdl, "ehci_do_soft_reset:" 3713921cd50dSgk " ASYNCLISTADDR write failed."); 3714921cd50dSgk 3715921cd50dSgk return (USB_FAILURE); 3716921cd50dSgk } 3717921cd50dSgk USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 3718921cd50dSgk "ehci_do_soft_reset: ASYNCLISTADDR " 3719*29aca3ebSlc "write failed, retry=%d", retry); 3720921cd50dSgk } 3721921cd50dSgk 37227c478bd9Sstevel@tonic-gate Set_OpReg(ehci_config_flag, (uint32_t) 3723*29aca3ebSlc ehci_save_regs->ehci_config_flag); 37247c478bd9Sstevel@tonic-gate 37257c478bd9Sstevel@tonic-gate /* Enable both Asynchronous and Periodic Schedule if necessary */ 37267c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehcip); 37277c478bd9Sstevel@tonic-gate 37287c478bd9Sstevel@tonic-gate /* 37297c478bd9Sstevel@tonic-gate * Set ehci_interrupt to enable all interrupts except Root 37307c478bd9Sstevel@tonic-gate * Hub Status change and frame list rollover interrupts. 37317c478bd9Sstevel@tonic-gate */ 37327c478bd9Sstevel@tonic-gate Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR | 37337c478bd9Sstevel@tonic-gate EHCI_INTR_FRAME_LIST_ROLLOVER | 37347c478bd9Sstevel@tonic-gate EHCI_INTR_USB_ERROR | 37357c478bd9Sstevel@tonic-gate EHCI_INTR_USB); 37367c478bd9Sstevel@tonic-gate 37377c478bd9Sstevel@tonic-gate /* 37387c478bd9Sstevel@tonic-gate * Deallocate the space that allocated for saving 37397c478bd9Sstevel@tonic-gate * HC registers. 37407c478bd9Sstevel@tonic-gate */ 37417c478bd9Sstevel@tonic-gate kmem_free((void *) ehci_save_regs, sizeof (ehci_regs_t)); 37427c478bd9Sstevel@tonic-gate 37437c478bd9Sstevel@tonic-gate /* 37447c478bd9Sstevel@tonic-gate * Set the desired interrupt threshold, frame list size (if 37457c478bd9Sstevel@tonic-gate * applicable) and turn EHCI host controller. 37467c478bd9Sstevel@tonic-gate */ 37477c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, ((Get_OpReg(ehci_command) & 37487c478bd9Sstevel@tonic-gate ~EHCI_CMD_INTR_THRESHOLD) | 37497c478bd9Sstevel@tonic-gate (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN))); 37507c478bd9Sstevel@tonic-gate 37517c478bd9Sstevel@tonic-gate /* Wait 10ms for EHCI to start sending SOF */ 37527c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT); 37537c478bd9Sstevel@tonic-gate 37547c478bd9Sstevel@tonic-gate /* 37557c478bd9Sstevel@tonic-gate * Get the current usb frame number before waiting for 37567c478bd9Sstevel@tonic-gate * few milliseconds. 37577c478bd9Sstevel@tonic-gate */ 37587c478bd9Sstevel@tonic-gate before_frame_number = ehci_get_current_frame_number(ehcip); 37597c478bd9Sstevel@tonic-gate 37607c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 37617c478bd9Sstevel@tonic-gate drv_usecwait(EHCI_SOF_TIMEWAIT); 37627c478bd9Sstevel@tonic-gate 37637c478bd9Sstevel@tonic-gate /* 37647c478bd9Sstevel@tonic-gate * Get the current usb frame number after waiting for 37657c478bd9Sstevel@tonic-gate * few milliseconds. 37667c478bd9Sstevel@tonic-gate */ 37677c478bd9Sstevel@tonic-gate after_frame_number = ehci_get_current_frame_number(ehcip); 37687c478bd9Sstevel@tonic-gate 37697c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 37707c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Before Frame Number 0x%llx " 37717c478bd9Sstevel@tonic-gate "After Frame Number 0x%llx", 37727c478bd9Sstevel@tonic-gate before_frame_number, after_frame_number); 37737c478bd9Sstevel@tonic-gate 37747c478bd9Sstevel@tonic-gate if ((after_frame_number <= before_frame_number) && 37757c478bd9Sstevel@tonic-gate (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) { 37767c478bd9Sstevel@tonic-gate 37777c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl, 37787c478bd9Sstevel@tonic-gate "ehci_do_soft_reset: Soft reset failed"); 37797c478bd9Sstevel@tonic-gate 37807c478bd9Sstevel@tonic-gate return (USB_FAILURE); 37817c478bd9Sstevel@tonic-gate } 37827c478bd9Sstevel@tonic-gate 37837c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 37847c478bd9Sstevel@tonic-gate } 37857c478bd9Sstevel@tonic-gate 37867c478bd9Sstevel@tonic-gate 37877c478bd9Sstevel@tonic-gate /* 37887c478bd9Sstevel@tonic-gate * ehci_get_xfer_attrs: 37897c478bd9Sstevel@tonic-gate * 37907c478bd9Sstevel@tonic-gate * Get the attributes of a particular xfer. 37917c478bd9Sstevel@tonic-gate * 37927c478bd9Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE. 37937c478bd9Sstevel@tonic-gate */ 37947c478bd9Sstevel@tonic-gate usb_req_attrs_t 37957c478bd9Sstevel@tonic-gate ehci_get_xfer_attrs( 37967c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 37977c478bd9Sstevel@tonic-gate ehci_pipe_private_t *pp, 37987c478bd9Sstevel@tonic-gate ehci_trans_wrapper_t *tw) 37997c478bd9Sstevel@tonic-gate { 38007c478bd9Sstevel@tonic-gate usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep; 38017c478bd9Sstevel@tonic-gate usb_req_attrs_t attrs = USB_ATTRS_NONE; 38027c478bd9Sstevel@tonic-gate 38037c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 38047c478bd9Sstevel@tonic-gate "ehci_get_xfer_attrs:"); 38057c478bd9Sstevel@tonic-gate 38067c478bd9Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) { 38077c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 38087c478bd9Sstevel@tonic-gate attrs = ((usb_ctrl_req_t *) 38097c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->ctrl_attributes; 38107c478bd9Sstevel@tonic-gate break; 38117c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 38127c478bd9Sstevel@tonic-gate attrs = ((usb_bulk_req_t *) 38137c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->bulk_attributes; 38147c478bd9Sstevel@tonic-gate break; 38157c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 38167c478bd9Sstevel@tonic-gate attrs = ((usb_intr_req_t *) 38177c478bd9Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->intr_attributes; 38187c478bd9Sstevel@tonic-gate break; 38197c478bd9Sstevel@tonic-gate } 38207c478bd9Sstevel@tonic-gate 38217c478bd9Sstevel@tonic-gate return (attrs); 38227c478bd9Sstevel@tonic-gate } 38237c478bd9Sstevel@tonic-gate 38247c478bd9Sstevel@tonic-gate 38257c478bd9Sstevel@tonic-gate /* 38267c478bd9Sstevel@tonic-gate * ehci_get_current_frame_number: 38277c478bd9Sstevel@tonic-gate * 38287c478bd9Sstevel@tonic-gate * Get the current software based usb frame number. 38297c478bd9Sstevel@tonic-gate */ 38307c478bd9Sstevel@tonic-gate usb_frame_number_t 38317c478bd9Sstevel@tonic-gate ehci_get_current_frame_number(ehci_state_t *ehcip) 38327c478bd9Sstevel@tonic-gate { 38337c478bd9Sstevel@tonic-gate usb_frame_number_t usb_frame_number; 38347c478bd9Sstevel@tonic-gate usb_frame_number_t ehci_fno, micro_frame_number; 38357c478bd9Sstevel@tonic-gate 38367c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 38377c478bd9Sstevel@tonic-gate 38387c478bd9Sstevel@tonic-gate ehci_fno = ehcip->ehci_fno; 38397c478bd9Sstevel@tonic-gate micro_frame_number = Get_OpReg(ehci_frame_index) & 0x3FFF; 38407c478bd9Sstevel@tonic-gate 38417c478bd9Sstevel@tonic-gate /* 38427c478bd9Sstevel@tonic-gate * Calculate current software based usb frame number. 38437c478bd9Sstevel@tonic-gate * 38447c478bd9Sstevel@tonic-gate * This code accounts for the fact that frame number is 38457c478bd9Sstevel@tonic-gate * updated by the Host Controller before the ehci driver 38467c478bd9Sstevel@tonic-gate * gets an FrameListRollover interrupt that will adjust 38477c478bd9Sstevel@tonic-gate * Frame higher part. 38487c478bd9Sstevel@tonic-gate * 38497c478bd9Sstevel@tonic-gate * Refer ehci specification 1.0, section 2.3.2, page 21. 38507c478bd9Sstevel@tonic-gate */ 38517c478bd9Sstevel@tonic-gate micro_frame_number = ((micro_frame_number & 0x1FFF) | 38527c478bd9Sstevel@tonic-gate ehci_fno) + (((micro_frame_number & 0x3FFF) ^ 38537c478bd9Sstevel@tonic-gate ehci_fno) & 0x2000); 38547c478bd9Sstevel@tonic-gate 38557c478bd9Sstevel@tonic-gate /* 38567c478bd9Sstevel@tonic-gate * Micro Frame number is equivalent to 125 usec. Eight 38577c478bd9Sstevel@tonic-gate * Micro Frame numbers are equivalent to one millsecond 38587c478bd9Sstevel@tonic-gate * or one usb frame number. 38597c478bd9Sstevel@tonic-gate */ 38607c478bd9Sstevel@tonic-gate usb_frame_number = micro_frame_number >> 38617c478bd9Sstevel@tonic-gate EHCI_uFRAMES_PER_USB_FRAME_SHIFT; 38627c478bd9Sstevel@tonic-gate 38637c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 38647c478bd9Sstevel@tonic-gate "ehci_get_current_frame_number: " 38657c478bd9Sstevel@tonic-gate "Current usb uframe number = 0x%llx " 38667c478bd9Sstevel@tonic-gate "Current usb frame number = 0x%llx", 38677c478bd9Sstevel@tonic-gate micro_frame_number, usb_frame_number); 38687c478bd9Sstevel@tonic-gate 38697c478bd9Sstevel@tonic-gate return (usb_frame_number); 38707c478bd9Sstevel@tonic-gate } 38717c478bd9Sstevel@tonic-gate 38727c478bd9Sstevel@tonic-gate 38737c478bd9Sstevel@tonic-gate /* 38747c478bd9Sstevel@tonic-gate * ehci_cpr_cleanup: 38757c478bd9Sstevel@tonic-gate * 38767c478bd9Sstevel@tonic-gate * Cleanup ehci state and other ehci specific informations across 38777c478bd9Sstevel@tonic-gate * Check Point Resume (CPR). 38787c478bd9Sstevel@tonic-gate */ 38797c478bd9Sstevel@tonic-gate static void 38807c478bd9Sstevel@tonic-gate ehci_cpr_cleanup(ehci_state_t *ehcip) 38817c478bd9Sstevel@tonic-gate { 38827c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 38837c478bd9Sstevel@tonic-gate 38847c478bd9Sstevel@tonic-gate /* Reset software part of usb frame number */ 38857c478bd9Sstevel@tonic-gate ehcip->ehci_fno = 0; 38867c478bd9Sstevel@tonic-gate } 38877c478bd9Sstevel@tonic-gate 38887c478bd9Sstevel@tonic-gate 38897c478bd9Sstevel@tonic-gate /* 38907c478bd9Sstevel@tonic-gate * ehci_wait_for_sof: 38917c478bd9Sstevel@tonic-gate * 38927c478bd9Sstevel@tonic-gate * Wait for couple of SOF interrupts 38937c478bd9Sstevel@tonic-gate */ 38947c478bd9Sstevel@tonic-gate int 38957c478bd9Sstevel@tonic-gate ehci_wait_for_sof(ehci_state_t *ehcip) 38967c478bd9Sstevel@tonic-gate { 38977c478bd9Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number; 38987c478bd9Sstevel@tonic-gate int error = USB_SUCCESS; 38997c478bd9Sstevel@tonic-gate 39007c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, 39017c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, "ehci_wait_for_sof"); 39027c478bd9Sstevel@tonic-gate 39037c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex)); 39047c478bd9Sstevel@tonic-gate 39057c478bd9Sstevel@tonic-gate error = ehci_state_is_operational(ehcip); 39067c478bd9Sstevel@tonic-gate 39077c478bd9Sstevel@tonic-gate if (error != USB_SUCCESS) { 39087c478bd9Sstevel@tonic-gate 39097c478bd9Sstevel@tonic-gate return (error); 39107c478bd9Sstevel@tonic-gate } 39117c478bd9Sstevel@tonic-gate 39127c478bd9Sstevel@tonic-gate /* Get the current usb frame number before waiting for two SOFs */ 39137c478bd9Sstevel@tonic-gate before_frame_number = ehci_get_current_frame_number(ehcip); 39147c478bd9Sstevel@tonic-gate 39157c478bd9Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex); 39167c478bd9Sstevel@tonic-gate 39177c478bd9Sstevel@tonic-gate /* Wait for few milliseconds */ 39187c478bd9Sstevel@tonic-gate delay(drv_usectohz(EHCI_SOF_TIMEWAIT)); 39197c478bd9Sstevel@tonic-gate 39207c478bd9Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex); 39217c478bd9Sstevel@tonic-gate 39227c478bd9Sstevel@tonic-gate /* Get the current usb frame number after woken up */ 39237c478bd9Sstevel@tonic-gate after_frame_number = ehci_get_current_frame_number(ehcip); 39247c478bd9Sstevel@tonic-gate 39257c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 39267c478bd9Sstevel@tonic-gate "ehci_wait_for_sof: framenumber: before 0x%llx " 39277c478bd9Sstevel@tonic-gate "after 0x%llx", before_frame_number, after_frame_number); 39287c478bd9Sstevel@tonic-gate 39297c478bd9Sstevel@tonic-gate /* Return failure, if usb frame number has not been changed */ 39307c478bd9Sstevel@tonic-gate if (after_frame_number <= before_frame_number) { 39317c478bd9Sstevel@tonic-gate 39327c478bd9Sstevel@tonic-gate if ((ehci_do_soft_reset(ehcip)) != USB_SUCCESS) { 39337c478bd9Sstevel@tonic-gate 39347c478bd9Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_LISTS, 39357c478bd9Sstevel@tonic-gate ehcip->ehci_log_hdl, "No SOF interrupts"); 39367c478bd9Sstevel@tonic-gate 39377c478bd9Sstevel@tonic-gate /* Set host controller soft state to error */ 39387c478bd9Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE; 39397c478bd9Sstevel@tonic-gate 39407c478bd9Sstevel@tonic-gate return (USB_FAILURE); 39417c478bd9Sstevel@tonic-gate } 39427c478bd9Sstevel@tonic-gate 39437c478bd9Sstevel@tonic-gate /* Get new usb frame number */ 39447c478bd9Sstevel@tonic-gate after_frame_number = before_frame_number = 39457c478bd9Sstevel@tonic-gate ehci_get_current_frame_number(ehcip); 39467c478bd9Sstevel@tonic-gate } 39477c478bd9Sstevel@tonic-gate 39487c478bd9Sstevel@tonic-gate ASSERT(after_frame_number > before_frame_number); 39497c478bd9Sstevel@tonic-gate 39507c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 39517c478bd9Sstevel@tonic-gate } 39527c478bd9Sstevel@tonic-gate 39537c478bd9Sstevel@tonic-gate 39547c478bd9Sstevel@tonic-gate /* 39557c478bd9Sstevel@tonic-gate * ehci_toggle_scheduler: 39567c478bd9Sstevel@tonic-gate * 39577c478bd9Sstevel@tonic-gate * Turn scheduler based on pipe open count. 39587c478bd9Sstevel@tonic-gate */ 39597c478bd9Sstevel@tonic-gate void 39607c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehci_state_t *ehcip) { 39617c478bd9Sstevel@tonic-gate uint_t temp_reg, cmd_reg; 39627c478bd9Sstevel@tonic-gate 39637c478bd9Sstevel@tonic-gate cmd_reg = Get_OpReg(ehci_command); 39647c478bd9Sstevel@tonic-gate temp_reg = cmd_reg; 39657c478bd9Sstevel@tonic-gate 39667c478bd9Sstevel@tonic-gate /* 39677c478bd9Sstevel@tonic-gate * Enable/Disable asynchronous scheduler, and 39687c478bd9Sstevel@tonic-gate * turn on/off async list door bell 39697c478bd9Sstevel@tonic-gate */ 39707c478bd9Sstevel@tonic-gate if (ehcip->ehci_open_async_count) { 39717c478bd9Sstevel@tonic-gate if (!(cmd_reg & EHCI_CMD_ASYNC_SCHED_ENABLE)) { 39727c478bd9Sstevel@tonic-gate /* 39737c478bd9Sstevel@tonic-gate * For some reason this address might get nulled out by 39747c478bd9Sstevel@tonic-gate * the ehci chip. Set it here just in case it is null. 39757c478bd9Sstevel@tonic-gate */ 39767c478bd9Sstevel@tonic-gate Set_OpReg(ehci_async_list_addr, 39777c478bd9Sstevel@tonic-gate ehci_qh_cpu_to_iommu(ehcip, 39787c478bd9Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list)); 3979921cd50dSgk 3980921cd50dSgk /* 3981921cd50dSgk * For some reason this register might get nulled out by 3982921cd50dSgk * the Uli M1575 Southbridge. To workaround the HW 3983921cd50dSgk * problem, check the value after write and retry if the 3984921cd50dSgk * last write fails. 3985921cd50dSgk * 3986921cd50dSgk * If the ASYNCLISTADDR remains "stuck" after 3987921cd50dSgk * EHCI_MAX_RETRY retries, then the M1575 is broken 3988921cd50dSgk * and is stuck in an inconsistent state and is about 3989921cd50dSgk * to crash the machine with a trn_oor panic when it 3990921cd50dSgk * does a DMA read from 0x0. It is better to panic 3991921cd50dSgk * now rather than wait for the trn_oor crash; this 3992921cd50dSgk * way Customer Service will have a clean signature 3993921cd50dSgk * that indicts the M1575 chip rather than a 3994921cd50dSgk * mysterious and hard-to-diagnose trn_oor panic. 3995921cd50dSgk */ 3996921cd50dSgk if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) && 3997921cd50dSgk (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) && 3998921cd50dSgk (ehci_qh_cpu_to_iommu(ehcip, 3999921cd50dSgk ehcip->ehci_head_of_async_sched_list) != 4000921cd50dSgk Get_OpReg(ehci_async_list_addr))) { 4001921cd50dSgk int retry = 0; 4002921cd50dSgk 4003921cd50dSgk Set_OpRegRetry(ehci_async_list_addr, 4004921cd50dSgk ehci_qh_cpu_to_iommu(ehcip, 4005921cd50dSgk ehcip->ehci_head_of_async_sched_list), 4006921cd50dSgk retry); 4007921cd50dSgk if (retry >= EHCI_MAX_RETRY) 4008921cd50dSgk cmn_err(CE_PANIC, 4009921cd50dSgk "ehci_toggle_scheduler: " 4010921cd50dSgk "ASYNCLISTADDR write failed."); 4011921cd50dSgk 4012921cd50dSgk USB_DPRINTF_L2(PRINT_MASK_ATTA, 4013921cd50dSgk ehcip->ehci_log_hdl, 4014921cd50dSgk "ehci_toggle_scheduler: ASYNCLISTADDR " 4015921cd50dSgk "write failed, retry=%d", retry); 4016921cd50dSgk } 40177c478bd9Sstevel@tonic-gate } 40187c478bd9Sstevel@tonic-gate cmd_reg |= EHCI_CMD_ASYNC_SCHED_ENABLE; 40197c478bd9Sstevel@tonic-gate } else { 40207c478bd9Sstevel@tonic-gate cmd_reg &= ~EHCI_CMD_ASYNC_SCHED_ENABLE; 40217c478bd9Sstevel@tonic-gate } 40227c478bd9Sstevel@tonic-gate 40237c478bd9Sstevel@tonic-gate if (ehcip->ehci_open_periodic_count) { 40247c478bd9Sstevel@tonic-gate if (!(cmd_reg & EHCI_CMD_PERIODIC_SCHED_ENABLE)) { 40257c478bd9Sstevel@tonic-gate /* 40267c478bd9Sstevel@tonic-gate * For some reason this address get's nulled out by 40277c478bd9Sstevel@tonic-gate * the ehci chip. Set it here just in case it is null. 40287c478bd9Sstevel@tonic-gate */ 40297c478bd9Sstevel@tonic-gate Set_OpReg(ehci_periodic_list_base, 40307c478bd9Sstevel@tonic-gate (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address & 40317c478bd9Sstevel@tonic-gate 0xFFFFF000)); 40327c478bd9Sstevel@tonic-gate } 40337c478bd9Sstevel@tonic-gate cmd_reg |= EHCI_CMD_PERIODIC_SCHED_ENABLE; 40347c478bd9Sstevel@tonic-gate } else { 40357c478bd9Sstevel@tonic-gate cmd_reg &= ~EHCI_CMD_PERIODIC_SCHED_ENABLE; 40367c478bd9Sstevel@tonic-gate } 40377c478bd9Sstevel@tonic-gate 40387c478bd9Sstevel@tonic-gate /* Just an optimization */ 40397c478bd9Sstevel@tonic-gate if (temp_reg != cmd_reg) { 40407c478bd9Sstevel@tonic-gate Set_OpReg(ehci_command, cmd_reg); 40417c478bd9Sstevel@tonic-gate } 40427c478bd9Sstevel@tonic-gate } 40437c478bd9Sstevel@tonic-gate 40447c478bd9Sstevel@tonic-gate /* 40457c478bd9Sstevel@tonic-gate * ehci print functions 40467c478bd9Sstevel@tonic-gate */ 40477c478bd9Sstevel@tonic-gate 40487c478bd9Sstevel@tonic-gate /* 40497c478bd9Sstevel@tonic-gate * ehci_print_caps: 40507c478bd9Sstevel@tonic-gate */ 40517c478bd9Sstevel@tonic-gate void 40527c478bd9Sstevel@tonic-gate ehci_print_caps(ehci_state_t *ehcip) 40537c478bd9Sstevel@tonic-gate { 40547c478bd9Sstevel@tonic-gate uint_t i; 40557c478bd9Sstevel@tonic-gate 40567c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40577c478bd9Sstevel@tonic-gate "\n\tUSB 2.0 Host Controller Characteristics\n"); 40587c478bd9Sstevel@tonic-gate 40597c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40607c478bd9Sstevel@tonic-gate "Caps Length: 0x%x Version: 0x%x\n", 40617c478bd9Sstevel@tonic-gate Get_8Cap(ehci_caps_length), Get_16Cap(ehci_version)); 40627c478bd9Sstevel@tonic-gate 40637c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40647c478bd9Sstevel@tonic-gate "Structural Parameters\n"); 40657c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40667c478bd9Sstevel@tonic-gate "Port indicators: %s", (Get_Cap(ehci_hcs_params) & 40677c478bd9Sstevel@tonic-gate EHCI_HCS_PORT_INDICATOR) ? "Yes" : "No"); 40687c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40697c478bd9Sstevel@tonic-gate "No of Classic host controllers: 0x%x", 40707c478bd9Sstevel@tonic-gate (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_COMP_CTRLS) 40717c478bd9Sstevel@tonic-gate >> EHCI_HCS_NUM_COMP_CTRL_SHIFT); 40727c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40737c478bd9Sstevel@tonic-gate "No of ports per Classic host controller: 0x%x", 40747c478bd9Sstevel@tonic-gate (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS_CC) 40757c478bd9Sstevel@tonic-gate >> EHCI_HCS_NUM_PORTS_CC_SHIFT); 40767c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40777c478bd9Sstevel@tonic-gate "Port routing rules: %s", (Get_Cap(ehci_hcs_params) & 40787c478bd9Sstevel@tonic-gate EHCI_HCS_PORT_ROUTING_RULES) ? "Yes" : "No"); 40797c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40807c478bd9Sstevel@tonic-gate "Port power control: %s", (Get_Cap(ehci_hcs_params) & 40817c478bd9Sstevel@tonic-gate EHCI_HCS_PORT_POWER_CONTROL) ? "Yes" : "No"); 40827c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40837c478bd9Sstevel@tonic-gate "No of root hub ports: 0x%x\n", 40847c478bd9Sstevel@tonic-gate Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); 40857c478bd9Sstevel@tonic-gate 40867c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40877c478bd9Sstevel@tonic-gate "Capability Parameters\n"); 40887c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40897c478bd9Sstevel@tonic-gate "EHCI extended capability: %s", (Get_Cap(ehci_hcc_params) & 40907c478bd9Sstevel@tonic-gate EHCI_HCC_EECP) ? "Yes" : "No"); 40917c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40927c478bd9Sstevel@tonic-gate "Isoch schedule threshold: 0x%x", 40937c478bd9Sstevel@tonic-gate Get_Cap(ehci_hcc_params) & EHCI_HCC_ISOCH_SCHED_THRESHOLD); 40947c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40957c478bd9Sstevel@tonic-gate "Async schedule park capability: %s", (Get_Cap(ehci_hcc_params) & 40967c478bd9Sstevel@tonic-gate EHCI_HCC_ASYNC_SCHED_PARK_CAP) ? "Yes" : "No"); 40977c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 40987c478bd9Sstevel@tonic-gate "Programmable frame list flag: %s", (Get_Cap(ehci_hcc_params) & 40997c478bd9Sstevel@tonic-gate EHCI_HCC_PROG_FRAME_LIST_FLAG) ? "256/512/1024" : "1024"); 41007c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41017c478bd9Sstevel@tonic-gate "64bit addressing capability: %s\n", (Get_Cap(ehci_hcc_params) & 41027c478bd9Sstevel@tonic-gate EHCI_HCC_64BIT_ADDR_CAP) ? "Yes" : "No"); 41037c478bd9Sstevel@tonic-gate 41047c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41057c478bd9Sstevel@tonic-gate "Classic Port Route Description"); 41067c478bd9Sstevel@tonic-gate 41077c478bd9Sstevel@tonic-gate for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) { 41087c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41097c478bd9Sstevel@tonic-gate "\tPort Route 0x%x: 0x%x", i, Get_8Cap(ehci_port_route[i])); 41107c478bd9Sstevel@tonic-gate } 41117c478bd9Sstevel@tonic-gate } 41127c478bd9Sstevel@tonic-gate 41137c478bd9Sstevel@tonic-gate 41147c478bd9Sstevel@tonic-gate /* 41157c478bd9Sstevel@tonic-gate * ehci_print_regs: 41167c478bd9Sstevel@tonic-gate */ 41177c478bd9Sstevel@tonic-gate void 41187c478bd9Sstevel@tonic-gate ehci_print_regs(ehci_state_t *ehcip) 41197c478bd9Sstevel@tonic-gate { 41207c478bd9Sstevel@tonic-gate uint_t i; 41217c478bd9Sstevel@tonic-gate 41227c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41237c478bd9Sstevel@tonic-gate "\n\tEHCI%d Operational Registers\n", 41247c478bd9Sstevel@tonic-gate ddi_get_instance(ehcip->ehci_dip)); 41257c478bd9Sstevel@tonic-gate 41267c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41277c478bd9Sstevel@tonic-gate "Command: 0x%x Status: 0x%x", 41287c478bd9Sstevel@tonic-gate Get_OpReg(ehci_command), Get_OpReg(ehci_status)); 41297c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41307c478bd9Sstevel@tonic-gate "Interrupt: 0x%x Frame Index: 0x%x", 41317c478bd9Sstevel@tonic-gate Get_OpReg(ehci_interrupt), Get_OpReg(ehci_frame_index)); 41327c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41337c478bd9Sstevel@tonic-gate "Control Segment: 0x%x Periodic List Base: 0x%x", 41347c478bd9Sstevel@tonic-gate Get_OpReg(ehci_ctrl_segment), Get_OpReg(ehci_periodic_list_base)); 41357c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41367c478bd9Sstevel@tonic-gate "Async List Addr: 0x%x Config Flag: 0x%x", 41377c478bd9Sstevel@tonic-gate Get_OpReg(ehci_async_list_addr), Get_OpReg(ehci_config_flag)); 41387c478bd9Sstevel@tonic-gate 41397c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41407c478bd9Sstevel@tonic-gate "Root Hub Port Status"); 41417c478bd9Sstevel@tonic-gate 41427c478bd9Sstevel@tonic-gate for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) { 41437c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, 41447c478bd9Sstevel@tonic-gate "\tPort Status 0x%x: 0x%x ", i, 41457c478bd9Sstevel@tonic-gate Get_OpReg(ehci_rh_port_status[i])); 41467c478bd9Sstevel@tonic-gate } 41477c478bd9Sstevel@tonic-gate } 41487c478bd9Sstevel@tonic-gate 41497c478bd9Sstevel@tonic-gate 41507c478bd9Sstevel@tonic-gate /* 41517c478bd9Sstevel@tonic-gate * ehci_print_qh: 41527c478bd9Sstevel@tonic-gate */ 41537c478bd9Sstevel@tonic-gate void 41547c478bd9Sstevel@tonic-gate ehci_print_qh( 41557c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 41567c478bd9Sstevel@tonic-gate ehci_qh_t *qh) 41577c478bd9Sstevel@tonic-gate { 41587c478bd9Sstevel@tonic-gate uint_t i; 41597c478bd9Sstevel@tonic-gate 41607c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41617c478bd9Sstevel@tonic-gate "ehci_print_qh: qh = 0x%p", (void *)qh); 41627c478bd9Sstevel@tonic-gate 41637c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41647c478bd9Sstevel@tonic-gate "\tqh_link_ptr: 0x%x ", Get_QH(qh->qh_link_ptr)); 41657c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41667c478bd9Sstevel@tonic-gate "\tqh_ctrl: 0x%x ", Get_QH(qh->qh_ctrl)); 41677c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41687c478bd9Sstevel@tonic-gate "\tqh_split_ctrl: 0x%x ", Get_QH(qh->qh_split_ctrl)); 41697c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41707c478bd9Sstevel@tonic-gate "\tqh_curr_qtd: 0x%x ", Get_QH(qh->qh_curr_qtd)); 41717c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41727c478bd9Sstevel@tonic-gate "\tqh_next_qtd: 0x%x ", Get_QH(qh->qh_next_qtd)); 41737c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41747c478bd9Sstevel@tonic-gate "\tqh_alt_next_qtd: 0x%x ", Get_QH(qh->qh_alt_next_qtd)); 41757c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41767c478bd9Sstevel@tonic-gate "\tqh_status: 0x%x ", Get_QH(qh->qh_status)); 41777c478bd9Sstevel@tonic-gate 41787c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 41797c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41807c478bd9Sstevel@tonic-gate "\tqh_buf[%d]: 0x%x ", i, Get_QH(qh->qh_buf[i])); 41817c478bd9Sstevel@tonic-gate } 41827c478bd9Sstevel@tonic-gate 41837c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 41847c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41857c478bd9Sstevel@tonic-gate "\tqh_buf_high[%d]: 0x%x ", 41867c478bd9Sstevel@tonic-gate i, Get_QH(qh->qh_buf_high[i])); 41877c478bd9Sstevel@tonic-gate } 41887c478bd9Sstevel@tonic-gate 41897c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41907c478bd9Sstevel@tonic-gate "\tqh_dummy_qtd: 0x%x ", Get_QH(qh->qh_dummy_qtd)); 41917c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41927c478bd9Sstevel@tonic-gate "\tqh_prev: 0x%x ", Get_QH(qh->qh_prev)); 41937c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41947c478bd9Sstevel@tonic-gate "\tqh_state: 0x%x ", Get_QH(qh->qh_state)); 41957c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41967c478bd9Sstevel@tonic-gate "\tqh_reclaim_next: 0x%x ", Get_QH(qh->qh_reclaim_next)); 41977c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 41987c478bd9Sstevel@tonic-gate "\tqh_reclaim_frame: 0x%x ", Get_QH(qh->qh_reclaim_frame)); 41997c478bd9Sstevel@tonic-gate } 42007c478bd9Sstevel@tonic-gate 42017c478bd9Sstevel@tonic-gate 42027c478bd9Sstevel@tonic-gate /* 42037c478bd9Sstevel@tonic-gate * ehci_print_qtd: 42047c478bd9Sstevel@tonic-gate */ 42057c478bd9Sstevel@tonic-gate void 42067c478bd9Sstevel@tonic-gate ehci_print_qtd( 42077c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 42087c478bd9Sstevel@tonic-gate ehci_qtd_t *qtd) 42097c478bd9Sstevel@tonic-gate { 42107c478bd9Sstevel@tonic-gate uint_t i; 42117c478bd9Sstevel@tonic-gate 42127c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42137c478bd9Sstevel@tonic-gate "ehci_print_qtd: qtd = 0x%p", (void *)qtd); 42147c478bd9Sstevel@tonic-gate 42157c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42167c478bd9Sstevel@tonic-gate "\tqtd_next_qtd: 0x%x ", Get_QTD(qtd->qtd_next_qtd)); 42177c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42187c478bd9Sstevel@tonic-gate "\tqtd_alt_next_qtd: 0x%x ", Get_QTD(qtd->qtd_alt_next_qtd)); 42197c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42207c478bd9Sstevel@tonic-gate "\tqtd_ctrl: 0x%x ", Get_QTD(qtd->qtd_ctrl)); 42217c478bd9Sstevel@tonic-gate 42227c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 42237c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42247c478bd9Sstevel@tonic-gate "\tqtd_buf[%d]: 0x%x ", i, Get_QTD(qtd->qtd_buf[i])); 42257c478bd9Sstevel@tonic-gate } 42267c478bd9Sstevel@tonic-gate 42277c478bd9Sstevel@tonic-gate for (i = 0; i < 5; i++) { 42287c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42297c478bd9Sstevel@tonic-gate "\tqtd_buf_high[%d]: 0x%x ", 42307c478bd9Sstevel@tonic-gate i, Get_QTD(qtd->qtd_buf_high[i])); 42317c478bd9Sstevel@tonic-gate } 42327c478bd9Sstevel@tonic-gate 42337c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42347c478bd9Sstevel@tonic-gate "\tqtd_trans_wrapper: 0x%x ", Get_QTD(qtd->qtd_trans_wrapper)); 42357c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42367c478bd9Sstevel@tonic-gate "\tqtd_tw_next_qtd: 0x%x ", Get_QTD(qtd->qtd_tw_next_qtd)); 42377c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42387c478bd9Sstevel@tonic-gate "\tqtd_active_qtd_next: 0x%x ", Get_QTD(qtd->qtd_active_qtd_next)); 42397c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42407c478bd9Sstevel@tonic-gate "\tqtd_active_qtd_prev: 0x%x ", Get_QTD(qtd->qtd_active_qtd_prev)); 42417c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42427c478bd9Sstevel@tonic-gate "\tqtd_state: 0x%x ", Get_QTD(qtd->qtd_state)); 42437c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42447c478bd9Sstevel@tonic-gate "\tqtd_ctrl_phase: 0x%x ", Get_QTD(qtd->qtd_ctrl_phase)); 42457c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42463304303fSsl "\tqtd_xfer_offs: 0x%x ", Get_QTD(qtd->qtd_xfer_offs)); 42477c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl, 42487c478bd9Sstevel@tonic-gate "\tqtd_xfer_len: 0x%x ", Get_QTD(qtd->qtd_xfer_len)); 42497c478bd9Sstevel@tonic-gate } 42507c478bd9Sstevel@tonic-gate 42517c478bd9Sstevel@tonic-gate /* 42527c478bd9Sstevel@tonic-gate * ehci kstat functions 42537c478bd9Sstevel@tonic-gate */ 42547c478bd9Sstevel@tonic-gate 42557c478bd9Sstevel@tonic-gate /* 42567c478bd9Sstevel@tonic-gate * ehci_create_stats: 42577c478bd9Sstevel@tonic-gate * 42587c478bd9Sstevel@tonic-gate * Allocate and initialize the ehci kstat structures 42597c478bd9Sstevel@tonic-gate */ 42607c478bd9Sstevel@tonic-gate void 42617c478bd9Sstevel@tonic-gate ehci_create_stats(ehci_state_t *ehcip) 42627c478bd9Sstevel@tonic-gate { 42637c478bd9Sstevel@tonic-gate char kstatname[KSTAT_STRLEN]; 42647c478bd9Sstevel@tonic-gate const char *dname = ddi_driver_name(ehcip->ehci_dip); 42657c478bd9Sstevel@tonic-gate char *usbtypes[USB_N_COUNT_KSTATS] = 4266*29aca3ebSlc {"ctrl", "isoch", "bulk", "intr"}; 42677c478bd9Sstevel@tonic-gate uint_t instance = ehcip->ehci_instance; 42687c478bd9Sstevel@tonic-gate ehci_intrs_stats_t *isp; 42697c478bd9Sstevel@tonic-gate int i; 42707c478bd9Sstevel@tonic-gate 42717c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip) == NULL) { 42727c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,intrs", 42737c478bd9Sstevel@tonic-gate dname, instance); 42747c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip) = kstat_create("usba", instance, 42757c478bd9Sstevel@tonic-gate kstatname, "usb_interrupts", KSTAT_TYPE_NAMED, 42767c478bd9Sstevel@tonic-gate sizeof (ehci_intrs_stats_t) / sizeof (kstat_named_t), 42777c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 42787c478bd9Sstevel@tonic-gate 42797c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) { 42807c478bd9Sstevel@tonic-gate isp = EHCI_INTRS_STATS_DATA(ehcip); 42817c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_total, 42827c478bd9Sstevel@tonic-gate "Interrupts Total", KSTAT_DATA_UINT64); 42837c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_not_claimed, 42847c478bd9Sstevel@tonic-gate "Not Claimed", KSTAT_DATA_UINT64); 42857c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_async_sched_status, 42867c478bd9Sstevel@tonic-gate "Async schedule status", KSTAT_DATA_UINT64); 42877c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_periodic_sched_status, 42887c478bd9Sstevel@tonic-gate "Periodic sched status", KSTAT_DATA_UINT64); 42897c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_empty_async_schedule, 42907c478bd9Sstevel@tonic-gate "Empty async schedule", KSTAT_DATA_UINT64); 42917c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_host_ctrl_halted, 42927c478bd9Sstevel@tonic-gate "Host controller Halted", KSTAT_DATA_UINT64); 42937c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_async_advance_intr, 42947c478bd9Sstevel@tonic-gate "Intr on async advance", KSTAT_DATA_UINT64); 42957c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_host_system_error_intr, 42967c478bd9Sstevel@tonic-gate "Host system error", KSTAT_DATA_UINT64); 42977c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_frm_list_rollover_intr, 42987c478bd9Sstevel@tonic-gate "Frame list rollover", KSTAT_DATA_UINT64); 42997c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_rh_port_change_intr, 43007c478bd9Sstevel@tonic-gate "Port change detect", KSTAT_DATA_UINT64); 43017c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_usb_error_intr, 43027c478bd9Sstevel@tonic-gate "USB error interrupt", KSTAT_DATA_UINT64); 43037c478bd9Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_usb_intr, 43047c478bd9Sstevel@tonic-gate "USB interrupt", KSTAT_DATA_UINT64); 43057c478bd9Sstevel@tonic-gate 43067c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip)->ks_private = ehcip; 43077c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip)->ks_update = nulldev; 43087c478bd9Sstevel@tonic-gate kstat_install(EHCI_INTRS_STATS(ehcip)); 43097c478bd9Sstevel@tonic-gate } 43107c478bd9Sstevel@tonic-gate } 43117c478bd9Sstevel@tonic-gate 43127c478bd9Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip) == NULL) { 43137c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,total", 43147c478bd9Sstevel@tonic-gate dname, instance); 43157c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS(ehcip) = kstat_create("usba", instance, 43167c478bd9Sstevel@tonic-gate kstatname, "usb_byte_count", KSTAT_TYPE_IO, 1, 43177c478bd9Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 43187c478bd9Sstevel@tonic-gate 43197c478bd9Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip)) { 43207c478bd9Sstevel@tonic-gate kstat_install(EHCI_TOTAL_STATS(ehcip)); 43217c478bd9Sstevel@tonic-gate } 43227c478bd9Sstevel@tonic-gate } 43237c478bd9Sstevel@tonic-gate 43247c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) { 43257c478bd9Sstevel@tonic-gate if (ehcip->ehci_count_stats[i] == NULL) { 43267c478bd9Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,%s", 43277c478bd9Sstevel@tonic-gate dname, instance, usbtypes[i]); 43287c478bd9Sstevel@tonic-gate ehcip->ehci_count_stats[i] = kstat_create("usba", 43297c478bd9Sstevel@tonic-gate instance, kstatname, "usb_byte_count", 43307c478bd9Sstevel@tonic-gate KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT); 43317c478bd9Sstevel@tonic-gate 43327c478bd9Sstevel@tonic-gate if (ehcip->ehci_count_stats[i]) { 43337c478bd9Sstevel@tonic-gate kstat_install(ehcip->ehci_count_stats[i]); 43347c478bd9Sstevel@tonic-gate } 43357c478bd9Sstevel@tonic-gate } 43367c478bd9Sstevel@tonic-gate } 43377c478bd9Sstevel@tonic-gate } 43387c478bd9Sstevel@tonic-gate 43397c478bd9Sstevel@tonic-gate 43407c478bd9Sstevel@tonic-gate /* 43417c478bd9Sstevel@tonic-gate * ehci_destroy_stats: 43427c478bd9Sstevel@tonic-gate * 43437c478bd9Sstevel@tonic-gate * Clean up ehci kstat structures 43447c478bd9Sstevel@tonic-gate */ 43457c478bd9Sstevel@tonic-gate void 43467c478bd9Sstevel@tonic-gate ehci_destroy_stats(ehci_state_t *ehcip) 43477c478bd9Sstevel@tonic-gate { 43487c478bd9Sstevel@tonic-gate int i; 43497c478bd9Sstevel@tonic-gate 43507c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) { 43517c478bd9Sstevel@tonic-gate kstat_delete(EHCI_INTRS_STATS(ehcip)); 43527c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip) = NULL; 43537c478bd9Sstevel@tonic-gate } 43547c478bd9Sstevel@tonic-gate 43557c478bd9Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip)) { 43567c478bd9Sstevel@tonic-gate kstat_delete(EHCI_TOTAL_STATS(ehcip)); 43577c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS(ehcip) = NULL; 43587c478bd9Sstevel@tonic-gate } 43597c478bd9Sstevel@tonic-gate 43607c478bd9Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) { 43617c478bd9Sstevel@tonic-gate if (ehcip->ehci_count_stats[i]) { 43627c478bd9Sstevel@tonic-gate kstat_delete(ehcip->ehci_count_stats[i]); 43637c478bd9Sstevel@tonic-gate ehcip->ehci_count_stats[i] = NULL; 43647c478bd9Sstevel@tonic-gate } 43657c478bd9Sstevel@tonic-gate } 43667c478bd9Sstevel@tonic-gate } 43677c478bd9Sstevel@tonic-gate 43687c478bd9Sstevel@tonic-gate 43697c478bd9Sstevel@tonic-gate /* 43707c478bd9Sstevel@tonic-gate * ehci_do_intrs_stats: 43717c478bd9Sstevel@tonic-gate * 43727c478bd9Sstevel@tonic-gate * ehci status information 43737c478bd9Sstevel@tonic-gate */ 43747c478bd9Sstevel@tonic-gate void 43757c478bd9Sstevel@tonic-gate ehci_do_intrs_stats( 43767c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 43777c478bd9Sstevel@tonic-gate int val) 43787c478bd9Sstevel@tonic-gate { 43797c478bd9Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) { 43807c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->ehci_sts_total.value.ui64++; 43817c478bd9Sstevel@tonic-gate switch (val) { 43827c478bd9Sstevel@tonic-gate case EHCI_STS_ASYNC_SCHED_STATUS: 43837c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 43847c478bd9Sstevel@tonic-gate ehci_sts_async_sched_status.value.ui64++; 43857c478bd9Sstevel@tonic-gate break; 43867c478bd9Sstevel@tonic-gate case EHCI_STS_PERIODIC_SCHED_STATUS: 43877c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 43887c478bd9Sstevel@tonic-gate ehci_sts_periodic_sched_status.value.ui64++; 43897c478bd9Sstevel@tonic-gate break; 43907c478bd9Sstevel@tonic-gate case EHCI_STS_EMPTY_ASYNC_SCHEDULE: 43917c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 43927c478bd9Sstevel@tonic-gate ehci_sts_empty_async_schedule.value.ui64++; 43937c478bd9Sstevel@tonic-gate break; 43947c478bd9Sstevel@tonic-gate case EHCI_STS_HOST_CTRL_HALTED: 43957c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 43967c478bd9Sstevel@tonic-gate ehci_sts_host_ctrl_halted.value.ui64++; 43977c478bd9Sstevel@tonic-gate break; 43987c478bd9Sstevel@tonic-gate case EHCI_STS_ASYNC_ADVANCE_INTR: 43997c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44007c478bd9Sstevel@tonic-gate ehci_sts_async_advance_intr.value.ui64++; 44017c478bd9Sstevel@tonic-gate break; 44027c478bd9Sstevel@tonic-gate case EHCI_STS_HOST_SYSTEM_ERROR_INTR: 44037c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44047c478bd9Sstevel@tonic-gate ehci_sts_host_system_error_intr.value.ui64++; 44057c478bd9Sstevel@tonic-gate break; 44067c478bd9Sstevel@tonic-gate case EHCI_STS_FRM_LIST_ROLLOVER_INTR: 44077c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44087c478bd9Sstevel@tonic-gate ehci_sts_frm_list_rollover_intr.value.ui64++; 44097c478bd9Sstevel@tonic-gate break; 44107c478bd9Sstevel@tonic-gate case EHCI_STS_RH_PORT_CHANGE_INTR: 44117c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44127c478bd9Sstevel@tonic-gate ehci_sts_rh_port_change_intr.value.ui64++; 44137c478bd9Sstevel@tonic-gate break; 44147c478bd9Sstevel@tonic-gate case EHCI_STS_USB_ERROR_INTR: 44157c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44167c478bd9Sstevel@tonic-gate ehci_sts_usb_error_intr.value.ui64++; 44177c478bd9Sstevel@tonic-gate break; 44187c478bd9Sstevel@tonic-gate case EHCI_STS_USB_INTR: 44197c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44207c478bd9Sstevel@tonic-gate ehci_sts_usb_intr.value.ui64++; 44217c478bd9Sstevel@tonic-gate break; 44227c478bd9Sstevel@tonic-gate default: 44237c478bd9Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)-> 44247c478bd9Sstevel@tonic-gate ehci_sts_not_claimed.value.ui64++; 44257c478bd9Sstevel@tonic-gate break; 44267c478bd9Sstevel@tonic-gate } 44277c478bd9Sstevel@tonic-gate } 44287c478bd9Sstevel@tonic-gate } 44297c478bd9Sstevel@tonic-gate 44307c478bd9Sstevel@tonic-gate 44317c478bd9Sstevel@tonic-gate /* 44327c478bd9Sstevel@tonic-gate * ehci_do_byte_stats: 44337c478bd9Sstevel@tonic-gate * 44347c478bd9Sstevel@tonic-gate * ehci data xfer information 44357c478bd9Sstevel@tonic-gate */ 44367c478bd9Sstevel@tonic-gate void 44377c478bd9Sstevel@tonic-gate ehci_do_byte_stats( 44387c478bd9Sstevel@tonic-gate ehci_state_t *ehcip, 44397c478bd9Sstevel@tonic-gate size_t len, 44407c478bd9Sstevel@tonic-gate uint8_t attr, 44417c478bd9Sstevel@tonic-gate uint8_t addr) 44427c478bd9Sstevel@tonic-gate { 44437c478bd9Sstevel@tonic-gate uint8_t type = attr & USB_EP_ATTR_MASK; 44447c478bd9Sstevel@tonic-gate uint8_t dir = addr & USB_EP_DIR_MASK; 44457c478bd9Sstevel@tonic-gate 44467c478bd9Sstevel@tonic-gate if (dir == USB_EP_DIR_IN) { 44477c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->reads++; 44487c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->nread += len; 44497c478bd9Sstevel@tonic-gate switch (type) { 44507c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 44517c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->reads++; 44527c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->nread += len; 44537c478bd9Sstevel@tonic-gate break; 44547c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 44557c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->reads++; 44567c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->nread += len; 44577c478bd9Sstevel@tonic-gate break; 44587c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 44597c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->reads++; 44607c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->nread += len; 44617c478bd9Sstevel@tonic-gate break; 44627c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 44637c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->reads++; 44647c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->nread += len; 44657c478bd9Sstevel@tonic-gate break; 44667c478bd9Sstevel@tonic-gate } 44677c478bd9Sstevel@tonic-gate } else if (dir == USB_EP_DIR_OUT) { 44687c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->writes++; 44697c478bd9Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->nwritten += len; 44707c478bd9Sstevel@tonic-gate switch (type) { 44717c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 44727c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->writes++; 44737c478bd9Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->nwritten += len; 44747c478bd9Sstevel@tonic-gate break; 44757c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 44767c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->writes++; 44777c478bd9Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->nwritten += len; 44787c478bd9Sstevel@tonic-gate break; 44797c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 44807c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->writes++; 44817c478bd9Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->nwritten += len; 44827c478bd9Sstevel@tonic-gate break; 44837c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 44847c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->writes++; 44857c478bd9Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->nwritten += len; 44867c478bd9Sstevel@tonic-gate break; 44877c478bd9Sstevel@tonic-gate } 44887c478bd9Sstevel@tonic-gate } 44897c478bd9Sstevel@tonic-gate } 4490