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