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 /*
2229aca3ebSlc  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * EHCI Host Controller Driver (EHCI)
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  * The EHCI driver is a software driver which interfaces to the Universal
317c478bd9Sstevel@tonic-gate  * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
327c478bd9Sstevel@tonic-gate  * the Host Controller is defined by the EHCI Host Controller Interface.
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * This module contains the main EHCI driver code which handles all USB
357c478bd9Sstevel@tonic-gate  * transfers, bandwidth allocations and other general functionalities.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h>
397c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_isoch.h>
407c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h>
417c478bd9Sstevel@tonic-gate 
429c75c6bfSgovinda /*
439c75c6bfSgovinda  * EHCI MSI tunable:
449c75c6bfSgovinda  *
459c75c6bfSgovinda  * By default MSI is enabled on all supported platforms except for the
469c75c6bfSgovinda  * EHCI controller of ULI1575 South bridge.
479c75c6bfSgovinda  */
489c75c6bfSgovinda boolean_t ehci_enable_msi = B_TRUE;
499c75c6bfSgovinda 
507c478bd9Sstevel@tonic-gate /* Pointer to the state structure */
517c478bd9Sstevel@tonic-gate extern void *ehci_statep;
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate extern void ehci_handle_endpoint_reclaimation(ehci_state_t *);
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate extern uint_t ehci_vt62x2_workaround;
562df1fe9cSrandyf extern int force_ehci_off;
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,
29429aca3ebSlc 	    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 
3103ceb94daSbc void
3113ceb94daSbc ehci_dma_attr_workaround(ehci_state_t	*ehcip)
3123ceb94daSbc {
3133ceb94daSbc 	/*
3143ceb94daSbc 	 * Some Nvidia chips can not handle qh dma address above 2G.
3153ceb94daSbc 	 * The bit 31 of the dma address might be omitted and it will
3163ceb94daSbc 	 * cause system crash or other unpredicable result. So force
3173ceb94daSbc 	 * the dma address allocated below 2G to make ehci work.
3183ceb94daSbc 	 */
3193ceb94daSbc 	if (PCI_VENDOR_NVIDIA == ehcip->ehci_vendor_id) {
3203ceb94daSbc 		switch (ehcip->ehci_device_id) {
3213ceb94daSbc 			case PCI_DEVICE_NVIDIA_CK804:
322*2259743eSbinzi cao - Sun Microsystems - Beijing China 			case PCI_DEVICE_NVIDIA_MCP04:
3233ceb94daSbc 				USB_DPRINTF_L2(PRINT_MASK_ATTA,
3243ceb94daSbc 				    ehcip->ehci_log_hdl,
3253ceb94daSbc 				    "ehci_dma_attr_workaround: NVIDIA dma "
3263ceb94daSbc 				    "workaround enabled, force dma address "
3273ceb94daSbc 				    "to be allocated below 2G");
3283ceb94daSbc 				ehcip->ehci_dma_attr.dma_attr_addr_hi =
3293ceb94daSbc 				    0x7fffffffull;
3303ceb94daSbc 				break;
3313ceb94daSbc 			default:
3323ceb94daSbc 				break;
3333ceb94daSbc 
3343ceb94daSbc 		}
3353ceb94daSbc 	}
3363ceb94daSbc }
3374610e4a0Sfrits 
3387c478bd9Sstevel@tonic-gate /*
3397c478bd9Sstevel@tonic-gate  * Host Controller Driver (HCD) initialization functions
3407c478bd9Sstevel@tonic-gate  */
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate /*
3437c478bd9Sstevel@tonic-gate  * ehci_set_dma_attributes:
3447c478bd9Sstevel@tonic-gate  *
3457c478bd9Sstevel@tonic-gate  * Set the limits in the DMA attributes structure. Most of the values used
3467c478bd9Sstevel@tonic-gate  * in the  DMA limit structures are the default values as specified by	the
3477c478bd9Sstevel@tonic-gate  * Writing PCI device drivers document.
3487c478bd9Sstevel@tonic-gate  */
3497c478bd9Sstevel@tonic-gate void
3507c478bd9Sstevel@tonic-gate ehci_set_dma_attributes(ehci_state_t	*ehcip)
3517c478bd9Sstevel@tonic-gate {
3527c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3537c478bd9Sstevel@tonic-gate 	    "ehci_set_dma_attributes:");
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	/* Initialize the DMA attributes */
3567c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_version = DMA_ATTR_V0;
3577c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_addr_lo = 0x00000000ull;
3587c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_addr_hi = 0xfffffffeull;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	/* 32 bit addressing */
3617c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_count_max = EHCI_DMA_ATTR_COUNT_MAX;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	/* Byte alignment */
3647c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	/*
3677c478bd9Sstevel@tonic-gate 	 * Since PCI  specification is byte alignment, the
3687c478bd9Sstevel@tonic-gate 	 * burst size field should be set to 1 for PCI devices.
3697c478bd9Sstevel@tonic-gate 	 */
3707c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_burstsizes = 0x1;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_minxfer = 0x1;
3737c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_maxxfer = EHCI_DMA_ATTR_MAX_XFER;
3747c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_seg = 0xffffffffull;
3757c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_sgllen = 1;
3767c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_granular = EHCI_DMA_ATTR_GRANULAR;
3777c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_flags = 0;
3783ceb94daSbc 	ehci_dma_attr_workaround(ehcip);
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate /*
3837c478bd9Sstevel@tonic-gate  * ehci_allocate_pools:
3847c478bd9Sstevel@tonic-gate  *
3857c478bd9Sstevel@tonic-gate  * Allocate the system memory for the Endpoint Descriptor (QH) and for the
3867c478bd9Sstevel@tonic-gate  * Transfer Descriptor (QTD) pools. Both QH and QTD structures must be aligned
3877c478bd9Sstevel@tonic-gate  * to a 16 byte boundary.
3887c478bd9Sstevel@tonic-gate  */
3897c478bd9Sstevel@tonic-gate int
3907c478bd9Sstevel@tonic-gate ehci_allocate_pools(ehci_state_t	*ehcip)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t		dev_attr;
3937c478bd9Sstevel@tonic-gate 	size_t				real_length;
3947c478bd9Sstevel@tonic-gate 	int				result;
3957c478bd9Sstevel@tonic-gate 	uint_t				ccount;
3967c478bd9Sstevel@tonic-gate 	int				i;
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3997c478bd9Sstevel@tonic-gate 	    "ehci_allocate_pools:");
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	/* The host controller will be little endian */
4027c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_version	= DDI_DEVICE_ATTR_V0;
4037c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
4047c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_dataorder	= DDI_STRICTORDER_ACC;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	/* Byte alignment */
4077c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_TD_QH_ALIGNMENT;
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	/* Allocate the QTD pool DMA handle */
4107c478bd9Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr,
41129aca3ebSlc 	    DDI_DMA_SLEEP, 0,
41229aca3ebSlc 	    &ehcip->ehci_qtd_pool_dma_handle) != DDI_SUCCESS) {
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 		goto failure;
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	/* Allocate the memory for the QTD pool */
4187c478bd9Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(ehcip->ehci_qtd_pool_dma_handle,
41929aca3ebSlc 	    ehci_qtd_pool_size * sizeof (ehci_qtd_t),
42029aca3ebSlc 	    &dev_attr,
42129aca3ebSlc 	    DDI_DMA_CONSISTENT,
42229aca3ebSlc 	    DDI_DMA_SLEEP,
42329aca3ebSlc 	    0,
42429aca3ebSlc 	    (caddr_t *)&ehcip->ehci_qtd_pool_addr,
42529aca3ebSlc 	    &real_length,
42629aca3ebSlc 	    &ehcip->ehci_qtd_pool_mem_handle)) {
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 		goto failure;
4297c478bd9Sstevel@tonic-gate 	}
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	/* Map the QTD pool into the I/O address space */
4327c478bd9Sstevel@tonic-gate 	result = ddi_dma_addr_bind_handle(
43329aca3ebSlc 	    ehcip->ehci_qtd_pool_dma_handle,
43429aca3ebSlc 	    NULL,
43529aca3ebSlc 	    (caddr_t)ehcip->ehci_qtd_pool_addr,
43629aca3ebSlc 	    real_length,
43729aca3ebSlc 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
43829aca3ebSlc 	    DDI_DMA_SLEEP,
43929aca3ebSlc 	    NULL,
44029aca3ebSlc 	    &ehcip->ehci_qtd_pool_cookie,
44129aca3ebSlc 	    &ccount);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	bzero((void *)ehcip->ehci_qtd_pool_addr,
44429aca3ebSlc 	    ehci_qtd_pool_size * sizeof (ehci_qtd_t));
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	/* Process the result */
4477c478bd9Sstevel@tonic-gate 	if (result == DDI_DMA_MAPPED) {
4487c478bd9Sstevel@tonic-gate 		/* The cookie count should be 1 */
4497c478bd9Sstevel@tonic-gate 		if (ccount != 1) {
4507c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4517c478bd9Sstevel@tonic-gate 			    "ehci_allocate_pools: More than 1 cookie");
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 		goto failure;
4547c478bd9Sstevel@tonic-gate 		}
4557c478bd9Sstevel@tonic-gate 	} else {
4567c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4577c478bd9Sstevel@tonic-gate 		    "ehci_allocate_pools: Result = %d", result);
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 		ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 		goto failure;
4627c478bd9Sstevel@tonic-gate 	}
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	/*
4657c478bd9Sstevel@tonic-gate 	 * DMA addresses for QTD pools are bound
4667c478bd9Sstevel@tonic-gate 	 */
4677c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_addr_bind_flag |= EHCI_QTD_POOL_BOUND;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	/* Initialize the QTD pool */
4707c478bd9Sstevel@tonic-gate 	for (i = 0; i < ehci_qtd_pool_size; i ++) {
4717c478bd9Sstevel@tonic-gate 		Set_QTD(ehcip->ehci_qtd_pool_addr[i].
4727c478bd9Sstevel@tonic-gate 		    qtd_state, EHCI_QTD_FREE);
4737c478bd9Sstevel@tonic-gate 	}
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	/* Allocate the QTD pool DMA handle */
4767c478bd9Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(ehcip->ehci_dip,
47729aca3ebSlc 	    &ehcip->ehci_dma_attr,
47829aca3ebSlc 	    DDI_DMA_SLEEP,
47929aca3ebSlc 	    0,
48029aca3ebSlc 	    &ehcip->ehci_qh_pool_dma_handle) != DDI_SUCCESS) {
4813ceb94daSbc 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4823ceb94daSbc 		    "ehci_allocate_pools: ddi_dma_alloc_handle failed");
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 		goto failure;
4857c478bd9Sstevel@tonic-gate 	}
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	/* Allocate the memory for the QH pool */
4887c478bd9Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(ehcip->ehci_qh_pool_dma_handle,
48929aca3ebSlc 	    ehci_qh_pool_size * sizeof (ehci_qh_t),
49029aca3ebSlc 	    &dev_attr,
49129aca3ebSlc 	    DDI_DMA_CONSISTENT,
49229aca3ebSlc 	    DDI_DMA_SLEEP,
49329aca3ebSlc 	    0,
49429aca3ebSlc 	    (caddr_t *)&ehcip->ehci_qh_pool_addr,
49529aca3ebSlc 	    &real_length,
49629aca3ebSlc 	    &ehcip->ehci_qh_pool_mem_handle) != DDI_SUCCESS) {
4973ceb94daSbc 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4983ceb94daSbc 		    "ehci_allocate_pools: ddi_dma_mem_alloc failed");
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 		goto failure;
5017c478bd9Sstevel@tonic-gate 	}
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	result = ddi_dma_addr_bind_handle(ehcip->ehci_qh_pool_dma_handle,
50429aca3ebSlc 	    NULL,
50529aca3ebSlc 	    (caddr_t)ehcip->ehci_qh_pool_addr,
50629aca3ebSlc 	    real_length,
50729aca3ebSlc 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
50829aca3ebSlc 	    DDI_DMA_SLEEP,
50929aca3ebSlc 	    NULL,
51029aca3ebSlc 	    &ehcip->ehci_qh_pool_cookie,
51129aca3ebSlc 	    &ccount);
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	bzero((void *)ehcip->ehci_qh_pool_addr,
51429aca3ebSlc 	    ehci_qh_pool_size * sizeof (ehci_qh_t));
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	/* Process the result */
5177c478bd9Sstevel@tonic-gate 	if (result == DDI_DMA_MAPPED) {
5187c478bd9Sstevel@tonic-gate 		/* The cookie count should be 1 */
5197c478bd9Sstevel@tonic-gate 		if (ccount != 1) {
5207c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
5217c478bd9Sstevel@tonic-gate 			    "ehci_allocate_pools: More than 1 cookie");
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 			goto failure;
5247c478bd9Sstevel@tonic-gate 		}
5257c478bd9Sstevel@tonic-gate 	} else {
5267c478bd9Sstevel@tonic-gate 		ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 		goto failure;
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	/*
5327c478bd9Sstevel@tonic-gate 	 * DMA addresses for QH pools are bound
5337c478bd9Sstevel@tonic-gate 	 */
5347c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_addr_bind_flag |= EHCI_QH_POOL_BOUND;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	/* Initialize the QH pool */
5377c478bd9Sstevel@tonic-gate 	for (i = 0; i < ehci_qh_pool_size; i ++) {
5387c478bd9Sstevel@tonic-gate 		Set_QH(ehcip->ehci_qh_pool_addr[i].qh_state, EHCI_QH_FREE);
5397c478bd9Sstevel@tonic-gate 	}
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	/* Byte alignment */
5427c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate failure:
5477c478bd9Sstevel@tonic-gate 	/* Byte alignment */
5487c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate /*
5557c478bd9Sstevel@tonic-gate  * ehci_decode_ddi_dma_addr_bind_handle_result:
5567c478bd9Sstevel@tonic-gate  *
5577c478bd9Sstevel@tonic-gate  * Process the return values of ddi_dma_addr_bind_handle()
5587c478bd9Sstevel@tonic-gate  */
5597c478bd9Sstevel@tonic-gate void
5607c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(
5617c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
5627c478bd9Sstevel@tonic-gate 	int		result)
5637c478bd9Sstevel@tonic-gate {
5647c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
5657c478bd9Sstevel@tonic-gate 	    "ehci_decode_ddi_dma_addr_bind_handle_result:");
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	switch (result) {
5687c478bd9Sstevel@tonic-gate 	case DDI_DMA_PARTIAL_MAP:
5697c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl,
5707c478bd9Sstevel@tonic-gate 		    "Partial transfers not allowed");
5717c478bd9Sstevel@tonic-gate 		break;
5727c478bd9Sstevel@tonic-gate 	case DDI_DMA_INUSE:
5737c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
5747c478bd9Sstevel@tonic-gate 		    "Handle is in use");
5757c478bd9Sstevel@tonic-gate 		break;
5767c478bd9Sstevel@tonic-gate 	case DDI_DMA_NORESOURCES:
5777c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
5787c478bd9Sstevel@tonic-gate 		    "No resources");
5797c478bd9Sstevel@tonic-gate 		break;
5807c478bd9Sstevel@tonic-gate 	case DDI_DMA_NOMAPPING:
5817c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
5827c478bd9Sstevel@tonic-gate 		    "No mapping");
5837c478bd9Sstevel@tonic-gate 		break;
5847c478bd9Sstevel@tonic-gate 	case DDI_DMA_TOOBIG:
5857c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
5867c478bd9Sstevel@tonic-gate 		    "Object is too big");
5877c478bd9Sstevel@tonic-gate 		break;
5887c478bd9Sstevel@tonic-gate 	default:
5897c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
5907c478bd9Sstevel@tonic-gate 		    "Unknown dma error");
5917c478bd9Sstevel@tonic-gate 	}
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate /*
5967c478bd9Sstevel@tonic-gate  * ehci_map_regs:
5977c478bd9Sstevel@tonic-gate  *
5987c478bd9Sstevel@tonic-gate  * The Host Controller (HC) contains a set of on-chip operational registers
5997c478bd9Sstevel@tonic-gate  * and which should be mapped into a non-cacheable portion of the  system
6007c478bd9Sstevel@tonic-gate  * addressable space.
6017c478bd9Sstevel@tonic-gate  */
6027c478bd9Sstevel@tonic-gate int
6037c478bd9Sstevel@tonic-gate ehci_map_regs(ehci_state_t	*ehcip)
6047c478bd9Sstevel@tonic-gate {
6057c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t	attr;
6067c478bd9Sstevel@tonic-gate 	uint16_t		cmd_reg;
6077c478bd9Sstevel@tonic-gate 	uint_t			length;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_map_regs:");
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	/* Check to make sure we have memory access */
6127c478bd9Sstevel@tonic-gate 	if (pci_config_setup(ehcip->ehci_dip,
61329aca3ebSlc 	    &ehcip->ehci_config_handle) != DDI_SUCCESS) {
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6167c478bd9Sstevel@tonic-gate 		    "ehci_map_regs: Config error");
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6197c478bd9Sstevel@tonic-gate 	}
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	/* Make sure Memory Access Enable is set */
6227c478bd9Sstevel@tonic-gate 	cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM);
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	if (!(cmd_reg & PCI_COMM_MAE)) {
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6277c478bd9Sstevel@tonic-gate 		    "ehci_map_regs: Memory base address access disabled");
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6307c478bd9Sstevel@tonic-gate 	}
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	/* The host controller will be little endian */
6337c478bd9Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
6347c478bd9Sstevel@tonic-gate 	attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
6357c478bd9Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	/* Map in EHCI Capability registers */
6387c478bd9Sstevel@tonic-gate 	if (ddi_regs_map_setup(ehcip->ehci_dip, 1,
6397c478bd9Sstevel@tonic-gate 	    (caddr_t *)&ehcip->ehci_capsp, 0,
6407c478bd9Sstevel@tonic-gate 	    sizeof (ehci_caps_t), &attr,
6417c478bd9Sstevel@tonic-gate 	    &ehcip->ehci_caps_handle) != DDI_SUCCESS) {
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6447c478bd9Sstevel@tonic-gate 		    "ehci_map_regs: Map setup error");
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6477c478bd9Sstevel@tonic-gate 	}
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	length = ddi_get8(ehcip->ehci_caps_handle,
6507c478bd9Sstevel@tonic-gate 	    (uint8_t *)&ehcip->ehci_capsp->ehci_caps_length);
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	/* Free the original mapping */
6537c478bd9Sstevel@tonic-gate 	ddi_regs_map_free(&ehcip->ehci_caps_handle);
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	/* Re-map in EHCI Capability and Operational registers */
6567c478bd9Sstevel@tonic-gate 	if (ddi_regs_map_setup(ehcip->ehci_dip, 1,
6577c478bd9Sstevel@tonic-gate 	    (caddr_t *)&ehcip->ehci_capsp, 0,
6587c478bd9Sstevel@tonic-gate 	    length + sizeof (ehci_regs_t), &attr,
6597c478bd9Sstevel@tonic-gate 	    &ehcip->ehci_caps_handle) != DDI_SUCCESS) {
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6627c478bd9Sstevel@tonic-gate 		    "ehci_map_regs: Map setup error");
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	/* Get the pointer to EHCI Operational Register */
6687c478bd9Sstevel@tonic-gate 	ehcip->ehci_regsp = (ehci_regs_t *)
6697c478bd9Sstevel@tonic-gate 	    ((uintptr_t)ehcip->ehci_capsp + length);
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6727c478bd9Sstevel@tonic-gate 	    "ehci_map_regs: Capsp 0x%p Regsp 0x%p\n",
673112116d8Sfb 	    (void *)ehcip->ehci_capsp, (void *)ehcip->ehci_regsp);
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate 
67828cdc3d7Sszhou /*
67928cdc3d7Sszhou  * The following simulated polling is for debugging purposes only.
68028cdc3d7Sszhou  * It is activated on x86 by setting usb-polling=true in GRUB or ehci.conf.
68128cdc3d7Sszhou  */
68228cdc3d7Sszhou static int
68328cdc3d7Sszhou ehci_is_polled(dev_info_t *dip)
68428cdc3d7Sszhou {
68528cdc3d7Sszhou 	int ret;
68628cdc3d7Sszhou 	char *propval;
68728cdc3d7Sszhou 
68828cdc3d7Sszhou 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
68928cdc3d7Sszhou 	    "usb-polling", &propval) != DDI_SUCCESS)
69028cdc3d7Sszhou 
69128cdc3d7Sszhou 		return (0);
69228cdc3d7Sszhou 
69328cdc3d7Sszhou 	ret = (strcmp(propval, "true") == 0);
69428cdc3d7Sszhou 	ddi_prop_free(propval);
69528cdc3d7Sszhou 
69628cdc3d7Sszhou 	return (ret);
69728cdc3d7Sszhou }
69828cdc3d7Sszhou 
69928cdc3d7Sszhou static void
70028cdc3d7Sszhou ehci_poll_intr(void *arg)
70128cdc3d7Sszhou {
70228cdc3d7Sszhou 	/* poll every msec */
70328cdc3d7Sszhou 	for (;;) {
70428cdc3d7Sszhou 		(void) ehci_intr(arg, NULL);
70528cdc3d7Sszhou 		delay(drv_usectohz(1000));
70628cdc3d7Sszhou 	}
70728cdc3d7Sszhou }
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate /*
7107c478bd9Sstevel@tonic-gate  * ehci_register_intrs_and_init_mutex:
7117c478bd9Sstevel@tonic-gate  *
7127c478bd9Sstevel@tonic-gate  * Register interrupts and initialize each mutex and condition variables
7137c478bd9Sstevel@tonic-gate  */
7147c478bd9Sstevel@tonic-gate int
7157c478bd9Sstevel@tonic-gate ehci_register_intrs_and_init_mutex(ehci_state_t	*ehcip)
7167c478bd9Sstevel@tonic-gate {
7179c75c6bfSgovinda 	int	intr_types;
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate #if defined(__x86)
7207c478bd9Sstevel@tonic-gate 	uint8_t iline;
7217c478bd9Sstevel@tonic-gate #endif
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7247c478bd9Sstevel@tonic-gate 	    "ehci_register_intrs_and_init_mutex:");
7257c478bd9Sstevel@tonic-gate 
7269c75c6bfSgovinda 	/*
7279c75c6bfSgovinda 	 * There is a known MSI hardware bug with the EHCI controller
7289c75c6bfSgovinda 	 * of ULI1575 southbridge. Hence MSI is disabled for this chip.
7299c75c6bfSgovinda 	 */
7309c75c6bfSgovinda 	if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
7319c75c6bfSgovinda 	    (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) {
7329c75c6bfSgovinda 		ehcip->ehci_msi_enabled = B_FALSE;
7339c75c6bfSgovinda 	} else {
7349c75c6bfSgovinda 		/* Set the MSI enable flag from the global EHCI MSI tunable */
7359c75c6bfSgovinda 		ehcip->ehci_msi_enabled = ehci_enable_msi;
7369c75c6bfSgovinda 	}
7379c75c6bfSgovinda 
73828cdc3d7Sszhou 	/* launch polling thread instead of enabling pci interrupt */
73928cdc3d7Sszhou 	if (ehci_is_polled(ehcip->ehci_dip)) {
74028cdc3d7Sszhou 		extern pri_t maxclsyspri;
74128cdc3d7Sszhou 
7428668df41Slg 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
74328cdc3d7Sszhou 		    "ehci_register_intrs_and_init_mutex: "
74428cdc3d7Sszhou 		    "running in simulated polled mode");
74528cdc3d7Sszhou 
74628cdc3d7Sszhou 		(void) thread_create(NULL, 0, ehci_poll_intr, ehcip, 0, &p0,
74728cdc3d7Sszhou 		    TS_RUN, maxclsyspri);
74828cdc3d7Sszhou 
74928cdc3d7Sszhou 		goto skip_intr;
75028cdc3d7Sszhou 	}
75128cdc3d7Sszhou 
7527c478bd9Sstevel@tonic-gate #if defined(__x86)
7537c478bd9Sstevel@tonic-gate 	/*
7547c478bd9Sstevel@tonic-gate 	 * Make sure that the interrupt pin is connected to the
7557c478bd9Sstevel@tonic-gate 	 * interrupt controller on x86.	 Interrupt line 255 means
7567c478bd9Sstevel@tonic-gate 	 * "unknown" or "not connected" (PCI spec 6.2.4, footnote 43).
7574610e4a0Sfrits 	 * If we would return failure when interrupt line equals 255, then
758f87a10b6Syq 	 * high speed devices will be routed to companion host controllers.
7594610e4a0Sfrits 	 * However, it is not necessary to return failure here, and
7604610e4a0Sfrits 	 * o/uhci codes don't check the interrupt line either.
7614610e4a0Sfrits 	 * But it's good to log a message here for debug purposes.
7627c478bd9Sstevel@tonic-gate 	 */
7637c478bd9Sstevel@tonic-gate 	iline = pci_config_get8(ehcip->ehci_config_handle,
7647c478bd9Sstevel@tonic-gate 	    PCI_CONF_ILINE);
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	if (iline == 255) {
7677c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7687c478bd9Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
7697c478bd9Sstevel@tonic-gate 		    "interrupt line value out of range (%d)",
7707c478bd9Sstevel@tonic-gate 		    iline);
7717c478bd9Sstevel@tonic-gate 	}
7727c478bd9Sstevel@tonic-gate #endif	/* __x86 */
7737c478bd9Sstevel@tonic-gate 
7749c75c6bfSgovinda 	/* Get supported interrupt types */
7759c75c6bfSgovinda 	if (ddi_intr_get_supported_types(ehcip->ehci_dip,
7769c75c6bfSgovinda 	    &intr_types) != DDI_SUCCESS) {
7777c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7787c478bd9Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
7799c75c6bfSgovinda 		    "ddi_intr_get_supported_types failed");
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7827c478bd9Sstevel@tonic-gate 	}
7837c478bd9Sstevel@tonic-gate 
7849c75c6bfSgovinda 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7859c75c6bfSgovinda 	    "ehci_register_intrs_and_init_mutex: "
7869c75c6bfSgovinda 	    "supported interrupt types 0x%x", intr_types);
7879c75c6bfSgovinda 
7889c75c6bfSgovinda 	if ((intr_types & DDI_INTR_TYPE_MSI) && ehcip->ehci_msi_enabled) {
7899c75c6bfSgovinda 		if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_MSI)
7909c75c6bfSgovinda 		    != DDI_SUCCESS) {
7919c75c6bfSgovinda 			USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7929c75c6bfSgovinda 			    "ehci_register_intrs_and_init_mutex: MSI "
7939c75c6bfSgovinda 			    "registration failed, trying FIXED interrupt \n");
7949c75c6bfSgovinda 		} else {
7959c75c6bfSgovinda 			USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7969c75c6bfSgovinda 			    "ehci_register_intrs_and_init_mutex: "
7979c75c6bfSgovinda 			    "Using MSI interrupt type\n");
7989c75c6bfSgovinda 
7999c75c6bfSgovinda 			ehcip->ehci_intr_type = DDI_INTR_TYPE_MSI;
8009c75c6bfSgovinda 			ehcip->ehci_flags |= EHCI_INTR;
8019c75c6bfSgovinda 		}
8029c75c6bfSgovinda 	}
8037c478bd9Sstevel@tonic-gate 
8049c75c6bfSgovinda 	if ((!(ehcip->ehci_flags & EHCI_INTR)) &&
8059c75c6bfSgovinda 	    (intr_types & DDI_INTR_TYPE_FIXED)) {
8069c75c6bfSgovinda 		if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_FIXED)
8079c75c6bfSgovinda 		    != DDI_SUCCESS) {
8089c75c6bfSgovinda 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8099c75c6bfSgovinda 			    "ehci_register_intrs_and_init_mutex: "
8109c75c6bfSgovinda 			    "FIXED interrupt registration failed\n");
8119c75c6bfSgovinda 
8129c75c6bfSgovinda 			return (DDI_FAILURE);
8139c75c6bfSgovinda 		}
8149c75c6bfSgovinda 
8159c75c6bfSgovinda 		USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8167c478bd9Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
8179c75c6bfSgovinda 		    "Using FIXED interrupt type\n");
8189c75c6bfSgovinda 
8199c75c6bfSgovinda 		ehcip->ehci_intr_type = DDI_INTR_TYPE_FIXED;
8209c75c6bfSgovinda 		ehcip->ehci_flags |= EHCI_INTR;
8219c75c6bfSgovinda 	}
8229c75c6bfSgovinda 
82328cdc3d7Sszhou skip_intr:
8249c75c6bfSgovinda 	/* Create prototype for advance on async schedule */
8259c75c6bfSgovinda 	cv_init(&ehcip->ehci_async_schedule_advance_cv,
8269c75c6bfSgovinda 	    NULL, CV_DRIVER, NULL);
8279c75c6bfSgovinda 
8289c75c6bfSgovinda 	return (DDI_SUCCESS);
8299c75c6bfSgovinda }
8309c75c6bfSgovinda 
8319c75c6bfSgovinda 
8329c75c6bfSgovinda /*
8339c75c6bfSgovinda  * ehci_add_intrs:
8349c75c6bfSgovinda  *
8359c75c6bfSgovinda  * Register FIXED or MSI interrupts.
8369c75c6bfSgovinda  */
8379c75c6bfSgovinda static int
8389c75c6bfSgovinda ehci_add_intrs(ehci_state_t	*ehcip,
8399c75c6bfSgovinda 		int		intr_type)
8409c75c6bfSgovinda {
8419c75c6bfSgovinda 	int	actual, avail, intr_size, count = 0;
84229aca3ebSlc 	int	i, flag, ret;
8439c75c6bfSgovinda 
8449c75c6bfSgovinda 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8459c75c6bfSgovinda 	    "ehci_add_intrs: interrupt type 0x%x", intr_type);
8469c75c6bfSgovinda 
8479c75c6bfSgovinda 	/* Get number of interrupts */
8489c75c6bfSgovinda 	ret = ddi_intr_get_nintrs(ehcip->ehci_dip, intr_type, &count);
8499c75c6bfSgovinda 	if ((ret != DDI_SUCCESS) || (count == 0)) {
8509c75c6bfSgovinda 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8519c75c6bfSgovinda 		    "ehci_add_intrs: ddi_intr_get_nintrs() failure, "
8529c75c6bfSgovinda 		    "ret: %d, count: %d", ret, count);
8539c75c6bfSgovinda 
8549c75c6bfSgovinda 		return (DDI_FAILURE);
8559c75c6bfSgovinda 	}
8569c75c6bfSgovinda 
8579c75c6bfSgovinda 	/* Get number of available interrupts */
8589c75c6bfSgovinda 	ret = ddi_intr_get_navail(ehcip->ehci_dip, intr_type, &avail);
8599c75c6bfSgovinda 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
8609c75c6bfSgovinda 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8619c75c6bfSgovinda 		    "ehci_add_intrs: ddi_intr_get_navail() failure, "
8629c75c6bfSgovinda 		    "ret: %d, count: %d", ret, count);
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8657c478bd9Sstevel@tonic-gate 	}
8667c478bd9Sstevel@tonic-gate 
8679c75c6bfSgovinda 	if (avail < count) {
8689c75c6bfSgovinda 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8699c75c6bfSgovinda 		    "ehci_add_intrs: ehci_add_intrs: nintrs () "
8709c75c6bfSgovinda 		    "returned %d, navail returned %d\n", count, avail);
8719c75c6bfSgovinda 	}
8729c75c6bfSgovinda 
8739c75c6bfSgovinda 	/* Allocate an array of interrupt handles */
8749c75c6bfSgovinda 	intr_size = count * sizeof (ddi_intr_handle_t);
8759c75c6bfSgovinda 	ehcip->ehci_htable = kmem_zalloc(intr_size, KM_SLEEP);
8769c75c6bfSgovinda 
8779c75c6bfSgovinda 	flag = (intr_type == DDI_INTR_TYPE_MSI) ?
8789c75c6bfSgovinda 	    DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL;
8799c75c6bfSgovinda 
8809c75c6bfSgovinda 	/* call ddi_intr_alloc() */
8817c478bd9Sstevel@tonic-gate 	ret = ddi_intr_alloc(ehcip->ehci_dip, ehcip->ehci_htable,
8829c75c6bfSgovinda 	    intr_type, 0, count, &actual, flag);
8837c478bd9Sstevel@tonic-gate 
8849c75c6bfSgovinda 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
8857c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8869c75c6bfSgovinda 		    "ehci_add_intrs: ddi_intr_alloc() failed %d", ret);
8877c478bd9Sstevel@tonic-gate 
8889c75c6bfSgovinda 		kmem_free(ehcip->ehci_htable, intr_size);
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8917c478bd9Sstevel@tonic-gate 	}
8927c478bd9Sstevel@tonic-gate 
8939c75c6bfSgovinda 	if (actual < count) {
8949c75c6bfSgovinda 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8959c75c6bfSgovinda 		    "ehci_add_intrs: Requested: %d, Received: %d\n",
8969c75c6bfSgovinda 		    count, actual);
8979c75c6bfSgovinda 
8989c75c6bfSgovinda 		for (i = 0; i < actual; i++)
8999c75c6bfSgovinda 			(void) ddi_intr_free(ehcip->ehci_htable[i]);
9009c75c6bfSgovinda 
9019c75c6bfSgovinda 		kmem_free(ehcip->ehci_htable, intr_size);
9029c75c6bfSgovinda 
9039c75c6bfSgovinda 		return (DDI_FAILURE);
9049c75c6bfSgovinda 	}
9057c478bd9Sstevel@tonic-gate 
9069c75c6bfSgovinda 	ehcip->ehci_intr_cnt = actual;
9079c75c6bfSgovinda 
9089c75c6bfSgovinda 	if ((ret = ddi_intr_get_pri(ehcip->ehci_htable[0],
9099c75c6bfSgovinda 	    &ehcip->ehci_intr_pri)) != DDI_SUCCESS) {
9107c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
9119c75c6bfSgovinda 		    "ehci_add_intrs: ddi_intr_get_pri() failed %d", ret);
9129c75c6bfSgovinda 
9139c75c6bfSgovinda 		for (i = 0; i < actual; i++)
9149c75c6bfSgovinda 			(void) ddi_intr_free(ehcip->ehci_htable[i]);
9157c478bd9Sstevel@tonic-gate 
9169c75c6bfSgovinda 		kmem_free(ehcip->ehci_htable, intr_size);
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9197c478bd9Sstevel@tonic-gate 	}
9207c478bd9Sstevel@tonic-gate 
9219c75c6bfSgovinda 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
9229c75c6bfSgovinda 	    "ehci_add_intrs: Supported Interrupt priority 0x%x",
9239c75c6bfSgovinda 	    ehcip->ehci_intr_pri);
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	/* Test for high level mutex */
9267c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_intr_pri >= ddi_intr_get_hilevel_pri()) {
9277c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
9289c75c6bfSgovinda 		    "ehci_add_intrs: Hi level interrupt not supported");
9299c75c6bfSgovinda 
9309c75c6bfSgovinda 		for (i = 0; i < actual; i++)
9319c75c6bfSgovinda 			(void) ddi_intr_free(ehcip->ehci_htable[i]);
9327c478bd9Sstevel@tonic-gate 
9339c75c6bfSgovinda 		kmem_free(ehcip->ehci_htable, intr_size);
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9367c478bd9Sstevel@tonic-gate 	}
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	/* Initialize the mutex */
9397c478bd9Sstevel@tonic-gate 	mutex_init(&ehcip->ehci_int_mutex, NULL, MUTEX_DRIVER,
940a195726fSgovinda 	    DDI_INTR_PRI(ehcip->ehci_intr_pri));
9417c478bd9Sstevel@tonic-gate 
9429c75c6bfSgovinda 	/* Call ddi_intr_add_handler() */
9439c75c6bfSgovinda 	for (i = 0; i < actual; i++) {
9449c75c6bfSgovinda 		if ((ret = ddi_intr_add_handler(ehcip->ehci_htable[i],
9459c75c6bfSgovinda 		    ehci_intr, (caddr_t)ehcip,
9469c75c6bfSgovinda 		    (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
9479c75c6bfSgovinda 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
9489c75c6bfSgovinda 			    "ehci_add_intrs:ddi_intr_add_handler() "
9499c75c6bfSgovinda 			    "failed %d", ret);
9507c478bd9Sstevel@tonic-gate 
9519c75c6bfSgovinda 			for (i = 0; i < actual; i++)
9529c75c6bfSgovinda 				(void) ddi_intr_free(ehcip->ehci_htable[i]);
9537c478bd9Sstevel@tonic-gate 
9549c75c6bfSgovinda 			mutex_destroy(&ehcip->ehci_int_mutex);
9559c75c6bfSgovinda 			kmem_free(ehcip->ehci_htable, intr_size);
9569c75c6bfSgovinda 
9579c75c6bfSgovinda 			return (DDI_FAILURE);
9589c75c6bfSgovinda 		}
9597c478bd9Sstevel@tonic-gate 	}
9607c478bd9Sstevel@tonic-gate 
9619c75c6bfSgovinda 	if ((ret = ddi_intr_get_cap(ehcip->ehci_htable[0],
9629c75c6bfSgovinda 	    &ehcip->ehci_intr_cap)) != DDI_SUCCESS) {
9637c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
9649c75c6bfSgovinda 		    "ehci_add_intrs: ddi_intr_get_cap() failed %d", ret);
9659c75c6bfSgovinda 
9669c75c6bfSgovinda 		for (i = 0; i < actual; i++) {
9679c75c6bfSgovinda 			(void) ddi_intr_remove_handler(ehcip->ehci_htable[i]);
9689c75c6bfSgovinda 			(void) ddi_intr_free(ehcip->ehci_htable[i]);
9699c75c6bfSgovinda 		}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 		mutex_destroy(&ehcip->ehci_int_mutex);
9729c75c6bfSgovinda 		kmem_free(ehcip->ehci_htable, intr_size);
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9757c478bd9Sstevel@tonic-gate 	}
9767c478bd9Sstevel@tonic-gate 
9779c75c6bfSgovinda 	/* Enable all interrupts */
9789c75c6bfSgovinda 	if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) {
9799c75c6bfSgovinda 		/* Call ddi_intr_block_enable() for MSI interrupts */
9809c75c6bfSgovinda 		(void) ddi_intr_block_enable(ehcip->ehci_htable,
9819c75c6bfSgovinda 		    ehcip->ehci_intr_cnt);
9829c75c6bfSgovinda 	} else {
9839c75c6bfSgovinda 		/* Call ddi_intr_enable for MSI or FIXED interrupts */
9849c75c6bfSgovinda 		for (i = 0; i < ehcip->ehci_intr_cnt; i++)
9859c75c6bfSgovinda 			(void) ddi_intr_enable(ehcip->ehci_htable[i]);
9869c75c6bfSgovinda 	}
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9897c478bd9Sstevel@tonic-gate }
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate /*
9933b00f311Syq  * ehci_init_hardware
9947c478bd9Sstevel@tonic-gate  *
9953b00f311Syq  * take control from BIOS, reset EHCI host controller, and check version, etc.
9967c478bd9Sstevel@tonic-gate  */
9977c478bd9Sstevel@tonic-gate int
9983b00f311Syq ehci_init_hardware(ehci_state_t	*ehcip)
9997c478bd9Sstevel@tonic-gate {
10007c478bd9Sstevel@tonic-gate 	int			revision;
10017c478bd9Sstevel@tonic-gate 	uint16_t		cmd_reg;
10027c478bd9Sstevel@tonic-gate 	int			abort_on_BIOS_take_over_failure;
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	/* Take control from the BIOS */
10057c478bd9Sstevel@tonic-gate 	if (ehci_take_control(ehcip) != USB_SUCCESS) {
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 		/* read .conf file properties */
10087c478bd9Sstevel@tonic-gate 		abort_on_BIOS_take_over_failure =
100929aca3ebSlc 		    ddi_prop_get_int(DDI_DEV_T_ANY,
101029aca3ebSlc 		    ehcip->ehci_dip, DDI_PROP_DONTPASS,
101129aca3ebSlc 		    "abort-on-BIOS-take-over-failure", 0);
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 		if (abort_on_BIOS_take_over_failure) {
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
10167c478bd9Sstevel@tonic-gate 			    "Unable to take control from BIOS.");
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
10197c478bd9Sstevel@tonic-gate 		}
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
10227c478bd9Sstevel@tonic-gate 		    "Unable to take control from BIOS. Failure is ignored.");
10237c478bd9Sstevel@tonic-gate 	}
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	/* set Memory Master Enable */
10267c478bd9Sstevel@tonic-gate 	cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM);
10277c478bd9Sstevel@tonic-gate 	cmd_reg |= (PCI_COMM_MAE | PCI_COMM_ME);
10287c478bd9Sstevel@tonic-gate 	pci_config_put16(ehcip->ehci_config_handle, PCI_CONF_COMM, cmd_reg);
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	/* Reset the EHCI host controller */
10317c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_command,
10327c478bd9Sstevel@tonic-gate 	    Get_OpReg(ehci_command) | EHCI_CMD_HOST_CTRL_RESET);
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 	/* Wait 10ms for reset to complete */
10357c478bd9Sstevel@tonic-gate 	drv_usecwait(EHCI_RESET_TIMEWAIT);
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	ASSERT(Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	/* Verify the version number */
10407c478bd9Sstevel@tonic-gate 	revision = Get_16Cap(ehci_version);
10417c478bd9Sstevel@tonic-gate 
10423b00f311Syq 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
10433b00f311Syq 	    "ehci_init_hardware: Revision 0x%x", revision);
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 	/*
10467c478bd9Sstevel@tonic-gate 	 * EHCI driver supports EHCI host controllers compliant to
10477c478bd9Sstevel@tonic-gate 	 * 0.95 and higher revisions of EHCI specifications.
10487c478bd9Sstevel@tonic-gate 	 */
10497c478bd9Sstevel@tonic-gate 	if (revision < EHCI_REVISION_0_95) {
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
10527c478bd9Sstevel@tonic-gate 		    "Revision 0x%x is not supported", revision);
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
10557c478bd9Sstevel@tonic-gate 	}
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_hc_soft_state == EHCI_CTLR_INIT_STATE) {
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 		/* Initialize the Frame list base address area */
10607c478bd9Sstevel@tonic-gate 		if (ehci_init_periodic_frame_lst_table(ehcip) != DDI_SUCCESS) {
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
10637c478bd9Sstevel@tonic-gate 		}
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 		/*
10667c478bd9Sstevel@tonic-gate 		 * For performance reasons, do not insert anything into the
10677c478bd9Sstevel@tonic-gate 		 * asynchronous list or activate the asynch list schedule until
10687c478bd9Sstevel@tonic-gate 		 * there is a valid QH.
10697c478bd9Sstevel@tonic-gate 		 */
10707c478bd9Sstevel@tonic-gate 		ehcip->ehci_head_of_async_sched_list = NULL;
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 		if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) &&
10737c478bd9Sstevel@tonic-gate 		    (ehci_vt62x2_workaround & EHCI_VIA_ASYNC_SCHEDULE)) {
10747c478bd9Sstevel@tonic-gate 			/*
10757c478bd9Sstevel@tonic-gate 			 * The driver is unable to reliably stop the asynch
10767c478bd9Sstevel@tonic-gate 			 * list schedule on VIA VT6202 controllers, so we
10777c478bd9Sstevel@tonic-gate 			 * always keep a dummy QH on the list.
10787c478bd9Sstevel@tonic-gate 			 */
10797c478bd9Sstevel@tonic-gate 			ehci_qh_t *dummy_async_qh =
10807c478bd9Sstevel@tonic-gate 			    ehci_alloc_qh(ehcip, NULL, NULL);
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 			Set_QH(dummy_async_qh->qh_link_ptr,
10837c478bd9Sstevel@tonic-gate 			    ((ehci_qh_cpu_to_iommu(ehcip, dummy_async_qh) &
10847c478bd9Sstevel@tonic-gate 			    EHCI_QH_LINK_PTR) | EHCI_QH_LINK_REF_QH));
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 			/* Set this QH to be the "head" of the circular list */
10877c478bd9Sstevel@tonic-gate 			Set_QH(dummy_async_qh->qh_ctrl,
10887c478bd9Sstevel@tonic-gate 			    Get_QH(dummy_async_qh->qh_ctrl) |
10897c478bd9Sstevel@tonic-gate 			    EHCI_QH_CTRL_RECLAIM_HEAD);
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 			Set_QH(dummy_async_qh->qh_next_qtd,
10927c478bd9Sstevel@tonic-gate 			    EHCI_QH_NEXT_QTD_PTR_VALID);
10937c478bd9Sstevel@tonic-gate 			Set_QH(dummy_async_qh->qh_alt_next_qtd,
10947c478bd9Sstevel@tonic-gate 			    EHCI_QH_ALT_NEXT_QTD_PTR_VALID);
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 			ehcip->ehci_head_of_async_sched_list = dummy_async_qh;
10977c478bd9Sstevel@tonic-gate 			ehcip->ehci_open_async_count++;
10987c478bd9Sstevel@tonic-gate 		}
10997c478bd9Sstevel@tonic-gate 	}
11007c478bd9Sstevel@tonic-gate 
11013b00f311Syq 	return (DDI_SUCCESS);
11023b00f311Syq }
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 
11053b00f311Syq /*
11063b00f311Syq  * ehci_init_workaround
11073b00f311Syq  *
11083b00f311Syq  * some workarounds during initializing ehci
11093b00f311Syq  */
11103b00f311Syq int
11113b00f311Syq ehci_init_workaround(ehci_state_t	*ehcip)
11123b00f311Syq {
11137c478bd9Sstevel@tonic-gate 	/*
11147c478bd9Sstevel@tonic-gate 	 * Acer Labs Inc. M5273 EHCI controller does not send
11157c478bd9Sstevel@tonic-gate 	 * interrupts unless the Root hub ports are routed to the EHCI
11167c478bd9Sstevel@tonic-gate 	 * host controller; so route the ports now, before we test for
11177c478bd9Sstevel@tonic-gate 	 * the presence of SOFs interrupts.
11187c478bd9Sstevel@tonic-gate 	 */
11197c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) {
112029aca3ebSlc 		/* Route all Root hub ports to EHCI host controller */
112129aca3ebSlc 		Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI);
11227c478bd9Sstevel@tonic-gate 	}
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate 	/*
11257c478bd9Sstevel@tonic-gate 	 * VIA chips have some issues and may not work reliably.
1126677739beShx 	 * Revisions >= 0x80 are part of a southbridge and appear
1127677739beShx 	 * to be reliable with the workaround.
11284610e4a0Sfrits 	 * For revisions < 0x80, if we	were bound using class
1129677739beShx 	 * complain, else proceed. This will allow the user to
1130677739beShx 	 * bind ehci specifically to this chip and not have the
1131677739beShx 	 * warnings
11327c478bd9Sstevel@tonic-gate 	 */
1133677739beShx 	if (ehcip->ehci_vendor_id == PCI_VENDOR_VIA) {
1134677739beShx 
113529aca3ebSlc 		if (ehcip->ehci_rev_id >= PCI_VIA_REVISION_6212) {
1136677739beShx 
1137fffe0b30Sqz 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1138fffe0b30Sqz 			    "ehci_init_workaround: Applying VIA workarounds "
1139fffe0b30Sqz 			    "for the 6212 chip.");
1140677739beShx 
114129aca3ebSlc 		} else if (strcmp(DEVI(ehcip->ehci_dip)->devi_binding_name,
1142fffe0b30Sqz 		    "pciclass,0c0320") == 0) {
1143677739beShx 
1144fffe0b30Sqz 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1145fffe0b30Sqz 			    "Due to recently discovered incompatibilities");
1146fffe0b30Sqz 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1147fffe0b30Sqz 			    "with this USB controller, USB2.x transfer");
1148fffe0b30Sqz 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1149fffe0b30Sqz 			    "support has been disabled. This device will");
1150fffe0b30Sqz 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1151fffe0b30Sqz 			    "continue to function as a USB1.x controller.");
1152fffe0b30Sqz 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1153fffe0b30Sqz 			    "If you are interested in enabling USB2.x");
1154fffe0b30Sqz 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1155fffe0b30Sqz 			    "support please, refer to the ehci(7D) man page.");
1156fffe0b30Sqz 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1157fffe0b30Sqz 			    "Please also refer to www.sun.com/io for");
1158fffe0b30Sqz 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1159fffe0b30Sqz 			    "Solaris Ready products and to");
1160fffe0b30Sqz 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1161fffe0b30Sqz 			    "www.sun.com/bigadmin/hcl for additional");
1162fffe0b30Sqz 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1163fffe0b30Sqz 			    "compatible USB products.");
11647c478bd9Sstevel@tonic-gate 
1165fffe0b30Sqz 			return (DDI_FAILURE);
1166677739beShx 
1167fffe0b30Sqz 			} else if (ehci_vt62x2_workaround) {
1168677739beShx 
1169fffe0b30Sqz 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1170fffe0b30Sqz 			    "Applying VIA workarounds");
117129aca3ebSlc 		}
11727c478bd9Sstevel@tonic-gate 	}
11737c478bd9Sstevel@tonic-gate 
11743b00f311Syq 	return (DDI_SUCCESS);
11753b00f311Syq }
11763b00f311Syq 
11773b00f311Syq 
11783b00f311Syq /*
11793b00f311Syq  * ehci_init_check_status
11803b00f311Syq  *
11813b00f311Syq  * Check if EHCI host controller is running
11823b00f311Syq  */
11833b00f311Syq int
11843b00f311Syq ehci_init_check_status(ehci_state_t	*ehcip)
11853b00f311Syq {
11863b00f311Syq 	clock_t			sof_time_wait;
11873b00f311Syq 
11887c478bd9Sstevel@tonic-gate 	/*
11897c478bd9Sstevel@tonic-gate 	 * Get the number of clock ticks to wait.
11907c478bd9Sstevel@tonic-gate 	 * This is based on the maximum time it takes for a frame list rollover
11917c478bd9Sstevel@tonic-gate 	 * and maximum time wait for SOFs to begin.
11927c478bd9Sstevel@tonic-gate 	 */
11937c478bd9Sstevel@tonic-gate 	sof_time_wait = drv_usectohz((EHCI_NUM_PERIODIC_FRAME_LISTS * 1000) +
11947c478bd9Sstevel@tonic-gate 	    EHCI_SOF_TIMEWAIT);
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 	/* Tell the ISR to broadcast ehci_async_schedule_advance_cv */
11977c478bd9Sstevel@tonic-gate 	ehcip->ehci_flags |= EHCI_CV_INTR;
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	/* We need to add a delay to allow the chip time to start running */
12007c478bd9Sstevel@tonic-gate 	(void) cv_timedwait(&ehcip->ehci_async_schedule_advance_cv,
12017c478bd9Sstevel@tonic-gate 	    &ehcip->ehci_int_mutex, ddi_get_lbolt() + sof_time_wait);
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 	/*
12047c478bd9Sstevel@tonic-gate 	 * Check EHCI host controller is running, otherwise return failure.
12057c478bd9Sstevel@tonic-gate 	 */
12067c478bd9Sstevel@tonic-gate 	if ((ehcip->ehci_flags & EHCI_CV_INTR) ||
12077c478bd9Sstevel@tonic-gate 	    (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) {
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
12107c478bd9Sstevel@tonic-gate 		    "No SOF interrupts have been received, this USB EHCI host"
12117c478bd9Sstevel@tonic-gate 		    "controller is unusable");
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 		/*
12147c478bd9Sstevel@tonic-gate 		 * Route all Root hub ports to Classic host
12157c478bd9Sstevel@tonic-gate 		 * controller, in case this is an unusable ALI M5273
12167c478bd9Sstevel@tonic-gate 		 * EHCI controller.
12177c478bd9Sstevel@tonic-gate 		 */
12187c478bd9Sstevel@tonic-gate 		if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) {
12197c478bd9Sstevel@tonic-gate 			Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC);
12207c478bd9Sstevel@tonic-gate 		}
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12237c478bd9Sstevel@tonic-gate 	}
12247c478bd9Sstevel@tonic-gate 
12253b00f311Syq 	return (DDI_SUCCESS);
12263b00f311Syq }
12273b00f311Syq 
12283b00f311Syq 
12293b00f311Syq /*
12303b00f311Syq  * ehci_init_ctlr:
12313b00f311Syq  *
12323b00f311Syq  * Initialize the Host Controller (HC).
12333b00f311Syq  */
12343b00f311Syq int
12353b00f311Syq ehci_init_ctlr(ehci_state_t	*ehcip,
12363b00f311Syq 		int		init_type)
12373b00f311Syq {
12383b00f311Syq 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_init_ctlr:");
12393b00f311Syq 
12403b00f311Syq 	if (init_type == EHCI_NORMAL_INITIALIZATION) {
12413b00f311Syq 
12423b00f311Syq 		if (ehci_init_hardware(ehcip) != DDI_SUCCESS) {
12433b00f311Syq 
12443b00f311Syq 			return (DDI_FAILURE);
12453b00f311Syq 		}
12463b00f311Syq 	}
12473b00f311Syq 
12483b00f311Syq 	/*
12493b00f311Syq 	 * Check for Asynchronous schedule park capability feature. If this
12503b00f311Syq 	 * feature is supported, then, program ehci command register with
12513b00f311Syq 	 * appropriate values..
12523b00f311Syq 	 */
12533b00f311Syq 	if (Get_Cap(ehci_hcc_params) & EHCI_HCC_ASYNC_SCHED_PARK_CAP) {
12543b00f311Syq 
12553b00f311Syq 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
12563b00f311Syq 		    "ehci_init_ctlr: Async park mode is supported");
12573b00f311Syq 
12583b00f311Syq 		Set_OpReg(ehci_command, (Get_OpReg(ehci_command) |
12593b00f311Syq 		    (EHCI_CMD_ASYNC_PARK_ENABLE |
12603b00f311Syq 		    EHCI_CMD_ASYNC_PARK_COUNT_3)));
12613b00f311Syq 	}
12623b00f311Syq 
12633b00f311Syq 	/*
12643b00f311Syq 	 * Check for programmable periodic frame list feature. If this
12653b00f311Syq 	 * feature is supported, then, program ehci command register with
12663b00f311Syq 	 * 1024 frame list value.
12673b00f311Syq 	 */
12683b00f311Syq 	if (Get_Cap(ehci_hcc_params) & EHCI_HCC_PROG_FRAME_LIST_FLAG) {
12693b00f311Syq 
12703b00f311Syq 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
12713b00f311Syq 		    "ehci_init_ctlr: Variable programmable periodic "
12723b00f311Syq 		    "frame list is supported");
12733b00f311Syq 
12743b00f311Syq 		Set_OpReg(ehci_command, (Get_OpReg(ehci_command) |
12753b00f311Syq 		    EHCI_CMD_FRAME_1024_SIZE));
12763b00f311Syq 	}
12773b00f311Syq 
12783b00f311Syq 	/*
12793b00f311Syq 	 * Currently EHCI driver doesn't support 64 bit addressing.
12803b00f311Syq 	 *
12813b00f311Syq 	 * If we are using 64 bit addressing capability, then, program
12823b00f311Syq 	 * ehci_ctrl_segment register with 4 Gigabyte segment where all
12833b00f311Syq 	 * of the interface data structures are allocated.
12843b00f311Syq 	 */
12853b00f311Syq 	if (Get_Cap(ehci_hcc_params) & EHCI_HCC_64BIT_ADDR_CAP) {
12863b00f311Syq 
12873b00f311Syq 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
12883b00f311Syq 		    "ehci_init_ctlr: EHCI driver doesn't support "
12893b00f311Syq 		    "64 bit addressing");
12903b00f311Syq 	}
12913b00f311Syq 
12923b00f311Syq 	/* 64 bit addressing is not support */
12933b00f311Syq 	Set_OpReg(ehci_ctrl_segment, 0x00000000);
12943b00f311Syq 
12953b00f311Syq 	/* Turn on/off the schedulers */
12963b00f311Syq 	ehci_toggle_scheduler(ehcip);
12973b00f311Syq 
1298fffe0b30Sqz 	/* Set host controller soft state to operational */
1299fffe0b30Sqz 	ehcip->ehci_hc_soft_state = EHCI_CTLR_OPERATIONAL_STATE;
1300fffe0b30Sqz 
13013b00f311Syq 	/*
13023b00f311Syq 	 * Set the Periodic Frame List Base Address register with the
13033b00f311Syq 	 * starting physical address of the Periodic Frame List.
13043b00f311Syq 	 */
13053b00f311Syq 	Set_OpReg(ehci_periodic_list_base,
13063b00f311Syq 	    (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address &
130729aca3ebSlc 	    EHCI_PERIODIC_LIST_BASE));
13083b00f311Syq 
13093b00f311Syq 	/*
13103b00f311Syq 	 * Set ehci_interrupt to enable all interrupts except Root
13113b00f311Syq 	 * Hub Status change interrupt.
13123b00f311Syq 	 */
13133b00f311Syq 	Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR |
13143b00f311Syq 	    EHCI_INTR_FRAME_LIST_ROLLOVER | EHCI_INTR_USB_ERROR |
13153b00f311Syq 	    EHCI_INTR_USB);
13163b00f311Syq 
13173b00f311Syq 	/*
13183b00f311Syq 	 * Set the desired interrupt threshold and turn on EHCI host controller.
13193b00f311Syq 	 */
13203b00f311Syq 	Set_OpReg(ehci_command,
13213b00f311Syq 	    ((Get_OpReg(ehci_command) & ~EHCI_CMD_INTR_THRESHOLD) |
132229aca3ebSlc 	    (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN)));
13233b00f311Syq 
13243b00f311Syq 	ASSERT(Get_OpReg(ehci_command) & EHCI_CMD_HOST_CTRL_RUN);
13253b00f311Syq 
13263b00f311Syq 	if (init_type == EHCI_NORMAL_INITIALIZATION) {
13273b00f311Syq 
13283b00f311Syq 		if (ehci_init_workaround(ehcip) != DDI_SUCCESS) {
13293b00f311Syq 
1330fffe0b30Sqz 			/* Set host controller soft state to error */
1331fffe0b30Sqz 			ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE;
1332fffe0b30Sqz 
13333b00f311Syq 			return (DDI_FAILURE);
13343b00f311Syq 		}
13353b00f311Syq 
13363b00f311Syq 		if (ehci_init_check_status(ehcip) != DDI_SUCCESS) {
13373b00f311Syq 
1338fffe0b30Sqz 			/* Set host controller soft state to error */
1339fffe0b30Sqz 			ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE;
1340fffe0b30Sqz 
13413b00f311Syq 			return (DDI_FAILURE);
13423b00f311Syq 		}
13433b00f311Syq 
13443b00f311Syq 		USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
13453b00f311Syq 		    "ehci_init_ctlr: SOF's have started");
13463b00f311Syq 	}
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	/* Route all Root hub ports to EHCI host controller */
13497c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI);
13507c478bd9Sstevel@tonic-gate 
13517c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
13527c478bd9Sstevel@tonic-gate }
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate /*
13557c478bd9Sstevel@tonic-gate  * ehci_take_control:
13567c478bd9Sstevel@tonic-gate  *
13577c478bd9Sstevel@tonic-gate  * Handshake to take EHCI control from BIOS if necessary.  Its only valid for
13587c478bd9Sstevel@tonic-gate  * x86 machines, because sparc doesn't have a BIOS.
13597c478bd9Sstevel@tonic-gate  * On x86 machine, the take control process includes
13607c478bd9Sstevel@tonic-gate  *    o get the base address of the extended capability list
13617c478bd9Sstevel@tonic-gate  *    o find out the capability for handoff synchronization in the list.
13627c478bd9Sstevel@tonic-gate  *    o check if BIOS has owned the host controller.
13637c478bd9Sstevel@tonic-gate  *    o set the OS Owned semaphore bit, ask the BIOS to release the ownership.
13647c478bd9Sstevel@tonic-gate  *    o wait for a constant time and check if BIOS has relinquished control.
13657c478bd9Sstevel@tonic-gate  */
13667c478bd9Sstevel@tonic-gate /* ARGSUSED */
13677c478bd9Sstevel@tonic-gate static int
13687c478bd9Sstevel@tonic-gate ehci_take_control(ehci_state_t *ehcip)
13697c478bd9Sstevel@tonic-gate {
13707c478bd9Sstevel@tonic-gate #if defined(__x86)
13717c478bd9Sstevel@tonic-gate 	uint32_t		extended_cap;
13727c478bd9Sstevel@tonic-gate 	uint32_t		extended_cap_offset;
13737c478bd9Sstevel@tonic-gate 	uint32_t		extended_cap_id;
13747c478bd9Sstevel@tonic-gate 	uint_t			retry;
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
13777c478bd9Sstevel@tonic-gate 	    "ehci_take_control:");
13787c478bd9Sstevel@tonic-gate 
13797c478bd9Sstevel@tonic-gate 	/*
13807c478bd9Sstevel@tonic-gate 	 * According EHCI Spec 2.2.4, get EECP base address from HCCPARAMS
13817c478bd9Sstevel@tonic-gate 	 * register.
13827c478bd9Sstevel@tonic-gate 	 */
13837c478bd9Sstevel@tonic-gate 	extended_cap_offset = (Get_Cap(ehci_hcc_params) & EHCI_HCC_EECP) >>
13847c478bd9Sstevel@tonic-gate 	    EHCI_HCC_EECP_SHIFT;
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	/*
13877c478bd9Sstevel@tonic-gate 	 * According EHCI Spec 2.2.4, if the extended capability offset is
13887c478bd9Sstevel@tonic-gate 	 * less than 40h then its not valid.  This means we don't need to
13897c478bd9Sstevel@tonic-gate 	 * worry about BIOS handoff.
13907c478bd9Sstevel@tonic-gate 	 */
13917c478bd9Sstevel@tonic-gate 	if (extended_cap_offset < EHCI_HCC_EECP_MIN_OFFSET) {
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
13947c478bd9Sstevel@tonic-gate 		    "ehci_take_control: Hardware doesn't support legacy.");
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 		goto success;
13977c478bd9Sstevel@tonic-gate 	}
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 	/*
14007c478bd9Sstevel@tonic-gate 	 * According EHCI Spec 2.1.7, A zero offset indicates the
14017c478bd9Sstevel@tonic-gate 	 * end of the extended capability list.
14027c478bd9Sstevel@tonic-gate 	 */
14037c478bd9Sstevel@tonic-gate 	while (extended_cap_offset) {
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 		/* Get the extended capability value. */
14067c478bd9Sstevel@tonic-gate 		extended_cap = pci_config_get32(ehcip->ehci_config_handle,
14077c478bd9Sstevel@tonic-gate 		    extended_cap_offset);
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 		/* Get the capability ID */
14107c478bd9Sstevel@tonic-gate 		extended_cap_id = (extended_cap & EHCI_EX_CAP_ID) >>
14117c478bd9Sstevel@tonic-gate 		    EHCI_EX_CAP_ID_SHIFT;
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 		/* Check if the card support legacy */
14147c478bd9Sstevel@tonic-gate 		if (extended_cap_id == EHCI_EX_CAP_ID_BIOS_HANDOFF) {
14157c478bd9Sstevel@tonic-gate 			break;
14167c478bd9Sstevel@tonic-gate 		}
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 		/* Get the offset of the next capability */
14197c478bd9Sstevel@tonic-gate 		extended_cap_offset = (extended_cap & EHCI_EX_CAP_NEXT_PTR) >>
14207c478bd9Sstevel@tonic-gate 		    EHCI_EX_CAP_NEXT_PTR_SHIFT;
14217c478bd9Sstevel@tonic-gate 	}
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	/*
14247c478bd9Sstevel@tonic-gate 	 * Unable to find legacy support in hardware's extended capability list.
14257c478bd9Sstevel@tonic-gate 	 * This means we don't need to worry about BIOS handoff.
14267c478bd9Sstevel@tonic-gate 	 */
14277c478bd9Sstevel@tonic-gate 	if (extended_cap_id != EHCI_EX_CAP_ID_BIOS_HANDOFF) {
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
14307c478bd9Sstevel@tonic-gate 		    "ehci_take_control: Hardware doesn't support legacy");
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate 		goto success;
14337c478bd9Sstevel@tonic-gate 	}
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 	/* Check if BIOS has owned it. */
14367c478bd9Sstevel@tonic-gate 	if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) {
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
14397c478bd9Sstevel@tonic-gate 		    "ehci_take_control: BIOS does not own EHCI");
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 		goto success;
14427c478bd9Sstevel@tonic-gate 	}
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	/*
14457c478bd9Sstevel@tonic-gate 	 * According EHCI Spec 5.1, The OS driver initiates an ownership
14467c478bd9Sstevel@tonic-gate 	 * request by setting the OS Owned semaphore to a one. The OS
14477c478bd9Sstevel@tonic-gate 	 * waits for the BIOS Owned bit to go to a zero before attempting
14487c478bd9Sstevel@tonic-gate 	 * to use the EHCI controller. The time that OS must wait for BIOS
14497c478bd9Sstevel@tonic-gate 	 * to respond to the request for ownership is beyond the scope of
14507c478bd9Sstevel@tonic-gate 	 * this specification.
14517c478bd9Sstevel@tonic-gate 	 * It waits up to EHCI_TAKEOVER_WAIT_COUNT*EHCI_TAKEOVER_DELAY ms
14527c478bd9Sstevel@tonic-gate 	 * for BIOS to release the ownership.
14537c478bd9Sstevel@tonic-gate 	 */
14547c478bd9Sstevel@tonic-gate 	extended_cap |= EHCI_LEGSUP_OS_OWNED_SEM;
14557c478bd9Sstevel@tonic-gate 	pci_config_put32(ehcip->ehci_config_handle, extended_cap_offset,
14567c478bd9Sstevel@tonic-gate 	    extended_cap);
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate 	for (retry = 0; retry < EHCI_TAKEOVER_WAIT_COUNT; retry++) {
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 		/* wait a special interval */
14614ebb14b2Sfrits #ifndef __lock_lint
14627c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(EHCI_TAKEOVER_DELAY));
14634ebb14b2Sfrits #endif
14647c478bd9Sstevel@tonic-gate 		/* Check to see if the BIOS has released the ownership */
14657c478bd9Sstevel@tonic-gate 		extended_cap = pci_config_get32(
14667c478bd9Sstevel@tonic-gate 		    ehcip->ehci_config_handle, extended_cap_offset);
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 		if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) {
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ATTA,
14717c478bd9Sstevel@tonic-gate 			    ehcip->ehci_log_hdl,
14727c478bd9Sstevel@tonic-gate 			    "ehci_take_control: BIOS has released "
14737c478bd9Sstevel@tonic-gate 			    "the ownership. retry = %d", retry);
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 			goto success;
14767c478bd9Sstevel@tonic-gate 		}
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 	}
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
14817c478bd9Sstevel@tonic-gate 	    "ehci_take_control: take control from BIOS failed.");
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate success:
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate #endif	/* __x86 */
14887c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
14897c478bd9Sstevel@tonic-gate }
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate /*
14937c478bd9Sstevel@tonic-gate  * ehci_init_periodic_frame_list_table :
14947c478bd9Sstevel@tonic-gate  *
14957c478bd9Sstevel@tonic-gate  * Allocate the system memory and initialize Host Controller
14967c478bd9Sstevel@tonic-gate  * Periodic Frame List table area. The starting of the Periodic
14977c478bd9Sstevel@tonic-gate  * Frame List Table area must be 4096 byte aligned.
14987c478bd9Sstevel@tonic-gate  */
14997c478bd9Sstevel@tonic-gate static int
15007c478bd9Sstevel@tonic-gate ehci_init_periodic_frame_lst_table(ehci_state_t *ehcip)
15017c478bd9Sstevel@tonic-gate {
15027c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t	dev_attr;
15037c478bd9Sstevel@tonic-gate 	size_t			real_length;
15047c478bd9Sstevel@tonic-gate 	uint_t			ccount;
15057c478bd9Sstevel@tonic-gate 	int			result;
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
15107c478bd9Sstevel@tonic-gate 	    "ehci_init_periodic_frame_lst_table:");
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate 	/* The host controller will be little endian */
15137c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
15147c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
15157c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 	/* Force the required 4K restrictive alignment */
15187c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_PFL_ALIGNMENT;
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 	/* Create space for the Periodic Frame List */
15217c478bd9Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr,
15227c478bd9Sstevel@tonic-gate 	    DDI_DMA_SLEEP, 0, &ehcip->ehci_pflt_dma_handle) != DDI_SUCCESS) {
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 		goto failure;
15257c478bd9Sstevel@tonic-gate 	}
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(ehcip->ehci_pflt_dma_handle,
15287c478bd9Sstevel@tonic-gate 	    sizeof (ehci_periodic_frame_list_t),
15297c478bd9Sstevel@tonic-gate 	    &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
15307c478bd9Sstevel@tonic-gate 	    0, (caddr_t *)&ehcip->ehci_periodic_frame_list_tablep,
15317c478bd9Sstevel@tonic-gate 	    &real_length, &ehcip->ehci_pflt_mem_handle)) {
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 		goto failure;
15347c478bd9Sstevel@tonic-gate 	}
15357c478bd9Sstevel@tonic-gate 
15363b00f311Syq 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
15377c478bd9Sstevel@tonic-gate 	    "ehci_init_periodic_frame_lst_table: "
15387c478bd9Sstevel@tonic-gate 	    "Real length %lu", real_length);
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate 	/* Map the whole Periodic Frame List into the I/O address space */
15417c478bd9Sstevel@tonic-gate 	result = ddi_dma_addr_bind_handle(ehcip->ehci_pflt_dma_handle,
15427c478bd9Sstevel@tonic-gate 	    NULL, (caddr_t)ehcip->ehci_periodic_frame_list_tablep,
15437c478bd9Sstevel@tonic-gate 	    real_length, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
15447c478bd9Sstevel@tonic-gate 	    DDI_DMA_SLEEP, NULL, &ehcip->ehci_pflt_cookie, &ccount);
15457c478bd9Sstevel@tonic-gate 
15467c478bd9Sstevel@tonic-gate 	if (result == DDI_DMA_MAPPED) {
15477c478bd9Sstevel@tonic-gate 		/* The cookie count should be 1 */
15487c478bd9Sstevel@tonic-gate 		if (ccount != 1) {
15497c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
15507c478bd9Sstevel@tonic-gate 			    "ehci_init_periodic_frame_lst_table: "
15517c478bd9Sstevel@tonic-gate 			    "More than 1 cookie");
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 			goto failure;
15547c478bd9Sstevel@tonic-gate 		}
15557c478bd9Sstevel@tonic-gate 	} else {
15567c478bd9Sstevel@tonic-gate 		ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 		goto failure;
15597c478bd9Sstevel@tonic-gate 	}
15607c478bd9Sstevel@tonic-gate 
15617c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
15627c478bd9Sstevel@tonic-gate 	    "ehci_init_periodic_frame_lst_table: virtual 0x%p physical 0x%x",
15637c478bd9Sstevel@tonic-gate 	    (void *)ehcip->ehci_periodic_frame_list_tablep,
15647c478bd9Sstevel@tonic-gate 	    ehcip->ehci_pflt_cookie.dmac_address);
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate 	/*
15677c478bd9Sstevel@tonic-gate 	 * DMA addresses for Periodic Frame List are bound.
15687c478bd9Sstevel@tonic-gate 	 */
15697c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_addr_bind_flag |= EHCI_PFLT_DMA_BOUND;
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate 	bzero((void *)ehcip->ehci_periodic_frame_list_tablep, real_length);
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 	/* Initialize the Periodic Frame List */
15747c478bd9Sstevel@tonic-gate 	ehci_build_interrupt_lattice(ehcip);
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 	/* Reset Byte Alignment to Default */
15777c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
15807c478bd9Sstevel@tonic-gate failure:
15817c478bd9Sstevel@tonic-gate 	/* Byte alignment */
15827c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
15837c478bd9Sstevel@tonic-gate 
15847c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
15857c478bd9Sstevel@tonic-gate }
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate /*
15897c478bd9Sstevel@tonic-gate  * ehci_build_interrupt_lattice:
15907c478bd9Sstevel@tonic-gate  *
15917c478bd9Sstevel@tonic-gate  * Construct the interrupt lattice tree using static Endpoint Descriptors
15927c478bd9Sstevel@tonic-gate  * (QH). This interrupt lattice tree will have total of 32 interrupt  QH
15937c478bd9Sstevel@tonic-gate  * lists and the Host Controller (HC) processes one interrupt QH list in
15947c478bd9Sstevel@tonic-gate  * every frame. The Host Controller traverses the periodic schedule by
15957c478bd9Sstevel@tonic-gate  * constructing an array offset reference from the Periodic List Base Address
15967c478bd9Sstevel@tonic-gate  * register and bits 12 to 3 of Frame Index register. It fetches the element
15977c478bd9Sstevel@tonic-gate  * and begins traversing the graph of linked schedule data structures.
15987c478bd9Sstevel@tonic-gate  */
15997c478bd9Sstevel@tonic-gate static void
16007c478bd9Sstevel@tonic-gate ehci_build_interrupt_lattice(ehci_state_t	*ehcip)
16017c478bd9Sstevel@tonic-gate {
16027c478bd9Sstevel@tonic-gate 	ehci_qh_t	*list_array = ehcip->ehci_qh_pool_addr;
16037c478bd9Sstevel@tonic-gate 	ushort_t	ehci_index[EHCI_NUM_PERIODIC_FRAME_LISTS];
16047c478bd9Sstevel@tonic-gate 	ehci_periodic_frame_list_t *periodic_frame_list =
160529aca3ebSlc 	    ehcip->ehci_periodic_frame_list_tablep;
16067c478bd9Sstevel@tonic-gate 	ushort_t	*temp, num_of_nodes;
16077c478bd9Sstevel@tonic-gate 	uintptr_t	addr;
16087c478bd9Sstevel@tonic-gate 	int		i, j, k;
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
16117c478bd9Sstevel@tonic-gate 	    "ehci_build_interrupt_lattice:");
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 	/*
16147c478bd9Sstevel@tonic-gate 	 * Reserve the first 63 Endpoint Descriptor (QH) structures
16157c478bd9Sstevel@tonic-gate 	 * in the pool as static endpoints & these are required for
16167c478bd9Sstevel@tonic-gate 	 * constructing interrupt lattice tree.
16177c478bd9Sstevel@tonic-gate 	 */
16187c478bd9Sstevel@tonic-gate 	for (i = 0; i < EHCI_NUM_STATIC_NODES; i++) {
16197c478bd9Sstevel@tonic-gate 		Set_QH(list_array[i].qh_state, EHCI_QH_STATIC);
16207c478bd9Sstevel@tonic-gate 		Set_QH(list_array[i].qh_status, EHCI_QH_STS_HALTED);
16217c478bd9Sstevel@tonic-gate 		Set_QH(list_array[i].qh_next_qtd, EHCI_QH_NEXT_QTD_PTR_VALID);
16227c478bd9Sstevel@tonic-gate 		Set_QH(list_array[i].qh_alt_next_qtd,
16237c478bd9Sstevel@tonic-gate 		    EHCI_QH_ALT_NEXT_QTD_PTR_VALID);
16247c478bd9Sstevel@tonic-gate 	}
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 	/*
16277c478bd9Sstevel@tonic-gate 	 * Make sure that last Endpoint on the periodic frame list terminates
16287c478bd9Sstevel@tonic-gate 	 * periodic schedule.
16297c478bd9Sstevel@tonic-gate 	 */
16307c478bd9Sstevel@tonic-gate 	Set_QH(list_array[0].qh_link_ptr, EHCI_QH_LINK_PTR_VALID);
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate 	/* Build the interrupt lattice tree */
16337c478bd9Sstevel@tonic-gate 	for (i = 0; i < (EHCI_NUM_STATIC_NODES / 2); i++) {
16347c478bd9Sstevel@tonic-gate 		/*
16357c478bd9Sstevel@tonic-gate 		 * The next  pointer in the host controller  endpoint
16367c478bd9Sstevel@tonic-gate 		 * descriptor must contain an iommu address. Calculate
16377c478bd9Sstevel@tonic-gate 		 * the offset into the cpu address and add this to the
16387c478bd9Sstevel@tonic-gate 		 * starting iommu address.
16397c478bd9Sstevel@tonic-gate 		 */
16407c478bd9Sstevel@tonic-gate 		addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *)&list_array[i]);
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 		Set_QH(list_array[2*i + 1].qh_link_ptr,
16437c478bd9Sstevel@tonic-gate 		    addr | EHCI_QH_LINK_REF_QH);
16447c478bd9Sstevel@tonic-gate 		Set_QH(list_array[2*i + 2].qh_link_ptr,
16457c478bd9Sstevel@tonic-gate 		    addr | EHCI_QH_LINK_REF_QH);
16467c478bd9Sstevel@tonic-gate 	}
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate 	/* Build the tree bottom */
16497c478bd9Sstevel@tonic-gate 	temp = (unsigned short *)
16507c478bd9Sstevel@tonic-gate 	    kmem_zalloc(EHCI_NUM_PERIODIC_FRAME_LISTS * 2, KM_SLEEP);
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate 	num_of_nodes = 1;
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 	/*
16557c478bd9Sstevel@tonic-gate 	 * Initialize the values which are used for setting up head pointers
16567c478bd9Sstevel@tonic-gate 	 * for the 32ms scheduling lists which starts from the Periodic Frame
16577c478bd9Sstevel@tonic-gate 	 * List.
16587c478bd9Sstevel@tonic-gate 	 */
16597c478bd9Sstevel@tonic-gate 	for (i = 0; i < ehci_log_2(EHCI_NUM_PERIODIC_FRAME_LISTS); i++) {
16607c478bd9Sstevel@tonic-gate 		for (j = 0, k = 0; k < num_of_nodes; k++, j++) {
16617c478bd9Sstevel@tonic-gate 			ehci_index[j++] = temp[k];
16627c478bd9Sstevel@tonic-gate 			ehci_index[j]	= temp[k] + ehci_pow_2(i);
16637c478bd9Sstevel@tonic-gate 		}
16647c478bd9Sstevel@tonic-gate 
16657c478bd9Sstevel@tonic-gate 		num_of_nodes *= 2;
16667c478bd9Sstevel@tonic-gate 		for (k = 0; k < num_of_nodes; k++)
16677c478bd9Sstevel@tonic-gate 			temp[k] = ehci_index[k];
16687c478bd9Sstevel@tonic-gate 	}
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	kmem_free((void *)temp, (EHCI_NUM_PERIODIC_FRAME_LISTS * 2));
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 	/*
16737c478bd9Sstevel@tonic-gate 	 * Initialize the interrupt list in the Periodic Frame List Table
16747c478bd9Sstevel@tonic-gate 	 * so that it points to the bottom of the tree.
16757c478bd9Sstevel@tonic-gate 	 */
16767c478bd9Sstevel@tonic-gate 	for (i = 0, j = 0; i < ehci_pow_2(TREE_HEIGHT); i++) {
16777c478bd9Sstevel@tonic-gate 		addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *)
16787c478bd9Sstevel@tonic-gate 		    (&list_array[((EHCI_NUM_STATIC_NODES + 1) / 2) + i - 1]));
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 		ASSERT(addr);
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 		for (k = 0; k < ehci_pow_2(TREE_HEIGHT); k++) {
16837c478bd9Sstevel@tonic-gate 			Set_PFLT(periodic_frame_list->
16847c478bd9Sstevel@tonic-gate 			    ehci_periodic_frame_list_table[ehci_index[j++]],
16857c478bd9Sstevel@tonic-gate 			    (uint32_t)(addr | EHCI_QH_LINK_REF_QH));
16867c478bd9Sstevel@tonic-gate 		}
16877c478bd9Sstevel@tonic-gate 	}
16887c478bd9Sstevel@tonic-gate }
16897c478bd9Sstevel@tonic-gate 
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate /*
16927c478bd9Sstevel@tonic-gate  * ehci_alloc_hcdi_ops:
16937c478bd9Sstevel@tonic-gate  *
16947c478bd9Sstevel@tonic-gate  * The HCDI interfaces or entry points are the software interfaces used by
16957c478bd9Sstevel@tonic-gate  * the Universal Serial Bus Driver  (USBA) to  access the services of the
16967c478bd9Sstevel@tonic-gate  * Host Controller Driver (HCD).  During HCD initialization, inform  USBA
16977c478bd9Sstevel@tonic-gate  * about all available HCDI interfaces or entry points.
16987c478bd9Sstevel@tonic-gate  */
16997c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *
17007c478bd9Sstevel@tonic-gate ehci_alloc_hcdi_ops(ehci_state_t	*ehcip)
17017c478bd9Sstevel@tonic-gate {
17027c478bd9Sstevel@tonic-gate 	usba_hcdi_ops_t			*usba_hcdi_ops;
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
17057c478bd9Sstevel@tonic-gate 	    "ehci_alloc_hcdi_ops:");
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate 	usba_hcdi_ops = usba_alloc_hcdi_ops();
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_ops_version = HCDI_OPS_VERSION;
17107c478bd9Sstevel@tonic-gate 
17114610e4a0Sfrits 	usba_hcdi_ops->usba_hcdi_pm_support = ehci_hcdi_pm_support;
17127c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_open = ehci_hcdi_pipe_open;
17137c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_close = ehci_hcdi_pipe_close;
17147c478bd9Sstevel@tonic-gate 
17157c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_reset = ehci_hcdi_pipe_reset;
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_ctrl_xfer = ehci_hcdi_pipe_ctrl_xfer;
17187c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_bulk_xfer = ehci_hcdi_pipe_bulk_xfer;
17197c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_intr_xfer = ehci_hcdi_pipe_intr_xfer;
17207c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_isoc_xfer = ehci_hcdi_pipe_isoc_xfer;
17217c478bd9Sstevel@tonic-gate 
17227c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_bulk_transfer_size =
172329aca3ebSlc 	    ehci_hcdi_bulk_transfer_size;
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_stop_intr_polling =
172629aca3ebSlc 	    ehci_hcdi_pipe_stop_intr_polling;
17277c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_stop_isoc_polling =
172829aca3ebSlc 	    ehci_hcdi_pipe_stop_isoc_polling;
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_get_current_frame_number =
173129aca3ebSlc 	    ehci_hcdi_get_current_frame_number;
17327c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_get_max_isoc_pkts =
173329aca3ebSlc 	    ehci_hcdi_get_max_isoc_pkts;
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_console_input_init =
173629aca3ebSlc 	    ehci_hcdi_polled_input_init;
17377c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_console_input_enter =
173829aca3ebSlc 	    ehci_hcdi_polled_input_enter;
17397c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_console_read =
174029aca3ebSlc 	    ehci_hcdi_polled_read;
17417c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_console_input_exit =
174229aca3ebSlc 	    ehci_hcdi_polled_input_exit;
17437c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_console_input_fini =
174429aca3ebSlc 	    ehci_hcdi_polled_input_fini;
17457c478bd9Sstevel@tonic-gate 	return (usba_hcdi_ops);
17467c478bd9Sstevel@tonic-gate }
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate /*
17507c478bd9Sstevel@tonic-gate  * Host Controller Driver (HCD) deinitialization functions
17517c478bd9Sstevel@tonic-gate  */
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate /*
17547c478bd9Sstevel@tonic-gate  * ehci_cleanup:
17557c478bd9Sstevel@tonic-gate  *
17567c478bd9Sstevel@tonic-gate  * Cleanup on attach failure or detach
17577c478bd9Sstevel@tonic-gate  */
17587c478bd9Sstevel@tonic-gate int
17597c478bd9Sstevel@tonic-gate ehci_cleanup(ehci_state_t	*ehcip)
17607c478bd9Sstevel@tonic-gate {
17617c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
17627c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
17637c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd;
17647c478bd9Sstevel@tonic-gate 	int			i, ctrl, rval;
17657c478bd9Sstevel@tonic-gate 	int			flags = ehcip->ehci_flags;
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_cleanup:");
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 	if (flags & EHCI_RHREG) {
17707c478bd9Sstevel@tonic-gate 		/* Unload the root hub driver */
17717c478bd9Sstevel@tonic-gate 		if (ehci_unload_root_hub_driver(ehcip) != USB_SUCCESS) {
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
17747c478bd9Sstevel@tonic-gate 		}
17757c478bd9Sstevel@tonic-gate 	}
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 	if (flags & EHCI_USBAREG) {
17787c478bd9Sstevel@tonic-gate 		/* Unregister this HCD instance with USBA */
17797c478bd9Sstevel@tonic-gate 		usba_hcdi_unregister(ehcip->ehci_dip);
17807c478bd9Sstevel@tonic-gate 	}
17817c478bd9Sstevel@tonic-gate 
17827c478bd9Sstevel@tonic-gate 	if (flags & EHCI_INTR) {
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 		mutex_enter(&ehcip->ehci_int_mutex);
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate 		/* Disable all EHCI QH list processing */
17877c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_command, (Get_OpReg(ehci_command) &
17887c478bd9Sstevel@tonic-gate 		    ~(EHCI_CMD_ASYNC_SCHED_ENABLE |
17897c478bd9Sstevel@tonic-gate 		    EHCI_CMD_PERIODIC_SCHED_ENABLE)));
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 		/* Disable all EHCI interrupts */
17927c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_interrupt, 0);
17937c478bd9Sstevel@tonic-gate 
17947c478bd9Sstevel@tonic-gate 		/* wait for the next SOF */
17957c478bd9Sstevel@tonic-gate 		(void) ehci_wait_for_sof(ehcip);
17967c478bd9Sstevel@tonic-gate 
17974610e4a0Sfrits 		/* Route all Root hub ports to Classic host controller */
17984610e4a0Sfrits 		Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC);
17994610e4a0Sfrits 
18007c478bd9Sstevel@tonic-gate 		/* Stop the EHCI host controller */
18017c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_command,
18027c478bd9Sstevel@tonic-gate 		    Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN);
18037c478bd9Sstevel@tonic-gate 
18047c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
18057c478bd9Sstevel@tonic-gate 
180629aca3ebSlc 		/* Wait for sometime */
180729aca3ebSlc 		delay(drv_usectohz(EHCI_TIMEWAIT));
180829aca3ebSlc 
18099c75c6bfSgovinda 		ehci_rem_intrs(ehcip);
18107c478bd9Sstevel@tonic-gate 	}
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 	/* Unmap the EHCI registers */
18137c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_caps_handle) {
18147c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&ehcip->ehci_caps_handle);
18157c478bd9Sstevel@tonic-gate 	}
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_config_handle) {
18187c478bd9Sstevel@tonic-gate 		pci_config_teardown(&ehcip->ehci_config_handle);
18197c478bd9Sstevel@tonic-gate 	}
18207c478bd9Sstevel@tonic-gate 
18217c478bd9Sstevel@tonic-gate 	/* Free all the buffers */
18227c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_qtd_pool_addr && ehcip->ehci_qtd_pool_mem_handle) {
18237c478bd9Sstevel@tonic-gate 		for (i = 0; i < ehci_qtd_pool_size; i ++) {
18247c478bd9Sstevel@tonic-gate 			qtd = &ehcip->ehci_qtd_pool_addr[i];
18257c478bd9Sstevel@tonic-gate 			ctrl = Get_QTD(ehcip->
18267c478bd9Sstevel@tonic-gate 			    ehci_qtd_pool_addr[i].qtd_state);
18277c478bd9Sstevel@tonic-gate 
18287c478bd9Sstevel@tonic-gate 			if ((ctrl != EHCI_QTD_FREE) &&
18297c478bd9Sstevel@tonic-gate 			    (ctrl != EHCI_QTD_DUMMY) &&
18307c478bd9Sstevel@tonic-gate 			    (qtd->qtd_trans_wrapper)) {
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate 				mutex_enter(&ehcip->ehci_int_mutex);
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate 				tw = (ehci_trans_wrapper_t *)
183529aca3ebSlc 				    EHCI_LOOKUP_ID((uint32_t)
183629aca3ebSlc 				    Get_QTD(qtd->qtd_trans_wrapper));
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 				/* Obtain the pipe private structure */
18397c478bd9Sstevel@tonic-gate 				pp = tw->tw_pipe_private;
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 				/* Stop the the transfer timer */
18427c478bd9Sstevel@tonic-gate 				ehci_stop_xfer_timer(ehcip, tw,
184329aca3ebSlc 				    EHCI_REMOVE_XFER_ALWAYS);
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate 				ehci_deallocate_tw(ehcip, pp, tw);
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 				mutex_exit(&ehcip->ehci_int_mutex);
18487c478bd9Sstevel@tonic-gate 			}
18497c478bd9Sstevel@tonic-gate 		}
18507c478bd9Sstevel@tonic-gate 
18517c478bd9Sstevel@tonic-gate 		/*
18527c478bd9Sstevel@tonic-gate 		 * If EHCI_QTD_POOL_BOUND flag is set, then unbind
18537c478bd9Sstevel@tonic-gate 		 * the handle for QTD pools.
18547c478bd9Sstevel@tonic-gate 		 */
18557c478bd9Sstevel@tonic-gate 		if ((ehcip->ehci_dma_addr_bind_flag &
18567c478bd9Sstevel@tonic-gate 		    EHCI_QTD_POOL_BOUND) == EHCI_QTD_POOL_BOUND) {
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 			rval = ddi_dma_unbind_handle(
18597c478bd9Sstevel@tonic-gate 			    ehcip->ehci_qtd_pool_dma_handle);
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
18627c478bd9Sstevel@tonic-gate 		}
18637c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&ehcip->ehci_qtd_pool_mem_handle);
18647c478bd9Sstevel@tonic-gate 	}
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate 	/* Free the QTD pool */
18677c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_qtd_pool_dma_handle) {
18687c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&ehcip->ehci_qtd_pool_dma_handle);
18697c478bd9Sstevel@tonic-gate 	}
18707c478bd9Sstevel@tonic-gate 
18717c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_qh_pool_addr && ehcip->ehci_qh_pool_mem_handle) {
18727c478bd9Sstevel@tonic-gate 		/*
18737c478bd9Sstevel@tonic-gate 		 * If EHCI_QH_POOL_BOUND flag is set, then unbind
18747c478bd9Sstevel@tonic-gate 		 * the handle for QH pools.
18757c478bd9Sstevel@tonic-gate 		 */
18767c478bd9Sstevel@tonic-gate 		if ((ehcip->ehci_dma_addr_bind_flag &
18777c478bd9Sstevel@tonic-gate 		    EHCI_QH_POOL_BOUND) == EHCI_QH_POOL_BOUND) {
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 			rval = ddi_dma_unbind_handle(
18807c478bd9Sstevel@tonic-gate 			    ehcip->ehci_qh_pool_dma_handle);
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
18837c478bd9Sstevel@tonic-gate 		}
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&ehcip->ehci_qh_pool_mem_handle);
18867c478bd9Sstevel@tonic-gate 	}
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate 	/* Free the QH pool */
18897c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_qh_pool_dma_handle) {
18907c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&ehcip->ehci_qh_pool_dma_handle);
18917c478bd9Sstevel@tonic-gate 	}
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate 	/* Free the Periodic frame list table (PFLT) area */
18947c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_periodic_frame_list_tablep &&
18957c478bd9Sstevel@tonic-gate 	    ehcip->ehci_pflt_mem_handle) {
18967c478bd9Sstevel@tonic-gate 		/*
18977c478bd9Sstevel@tonic-gate 		 * If EHCI_PFLT_DMA_BOUND flag is set, then unbind
18987c478bd9Sstevel@tonic-gate 		 * the handle for PFLT.
18997c478bd9Sstevel@tonic-gate 		 */
19007c478bd9Sstevel@tonic-gate 		if ((ehcip->ehci_dma_addr_bind_flag &
19017c478bd9Sstevel@tonic-gate 		    EHCI_PFLT_DMA_BOUND) == EHCI_PFLT_DMA_BOUND) {
19027c478bd9Sstevel@tonic-gate 
19037c478bd9Sstevel@tonic-gate 			rval = ddi_dma_unbind_handle(
19047c478bd9Sstevel@tonic-gate 			    ehcip->ehci_pflt_dma_handle);
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
19077c478bd9Sstevel@tonic-gate 		}
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&ehcip->ehci_pflt_mem_handle);
19107c478bd9Sstevel@tonic-gate 	}
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 	(void) ehci_isoc_cleanup(ehcip);
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_pflt_dma_handle) {
19157c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&ehcip->ehci_pflt_dma_handle);
19167c478bd9Sstevel@tonic-gate 	}
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate 	if (flags & EHCI_INTR) {
19197c478bd9Sstevel@tonic-gate 		/* Destroy the mutex */
19207c478bd9Sstevel@tonic-gate 		mutex_destroy(&ehcip->ehci_int_mutex);
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 		/* Destroy the async schedule advance condition variable */
19237c478bd9Sstevel@tonic-gate 		cv_destroy(&ehcip->ehci_async_schedule_advance_cv);
19247c478bd9Sstevel@tonic-gate 	}
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate 	/* clean up kstat structs */
19277c478bd9Sstevel@tonic-gate 	ehci_destroy_stats(ehcip);
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate 	/* Free ehci hcdi ops */
19307c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_hcdi_ops) {
19317c478bd9Sstevel@tonic-gate 		usba_free_hcdi_ops(ehcip->ehci_hcdi_ops);
19327c478bd9Sstevel@tonic-gate 	}
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 	if (flags & EHCI_ZALLOC) {
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 		usb_free_log_hdl(ehcip->ehci_log_hdl);
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate 		/* Remove all properties that might have been created */
19397c478bd9Sstevel@tonic-gate 		ddi_prop_remove_all(ehcip->ehci_dip);
19407c478bd9Sstevel@tonic-gate 
19417c478bd9Sstevel@tonic-gate 		/* Free the soft state */
19427c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(ehci_statep,
194329aca3ebSlc 		    ddi_get_instance(ehcip->ehci_dip));
19447c478bd9Sstevel@tonic-gate 	}
19457c478bd9Sstevel@tonic-gate 
19467c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
19477c478bd9Sstevel@tonic-gate }
19487c478bd9Sstevel@tonic-gate 
19497c478bd9Sstevel@tonic-gate 
19509c75c6bfSgovinda /*
19519c75c6bfSgovinda  * ehci_rem_intrs:
19529c75c6bfSgovinda  *
19539c75c6bfSgovinda  * Unregister FIXED or MSI interrupts
19549c75c6bfSgovinda  */
19559c75c6bfSgovinda static void
19569c75c6bfSgovinda ehci_rem_intrs(ehci_state_t	*ehcip)
19579c75c6bfSgovinda {
19589c75c6bfSgovinda 	int	i;
19599c75c6bfSgovinda 
19609c75c6bfSgovinda 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
19619c75c6bfSgovinda 	    "ehci_rem_intrs: interrupt type 0x%x", ehcip->ehci_intr_type);
19629c75c6bfSgovinda 
19639c75c6bfSgovinda 	/* Disable all interrupts */
19649c75c6bfSgovinda 	if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) {
19659c75c6bfSgovinda 		(void) ddi_intr_block_disable(ehcip->ehci_htable,
19669c75c6bfSgovinda 		    ehcip->ehci_intr_cnt);
19679c75c6bfSgovinda 	} else {
19689c75c6bfSgovinda 		for (i = 0; i < ehcip->ehci_intr_cnt; i++) {
19699c75c6bfSgovinda 			(void) ddi_intr_disable(ehcip->ehci_htable[i]);
19709c75c6bfSgovinda 		}
19719c75c6bfSgovinda 	}
19729c75c6bfSgovinda 
19739c75c6bfSgovinda 	/* Call ddi_intr_remove_handler() */
19749c75c6bfSgovinda 	for (i = 0; i < ehcip->ehci_intr_cnt; i++) {
19759c75c6bfSgovinda 		(void) ddi_intr_remove_handler(ehcip->ehci_htable[i]);
19769c75c6bfSgovinda 		(void) ddi_intr_free(ehcip->ehci_htable[i]);
19779c75c6bfSgovinda 	}
19789c75c6bfSgovinda 
19799c75c6bfSgovinda 	kmem_free(ehcip->ehci_htable,
19809c75c6bfSgovinda 	    ehcip->ehci_intr_cnt * sizeof (ddi_intr_handle_t));
19819c75c6bfSgovinda }
19829c75c6bfSgovinda 
19839c75c6bfSgovinda 
19847c478bd9Sstevel@tonic-gate /*
19857c478bd9Sstevel@tonic-gate  * ehci_cpr_suspend
19867c478bd9Sstevel@tonic-gate  */
19877c478bd9Sstevel@tonic-gate int
19887c478bd9Sstevel@tonic-gate ehci_cpr_suspend(ehci_state_t	*ehcip)
19897c478bd9Sstevel@tonic-gate {
19907c478bd9Sstevel@tonic-gate 	int	i;
19917c478bd9Sstevel@tonic-gate 
19927c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
19937c478bd9Sstevel@tonic-gate 	    "ehci_cpr_suspend:");
19947c478bd9Sstevel@tonic-gate 
19957c478bd9Sstevel@tonic-gate 	/* Call into the root hub and suspend it */
19967c478bd9Sstevel@tonic-gate 	if (usba_hubdi_detach(ehcip->ehci_dip, DDI_SUSPEND) != DDI_SUCCESS) {
19977c478bd9Sstevel@tonic-gate 
19987c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
199929aca3ebSlc 		    "ehci_cpr_suspend: root hub fails to suspend");
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
20027c478bd9Sstevel@tonic-gate 	}
20037c478bd9Sstevel@tonic-gate 
20047c478bd9Sstevel@tonic-gate 	/* Only root hub's intr pipe should be open at this time */
20057c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
20067c478bd9Sstevel@tonic-gate 
20077c478bd9Sstevel@tonic-gate 	ASSERT(ehcip->ehci_open_pipe_count == 0);
20087c478bd9Sstevel@tonic-gate 
20097c478bd9Sstevel@tonic-gate 	/* Just wait till all resources are reclaimed */
20107c478bd9Sstevel@tonic-gate 	i = 0;
20117c478bd9Sstevel@tonic-gate 	while ((ehcip->ehci_reclaim_list != NULL) && (i++ < 3)) {
20127c478bd9Sstevel@tonic-gate 		ehci_handle_endpoint_reclaimation(ehcip);
20137c478bd9Sstevel@tonic-gate 		(void) ehci_wait_for_sof(ehcip);
20147c478bd9Sstevel@tonic-gate 	}
20157c478bd9Sstevel@tonic-gate 	ASSERT(ehcip->ehci_reclaim_list == NULL);
20167c478bd9Sstevel@tonic-gate 
20173b00f311Syq 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20187c478bd9Sstevel@tonic-gate 	    "ehci_cpr_suspend: Disable HC QH list processing");
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate 	/* Disable all EHCI QH list processing */
20217c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_command, (Get_OpReg(ehci_command) &
20227c478bd9Sstevel@tonic-gate 	    ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE)));
20237c478bd9Sstevel@tonic-gate 
20243b00f311Syq 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20257c478bd9Sstevel@tonic-gate 	    "ehci_cpr_suspend: Disable HC interrupts");
20267c478bd9Sstevel@tonic-gate 
20277c478bd9Sstevel@tonic-gate 	/* Disable all EHCI interrupts */
20287c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_interrupt, 0);
20297c478bd9Sstevel@tonic-gate 
20303b00f311Syq 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20317c478bd9Sstevel@tonic-gate 	    "ehci_cpr_suspend: Wait for the next SOF");
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate 	/* Wait for the next SOF */
20347c478bd9Sstevel@tonic-gate 	if (ehci_wait_for_sof(ehcip) != USB_SUCCESS) {
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20377c478bd9Sstevel@tonic-gate 		    "ehci_cpr_suspend: ehci host controller suspend failed");
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
20407c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
20417c478bd9Sstevel@tonic-gate 	}
20427c478bd9Sstevel@tonic-gate 
20437c478bd9Sstevel@tonic-gate 	/*
20447c478bd9Sstevel@tonic-gate 	 * Stop the ehci host controller
20457c478bd9Sstevel@tonic-gate 	 * if usb keyboard is not connected.
20467c478bd9Sstevel@tonic-gate 	 */
20472df1fe9cSrandyf 	if (ehcip->ehci_polled_kbd_count == 0 || force_ehci_off != 0) {
20487c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_command,
20497c478bd9Sstevel@tonic-gate 		    Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN);
20507c478bd9Sstevel@tonic-gate 	}
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate 	/* Set host controller soft state to suspend */
20537c478bd9Sstevel@tonic-gate 	ehcip->ehci_hc_soft_state = EHCI_CTLR_SUSPEND_STATE;
20547c478bd9Sstevel@tonic-gate 
20557c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
20587c478bd9Sstevel@tonic-gate }
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate 
20617c478bd9Sstevel@tonic-gate /*
20627c478bd9Sstevel@tonic-gate  * ehci_cpr_resume
20637c478bd9Sstevel@tonic-gate  */
20647c478bd9Sstevel@tonic-gate int
20657c478bd9Sstevel@tonic-gate ehci_cpr_resume(ehci_state_t	*ehcip)
20667c478bd9Sstevel@tonic-gate {
20677c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20707c478bd9Sstevel@tonic-gate 	    "ehci_cpr_resume: Restart the controller");
20717c478bd9Sstevel@tonic-gate 
20727c478bd9Sstevel@tonic-gate 	/* Cleanup ehci specific information across cpr */
20737c478bd9Sstevel@tonic-gate 	ehci_cpr_cleanup(ehcip);
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate 	/* Restart the controller */
20763b00f311Syq 	if (ehci_init_ctlr(ehcip, EHCI_NORMAL_INITIALIZATION) != DDI_SUCCESS) {
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20797c478bd9Sstevel@tonic-gate 		    "ehci_cpr_resume: ehci host controller resume failed ");
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
20827c478bd9Sstevel@tonic-gate 
20837c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
20847c478bd9Sstevel@tonic-gate 	}
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
20877c478bd9Sstevel@tonic-gate 
20887c478bd9Sstevel@tonic-gate 	/* Now resume the root hub */
20897c478bd9Sstevel@tonic-gate 	if (usba_hubdi_attach(ehcip->ehci_dip, DDI_RESUME) != DDI_SUCCESS) {
20907c478bd9Sstevel@tonic-gate 
20917c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
20927c478bd9Sstevel@tonic-gate 	}
20937c478bd9Sstevel@tonic-gate 
20947c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
20957c478bd9Sstevel@tonic-gate }
20967c478bd9Sstevel@tonic-gate 
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate /*
20997c478bd9Sstevel@tonic-gate  * Bandwidth Allocation functions
21007c478bd9Sstevel@tonic-gate  */
21017c478bd9Sstevel@tonic-gate 
21027c478bd9Sstevel@tonic-gate /*
21037c478bd9Sstevel@tonic-gate  * ehci_allocate_bandwidth:
21047c478bd9Sstevel@tonic-gate  *
21057c478bd9Sstevel@tonic-gate  * Figure out whether or not this interval may be supported. Return the index
21067c478bd9Sstevel@tonic-gate  * into the  lattice if it can be supported.  Return allocation failure if it
21077c478bd9Sstevel@tonic-gate  * can not be supported.
21087c478bd9Sstevel@tonic-gate  */
21097c478bd9Sstevel@tonic-gate int
21107c478bd9Sstevel@tonic-gate ehci_allocate_bandwidth(
21117c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
21127c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
21137c478bd9Sstevel@tonic-gate 	uint_t			*pnode,
21147c478bd9Sstevel@tonic-gate 	uchar_t			*smask,
21157c478bd9Sstevel@tonic-gate 	uchar_t			*cmask)
21167c478bd9Sstevel@tonic-gate {
21177c478bd9Sstevel@tonic-gate 	int			error = USB_SUCCESS;
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
21207c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
21217c478bd9Sstevel@tonic-gate 
21227c478bd9Sstevel@tonic-gate 	/* Reset the pnode to the last checked pnode */
21237c478bd9Sstevel@tonic-gate 	*pnode = 0;
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 	/* Allocate high speed bandwidth */
21267c478bd9Sstevel@tonic-gate 	if ((error = ehci_allocate_high_speed_bandwidth(ehcip,
21277c478bd9Sstevel@tonic-gate 	    ph, pnode, smask, cmask)) != USB_SUCCESS) {
21287c478bd9Sstevel@tonic-gate 
21297c478bd9Sstevel@tonic-gate 		return (error);
21307c478bd9Sstevel@tonic-gate 	}
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 	/*
21337c478bd9Sstevel@tonic-gate 	 * For low/full speed usb devices, allocate classic TT bandwidth
21347c478bd9Sstevel@tonic-gate 	 * in additional to high speed bandwidth.
21357c478bd9Sstevel@tonic-gate 	 */
21367c478bd9Sstevel@tonic-gate 	if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) {
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate 		/* Allocate classic TT bandwidth */
21397c478bd9Sstevel@tonic-gate 		if ((error = ehci_allocate_classic_tt_bandwidth(
21407c478bd9Sstevel@tonic-gate 		    ehcip, ph, *pnode)) != USB_SUCCESS) {
21417c478bd9Sstevel@tonic-gate 
21427c478bd9Sstevel@tonic-gate 			/* Deallocate high speed bandwidth */
21437c478bd9Sstevel@tonic-gate 			ehci_deallocate_high_speed_bandwidth(
21447c478bd9Sstevel@tonic-gate 			    ehcip, ph, *pnode, *smask, *cmask);
21457c478bd9Sstevel@tonic-gate 		}
21467c478bd9Sstevel@tonic-gate 	}
21477c478bd9Sstevel@tonic-gate 
21487c478bd9Sstevel@tonic-gate 	return (error);
21497c478bd9Sstevel@tonic-gate }
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate 
21527c478bd9Sstevel@tonic-gate /*
21537c478bd9Sstevel@tonic-gate  * ehci_allocate_high_speed_bandwidth:
21547c478bd9Sstevel@tonic-gate  *
21557c478bd9Sstevel@tonic-gate  * Allocate high speed bandwidth for the low/full/high speed interrupt and
21567c478bd9Sstevel@tonic-gate  * isochronous endpoints.
21577c478bd9Sstevel@tonic-gate  */
21587c478bd9Sstevel@tonic-gate static int
21597c478bd9Sstevel@tonic-gate ehci_allocate_high_speed_bandwidth(
21607c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
21617c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
21627c478bd9Sstevel@tonic-gate 	uint_t			*pnode,
21637c478bd9Sstevel@tonic-gate 	uchar_t			*smask,
21647c478bd9Sstevel@tonic-gate 	uchar_t			*cmask)
21657c478bd9Sstevel@tonic-gate {
21667c478bd9Sstevel@tonic-gate 	uint_t			sbandwidth, cbandwidth;
21677c478bd9Sstevel@tonic-gate 	int			interval;
21687c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint = &ph->p_ep;
21697c478bd9Sstevel@tonic-gate 	usba_device_t		*child_ud;
21707c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status;
21717c478bd9Sstevel@tonic-gate 	int			error;
21727c478bd9Sstevel@tonic-gate 
21737c478bd9Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
21747c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
21757c478bd9Sstevel@tonic-gate 
21767c478bd9Sstevel@tonic-gate 	/* Get child's usba device structure */
21777c478bd9Sstevel@tonic-gate 	child_ud = ph->p_usba_device;
21787c478bd9Sstevel@tonic-gate 
21797c478bd9Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
21807c478bd9Sstevel@tonic-gate 
21817c478bd9Sstevel@tonic-gate 	/* Get the current usb device's port status */
21827c478bd9Sstevel@tonic-gate 	port_status = ph->p_usba_device->usb_port_status;
21837c478bd9Sstevel@tonic-gate 
21847c478bd9Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 	/*
21877c478bd9Sstevel@tonic-gate 	 * Calculate the length in bytes of a transaction on this
21887c478bd9Sstevel@tonic-gate 	 * periodic endpoint. Return failure if maximum packet is
21897c478bd9Sstevel@tonic-gate 	 * zero.
21907c478bd9Sstevel@tonic-gate 	 */
21917c478bd9Sstevel@tonic-gate 	error = ehci_compute_high_speed_bandwidth(ehcip, endpoint,
21927c478bd9Sstevel@tonic-gate 	    port_status, &sbandwidth, &cbandwidth);
21937c478bd9Sstevel@tonic-gate 	if (error != USB_SUCCESS) {
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate 		return (error);
21967c478bd9Sstevel@tonic-gate 	}
21977c478bd9Sstevel@tonic-gate 
21987c478bd9Sstevel@tonic-gate 	/*
21997c478bd9Sstevel@tonic-gate 	 * Adjust polling interval to be a power of 2.
22007c478bd9Sstevel@tonic-gate 	 * If this interval can't be supported, return
22017c478bd9Sstevel@tonic-gate 	 * allocation failure.
22027c478bd9Sstevel@tonic-gate 	 */
22037c478bd9Sstevel@tonic-gate 	interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
22047c478bd9Sstevel@tonic-gate 	if (interval == USB_FAILURE) {
22057c478bd9Sstevel@tonic-gate 
22067c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
22077c478bd9Sstevel@tonic-gate 	}
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	if (port_status == USBA_HIGH_SPEED_DEV) {
2210b3001defSlg 		/* Allocate bandwidth for high speed devices */
2211b3001defSlg 		if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) ==
2212b3001defSlg 		    USB_EP_ATTR_ISOCH) {
2213b3001defSlg 			error = USB_SUCCESS;
2214b3001defSlg 		} else {
2215b3001defSlg 
2216b3001defSlg 			error = ehci_find_bestfit_hs_mask(ehcip, smask, pnode,
2217b3001defSlg 			    endpoint, sbandwidth, interval);
2218b3001defSlg 		}
2219b3001defSlg 
22207c478bd9Sstevel@tonic-gate 		*cmask = 0x00;
22217c478bd9Sstevel@tonic-gate 
22227c478bd9Sstevel@tonic-gate 	} else {
22237c478bd9Sstevel@tonic-gate 		if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) ==
22247c478bd9Sstevel@tonic-gate 		    USB_EP_ATTR_INTR) {
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate 			/* Allocate bandwidth for low speed interrupt */
22277c478bd9Sstevel@tonic-gate 			error = ehci_find_bestfit_ls_intr_mask(ehcip,
22287c478bd9Sstevel@tonic-gate 			    smask, cmask, pnode, sbandwidth, cbandwidth,
22297c478bd9Sstevel@tonic-gate 			    interval);
22307c478bd9Sstevel@tonic-gate 		} else {
22317c478bd9Sstevel@tonic-gate 			if ((endpoint->bEndpointAddress &
22327c478bd9Sstevel@tonic-gate 			    USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
22337c478bd9Sstevel@tonic-gate 
22347c478bd9Sstevel@tonic-gate 				/* Allocate bandwidth for sitd in */
22357c478bd9Sstevel@tonic-gate 				error = ehci_find_bestfit_sitd_in_mask(ehcip,
22367c478bd9Sstevel@tonic-gate 				    smask, cmask, pnode, sbandwidth, cbandwidth,
22377c478bd9Sstevel@tonic-gate 				    interval);
22387c478bd9Sstevel@tonic-gate 			} else {
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate 				/* Allocate bandwidth for sitd out */
22417c478bd9Sstevel@tonic-gate 				error = ehci_find_bestfit_sitd_out_mask(ehcip,
22427c478bd9Sstevel@tonic-gate 				    smask, pnode, sbandwidth, interval);
22437c478bd9Sstevel@tonic-gate 				*cmask = 0x00;
22447c478bd9Sstevel@tonic-gate 			}
22457c478bd9Sstevel@tonic-gate 		}
22467c478bd9Sstevel@tonic-gate 	}
22477c478bd9Sstevel@tonic-gate 
22487c478bd9Sstevel@tonic-gate 	if (error != USB_SUCCESS) {
22497c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
22507c478bd9Sstevel@tonic-gate 		    "ehci_allocate_high_speed_bandwidth: Reached maximum "
22517c478bd9Sstevel@tonic-gate 		    "bandwidth value and cannot allocate bandwidth for a "
22527c478bd9Sstevel@tonic-gate 		    "given high-speed periodic endpoint");
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate 		return (USB_NO_BANDWIDTH);
22557c478bd9Sstevel@tonic-gate 	}
22567c478bd9Sstevel@tonic-gate 
22577c478bd9Sstevel@tonic-gate 	return (error);
22587c478bd9Sstevel@tonic-gate }
22597c478bd9Sstevel@tonic-gate 
22607c478bd9Sstevel@tonic-gate 
22617c478bd9Sstevel@tonic-gate /*
22627c478bd9Sstevel@tonic-gate  * ehci_allocate_classic_tt_speed_bandwidth:
22637c478bd9Sstevel@tonic-gate  *
22647c478bd9Sstevel@tonic-gate  * Allocate classic TT bandwidth for the low/full speed interrupt and
22657c478bd9Sstevel@tonic-gate  * isochronous endpoints.
22667c478bd9Sstevel@tonic-gate  */
22677c478bd9Sstevel@tonic-gate static int
22687c478bd9Sstevel@tonic-gate ehci_allocate_classic_tt_bandwidth(
22697c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
22707c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
22717c478bd9Sstevel@tonic-gate 	uint_t			pnode)
22727c478bd9Sstevel@tonic-gate {
22737c478bd9Sstevel@tonic-gate 	uint_t			bandwidth, min;
22747c478bd9Sstevel@tonic-gate 	uint_t			height, leftmost, list;
22757c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint = &ph->p_ep;
22767c478bd9Sstevel@tonic-gate 	usba_device_t		*child_ud, *parent_ud;
22777c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status;
22787c478bd9Sstevel@tonic-gate 	int			i, interval;
22797c478bd9Sstevel@tonic-gate 
22807c478bd9Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
22817c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
22827c478bd9Sstevel@tonic-gate 
22837c478bd9Sstevel@tonic-gate 	/* Get child's usba device structure */
22847c478bd9Sstevel@tonic-gate 	child_ud = ph->p_usba_device;
22857c478bd9Sstevel@tonic-gate 
22867c478bd9Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
22877c478bd9Sstevel@tonic-gate 
22887c478bd9Sstevel@tonic-gate 	/* Get the current usb device's port status */
22897c478bd9Sstevel@tonic-gate 	port_status = child_ud->usb_port_status;
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate 	/* Get the parent high speed hub's usba device structure */
22927c478bd9Sstevel@tonic-gate 	parent_ud = child_ud->usb_hs_hub_usba_dev;
22937c478bd9Sstevel@tonic-gate 
22947c478bd9Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
22957c478bd9Sstevel@tonic-gate 
22963b00f311Syq 	USB_DPRINTF_L3(PRINT_MASK_BW, ehcip->ehci_log_hdl,
22977c478bd9Sstevel@tonic-gate 	    "ehci_allocate_classic_tt_bandwidth: "
2298112116d8Sfb 	    "child_ud 0x%p parent_ud 0x%p",
2299112116d8Sfb 	    (void *)child_ud, (void *)parent_ud);
23007c478bd9Sstevel@tonic-gate 
23017c478bd9Sstevel@tonic-gate 	/*
23027c478bd9Sstevel@tonic-gate 	 * Calculate the length in bytes of a transaction on this
23037c478bd9Sstevel@tonic-gate 	 * periodic endpoint. Return failure if maximum packet is
23047c478bd9Sstevel@tonic-gate 	 * zero.
23057c478bd9Sstevel@tonic-gate 	 */
23067c478bd9Sstevel@tonic-gate 	if (ehci_compute_classic_bandwidth(endpoint,
23077c478bd9Sstevel@tonic-gate 	    port_status, &bandwidth) != USB_SUCCESS) {
23087c478bd9Sstevel@tonic-gate 
23097c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
23107c478bd9Sstevel@tonic-gate 		    "ehci_allocate_classic_tt_bandwidth: Periodic endpoint "
23117c478bd9Sstevel@tonic-gate 		    "with zero endpoint maximum packet size is not supported");
23127c478bd9Sstevel@tonic-gate 
23137c478bd9Sstevel@tonic-gate 		return (USB_NOT_SUPPORTED);
23147c478bd9Sstevel@tonic-gate 	}
23157c478bd9Sstevel@tonic-gate 
23163b00f311Syq 	USB_DPRINTF_L3(PRINT_MASK_BW, ehcip->ehci_log_hdl,
23177c478bd9Sstevel@tonic-gate 	    "ehci_allocate_classic_tt_bandwidth: bandwidth %d", bandwidth);
23187c478bd9Sstevel@tonic-gate 
23197c478bd9Sstevel@tonic-gate 	mutex_enter(&parent_ud->usb_mutex);
23207c478bd9Sstevel@tonic-gate 
23217c478bd9Sstevel@tonic-gate 	/*
23227c478bd9Sstevel@tonic-gate 	 * If the length in bytes plus the allocated bandwidth exceeds
23237c478bd9Sstevel@tonic-gate 	 * the maximum, return bandwidth allocation failure.
23247c478bd9Sstevel@tonic-gate 	 */
23257c478bd9Sstevel@tonic-gate 	if ((parent_ud->usb_hs_hub_min_bandwidth + bandwidth) >
23267c478bd9Sstevel@tonic-gate 	    FS_PERIODIC_BANDWIDTH) {
23277c478bd9Sstevel@tonic-gate 
23287c478bd9Sstevel@tonic-gate 		mutex_exit(&parent_ud->usb_mutex);
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
23317c478bd9Sstevel@tonic-gate 		    "ehci_allocate_classic_tt_bandwidth: Reached maximum "
23327c478bd9Sstevel@tonic-gate 		    "bandwidth value and cannot allocate bandwidth for a "
23337c478bd9Sstevel@tonic-gate 		    "given low/full speed periodic endpoint");
23347c478bd9Sstevel@tonic-gate 
23357c478bd9Sstevel@tonic-gate 		return (USB_NO_BANDWIDTH);
23367c478bd9Sstevel@tonic-gate 	}
23377c478bd9Sstevel@tonic-gate 
23387c478bd9Sstevel@tonic-gate 	mutex_exit(&parent_ud->usb_mutex);
23397c478bd9Sstevel@tonic-gate 
23407c478bd9Sstevel@tonic-gate 	/* Adjust polling interval to be a power of 2 */
23417c478bd9Sstevel@tonic-gate 	interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate 	/* Find the height in the tree */
23447c478bd9Sstevel@tonic-gate 	height = ehci_lattice_height(interval);
23457c478bd9Sstevel@tonic-gate 
23467c478bd9Sstevel@tonic-gate 	/* Find the leftmost leaf in the subtree specified by the node. */
23477c478bd9Sstevel@tonic-gate 	leftmost = ehci_leftmost_leaf(pnode, height);
23487c478bd9Sstevel@tonic-gate 
23497c478bd9Sstevel@tonic-gate 	mutex_enter(&parent_ud->usb_mutex);
23507c478bd9Sstevel@tonic-gate 
23517c478bd9Sstevel@tonic-gate 	for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) {
23527c478bd9Sstevel@tonic-gate 		list = ehci_index[leftmost + i];
23537c478bd9Sstevel@tonic-gate 
23547c478bd9Sstevel@tonic-gate 		if ((parent_ud->usb_hs_hub_bandwidth[list] +
23557c478bd9Sstevel@tonic-gate 		    bandwidth) > FS_PERIODIC_BANDWIDTH) {
23567c478bd9Sstevel@tonic-gate 
23577c478bd9Sstevel@tonic-gate 			mutex_exit(&parent_ud->usb_mutex);
23587c478bd9Sstevel@tonic-gate 
23597c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
23607c478bd9Sstevel@tonic-gate 			    "ehci_allocate_classic_tt_bandwidth: Reached "
23617c478bd9Sstevel@tonic-gate 			    "maximum bandwidth value and cannot allocate "
23627c478bd9Sstevel@tonic-gate 			    "bandwidth for low/full periodic endpoint");
23637c478bd9Sstevel@tonic-gate 
23647c478bd9Sstevel@tonic-gate 			return (USB_NO_BANDWIDTH);
23657c478bd9Sstevel@tonic-gate 		}
23667c478bd9Sstevel@tonic-gate 	}
23677c478bd9Sstevel@tonic-gate 
23687c478bd9Sstevel@tonic-gate 	/*
23697c478bd9Sstevel@tonic-gate 	 * All the leaves for this node must be updated with the bandwidth.
23707c478bd9Sstevel@tonic-gate 	 */
23717c478bd9Sstevel@tonic-gate 	for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) {
23727c478bd9Sstevel@tonic-gate 		list = ehci_index[leftmost + i];
23737c478bd9Sstevel@tonic-gate 		parent_ud->usb_hs_hub_bandwidth[list] += bandwidth;
23747c478bd9Sstevel@tonic-gate 	}
23757c478bd9Sstevel@tonic-gate 
23767c478bd9Sstevel@tonic-gate 	/* Find the leaf with the smallest allocated bandwidth */
23777c478bd9Sstevel@tonic-gate 	min = parent_ud->usb_hs_hub_bandwidth[0];
23787c478bd9Sstevel@tonic-gate 
23797c478bd9Sstevel@tonic-gate 	for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) {
23807c478bd9Sstevel@tonic-gate 		if (parent_ud->usb_hs_hub_bandwidth[i] < min) {
23817c478bd9Sstevel@tonic-gate 			min = parent_ud->usb_hs_hub_bandwidth[i];
23827c478bd9Sstevel@tonic-gate 		}
23837c478bd9Sstevel@tonic-gate 	}
23847c478bd9Sstevel@tonic-gate 
23857c478bd9Sstevel@tonic-gate 	/* Save the minimum for later use */
23867c478bd9Sstevel@tonic-gate 	parent_ud->usb_hs_hub_min_bandwidth = min;
23877c478bd9Sstevel@tonic-gate 
23887c478bd9Sstevel@tonic-gate 	mutex_exit(&parent_ud->usb_mutex);
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
23917c478bd9Sstevel@tonic-gate }
23927c478bd9Sstevel@tonic-gate 
23937c478bd9Sstevel@tonic-gate 
23947c478bd9Sstevel@tonic-gate /*
23957c478bd9Sstevel@tonic-gate  * ehci_deallocate_bandwidth:
23967c478bd9Sstevel@tonic-gate  *
23977c478bd9Sstevel@tonic-gate  * Deallocate bandwidth for the given node in the lattice and the length
23987c478bd9Sstevel@tonic-gate  * of transfer.
23997c478bd9Sstevel@tonic-gate  */
24007c478bd9Sstevel@tonic-gate void
24017c478bd9Sstevel@tonic-gate ehci_deallocate_bandwidth(
24027c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
24037c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
24047c478bd9Sstevel@tonic-gate 	uint_t			pnode,
24057c478bd9Sstevel@tonic-gate 	uchar_t			smask,
24067c478bd9Sstevel@tonic-gate 	uchar_t			cmask)
24077c478bd9Sstevel@tonic-gate {
24087c478bd9Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
24097c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
24107c478bd9Sstevel@tonic-gate 
24117c478bd9Sstevel@tonic-gate 	ehci_deallocate_high_speed_bandwidth(ehcip, ph, pnode, smask, cmask);
24127c478bd9Sstevel@tonic-gate 
24137c478bd9Sstevel@tonic-gate 	/*
24147c478bd9Sstevel@tonic-gate 	 * For low/full speed usb devices, deallocate classic TT bandwidth
24157c478bd9Sstevel@tonic-gate 	 * in additional to high speed bandwidth.
24167c478bd9Sstevel@tonic-gate 	 */
24177c478bd9Sstevel@tonic-gate 	if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) {
24187c478bd9Sstevel@tonic-gate 
24197c478bd9Sstevel@tonic-gate 		/* Deallocate classic TT bandwidth */
24207c478bd9Sstevel@tonic-gate 		ehci_deallocate_classic_tt_bandwidth(ehcip, ph, pnode);
24217c478bd9Sstevel@tonic-gate 	}
24227c478bd9Sstevel@tonic-gate }
24237c478bd9Sstevel@tonic-gate 
24247c478bd9Sstevel@tonic-gate 
24257c478bd9Sstevel@tonic-gate /*
24267c478bd9Sstevel@tonic-gate  * ehci_deallocate_high_speed_bandwidth:
24277c478bd9Sstevel@tonic-gate  *
24287c478bd9Sstevel@tonic-gate  * Deallocate high speed bandwidth of a interrupt or isochronous endpoint.
24297c478bd9Sstevel@tonic-gate  */
24307c478bd9Sstevel@tonic-gate static void
24317c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth(
24327c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
24337c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
24347c478bd9Sstevel@tonic-gate 	uint_t			pnode,
24357c478bd9Sstevel@tonic-gate 	uchar_t			smask,
24367c478bd9Sstevel@tonic-gate 	uchar_t			cmask)
24377c478bd9Sstevel@tonic-gate {
24387c478bd9Sstevel@tonic-gate 	uint_t			height, leftmost;
24397c478bd9Sstevel@tonic-gate 	uint_t			list_count;
24407c478bd9Sstevel@tonic-gate 	uint_t			sbandwidth, cbandwidth;
24417c478bd9Sstevel@tonic-gate 	int			interval;
24427c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint = &ph->p_ep;
24437c478bd9Sstevel@tonic-gate 	usba_device_t		*child_ud;
24447c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status;
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
24477c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate 	/* Get child's usba device structure */
24507c478bd9Sstevel@tonic-gate 	child_ud = ph->p_usba_device;
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
24537c478bd9Sstevel@tonic-gate 
24547c478bd9Sstevel@tonic-gate 	/* Get the current usb device's port status */
24557c478bd9Sstevel@tonic-gate 	port_status = ph->p_usba_device->usb_port_status;
24567c478bd9Sstevel@tonic-gate 
24577c478bd9Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
24587c478bd9Sstevel@tonic-gate 
24597c478bd9Sstevel@tonic-gate 	(void) ehci_compute_high_speed_bandwidth(ehcip, endpoint,
24607c478bd9Sstevel@tonic-gate 	    port_status, &sbandwidth, &cbandwidth);
24617c478bd9Sstevel@tonic-gate 
24627c478bd9Sstevel@tonic-gate 	/* Adjust polling interval to be a power of 2 */
24637c478bd9Sstevel@tonic-gate 	interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
24647c478bd9Sstevel@tonic-gate 
24657c478bd9Sstevel@tonic-gate 	/* Find the height in the tree */
24667c478bd9Sstevel@tonic-gate 	height = ehci_lattice_height(interval);
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate 	/*
24697c478bd9Sstevel@tonic-gate 	 * Find the leftmost leaf in the subtree specified by the node
24707c478bd9Sstevel@tonic-gate 	 */
24717c478bd9Sstevel@tonic-gate 	leftmost = ehci_leftmost_leaf(pnode, height);
24727c478bd9Sstevel@tonic-gate 
24737c478bd9Sstevel@tonic-gate 	list_count = EHCI_NUM_INTR_QH_LISTS/interval;
24747c478bd9Sstevel@tonic-gate 
24757c478bd9Sstevel@tonic-gate 	/* Delete the bandwidth from the appropriate lists */
24767c478bd9Sstevel@tonic-gate 	if (port_status == USBA_HIGH_SPEED_DEV) {
24777c478bd9Sstevel@tonic-gate 
24787c478bd9Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, -sbandwidth,
24797c478bd9Sstevel@tonic-gate 		    leftmost, list_count, smask);
24807c478bd9Sstevel@tonic-gate 	} else {
24817c478bd9Sstevel@tonic-gate 		if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) ==
24827c478bd9Sstevel@tonic-gate 		    USB_EP_ATTR_INTR) {
24837c478bd9Sstevel@tonic-gate 
24847c478bd9Sstevel@tonic-gate 			ehci_update_bw_availability(ehcip, -sbandwidth,
24857c478bd9Sstevel@tonic-gate 			    leftmost, list_count, smask);
24867c478bd9Sstevel@tonic-gate 			ehci_update_bw_availability(ehcip, -cbandwidth,
24877c478bd9Sstevel@tonic-gate 			    leftmost, list_count, cmask);
24887c478bd9Sstevel@tonic-gate 		} else {
24897c478bd9Sstevel@tonic-gate 			if ((endpoint->bEndpointAddress &
24907c478bd9Sstevel@tonic-gate 			    USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
24917c478bd9Sstevel@tonic-gate 
24927c478bd9Sstevel@tonic-gate 				ehci_update_bw_availability(ehcip, -sbandwidth,
24937c478bd9Sstevel@tonic-gate 				    leftmost, list_count, smask);
24947c478bd9Sstevel@tonic-gate 				ehci_update_bw_availability(ehcip,
24957c478bd9Sstevel@tonic-gate 				    -MAX_UFRAME_SITD_XFER, leftmost,
24967c478bd9Sstevel@tonic-gate 				    list_count, cmask);
24977c478bd9Sstevel@tonic-gate 			} else {
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate 				ehci_update_bw_availability(ehcip,
25007c478bd9Sstevel@tonic-gate 				    -MAX_UFRAME_SITD_XFER, leftmost,
25017c478bd9Sstevel@tonic-gate 				    list_count, smask);
25027c478bd9Sstevel@tonic-gate 			}
25037c478bd9Sstevel@tonic-gate 		}
25047c478bd9Sstevel@tonic-gate 	}
25057c478bd9Sstevel@tonic-gate }
25067c478bd9Sstevel@tonic-gate 
25077c478bd9Sstevel@tonic-gate /*
25087c478bd9Sstevel@tonic-gate  * ehci_deallocate_classic_tt_bandwidth:
25097c478bd9Sstevel@tonic-gate  *
25107c478bd9Sstevel@tonic-gate  * Deallocate high speed bandwidth of a interrupt or isochronous endpoint.
25117c478bd9Sstevel@tonic-gate  */
25127c478bd9Sstevel@tonic-gate static void
25137c478bd9Sstevel@tonic-gate ehci_deallocate_classic_tt_bandwidth(
25147c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
25157c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
25167c478bd9Sstevel@tonic-gate 	uint_t			pnode)
25177c478bd9Sstevel@tonic-gate {
25187c478bd9Sstevel@tonic-gate 	uint_t			bandwidth, height, leftmost, list, min;
25197c478bd9Sstevel@tonic-gate 	int			i, interval;
25207c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint = &ph->p_ep;
25217c478bd9Sstevel@tonic-gate 	usba_device_t		*child_ud, *parent_ud;
25227c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status;
25237c478bd9Sstevel@tonic-gate 
25247c478bd9Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
25257c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate 	/* Get child's usba device structure */
25287c478bd9Sstevel@tonic-gate 	child_ud = ph->p_usba_device;
25297c478bd9Sstevel@tonic-gate 
25307c478bd9Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
25317c478bd9Sstevel@tonic-gate 
25327c478bd9Sstevel@tonic-gate 	/* Get the current usb device's port status */
25337c478bd9Sstevel@tonic-gate 	port_status = child_ud->usb_port_status;
25347c478bd9Sstevel@tonic-gate 
25357c478bd9Sstevel@tonic-gate 	/* Get the parent high speed hub's usba device structure */
25367c478bd9Sstevel@tonic-gate 	parent_ud = child_ud->usb_hs_hub_usba_dev;
25377c478bd9Sstevel@tonic-gate 
25387c478bd9Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
25397c478bd9Sstevel@tonic-gate 
25407c478bd9Sstevel@tonic-gate 	/* Obtain the bandwidth */
25417c478bd9Sstevel@tonic-gate 	(void) ehci_compute_classic_bandwidth(endpoint,
25427c478bd9Sstevel@tonic-gate 	    port_status, &bandwidth);
25437c478bd9Sstevel@tonic-gate 
25447c478bd9Sstevel@tonic-gate 	/* Adjust polling interval to be a power of 2 */
25457c478bd9Sstevel@tonic-gate 	interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate 	/* Find the height in the tree */
25487c478bd9Sstevel@tonic-gate 	height = ehci_lattice_height(interval);
25497c478bd9Sstevel@tonic-gate 
25507c478bd9Sstevel@tonic-gate 	/* Find the leftmost leaf in the subtree specified by the node */
25517c478bd9Sstevel@tonic-gate 	leftmost = ehci_leftmost_leaf(pnode, height);
25527c478bd9Sstevel@tonic-gate 
25537c478bd9Sstevel@tonic-gate 	mutex_enter(&parent_ud->usb_mutex);
25547c478bd9Sstevel@tonic-gate 
25557c478bd9Sstevel@tonic-gate 	/* Delete the bandwidth from the appropriate lists */
25567c478bd9Sstevel@tonic-gate 	for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) {
25577c478bd9Sstevel@tonic-gate 		list = ehci_index[leftmost + i];
25587c478bd9Sstevel@tonic-gate 		parent_ud->usb_hs_hub_bandwidth[list] -= bandwidth;
25597c478bd9Sstevel@tonic-gate 	}
25607c478bd9Sstevel@tonic-gate 
25617c478bd9Sstevel@tonic-gate 	/* Find the leaf with the smallest allocated bandwidth */
25627c478bd9Sstevel@tonic-gate 	min = parent_ud->usb_hs_hub_bandwidth[0];
25637c478bd9Sstevel@tonic-gate 
25647c478bd9Sstevel@tonic-gate 	for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) {
25657c478bd9Sstevel@tonic-gate 		if (parent_ud->usb_hs_hub_bandwidth[i] < min) {
25667c478bd9Sstevel@tonic-gate 			min = parent_ud->usb_hs_hub_bandwidth[i];
25677c478bd9Sstevel@tonic-gate 		}
25687c478bd9Sstevel@tonic-gate 	}
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 	/* Save the minimum for later use */
25717c478bd9Sstevel@tonic-gate 	parent_ud->usb_hs_hub_min_bandwidth = min;
25727c478bd9Sstevel@tonic-gate 
25737c478bd9Sstevel@tonic-gate 	mutex_exit(&parent_ud->usb_mutex);
25747c478bd9Sstevel@tonic-gate }
25757c478bd9Sstevel@tonic-gate 
25767c478bd9Sstevel@tonic-gate 
25777c478bd9Sstevel@tonic-gate /*
25787c478bd9Sstevel@tonic-gate  * ehci_compute_high_speed_bandwidth:
25797c478bd9Sstevel@tonic-gate  *
25807c478bd9Sstevel@tonic-gate  * Given a periodic endpoint (interrupt or isochronous) determine the total
25817c478bd9Sstevel@tonic-gate  * bandwidth for one transaction. The EHCI host controller traverses the
25827c478bd9Sstevel@tonic-gate  * endpoint descriptor lists on a first-come-first-serve basis. When the HC
25837c478bd9Sstevel@tonic-gate  * services an endpoint, only a single transaction attempt is made. The  HC
25847c478bd9Sstevel@tonic-gate  * moves to the next Endpoint Descriptor after the first transaction attempt
25857c478bd9Sstevel@tonic-gate  * rather than finishing the entire Transfer Descriptor. Therefore, when  a
25867c478bd9Sstevel@tonic-gate  * Transfer Descriptor is inserted into the lattice, we will only count the
25877c478bd9Sstevel@tonic-gate  * number of bytes for one transaction.
25887c478bd9Sstevel@tonic-gate  *
25897c478bd9Sstevel@tonic-gate  * The following are the formulas used for  calculating bandwidth in  terms
25907c478bd9Sstevel@tonic-gate  * bytes and it is for the single USB high speed transaction.  The protocol
25917c478bd9Sstevel@tonic-gate  * overheads will be different for each of type of USB transfer & all these
25927c478bd9Sstevel@tonic-gate  * formulas & protocol overheads are derived from the 5.11.3 section of the
25937c478bd9Sstevel@tonic-gate  * USB 2.0 Specification.
25947c478bd9Sstevel@tonic-gate  *
25957c478bd9Sstevel@tonic-gate  * High-Speed:
25967c478bd9Sstevel@tonic-gate  *		Protocol overhead + ((MaxPktSz * 7)/6) + Host_Delay
25977c478bd9Sstevel@tonic-gate  *
25987c478bd9Sstevel@tonic-gate  * Split Transaction: (Low/Full speed devices connected behind usb2.0 hub)
25997c478bd9Sstevel@tonic-gate  *
26007c478bd9Sstevel@tonic-gate  *		Protocol overhead + Split transaction overhead +
26017c478bd9Sstevel@tonic-gate  *			((MaxPktSz * 7)/6) + Host_Delay;
26027c478bd9Sstevel@tonic-gate  */
26037c478bd9Sstevel@tonic-gate /* ARGSUSED */
26047c478bd9Sstevel@tonic-gate static int
26057c478bd9Sstevel@tonic-gate ehci_compute_high_speed_bandwidth(
26067c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
26077c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint,
26087c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status,
26097c478bd9Sstevel@tonic-gate 	uint_t			*sbandwidth,
26107c478bd9Sstevel@tonic-gate 	uint_t			*cbandwidth)
26117c478bd9Sstevel@tonic-gate {
26127c478bd9Sstevel@tonic-gate 	ushort_t		maxpacketsize = endpoint->wMaxPacketSize;
26137c478bd9Sstevel@tonic-gate 
26147c478bd9Sstevel@tonic-gate 	/* Return failure if endpoint maximum packet is zero */
26157c478bd9Sstevel@tonic-gate 	if (maxpacketsize == 0) {
26167c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
26177c478bd9Sstevel@tonic-gate 		    "ehci_allocate_high_speed_bandwidth: Periodic endpoint "
26187c478bd9Sstevel@tonic-gate 		    "with zero endpoint maximum packet size is not supported");
26197c478bd9Sstevel@tonic-gate 
26207c478bd9Sstevel@tonic-gate 		return (USB_NOT_SUPPORTED);
26217c478bd9Sstevel@tonic-gate 	}
26227c478bd9Sstevel@tonic-gate 
26237c478bd9Sstevel@tonic-gate 	/* Add bit-stuffing overhead */
26247c478bd9Sstevel@tonic-gate 	maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6);
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 	/* Add Host Controller specific delay to required bandwidth */
26277c478bd9Sstevel@tonic-gate 	*sbandwidth = EHCI_HOST_CONTROLLER_DELAY;
26287c478bd9Sstevel@tonic-gate 
26297c478bd9Sstevel@tonic-gate 	/* Add xfer specific protocol overheads */
26307c478bd9Sstevel@tonic-gate 	if ((endpoint->bmAttributes &
26317c478bd9Sstevel@tonic-gate 	    USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) {
26327c478bd9Sstevel@tonic-gate 		/* High speed interrupt transaction */
26337c478bd9Sstevel@tonic-gate 		*sbandwidth += HS_NON_ISOC_PROTO_OVERHEAD;
26347c478bd9Sstevel@tonic-gate 	} else {
26357c478bd9Sstevel@tonic-gate 		/* Isochronous transaction */
26367c478bd9Sstevel@tonic-gate 		*sbandwidth += HS_ISOC_PROTO_OVERHEAD;
26377c478bd9Sstevel@tonic-gate 	}
26387c478bd9Sstevel@tonic-gate 
26397c478bd9Sstevel@tonic-gate 	/*
26407c478bd9Sstevel@tonic-gate 	 * For low/full speed devices, add split transaction specific
26417c478bd9Sstevel@tonic-gate 	 * overheads.
26427c478bd9Sstevel@tonic-gate 	 */
26437c478bd9Sstevel@tonic-gate 	if (port_status != USBA_HIGH_SPEED_DEV) {
26447c478bd9Sstevel@tonic-gate 		/*
26457c478bd9Sstevel@tonic-gate 		 * Add start and complete split transaction
26467c478bd9Sstevel@tonic-gate 		 * tokens overheads.
26477c478bd9Sstevel@tonic-gate 		 */
26487c478bd9Sstevel@tonic-gate 		*cbandwidth = *sbandwidth + COMPLETE_SPLIT_OVERHEAD;
26497c478bd9Sstevel@tonic-gate 		*sbandwidth += START_SPLIT_OVERHEAD;
26507c478bd9Sstevel@tonic-gate 
26517c478bd9Sstevel@tonic-gate 		/* Add data overhead depending on data direction */
26527c478bd9Sstevel@tonic-gate 		if ((endpoint->bEndpointAddress &
26537c478bd9Sstevel@tonic-gate 		    USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
26547c478bd9Sstevel@tonic-gate 			*cbandwidth += maxpacketsize;
26557c478bd9Sstevel@tonic-gate 		} else {
26567c478bd9Sstevel@tonic-gate 			if ((endpoint->bmAttributes &
26577c478bd9Sstevel@tonic-gate 			    USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) {
26587c478bd9Sstevel@tonic-gate 				/* There is no compete splits for out */
26597c478bd9Sstevel@tonic-gate 				*cbandwidth = 0;
26607c478bd9Sstevel@tonic-gate 			}
26617c478bd9Sstevel@tonic-gate 			*sbandwidth += maxpacketsize;
26627c478bd9Sstevel@tonic-gate 		}
26637c478bd9Sstevel@tonic-gate 	} else {
26647c478bd9Sstevel@tonic-gate 		uint_t		xactions;
26657c478bd9Sstevel@tonic-gate 
26667c478bd9Sstevel@tonic-gate 		/* Get the max transactions per microframe */
26677c478bd9Sstevel@tonic-gate 		xactions = ((maxpacketsize & USB_EP_MAX_XACTS_MASK) >>
26687c478bd9Sstevel@tonic-gate 		    USB_EP_MAX_XACTS_SHIFT) + 1;
26697c478bd9Sstevel@tonic-gate 
26707c478bd9Sstevel@tonic-gate 		/* High speed transaction */
26717c478bd9Sstevel@tonic-gate 		*sbandwidth += maxpacketsize;
26727c478bd9Sstevel@tonic-gate 
26737c478bd9Sstevel@tonic-gate 		/* Calculate bandwidth per micro-frame */
26747c478bd9Sstevel@tonic-gate 		*sbandwidth *= xactions;
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate 		*cbandwidth = 0;
26777c478bd9Sstevel@tonic-gate 	}
26787c478bd9Sstevel@tonic-gate 
26797c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
26807c478bd9Sstevel@tonic-gate 	    "ehci_allocate_high_speed_bandwidth: "
26817c478bd9Sstevel@tonic-gate 	    "Start split bandwidth %d Complete split bandwidth %d",
26827c478bd9Sstevel@tonic-gate 	    *sbandwidth, *cbandwidth);
26837c478bd9Sstevel@tonic-gate 
26847c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
26857c478bd9Sstevel@tonic-gate }
26867c478bd9Sstevel@tonic-gate 
26877c478bd9Sstevel@tonic-gate 
26887c478bd9Sstevel@tonic-gate /*
26897c478bd9Sstevel@tonic-gate  * ehci_compute_classic_bandwidth:
26907c478bd9Sstevel@tonic-gate  *
26917c478bd9Sstevel@tonic-gate  * Given a periodic endpoint (interrupt or isochronous) determine the total
26927c478bd9Sstevel@tonic-gate  * bandwidth for one transaction. The EHCI host controller traverses the
26937c478bd9Sstevel@tonic-gate  * endpoint descriptor lists on a first-come-first-serve basis. When the HC
26947c478bd9Sstevel@tonic-gate  * services an endpoint, only a single transaction attempt is made. The  HC
26957c478bd9Sstevel@tonic-gate  * moves to the next Endpoint Descriptor after the first transaction attempt
26967c478bd9Sstevel@tonic-gate  * rather than finishing the entire Transfer Descriptor. Therefore, when  a
26977c478bd9Sstevel@tonic-gate  * Transfer Descriptor is inserted into the lattice, we will only count the
26987c478bd9Sstevel@tonic-gate  * number of bytes for one transaction.
26997c478bd9Sstevel@tonic-gate  *
27007c478bd9Sstevel@tonic-gate  * The following are the formulas used for  calculating bandwidth in  terms
27017c478bd9Sstevel@tonic-gate  * bytes and it is for the single USB high speed transaction.  The protocol
27027c478bd9Sstevel@tonic-gate  * overheads will be different for each of type of USB transfer & all these
27037c478bd9Sstevel@tonic-gate  * formulas & protocol overheads are derived from the 5.11.3 section of the
27047c478bd9Sstevel@tonic-gate  * USB 2.0 Specification.
27057c478bd9Sstevel@tonic-gate  *
27067c478bd9Sstevel@tonic-gate  * Low-Speed:
27077c478bd9Sstevel@tonic-gate  *		Protocol overhead + Hub LS overhead +
27087c478bd9Sstevel@tonic-gate  *		(Low Speed clock * ((MaxPktSz * 7)/6)) + TT_Delay
27097c478bd9Sstevel@tonic-gate  *
27107c478bd9Sstevel@tonic-gate  * Full-Speed:
27117c478bd9Sstevel@tonic-gate  *		Protocol overhead + ((MaxPktSz * 7)/6) + TT_Delay
27127c478bd9Sstevel@tonic-gate  */
27137c478bd9Sstevel@tonic-gate /* ARGSUSED */
27147c478bd9Sstevel@tonic-gate static int
27157c478bd9Sstevel@tonic-gate ehci_compute_classic_bandwidth(
27167c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint,
27177c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status,
27187c478bd9Sstevel@tonic-gate 	uint_t			*bandwidth)
27197c478bd9Sstevel@tonic-gate {
27207c478bd9Sstevel@tonic-gate 	ushort_t		maxpacketsize = endpoint->wMaxPacketSize;
27217c478bd9Sstevel@tonic-gate 
27227c478bd9Sstevel@tonic-gate 	/*
27237c478bd9Sstevel@tonic-gate 	 * If endpoint maximum packet is zero, then return immediately.
27247c478bd9Sstevel@tonic-gate 	 */
27257c478bd9Sstevel@tonic-gate 	if (maxpacketsize == 0) {
27267c478bd9Sstevel@tonic-gate 
27277c478bd9Sstevel@tonic-gate 		return (USB_NOT_SUPPORTED);
27287c478bd9Sstevel@tonic-gate 	}
27297c478bd9Sstevel@tonic-gate 
27307c478bd9Sstevel@tonic-gate 	/* Add TT delay to required bandwidth */
27317c478bd9Sstevel@tonic-gate 	*bandwidth = TT_DELAY;
27327c478bd9Sstevel@tonic-gate 
27337c478bd9Sstevel@tonic-gate 	/* Add bit-stuffing overhead */
27347c478bd9Sstevel@tonic-gate 	maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6);
27357c478bd9Sstevel@tonic-gate 
27367c478bd9Sstevel@tonic-gate 	switch (port_status) {
27377c478bd9Sstevel@tonic-gate 	case USBA_LOW_SPEED_DEV:
27387c478bd9Sstevel@tonic-gate 		/* Low speed interrupt transaction */
27397c478bd9Sstevel@tonic-gate 		*bandwidth += (LOW_SPEED_PROTO_OVERHEAD +
27407c478bd9Sstevel@tonic-gate 		    HUB_LOW_SPEED_PROTO_OVERHEAD +
27417c478bd9Sstevel@tonic-gate 		    (LOW_SPEED_CLOCK * maxpacketsize));
27427c478bd9Sstevel@tonic-gate 		break;
27437c478bd9Sstevel@tonic-gate 	case USBA_FULL_SPEED_DEV:
27447c478bd9Sstevel@tonic-gate 		/* Full speed transaction */
27457c478bd9Sstevel@tonic-gate 		*bandwidth += maxpacketsize;
27467c478bd9Sstevel@tonic-gate 
27477c478bd9Sstevel@tonic-gate 		/* Add xfer specific protocol overheads */
27487c478bd9Sstevel@tonic-gate 		if ((endpoint->bmAttributes &
27497c478bd9Sstevel@tonic-gate 		    USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) {
27507c478bd9Sstevel@tonic-gate 			/* Full speed interrupt transaction */
27517c478bd9Sstevel@tonic-gate 			*bandwidth += FS_NON_ISOC_PROTO_OVERHEAD;
27527c478bd9Sstevel@tonic-gate 		} else {
27537c478bd9Sstevel@tonic-gate 			/* Isochronous and input transaction */
27547c478bd9Sstevel@tonic-gate 			if ((endpoint->bEndpointAddress &
27557c478bd9Sstevel@tonic-gate 			    USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
27567c478bd9Sstevel@tonic-gate 				*bandwidth += FS_ISOC_INPUT_PROTO_OVERHEAD;
27577c478bd9Sstevel@tonic-gate 			} else {
27587c478bd9Sstevel@tonic-gate 				/* Isochronous and output transaction */
27597c478bd9Sstevel@tonic-gate 				*bandwidth += FS_ISOC_OUTPUT_PROTO_OVERHEAD;
27607c478bd9Sstevel@tonic-gate 			}
27617c478bd9Sstevel@tonic-gate 		}
27627c478bd9Sstevel@tonic-gate 		break;
27637c478bd9Sstevel@tonic-gate 	}
27647c478bd9Sstevel@tonic-gate 
27657c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
27667c478bd9Sstevel@tonic-gate }
27677c478bd9Sstevel@tonic-gate 
27687c478bd9Sstevel@tonic-gate 
27697c478bd9Sstevel@tonic-gate /*
27707c478bd9Sstevel@tonic-gate  * ehci_adjust_polling_interval:
27717c478bd9Sstevel@tonic-gate  *
27727c478bd9Sstevel@tonic-gate  * Adjust bandwidth according usb device speed.
27737c478bd9Sstevel@tonic-gate  */
27747c478bd9Sstevel@tonic-gate /* ARGSUSED */
27757c478bd9Sstevel@tonic-gate int
27767c478bd9Sstevel@tonic-gate ehci_adjust_polling_interval(
27777c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
27787c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint,
27797c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status)
27807c478bd9Sstevel@tonic-gate {
27817c478bd9Sstevel@tonic-gate 	uint_t			interval;
27827c478bd9Sstevel@tonic-gate 	int			i = 0;
27837c478bd9Sstevel@tonic-gate 
27847c478bd9Sstevel@tonic-gate 	/* Get the polling interval */
27857c478bd9Sstevel@tonic-gate 	interval = endpoint->bInterval;
27867c478bd9Sstevel@tonic-gate 
27877c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
27887c478bd9Sstevel@tonic-gate 	    "ehci_adjust_polling_interval: Polling interval 0x%x", interval);
27897c478bd9Sstevel@tonic-gate 
27907c478bd9Sstevel@tonic-gate 	/*
27917c478bd9Sstevel@tonic-gate 	 * According USB 2.0 Specifications, a high-speed endpoint's
27927c478bd9Sstevel@tonic-gate 	 * polling intervals are specified interms of 125us or micro
27937c478bd9Sstevel@tonic-gate 	 * frame, where as full/low endpoint's polling intervals are
27947c478bd9Sstevel@tonic-gate 	 * specified in milliseconds.
27957c478bd9Sstevel@tonic-gate 	 *
27967c478bd9Sstevel@tonic-gate 	 * A high speed interrupt/isochronous endpoints can specify
27977c478bd9Sstevel@tonic-gate 	 * desired polling interval between 1 to 16 micro-frames,
27987c478bd9Sstevel@tonic-gate 	 * where as full/low endpoints can specify between 1 to 255
27997c478bd9Sstevel@tonic-gate 	 * milliseconds.
28007c478bd9Sstevel@tonic-gate 	 */
28017c478bd9Sstevel@tonic-gate 	switch (port_status) {
28027c478bd9Sstevel@tonic-gate 	case USBA_LOW_SPEED_DEV:
28037c478bd9Sstevel@tonic-gate 		/*
28047c478bd9Sstevel@tonic-gate 		 * Low speed  endpoints are limited to	specifying
28057c478bd9Sstevel@tonic-gate 		 * only 8ms to 255ms in this driver. If a device
28067c478bd9Sstevel@tonic-gate 		 * reports a polling interval that is less than 8ms,
28077c478bd9Sstevel@tonic-gate 		 * it will use 8 ms instead.
28087c478bd9Sstevel@tonic-gate 		 */
28097c478bd9Sstevel@tonic-gate 		if (interval < LS_MIN_POLL_INTERVAL) {
28107c478bd9Sstevel@tonic-gate 
28117c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
28127c478bd9Sstevel@tonic-gate 			    "Low speed endpoint's poll interval of %d ms "
28137c478bd9Sstevel@tonic-gate 			    "is below threshold. Rounding up to %d ms",
28147c478bd9Sstevel@tonic-gate 			    interval, LS_MIN_POLL_INTERVAL);
28157c478bd9Sstevel@tonic-gate 
28167c478bd9Sstevel@tonic-gate 			interval = LS_MIN_POLL_INTERVAL;
28177c478bd9Sstevel@tonic-gate 		}
28187c478bd9Sstevel@tonic-gate 
28197c478bd9Sstevel@tonic-gate 		/*
28207c478bd9Sstevel@tonic-gate 		 * Return an error if the polling interval is greater
28217c478bd9Sstevel@tonic-gate 		 * than 255ms.
28227c478bd9Sstevel@tonic-gate 		 */
28237c478bd9Sstevel@tonic-gate 		if (interval > LS_MAX_POLL_INTERVAL) {
28247c478bd9Sstevel@tonic-gate 
28257c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
28267c478bd9Sstevel@tonic-gate 			    "Low speed endpoint's poll interval is "
28277c478bd9Sstevel@tonic-gate 			    "greater than %d ms", LS_MAX_POLL_INTERVAL);
28287c478bd9Sstevel@tonic-gate 
28297c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
28307c478bd9Sstevel@tonic-gate 		}
28317c478bd9Sstevel@tonic-gate 		break;
28327c478bd9Sstevel@tonic-gate 
28337c478bd9Sstevel@tonic-gate 	case USBA_FULL_SPEED_DEV:
28347c478bd9Sstevel@tonic-gate 		/*
28357c478bd9Sstevel@tonic-gate 		 * Return an error if the polling interval is less
28367c478bd9Sstevel@tonic-gate 		 * than 1ms and greater than 255ms.
28377c478bd9Sstevel@tonic-gate 		 */
28387c478bd9Sstevel@tonic-gate 		if ((interval < FS_MIN_POLL_INTERVAL) &&
28397c478bd9Sstevel@tonic-gate 		    (interval > FS_MAX_POLL_INTERVAL)) {
28407c478bd9Sstevel@tonic-gate 
28417c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
28427c478bd9Sstevel@tonic-gate 			    "Full speed endpoint's poll interval must "
28437c478bd9Sstevel@tonic-gate 			    "be between %d and %d ms", FS_MIN_POLL_INTERVAL,
28447c478bd9Sstevel@tonic-gate 			    FS_MAX_POLL_INTERVAL);
28457c478bd9Sstevel@tonic-gate 
28467c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
28477c478bd9Sstevel@tonic-gate 		}
28487c478bd9Sstevel@tonic-gate 		break;
28497c478bd9Sstevel@tonic-gate 	case USBA_HIGH_SPEED_DEV:
28507c478bd9Sstevel@tonic-gate 		/*
28517c478bd9Sstevel@tonic-gate 		 * Return an error if the polling interval is less 1
28527c478bd9Sstevel@tonic-gate 		 * and greater than 16. Convert this value to 125us
28537c478bd9Sstevel@tonic-gate 		 * units using 2^(bInterval -1). refer usb 2.0 spec
28547c478bd9Sstevel@tonic-gate 		 * page 51 for details.
28557c478bd9Sstevel@tonic-gate 		 */
28567c478bd9Sstevel@tonic-gate 		if ((interval < HS_MIN_POLL_INTERVAL) &&
28577c478bd9Sstevel@tonic-gate 		    (interval > HS_MAX_POLL_INTERVAL)) {
28587c478bd9Sstevel@tonic-gate 
28597c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
28607c478bd9Sstevel@tonic-gate 			    "High speed endpoint's poll interval "
28617c478bd9Sstevel@tonic-gate 			    "must be between %d and %d units",
28627c478bd9Sstevel@tonic-gate 			    HS_MIN_POLL_INTERVAL, HS_MAX_POLL_INTERVAL);
28637c478bd9Sstevel@tonic-gate 
28647c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
28657c478bd9Sstevel@tonic-gate 		}
28667c478bd9Sstevel@tonic-gate 
28677c478bd9Sstevel@tonic-gate 		/* Adjust high speed device polling interval */
28687c478bd9Sstevel@tonic-gate 		interval =
28697c478bd9Sstevel@tonic-gate 		    ehci_adjust_high_speed_polling_interval(ehcip, endpoint);
28707c478bd9Sstevel@tonic-gate 
28717c478bd9Sstevel@tonic-gate 		break;
28727c478bd9Sstevel@tonic-gate 	}
28737c478bd9Sstevel@tonic-gate 
28747c478bd9Sstevel@tonic-gate 	/*
28757c478bd9Sstevel@tonic-gate 	 * If polling interval is greater than 32ms,
28767c478bd9Sstevel@tonic-gate 	 * adjust polling interval equal to 32ms.
28777c478bd9Sstevel@tonic-gate 	 */
28787c478bd9Sstevel@tonic-gate 	if (interval > EHCI_NUM_INTR_QH_LISTS) {
28797c478bd9Sstevel@tonic-gate 		interval = EHCI_NUM_INTR_QH_LISTS;
28807c478bd9Sstevel@tonic-gate 	}
28817c478bd9Sstevel@tonic-gate 
28827c478bd9Sstevel@tonic-gate 	/*
28837c478bd9Sstevel@tonic-gate 	 * Find the nearest power of 2 that's less
28847c478bd9Sstevel@tonic-gate 	 * than interval.
28857c478bd9Sstevel@tonic-gate 	 */
28867c478bd9Sstevel@tonic-gate 	while ((ehci_pow_2(i)) <= interval) {
28877c478bd9Sstevel@tonic-gate 		i++;
28887c478bd9Sstevel@tonic-gate 	}
28897c478bd9Sstevel@tonic-gate 
28907c478bd9Sstevel@tonic-gate 	return (ehci_pow_2((i - 1)));
28917c478bd9Sstevel@tonic-gate }
28927c478bd9Sstevel@tonic-gate 
28937c478bd9Sstevel@tonic-gate 
28947c478bd9Sstevel@tonic-gate /*
28957c478bd9Sstevel@tonic-gate  * ehci_adjust_high_speed_polling_interval:
28967c478bd9Sstevel@tonic-gate  */
28977c478bd9Sstevel@tonic-gate /* ARGSUSED */
28987c478bd9Sstevel@tonic-gate static int
28997c478bd9Sstevel@tonic-gate ehci_adjust_high_speed_polling_interval(
29007c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
29017c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint)
29027c478bd9Sstevel@tonic-gate {
29037c478bd9Sstevel@tonic-gate 	uint_t			interval;
29047c478bd9Sstevel@tonic-gate 
29057c478bd9Sstevel@tonic-gate 	/* Get the polling interval */
29067c478bd9Sstevel@tonic-gate 	interval = ehci_pow_2(endpoint->bInterval - 1);
29077c478bd9Sstevel@tonic-gate 
29087c478bd9Sstevel@tonic-gate 	/*
29097c478bd9Sstevel@tonic-gate 	 * Convert polling interval from micro seconds
29107c478bd9Sstevel@tonic-gate 	 * to milli seconds.
29117c478bd9Sstevel@tonic-gate 	 */
29127c478bd9Sstevel@tonic-gate 	if (interval <= EHCI_MAX_UFRAMES) {
29137c478bd9Sstevel@tonic-gate 		interval = 1;
29147c478bd9Sstevel@tonic-gate 	} else {
29157c478bd9Sstevel@tonic-gate 		interval = interval/EHCI_MAX_UFRAMES;
29167c478bd9Sstevel@tonic-gate 	}
29177c478bd9Sstevel@tonic-gate 
29187c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
29197c478bd9Sstevel@tonic-gate 	    "ehci_adjust_high_speed_polling_interval: "
29207c478bd9Sstevel@tonic-gate 	    "High speed adjusted interval 0x%x", interval);
29217c478bd9Sstevel@tonic-gate 
29227c478bd9Sstevel@tonic-gate 	return (interval);
29237c478bd9Sstevel@tonic-gate }
29247c478bd9Sstevel@tonic-gate 
29257c478bd9Sstevel@tonic-gate 
29267c478bd9Sstevel@tonic-gate /*
29277c478bd9Sstevel@tonic-gate  * ehci_lattice_height:
29287c478bd9Sstevel@tonic-gate  *
29297c478bd9Sstevel@tonic-gate  * Given the requested bandwidth, find the height in the tree at which the
29307c478bd9Sstevel@tonic-gate  * nodes for this bandwidth fall.  The height is measured as the number of
29317c478bd9Sstevel@tonic-gate  * nodes from the leaf to the level specified by bandwidth The root of the
29327c478bd9Sstevel@tonic-gate  * tree is at height TREE_HEIGHT.
29337c478bd9Sstevel@tonic-gate  */
29347c478bd9Sstevel@tonic-gate static uint_t
29357c478bd9Sstevel@tonic-gate ehci_lattice_height(uint_t interval)
29367c478bd9Sstevel@tonic-gate {
29377c478bd9Sstevel@tonic-gate 	return (TREE_HEIGHT - (ehci_log_2(interval)));
29387c478bd9Sstevel@tonic-gate }
29397c478bd9Sstevel@tonic-gate 
29407c478bd9Sstevel@tonic-gate 
29417c478bd9Sstevel@tonic-gate /*
29427c478bd9Sstevel@tonic-gate  * ehci_lattice_parent:
29437c478bd9Sstevel@tonic-gate  *
29447c478bd9Sstevel@tonic-gate  * Given a node in the lattice, find the index of the parent node
29457c478bd9Sstevel@tonic-gate  */
29467c478bd9Sstevel@tonic-gate static uint_t
29477c478bd9Sstevel@tonic-gate ehci_lattice_parent(uint_t node)
29487c478bd9Sstevel@tonic-gate {
29497c478bd9Sstevel@tonic-gate 	if ((node % 2) == 0) {
29507c478bd9Sstevel@tonic-gate 
29517c478bd9Sstevel@tonic-gate 		return ((node/2) - 1);
29527c478bd9Sstevel@tonic-gate 	} else {
29537c478bd9Sstevel@tonic-gate 
29547c478bd9Sstevel@tonic-gate 		return ((node + 1)/2 - 1);
29557c478bd9Sstevel@tonic-gate 	}
29567c478bd9Sstevel@tonic-gate }
29577c478bd9Sstevel@tonic-gate 
29587c478bd9Sstevel@tonic-gate 
29597c478bd9Sstevel@tonic-gate /*
29607c478bd9Sstevel@tonic-gate  * ehci_find_periodic_node:
29617c478bd9Sstevel@tonic-gate  *
29627c478bd9Sstevel@tonic-gate  * Based on the "real" array leaf node and interval, get the periodic node.
29637c478bd9Sstevel@tonic-gate  */
29647c478bd9Sstevel@tonic-gate static uint_t
29657c478bd9Sstevel@tonic-gate ehci_find_periodic_node(uint_t leaf, int interval) {
29667c478bd9Sstevel@tonic-gate 	uint_t	lattice_leaf;
29677c478bd9Sstevel@tonic-gate 	uint_t	height = ehci_lattice_height(interval);
29687c478bd9Sstevel@tonic-gate 	uint_t	pnode;
29697c478bd9Sstevel@tonic-gate 	int	i;
29707c478bd9Sstevel@tonic-gate 
29717c478bd9Sstevel@tonic-gate 	/* Get the leaf number in the lattice */
29727c478bd9Sstevel@tonic-gate 	lattice_leaf = leaf + EHCI_NUM_INTR_QH_LISTS - 1;
29737c478bd9Sstevel@tonic-gate 
29747c478bd9Sstevel@tonic-gate 	/* Get the node in the lattice based on the height and leaf */
29757c478bd9Sstevel@tonic-gate 	pnode = lattice_leaf;
29767c478bd9Sstevel@tonic-gate 	for (i = 0; i < height; i++) {
29777c478bd9Sstevel@tonic-gate 		pnode = ehci_lattice_parent(pnode);
29787c478bd9Sstevel@tonic-gate 	}
29797c478bd9Sstevel@tonic-gate 
29807c478bd9Sstevel@tonic-gate 	return (pnode);
29817c478bd9Sstevel@tonic-gate }
29827c478bd9Sstevel@tonic-gate 
29837c478bd9Sstevel@tonic-gate 
29847c478bd9Sstevel@tonic-gate /*
29857c478bd9Sstevel@tonic-gate  * ehci_leftmost_leaf:
29867c478bd9Sstevel@tonic-gate  *
29877c478bd9Sstevel@tonic-gate  * Find the leftmost leaf in the subtree specified by the node. Height refers
29887c478bd9Sstevel@tonic-gate  * to number of nodes from the bottom of the tree to the node,	including the
29897c478bd9Sstevel@tonic-gate  * node.
29907c478bd9Sstevel@tonic-gate  *
29917c478bd9Sstevel@tonic-gate  * The formula for a zero based tree is:
29927c478bd9Sstevel@tonic-gate  *     2^H * Node + 2^H - 1
29937c478bd9Sstevel@tonic-gate  * The leaf of the tree is an array, convert the number for the array.
29947c478bd9Sstevel@tonic-gate  *     Subtract the size of nodes not in the array
29957c478bd9Sstevel@tonic-gate  *     2^H * Node + 2^H - 1 - (EHCI_NUM_INTR_QH_LISTS - 1) =
29967c478bd9Sstevel@tonic-gate  *     2^H * Node + 2^H - EHCI_NUM_INTR_QH_LISTS =
29977c478bd9Sstevel@tonic-gate  *     2^H * (Node + 1) - EHCI_NUM_INTR_QH_LISTS
29987c478bd9Sstevel@tonic-gate  *	   0
29997c478bd9Sstevel@tonic-gate  *	 1   2
30007c478bd9Sstevel@tonic-gate  *	0 1 2 3
30017c478bd9Sstevel@tonic-gate  */
30027c478bd9Sstevel@tonic-gate static uint_t
30037c478bd9Sstevel@tonic-gate ehci_leftmost_leaf(
30047c478bd9Sstevel@tonic-gate 	uint_t	node,
30057c478bd9Sstevel@tonic-gate 	uint_t	height)
30067c478bd9Sstevel@tonic-gate {
30077c478bd9Sstevel@tonic-gate 	return ((ehci_pow_2(height) * (node + 1)) - EHCI_NUM_INTR_QH_LISTS);
30087c478bd9Sstevel@tonic-gate }
30097c478bd9Sstevel@tonic-gate 
30107c478bd9Sstevel@tonic-gate 
30117c478bd9Sstevel@tonic-gate /*
30127c478bd9Sstevel@tonic-gate  * ehci_pow_2:
30137c478bd9Sstevel@tonic-gate  *
30147c478bd9Sstevel@tonic-gate  * Compute 2 to the power
30157c478bd9Sstevel@tonic-gate  */
30167c478bd9Sstevel@tonic-gate static uint_t
30177c478bd9Sstevel@tonic-gate ehci_pow_2(uint_t x)
30187c478bd9Sstevel@tonic-gate {
30197c478bd9Sstevel@tonic-gate 	if (x == 0) {
30207c478bd9Sstevel@tonic-gate 
30217c478bd9Sstevel@tonic-gate 		return (1);
30227c478bd9Sstevel@tonic-gate 	} else {
30237c478bd9Sstevel@tonic-gate 
30247c478bd9Sstevel@tonic-gate 		return (2 << (x - 1));
30257c478bd9Sstevel@tonic-gate 	}
30267c478bd9Sstevel@tonic-gate }
30277c478bd9Sstevel@tonic-gate 
30287c478bd9Sstevel@tonic-gate 
30297c478bd9Sstevel@tonic-gate /*
30307c478bd9Sstevel@tonic-gate  * ehci_log_2:
30317c478bd9Sstevel@tonic-gate  *
30327c478bd9Sstevel@tonic-gate  * Compute log base 2 of x
30337c478bd9Sstevel@tonic-gate  */
30347c478bd9Sstevel@tonic-gate static uint_t
30357c478bd9Sstevel@tonic-gate ehci_log_2(uint_t x)
30367c478bd9Sstevel@tonic-gate {
30377c478bd9Sstevel@tonic-gate 	int i = 0;
30387c478bd9Sstevel@tonic-gate 
30397c478bd9Sstevel@tonic-gate 	while (x != 1) {
30407c478bd9Sstevel@tonic-gate 		x = x >> 1;
30417c478bd9Sstevel@tonic-gate 		i++;
30427c478bd9Sstevel@tonic-gate 	}
30437c478bd9Sstevel@tonic-gate 
30447c478bd9Sstevel@tonic-gate 	return (i);
30457c478bd9Sstevel@tonic-gate }
30467c478bd9Sstevel@tonic-gate 
30477c478bd9Sstevel@tonic-gate 
30487c478bd9Sstevel@tonic-gate /*
30497c478bd9Sstevel@tonic-gate  * ehci_find_bestfit_hs_mask:
30507c478bd9Sstevel@tonic-gate  *
30517c478bd9Sstevel@tonic-gate  * Find the smask and cmask in the bandwidth allocation, and update the
30527c478bd9Sstevel@tonic-gate  * bandwidth allocation.
30537c478bd9Sstevel@tonic-gate  */
30547c478bd9Sstevel@tonic-gate static int
30557c478bd9Sstevel@tonic-gate ehci_find_bestfit_hs_mask(
30567c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
30577c478bd9Sstevel@tonic-gate 	uchar_t		*smask,
30587c478bd9Sstevel@tonic-gate 	uint_t		*pnode,
30597c478bd9Sstevel@tonic-gate 	usb_ep_descr_t	*endpoint,
30607c478bd9Sstevel@tonic-gate 	uint_t		bandwidth,
30617c478bd9Sstevel@tonic-gate 	int		interval)
30627c478bd9Sstevel@tonic-gate {
30637c478bd9Sstevel@tonic-gate 	int		i;
30647c478bd9Sstevel@tonic-gate 	uint_t		elements, index;
30657c478bd9Sstevel@tonic-gate 	int		array_leaf, best_array_leaf;
30667c478bd9Sstevel@tonic-gate 	uint_t		node_bandwidth, best_node_bandwidth;
30677c478bd9Sstevel@tonic-gate 	uint_t		leaf_count;
30687c478bd9Sstevel@tonic-gate 	uchar_t		bw_mask;
30697c478bd9Sstevel@tonic-gate 	uchar_t		best_smask;
30707c478bd9Sstevel@tonic-gate 
30717c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
30727c478bd9Sstevel@tonic-gate 	    "ehci_find_bestfit_hs_mask: ");
30737c478bd9Sstevel@tonic-gate 
30747c478bd9Sstevel@tonic-gate 	/* Get all the valid smasks */
30757c478bd9Sstevel@tonic-gate 	switch (ehci_pow_2(endpoint->bInterval - 1)) {
30767c478bd9Sstevel@tonic-gate 	case EHCI_INTR_1US_POLL:
30777c478bd9Sstevel@tonic-gate 		index = EHCI_1US_MASK_INDEX;
30787c478bd9Sstevel@tonic-gate 		elements = EHCI_INTR_1US_POLL;
30797c478bd9Sstevel@tonic-gate 		break;
30807c478bd9Sstevel@tonic-gate 	case EHCI_INTR_2US_POLL:
30817c478bd9Sstevel@tonic-gate 		index = EHCI_2US_MASK_INDEX;
30827c478bd9Sstevel@tonic-gate 		elements = EHCI_INTR_2US_POLL;
30837c478bd9Sstevel@tonic-gate 		break;
30847c478bd9Sstevel@tonic-gate 	case EHCI_INTR_4US_POLL:
30857c478bd9Sstevel@tonic-gate 		index = EHCI_4US_MASK_INDEX;
30867c478bd9Sstevel@tonic-gate 		elements = EHCI_INTR_4US_POLL;
30877c478bd9Sstevel@tonic-gate 		break;
30887c478bd9Sstevel@tonic-gate 	case EHCI_INTR_XUS_POLL:
30897c478bd9Sstevel@tonic-gate 	default:
30907c478bd9Sstevel@tonic-gate 		index = EHCI_XUS_MASK_INDEX;
30917c478bd9Sstevel@tonic-gate 		elements = EHCI_INTR_XUS_POLL;
30927c478bd9Sstevel@tonic-gate 		break;
30937c478bd9Sstevel@tonic-gate 	}
30947c478bd9Sstevel@tonic-gate 
30957c478bd9Sstevel@tonic-gate 	leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
30967c478bd9Sstevel@tonic-gate 
30977c478bd9Sstevel@tonic-gate 	/*
30987c478bd9Sstevel@tonic-gate 	 * Because of the way the leaves are setup, we will automatically
30997c478bd9Sstevel@tonic-gate 	 * hit the leftmost leaf of every possible node with this interval.
31007c478bd9Sstevel@tonic-gate 	 */
31017c478bd9Sstevel@tonic-gate 	best_smask = 0x00;
31027c478bd9Sstevel@tonic-gate 	best_node_bandwidth = 0;
31037c478bd9Sstevel@tonic-gate 	for (array_leaf = 0; array_leaf < interval; array_leaf++) {
31047c478bd9Sstevel@tonic-gate 		/* Find the bandwidth mask */
31057c478bd9Sstevel@tonic-gate 		node_bandwidth = ehci_calculate_bw_availability_mask(ehcip,
31067c478bd9Sstevel@tonic-gate 		    bandwidth, ehci_index[array_leaf], leaf_count, &bw_mask);
31077c478bd9Sstevel@tonic-gate 
31087c478bd9Sstevel@tonic-gate 		/*
31097c478bd9Sstevel@tonic-gate 		 * If this node cannot support our requirements skip to the
31107c478bd9Sstevel@tonic-gate 		 * next leaf.
31117c478bd9Sstevel@tonic-gate 		 */
31127c478bd9Sstevel@tonic-gate 		if (bw_mask == 0x00) {
31137c478bd9Sstevel@tonic-gate 			continue;
31147c478bd9Sstevel@tonic-gate 		}
31157c478bd9Sstevel@tonic-gate 
31167c478bd9Sstevel@tonic-gate 		/*
31177c478bd9Sstevel@tonic-gate 		 * Now make sure our bandwidth requirements can be
31187c478bd9Sstevel@tonic-gate 		 * satisfied with one of smasks in this node.
31197c478bd9Sstevel@tonic-gate 		 */
31207c478bd9Sstevel@tonic-gate 		*smask = 0x00;
31217c478bd9Sstevel@tonic-gate 		for (i = index; i < (index + elements); i++) {
31227c478bd9Sstevel@tonic-gate 			/* Check the start split mask value */
31237c478bd9Sstevel@tonic-gate 			if (ehci_start_split_mask[index] & bw_mask) {
31247c478bd9Sstevel@tonic-gate 				*smask = ehci_start_split_mask[index];
31257c478bd9Sstevel@tonic-gate 				break;
31267c478bd9Sstevel@tonic-gate 			}
31277c478bd9Sstevel@tonic-gate 		}
31287c478bd9Sstevel@tonic-gate 
31297c478bd9Sstevel@tonic-gate 		/*
31307c478bd9Sstevel@tonic-gate 		 * If an appropriate smask is found save the information if:
31317c478bd9Sstevel@tonic-gate 		 * o best_smask has not been found yet.
31327c478bd9Sstevel@tonic-gate 		 * - or -
31337c478bd9Sstevel@tonic-gate 		 * o This is the node with the least amount of bandwidth
31347c478bd9Sstevel@tonic-gate 		 */
31357c478bd9Sstevel@tonic-gate 		if ((*smask != 0x00) &&
31367c478bd9Sstevel@tonic-gate 		    ((best_smask == 0x00) ||
313729aca3ebSlc 		    (best_node_bandwidth > node_bandwidth))) {
31387c478bd9Sstevel@tonic-gate 
31397c478bd9Sstevel@tonic-gate 			best_node_bandwidth = node_bandwidth;
31407c478bd9Sstevel@tonic-gate 			best_array_leaf = array_leaf;
31417c478bd9Sstevel@tonic-gate 			best_smask = *smask;
31427c478bd9Sstevel@tonic-gate 		}
31437c478bd9Sstevel@tonic-gate 	}
31447c478bd9Sstevel@tonic-gate 
31457c478bd9Sstevel@tonic-gate 	/*
31467c478bd9Sstevel@tonic-gate 	 * If we find node that can handle the bandwidth populate the
31477c478bd9Sstevel@tonic-gate 	 * appropriate variables and return success.
31487c478bd9Sstevel@tonic-gate 	 */
31497c478bd9Sstevel@tonic-gate 	if (best_smask) {
31507c478bd9Sstevel@tonic-gate 		*smask = best_smask;
31517c478bd9Sstevel@tonic-gate 		*pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
31527c478bd9Sstevel@tonic-gate 		    interval);
31537c478bd9Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, bandwidth,
31547c478bd9Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_smask);
31557c478bd9Sstevel@tonic-gate 
31567c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
31577c478bd9Sstevel@tonic-gate 	}
31587c478bd9Sstevel@tonic-gate 
31597c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
31607c478bd9Sstevel@tonic-gate }
31617c478bd9Sstevel@tonic-gate 
31627c478bd9Sstevel@tonic-gate 
31637c478bd9Sstevel@tonic-gate /*
31647c478bd9Sstevel@tonic-gate  * ehci_find_bestfit_ls_intr_mask:
31657c478bd9Sstevel@tonic-gate  *
31667c478bd9Sstevel@tonic-gate  * Find the smask and cmask in the bandwidth allocation.
31677c478bd9Sstevel@tonic-gate  */
31687c478bd9Sstevel@tonic-gate static int
31697c478bd9Sstevel@tonic-gate ehci_find_bestfit_ls_intr_mask(
31707c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
31717c478bd9Sstevel@tonic-gate 	uchar_t		*smask,
31727c478bd9Sstevel@tonic-gate 	uchar_t		*cmask,
31737c478bd9Sstevel@tonic-gate 	uint_t		*pnode,
31747c478bd9Sstevel@tonic-gate 	uint_t		sbandwidth,
31757c478bd9Sstevel@tonic-gate 	uint_t		cbandwidth,
31767c478bd9Sstevel@tonic-gate 	int		interval)
31777c478bd9Sstevel@tonic-gate {
31787c478bd9Sstevel@tonic-gate 	int		i;
31797c478bd9Sstevel@tonic-gate 	uint_t		elements, index;
31807c478bd9Sstevel@tonic-gate 	int		array_leaf, best_array_leaf;
31817c478bd9Sstevel@tonic-gate 	uint_t		node_sbandwidth, node_cbandwidth;
31827c478bd9Sstevel@tonic-gate 	uint_t		best_node_bandwidth;
31837c478bd9Sstevel@tonic-gate 	uint_t		leaf_count;
31847c478bd9Sstevel@tonic-gate 	uchar_t		bw_smask, bw_cmask;
31857c478bd9Sstevel@tonic-gate 	uchar_t		best_smask, best_cmask;
31867c478bd9Sstevel@tonic-gate 
31877c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
31887c478bd9Sstevel@tonic-gate 	    "ehci_find_bestfit_ls_intr_mask: ");
31897c478bd9Sstevel@tonic-gate 
31907c478bd9Sstevel@tonic-gate 	/* For low and full speed devices */
31917c478bd9Sstevel@tonic-gate 	index = EHCI_XUS_MASK_INDEX;
31927c478bd9Sstevel@tonic-gate 	elements = EHCI_INTR_4MS_POLL;
31937c478bd9Sstevel@tonic-gate 
31947c478bd9Sstevel@tonic-gate 	leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
31957c478bd9Sstevel@tonic-gate 
31967c478bd9Sstevel@tonic-gate 	/*
31977c478bd9Sstevel@tonic-gate 	 * Because of the way the leaves are setup, we will automatically
31987c478bd9Sstevel@tonic-gate 	 * hit the leftmost leaf of every possible node with this interval.
31997c478bd9Sstevel@tonic-gate 	 */
32007c478bd9Sstevel@tonic-gate 	best_smask = 0x00;
32017c478bd9Sstevel@tonic-gate 	best_node_bandwidth = 0;
32027c478bd9Sstevel@tonic-gate 	for (array_leaf = 0; array_leaf < interval; array_leaf++) {
32037c478bd9Sstevel@tonic-gate 		/* Find the bandwidth mask */
32047c478bd9Sstevel@tonic-gate 		node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip,
32057c478bd9Sstevel@tonic-gate 		    sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask);
32067c478bd9Sstevel@tonic-gate 		node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip,
32077c478bd9Sstevel@tonic-gate 		    cbandwidth, ehci_index[array_leaf], leaf_count, &bw_cmask);
32087c478bd9Sstevel@tonic-gate 
32097c478bd9Sstevel@tonic-gate 		/*
32107c478bd9Sstevel@tonic-gate 		 * If this node cannot support our requirements skip to the
32117c478bd9Sstevel@tonic-gate 		 * next leaf.
32127c478bd9Sstevel@tonic-gate 		 */
32137c478bd9Sstevel@tonic-gate 		if ((bw_smask == 0x00) || (bw_cmask == 0x00)) {
32147c478bd9Sstevel@tonic-gate 			continue;
32157c478bd9Sstevel@tonic-gate 		}
32167c478bd9Sstevel@tonic-gate 
32177c478bd9Sstevel@tonic-gate 		/*
32187c478bd9Sstevel@tonic-gate 		 * Now make sure our bandwidth requirements can be
32197c478bd9Sstevel@tonic-gate 		 * satisfied with one of smasks in this node.
32207c478bd9Sstevel@tonic-gate 		 */
32217c478bd9Sstevel@tonic-gate 		*smask = 0x00;
32227c478bd9Sstevel@tonic-gate 		*cmask = 0x00;
32237c478bd9Sstevel@tonic-gate 		for (i = index; i < (index + elements); i++) {
32247c478bd9Sstevel@tonic-gate 			/* Check the start split mask value */
32257c478bd9Sstevel@tonic-gate 			if ((ehci_start_split_mask[index] & bw_smask) &&
32267c478bd9Sstevel@tonic-gate 			    (ehci_intr_complete_split_mask[index] & bw_cmask)) {
32277c478bd9Sstevel@tonic-gate 				*smask = ehci_start_split_mask[index];
32287c478bd9Sstevel@tonic-gate 				*cmask = ehci_intr_complete_split_mask[index];
32297c478bd9Sstevel@tonic-gate 				break;
32307c478bd9Sstevel@tonic-gate 			}
32317c478bd9Sstevel@tonic-gate 		}
32327c478bd9Sstevel@tonic-gate 
32337c478bd9Sstevel@tonic-gate 		/*
32347c478bd9Sstevel@tonic-gate 		 * If an appropriate smask is found save the information if:
32357c478bd9Sstevel@tonic-gate 		 * o best_smask has not been found yet.
32367c478bd9Sstevel@tonic-gate 		 * - or -
32377c478bd9Sstevel@tonic-gate 		 * o This is the node with the least amount of bandwidth
32387c478bd9Sstevel@tonic-gate 		 */
32397c478bd9Sstevel@tonic-gate 		if ((*smask != 0x00) &&
32407c478bd9Sstevel@tonic-gate 		    ((best_smask == 0x00) ||
324129aca3ebSlc 		    (best_node_bandwidth >
324229aca3ebSlc 		    (node_sbandwidth + node_cbandwidth)))) {
32437c478bd9Sstevel@tonic-gate 			best_node_bandwidth = node_sbandwidth + node_cbandwidth;
32447c478bd9Sstevel@tonic-gate 			best_array_leaf = array_leaf;
32457c478bd9Sstevel@tonic-gate 			best_smask = *smask;
32467c478bd9Sstevel@tonic-gate 			best_cmask = *cmask;
32477c478bd9Sstevel@tonic-gate 		}
32487c478bd9Sstevel@tonic-gate 	}
32497c478bd9Sstevel@tonic-gate 
32507c478bd9Sstevel@tonic-gate 	/*
32517c478bd9Sstevel@tonic-gate 	 * If we find node that can handle the bandwidth populate the
32527c478bd9Sstevel@tonic-gate 	 * appropriate variables and return success.
32537c478bd9Sstevel@tonic-gate 	 */
32547c478bd9Sstevel@tonic-gate 	if (best_smask) {
32557c478bd9Sstevel@tonic-gate 		*smask = best_smask;
32567c478bd9Sstevel@tonic-gate 		*cmask = best_cmask;
32577c478bd9Sstevel@tonic-gate 		*pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
32587c478bd9Sstevel@tonic-gate 		    interval);
32597c478bd9Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, sbandwidth,
32607c478bd9Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_smask);
32617c478bd9Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, cbandwidth,
32627c478bd9Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_cmask);
32637c478bd9Sstevel@tonic-gate 
32647c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
32657c478bd9Sstevel@tonic-gate 	}
32667c478bd9Sstevel@tonic-gate 
32677c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
32687c478bd9Sstevel@tonic-gate }
32697c478bd9Sstevel@tonic-gate 
32707c478bd9Sstevel@tonic-gate 
32717c478bd9Sstevel@tonic-gate /*
32727c478bd9Sstevel@tonic-gate  * ehci_find_bestfit_sitd_in_mask:
32737c478bd9Sstevel@tonic-gate  *
32747c478bd9Sstevel@tonic-gate  * Find the smask and cmask in the bandwidth allocation.
32757c478bd9Sstevel@tonic-gate  */
32767c478bd9Sstevel@tonic-gate static int
32777c478bd9Sstevel@tonic-gate ehci_find_bestfit_sitd_in_mask(
32787c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
32797c478bd9Sstevel@tonic-gate 	uchar_t		*smask,
32807c478bd9Sstevel@tonic-gate 	uchar_t		*cmask,
32817c478bd9Sstevel@tonic-gate 	uint_t		*pnode,
32827c478bd9Sstevel@tonic-gate 	uint_t		sbandwidth,
32837c478bd9Sstevel@tonic-gate 	uint_t		cbandwidth,
32847c478bd9Sstevel@tonic-gate 	int		interval)
32857c478bd9Sstevel@tonic-gate {
32867c478bd9Sstevel@tonic-gate 	int		i, uFrames, found;
32877c478bd9Sstevel@tonic-gate 	int		array_leaf, best_array_leaf;
32887c478bd9Sstevel@tonic-gate 	uint_t		node_sbandwidth, node_cbandwidth;
32897c478bd9Sstevel@tonic-gate 	uint_t		best_node_bandwidth;
32907c478bd9Sstevel@tonic-gate 	uint_t		leaf_count;
32917c478bd9Sstevel@tonic-gate 	uchar_t		bw_smask, bw_cmask;
32927c478bd9Sstevel@tonic-gate 	uchar_t		best_smask, best_cmask;
32937c478bd9Sstevel@tonic-gate 
32947c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
32957c478bd9Sstevel@tonic-gate 	    "ehci_find_bestfit_sitd_in_mask: ");
32967c478bd9Sstevel@tonic-gate 
32977c478bd9Sstevel@tonic-gate 	leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
32987c478bd9Sstevel@tonic-gate 
32997c478bd9Sstevel@tonic-gate 	/*
33007c478bd9Sstevel@tonic-gate 	 * Because of the way the leaves are setup, we will automatically
33017c478bd9Sstevel@tonic-gate 	 * hit the leftmost leaf of every possible node with this interval.
33027c478bd9Sstevel@tonic-gate 	 * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame.
33037c478bd9Sstevel@tonic-gate 	 */
33047c478bd9Sstevel@tonic-gate 	/*
33057c478bd9Sstevel@tonic-gate 	 * Need to add an additional 2 uFrames, if the "L"ast
33067c478bd9Sstevel@tonic-gate 	 * complete split is before uFrame 6.  See section
33077c478bd9Sstevel@tonic-gate 	 * 11.8.4 in USB 2.0 Spec.  Currently we do not support
33087c478bd9Sstevel@tonic-gate 	 * the "Back Ptr" which means we support on IN of
33097c478bd9Sstevel@tonic-gate 	 * ~4*MAX_UFRAME_SITD_XFER bandwidth/
33107c478bd9Sstevel@tonic-gate 	 */
33117c478bd9Sstevel@tonic-gate 	uFrames = (cbandwidth / MAX_UFRAME_SITD_XFER) + 2;
33127c478bd9Sstevel@tonic-gate 	if (cbandwidth % MAX_UFRAME_SITD_XFER) {
33137c478bd9Sstevel@tonic-gate 		uFrames++;
33147c478bd9Sstevel@tonic-gate 	}
33157c478bd9Sstevel@tonic-gate 	if (uFrames > 6) {
33167c478bd9Sstevel@tonic-gate 
33177c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
33187c478bd9Sstevel@tonic-gate 	}
33197c478bd9Sstevel@tonic-gate 	*smask = 0x1;
33207c478bd9Sstevel@tonic-gate 	*cmask = 0x00;
33217c478bd9Sstevel@tonic-gate 	for (i = 0; i < uFrames; i++) {
33227c478bd9Sstevel@tonic-gate 		*cmask = *cmask << 1;
33237c478bd9Sstevel@tonic-gate 		*cmask |= 0x1;
33247c478bd9Sstevel@tonic-gate 	}
33257c478bd9Sstevel@tonic-gate 	/* cmask must start 2 frames after the smask */
33267c478bd9Sstevel@tonic-gate 	*cmask = *cmask << 2;
33277c478bd9Sstevel@tonic-gate 
33287c478bd9Sstevel@tonic-gate 	found = 0;
33297c478bd9Sstevel@tonic-gate 	best_smask = 0x00;
33307c478bd9Sstevel@tonic-gate 	best_node_bandwidth = 0;
33317c478bd9Sstevel@tonic-gate 	for (array_leaf = 0; array_leaf < interval; array_leaf++) {
33327c478bd9Sstevel@tonic-gate 		node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip,
33337c478bd9Sstevel@tonic-gate 		    sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask);
33347c478bd9Sstevel@tonic-gate 		node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip,
33357c478bd9Sstevel@tonic-gate 		    MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count,
33367c478bd9Sstevel@tonic-gate 		    &bw_cmask);
33377c478bd9Sstevel@tonic-gate 
33387c478bd9Sstevel@tonic-gate 		/*
33397c478bd9Sstevel@tonic-gate 		 * If this node cannot support our requirements skip to the
33407c478bd9Sstevel@tonic-gate 		 * next leaf.
33417c478bd9Sstevel@tonic-gate 		 */
33427c478bd9Sstevel@tonic-gate 		if ((bw_smask == 0x00) || (bw_cmask == 0x00)) {
33437c478bd9Sstevel@tonic-gate 			continue;
33447c478bd9Sstevel@tonic-gate 		}
33457c478bd9Sstevel@tonic-gate 
33467c478bd9Sstevel@tonic-gate 		for (i = 0; i < (EHCI_MAX_UFRAMES - uFrames - 2); i++) {
33477c478bd9Sstevel@tonic-gate 			if ((*smask & bw_smask) && (*cmask & bw_cmask)) {
33487c478bd9Sstevel@tonic-gate 				found = 1;
33497c478bd9Sstevel@tonic-gate 				break;
33507c478bd9Sstevel@tonic-gate 			}
33517c478bd9Sstevel@tonic-gate 			*smask = *smask << 1;
33527c478bd9Sstevel@tonic-gate 			*cmask = *cmask << 1;
33537c478bd9Sstevel@tonic-gate 		}
33547c478bd9Sstevel@tonic-gate 
33557c478bd9Sstevel@tonic-gate 		/*
33567c478bd9Sstevel@tonic-gate 		 * If an appropriate smask is found save the information if:
33577c478bd9Sstevel@tonic-gate 		 * o best_smask has not been found yet.
33587c478bd9Sstevel@tonic-gate 		 * - or -
33597c478bd9Sstevel@tonic-gate 		 * o This is the node with the least amount of bandwidth
33607c478bd9Sstevel@tonic-gate 		 */
33617c478bd9Sstevel@tonic-gate 		if (found &&
33627c478bd9Sstevel@tonic-gate 		    ((best_smask == 0x00) ||
336329aca3ebSlc 		    (best_node_bandwidth >
336429aca3ebSlc 		    (node_sbandwidth + node_cbandwidth)))) {
33657c478bd9Sstevel@tonic-gate 			best_node_bandwidth = node_sbandwidth + node_cbandwidth;
33667c478bd9Sstevel@tonic-gate 			best_array_leaf = array_leaf;
33677c478bd9Sstevel@tonic-gate 			best_smask = *smask;
33687c478bd9Sstevel@tonic-gate 			best_cmask = *cmask;
33697c478bd9Sstevel@tonic-gate 		}
33707c478bd9Sstevel@tonic-gate 	}
33717c478bd9Sstevel@tonic-gate 
33727c478bd9Sstevel@tonic-gate 	/*
33737c478bd9Sstevel@tonic-gate 	 * If we find node that can handle the bandwidth populate the
33747c478bd9Sstevel@tonic-gate 	 * appropriate variables and return success.
33757c478bd9Sstevel@tonic-gate 	 */
33767c478bd9Sstevel@tonic-gate 	if (best_smask) {
33777c478bd9Sstevel@tonic-gate 		*smask = best_smask;
33787c478bd9Sstevel@tonic-gate 		*cmask = best_cmask;
33797c478bd9Sstevel@tonic-gate 		*pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
33807c478bd9Sstevel@tonic-gate 		    interval);
33817c478bd9Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, sbandwidth,
33827c478bd9Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_smask);
33837c478bd9Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER,
33847c478bd9Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_cmask);
33857c478bd9Sstevel@tonic-gate 
33867c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
33877c478bd9Sstevel@tonic-gate 	}
33887c478bd9Sstevel@tonic-gate 
33897c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
33907c478bd9Sstevel@tonic-gate }
33917c478bd9Sstevel@tonic-gate 
33927c478bd9Sstevel@tonic-gate 
33937c478bd9Sstevel@tonic-gate /*
33947c478bd9Sstevel@tonic-gate  * ehci_find_bestfit_sitd_out_mask:
33957c478bd9Sstevel@tonic-gate  *
33967c478bd9Sstevel@tonic-gate  * Find the smask in the bandwidth allocation.
33977c478bd9Sstevel@tonic-gate  */
33987c478bd9Sstevel@tonic-gate static int
33997c478bd9Sstevel@tonic-gate ehci_find_bestfit_sitd_out_mask(
34007c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
34017c478bd9Sstevel@tonic-gate 	uchar_t		*smask,
34027c478bd9Sstevel@tonic-gate 	uint_t		*pnode,
34037c478bd9Sstevel@tonic-gate 	uint_t		sbandwidth,
34047c478bd9Sstevel@tonic-gate 	int		interval)
34057c478bd9Sstevel@tonic-gate {
34067c478bd9Sstevel@tonic-gate 	int		i, uFrames, found;
34077c478bd9Sstevel@tonic-gate 	int		array_leaf, best_array_leaf;
34087c478bd9Sstevel@tonic-gate 	uint_t		node_sbandwidth;
34097c478bd9Sstevel@tonic-gate 	uint_t		best_node_bandwidth;
34107c478bd9Sstevel@tonic-gate 	uint_t		leaf_count;
34117c478bd9Sstevel@tonic-gate 	uchar_t		bw_smask;
34127c478bd9Sstevel@tonic-gate 	uchar_t		best_smask;
34137c478bd9Sstevel@tonic-gate 
34147c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
34157c478bd9Sstevel@tonic-gate 	    "ehci_find_bestfit_sitd_out_mask: ");
34167c478bd9Sstevel@tonic-gate 
34177c478bd9Sstevel@tonic-gate 	leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
34187c478bd9Sstevel@tonic-gate 
34197c478bd9Sstevel@tonic-gate 	/*
34207c478bd9Sstevel@tonic-gate 	 * Because of the way the leaves are setup, we will automatically
34217c478bd9Sstevel@tonic-gate 	 * hit the leftmost leaf of every possible node with this interval.
34227c478bd9Sstevel@tonic-gate 	 * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame.
34237c478bd9Sstevel@tonic-gate 	 */
34247c478bd9Sstevel@tonic-gate 	*smask = 0x00;
34257c478bd9Sstevel@tonic-gate 	uFrames = sbandwidth / MAX_UFRAME_SITD_XFER;
34267c478bd9Sstevel@tonic-gate 	if (sbandwidth % MAX_UFRAME_SITD_XFER) {
34277c478bd9Sstevel@tonic-gate 		uFrames++;
34287c478bd9Sstevel@tonic-gate 	}
34297c478bd9Sstevel@tonic-gate 	for (i = 0; i < uFrames; i++) {
34307c478bd9Sstevel@tonic-gate 		*smask = *smask << 1;
34317c478bd9Sstevel@tonic-gate 		*smask |= 0x1;
34327c478bd9Sstevel@tonic-gate 	}
34337c478bd9Sstevel@tonic-gate 
34347c478bd9Sstevel@tonic-gate 	found = 0;
34357c478bd9Sstevel@tonic-gate 	best_smask = 0x00;
34367c478bd9Sstevel@tonic-gate 	best_node_bandwidth = 0;
34377c478bd9Sstevel@tonic-gate 	for (array_leaf = 0; array_leaf < interval; array_leaf++) {
34387c478bd9Sstevel@tonic-gate 		node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip,
34397c478bd9Sstevel@tonic-gate 		    MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count,
34407c478bd9Sstevel@tonic-gate 		    &bw_smask);
34417c478bd9Sstevel@tonic-gate 
34427c478bd9Sstevel@tonic-gate 		/*
34437c478bd9Sstevel@tonic-gate 		 * If this node cannot support our requirements skip to the
34447c478bd9Sstevel@tonic-gate 		 * next leaf.
34457c478bd9Sstevel@tonic-gate 		 */
34467c478bd9Sstevel@tonic-gate 		if (bw_smask == 0x00) {
34477c478bd9Sstevel@tonic-gate 			continue;
34487c478bd9Sstevel@tonic-gate 		}
34497c478bd9Sstevel@tonic-gate 
34507c478bd9Sstevel@tonic-gate 		/* You cannot have a start split on the 8th uFrame */
34517c478bd9Sstevel@tonic-gate 		for (i = 0; (*smask & 0x80) == 0; i++) {
34527c478bd9Sstevel@tonic-gate 			if (*smask & bw_smask) {
34537c478bd9Sstevel@tonic-gate 				found = 1;
34547c478bd9Sstevel@tonic-gate 				break;
34557c478bd9Sstevel@tonic-gate 			}
34567c478bd9Sstevel@tonic-gate 			*smask = *smask << 1;
34577c478bd9Sstevel@tonic-gate 		}
34587c478bd9Sstevel@tonic-gate 
34597c478bd9Sstevel@tonic-gate 		/*
34607c478bd9Sstevel@tonic-gate 		 * If an appropriate smask is found save the information if:
34617c478bd9Sstevel@tonic-gate 		 * o best_smask has not been found yet.
34627c478bd9Sstevel@tonic-gate 		 * - or -
34637c478bd9Sstevel@tonic-gate 		 * o This is the node with the least amount of bandwidth
34647c478bd9Sstevel@tonic-gate 		 */
34657c478bd9Sstevel@tonic-gate 		if (found &&
34667c478bd9Sstevel@tonic-gate 		    ((best_smask == 0x00) ||
346729aca3ebSlc 		    (best_node_bandwidth > node_sbandwidth))) {
34687c478bd9Sstevel@tonic-gate 			best_node_bandwidth = node_sbandwidth;
34697c478bd9Sstevel@tonic-gate 			best_array_leaf = array_leaf;
34707c478bd9Sstevel@tonic-gate 			best_smask = *smask;
34717c478bd9Sstevel@tonic-gate 		}
34727c478bd9Sstevel@tonic-gate 	}
34737c478bd9Sstevel@tonic-gate 
34747c478bd9Sstevel@tonic-gate 	/*
34757c478bd9Sstevel@tonic-gate 	 * If we find node that can handle the bandwidth populate the
34767c478bd9Sstevel@tonic-gate 	 * appropriate variables and return success.
34777c478bd9Sstevel@tonic-gate 	 */
34787c478bd9Sstevel@tonic-gate 	if (best_smask) {
34797c478bd9Sstevel@tonic-gate 		*smask = best_smask;
34807c478bd9Sstevel@tonic-gate 		*pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
34817c478bd9Sstevel@tonic-gate 		    interval);
34827c478bd9Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER,
34837c478bd9Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_smask);
34847c478bd9Sstevel@tonic-gate 
34857c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
34867c478bd9Sstevel@tonic-gate 	}
34877c478bd9Sstevel@tonic-gate 
34887c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
34897c478bd9Sstevel@tonic-gate }
34907c478bd9Sstevel@tonic-gate 
34917c478bd9Sstevel@tonic-gate 
34927c478bd9Sstevel@tonic-gate /*
34937c478bd9Sstevel@tonic-gate  * ehci_calculate_bw_availability_mask:
34947c478bd9Sstevel@tonic-gate  *
34957c478bd9Sstevel@tonic-gate  * Returns the "total bandwidth used" in this node.
34967c478bd9Sstevel@tonic-gate  * Populates bw_mask with the uFrames that can support the bandwidth.
34977c478bd9Sstevel@tonic-gate  *
34987c478bd9Sstevel@tonic-gate  * If all the Frames cannot support this bandwidth, then bw_mask
34997c478bd9Sstevel@tonic-gate  * will return 0x00 and the "total bandwidth used" will be invalid.
35007c478bd9Sstevel@tonic-gate  */
35017c478bd9Sstevel@tonic-gate static uint_t
35027c478bd9Sstevel@tonic-gate ehci_calculate_bw_availability_mask(
35037c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
35047c478bd9Sstevel@tonic-gate 	uint_t		bandwidth,
35057c478bd9Sstevel@tonic-gate 	int		leaf,
35067c478bd9Sstevel@tonic-gate 	int		leaf_count,
35077c478bd9Sstevel@tonic-gate 	uchar_t		*bw_mask)
35087c478bd9Sstevel@tonic-gate {
35097c478bd9Sstevel@tonic-gate 	int			i, j;
35107c478bd9Sstevel@tonic-gate 	uchar_t			bw_uframe;
35117c478bd9Sstevel@tonic-gate 	int			uframe_total;
35127c478bd9Sstevel@tonic-gate 	ehci_frame_bandwidth_t	*fbp;
35137c478bd9Sstevel@tonic-gate 	uint_t			total_bandwidth = 0;
35147c478bd9Sstevel@tonic-gate 
35157c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
35167c478bd9Sstevel@tonic-gate 	    "ehci_calculate_bw_availability_mask: leaf %d leaf count %d",
35177c478bd9Sstevel@tonic-gate 	    leaf, leaf_count);
35187c478bd9Sstevel@tonic-gate 
35197c478bd9Sstevel@tonic-gate 	/* Start by saying all uFrames are available */
35207c478bd9Sstevel@tonic-gate 	*bw_mask = 0xFF;
35217c478bd9Sstevel@tonic-gate 
35227c478bd9Sstevel@tonic-gate 	for (i = 0; (i < leaf_count) || (*bw_mask == 0x00); i++) {
35237c478bd9Sstevel@tonic-gate 		fbp = &ehcip->ehci_frame_bandwidth[leaf + i];
35247c478bd9Sstevel@tonic-gate 
35257c478bd9Sstevel@tonic-gate 		total_bandwidth += fbp->ehci_allocated_frame_bandwidth;
35267c478bd9Sstevel@tonic-gate 
35277c478bd9Sstevel@tonic-gate 		for (j = 0; j < EHCI_MAX_UFRAMES; j++) {
35287c478bd9Sstevel@tonic-gate 			/*
35297c478bd9Sstevel@tonic-gate 			 * If the uFrame in bw_mask is available check to see if
35307c478bd9Sstevel@tonic-gate 			 * it can support the additional bandwidth.
35317c478bd9Sstevel@tonic-gate 			 */
35327c478bd9Sstevel@tonic-gate 			bw_uframe = (*bw_mask & (0x1 << j));
35337c478bd9Sstevel@tonic-gate 			uframe_total =
35347c478bd9Sstevel@tonic-gate 			    fbp->ehci_micro_frame_bandwidth[j] +
35357c478bd9Sstevel@tonic-gate 			    bandwidth;
35367c478bd9Sstevel@tonic-gate 			if ((bw_uframe) &&
35377c478bd9Sstevel@tonic-gate 			    (uframe_total > HS_PERIODIC_BANDWIDTH)) {
35387c478bd9Sstevel@tonic-gate 				*bw_mask = *bw_mask & ~bw_uframe;
35397c478bd9Sstevel@tonic-gate 			}
35407c478bd9Sstevel@tonic-gate 		}
35417c478bd9Sstevel@tonic-gate 	}
35427c478bd9Sstevel@tonic-gate 
35437c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
35447c478bd9Sstevel@tonic-gate 	    "ehci_calculate_bw_availability_mask: bandwidth mask 0x%x",
35457c478bd9Sstevel@tonic-gate 	    *bw_mask);
35467c478bd9Sstevel@tonic-gate 
35477c478bd9Sstevel@tonic-gate 	return (total_bandwidth);
35487c478bd9Sstevel@tonic-gate }
35497c478bd9Sstevel@tonic-gate 
35507c478bd9Sstevel@tonic-gate 
35517c478bd9Sstevel@tonic-gate /*
35527c478bd9Sstevel@tonic-gate  * ehci_update_bw_availability:
35537c478bd9Sstevel@tonic-gate  *
35547c478bd9Sstevel@tonic-gate  * The leftmost leaf needs to be in terms of array position and
35557c478bd9Sstevel@tonic-gate  * not the actual lattice position.
35567c478bd9Sstevel@tonic-gate  */
35577c478bd9Sstevel@tonic-gate static void
35587c478bd9Sstevel@tonic-gate ehci_update_bw_availability(
35597c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
35607c478bd9Sstevel@tonic-gate 	int		bandwidth,
35617c478bd9Sstevel@tonic-gate 	int		leftmost_leaf,
35627c478bd9Sstevel@tonic-gate 	int		leaf_count,
35637c478bd9Sstevel@tonic-gate 	uchar_t		mask)
35647c478bd9Sstevel@tonic-gate {
35657c478bd9Sstevel@tonic-gate 	int			i, j;
35667c478bd9Sstevel@tonic-gate 	ehci_frame_bandwidth_t	*fbp;
35677c478bd9Sstevel@tonic-gate 	int			uFrame_bandwidth[8];
35687c478bd9Sstevel@tonic-gate 
35697c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
35707c478bd9Sstevel@tonic-gate 	    "ehci_update_bw_availability: "
35717c478bd9Sstevel@tonic-gate 	    "leaf %d count %d bandwidth 0x%x mask 0x%x",
35727c478bd9Sstevel@tonic-gate 	    leftmost_leaf, leaf_count, bandwidth, mask);
35737c478bd9Sstevel@tonic-gate 
35747c478bd9Sstevel@tonic-gate 	ASSERT(leftmost_leaf < 32);
35757c478bd9Sstevel@tonic-gate 	ASSERT(leftmost_leaf >= 0);
35767c478bd9Sstevel@tonic-gate 
35777c478bd9Sstevel@tonic-gate 	for (j = 0; j < EHCI_MAX_UFRAMES; j++) {
35787c478bd9Sstevel@tonic-gate 		if (mask & 0x1) {
35797c478bd9Sstevel@tonic-gate 			uFrame_bandwidth[j] = bandwidth;
35807c478bd9Sstevel@tonic-gate 		} else {
35817c478bd9Sstevel@tonic-gate 			uFrame_bandwidth[j] = 0;
35827c478bd9Sstevel@tonic-gate 		}
35837c478bd9Sstevel@tonic-gate 
35847c478bd9Sstevel@tonic-gate 		mask = mask >> 1;
35857c478bd9Sstevel@tonic-gate 	}
35867c478bd9Sstevel@tonic-gate 
35877c478bd9Sstevel@tonic-gate 	/* Updated all the effected leafs with the bandwidth */
35887c478bd9Sstevel@tonic-gate 	for (i = 0; i < leaf_count; i++) {
35897c478bd9Sstevel@tonic-gate 		fbp = &ehcip->ehci_frame_bandwidth[leftmost_leaf + i];
35907c478bd9Sstevel@tonic-gate 
35917c478bd9Sstevel@tonic-gate 		for (j = 0; j < EHCI_MAX_UFRAMES; j++) {
35927c478bd9Sstevel@tonic-gate 			fbp->ehci_micro_frame_bandwidth[j] +=
35937c478bd9Sstevel@tonic-gate 			    uFrame_bandwidth[j];
35947c478bd9Sstevel@tonic-gate 			fbp->ehci_allocated_frame_bandwidth +=
35957c478bd9Sstevel@tonic-gate 			    uFrame_bandwidth[j];
35967c478bd9Sstevel@tonic-gate 		}
35977c478bd9Sstevel@tonic-gate 	}
35987c478bd9Sstevel@tonic-gate }
35997c478bd9Sstevel@tonic-gate 
36007c478bd9Sstevel@tonic-gate /*
36017c478bd9Sstevel@tonic-gate  * Miscellaneous functions
36027c478bd9Sstevel@tonic-gate  */
36037c478bd9Sstevel@tonic-gate 
36047c478bd9Sstevel@tonic-gate /*
36057c478bd9Sstevel@tonic-gate  * ehci_obtain_state:
36067c478bd9Sstevel@tonic-gate  *
36077c478bd9Sstevel@tonic-gate  * NOTE: This function is also called from POLLED MODE.
36087c478bd9Sstevel@tonic-gate  */
36097c478bd9Sstevel@tonic-gate ehci_state_t *
36107c478bd9Sstevel@tonic-gate ehci_obtain_state(dev_info_t	*dip)
36117c478bd9Sstevel@tonic-gate {
36127c478bd9Sstevel@tonic-gate 	int			instance = ddi_get_instance(dip);
36137c478bd9Sstevel@tonic-gate 
36147c478bd9Sstevel@tonic-gate 	ehci_state_t *state = ddi_get_soft_state(ehci_statep, instance);
36157c478bd9Sstevel@tonic-gate 
36167c478bd9Sstevel@tonic-gate 	ASSERT(state != NULL);
36177c478bd9Sstevel@tonic-gate 
36187c478bd9Sstevel@tonic-gate 	return (state);
36197c478bd9Sstevel@tonic-gate }
36207c478bd9Sstevel@tonic-gate 
36217c478bd9Sstevel@tonic-gate 
36227c478bd9Sstevel@tonic-gate /*
36237c478bd9Sstevel@tonic-gate  * ehci_state_is_operational:
36247c478bd9Sstevel@tonic-gate  *
36257c478bd9Sstevel@tonic-gate  * Check the Host controller state and return proper values.
36267c478bd9Sstevel@tonic-gate  */
36277c478bd9Sstevel@tonic-gate int
36287c478bd9Sstevel@tonic-gate ehci_state_is_operational(ehci_state_t	*ehcip)
36297c478bd9Sstevel@tonic-gate {
36307c478bd9Sstevel@tonic-gate 	int	val;
36317c478bd9Sstevel@tonic-gate 
36327c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
36337c478bd9Sstevel@tonic-gate 
36347c478bd9Sstevel@tonic-gate 	switch (ehcip->ehci_hc_soft_state) {
36357c478bd9Sstevel@tonic-gate 	case EHCI_CTLR_INIT_STATE:
36367c478bd9Sstevel@tonic-gate 	case EHCI_CTLR_SUSPEND_STATE:
36377c478bd9Sstevel@tonic-gate 		val = USB_FAILURE;
36387c478bd9Sstevel@tonic-gate 		break;
36397c478bd9Sstevel@tonic-gate 	case EHCI_CTLR_OPERATIONAL_STATE:
36407c478bd9Sstevel@tonic-gate 		val = USB_SUCCESS;
36417c478bd9Sstevel@tonic-gate 		break;
36427c478bd9Sstevel@tonic-gate 	case EHCI_CTLR_ERROR_STATE:
36437c478bd9Sstevel@tonic-gate 		val = USB_HC_HARDWARE_ERROR;
36447c478bd9Sstevel@tonic-gate 		break;
36457c478bd9Sstevel@tonic-gate 	default:
36467c478bd9Sstevel@tonic-gate 		val = USB_FAILURE;
36477c478bd9Sstevel@tonic-gate 		break;
36487c478bd9Sstevel@tonic-gate 	}
36497c478bd9Sstevel@tonic-gate 
36507c478bd9Sstevel@tonic-gate 	return (val);
36517c478bd9Sstevel@tonic-gate }
36527c478bd9Sstevel@tonic-gate 
36537c478bd9Sstevel@tonic-gate 
36547c478bd9Sstevel@tonic-gate /*
36557c478bd9Sstevel@tonic-gate  * ehci_do_soft_reset
36567c478bd9Sstevel@tonic-gate  *
36577c478bd9Sstevel@tonic-gate  * Do soft reset of ehci host controller.
36587c478bd9Sstevel@tonic-gate  */
36597c478bd9Sstevel@tonic-gate int
36607c478bd9Sstevel@tonic-gate ehci_do_soft_reset(ehci_state_t	*ehcip)
36617c478bd9Sstevel@tonic-gate {
36627c478bd9Sstevel@tonic-gate 	usb_frame_number_t	before_frame_number, after_frame_number;
36637c478bd9Sstevel@tonic-gate 	ehci_regs_t		*ehci_save_regs;
36647c478bd9Sstevel@tonic-gate 
36657c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
36667c478bd9Sstevel@tonic-gate 
36677c478bd9Sstevel@tonic-gate 	/* Increment host controller error count */
36687c478bd9Sstevel@tonic-gate 	ehcip->ehci_hc_error++;
36697c478bd9Sstevel@tonic-gate 
36707c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
36717c478bd9Sstevel@tonic-gate 	    "ehci_do_soft_reset:"
36727c478bd9Sstevel@tonic-gate 	    "Reset ehci host controller 0x%x", ehcip->ehci_hc_error);
36737c478bd9Sstevel@tonic-gate 
36747c478bd9Sstevel@tonic-gate 	/*
36757c478bd9Sstevel@tonic-gate 	 * Allocate space for saving current Host Controller
36767c478bd9Sstevel@tonic-gate 	 * registers. Don't do any recovery if allocation
36777c478bd9Sstevel@tonic-gate 	 * fails.
36787c478bd9Sstevel@tonic-gate 	 */
36797c478bd9Sstevel@tonic-gate 	ehci_save_regs = (ehci_regs_t *)
36807c478bd9Sstevel@tonic-gate 	    kmem_zalloc(sizeof (ehci_regs_t), KM_NOSLEEP);
36817c478bd9Sstevel@tonic-gate 
36827c478bd9Sstevel@tonic-gate 	if (ehci_save_regs == NULL) {
36837c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR,  ehcip->ehci_log_hdl,
36847c478bd9Sstevel@tonic-gate 		    "ehci_do_soft_reset: kmem_zalloc failed");
36857c478bd9Sstevel@tonic-gate 
36867c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
36877c478bd9Sstevel@tonic-gate 	}
36887c478bd9Sstevel@tonic-gate 
36897c478bd9Sstevel@tonic-gate 	/* Save current ehci registers */
36907c478bd9Sstevel@tonic-gate 	ehci_save_regs->ehci_command = Get_OpReg(ehci_command);
36917c478bd9Sstevel@tonic-gate 	ehci_save_regs->ehci_interrupt = Get_OpReg(ehci_interrupt);
36927c478bd9Sstevel@tonic-gate 	ehci_save_regs->ehci_ctrl_segment = Get_OpReg(ehci_ctrl_segment);
36937c478bd9Sstevel@tonic-gate 	ehci_save_regs->ehci_async_list_addr = Get_OpReg(ehci_async_list_addr);
36947c478bd9Sstevel@tonic-gate 	ehci_save_regs->ehci_config_flag = Get_OpReg(ehci_config_flag);
36957c478bd9Sstevel@tonic-gate 	ehci_save_regs->ehci_periodic_list_base =
36967c478bd9Sstevel@tonic-gate 	    Get_OpReg(ehci_periodic_list_base);
36977c478bd9Sstevel@tonic-gate 
36983b00f311Syq 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
3699112116d8Sfb 	    "ehci_do_soft_reset: Save reg = 0x%p", (void *)ehci_save_regs);
37007c478bd9Sstevel@tonic-gate 
37017c478bd9Sstevel@tonic-gate 	/* Disable all list processing and interrupts */
37027c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_command, Get_OpReg(ehci_command) &
37037c478bd9Sstevel@tonic-gate 	    ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE));
37047c478bd9Sstevel@tonic-gate 
37057c478bd9Sstevel@tonic-gate 	/* Disable all EHCI interrupts */
37067c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_interrupt, 0);
37077c478bd9Sstevel@tonic-gate 
37087c478bd9Sstevel@tonic-gate 	/* Wait for few milliseconds */
37097c478bd9Sstevel@tonic-gate 	drv_usecwait(EHCI_SOF_TIMEWAIT);
37107c478bd9Sstevel@tonic-gate 
37117c478bd9Sstevel@tonic-gate 	/* Do light soft reset of ehci host controller */
37127c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_command,
37137c478bd9Sstevel@tonic-gate 	    Get_OpReg(ehci_command) | EHCI_CMD_LIGHT_HC_RESET);
37147c478bd9Sstevel@tonic-gate 
37153b00f311Syq 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
37167c478bd9Sstevel@tonic-gate 	    "ehci_do_soft_reset: Reset in progress");
37177c478bd9Sstevel@tonic-gate 
37187c478bd9Sstevel@tonic-gate 	/* Wait for reset to complete */
37197c478bd9Sstevel@tonic-gate 	drv_usecwait(EHCI_RESET_TIMEWAIT);
37207c478bd9Sstevel@tonic-gate 
37217c478bd9Sstevel@tonic-gate 	/*
37227c478bd9Sstevel@tonic-gate 	 * Restore previous saved EHCI register value
37237c478bd9Sstevel@tonic-gate 	 * into the current EHCI registers.
37247c478bd9Sstevel@tonic-gate 	 */
37257c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_ctrl_segment, (uint32_t)
372629aca3ebSlc 	    ehci_save_regs->ehci_ctrl_segment);
37277c478bd9Sstevel@tonic-gate 
37287c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_periodic_list_base, (uint32_t)
372929aca3ebSlc 	    ehci_save_regs->ehci_periodic_list_base);
37307c478bd9Sstevel@tonic-gate 
37317c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_async_list_addr, (uint32_t)
373229aca3ebSlc 	    ehci_save_regs->ehci_async_list_addr);
37337c478bd9Sstevel@tonic-gate 
3734921cd50dSgk 	/*
3735921cd50dSgk 	 * For some reason this register might get nulled out by
3736921cd50dSgk 	 * the Uli M1575 South Bridge. To workaround the hardware
3737921cd50dSgk 	 * problem, check the value after write and retry if the
3738921cd50dSgk 	 * last write fails.
3739921cd50dSgk 	 */
3740921cd50dSgk 	if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
3741921cd50dSgk 	    (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) &&
3742921cd50dSgk 	    (ehci_save_regs->ehci_async_list_addr !=
3743921cd50dSgk 	    Get_OpReg(ehci_async_list_addr))) {
3744921cd50dSgk 		int retry = 0;
3745921cd50dSgk 
3746921cd50dSgk 		Set_OpRegRetry(ehci_async_list_addr, (uint32_t)
374729aca3ebSlc 		    ehci_save_regs->ehci_async_list_addr, retry);
3748921cd50dSgk 		if (retry >= EHCI_MAX_RETRY) {
37498668df41Slg 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
3750921cd50dSgk 			    ehcip->ehci_log_hdl, "ehci_do_soft_reset:"
3751921cd50dSgk 			    " ASYNCLISTADDR write failed.");
3752921cd50dSgk 
3753921cd50dSgk 			return (USB_FAILURE);
3754921cd50dSgk 		}
3755921cd50dSgk 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3756921cd50dSgk 		    "ehci_do_soft_reset: ASYNCLISTADDR "
375729aca3ebSlc 		    "write failed, retry=%d", retry);
3758921cd50dSgk 	}
3759921cd50dSgk 
37607c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_config_flag, (uint32_t)
376129aca3ebSlc 	    ehci_save_regs->ehci_config_flag);
37627c478bd9Sstevel@tonic-gate 
37637c478bd9Sstevel@tonic-gate 	/* Enable both Asynchronous and Periodic Schedule if necessary */
37647c478bd9Sstevel@tonic-gate 	ehci_toggle_scheduler(ehcip);
37657c478bd9Sstevel@tonic-gate 
37667c478bd9Sstevel@tonic-gate 	/*
37677c478bd9Sstevel@tonic-gate 	 * Set ehci_interrupt to enable all interrupts except Root
37687c478bd9Sstevel@tonic-gate 	 * Hub Status change and frame list rollover interrupts.
37697c478bd9Sstevel@tonic-gate 	 */
37707c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR |
37717c478bd9Sstevel@tonic-gate 	    EHCI_INTR_FRAME_LIST_ROLLOVER |
37727c478bd9Sstevel@tonic-gate 	    EHCI_INTR_USB_ERROR |
37737c478bd9Sstevel@tonic-gate 	    EHCI_INTR_USB);
37747c478bd9Sstevel@tonic-gate 
37757c478bd9Sstevel@tonic-gate 	/*
37767c478bd9Sstevel@tonic-gate 	 * Deallocate the space that allocated for saving
37777c478bd9Sstevel@tonic-gate 	 * HC registers.
37787c478bd9Sstevel@tonic-gate 	 */
37797c478bd9Sstevel@tonic-gate 	kmem_free((void *) ehci_save_regs, sizeof (ehci_regs_t));
37807c478bd9Sstevel@tonic-gate 
37817c478bd9Sstevel@tonic-gate 	/*
37827c478bd9Sstevel@tonic-gate 	 * Set the desired interrupt threshold, frame list size (if
37837c478bd9Sstevel@tonic-gate 	 * applicable) and turn EHCI host controller.
37847c478bd9Sstevel@tonic-gate 	 */
37857c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_command, ((Get_OpReg(ehci_command) &
37867c478bd9Sstevel@tonic-gate 	    ~EHCI_CMD_INTR_THRESHOLD) |
37877c478bd9Sstevel@tonic-gate 	    (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN)));
37887c478bd9Sstevel@tonic-gate 
37897c478bd9Sstevel@tonic-gate 	/* Wait 10ms for EHCI to start sending SOF */
37907c478bd9Sstevel@tonic-gate 	drv_usecwait(EHCI_RESET_TIMEWAIT);
37917c478bd9Sstevel@tonic-gate 
37927c478bd9Sstevel@tonic-gate 	/*
37937c478bd9Sstevel@tonic-gate 	 * Get the current usb frame number before waiting for
37947c478bd9Sstevel@tonic-gate 	 * few milliseconds.
37957c478bd9Sstevel@tonic-gate 	 */
37967c478bd9Sstevel@tonic-gate 	before_frame_number = ehci_get_current_frame_number(ehcip);
37977c478bd9Sstevel@tonic-gate 
37987c478bd9Sstevel@tonic-gate 	/* Wait for few milliseconds */
37997c478bd9Sstevel@tonic-gate 	drv_usecwait(EHCI_SOF_TIMEWAIT);
38007c478bd9Sstevel@tonic-gate 
38017c478bd9Sstevel@tonic-gate 	/*
38027c478bd9Sstevel@tonic-gate 	 * Get the current usb frame number after waiting for
38037c478bd9Sstevel@tonic-gate 	 * few milliseconds.
38047c478bd9Sstevel@tonic-gate 	 */
38057c478bd9Sstevel@tonic-gate 	after_frame_number = ehci_get_current_frame_number(ehcip);
38067c478bd9Sstevel@tonic-gate 
38077c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
38087c478bd9Sstevel@tonic-gate 	    "ehci_do_soft_reset: Before Frame Number 0x%llx "
38097c478bd9Sstevel@tonic-gate 	    "After Frame Number 0x%llx",
3810112116d8Sfb 	    (unsigned long long)before_frame_number,
3811112116d8Sfb 	    (unsigned long long)after_frame_number);
38127c478bd9Sstevel@tonic-gate 
38137c478bd9Sstevel@tonic-gate 	if ((after_frame_number <= before_frame_number) &&
38147c478bd9Sstevel@tonic-gate 	    (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) {
38157c478bd9Sstevel@tonic-gate 
38167c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
38177c478bd9Sstevel@tonic-gate 		    "ehci_do_soft_reset: Soft reset failed");
38187c478bd9Sstevel@tonic-gate 
38197c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
38207c478bd9Sstevel@tonic-gate 	}
38217c478bd9Sstevel@tonic-gate 
38227c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
38237c478bd9Sstevel@tonic-gate }
38247c478bd9Sstevel@tonic-gate 
38257c478bd9Sstevel@tonic-gate 
38267c478bd9Sstevel@tonic-gate /*
38277c478bd9Sstevel@tonic-gate  * ehci_get_xfer_attrs:
38287c478bd9Sstevel@tonic-gate  *
38297c478bd9Sstevel@tonic-gate  * Get the attributes of a particular xfer.
38307c478bd9Sstevel@tonic-gate  *
38317c478bd9Sstevel@tonic-gate  * NOTE: This function is also called from POLLED MODE.
38327c478bd9Sstevel@tonic-gate  */
38337c478bd9Sstevel@tonic-gate usb_req_attrs_t
38347c478bd9Sstevel@tonic-gate ehci_get_xfer_attrs(
38357c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
38367c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
38377c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw)
38387c478bd9Sstevel@tonic-gate {
38397c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &pp->pp_pipe_handle->p_ep;
38407c478bd9Sstevel@tonic-gate 	usb_req_attrs_t		attrs = USB_ATTRS_NONE;
38417c478bd9Sstevel@tonic-gate 
38427c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
38437c478bd9Sstevel@tonic-gate 	    "ehci_get_xfer_attrs:");
38447c478bd9Sstevel@tonic-gate 
38457c478bd9Sstevel@tonic-gate 	switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
38467c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
38477c478bd9Sstevel@tonic-gate 		attrs = ((usb_ctrl_req_t *)
38487c478bd9Sstevel@tonic-gate 		    tw->tw_curr_xfer_reqp)->ctrl_attributes;
38497c478bd9Sstevel@tonic-gate 		break;
38507c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
38517c478bd9Sstevel@tonic-gate 		attrs = ((usb_bulk_req_t *)
38527c478bd9Sstevel@tonic-gate 		    tw->tw_curr_xfer_reqp)->bulk_attributes;
38537c478bd9Sstevel@tonic-gate 		break;
38547c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
38557c478bd9Sstevel@tonic-gate 		attrs = ((usb_intr_req_t *)
38567c478bd9Sstevel@tonic-gate 		    tw->tw_curr_xfer_reqp)->intr_attributes;
38577c478bd9Sstevel@tonic-gate 		break;
38587c478bd9Sstevel@tonic-gate 	}
38597c478bd9Sstevel@tonic-gate 
38607c478bd9Sstevel@tonic-gate 	return (attrs);
38617c478bd9Sstevel@tonic-gate }
38627c478bd9Sstevel@tonic-gate 
38637c478bd9Sstevel@tonic-gate 
38647c478bd9Sstevel@tonic-gate /*
38657c478bd9Sstevel@tonic-gate  * ehci_get_current_frame_number:
38667c478bd9Sstevel@tonic-gate  *
38677c478bd9Sstevel@tonic-gate  * Get the current software based usb frame number.
38687c478bd9Sstevel@tonic-gate  */
38697c478bd9Sstevel@tonic-gate usb_frame_number_t
38707c478bd9Sstevel@tonic-gate ehci_get_current_frame_number(ehci_state_t *ehcip)
38717c478bd9Sstevel@tonic-gate {
38727c478bd9Sstevel@tonic-gate 	usb_frame_number_t	usb_frame_number;
38737c478bd9Sstevel@tonic-gate 	usb_frame_number_t	ehci_fno, micro_frame_number;
38747c478bd9Sstevel@tonic-gate 
38757c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
38767c478bd9Sstevel@tonic-gate 
38777c478bd9Sstevel@tonic-gate 	ehci_fno = ehcip->ehci_fno;
38787c478bd9Sstevel@tonic-gate 	micro_frame_number = Get_OpReg(ehci_frame_index) & 0x3FFF;
38797c478bd9Sstevel@tonic-gate 
38807c478bd9Sstevel@tonic-gate 	/*
38817c478bd9Sstevel@tonic-gate 	 * Calculate current software based usb frame number.
38827c478bd9Sstevel@tonic-gate 	 *
38837c478bd9Sstevel@tonic-gate 	 * This code accounts for the fact that frame number is
38847c478bd9Sstevel@tonic-gate 	 * updated by the Host Controller before the ehci driver
38857c478bd9Sstevel@tonic-gate 	 * gets an FrameListRollover interrupt that will adjust
38867c478bd9Sstevel@tonic-gate 	 * Frame higher part.
38877c478bd9Sstevel@tonic-gate 	 *
38887c478bd9Sstevel@tonic-gate 	 * Refer ehci specification 1.0, section 2.3.2, page 21.
38897c478bd9Sstevel@tonic-gate 	 */
38907c478bd9Sstevel@tonic-gate 	micro_frame_number = ((micro_frame_number & 0x1FFF) |
38917c478bd9Sstevel@tonic-gate 	    ehci_fno) + (((micro_frame_number & 0x3FFF) ^
38927c478bd9Sstevel@tonic-gate 	    ehci_fno) & 0x2000);
38937c478bd9Sstevel@tonic-gate 
38947c478bd9Sstevel@tonic-gate 	/*
38957c478bd9Sstevel@tonic-gate 	 * Micro Frame number is equivalent to 125 usec. Eight
38967c478bd9Sstevel@tonic-gate 	 * Micro Frame numbers are equivalent to one millsecond
38977c478bd9Sstevel@tonic-gate 	 * or one usb frame number.
38987c478bd9Sstevel@tonic-gate 	 */
38997c478bd9Sstevel@tonic-gate 	usb_frame_number = micro_frame_number >>
39007c478bd9Sstevel@tonic-gate 	    EHCI_uFRAMES_PER_USB_FRAME_SHIFT;
39017c478bd9Sstevel@tonic-gate 
39027c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
39037c478bd9Sstevel@tonic-gate 	    "ehci_get_current_frame_number: "
39047c478bd9Sstevel@tonic-gate 	    "Current usb uframe number = 0x%llx "
39057c478bd9Sstevel@tonic-gate 	    "Current usb frame number  = 0x%llx",
3906112116d8Sfb 	    (unsigned long long)micro_frame_number,
3907112116d8Sfb 	    (unsigned long long)usb_frame_number);
39087c478bd9Sstevel@tonic-gate 
39097c478bd9Sstevel@tonic-gate 	return (usb_frame_number);
39107c478bd9Sstevel@tonic-gate }
39117c478bd9Sstevel@tonic-gate 
39127c478bd9Sstevel@tonic-gate 
39137c478bd9Sstevel@tonic-gate /*
39147c478bd9Sstevel@tonic-gate  * ehci_cpr_cleanup:
39157c478bd9Sstevel@tonic-gate  *
39167c478bd9Sstevel@tonic-gate  * Cleanup ehci state and other ehci specific informations across
39177c478bd9Sstevel@tonic-gate  * Check Point Resume (CPR).
39187c478bd9Sstevel@tonic-gate  */
39197c478bd9Sstevel@tonic-gate static	void
39207c478bd9Sstevel@tonic-gate ehci_cpr_cleanup(ehci_state_t *ehcip)
39217c478bd9Sstevel@tonic-gate {
39227c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
39237c478bd9Sstevel@tonic-gate 
39247c478bd9Sstevel@tonic-gate 	/* Reset software part of usb frame number */
39257c478bd9Sstevel@tonic-gate 	ehcip->ehci_fno = 0;
39267c478bd9Sstevel@tonic-gate }
39277c478bd9Sstevel@tonic-gate 
39287c478bd9Sstevel@tonic-gate 
39297c478bd9Sstevel@tonic-gate /*
39307c478bd9Sstevel@tonic-gate  * ehci_wait_for_sof:
39317c478bd9Sstevel@tonic-gate  *
39327c478bd9Sstevel@tonic-gate  * Wait for couple of SOF interrupts
39337c478bd9Sstevel@tonic-gate  */
39347c478bd9Sstevel@tonic-gate int
39357c478bd9Sstevel@tonic-gate ehci_wait_for_sof(ehci_state_t	*ehcip)
39367c478bd9Sstevel@tonic-gate {
39377c478bd9Sstevel@tonic-gate 	usb_frame_number_t	before_frame_number, after_frame_number;
39387c478bd9Sstevel@tonic-gate 	int			error = USB_SUCCESS;
39397c478bd9Sstevel@tonic-gate 
39407c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS,
39417c478bd9Sstevel@tonic-gate 	    ehcip->ehci_log_hdl, "ehci_wait_for_sof");
39427c478bd9Sstevel@tonic-gate 
39437c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
39447c478bd9Sstevel@tonic-gate 
39457c478bd9Sstevel@tonic-gate 	error = ehci_state_is_operational(ehcip);
39467c478bd9Sstevel@tonic-gate 
39477c478bd9Sstevel@tonic-gate 	if (error != USB_SUCCESS) {
39487c478bd9Sstevel@tonic-gate 
39497c478bd9Sstevel@tonic-gate 		return (error);
39507c478bd9Sstevel@tonic-gate 	}
39517c478bd9Sstevel@tonic-gate 
39527c478bd9Sstevel@tonic-gate 	/* Get the current usb frame number before waiting for two SOFs */
39537c478bd9Sstevel@tonic-gate 	before_frame_number = ehci_get_current_frame_number(ehcip);
39547c478bd9Sstevel@tonic-gate 
39557c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
39567c478bd9Sstevel@tonic-gate 
39577c478bd9Sstevel@tonic-gate 	/* Wait for few milliseconds */
39587c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(EHCI_SOF_TIMEWAIT));
39597c478bd9Sstevel@tonic-gate 
39607c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
39617c478bd9Sstevel@tonic-gate 
39627c478bd9Sstevel@tonic-gate 	/* Get the current usb frame number after woken up */
39637c478bd9Sstevel@tonic-gate 	after_frame_number = ehci_get_current_frame_number(ehcip);
39647c478bd9Sstevel@tonic-gate 
39657c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
39667c478bd9Sstevel@tonic-gate 	    "ehci_wait_for_sof: framenumber: before 0x%llx "
3967112116d8Sfb 	    "after 0x%llx",
3968112116d8Sfb 	    (unsigned long long)before_frame_number,
3969112116d8Sfb 	    (unsigned long long)after_frame_number);
39707c478bd9Sstevel@tonic-gate 
39717c478bd9Sstevel@tonic-gate 	/* Return failure, if usb frame number has not been changed */
39727c478bd9Sstevel@tonic-gate 	if (after_frame_number <= before_frame_number) {
39737c478bd9Sstevel@tonic-gate 
39747c478bd9Sstevel@tonic-gate 		if ((ehci_do_soft_reset(ehcip)) != USB_SUCCESS) {
39757c478bd9Sstevel@tonic-gate 
39767c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L0(PRINT_MASK_LISTS,
39777c478bd9Sstevel@tonic-gate 			    ehcip->ehci_log_hdl, "No SOF interrupts");
39787c478bd9Sstevel@tonic-gate 
39797c478bd9Sstevel@tonic-gate 			/* Set host controller soft state to error */
39807c478bd9Sstevel@tonic-gate 			ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE;
39817c478bd9Sstevel@tonic-gate 
39827c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
39837c478bd9Sstevel@tonic-gate 		}
39847c478bd9Sstevel@tonic-gate 
39857c478bd9Sstevel@tonic-gate 	}
39867c478bd9Sstevel@tonic-gate 
39877c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
39887c478bd9Sstevel@tonic-gate }
39897c478bd9Sstevel@tonic-gate 
39907c478bd9Sstevel@tonic-gate 
39917c478bd9Sstevel@tonic-gate /*
39927c478bd9Sstevel@tonic-gate  * ehci_toggle_scheduler:
39937c478bd9Sstevel@tonic-gate  *
39947c478bd9Sstevel@tonic-gate  * Turn scheduler based on pipe open count.
39957c478bd9Sstevel@tonic-gate  */
39967c478bd9Sstevel@tonic-gate void
39977c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehci_state_t *ehcip) {
39987c478bd9Sstevel@tonic-gate 	uint_t	temp_reg, cmd_reg;
39997c478bd9Sstevel@tonic-gate 
40007c478bd9Sstevel@tonic-gate 	cmd_reg = Get_OpReg(ehci_command);
40017c478bd9Sstevel@tonic-gate 	temp_reg = cmd_reg;
40027c478bd9Sstevel@tonic-gate 
40037c478bd9Sstevel@tonic-gate 	/*
40047c478bd9Sstevel@tonic-gate 	 * Enable/Disable asynchronous scheduler, and
40057c478bd9Sstevel@tonic-gate 	 * turn on/off async list door bell
40067c478bd9Sstevel@tonic-gate 	 */
40077c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_open_async_count) {
40087c478bd9Sstevel@tonic-gate 		if (!(cmd_reg & EHCI_CMD_ASYNC_SCHED_ENABLE)) {
40097c478bd9Sstevel@tonic-gate 			/*
40107c478bd9Sstevel@tonic-gate 			 * For some reason this address might get nulled out by
40117c478bd9Sstevel@tonic-gate 			 * the ehci chip. Set it here just in case it is null.
40127c478bd9Sstevel@tonic-gate 			 */
40137c478bd9Sstevel@tonic-gate 			Set_OpReg(ehci_async_list_addr,
40147c478bd9Sstevel@tonic-gate 			    ehci_qh_cpu_to_iommu(ehcip,
40157c478bd9Sstevel@tonic-gate 				ehcip->ehci_head_of_async_sched_list));
4016921cd50dSgk 
4017921cd50dSgk 			/*
4018921cd50dSgk 			 * For some reason this register might get nulled out by
4019921cd50dSgk 			 * the Uli M1575 Southbridge. To workaround the HW
4020921cd50dSgk 			 * problem, check the value after write and retry if the
4021921cd50dSgk 			 * last write fails.
4022921cd50dSgk 			 *
4023921cd50dSgk 			 * If the ASYNCLISTADDR remains "stuck" after
4024921cd50dSgk 			 * EHCI_MAX_RETRY retries, then the M1575 is broken
4025921cd50dSgk 			 * and is stuck in an inconsistent state and is about
4026921cd50dSgk 			 * to crash the machine with a trn_oor panic when it
4027921cd50dSgk 			 * does a DMA read from 0x0.  It is better to panic
4028921cd50dSgk 			 * now rather than wait for the trn_oor crash; this
4029921cd50dSgk 			 * way Customer Service will have a clean signature
4030921cd50dSgk 			 * that indicts the M1575 chip rather than a
4031921cd50dSgk 			 * mysterious and hard-to-diagnose trn_oor panic.
4032921cd50dSgk 			 */
4033921cd50dSgk 			if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
4034921cd50dSgk 			    (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) &&
4035921cd50dSgk 			    (ehci_qh_cpu_to_iommu(ehcip,
4036921cd50dSgk 			    ehcip->ehci_head_of_async_sched_list) !=
4037921cd50dSgk 			    Get_OpReg(ehci_async_list_addr))) {
4038921cd50dSgk 				int retry = 0;
4039921cd50dSgk 
4040921cd50dSgk 				Set_OpRegRetry(ehci_async_list_addr,
4041921cd50dSgk 				    ehci_qh_cpu_to_iommu(ehcip,
4042921cd50dSgk 				    ehcip->ehci_head_of_async_sched_list),
4043921cd50dSgk 				    retry);
4044921cd50dSgk 				if (retry >= EHCI_MAX_RETRY)
4045921cd50dSgk 					cmn_err(CE_PANIC,
4046921cd50dSgk 					    "ehci_toggle_scheduler: "
4047921cd50dSgk 					    "ASYNCLISTADDR write failed.");
4048921cd50dSgk 
4049921cd50dSgk 				USB_DPRINTF_L2(PRINT_MASK_ATTA,
4050921cd50dSgk 				    ehcip->ehci_log_hdl,
4051921cd50dSgk 				    "ehci_toggle_scheduler: ASYNCLISTADDR "
4052921cd50dSgk 					"write failed, retry=%d", retry);
4053921cd50dSgk 			}
40547c478bd9Sstevel@tonic-gate 		}
40557c478bd9Sstevel@tonic-gate 		cmd_reg |= EHCI_CMD_ASYNC_SCHED_ENABLE;
40567c478bd9Sstevel@tonic-gate 	} else {
40577c478bd9Sstevel@tonic-gate 		cmd_reg &= ~EHCI_CMD_ASYNC_SCHED_ENABLE;
40587c478bd9Sstevel@tonic-gate 	}
40597c478bd9Sstevel@tonic-gate 
40607c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_open_periodic_count) {
40617c478bd9Sstevel@tonic-gate 		if (!(cmd_reg & EHCI_CMD_PERIODIC_SCHED_ENABLE)) {
40627c478bd9Sstevel@tonic-gate 			/*
40637c478bd9Sstevel@tonic-gate 			 * For some reason this address get's nulled out by
40647c478bd9Sstevel@tonic-gate 			 * the ehci chip. Set it here just in case it is null.
40657c478bd9Sstevel@tonic-gate 			 */
40667c478bd9Sstevel@tonic-gate 			Set_OpReg(ehci_periodic_list_base,
40677c478bd9Sstevel@tonic-gate 			    (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address &
40687c478bd9Sstevel@tonic-gate 				0xFFFFF000));
40697c478bd9Sstevel@tonic-gate 		}
40707c478bd9Sstevel@tonic-gate 		cmd_reg |= EHCI_CMD_PERIODIC_SCHED_ENABLE;
40717c478bd9Sstevel@tonic-gate 	} else {
40727c478bd9Sstevel@tonic-gate 		cmd_reg &= ~EHCI_CMD_PERIODIC_SCHED_ENABLE;
40737c478bd9Sstevel@tonic-gate 	}
40747c478bd9Sstevel@tonic-gate 
40757c478bd9Sstevel@tonic-gate 	/* Just an optimization */
40767c478bd9Sstevel@tonic-gate 	if (temp_reg != cmd_reg) {
40777c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_command, cmd_reg);
40787c478bd9Sstevel@tonic-gate 	}
40797c478bd9Sstevel@tonic-gate }
40807c478bd9Sstevel@tonic-gate 
40817c478bd9Sstevel@tonic-gate /*
40827c478bd9Sstevel@tonic-gate  * ehci print functions
40837c478bd9Sstevel@tonic-gate  */
40847c478bd9Sstevel@tonic-gate 
40857c478bd9Sstevel@tonic-gate /*
40867c478bd9Sstevel@tonic-gate  * ehci_print_caps:
40877c478bd9Sstevel@tonic-gate  */
40887c478bd9Sstevel@tonic-gate void
40897c478bd9Sstevel@tonic-gate ehci_print_caps(ehci_state_t	*ehcip)
40907c478bd9Sstevel@tonic-gate {
40917c478bd9Sstevel@tonic-gate 	uint_t			i;
40927c478bd9Sstevel@tonic-gate 
40937c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
40947c478bd9Sstevel@tonic-gate 	    "\n\tUSB 2.0 Host Controller Characteristics\n");
40957c478bd9Sstevel@tonic-gate 
40967c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
40977c478bd9Sstevel@tonic-gate 	    "Caps Length: 0x%x Version: 0x%x\n",
40987c478bd9Sstevel@tonic-gate 	    Get_8Cap(ehci_caps_length), Get_16Cap(ehci_version));
40997c478bd9Sstevel@tonic-gate 
41007c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41017c478bd9Sstevel@tonic-gate 	    "Structural Parameters\n");
41027c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41037c478bd9Sstevel@tonic-gate 	    "Port indicators: %s", (Get_Cap(ehci_hcs_params) &
41047c478bd9Sstevel@tonic-gate 	    EHCI_HCS_PORT_INDICATOR) ? "Yes" : "No");
41057c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41067c478bd9Sstevel@tonic-gate 	    "No of Classic host controllers: 0x%x",
41077c478bd9Sstevel@tonic-gate 	    (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_COMP_CTRLS)
41087c478bd9Sstevel@tonic-gate 	    >> EHCI_HCS_NUM_COMP_CTRL_SHIFT);
41097c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41107c478bd9Sstevel@tonic-gate 	    "No of ports per Classic host controller: 0x%x",
41117c478bd9Sstevel@tonic-gate 	    (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS_CC)
41127c478bd9Sstevel@tonic-gate 	    >> EHCI_HCS_NUM_PORTS_CC_SHIFT);
41137c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41147c478bd9Sstevel@tonic-gate 	    "Port routing rules: %s", (Get_Cap(ehci_hcs_params) &
41157c478bd9Sstevel@tonic-gate 	    EHCI_HCS_PORT_ROUTING_RULES) ? "Yes" : "No");
41167c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41177c478bd9Sstevel@tonic-gate 	    "Port power control: %s", (Get_Cap(ehci_hcs_params) &
41187c478bd9Sstevel@tonic-gate 	    EHCI_HCS_PORT_POWER_CONTROL) ? "Yes" : "No");
41197c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41207c478bd9Sstevel@tonic-gate 	    "No of root hub ports: 0x%x\n",
41217c478bd9Sstevel@tonic-gate 	    Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS);
41227c478bd9Sstevel@tonic-gate 
41237c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41247c478bd9Sstevel@tonic-gate 	    "Capability Parameters\n");
41257c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41267c478bd9Sstevel@tonic-gate 	    "EHCI extended capability: %s", (Get_Cap(ehci_hcc_params) &
41277c478bd9Sstevel@tonic-gate 	    EHCI_HCC_EECP) ? "Yes" : "No");
41287c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41297c478bd9Sstevel@tonic-gate 	    "Isoch schedule threshold: 0x%x",
41307c478bd9Sstevel@tonic-gate 	    Get_Cap(ehci_hcc_params) & EHCI_HCC_ISOCH_SCHED_THRESHOLD);
41317c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41327c478bd9Sstevel@tonic-gate 	    "Async schedule park capability: %s", (Get_Cap(ehci_hcc_params) &
41337c478bd9Sstevel@tonic-gate 	    EHCI_HCC_ASYNC_SCHED_PARK_CAP) ? "Yes" : "No");
41347c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41357c478bd9Sstevel@tonic-gate 	    "Programmable frame list flag: %s", (Get_Cap(ehci_hcc_params) &
41367c478bd9Sstevel@tonic-gate 	    EHCI_HCC_PROG_FRAME_LIST_FLAG) ? "256/512/1024" : "1024");
41377c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41387c478bd9Sstevel@tonic-gate 	    "64bit addressing capability: %s\n", (Get_Cap(ehci_hcc_params) &
41397c478bd9Sstevel@tonic-gate 	    EHCI_HCC_64BIT_ADDR_CAP) ? "Yes" : "No");
41407c478bd9Sstevel@tonic-gate 
41417c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41427c478bd9Sstevel@tonic-gate 	    "Classic Port Route Description");
41437c478bd9Sstevel@tonic-gate 
41447c478bd9Sstevel@tonic-gate 	for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) {
41457c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41467c478bd9Sstevel@tonic-gate 		    "\tPort Route 0x%x: 0x%x", i, Get_8Cap(ehci_port_route[i]));
41477c478bd9Sstevel@tonic-gate 	}
41487c478bd9Sstevel@tonic-gate }
41497c478bd9Sstevel@tonic-gate 
41507c478bd9Sstevel@tonic-gate 
41517c478bd9Sstevel@tonic-gate /*
41527c478bd9Sstevel@tonic-gate  * ehci_print_regs:
41537c478bd9Sstevel@tonic-gate  */
41547c478bd9Sstevel@tonic-gate void
41557c478bd9Sstevel@tonic-gate ehci_print_regs(ehci_state_t	*ehcip)
41567c478bd9Sstevel@tonic-gate {
41577c478bd9Sstevel@tonic-gate 	uint_t			i;
41587c478bd9Sstevel@tonic-gate 
41597c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41607c478bd9Sstevel@tonic-gate 	    "\n\tEHCI%d Operational Registers\n",
41617c478bd9Sstevel@tonic-gate 	    ddi_get_instance(ehcip->ehci_dip));
41627c478bd9Sstevel@tonic-gate 
41637c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41647c478bd9Sstevel@tonic-gate 	    "Command: 0x%x Status: 0x%x",
41657c478bd9Sstevel@tonic-gate 	    Get_OpReg(ehci_command), Get_OpReg(ehci_status));
41667c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41677c478bd9Sstevel@tonic-gate 	    "Interrupt: 0x%x Frame Index: 0x%x",
41687c478bd9Sstevel@tonic-gate 	    Get_OpReg(ehci_interrupt), Get_OpReg(ehci_frame_index));
41697c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41707c478bd9Sstevel@tonic-gate 	    "Control Segment: 0x%x Periodic List Base: 0x%x",
41717c478bd9Sstevel@tonic-gate 	    Get_OpReg(ehci_ctrl_segment), Get_OpReg(ehci_periodic_list_base));
41727c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41737c478bd9Sstevel@tonic-gate 	    "Async List Addr: 0x%x Config Flag: 0x%x",
41747c478bd9Sstevel@tonic-gate 	    Get_OpReg(ehci_async_list_addr), Get_OpReg(ehci_config_flag));
41757c478bd9Sstevel@tonic-gate 
41767c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41777c478bd9Sstevel@tonic-gate 	    "Root Hub Port Status");
41787c478bd9Sstevel@tonic-gate 
41797c478bd9Sstevel@tonic-gate 	for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) {
41807c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
41817c478bd9Sstevel@tonic-gate 		    "\tPort Status 0x%x: 0x%x ", i,
41827c478bd9Sstevel@tonic-gate 		    Get_OpReg(ehci_rh_port_status[i]));
41837c478bd9Sstevel@tonic-gate 	}
41847c478bd9Sstevel@tonic-gate }
41857c478bd9Sstevel@tonic-gate 
41867c478bd9Sstevel@tonic-gate 
41877c478bd9Sstevel@tonic-gate /*
41887c478bd9Sstevel@tonic-gate  * ehci_print_qh:
41897c478bd9Sstevel@tonic-gate  */
41907c478bd9Sstevel@tonic-gate void
41917c478bd9Sstevel@tonic-gate ehci_print_qh(
41927c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
41937c478bd9Sstevel@tonic-gate 	ehci_qh_t	*qh)
41947c478bd9Sstevel@tonic-gate {
41957c478bd9Sstevel@tonic-gate 	uint_t		i;
41967c478bd9Sstevel@tonic-gate 
41977c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
41987c478bd9Sstevel@tonic-gate 	    "ehci_print_qh: qh = 0x%p", (void *)qh);
41997c478bd9Sstevel@tonic-gate 
42007c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42017c478bd9Sstevel@tonic-gate 	    "\tqh_link_ptr: 0x%x ", Get_QH(qh->qh_link_ptr));
42027c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42037c478bd9Sstevel@tonic-gate 	    "\tqh_ctrl: 0x%x ", Get_QH(qh->qh_ctrl));
42047c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42057c478bd9Sstevel@tonic-gate 	    "\tqh_split_ctrl: 0x%x ", Get_QH(qh->qh_split_ctrl));
42067c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42077c478bd9Sstevel@tonic-gate 	    "\tqh_curr_qtd: 0x%x ", Get_QH(qh->qh_curr_qtd));
42087c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42097c478bd9Sstevel@tonic-gate 	    "\tqh_next_qtd: 0x%x ", Get_QH(qh->qh_next_qtd));
42107c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42117c478bd9Sstevel@tonic-gate 	    "\tqh_alt_next_qtd: 0x%x ", Get_QH(qh->qh_alt_next_qtd));
42127c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42137c478bd9Sstevel@tonic-gate 	    "\tqh_status: 0x%x ", Get_QH(qh->qh_status));
42147c478bd9Sstevel@tonic-gate 
42157c478bd9Sstevel@tonic-gate 	for (i = 0; i < 5; i++) {
42167c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42177c478bd9Sstevel@tonic-gate 		    "\tqh_buf[%d]: 0x%x ", i, Get_QH(qh->qh_buf[i]));
42187c478bd9Sstevel@tonic-gate 	}
42197c478bd9Sstevel@tonic-gate 
42207c478bd9Sstevel@tonic-gate 	for (i = 0; i < 5; i++) {
42217c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42227c478bd9Sstevel@tonic-gate 		    "\tqh_buf_high[%d]: 0x%x ",
42237c478bd9Sstevel@tonic-gate 		    i, Get_QH(qh->qh_buf_high[i]));
42247c478bd9Sstevel@tonic-gate 	}
42257c478bd9Sstevel@tonic-gate 
42267c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42277c478bd9Sstevel@tonic-gate 	    "\tqh_dummy_qtd: 0x%x ", Get_QH(qh->qh_dummy_qtd));
42287c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42297c478bd9Sstevel@tonic-gate 	    "\tqh_prev: 0x%x ", Get_QH(qh->qh_prev));
42307c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42317c478bd9Sstevel@tonic-gate 	    "\tqh_state: 0x%x ", Get_QH(qh->qh_state));
42327c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42337c478bd9Sstevel@tonic-gate 	    "\tqh_reclaim_next: 0x%x ", Get_QH(qh->qh_reclaim_next));
42347c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42357c478bd9Sstevel@tonic-gate 	    "\tqh_reclaim_frame: 0x%x ", Get_QH(qh->qh_reclaim_frame));
42367c478bd9Sstevel@tonic-gate }
42377c478bd9Sstevel@tonic-gate 
42387c478bd9Sstevel@tonic-gate 
42397c478bd9Sstevel@tonic-gate /*
42407c478bd9Sstevel@tonic-gate  * ehci_print_qtd:
42417c478bd9Sstevel@tonic-gate  */
42427c478bd9Sstevel@tonic-gate void
42437c478bd9Sstevel@tonic-gate ehci_print_qtd(
42447c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
42457c478bd9Sstevel@tonic-gate 	ehci_qtd_t	*qtd)
42467c478bd9Sstevel@tonic-gate {
42477c478bd9Sstevel@tonic-gate 	uint_t		i;
42487c478bd9Sstevel@tonic-gate 
42497c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42507c478bd9Sstevel@tonic-gate 	    "ehci_print_qtd: qtd = 0x%p", (void *)qtd);
42517c478bd9Sstevel@tonic-gate 
42527c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42537c478bd9Sstevel@tonic-gate 	    "\tqtd_next_qtd: 0x%x ", Get_QTD(qtd->qtd_next_qtd));
42547c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42557c478bd9Sstevel@tonic-gate 	    "\tqtd_alt_next_qtd: 0x%x ", Get_QTD(qtd->qtd_alt_next_qtd));
42567c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42577c478bd9Sstevel@tonic-gate 	    "\tqtd_ctrl: 0x%x ", Get_QTD(qtd->qtd_ctrl));
42587c478bd9Sstevel@tonic-gate 
42597c478bd9Sstevel@tonic-gate 	for (i = 0; i < 5; i++) {
42607c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42617c478bd9Sstevel@tonic-gate 		    "\tqtd_buf[%d]: 0x%x ", i, Get_QTD(qtd->qtd_buf[i]));
42627c478bd9Sstevel@tonic-gate 	}
42637c478bd9Sstevel@tonic-gate 
42647c478bd9Sstevel@tonic-gate 	for (i = 0; i < 5; i++) {
42657c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42667c478bd9Sstevel@tonic-gate 		    "\tqtd_buf_high[%d]: 0x%x ",
42677c478bd9Sstevel@tonic-gate 		    i, Get_QTD(qtd->qtd_buf_high[i]));
42687c478bd9Sstevel@tonic-gate 	}
42697c478bd9Sstevel@tonic-gate 
42707c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42717c478bd9Sstevel@tonic-gate 	    "\tqtd_trans_wrapper: 0x%x ", Get_QTD(qtd->qtd_trans_wrapper));
42727c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42737c478bd9Sstevel@tonic-gate 	    "\tqtd_tw_next_qtd: 0x%x ", Get_QTD(qtd->qtd_tw_next_qtd));
42747c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42757c478bd9Sstevel@tonic-gate 	    "\tqtd_active_qtd_next: 0x%x ", Get_QTD(qtd->qtd_active_qtd_next));
42767c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42777c478bd9Sstevel@tonic-gate 	    "\tqtd_active_qtd_prev: 0x%x ", Get_QTD(qtd->qtd_active_qtd_prev));
42787c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42797c478bd9Sstevel@tonic-gate 	    "\tqtd_state: 0x%x ", Get_QTD(qtd->qtd_state));
42807c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42817c478bd9Sstevel@tonic-gate 	    "\tqtd_ctrl_phase: 0x%x ", Get_QTD(qtd->qtd_ctrl_phase));
42827c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42833304303fSsl 	    "\tqtd_xfer_offs: 0x%x ", Get_QTD(qtd->qtd_xfer_offs));
42847c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
42857c478bd9Sstevel@tonic-gate 	    "\tqtd_xfer_len: 0x%x ", Get_QTD(qtd->qtd_xfer_len));
42867c478bd9Sstevel@tonic-gate }
42877c478bd9Sstevel@tonic-gate 
42887c478bd9Sstevel@tonic-gate /*
42897c478bd9Sstevel@tonic-gate  * ehci kstat functions
42907c478bd9Sstevel@tonic-gate  */
42917c478bd9Sstevel@tonic-gate 
42927c478bd9Sstevel@tonic-gate /*
42937c478bd9Sstevel@tonic-gate  * ehci_create_stats:
42947c478bd9Sstevel@tonic-gate  *
42957c478bd9Sstevel@tonic-gate  * Allocate and initialize the ehci kstat structures
42967c478bd9Sstevel@tonic-gate  */
42977c478bd9Sstevel@tonic-gate void
42987c478bd9Sstevel@tonic-gate ehci_create_stats(ehci_state_t	*ehcip)
42997c478bd9Sstevel@tonic-gate {
43007c478bd9Sstevel@tonic-gate 	char			kstatname[KSTAT_STRLEN];
43017c478bd9Sstevel@tonic-gate 	const char		*dname = ddi_driver_name(ehcip->ehci_dip);
43027c478bd9Sstevel@tonic-gate 	char			*usbtypes[USB_N_COUNT_KSTATS] =
430329aca3ebSlc 	    {"ctrl", "isoch", "bulk", "intr"};
43047c478bd9Sstevel@tonic-gate 	uint_t			instance = ehcip->ehci_instance;
43057c478bd9Sstevel@tonic-gate 	ehci_intrs_stats_t	*isp;
43067c478bd9Sstevel@tonic-gate 	int			i;
43077c478bd9Sstevel@tonic-gate 
43087c478bd9Sstevel@tonic-gate 	if (EHCI_INTRS_STATS(ehcip) == NULL) {
43097c478bd9Sstevel@tonic-gate 		(void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,intrs",
43107c478bd9Sstevel@tonic-gate 		    dname, instance);
43117c478bd9Sstevel@tonic-gate 		EHCI_INTRS_STATS(ehcip) = kstat_create("usba", instance,
43127c478bd9Sstevel@tonic-gate 		    kstatname, "usb_interrupts", KSTAT_TYPE_NAMED,
43137c478bd9Sstevel@tonic-gate 		    sizeof (ehci_intrs_stats_t) / sizeof (kstat_named_t),
43147c478bd9Sstevel@tonic-gate 		    KSTAT_FLAG_PERSISTENT);
43157c478bd9Sstevel@tonic-gate 
43167c478bd9Sstevel@tonic-gate 		if (EHCI_INTRS_STATS(ehcip)) {
43177c478bd9Sstevel@tonic-gate 			isp = EHCI_INTRS_STATS_DATA(ehcip);
43187c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_total,
43197c478bd9Sstevel@tonic-gate 			    "Interrupts Total", KSTAT_DATA_UINT64);
43207c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_not_claimed,
43217c478bd9Sstevel@tonic-gate 			    "Not Claimed", KSTAT_DATA_UINT64);
43227c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_async_sched_status,
43237c478bd9Sstevel@tonic-gate 			    "Async schedule status", KSTAT_DATA_UINT64);
43247c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_periodic_sched_status,
43257c478bd9Sstevel@tonic-gate 			    "Periodic sched status", KSTAT_DATA_UINT64);
43267c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_empty_async_schedule,
43277c478bd9Sstevel@tonic-gate 			    "Empty async schedule", KSTAT_DATA_UINT64);
43287c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_host_ctrl_halted,
43297c478bd9Sstevel@tonic-gate 			    "Host controller Halted", KSTAT_DATA_UINT64);
43307c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_async_advance_intr,
43317c478bd9Sstevel@tonic-gate 			    "Intr on async advance", KSTAT_DATA_UINT64);
43327c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_host_system_error_intr,
43337c478bd9Sstevel@tonic-gate 			    "Host system error", KSTAT_DATA_UINT64);
43347c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_frm_list_rollover_intr,
43357c478bd9Sstevel@tonic-gate 			    "Frame list rollover", KSTAT_DATA_UINT64);
43367c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_rh_port_change_intr,
43377c478bd9Sstevel@tonic-gate 			    "Port change detect", KSTAT_DATA_UINT64);
43387c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_usb_error_intr,
43397c478bd9Sstevel@tonic-gate 			    "USB error interrupt", KSTAT_DATA_UINT64);
43407c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_usb_intr,
43417c478bd9Sstevel@tonic-gate 			    "USB interrupt", KSTAT_DATA_UINT64);
43427c478bd9Sstevel@tonic-gate 
43437c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS(ehcip)->ks_private = ehcip;
43447c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS(ehcip)->ks_update = nulldev;
43457c478bd9Sstevel@tonic-gate 			kstat_install(EHCI_INTRS_STATS(ehcip));
43467c478bd9Sstevel@tonic-gate 		}
43477c478bd9Sstevel@tonic-gate 	}
43487c478bd9Sstevel@tonic-gate 
43497c478bd9Sstevel@tonic-gate 	if (EHCI_TOTAL_STATS(ehcip) == NULL) {
43507c478bd9Sstevel@tonic-gate 		(void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,total",
43517c478bd9Sstevel@tonic-gate 		    dname, instance);
43527c478bd9Sstevel@tonic-gate 		EHCI_TOTAL_STATS(ehcip) = kstat_create("usba", instance,
43537c478bd9Sstevel@tonic-gate 		    kstatname, "usb_byte_count", KSTAT_TYPE_IO, 1,
43547c478bd9Sstevel@tonic-gate 		    KSTAT_FLAG_PERSISTENT);
43557c478bd9Sstevel@tonic-gate 
43567c478bd9Sstevel@tonic-gate 		if (EHCI_TOTAL_STATS(ehcip)) {
43577c478bd9Sstevel@tonic-gate 			kstat_install(EHCI_TOTAL_STATS(ehcip));
43587c478bd9Sstevel@tonic-gate 		}
43597c478bd9Sstevel@tonic-gate 	}
43607c478bd9Sstevel@tonic-gate 
43617c478bd9Sstevel@tonic-gate 	for (i = 0; i < USB_N_COUNT_KSTATS; i++) {
43627c478bd9Sstevel@tonic-gate 		if (ehcip->ehci_count_stats[i] == NULL) {
43637c478bd9Sstevel@tonic-gate 			(void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,%s",
43647c478bd9Sstevel@tonic-gate 			    dname, instance, usbtypes[i]);
43657c478bd9Sstevel@tonic-gate 			ehcip->ehci_count_stats[i] = kstat_create("usba",
43667c478bd9Sstevel@tonic-gate 			    instance, kstatname, "usb_byte_count",
43677c478bd9Sstevel@tonic-gate 			    KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
43687c478bd9Sstevel@tonic-gate 
43697c478bd9Sstevel@tonic-gate 			if (ehcip->ehci_count_stats[i]) {
43707c478bd9Sstevel@tonic-gate 				kstat_install(ehcip->ehci_count_stats[i]);
43717c478bd9Sstevel@tonic-gate 			}
43727c478bd9Sstevel@tonic-gate 		}
43737c478bd9Sstevel@tonic-gate 	}
43747c478bd9Sstevel@tonic-gate }
43757c478bd9Sstevel@tonic-gate 
43767c478bd9Sstevel@tonic-gate 
43777c478bd9Sstevel@tonic-gate /*
43787c478bd9Sstevel@tonic-gate  * ehci_destroy_stats:
43797c478bd9Sstevel@tonic-gate  *
43807c478bd9Sstevel@tonic-gate  * Clean up ehci kstat structures
43817c478bd9Sstevel@tonic-gate  */
43827c478bd9Sstevel@tonic-gate void
43837c478bd9Sstevel@tonic-gate ehci_destroy_stats(ehci_state_t	*ehcip)
43847c478bd9Sstevel@tonic-gate {
43857c478bd9Sstevel@tonic-gate 	int	i;
43867c478bd9Sstevel@tonic-gate 
43877c478bd9Sstevel@tonic-gate 	if (EHCI_INTRS_STATS(ehcip)) {
43887c478bd9Sstevel@tonic-gate 		kstat_delete(EHCI_INTRS_STATS(ehcip));
43897c478bd9Sstevel@tonic-gate 		EHCI_INTRS_STATS(ehcip) = NULL;
43907c478bd9Sstevel@tonic-gate 	}
43917c478bd9Sstevel@tonic-gate 
43927c478bd9Sstevel@tonic-gate 	if (EHCI_TOTAL_STATS(ehcip)) {
43937c478bd9Sstevel@tonic-gate 		kstat_delete(EHCI_TOTAL_STATS(ehcip));
43947c478bd9Sstevel@tonic-gate 		EHCI_TOTAL_STATS(ehcip) = NULL;
43957c478bd9Sstevel@tonic-gate 	}
43967c478bd9Sstevel@tonic-gate 
43977c478bd9Sstevel@tonic-gate 	for (i = 0; i < USB_N_COUNT_KSTATS; i++) {
43987c478bd9Sstevel@tonic-gate 		if (ehcip->ehci_count_stats[i]) {
43997c478bd9Sstevel@tonic-gate 			kstat_delete(ehcip->ehci_count_stats[i]);
44007c478bd9Sstevel@tonic-gate 			ehcip->ehci_count_stats[i] = NULL;
44017c478bd9Sstevel@tonic-gate 		}
44027c478bd9Sstevel@tonic-gate 	}
44037c478bd9Sstevel@tonic-gate }
44047c478bd9Sstevel@tonic-gate 
44057c478bd9Sstevel@tonic-gate 
44067c478bd9Sstevel@tonic-gate /*
44077c478bd9Sstevel@tonic-gate  * ehci_do_intrs_stats:
44087c478bd9Sstevel@tonic-gate  *
44097c478bd9Sstevel@tonic-gate  * ehci status information
44107c478bd9Sstevel@tonic-gate  */
44117c478bd9Sstevel@tonic-gate void
44127c478bd9Sstevel@tonic-gate ehci_do_intrs_stats(
44137c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
44147c478bd9Sstevel@tonic-gate 	int		val)
44157c478bd9Sstevel@tonic-gate {
44167c478bd9Sstevel@tonic-gate 	if (EHCI_INTRS_STATS(ehcip)) {
44177c478bd9Sstevel@tonic-gate 		EHCI_INTRS_STATS_DATA(ehcip)->ehci_sts_total.value.ui64++;
44187c478bd9Sstevel@tonic-gate 		switch (val) {
44197c478bd9Sstevel@tonic-gate 		case EHCI_STS_ASYNC_SCHED_STATUS:
44207c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
44217c478bd9Sstevel@tonic-gate 			    ehci_sts_async_sched_status.value.ui64++;
44227c478bd9Sstevel@tonic-gate 			break;
44237c478bd9Sstevel@tonic-gate 		case EHCI_STS_PERIODIC_SCHED_STATUS:
44247c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
44257c478bd9Sstevel@tonic-gate 			    ehci_sts_periodic_sched_status.value.ui64++;
44267c478bd9Sstevel@tonic-gate 			break;
44277c478bd9Sstevel@tonic-gate 		case EHCI_STS_EMPTY_ASYNC_SCHEDULE:
44287c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
44297c478bd9Sstevel@tonic-gate 			    ehci_sts_empty_async_schedule.value.ui64++;
44307c478bd9Sstevel@tonic-gate 			break;
44317c478bd9Sstevel@tonic-gate 		case EHCI_STS_HOST_CTRL_HALTED:
44327c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
44337c478bd9Sstevel@tonic-gate 			    ehci_sts_host_ctrl_halted.value.ui64++;
44347c478bd9Sstevel@tonic-gate 			break;
44357c478bd9Sstevel@tonic-gate 		case EHCI_STS_ASYNC_ADVANCE_INTR:
44367c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
44377c478bd9Sstevel@tonic-gate 			    ehci_sts_async_advance_intr.value.ui64++;
44387c478bd9Sstevel@tonic-gate 			break;
44397c478bd9Sstevel@tonic-gate 		case EHCI_STS_HOST_SYSTEM_ERROR_INTR:
44407c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
44417c478bd9Sstevel@tonic-gate 			    ehci_sts_host_system_error_intr.value.ui64++;
44427c478bd9Sstevel@tonic-gate 			break;
44437c478bd9Sstevel@tonic-gate 		case EHCI_STS_FRM_LIST_ROLLOVER_INTR:
44447c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
44457c478bd9Sstevel@tonic-gate 			    ehci_sts_frm_list_rollover_intr.value.ui64++;
44467c478bd9Sstevel@tonic-gate 			break;
44477c478bd9Sstevel@tonic-gate 		case EHCI_STS_RH_PORT_CHANGE_INTR:
44487c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
44497c478bd9Sstevel@tonic-gate 			    ehci_sts_rh_port_change_intr.value.ui64++;
44507c478bd9Sstevel@tonic-gate 			break;
44517c478bd9Sstevel@tonic-gate 		case EHCI_STS_USB_ERROR_INTR:
44527c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
44537c478bd9Sstevel@tonic-gate 			    ehci_sts_usb_error_intr.value.ui64++;
44547c478bd9Sstevel@tonic-gate 			break;
44557c478bd9Sstevel@tonic-gate 		case EHCI_STS_USB_INTR:
44567c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
44577c478bd9Sstevel@tonic-gate 			    ehci_sts_usb_intr.value.ui64++;
44587c478bd9Sstevel@tonic-gate 			break;
44597c478bd9Sstevel@tonic-gate 		default:
44607c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
44617c478bd9Sstevel@tonic-gate 			    ehci_sts_not_claimed.value.ui64++;
44627c478bd9Sstevel@tonic-gate 			break;
44637c478bd9Sstevel@tonic-gate 		}
44647c478bd9Sstevel@tonic-gate 	}
44657c478bd9Sstevel@tonic-gate }
44667c478bd9Sstevel@tonic-gate 
44677c478bd9Sstevel@tonic-gate 
44687c478bd9Sstevel@tonic-gate /*
44697c478bd9Sstevel@tonic-gate  * ehci_do_byte_stats:
44707c478bd9Sstevel@tonic-gate  *
44717c478bd9Sstevel@tonic-gate  * ehci data xfer information
44727c478bd9Sstevel@tonic-gate  */
44737c478bd9Sstevel@tonic-gate void
44747c478bd9Sstevel@tonic-gate ehci_do_byte_stats(
44757c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
44767c478bd9Sstevel@tonic-gate 	size_t		len,
44777c478bd9Sstevel@tonic-gate 	uint8_t		attr,
44787c478bd9Sstevel@tonic-gate 	uint8_t		addr)
44797c478bd9Sstevel@tonic-gate {
44807c478bd9Sstevel@tonic-gate 	uint8_t 	type = attr & USB_EP_ATTR_MASK;
44817c478bd9Sstevel@tonic-gate 	uint8_t 	dir = addr & USB_EP_DIR_MASK;
44827c478bd9Sstevel@tonic-gate 
44837c478bd9Sstevel@tonic-gate 	if (dir == USB_EP_DIR_IN) {
44847c478bd9Sstevel@tonic-gate 		EHCI_TOTAL_STATS_DATA(ehcip)->reads++;
44857c478bd9Sstevel@tonic-gate 		EHCI_TOTAL_STATS_DATA(ehcip)->nread += len;
44867c478bd9Sstevel@tonic-gate 		switch (type) {
44877c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_CONTROL:
44887c478bd9Sstevel@tonic-gate 				EHCI_CTRL_STATS(ehcip)->reads++;
44897c478bd9Sstevel@tonic-gate 				EHCI_CTRL_STATS(ehcip)->nread += len;
44907c478bd9Sstevel@tonic-gate 				break;
44917c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_BULK:
44927c478bd9Sstevel@tonic-gate 				EHCI_BULK_STATS(ehcip)->reads++;
44937c478bd9Sstevel@tonic-gate 				EHCI_BULK_STATS(ehcip)->nread += len;
44947c478bd9Sstevel@tonic-gate 				break;
44957c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_INTR:
44967c478bd9Sstevel@tonic-gate 				EHCI_INTR_STATS(ehcip)->reads++;
44977c478bd9Sstevel@tonic-gate 				EHCI_INTR_STATS(ehcip)->nread += len;
44987c478bd9Sstevel@tonic-gate 				break;
44997c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_ISOCH:
45007c478bd9Sstevel@tonic-gate 				EHCI_ISOC_STATS(ehcip)->reads++;
45017c478bd9Sstevel@tonic-gate 				EHCI_ISOC_STATS(ehcip)->nread += len;
45027c478bd9Sstevel@tonic-gate 				break;
45037c478bd9Sstevel@tonic-gate 		}
45047c478bd9Sstevel@tonic-gate 	} else if (dir == USB_EP_DIR_OUT) {
45057c478bd9Sstevel@tonic-gate 		EHCI_TOTAL_STATS_DATA(ehcip)->writes++;
45067c478bd9Sstevel@tonic-gate 		EHCI_TOTAL_STATS_DATA(ehcip)->nwritten += len;
45077c478bd9Sstevel@tonic-gate 		switch (type) {
45087c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_CONTROL:
45097c478bd9Sstevel@tonic-gate 				EHCI_CTRL_STATS(ehcip)->writes++;
45107c478bd9Sstevel@tonic-gate 				EHCI_CTRL_STATS(ehcip)->nwritten += len;
45117c478bd9Sstevel@tonic-gate 				break;
45127c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_BULK:
45137c478bd9Sstevel@tonic-gate 				EHCI_BULK_STATS(ehcip)->writes++;
45147c478bd9Sstevel@tonic-gate 				EHCI_BULK_STATS(ehcip)->nwritten += len;
45157c478bd9Sstevel@tonic-gate 				break;
45167c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_INTR:
45177c478bd9Sstevel@tonic-gate 				EHCI_INTR_STATS(ehcip)->writes++;
45187c478bd9Sstevel@tonic-gate 				EHCI_INTR_STATS(ehcip)->nwritten += len;
45197c478bd9Sstevel@tonic-gate 				break;
45207c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_ISOCH:
45217c478bd9Sstevel@tonic-gate 				EHCI_ISOC_STATS(ehcip)->writes++;
45227c478bd9Sstevel@tonic-gate 				EHCI_ISOC_STATS(ehcip)->nwritten += len;
45237c478bd9Sstevel@tonic-gate 				break;
45247c478bd9Sstevel@tonic-gate 		}
45257c478bd9Sstevel@tonic-gate 	}
45267c478bd9Sstevel@tonic-gate }
4527