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