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