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