1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * EHCI Host Controller Driver (EHCI)
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * The EHCI driver is a software driver which interfaces to the Universal
33*7c478bd9Sstevel@tonic-gate  * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
34*7c478bd9Sstevel@tonic-gate  * the Host Controller is defined by the EHCI Host Controller Interface.
35*7c478bd9Sstevel@tonic-gate  *
36*7c478bd9Sstevel@tonic-gate  * This module contains the main EHCI driver code which handles all USB
37*7c478bd9Sstevel@tonic-gate  * transfers, bandwidth allocations and other general functionalities.
38*7c478bd9Sstevel@tonic-gate  */
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_isoch.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate /* Pointer to the state structure */
45*7c478bd9Sstevel@tonic-gate extern void *ehci_statep;
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate extern void ehci_handle_endpoint_reclaimation(ehci_state_t *);
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate extern uint_t ehci_vt62x2_workaround;
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate /* Adjustable variables for the size of the pools */
52*7c478bd9Sstevel@tonic-gate int ehci_qh_pool_size = EHCI_QH_POOL_SIZE;
53*7c478bd9Sstevel@tonic-gate int ehci_qtd_pool_size = EHCI_QTD_POOL_SIZE;
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate /*
56*7c478bd9Sstevel@tonic-gate  * Initialize the values which the order of 32ms intr qh are executed
57*7c478bd9Sstevel@tonic-gate  * by the host controller in the lattice tree.
58*7c478bd9Sstevel@tonic-gate  */
59*7c478bd9Sstevel@tonic-gate static uchar_t ehci_index[EHCI_NUM_INTR_QH_LISTS] =
60*7c478bd9Sstevel@tonic-gate 	{0x00, 0x10, 0x08, 0x18,
61*7c478bd9Sstevel@tonic-gate 	0x04, 0x14, 0x0c, 0x1c,
62*7c478bd9Sstevel@tonic-gate 	0x02, 0x12, 0x0a, 0x1a,
63*7c478bd9Sstevel@tonic-gate 	0x06, 0x16, 0x0e, 0x1e,
64*7c478bd9Sstevel@tonic-gate 	0x01, 0x11, 0x09, 0x19,
65*7c478bd9Sstevel@tonic-gate 	0x05, 0x15, 0x0d, 0x1d,
66*7c478bd9Sstevel@tonic-gate 	0x03, 0x13, 0x0b, 0x1b,
67*7c478bd9Sstevel@tonic-gate 	0x07, 0x17, 0x0f, 0x1f};
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate /*
70*7c478bd9Sstevel@tonic-gate  * Initialize the values which are used to calculate start split mask
71*7c478bd9Sstevel@tonic-gate  * for the low/full/high speed interrupt and isochronous endpoints.
72*7c478bd9Sstevel@tonic-gate  */
73*7c478bd9Sstevel@tonic-gate static uint_t ehci_start_split_mask[15] = {
74*7c478bd9Sstevel@tonic-gate 		/*
75*7c478bd9Sstevel@tonic-gate 		 * For high/full/low speed usb devices. For high speed
76*7c478bd9Sstevel@tonic-gate 		 * device with polling interval greater than or equal
77*7c478bd9Sstevel@tonic-gate 		 * to 8us (125us).
78*7c478bd9Sstevel@tonic-gate 		 */
79*7c478bd9Sstevel@tonic-gate 		0x01,	/* 00000001 */
80*7c478bd9Sstevel@tonic-gate 		0x02,	/* 00000010 */
81*7c478bd9Sstevel@tonic-gate 		0x04,	/* 00000100 */
82*7c478bd9Sstevel@tonic-gate 		0x08,	/* 00001000 */
83*7c478bd9Sstevel@tonic-gate 		0x10,	/* 00010000 */
84*7c478bd9Sstevel@tonic-gate 		0x20,	/* 00100000 */
85*7c478bd9Sstevel@tonic-gate 		0x40,	/* 01000000 */
86*7c478bd9Sstevel@tonic-gate 		0x80,	/* 10000000 */
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 		/* Only for high speed devices with polling interval 4us */
89*7c478bd9Sstevel@tonic-gate 		0x11,	/* 00010001 */
90*7c478bd9Sstevel@tonic-gate 		0x22,	/* 00100010 */
91*7c478bd9Sstevel@tonic-gate 		0x44,	/* 01000100 */
92*7c478bd9Sstevel@tonic-gate 		0x88,	/* 10001000 */
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate 		/* Only for high speed devices with polling interval 2us */
95*7c478bd9Sstevel@tonic-gate 		0x55,	/* 01010101 */
96*7c478bd9Sstevel@tonic-gate 		0xaa,	/* 10101010 */
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate 		/* Only for high speed devices with polling interval 1us */
99*7c478bd9Sstevel@tonic-gate 		0xff	/* 11111111 */
100*7c478bd9Sstevel@tonic-gate };
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate /*
103*7c478bd9Sstevel@tonic-gate  * Initialize the values which are used to calculate complete split mask
104*7c478bd9Sstevel@tonic-gate  * for the low/full speed interrupt and isochronous endpoints.
105*7c478bd9Sstevel@tonic-gate  */
106*7c478bd9Sstevel@tonic-gate static uint_t ehci_intr_complete_split_mask[7] = {
107*7c478bd9Sstevel@tonic-gate 		/* Only full/low speed devices */
108*7c478bd9Sstevel@tonic-gate 		0x1c,	/* 00011100 */
109*7c478bd9Sstevel@tonic-gate 		0x38,	/* 00111000 */
110*7c478bd9Sstevel@tonic-gate 		0x70,	/* 01110000 */
111*7c478bd9Sstevel@tonic-gate 		0xe0,	/* 11100000 */
112*7c478bd9Sstevel@tonic-gate 		0x00,	/* Need FSTN feature */
113*7c478bd9Sstevel@tonic-gate 		0x00,	/* Need FSTN feature */
114*7c478bd9Sstevel@tonic-gate 		0x00	/* Need FSTN feature */
115*7c478bd9Sstevel@tonic-gate };
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate /*
119*7c478bd9Sstevel@tonic-gate  * EHCI Internal Function Prototypes
120*7c478bd9Sstevel@tonic-gate  */
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) initialization functions */
123*7c478bd9Sstevel@tonic-gate void		ehci_set_dma_attributes(ehci_state_t	*ehcip);
124*7c478bd9Sstevel@tonic-gate int		ehci_allocate_pools(ehci_state_t	*ehcip);
125*7c478bd9Sstevel@tonic-gate void		ehci_decode_ddi_dma_addr_bind_handle_result(
126*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
127*7c478bd9Sstevel@tonic-gate 				int			result);
128*7c478bd9Sstevel@tonic-gate int		ehci_map_regs(ehci_state_t		*ehcip);
129*7c478bd9Sstevel@tonic-gate int		ehci_register_intrs_and_init_mutex(
130*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
131*7c478bd9Sstevel@tonic-gate int		ehci_init_ctlr(ehci_state_t		*ehcip);
132*7c478bd9Sstevel@tonic-gate static int	ehci_take_control(ehci_state_t		*ehcip);
133*7c478bd9Sstevel@tonic-gate static int	ehci_init_periodic_frame_lst_table(
134*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
135*7c478bd9Sstevel@tonic-gate static void	ehci_build_interrupt_lattice(
136*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
137*7c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *ehci_alloc_hcdi_ops(ehci_state_t	*ehcip);
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) deinitialization functions */
140*7c478bd9Sstevel@tonic-gate int		ehci_cleanup(ehci_state_t		*ehcip);
141*7c478bd9Sstevel@tonic-gate int		ehci_cpr_suspend(ehci_state_t		*ehcip);
142*7c478bd9Sstevel@tonic-gate int		ehci_cpr_resume(ehci_state_t		*ehcip);
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate /* Bandwidth Allocation functions */
145*7c478bd9Sstevel@tonic-gate int		ehci_allocate_bandwidth(ehci_state_t	*ehcip,
146*7c478bd9Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
147*7c478bd9Sstevel@tonic-gate 				uint_t			*pnode,
148*7c478bd9Sstevel@tonic-gate 				uchar_t			*smask,
149*7c478bd9Sstevel@tonic-gate 				uchar_t			*cmask);
150*7c478bd9Sstevel@tonic-gate static int	ehci_allocate_high_speed_bandwidth(
151*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
152*7c478bd9Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
153*7c478bd9Sstevel@tonic-gate 				uint_t			*hnode,
154*7c478bd9Sstevel@tonic-gate 				uchar_t			*smask,
155*7c478bd9Sstevel@tonic-gate 				uchar_t			*cmask);
156*7c478bd9Sstevel@tonic-gate static int	ehci_allocate_classic_tt_bandwidth(
157*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
158*7c478bd9Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
159*7c478bd9Sstevel@tonic-gate 				uint_t			pnode);
160*7c478bd9Sstevel@tonic-gate void		ehci_deallocate_bandwidth(ehci_state_t	*ehcip,
161*7c478bd9Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
162*7c478bd9Sstevel@tonic-gate 				uint_t			pnode,
163*7c478bd9Sstevel@tonic-gate 				uchar_t			smask,
164*7c478bd9Sstevel@tonic-gate 				uchar_t			cmask);
165*7c478bd9Sstevel@tonic-gate static void	ehci_deallocate_high_speed_bandwidth(
166*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
167*7c478bd9Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
168*7c478bd9Sstevel@tonic-gate 				uint_t			hnode,
169*7c478bd9Sstevel@tonic-gate 				uchar_t			smask,
170*7c478bd9Sstevel@tonic-gate 				uchar_t			cmask);
171*7c478bd9Sstevel@tonic-gate static void	ehci_deallocate_classic_tt_bandwidth(
172*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
173*7c478bd9Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
174*7c478bd9Sstevel@tonic-gate 				uint_t			pnode);
175*7c478bd9Sstevel@tonic-gate static int	ehci_compute_high_speed_bandwidth(
176*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
177*7c478bd9Sstevel@tonic-gate 				usb_ep_descr_t		*endpoint,
178*7c478bd9Sstevel@tonic-gate 				usb_port_status_t	port_status,
179*7c478bd9Sstevel@tonic-gate 				uint_t			*sbandwidth,
180*7c478bd9Sstevel@tonic-gate 				uint_t			*cbandwidth);
181*7c478bd9Sstevel@tonic-gate static int	ehci_compute_classic_bandwidth(
182*7c478bd9Sstevel@tonic-gate 				usb_ep_descr_t		*endpoint,
183*7c478bd9Sstevel@tonic-gate 				usb_port_status_t	port_status,
184*7c478bd9Sstevel@tonic-gate 				uint_t			*bandwidth);
185*7c478bd9Sstevel@tonic-gate int		ehci_adjust_polling_interval(
186*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
187*7c478bd9Sstevel@tonic-gate 				usb_ep_descr_t		*endpoint,
188*7c478bd9Sstevel@tonic-gate 				usb_port_status_t	port_status);
189*7c478bd9Sstevel@tonic-gate static int	ehci_adjust_high_speed_polling_interval(
190*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
191*7c478bd9Sstevel@tonic-gate 				usb_ep_descr_t		*endpoint);
192*7c478bd9Sstevel@tonic-gate static uint_t	ehci_lattice_height(uint_t		interval);
193*7c478bd9Sstevel@tonic-gate static uint_t	ehci_lattice_parent(uint_t		node);
194*7c478bd9Sstevel@tonic-gate static uint_t	ehci_find_periodic_node(
195*7c478bd9Sstevel@tonic-gate 				uint_t			leaf,
196*7c478bd9Sstevel@tonic-gate 				int			interval);
197*7c478bd9Sstevel@tonic-gate static uint_t	ehci_leftmost_leaf(uint_t		node,
198*7c478bd9Sstevel@tonic-gate 				uint_t			height);
199*7c478bd9Sstevel@tonic-gate static uint_t	ehci_pow_2(uint_t x);
200*7c478bd9Sstevel@tonic-gate static uint_t	ehci_log_2(uint_t x);
201*7c478bd9Sstevel@tonic-gate static int	ehci_find_bestfit_hs_mask(
202*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
203*7c478bd9Sstevel@tonic-gate 				uchar_t			*smask,
204*7c478bd9Sstevel@tonic-gate 				uint_t			*pnode,
205*7c478bd9Sstevel@tonic-gate 				usb_ep_descr_t		*endpoint,
206*7c478bd9Sstevel@tonic-gate 				uint_t			bandwidth,
207*7c478bd9Sstevel@tonic-gate 				int			interval);
208*7c478bd9Sstevel@tonic-gate static int	ehci_find_bestfit_ls_intr_mask(
209*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
210*7c478bd9Sstevel@tonic-gate 				uchar_t			*smask,
211*7c478bd9Sstevel@tonic-gate 				uchar_t			*cmask,
212*7c478bd9Sstevel@tonic-gate 				uint_t			*pnode,
213*7c478bd9Sstevel@tonic-gate 				uint_t			sbandwidth,
214*7c478bd9Sstevel@tonic-gate 				uint_t			cbandwidth,
215*7c478bd9Sstevel@tonic-gate 				int			interval);
216*7c478bd9Sstevel@tonic-gate static int	ehci_find_bestfit_sitd_in_mask(
217*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
218*7c478bd9Sstevel@tonic-gate 				uchar_t			*smask,
219*7c478bd9Sstevel@tonic-gate 				uchar_t			*cmask,
220*7c478bd9Sstevel@tonic-gate 				uint_t			*pnode,
221*7c478bd9Sstevel@tonic-gate 				uint_t			sbandwidth,
222*7c478bd9Sstevel@tonic-gate 				uint_t			cbandwidth,
223*7c478bd9Sstevel@tonic-gate 				int			interval);
224*7c478bd9Sstevel@tonic-gate static int	ehci_find_bestfit_sitd_out_mask(
225*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
226*7c478bd9Sstevel@tonic-gate 				uchar_t			*smask,
227*7c478bd9Sstevel@tonic-gate 				uint_t			*pnode,
228*7c478bd9Sstevel@tonic-gate 				uint_t			sbandwidth,
229*7c478bd9Sstevel@tonic-gate 				int			interval);
230*7c478bd9Sstevel@tonic-gate static uint_t	ehci_calculate_bw_availability_mask(
231*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
232*7c478bd9Sstevel@tonic-gate 				uint_t			bandwidth,
233*7c478bd9Sstevel@tonic-gate 				int			leaf,
234*7c478bd9Sstevel@tonic-gate 				int			leaf_count,
235*7c478bd9Sstevel@tonic-gate 				uchar_t			*bw_mask);
236*7c478bd9Sstevel@tonic-gate static void	ehci_update_bw_availability(
237*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
238*7c478bd9Sstevel@tonic-gate 				int			bandwidth,
239*7c478bd9Sstevel@tonic-gate 				int			leftmost_leaf,
240*7c478bd9Sstevel@tonic-gate 				int			leaf_count,
241*7c478bd9Sstevel@tonic-gate 				uchar_t			mask);
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate /* Miscellaneous functions */
244*7c478bd9Sstevel@tonic-gate ehci_state_t	*ehci_obtain_state(
245*7c478bd9Sstevel@tonic-gate 				dev_info_t		*dip);
246*7c478bd9Sstevel@tonic-gate int		ehci_state_is_operational(
247*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
248*7c478bd9Sstevel@tonic-gate int		ehci_do_soft_reset(
249*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
250*7c478bd9Sstevel@tonic-gate usb_req_attrs_t ehci_get_xfer_attrs(ehci_state_t	*ehcip,
251*7c478bd9Sstevel@tonic-gate 				ehci_pipe_private_t	*pp,
252*7c478bd9Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw);
253*7c478bd9Sstevel@tonic-gate usb_frame_number_t ehci_get_current_frame_number(
254*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
255*7c478bd9Sstevel@tonic-gate static void	ehci_cpr_cleanup(
256*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
257*7c478bd9Sstevel@tonic-gate int		ehci_wait_for_sof(
258*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
259*7c478bd9Sstevel@tonic-gate void		ehci_toggle_scheduler(
260*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
261*7c478bd9Sstevel@tonic-gate void		ehci_print_caps(ehci_state_t		*ehcip);
262*7c478bd9Sstevel@tonic-gate void		ehci_print_regs(ehci_state_t		*ehcip);
263*7c478bd9Sstevel@tonic-gate void		ehci_print_qh(ehci_state_t		*ehcip,
264*7c478bd9Sstevel@tonic-gate 				ehci_qh_t		*qh);
265*7c478bd9Sstevel@tonic-gate void		ehci_print_qtd(ehci_state_t		*ehcip,
266*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd);
267*7c478bd9Sstevel@tonic-gate void		ehci_create_stats(ehci_state_t		*ehcip);
268*7c478bd9Sstevel@tonic-gate void		ehci_destroy_stats(ehci_state_t		*ehcip);
269*7c478bd9Sstevel@tonic-gate void		ehci_do_intrs_stats(ehci_state_t	*ehcip,
270*7c478bd9Sstevel@tonic-gate 				int		val);
271*7c478bd9Sstevel@tonic-gate void		ehci_do_byte_stats(ehci_state_t		*ehcip,
272*7c478bd9Sstevel@tonic-gate 				size_t		len,
273*7c478bd9Sstevel@tonic-gate 				uint8_t		attr,
274*7c478bd9Sstevel@tonic-gate 				uint8_t		addr);
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate /*
277*7c478bd9Sstevel@tonic-gate  * Host Controller Driver (HCD) initialization functions
278*7c478bd9Sstevel@tonic-gate  */
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate /*
281*7c478bd9Sstevel@tonic-gate  * ehci_set_dma_attributes:
282*7c478bd9Sstevel@tonic-gate  *
283*7c478bd9Sstevel@tonic-gate  * Set the limits in the DMA attributes structure. Most of the values used
284*7c478bd9Sstevel@tonic-gate  * in the  DMA limit structures are the default values as specified by	the
285*7c478bd9Sstevel@tonic-gate  * Writing PCI device drivers document.
286*7c478bd9Sstevel@tonic-gate  */
287*7c478bd9Sstevel@tonic-gate void
288*7c478bd9Sstevel@tonic-gate ehci_set_dma_attributes(ehci_state_t	*ehcip)
289*7c478bd9Sstevel@tonic-gate {
290*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
291*7c478bd9Sstevel@tonic-gate 	    "ehci_set_dma_attributes:");
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 	/* Initialize the DMA attributes */
294*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_version = DMA_ATTR_V0;
295*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_addr_lo = 0x00000000ull;
296*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_addr_hi = 0xfffffffeull;
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 	/* 32 bit addressing */
299*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_count_max = EHCI_DMA_ATTR_COUNT_MAX;
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 	/* Byte alignment */
302*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	/*
305*7c478bd9Sstevel@tonic-gate 	 * Since PCI  specification is byte alignment, the
306*7c478bd9Sstevel@tonic-gate 	 * burst size field should be set to 1 for PCI devices.
307*7c478bd9Sstevel@tonic-gate 	 */
308*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_burstsizes = 0x1;
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_minxfer = 0x1;
311*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_maxxfer = EHCI_DMA_ATTR_MAX_XFER;
312*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_seg = 0xffffffffull;
313*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_sgllen = 1;
314*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_granular = EHCI_DMA_ATTR_GRANULAR;
315*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_flags = 0;
316*7c478bd9Sstevel@tonic-gate }
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate /*
320*7c478bd9Sstevel@tonic-gate  * ehci_allocate_pools:
321*7c478bd9Sstevel@tonic-gate  *
322*7c478bd9Sstevel@tonic-gate  * Allocate the system memory for the Endpoint Descriptor (QH) and for the
323*7c478bd9Sstevel@tonic-gate  * Transfer Descriptor (QTD) pools. Both QH and QTD structures must be aligned
324*7c478bd9Sstevel@tonic-gate  * to a 16 byte boundary.
325*7c478bd9Sstevel@tonic-gate  */
326*7c478bd9Sstevel@tonic-gate int
327*7c478bd9Sstevel@tonic-gate ehci_allocate_pools(ehci_state_t	*ehcip)
328*7c478bd9Sstevel@tonic-gate {
329*7c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t		dev_attr;
330*7c478bd9Sstevel@tonic-gate 	size_t				real_length;
331*7c478bd9Sstevel@tonic-gate 	int				result;
332*7c478bd9Sstevel@tonic-gate 	uint_t				ccount;
333*7c478bd9Sstevel@tonic-gate 	int				i;
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
336*7c478bd9Sstevel@tonic-gate 	    "ehci_allocate_pools:");
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 	/* The host controller will be little endian */
339*7c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_version	= DDI_DEVICE_ATTR_V0;
340*7c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
341*7c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_dataorder	= DDI_STRICTORDER_ACC;
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	/* Byte alignment */
344*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_TD_QH_ALIGNMENT;
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 	/* Allocate the QTD pool DMA handle */
347*7c478bd9Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr,
348*7c478bd9Sstevel@tonic-gate 			DDI_DMA_SLEEP, 0,
349*7c478bd9Sstevel@tonic-gate 			&ehcip->ehci_qtd_pool_dma_handle) != DDI_SUCCESS) {
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 		goto failure;
352*7c478bd9Sstevel@tonic-gate 	}
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	/* Allocate the memory for the QTD pool */
355*7c478bd9Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(ehcip->ehci_qtd_pool_dma_handle,
356*7c478bd9Sstevel@tonic-gate 			ehci_qtd_pool_size * sizeof (ehci_qtd_t),
357*7c478bd9Sstevel@tonic-gate 			&dev_attr,
358*7c478bd9Sstevel@tonic-gate 			DDI_DMA_CONSISTENT,
359*7c478bd9Sstevel@tonic-gate 			DDI_DMA_SLEEP,
360*7c478bd9Sstevel@tonic-gate 			0,
361*7c478bd9Sstevel@tonic-gate 			(caddr_t *)&ehcip->ehci_qtd_pool_addr,
362*7c478bd9Sstevel@tonic-gate 			&real_length,
363*7c478bd9Sstevel@tonic-gate 			&ehcip->ehci_qtd_pool_mem_handle)) {
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 		goto failure;
366*7c478bd9Sstevel@tonic-gate 	}
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	/* Map the QTD pool into the I/O address space */
369*7c478bd9Sstevel@tonic-gate 	result = ddi_dma_addr_bind_handle(
370*7c478bd9Sstevel@tonic-gate 			ehcip->ehci_qtd_pool_dma_handle,
371*7c478bd9Sstevel@tonic-gate 			NULL,
372*7c478bd9Sstevel@tonic-gate 			(caddr_t)ehcip->ehci_qtd_pool_addr,
373*7c478bd9Sstevel@tonic-gate 			real_length,
374*7c478bd9Sstevel@tonic-gate 			DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
375*7c478bd9Sstevel@tonic-gate 			DDI_DMA_SLEEP,
376*7c478bd9Sstevel@tonic-gate 			NULL,
377*7c478bd9Sstevel@tonic-gate 			&ehcip->ehci_qtd_pool_cookie,
378*7c478bd9Sstevel@tonic-gate 			&ccount);
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	bzero((void *)ehcip->ehci_qtd_pool_addr,
381*7c478bd9Sstevel@tonic-gate 			ehci_qtd_pool_size * sizeof (ehci_qtd_t));
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	/* Process the result */
384*7c478bd9Sstevel@tonic-gate 	if (result == DDI_DMA_MAPPED) {
385*7c478bd9Sstevel@tonic-gate 		/* The cookie count should be 1 */
386*7c478bd9Sstevel@tonic-gate 		if (ccount != 1) {
387*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
388*7c478bd9Sstevel@tonic-gate 			    "ehci_allocate_pools: More than 1 cookie");
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 		goto failure;
391*7c478bd9Sstevel@tonic-gate 		}
392*7c478bd9Sstevel@tonic-gate 	} else {
393*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
394*7c478bd9Sstevel@tonic-gate 		    "ehci_allocate_pools: Result = %d", result);
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 		ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 		goto failure;
399*7c478bd9Sstevel@tonic-gate 	}
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 	/*
402*7c478bd9Sstevel@tonic-gate 	 * DMA addresses for QTD pools are bound
403*7c478bd9Sstevel@tonic-gate 	 */
404*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_addr_bind_flag |= EHCI_QTD_POOL_BOUND;
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	/* Initialize the QTD pool */
407*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ehci_qtd_pool_size; i ++) {
408*7c478bd9Sstevel@tonic-gate 		Set_QTD(ehcip->ehci_qtd_pool_addr[i].
409*7c478bd9Sstevel@tonic-gate 		    qtd_state, EHCI_QTD_FREE);
410*7c478bd9Sstevel@tonic-gate 	}
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate 	/* Allocate the QTD pool DMA handle */
413*7c478bd9Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(ehcip->ehci_dip,
414*7c478bd9Sstevel@tonic-gate 			&ehcip->ehci_dma_attr,
415*7c478bd9Sstevel@tonic-gate 			DDI_DMA_SLEEP,
416*7c478bd9Sstevel@tonic-gate 			0,
417*7c478bd9Sstevel@tonic-gate 			&ehcip->ehci_qh_pool_dma_handle) != DDI_SUCCESS) {
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 		goto failure;
420*7c478bd9Sstevel@tonic-gate 	}
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 	/* Allocate the memory for the QH pool */
423*7c478bd9Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(ehcip->ehci_qh_pool_dma_handle,
424*7c478bd9Sstevel@tonic-gate 			ehci_qh_pool_size * sizeof (ehci_qh_t),
425*7c478bd9Sstevel@tonic-gate 			&dev_attr,
426*7c478bd9Sstevel@tonic-gate 			DDI_DMA_CONSISTENT,
427*7c478bd9Sstevel@tonic-gate 			DDI_DMA_SLEEP,
428*7c478bd9Sstevel@tonic-gate 			0,
429*7c478bd9Sstevel@tonic-gate 			(caddr_t *)&ehcip->ehci_qh_pool_addr,
430*7c478bd9Sstevel@tonic-gate 			&real_length,
431*7c478bd9Sstevel@tonic-gate 			&ehcip->ehci_qh_pool_mem_handle) != DDI_SUCCESS) {
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 		goto failure;
434*7c478bd9Sstevel@tonic-gate 	}
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 	result = ddi_dma_addr_bind_handle(ehcip->ehci_qh_pool_dma_handle,
437*7c478bd9Sstevel@tonic-gate 			NULL,
438*7c478bd9Sstevel@tonic-gate 			(caddr_t)ehcip->ehci_qh_pool_addr,
439*7c478bd9Sstevel@tonic-gate 			real_length,
440*7c478bd9Sstevel@tonic-gate 			DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
441*7c478bd9Sstevel@tonic-gate 			DDI_DMA_SLEEP,
442*7c478bd9Sstevel@tonic-gate 			NULL,
443*7c478bd9Sstevel@tonic-gate 			&ehcip->ehci_qh_pool_cookie,
444*7c478bd9Sstevel@tonic-gate 			&ccount);
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 	bzero((void *)ehcip->ehci_qh_pool_addr,
447*7c478bd9Sstevel@tonic-gate 			ehci_qh_pool_size * sizeof (ehci_qh_t));
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	/* Process the result */
450*7c478bd9Sstevel@tonic-gate 	if (result == DDI_DMA_MAPPED) {
451*7c478bd9Sstevel@tonic-gate 		/* The cookie count should be 1 */
452*7c478bd9Sstevel@tonic-gate 		if (ccount != 1) {
453*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
454*7c478bd9Sstevel@tonic-gate 			    "ehci_allocate_pools: More than 1 cookie");
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 			goto failure;
457*7c478bd9Sstevel@tonic-gate 		}
458*7c478bd9Sstevel@tonic-gate 	} else {
459*7c478bd9Sstevel@tonic-gate 		ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 		goto failure;
462*7c478bd9Sstevel@tonic-gate 	}
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	/*
465*7c478bd9Sstevel@tonic-gate 	 * DMA addresses for QH pools are bound
466*7c478bd9Sstevel@tonic-gate 	 */
467*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_addr_bind_flag |= EHCI_QH_POOL_BOUND;
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	/* Initialize the QH pool */
470*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ehci_qh_pool_size; i ++) {
471*7c478bd9Sstevel@tonic-gate 		Set_QH(ehcip->ehci_qh_pool_addr[i].qh_state, EHCI_QH_FREE);
472*7c478bd9Sstevel@tonic-gate 	}
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	/* Byte alignment */
475*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate failure:
480*7c478bd9Sstevel@tonic-gate 	/* Byte alignment */
481*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
484*7c478bd9Sstevel@tonic-gate }
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate /*
488*7c478bd9Sstevel@tonic-gate  * ehci_decode_ddi_dma_addr_bind_handle_result:
489*7c478bd9Sstevel@tonic-gate  *
490*7c478bd9Sstevel@tonic-gate  * Process the return values of ddi_dma_addr_bind_handle()
491*7c478bd9Sstevel@tonic-gate  */
492*7c478bd9Sstevel@tonic-gate void
493*7c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(
494*7c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
495*7c478bd9Sstevel@tonic-gate 	int		result)
496*7c478bd9Sstevel@tonic-gate {
497*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
498*7c478bd9Sstevel@tonic-gate 	    "ehci_decode_ddi_dma_addr_bind_handle_result:");
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate 	switch (result) {
501*7c478bd9Sstevel@tonic-gate 	case DDI_DMA_PARTIAL_MAP:
502*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl,
503*7c478bd9Sstevel@tonic-gate 		    "Partial transfers not allowed");
504*7c478bd9Sstevel@tonic-gate 		break;
505*7c478bd9Sstevel@tonic-gate 	case DDI_DMA_INUSE:
506*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
507*7c478bd9Sstevel@tonic-gate 		    "Handle is in use");
508*7c478bd9Sstevel@tonic-gate 		break;
509*7c478bd9Sstevel@tonic-gate 	case DDI_DMA_NORESOURCES:
510*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
511*7c478bd9Sstevel@tonic-gate 		    "No resources");
512*7c478bd9Sstevel@tonic-gate 		break;
513*7c478bd9Sstevel@tonic-gate 	case DDI_DMA_NOMAPPING:
514*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
515*7c478bd9Sstevel@tonic-gate 		    "No mapping");
516*7c478bd9Sstevel@tonic-gate 		break;
517*7c478bd9Sstevel@tonic-gate 	case DDI_DMA_TOOBIG:
518*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
519*7c478bd9Sstevel@tonic-gate 		    "Object is too big");
520*7c478bd9Sstevel@tonic-gate 		break;
521*7c478bd9Sstevel@tonic-gate 	default:
522*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
523*7c478bd9Sstevel@tonic-gate 		    "Unknown dma error");
524*7c478bd9Sstevel@tonic-gate 	}
525*7c478bd9Sstevel@tonic-gate }
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate /*
529*7c478bd9Sstevel@tonic-gate  * ehci_map_regs:
530*7c478bd9Sstevel@tonic-gate  *
531*7c478bd9Sstevel@tonic-gate  * The Host Controller (HC) contains a set of on-chip operational registers
532*7c478bd9Sstevel@tonic-gate  * and which should be mapped into a non-cacheable portion of the  system
533*7c478bd9Sstevel@tonic-gate  * addressable space.
534*7c478bd9Sstevel@tonic-gate  */
535*7c478bd9Sstevel@tonic-gate int
536*7c478bd9Sstevel@tonic-gate ehci_map_regs(ehci_state_t	*ehcip)
537*7c478bd9Sstevel@tonic-gate {
538*7c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t	attr;
539*7c478bd9Sstevel@tonic-gate 	uint16_t		cmd_reg;
540*7c478bd9Sstevel@tonic-gate 	uint_t			length;
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_map_regs:");
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 	/* Check to make sure we have memory access */
545*7c478bd9Sstevel@tonic-gate 	if (pci_config_setup(ehcip->ehci_dip,
546*7c478bd9Sstevel@tonic-gate 		&ehcip->ehci_config_handle) != DDI_SUCCESS) {
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
549*7c478bd9Sstevel@tonic-gate 		    "ehci_map_regs: Config error");
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
552*7c478bd9Sstevel@tonic-gate 	}
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 	/* Make sure Memory Access Enable is set */
555*7c478bd9Sstevel@tonic-gate 	cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM);
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	if (!(cmd_reg & PCI_COMM_MAE)) {
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
560*7c478bd9Sstevel@tonic-gate 		    "ehci_map_regs: Memory base address access disabled");
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
563*7c478bd9Sstevel@tonic-gate 	}
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 	/* The host controller will be little endian */
566*7c478bd9Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
567*7c478bd9Sstevel@tonic-gate 	attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
568*7c478bd9Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 	/* Map in EHCI Capability registers */
571*7c478bd9Sstevel@tonic-gate 	if (ddi_regs_map_setup(ehcip->ehci_dip, 1,
572*7c478bd9Sstevel@tonic-gate 	    (caddr_t *)&ehcip->ehci_capsp, 0,
573*7c478bd9Sstevel@tonic-gate 	    sizeof (ehci_caps_t), &attr,
574*7c478bd9Sstevel@tonic-gate 	    &ehcip->ehci_caps_handle) != DDI_SUCCESS) {
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
577*7c478bd9Sstevel@tonic-gate 		    "ehci_map_regs: Map setup error");
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
580*7c478bd9Sstevel@tonic-gate 	}
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	length = ddi_get8(ehcip->ehci_caps_handle,
583*7c478bd9Sstevel@tonic-gate 	    (uint8_t *)&ehcip->ehci_capsp->ehci_caps_length);
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 	/* Free the original mapping */
586*7c478bd9Sstevel@tonic-gate 	ddi_regs_map_free(&ehcip->ehci_caps_handle);
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 	/* Re-map in EHCI Capability and Operational registers */
589*7c478bd9Sstevel@tonic-gate 	if (ddi_regs_map_setup(ehcip->ehci_dip, 1,
590*7c478bd9Sstevel@tonic-gate 	    (caddr_t *)&ehcip->ehci_capsp, 0,
591*7c478bd9Sstevel@tonic-gate 	    length + sizeof (ehci_regs_t), &attr,
592*7c478bd9Sstevel@tonic-gate 	    &ehcip->ehci_caps_handle) != DDI_SUCCESS) {
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
595*7c478bd9Sstevel@tonic-gate 		    "ehci_map_regs: Map setup error");
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
598*7c478bd9Sstevel@tonic-gate 	}
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	/* Get the pointer to EHCI Operational Register */
601*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_regsp = (ehci_regs_t *)
602*7c478bd9Sstevel@tonic-gate 	    ((uintptr_t)ehcip->ehci_capsp + length);
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
605*7c478bd9Sstevel@tonic-gate 	    "ehci_map_regs: Capsp 0x%p Regsp 0x%p\n",
606*7c478bd9Sstevel@tonic-gate 	    ehcip->ehci_capsp, ehcip->ehci_regsp);
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
609*7c478bd9Sstevel@tonic-gate }
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate /*
613*7c478bd9Sstevel@tonic-gate  * ehci_register_intrs_and_init_mutex:
614*7c478bd9Sstevel@tonic-gate  *
615*7c478bd9Sstevel@tonic-gate  * Register interrupts and initialize each mutex and condition variables
616*7c478bd9Sstevel@tonic-gate  */
617*7c478bd9Sstevel@tonic-gate int
618*7c478bd9Sstevel@tonic-gate ehci_register_intrs_and_init_mutex(ehci_state_t	*ehcip)
619*7c478bd9Sstevel@tonic-gate {
620*7c478bd9Sstevel@tonic-gate 	int type, count = 0, actual, ret;
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate #if defined(__x86)
623*7c478bd9Sstevel@tonic-gate 	uint8_t iline;
624*7c478bd9Sstevel@tonic-gate #endif
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
627*7c478bd9Sstevel@tonic-gate 	    "ehci_register_intrs_and_init_mutex:");
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate #if defined(__x86)
630*7c478bd9Sstevel@tonic-gate 	/*
631*7c478bd9Sstevel@tonic-gate 	 * Make sure that the interrupt pin is connected to the
632*7c478bd9Sstevel@tonic-gate 	 * interrupt controller on x86.	 Interrupt line 255 means
633*7c478bd9Sstevel@tonic-gate 	 * "unknown" or "not connected" (PCI spec 6.2.4, footnote 43).
634*7c478bd9Sstevel@tonic-gate 	 */
635*7c478bd9Sstevel@tonic-gate 	iline = pci_config_get8(ehcip->ehci_config_handle,
636*7c478bd9Sstevel@tonic-gate 	    PCI_CONF_ILINE);
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 	if (iline == 255) {
639*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
640*7c478bd9Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
641*7c478bd9Sstevel@tonic-gate 		    "interrupt line value out of range (%d)",
642*7c478bd9Sstevel@tonic-gate 		    iline);
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
645*7c478bd9Sstevel@tonic-gate 	}
646*7c478bd9Sstevel@tonic-gate #endif	/* __x86 */
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate 	ret = ddi_intr_get_supported_types(ehcip->ehci_dip, &type);
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate 	if ((ret != DDI_SUCCESS) || (!(type & DDI_INTR_TYPE_FIXED))) {
651*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
652*7c478bd9Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
653*7c478bd9Sstevel@tonic-gate 		    "Fixed type interrupt is not supported");
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
656*7c478bd9Sstevel@tonic-gate 	}
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 	ret = ddi_intr_get_nintrs(ehcip->ehci_dip, DDI_INTR_TYPE_FIXED, &count);
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	/*
661*7c478bd9Sstevel@tonic-gate 	 * Fixed interrupts can only have one interrupt. Check to make
662*7c478bd9Sstevel@tonic-gate 	 * sure that number of supported interrupts and number of
663*7c478bd9Sstevel@tonic-gate 	 * available interrupts are both equal to 1.
664*7c478bd9Sstevel@tonic-gate 	 */
665*7c478bd9Sstevel@tonic-gate 	if ((ret != DDI_SUCCESS) || (count != 1)) {
666*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
667*7c478bd9Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
668*7c478bd9Sstevel@tonic-gate 		    "no fixed interrupts");
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
671*7c478bd9Sstevel@tonic-gate 	}
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
674*7c478bd9Sstevel@tonic-gate 	ret = ddi_intr_alloc(ehcip->ehci_dip, ehcip->ehci_htable,
675*7c478bd9Sstevel@tonic-gate 	    DDI_INTR_TYPE_FIXED, 0, count, &actual, 0);
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 	if ((ret != DDI_SUCCESS) || (actual != 1)) {
678*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
679*7c478bd9Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
680*7c478bd9Sstevel@tonic-gate 		    "ddi_intr_alloc() failed 0x%x", ret);
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate 		kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t));
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
685*7c478bd9Sstevel@tonic-gate 	}
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate 	/* Sanity check that count and avail are the same. */
688*7c478bd9Sstevel@tonic-gate 	ASSERT(count == actual);
689*7c478bd9Sstevel@tonic-gate 
690*7c478bd9Sstevel@tonic-gate 	if (ddi_intr_get_pri(ehcip->ehci_htable[0], &ehcip->ehci_intr_pri)) {
691*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
692*7c478bd9Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
693*7c478bd9Sstevel@tonic-gate 		    "ddi_intr_get_pri() failed");
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(ehcip->ehci_htable[0]);
696*7c478bd9Sstevel@tonic-gate 		kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t));
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
699*7c478bd9Sstevel@tonic-gate 	}
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
702*7c478bd9Sstevel@tonic-gate 	    "Supported Interrupt priority = 0x%x", ehcip->ehci_intr_pri);
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate 	/* Test for high level mutex */
705*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_intr_pri >= ddi_intr_get_hilevel_pri()) {
706*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
707*7c478bd9Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
708*7c478bd9Sstevel@tonic-gate 		    "Hi level interrupt not supported");
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(ehcip->ehci_htable[0]);
711*7c478bd9Sstevel@tonic-gate 		kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t));
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
714*7c478bd9Sstevel@tonic-gate 	}
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	/* Initialize the mutex */
717*7c478bd9Sstevel@tonic-gate 	mutex_init(&ehcip->ehci_int_mutex, NULL, MUTEX_DRIVER,
718*7c478bd9Sstevel@tonic-gate 	    (void *)(uintptr_t)ehcip->ehci_intr_pri);
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 	if (ddi_intr_add_handler(ehcip->ehci_htable[0],
721*7c478bd9Sstevel@tonic-gate 	    (ddi_intr_handler_t *)ehci_intr, (caddr_t)ehcip, NULL) !=
722*7c478bd9Sstevel@tonic-gate 		DDI_SUCCESS) {
723*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
724*7c478bd9Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
725*7c478bd9Sstevel@tonic-gate 		    "ddi_intr_add_handler() failed");
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&ehcip->ehci_int_mutex);
728*7c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(ehcip->ehci_htable[0]);
729*7c478bd9Sstevel@tonic-gate 		kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t));
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
732*7c478bd9Sstevel@tonic-gate 	}
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 	if (ddi_intr_enable(ehcip->ehci_htable[0]) != DDI_SUCCESS) {
735*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
736*7c478bd9Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
737*7c478bd9Sstevel@tonic-gate 		    "ddi_intr_enable() failed");
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 		(void) ddi_intr_remove_handler(ehcip->ehci_htable[0]);
740*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&ehcip->ehci_int_mutex);
741*7c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(ehcip->ehci_htable[0]);
742*7c478bd9Sstevel@tonic-gate 		kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t));
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
745*7c478bd9Sstevel@tonic-gate 	}
746*7c478bd9Sstevel@tonic-gate 
747*7c478bd9Sstevel@tonic-gate 	/* Create prototype for advance on async schedule */
748*7c478bd9Sstevel@tonic-gate 	cv_init(&ehcip->ehci_async_schedule_advance_cv,
749*7c478bd9Sstevel@tonic-gate 	    NULL, CV_DRIVER, NULL);
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
752*7c478bd9Sstevel@tonic-gate }
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 
755*7c478bd9Sstevel@tonic-gate /*
756*7c478bd9Sstevel@tonic-gate  * ehci_init_ctlr:
757*7c478bd9Sstevel@tonic-gate  *
758*7c478bd9Sstevel@tonic-gate  * Initialize the Host Controller (HC).
759*7c478bd9Sstevel@tonic-gate  */
760*7c478bd9Sstevel@tonic-gate int
761*7c478bd9Sstevel@tonic-gate ehci_init_ctlr(ehci_state_t	*ehcip)
762*7c478bd9Sstevel@tonic-gate {
763*7c478bd9Sstevel@tonic-gate 	int			revision;
764*7c478bd9Sstevel@tonic-gate 	uint16_t		cmd_reg;
765*7c478bd9Sstevel@tonic-gate 	clock_t			sof_time_wait;
766*7c478bd9Sstevel@tonic-gate 	int			abort_on_BIOS_take_over_failure;
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_init_ctlr:");
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 	/* Take control from the BIOS */
771*7c478bd9Sstevel@tonic-gate 	if (ehci_take_control(ehcip) != USB_SUCCESS) {
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 		/* read .conf file properties */
774*7c478bd9Sstevel@tonic-gate 		abort_on_BIOS_take_over_failure =
775*7c478bd9Sstevel@tonic-gate 					ddi_prop_get_int(DDI_DEV_T_ANY,
776*7c478bd9Sstevel@tonic-gate 					ehcip->ehci_dip, DDI_PROP_DONTPASS,
777*7c478bd9Sstevel@tonic-gate 					"abort-on-BIOS-take-over-failure", 0);
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate 		if (abort_on_BIOS_take_over_failure) {
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
782*7c478bd9Sstevel@tonic-gate 			    "Unable to take control from BIOS.");
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
785*7c478bd9Sstevel@tonic-gate 		}
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
788*7c478bd9Sstevel@tonic-gate 		    "Unable to take control from BIOS. Failure is ignored.");
789*7c478bd9Sstevel@tonic-gate 	}
790*7c478bd9Sstevel@tonic-gate 
791*7c478bd9Sstevel@tonic-gate 	/* set Memory Master Enable */
792*7c478bd9Sstevel@tonic-gate 	cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM);
793*7c478bd9Sstevel@tonic-gate 	cmd_reg |= (PCI_COMM_MAE | PCI_COMM_ME);
794*7c478bd9Sstevel@tonic-gate 	pci_config_put16(ehcip->ehci_config_handle, PCI_CONF_COMM, cmd_reg);
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate 	/* Reset the EHCI host controller */
797*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_command,
798*7c478bd9Sstevel@tonic-gate 	    Get_OpReg(ehci_command) | EHCI_CMD_HOST_CTRL_RESET);
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 	/* Wait 10ms for reset to complete */
801*7c478bd9Sstevel@tonic-gate 	drv_usecwait(EHCI_RESET_TIMEWAIT);
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate 	ASSERT(Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED);
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate 	/* Verify the version number */
806*7c478bd9Sstevel@tonic-gate 	revision = Get_16Cap(ehci_version);
807*7c478bd9Sstevel@tonic-gate 
808*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
809*7c478bd9Sstevel@tonic-gate 	    "ehci_init_ctlr: Revision 0x%x", revision);
810*7c478bd9Sstevel@tonic-gate 
811*7c478bd9Sstevel@tonic-gate 	/*
812*7c478bd9Sstevel@tonic-gate 	 * EHCI driver supports EHCI host controllers compliant to
813*7c478bd9Sstevel@tonic-gate 	 * 0.95 and higher revisions of EHCI specifications.
814*7c478bd9Sstevel@tonic-gate 	 */
815*7c478bd9Sstevel@tonic-gate 	if (revision < EHCI_REVISION_0_95) {
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
818*7c478bd9Sstevel@tonic-gate 		    "Revision 0x%x is not supported", revision);
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
821*7c478bd9Sstevel@tonic-gate 	}
822*7c478bd9Sstevel@tonic-gate 
823*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_hc_soft_state == EHCI_CTLR_INIT_STATE) {
824*7c478bd9Sstevel@tonic-gate 
825*7c478bd9Sstevel@tonic-gate 		/* Get the ehci chip vendor and device id */
826*7c478bd9Sstevel@tonic-gate 		ehcip->ehci_vendor_id = pci_config_get16(
827*7c478bd9Sstevel@tonic-gate 		    ehcip->ehci_config_handle, PCI_CONF_VENID);
828*7c478bd9Sstevel@tonic-gate 		ehcip->ehci_device_id = pci_config_get16(
829*7c478bd9Sstevel@tonic-gate 		    ehcip->ehci_config_handle, PCI_CONF_DEVID);
830*7c478bd9Sstevel@tonic-gate 		ehcip->ehci_rev_id = pci_config_get8(
831*7c478bd9Sstevel@tonic-gate 		    ehcip->ehci_config_handle, PCI_CONF_REVID);
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate 		/* Initialize the Frame list base address area */
834*7c478bd9Sstevel@tonic-gate 		if (ehci_init_periodic_frame_lst_table(ehcip) != DDI_SUCCESS) {
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
837*7c478bd9Sstevel@tonic-gate 		}
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 		/*
840*7c478bd9Sstevel@tonic-gate 		 * For performance reasons, do not insert anything into the
841*7c478bd9Sstevel@tonic-gate 		 * asynchronous list or activate the asynch list schedule until
842*7c478bd9Sstevel@tonic-gate 		 * there is a valid QH.
843*7c478bd9Sstevel@tonic-gate 		 */
844*7c478bd9Sstevel@tonic-gate 		ehcip->ehci_head_of_async_sched_list = NULL;
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate 		if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) &&
847*7c478bd9Sstevel@tonic-gate 		    (ehci_vt62x2_workaround & EHCI_VIA_ASYNC_SCHEDULE)) {
848*7c478bd9Sstevel@tonic-gate 			/*
849*7c478bd9Sstevel@tonic-gate 			 * The driver is unable to reliably stop the asynch
850*7c478bd9Sstevel@tonic-gate 			 * list schedule on VIA VT6202 controllers, so we
851*7c478bd9Sstevel@tonic-gate 			 * always keep a dummy QH on the list.
852*7c478bd9Sstevel@tonic-gate 			 */
853*7c478bd9Sstevel@tonic-gate 			ehci_qh_t *dummy_async_qh =
854*7c478bd9Sstevel@tonic-gate 			    ehci_alloc_qh(ehcip, NULL, NULL);
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 			Set_QH(dummy_async_qh->qh_link_ptr,
857*7c478bd9Sstevel@tonic-gate 			    ((ehci_qh_cpu_to_iommu(ehcip, dummy_async_qh) &
858*7c478bd9Sstevel@tonic-gate 			    EHCI_QH_LINK_PTR) | EHCI_QH_LINK_REF_QH));
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 			/* Set this QH to be the "head" of the circular list */
861*7c478bd9Sstevel@tonic-gate 			Set_QH(dummy_async_qh->qh_ctrl,
862*7c478bd9Sstevel@tonic-gate 			    Get_QH(dummy_async_qh->qh_ctrl) |
863*7c478bd9Sstevel@tonic-gate 			    EHCI_QH_CTRL_RECLAIM_HEAD);
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate 			Set_QH(dummy_async_qh->qh_next_qtd,
866*7c478bd9Sstevel@tonic-gate 			    EHCI_QH_NEXT_QTD_PTR_VALID);
867*7c478bd9Sstevel@tonic-gate 			Set_QH(dummy_async_qh->qh_alt_next_qtd,
868*7c478bd9Sstevel@tonic-gate 			    EHCI_QH_ALT_NEXT_QTD_PTR_VALID);
869*7c478bd9Sstevel@tonic-gate 
870*7c478bd9Sstevel@tonic-gate 			ehcip->ehci_head_of_async_sched_list = dummy_async_qh;
871*7c478bd9Sstevel@tonic-gate 			ehcip->ehci_open_async_count++;
872*7c478bd9Sstevel@tonic-gate 		}
873*7c478bd9Sstevel@tonic-gate 	}
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 	/*
876*7c478bd9Sstevel@tonic-gate 	 * Check for Asynchronous schedule park capability feature. If this
877*7c478bd9Sstevel@tonic-gate 	 * feature is supported, then, program ehci command register with
878*7c478bd9Sstevel@tonic-gate 	 * appropriate values..
879*7c478bd9Sstevel@tonic-gate 	 */
880*7c478bd9Sstevel@tonic-gate 	if (Get_Cap(ehci_hcc_params) & EHCI_HCC_ASYNC_SCHED_PARK_CAP) {
881*7c478bd9Sstevel@tonic-gate 
882*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
883*7c478bd9Sstevel@tonic-gate 		    "ehci_init_ctlr: Async park mode is supported");
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_command, (Get_OpReg(ehci_command) |
886*7c478bd9Sstevel@tonic-gate 		    (EHCI_CMD_ASYNC_PARK_ENABLE |
887*7c478bd9Sstevel@tonic-gate 		    EHCI_CMD_ASYNC_PARK_COUNT_3)));
888*7c478bd9Sstevel@tonic-gate 	}
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate 	/*
891*7c478bd9Sstevel@tonic-gate 	 * Check for programmable periodic frame list feature. If this
892*7c478bd9Sstevel@tonic-gate 	 * feature is supported, then, program ehci command register with
893*7c478bd9Sstevel@tonic-gate 	 * 1024 frame list value.
894*7c478bd9Sstevel@tonic-gate 	 */
895*7c478bd9Sstevel@tonic-gate 	if (Get_Cap(ehci_hcc_params) & EHCI_HCC_PROG_FRAME_LIST_FLAG) {
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
898*7c478bd9Sstevel@tonic-gate 		    "ehci_init_ctlr: Variable programmable periodic "
899*7c478bd9Sstevel@tonic-gate 		    "frame list is supported");
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_command, (Get_OpReg(ehci_command) |
902*7c478bd9Sstevel@tonic-gate 		    EHCI_CMD_FRAME_1024_SIZE));
903*7c478bd9Sstevel@tonic-gate 	}
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 	/*
906*7c478bd9Sstevel@tonic-gate 	 * Currently EHCI driver doesn't support 64 bit addressing.
907*7c478bd9Sstevel@tonic-gate 	 *
908*7c478bd9Sstevel@tonic-gate 	 * If we are using 64 bit addressing capability, then, program
909*7c478bd9Sstevel@tonic-gate 	 * ehci_ctrl_segment register with 4 Gigabyte segment where all
910*7c478bd9Sstevel@tonic-gate 	 * of the interface data structures are allocated.
911*7c478bd9Sstevel@tonic-gate 	 */
912*7c478bd9Sstevel@tonic-gate 	if (Get_Cap(ehci_hcc_params) & EHCI_HCC_64BIT_ADDR_CAP) {
913*7c478bd9Sstevel@tonic-gate 
914*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
915*7c478bd9Sstevel@tonic-gate 		    "ehci_init_ctlr: EHCI driver doesn't support "
916*7c478bd9Sstevel@tonic-gate 		    "64 bit addressing");
917*7c478bd9Sstevel@tonic-gate 	}
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate 	/* 64 bit addressing is not support */
920*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_ctrl_segment, 0x00000000);
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 	/* Turn on/off the schedulers */
923*7c478bd9Sstevel@tonic-gate 	ehci_toggle_scheduler(ehcip);
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 	/*
926*7c478bd9Sstevel@tonic-gate 	 * Set the Periodic Frame List Base Address register with the
927*7c478bd9Sstevel@tonic-gate 	 * starting physical address of the Periodic Frame List.
928*7c478bd9Sstevel@tonic-gate 	 */
929*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_periodic_list_base,
930*7c478bd9Sstevel@tonic-gate 	    (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address & 0xFFFFF000));
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 	/*
933*7c478bd9Sstevel@tonic-gate 	 * Set ehci_interrupt to enable all interrupts except Root
934*7c478bd9Sstevel@tonic-gate 	 * Hub Status change interrupt.
935*7c478bd9Sstevel@tonic-gate 	 */
936*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR |
937*7c478bd9Sstevel@tonic-gate 	    EHCI_INTR_FRAME_LIST_ROLLOVER | EHCI_INTR_USB_ERROR |
938*7c478bd9Sstevel@tonic-gate 	    EHCI_INTR_USB);
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate 	/*
941*7c478bd9Sstevel@tonic-gate 	 * Set the desired interrupt threshold and turn on EHCI host controller.
942*7c478bd9Sstevel@tonic-gate 	 */
943*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_command,
944*7c478bd9Sstevel@tonic-gate 	    ((Get_OpReg(ehci_command) & ~EHCI_CMD_INTR_THRESHOLD) |
945*7c478bd9Sstevel@tonic-gate 		(EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN)));
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 	ASSERT(Get_OpReg(ehci_command) & EHCI_CMD_HOST_CTRL_RUN);
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 	/*
950*7c478bd9Sstevel@tonic-gate 	 * Acer Labs Inc. M5273 EHCI controller does not send
951*7c478bd9Sstevel@tonic-gate 	 * interrupts unless the Root hub ports are routed to the EHCI
952*7c478bd9Sstevel@tonic-gate 	 * host controller; so route the ports now, before we test for
953*7c478bd9Sstevel@tonic-gate 	 * the presence of SOFs interrupts.
954*7c478bd9Sstevel@tonic-gate 	 */
955*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) {
956*7c478bd9Sstevel@tonic-gate 	    /* Route all Root hub ports to EHCI host controller */
957*7c478bd9Sstevel@tonic-gate 	    Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI);
958*7c478bd9Sstevel@tonic-gate 	}
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate 	/*
961*7c478bd9Sstevel@tonic-gate 	 * VIA chips have some issues and may not work reliably.
962*7c478bd9Sstevel@tonic-gate 	 * If we were bound using class pciclass,0c0320,
963*7c478bd9Sstevel@tonic-gate 	 * complain, else proceed. This will allow the user
964*7c478bd9Sstevel@tonic-gate 	 * to bind ehci specifically to this chip and not
965*7c478bd9Sstevel@tonic-gate 	 * have the warnings
966*7c478bd9Sstevel@tonic-gate 	 */
967*7c478bd9Sstevel@tonic-gate 	if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) &&
968*7c478bd9Sstevel@tonic-gate 	    (strcmp(DEVI(ehcip->ehci_dip)->devi_binding_name,
969*7c478bd9Sstevel@tonic-gate 	    "pciclass,0c0320") == 0)) {
970*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
971*7c478bd9Sstevel@tonic-gate 		    "Due to recently discovered incompatibilities");
972*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
973*7c478bd9Sstevel@tonic-gate 		    "with this USB controller, USB2.x transfer");
974*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
975*7c478bd9Sstevel@tonic-gate 		    "support has been disabled. This device will");
976*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
977*7c478bd9Sstevel@tonic-gate 		    "continue to function as a USB1.x controller.");
978*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
979*7c478bd9Sstevel@tonic-gate 		    "If you are interested in enabling USB2.x");
980*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
981*7c478bd9Sstevel@tonic-gate 		    "support please, refer to the ehci(7D) man page.");
982*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
983*7c478bd9Sstevel@tonic-gate 		    "Please also refer to www.sun.com/io for");
984*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
985*7c478bd9Sstevel@tonic-gate 		    "Solaris Ready products and to");
986*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
987*7c478bd9Sstevel@tonic-gate 		    "www.sun.com/bigadmin/hcl for additional");
988*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
989*7c478bd9Sstevel@tonic-gate 		    "compatible USB products.");
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
992*7c478bd9Sstevel@tonic-gate 	} else if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) &&
993*7c478bd9Sstevel@tonic-gate 	    ehci_vt62x2_workaround) {
994*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
995*7c478bd9Sstevel@tonic-gate 		    "Applying VIA workarounds");
996*7c478bd9Sstevel@tonic-gate 	}
997*7c478bd9Sstevel@tonic-gate 
998*7c478bd9Sstevel@tonic-gate 	/*
999*7c478bd9Sstevel@tonic-gate 	 * Get the number of clock ticks to wait.
1000*7c478bd9Sstevel@tonic-gate 	 * This is based on the maximum time it takes for a frame list rollover
1001*7c478bd9Sstevel@tonic-gate 	 * and maximum time wait for SOFs to begin.
1002*7c478bd9Sstevel@tonic-gate 	 */
1003*7c478bd9Sstevel@tonic-gate 	sof_time_wait = drv_usectohz((EHCI_NUM_PERIODIC_FRAME_LISTS * 1000) +
1004*7c478bd9Sstevel@tonic-gate 	    EHCI_SOF_TIMEWAIT);
1005*7c478bd9Sstevel@tonic-gate 
1006*7c478bd9Sstevel@tonic-gate 	/* Tell the ISR to broadcast ehci_async_schedule_advance_cv */
1007*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_flags |= EHCI_CV_INTR;
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 	/* We need to add a delay to allow the chip time to start running */
1010*7c478bd9Sstevel@tonic-gate 	(void) cv_timedwait(&ehcip->ehci_async_schedule_advance_cv,
1011*7c478bd9Sstevel@tonic-gate 	    &ehcip->ehci_int_mutex, ddi_get_lbolt() + sof_time_wait);
1012*7c478bd9Sstevel@tonic-gate 
1013*7c478bd9Sstevel@tonic-gate 	/*
1014*7c478bd9Sstevel@tonic-gate 	 * Check EHCI host controller is running, otherwise return failure.
1015*7c478bd9Sstevel@tonic-gate 	 */
1016*7c478bd9Sstevel@tonic-gate 	if ((ehcip->ehci_flags & EHCI_CV_INTR) ||
1017*7c478bd9Sstevel@tonic-gate 	    (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) {
1018*7c478bd9Sstevel@tonic-gate 
1019*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1020*7c478bd9Sstevel@tonic-gate 		    "No SOF interrupts have been received, this USB EHCI host"
1021*7c478bd9Sstevel@tonic-gate 		    "controller is unusable");
1022*7c478bd9Sstevel@tonic-gate 
1023*7c478bd9Sstevel@tonic-gate 		/*
1024*7c478bd9Sstevel@tonic-gate 		 * Route all Root hub ports to Classic host
1025*7c478bd9Sstevel@tonic-gate 		 * controller, in case this is an unusable ALI M5273
1026*7c478bd9Sstevel@tonic-gate 		 * EHCI controller.
1027*7c478bd9Sstevel@tonic-gate 		 */
1028*7c478bd9Sstevel@tonic-gate 		if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) {
1029*7c478bd9Sstevel@tonic-gate 			Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC);
1030*7c478bd9Sstevel@tonic-gate 		}
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1033*7c478bd9Sstevel@tonic-gate 	}
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1036*7c478bd9Sstevel@tonic-gate 	    "ehci_init_ctlr: SOF's have started");
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate 	/* Route all Root hub ports to EHCI host controller */
1039*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI);
1040*7c478bd9Sstevel@tonic-gate 
1041*7c478bd9Sstevel@tonic-gate 	/* Set host controller soft state to operational */
1042*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_hc_soft_state = EHCI_CTLR_OPERATIONAL_STATE;
1043*7c478bd9Sstevel@tonic-gate 
1044*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1045*7c478bd9Sstevel@tonic-gate }
1046*7c478bd9Sstevel@tonic-gate 
1047*7c478bd9Sstevel@tonic-gate /*
1048*7c478bd9Sstevel@tonic-gate  * ehci_take_control:
1049*7c478bd9Sstevel@tonic-gate  *
1050*7c478bd9Sstevel@tonic-gate  * Handshake to take EHCI control from BIOS if necessary.  Its only valid for
1051*7c478bd9Sstevel@tonic-gate  * x86 machines, because sparc doesn't have a BIOS.
1052*7c478bd9Sstevel@tonic-gate  * On x86 machine, the take control process includes
1053*7c478bd9Sstevel@tonic-gate  *    o get the base address of the extended capability list
1054*7c478bd9Sstevel@tonic-gate  *    o find out the capability for handoff synchronization in the list.
1055*7c478bd9Sstevel@tonic-gate  *    o check if BIOS has owned the host controller.
1056*7c478bd9Sstevel@tonic-gate  *    o set the OS Owned semaphore bit, ask the BIOS to release the ownership.
1057*7c478bd9Sstevel@tonic-gate  *    o wait for a constant time and check if BIOS has relinquished control.
1058*7c478bd9Sstevel@tonic-gate  */
1059*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1060*7c478bd9Sstevel@tonic-gate static int
1061*7c478bd9Sstevel@tonic-gate ehci_take_control(ehci_state_t *ehcip)
1062*7c478bd9Sstevel@tonic-gate {
1063*7c478bd9Sstevel@tonic-gate #if defined(__x86)
1064*7c478bd9Sstevel@tonic-gate 	uint32_t		extended_cap;
1065*7c478bd9Sstevel@tonic-gate 	uint32_t		extended_cap_offset;
1066*7c478bd9Sstevel@tonic-gate 	uint32_t		extended_cap_id;
1067*7c478bd9Sstevel@tonic-gate 	uint_t			retry;
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1070*7c478bd9Sstevel@tonic-gate 	    "ehci_take_control:");
1071*7c478bd9Sstevel@tonic-gate 
1072*7c478bd9Sstevel@tonic-gate 	/*
1073*7c478bd9Sstevel@tonic-gate 	 * According EHCI Spec 2.2.4, get EECP base address from HCCPARAMS
1074*7c478bd9Sstevel@tonic-gate 	 * register.
1075*7c478bd9Sstevel@tonic-gate 	 */
1076*7c478bd9Sstevel@tonic-gate 	extended_cap_offset = (Get_Cap(ehci_hcc_params) & EHCI_HCC_EECP) >>
1077*7c478bd9Sstevel@tonic-gate 	    EHCI_HCC_EECP_SHIFT;
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 	/*
1080*7c478bd9Sstevel@tonic-gate 	 * According EHCI Spec 2.2.4, if the extended capability offset is
1081*7c478bd9Sstevel@tonic-gate 	 * less than 40h then its not valid.  This means we don't need to
1082*7c478bd9Sstevel@tonic-gate 	 * worry about BIOS handoff.
1083*7c478bd9Sstevel@tonic-gate 	 */
1084*7c478bd9Sstevel@tonic-gate 	if (extended_cap_offset < EHCI_HCC_EECP_MIN_OFFSET) {
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1087*7c478bd9Sstevel@tonic-gate 		    "ehci_take_control: Hardware doesn't support legacy.");
1088*7c478bd9Sstevel@tonic-gate 
1089*7c478bd9Sstevel@tonic-gate 		goto success;
1090*7c478bd9Sstevel@tonic-gate 	}
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 	/*
1093*7c478bd9Sstevel@tonic-gate 	 * According EHCI Spec 2.1.7, A zero offset indicates the
1094*7c478bd9Sstevel@tonic-gate 	 * end of the extended capability list.
1095*7c478bd9Sstevel@tonic-gate 	 */
1096*7c478bd9Sstevel@tonic-gate 	while (extended_cap_offset) {
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate 		/* Get the extended capability value. */
1099*7c478bd9Sstevel@tonic-gate 		extended_cap = pci_config_get32(ehcip->ehci_config_handle,
1100*7c478bd9Sstevel@tonic-gate 		    extended_cap_offset);
1101*7c478bd9Sstevel@tonic-gate 
1102*7c478bd9Sstevel@tonic-gate 		/* Get the capability ID */
1103*7c478bd9Sstevel@tonic-gate 		extended_cap_id = (extended_cap & EHCI_EX_CAP_ID) >>
1104*7c478bd9Sstevel@tonic-gate 		    EHCI_EX_CAP_ID_SHIFT;
1105*7c478bd9Sstevel@tonic-gate 
1106*7c478bd9Sstevel@tonic-gate 		/* Check if the card support legacy */
1107*7c478bd9Sstevel@tonic-gate 		if (extended_cap_id == EHCI_EX_CAP_ID_BIOS_HANDOFF) {
1108*7c478bd9Sstevel@tonic-gate 			break;
1109*7c478bd9Sstevel@tonic-gate 		}
1110*7c478bd9Sstevel@tonic-gate 
1111*7c478bd9Sstevel@tonic-gate 		/* Get the offset of the next capability */
1112*7c478bd9Sstevel@tonic-gate 		extended_cap_offset = (extended_cap & EHCI_EX_CAP_NEXT_PTR) >>
1113*7c478bd9Sstevel@tonic-gate 		    EHCI_EX_CAP_NEXT_PTR_SHIFT;
1114*7c478bd9Sstevel@tonic-gate 	}
1115*7c478bd9Sstevel@tonic-gate 
1116*7c478bd9Sstevel@tonic-gate 	/*
1117*7c478bd9Sstevel@tonic-gate 	 * Unable to find legacy support in hardware's extended capability list.
1118*7c478bd9Sstevel@tonic-gate 	 * This means we don't need to worry about BIOS handoff.
1119*7c478bd9Sstevel@tonic-gate 	 */
1120*7c478bd9Sstevel@tonic-gate 	if (extended_cap_id != EHCI_EX_CAP_ID_BIOS_HANDOFF) {
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1123*7c478bd9Sstevel@tonic-gate 		    "ehci_take_control: Hardware doesn't support legacy");
1124*7c478bd9Sstevel@tonic-gate 
1125*7c478bd9Sstevel@tonic-gate 		goto success;
1126*7c478bd9Sstevel@tonic-gate 	}
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate 	/* Check if BIOS has owned it. */
1129*7c478bd9Sstevel@tonic-gate 	if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) {
1130*7c478bd9Sstevel@tonic-gate 
1131*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1132*7c478bd9Sstevel@tonic-gate 		    "ehci_take_control: BIOS does not own EHCI");
1133*7c478bd9Sstevel@tonic-gate 
1134*7c478bd9Sstevel@tonic-gate 		goto success;
1135*7c478bd9Sstevel@tonic-gate 	}
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate 	/*
1138*7c478bd9Sstevel@tonic-gate 	 * According EHCI Spec 5.1, The OS driver initiates an ownership
1139*7c478bd9Sstevel@tonic-gate 	 * request by setting the OS Owned semaphore to a one. The OS
1140*7c478bd9Sstevel@tonic-gate 	 * waits for the BIOS Owned bit to go to a zero before attempting
1141*7c478bd9Sstevel@tonic-gate 	 * to use the EHCI controller. The time that OS must wait for BIOS
1142*7c478bd9Sstevel@tonic-gate 	 * to respond to the request for ownership is beyond the scope of
1143*7c478bd9Sstevel@tonic-gate 	 * this specification.
1144*7c478bd9Sstevel@tonic-gate 	 * It waits up to EHCI_TAKEOVER_WAIT_COUNT*EHCI_TAKEOVER_DELAY ms
1145*7c478bd9Sstevel@tonic-gate 	 * for BIOS to release the ownership.
1146*7c478bd9Sstevel@tonic-gate 	 */
1147*7c478bd9Sstevel@tonic-gate 	extended_cap |= EHCI_LEGSUP_OS_OWNED_SEM;
1148*7c478bd9Sstevel@tonic-gate 	pci_config_put32(ehcip->ehci_config_handle, extended_cap_offset,
1149*7c478bd9Sstevel@tonic-gate 	    extended_cap);
1150*7c478bd9Sstevel@tonic-gate 
1151*7c478bd9Sstevel@tonic-gate 	for (retry = 0; retry < EHCI_TAKEOVER_WAIT_COUNT; retry++) {
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate 		/* wait a special interval */
1154*7c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(EHCI_TAKEOVER_DELAY));
1155*7c478bd9Sstevel@tonic-gate 
1156*7c478bd9Sstevel@tonic-gate 		/* Check to see if the BIOS has released the ownership */
1157*7c478bd9Sstevel@tonic-gate 		extended_cap = pci_config_get32(
1158*7c478bd9Sstevel@tonic-gate 		    ehcip->ehci_config_handle, extended_cap_offset);
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate 		if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) {
1161*7c478bd9Sstevel@tonic-gate 
1162*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ATTA,
1163*7c478bd9Sstevel@tonic-gate 			    ehcip->ehci_log_hdl,
1164*7c478bd9Sstevel@tonic-gate 			    "ehci_take_control: BIOS has released "
1165*7c478bd9Sstevel@tonic-gate 			    "the ownership. retry = %d", retry);
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 			goto success;
1168*7c478bd9Sstevel@tonic-gate 		}
1169*7c478bd9Sstevel@tonic-gate 
1170*7c478bd9Sstevel@tonic-gate 	}
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1173*7c478bd9Sstevel@tonic-gate 	    "ehci_take_control: take control from BIOS failed.");
1174*7c478bd9Sstevel@tonic-gate 
1175*7c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
1176*7c478bd9Sstevel@tonic-gate 
1177*7c478bd9Sstevel@tonic-gate success:
1178*7c478bd9Sstevel@tonic-gate 
1179*7c478bd9Sstevel@tonic-gate #endif	/* __x86 */
1180*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1181*7c478bd9Sstevel@tonic-gate }
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate /*
1185*7c478bd9Sstevel@tonic-gate  * ehci_init_periodic_frame_list_table :
1186*7c478bd9Sstevel@tonic-gate  *
1187*7c478bd9Sstevel@tonic-gate  * Allocate the system memory and initialize Host Controller
1188*7c478bd9Sstevel@tonic-gate  * Periodic Frame List table area. The starting of the Periodic
1189*7c478bd9Sstevel@tonic-gate  * Frame List Table area must be 4096 byte aligned.
1190*7c478bd9Sstevel@tonic-gate  */
1191*7c478bd9Sstevel@tonic-gate static int
1192*7c478bd9Sstevel@tonic-gate ehci_init_periodic_frame_lst_table(ehci_state_t *ehcip)
1193*7c478bd9Sstevel@tonic-gate {
1194*7c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t	dev_attr;
1195*7c478bd9Sstevel@tonic-gate 	size_t			real_length;
1196*7c478bd9Sstevel@tonic-gate 	uint_t			ccount;
1197*7c478bd9Sstevel@tonic-gate 	int			result;
1198*7c478bd9Sstevel@tonic-gate 
1199*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1200*7c478bd9Sstevel@tonic-gate 
1201*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1202*7c478bd9Sstevel@tonic-gate 	    "ehci_init_periodic_frame_lst_table:");
1203*7c478bd9Sstevel@tonic-gate 
1204*7c478bd9Sstevel@tonic-gate 	/* The host controller will be little endian */
1205*7c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1206*7c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
1207*7c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1208*7c478bd9Sstevel@tonic-gate 
1209*7c478bd9Sstevel@tonic-gate 	/* Force the required 4K restrictive alignment */
1210*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_PFL_ALIGNMENT;
1211*7c478bd9Sstevel@tonic-gate 
1212*7c478bd9Sstevel@tonic-gate 	/* Create space for the Periodic Frame List */
1213*7c478bd9Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr,
1214*7c478bd9Sstevel@tonic-gate 	    DDI_DMA_SLEEP, 0, &ehcip->ehci_pflt_dma_handle) != DDI_SUCCESS) {
1215*7c478bd9Sstevel@tonic-gate 
1216*7c478bd9Sstevel@tonic-gate 		goto failure;
1217*7c478bd9Sstevel@tonic-gate 	}
1218*7c478bd9Sstevel@tonic-gate 
1219*7c478bd9Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(ehcip->ehci_pflt_dma_handle,
1220*7c478bd9Sstevel@tonic-gate 	    sizeof (ehci_periodic_frame_list_t),
1221*7c478bd9Sstevel@tonic-gate 	    &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
1222*7c478bd9Sstevel@tonic-gate 	    0, (caddr_t *)&ehcip->ehci_periodic_frame_list_tablep,
1223*7c478bd9Sstevel@tonic-gate 	    &real_length, &ehcip->ehci_pflt_mem_handle)) {
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate 		goto failure;
1226*7c478bd9Sstevel@tonic-gate 	}
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1229*7c478bd9Sstevel@tonic-gate 	    "ehci_init_periodic_frame_lst_table: "
1230*7c478bd9Sstevel@tonic-gate 	    "Real length %lu", real_length);
1231*7c478bd9Sstevel@tonic-gate 
1232*7c478bd9Sstevel@tonic-gate 	/* Map the whole Periodic Frame List into the I/O address space */
1233*7c478bd9Sstevel@tonic-gate 	result = ddi_dma_addr_bind_handle(ehcip->ehci_pflt_dma_handle,
1234*7c478bd9Sstevel@tonic-gate 	    NULL, (caddr_t)ehcip->ehci_periodic_frame_list_tablep,
1235*7c478bd9Sstevel@tonic-gate 	    real_length, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1236*7c478bd9Sstevel@tonic-gate 	    DDI_DMA_SLEEP, NULL, &ehcip->ehci_pflt_cookie, &ccount);
1237*7c478bd9Sstevel@tonic-gate 
1238*7c478bd9Sstevel@tonic-gate 	if (result == DDI_DMA_MAPPED) {
1239*7c478bd9Sstevel@tonic-gate 		/* The cookie count should be 1 */
1240*7c478bd9Sstevel@tonic-gate 		if (ccount != 1) {
1241*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1242*7c478bd9Sstevel@tonic-gate 			    "ehci_init_periodic_frame_lst_table: "
1243*7c478bd9Sstevel@tonic-gate 			    "More than 1 cookie");
1244*7c478bd9Sstevel@tonic-gate 
1245*7c478bd9Sstevel@tonic-gate 			goto failure;
1246*7c478bd9Sstevel@tonic-gate 		}
1247*7c478bd9Sstevel@tonic-gate 	} else {
1248*7c478bd9Sstevel@tonic-gate 		ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
1249*7c478bd9Sstevel@tonic-gate 
1250*7c478bd9Sstevel@tonic-gate 		goto failure;
1251*7c478bd9Sstevel@tonic-gate 	}
1252*7c478bd9Sstevel@tonic-gate 
1253*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1254*7c478bd9Sstevel@tonic-gate 	    "ehci_init_periodic_frame_lst_table: virtual 0x%p physical 0x%x",
1255*7c478bd9Sstevel@tonic-gate 	    (void *)ehcip->ehci_periodic_frame_list_tablep,
1256*7c478bd9Sstevel@tonic-gate 	    ehcip->ehci_pflt_cookie.dmac_address);
1257*7c478bd9Sstevel@tonic-gate 
1258*7c478bd9Sstevel@tonic-gate 	/*
1259*7c478bd9Sstevel@tonic-gate 	 * DMA addresses for Periodic Frame List are bound.
1260*7c478bd9Sstevel@tonic-gate 	 */
1261*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_addr_bind_flag |= EHCI_PFLT_DMA_BOUND;
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate 	bzero((void *)ehcip->ehci_periodic_frame_list_tablep, real_length);
1264*7c478bd9Sstevel@tonic-gate 
1265*7c478bd9Sstevel@tonic-gate 	/* Initialize the Periodic Frame List */
1266*7c478bd9Sstevel@tonic-gate 	ehci_build_interrupt_lattice(ehcip);
1267*7c478bd9Sstevel@tonic-gate 
1268*7c478bd9Sstevel@tonic-gate 	/* Reset Byte Alignment to Default */
1269*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1272*7c478bd9Sstevel@tonic-gate failure:
1273*7c478bd9Sstevel@tonic-gate 	/* Byte alignment */
1274*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
1275*7c478bd9Sstevel@tonic-gate 
1276*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
1277*7c478bd9Sstevel@tonic-gate }
1278*7c478bd9Sstevel@tonic-gate 
1279*7c478bd9Sstevel@tonic-gate 
1280*7c478bd9Sstevel@tonic-gate /*
1281*7c478bd9Sstevel@tonic-gate  * ehci_build_interrupt_lattice:
1282*7c478bd9Sstevel@tonic-gate  *
1283*7c478bd9Sstevel@tonic-gate  * Construct the interrupt lattice tree using static Endpoint Descriptors
1284*7c478bd9Sstevel@tonic-gate  * (QH). This interrupt lattice tree will have total of 32 interrupt  QH
1285*7c478bd9Sstevel@tonic-gate  * lists and the Host Controller (HC) processes one interrupt QH list in
1286*7c478bd9Sstevel@tonic-gate  * every frame. The Host Controller traverses the periodic schedule by
1287*7c478bd9Sstevel@tonic-gate  * constructing an array offset reference from the Periodic List Base Address
1288*7c478bd9Sstevel@tonic-gate  * register and bits 12 to 3 of Frame Index register. It fetches the element
1289*7c478bd9Sstevel@tonic-gate  * and begins traversing the graph of linked schedule data structures.
1290*7c478bd9Sstevel@tonic-gate  */
1291*7c478bd9Sstevel@tonic-gate static void
1292*7c478bd9Sstevel@tonic-gate ehci_build_interrupt_lattice(ehci_state_t	*ehcip)
1293*7c478bd9Sstevel@tonic-gate {
1294*7c478bd9Sstevel@tonic-gate 	ehci_qh_t	*list_array = ehcip->ehci_qh_pool_addr;
1295*7c478bd9Sstevel@tonic-gate 	ushort_t	ehci_index[EHCI_NUM_PERIODIC_FRAME_LISTS];
1296*7c478bd9Sstevel@tonic-gate 	ehci_periodic_frame_list_t *periodic_frame_list =
1297*7c478bd9Sstevel@tonic-gate 			    ehcip->ehci_periodic_frame_list_tablep;
1298*7c478bd9Sstevel@tonic-gate 	ushort_t	*temp, num_of_nodes;
1299*7c478bd9Sstevel@tonic-gate 	uintptr_t	addr;
1300*7c478bd9Sstevel@tonic-gate 	int		i, j, k;
1301*7c478bd9Sstevel@tonic-gate 
1302*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1303*7c478bd9Sstevel@tonic-gate 	    "ehci_build_interrupt_lattice:");
1304*7c478bd9Sstevel@tonic-gate 
1305*7c478bd9Sstevel@tonic-gate 	/*
1306*7c478bd9Sstevel@tonic-gate 	 * Reserve the first 63 Endpoint Descriptor (QH) structures
1307*7c478bd9Sstevel@tonic-gate 	 * in the pool as static endpoints & these are required for
1308*7c478bd9Sstevel@tonic-gate 	 * constructing interrupt lattice tree.
1309*7c478bd9Sstevel@tonic-gate 	 */
1310*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < EHCI_NUM_STATIC_NODES; i++) {
1311*7c478bd9Sstevel@tonic-gate 		Set_QH(list_array[i].qh_state, EHCI_QH_STATIC);
1312*7c478bd9Sstevel@tonic-gate 		Set_QH(list_array[i].qh_status, EHCI_QH_STS_HALTED);
1313*7c478bd9Sstevel@tonic-gate 		Set_QH(list_array[i].qh_next_qtd, EHCI_QH_NEXT_QTD_PTR_VALID);
1314*7c478bd9Sstevel@tonic-gate 		Set_QH(list_array[i].qh_alt_next_qtd,
1315*7c478bd9Sstevel@tonic-gate 		    EHCI_QH_ALT_NEXT_QTD_PTR_VALID);
1316*7c478bd9Sstevel@tonic-gate 	}
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate 	/*
1319*7c478bd9Sstevel@tonic-gate 	 * Make sure that last Endpoint on the periodic frame list terminates
1320*7c478bd9Sstevel@tonic-gate 	 * periodic schedule.
1321*7c478bd9Sstevel@tonic-gate 	 */
1322*7c478bd9Sstevel@tonic-gate 	Set_QH(list_array[0].qh_link_ptr, EHCI_QH_LINK_PTR_VALID);
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 	/* Build the interrupt lattice tree */
1325*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < (EHCI_NUM_STATIC_NODES / 2); i++) {
1326*7c478bd9Sstevel@tonic-gate 		/*
1327*7c478bd9Sstevel@tonic-gate 		 * The next  pointer in the host controller  endpoint
1328*7c478bd9Sstevel@tonic-gate 		 * descriptor must contain an iommu address. Calculate
1329*7c478bd9Sstevel@tonic-gate 		 * the offset into the cpu address and add this to the
1330*7c478bd9Sstevel@tonic-gate 		 * starting iommu address.
1331*7c478bd9Sstevel@tonic-gate 		 */
1332*7c478bd9Sstevel@tonic-gate 		addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *)&list_array[i]);
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 		Set_QH(list_array[2*i + 1].qh_link_ptr,
1335*7c478bd9Sstevel@tonic-gate 		    addr | EHCI_QH_LINK_REF_QH);
1336*7c478bd9Sstevel@tonic-gate 		Set_QH(list_array[2*i + 2].qh_link_ptr,
1337*7c478bd9Sstevel@tonic-gate 		    addr | EHCI_QH_LINK_REF_QH);
1338*7c478bd9Sstevel@tonic-gate 	}
1339*7c478bd9Sstevel@tonic-gate 
1340*7c478bd9Sstevel@tonic-gate 	/* Build the tree bottom */
1341*7c478bd9Sstevel@tonic-gate 	temp = (unsigned short *)
1342*7c478bd9Sstevel@tonic-gate 	    kmem_zalloc(EHCI_NUM_PERIODIC_FRAME_LISTS * 2, KM_SLEEP);
1343*7c478bd9Sstevel@tonic-gate 
1344*7c478bd9Sstevel@tonic-gate 	num_of_nodes = 1;
1345*7c478bd9Sstevel@tonic-gate 
1346*7c478bd9Sstevel@tonic-gate 	/*
1347*7c478bd9Sstevel@tonic-gate 	 * Initialize the values which are used for setting up head pointers
1348*7c478bd9Sstevel@tonic-gate 	 * for the 32ms scheduling lists which starts from the Periodic Frame
1349*7c478bd9Sstevel@tonic-gate 	 * List.
1350*7c478bd9Sstevel@tonic-gate 	 */
1351*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ehci_log_2(EHCI_NUM_PERIODIC_FRAME_LISTS); i++) {
1352*7c478bd9Sstevel@tonic-gate 		for (j = 0, k = 0; k < num_of_nodes; k++, j++) {
1353*7c478bd9Sstevel@tonic-gate 			ehci_index[j++] = temp[k];
1354*7c478bd9Sstevel@tonic-gate 			ehci_index[j]	= temp[k] + ehci_pow_2(i);
1355*7c478bd9Sstevel@tonic-gate 		}
1356*7c478bd9Sstevel@tonic-gate 
1357*7c478bd9Sstevel@tonic-gate 		num_of_nodes *= 2;
1358*7c478bd9Sstevel@tonic-gate 		for (k = 0; k < num_of_nodes; k++)
1359*7c478bd9Sstevel@tonic-gate 			temp[k] = ehci_index[k];
1360*7c478bd9Sstevel@tonic-gate 	}
1361*7c478bd9Sstevel@tonic-gate 
1362*7c478bd9Sstevel@tonic-gate 	kmem_free((void *)temp, (EHCI_NUM_PERIODIC_FRAME_LISTS * 2));
1363*7c478bd9Sstevel@tonic-gate 
1364*7c478bd9Sstevel@tonic-gate 	/*
1365*7c478bd9Sstevel@tonic-gate 	 * Initialize the interrupt list in the Periodic Frame List Table
1366*7c478bd9Sstevel@tonic-gate 	 * so that it points to the bottom of the tree.
1367*7c478bd9Sstevel@tonic-gate 	 */
1368*7c478bd9Sstevel@tonic-gate 	for (i = 0, j = 0; i < ehci_pow_2(TREE_HEIGHT); i++) {
1369*7c478bd9Sstevel@tonic-gate 		addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *)
1370*7c478bd9Sstevel@tonic-gate 		    (&list_array[((EHCI_NUM_STATIC_NODES + 1) / 2) + i - 1]));
1371*7c478bd9Sstevel@tonic-gate 
1372*7c478bd9Sstevel@tonic-gate 		ASSERT(addr);
1373*7c478bd9Sstevel@tonic-gate 
1374*7c478bd9Sstevel@tonic-gate 		for (k = 0; k < ehci_pow_2(TREE_HEIGHT); k++) {
1375*7c478bd9Sstevel@tonic-gate 			Set_PFLT(periodic_frame_list->
1376*7c478bd9Sstevel@tonic-gate 			    ehci_periodic_frame_list_table[ehci_index[j++]],
1377*7c478bd9Sstevel@tonic-gate 			    (uint32_t)(addr | EHCI_QH_LINK_REF_QH));
1378*7c478bd9Sstevel@tonic-gate 		}
1379*7c478bd9Sstevel@tonic-gate 	}
1380*7c478bd9Sstevel@tonic-gate }
1381*7c478bd9Sstevel@tonic-gate 
1382*7c478bd9Sstevel@tonic-gate 
1383*7c478bd9Sstevel@tonic-gate /*
1384*7c478bd9Sstevel@tonic-gate  * ehci_alloc_hcdi_ops:
1385*7c478bd9Sstevel@tonic-gate  *
1386*7c478bd9Sstevel@tonic-gate  * The HCDI interfaces or entry points are the software interfaces used by
1387*7c478bd9Sstevel@tonic-gate  * the Universal Serial Bus Driver  (USBA) to  access the services of the
1388*7c478bd9Sstevel@tonic-gate  * Host Controller Driver (HCD).  During HCD initialization, inform  USBA
1389*7c478bd9Sstevel@tonic-gate  * about all available HCDI interfaces or entry points.
1390*7c478bd9Sstevel@tonic-gate  */
1391*7c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *
1392*7c478bd9Sstevel@tonic-gate ehci_alloc_hcdi_ops(ehci_state_t	*ehcip)
1393*7c478bd9Sstevel@tonic-gate {
1394*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops_t			*usba_hcdi_ops;
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1397*7c478bd9Sstevel@tonic-gate 	    "ehci_alloc_hcdi_ops:");
1398*7c478bd9Sstevel@tonic-gate 
1399*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops = usba_alloc_hcdi_ops();
1400*7c478bd9Sstevel@tonic-gate 
1401*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_ops_version = HCDI_OPS_VERSION;
1402*7c478bd9Sstevel@tonic-gate 
1403*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_open = ehci_hcdi_pipe_open;
1404*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_close = ehci_hcdi_pipe_close;
1405*7c478bd9Sstevel@tonic-gate 
1406*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_reset = ehci_hcdi_pipe_reset;
1407*7c478bd9Sstevel@tonic-gate 
1408*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_ctrl_xfer = ehci_hcdi_pipe_ctrl_xfer;
1409*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_bulk_xfer = ehci_hcdi_pipe_bulk_xfer;
1410*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_intr_xfer = ehci_hcdi_pipe_intr_xfer;
1411*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_isoc_xfer = ehci_hcdi_pipe_isoc_xfer;
1412*7c478bd9Sstevel@tonic-gate 
1413*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_bulk_transfer_size =
1414*7c478bd9Sstevel@tonic-gate 					ehci_hcdi_bulk_transfer_size;
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_stop_intr_polling =
1417*7c478bd9Sstevel@tonic-gate 					ehci_hcdi_pipe_stop_intr_polling;
1418*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_stop_isoc_polling =
1419*7c478bd9Sstevel@tonic-gate 					ehci_hcdi_pipe_stop_isoc_polling;
1420*7c478bd9Sstevel@tonic-gate 
1421*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_get_current_frame_number =
1422*7c478bd9Sstevel@tonic-gate 					ehci_hcdi_get_current_frame_number;
1423*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_get_max_isoc_pkts =
1424*7c478bd9Sstevel@tonic-gate 					ehci_hcdi_get_max_isoc_pkts;
1425*7c478bd9Sstevel@tonic-gate 
1426*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_console_input_init =
1427*7c478bd9Sstevel@tonic-gate 					ehci_hcdi_polled_input_init;
1428*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_console_input_enter =
1429*7c478bd9Sstevel@tonic-gate 					ehci_hcdi_polled_input_enter;
1430*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_console_read =
1431*7c478bd9Sstevel@tonic-gate 					ehci_hcdi_polled_read;
1432*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_console_input_exit =
1433*7c478bd9Sstevel@tonic-gate 					ehci_hcdi_polled_input_exit;
1434*7c478bd9Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_console_input_fini =
1435*7c478bd9Sstevel@tonic-gate 					ehci_hcdi_polled_input_fini;
1436*7c478bd9Sstevel@tonic-gate 	return (usba_hcdi_ops);
1437*7c478bd9Sstevel@tonic-gate }
1438*7c478bd9Sstevel@tonic-gate 
1439*7c478bd9Sstevel@tonic-gate 
1440*7c478bd9Sstevel@tonic-gate /*
1441*7c478bd9Sstevel@tonic-gate  * Host Controller Driver (HCD) deinitialization functions
1442*7c478bd9Sstevel@tonic-gate  */
1443*7c478bd9Sstevel@tonic-gate 
1444*7c478bd9Sstevel@tonic-gate /*
1445*7c478bd9Sstevel@tonic-gate  * ehci_cleanup:
1446*7c478bd9Sstevel@tonic-gate  *
1447*7c478bd9Sstevel@tonic-gate  * Cleanup on attach failure or detach
1448*7c478bd9Sstevel@tonic-gate  */
1449*7c478bd9Sstevel@tonic-gate int
1450*7c478bd9Sstevel@tonic-gate ehci_cleanup(ehci_state_t	*ehcip)
1451*7c478bd9Sstevel@tonic-gate {
1452*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
1453*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
1454*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd;
1455*7c478bd9Sstevel@tonic-gate 	int			i, ctrl, rval;
1456*7c478bd9Sstevel@tonic-gate 	int			flags = ehcip->ehci_flags;
1457*7c478bd9Sstevel@tonic-gate 
1458*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_cleanup:");
1459*7c478bd9Sstevel@tonic-gate 
1460*7c478bd9Sstevel@tonic-gate 	if (flags & EHCI_RHREG) {
1461*7c478bd9Sstevel@tonic-gate 		/* Unload the root hub driver */
1462*7c478bd9Sstevel@tonic-gate 		if (ehci_unload_root_hub_driver(ehcip) != USB_SUCCESS) {
1463*7c478bd9Sstevel@tonic-gate 
1464*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
1465*7c478bd9Sstevel@tonic-gate 		}
1466*7c478bd9Sstevel@tonic-gate 	}
1467*7c478bd9Sstevel@tonic-gate 
1468*7c478bd9Sstevel@tonic-gate 	if (flags & EHCI_USBAREG) {
1469*7c478bd9Sstevel@tonic-gate 		/* Unregister this HCD instance with USBA */
1470*7c478bd9Sstevel@tonic-gate 		usba_hcdi_unregister(ehcip->ehci_dip);
1471*7c478bd9Sstevel@tonic-gate 	}
1472*7c478bd9Sstevel@tonic-gate 
1473*7c478bd9Sstevel@tonic-gate 	if (flags & EHCI_INTR) {
1474*7c478bd9Sstevel@tonic-gate 
1475*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ehcip->ehci_int_mutex);
1476*7c478bd9Sstevel@tonic-gate 
1477*7c478bd9Sstevel@tonic-gate 		/* Route all Root hub ports to Classic host controller */
1478*7c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC);
1479*7c478bd9Sstevel@tonic-gate 
1480*7c478bd9Sstevel@tonic-gate 		/* Disable all EHCI QH list processing */
1481*7c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_command, (Get_OpReg(ehci_command) &
1482*7c478bd9Sstevel@tonic-gate 		    ~(EHCI_CMD_ASYNC_SCHED_ENABLE |
1483*7c478bd9Sstevel@tonic-gate 		    EHCI_CMD_PERIODIC_SCHED_ENABLE)));
1484*7c478bd9Sstevel@tonic-gate 
1485*7c478bd9Sstevel@tonic-gate 		/* Disable all EHCI interrupts */
1486*7c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_interrupt, 0);
1487*7c478bd9Sstevel@tonic-gate 
1488*7c478bd9Sstevel@tonic-gate 		/* wait for the next SOF */
1489*7c478bd9Sstevel@tonic-gate 		(void) ehci_wait_for_sof(ehcip);
1490*7c478bd9Sstevel@tonic-gate 
1491*7c478bd9Sstevel@tonic-gate 		/* Stop the EHCI host controller */
1492*7c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_command,
1493*7c478bd9Sstevel@tonic-gate 		    Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN);
1494*7c478bd9Sstevel@tonic-gate 
1495*7c478bd9Sstevel@tonic-gate 		/* Wait for sometime */
1496*7c478bd9Sstevel@tonic-gate 		drv_usecwait(EHCI_TIMEWAIT);
1497*7c478bd9Sstevel@tonic-gate 
1498*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
1499*7c478bd9Sstevel@tonic-gate 
1500*7c478bd9Sstevel@tonic-gate 		/* disable interrupt */
1501*7c478bd9Sstevel@tonic-gate 		(void) ddi_intr_disable(ehcip->ehci_htable[0]);
1502*7c478bd9Sstevel@tonic-gate 
1503*7c478bd9Sstevel@tonic-gate 		/* Remove interrupt handler */
1504*7c478bd9Sstevel@tonic-gate 		(void) ddi_intr_remove_handler(ehcip->ehci_htable[0]);
1505*7c478bd9Sstevel@tonic-gate 
1506*7c478bd9Sstevel@tonic-gate 		/* free interrupt handle */
1507*7c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(ehcip->ehci_htable[0]);
1508*7c478bd9Sstevel@tonic-gate 
1509*7c478bd9Sstevel@tonic-gate 		/* free memory */
1510*7c478bd9Sstevel@tonic-gate 		kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t));
1511*7c478bd9Sstevel@tonic-gate 	}
1512*7c478bd9Sstevel@tonic-gate 
1513*7c478bd9Sstevel@tonic-gate 	/* Unmap the EHCI registers */
1514*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_caps_handle) {
1515*7c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&ehcip->ehci_caps_handle);
1516*7c478bd9Sstevel@tonic-gate 	}
1517*7c478bd9Sstevel@tonic-gate 
1518*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_config_handle) {
1519*7c478bd9Sstevel@tonic-gate 		pci_config_teardown(&ehcip->ehci_config_handle);
1520*7c478bd9Sstevel@tonic-gate 	}
1521*7c478bd9Sstevel@tonic-gate 
1522*7c478bd9Sstevel@tonic-gate 	/* Free all the buffers */
1523*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_qtd_pool_addr && ehcip->ehci_qtd_pool_mem_handle) {
1524*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < ehci_qtd_pool_size; i ++) {
1525*7c478bd9Sstevel@tonic-gate 			qtd = &ehcip->ehci_qtd_pool_addr[i];
1526*7c478bd9Sstevel@tonic-gate 			ctrl = Get_QTD(ehcip->
1527*7c478bd9Sstevel@tonic-gate 			    ehci_qtd_pool_addr[i].qtd_state);
1528*7c478bd9Sstevel@tonic-gate 
1529*7c478bd9Sstevel@tonic-gate 			if ((ctrl != EHCI_QTD_FREE) &&
1530*7c478bd9Sstevel@tonic-gate 			    (ctrl != EHCI_QTD_DUMMY) &&
1531*7c478bd9Sstevel@tonic-gate 			    (qtd->qtd_trans_wrapper)) {
1532*7c478bd9Sstevel@tonic-gate 
1533*7c478bd9Sstevel@tonic-gate 				mutex_enter(&ehcip->ehci_int_mutex);
1534*7c478bd9Sstevel@tonic-gate 
1535*7c478bd9Sstevel@tonic-gate 				tw = (ehci_trans_wrapper_t *)
1536*7c478bd9Sstevel@tonic-gate 					EHCI_LOOKUP_ID((uint32_t)
1537*7c478bd9Sstevel@tonic-gate 					Get_QTD(qtd->qtd_trans_wrapper));
1538*7c478bd9Sstevel@tonic-gate 
1539*7c478bd9Sstevel@tonic-gate 				/* Obtain the pipe private structure */
1540*7c478bd9Sstevel@tonic-gate 				pp = tw->tw_pipe_private;
1541*7c478bd9Sstevel@tonic-gate 
1542*7c478bd9Sstevel@tonic-gate 				/* Stop the the transfer timer */
1543*7c478bd9Sstevel@tonic-gate 				ehci_stop_xfer_timer(ehcip, tw,
1544*7c478bd9Sstevel@tonic-gate 						EHCI_REMOVE_XFER_ALWAYS);
1545*7c478bd9Sstevel@tonic-gate 
1546*7c478bd9Sstevel@tonic-gate 				ehci_deallocate_tw(ehcip, pp, tw);
1547*7c478bd9Sstevel@tonic-gate 
1548*7c478bd9Sstevel@tonic-gate 				mutex_exit(&ehcip->ehci_int_mutex);
1549*7c478bd9Sstevel@tonic-gate 			}
1550*7c478bd9Sstevel@tonic-gate 		}
1551*7c478bd9Sstevel@tonic-gate 
1552*7c478bd9Sstevel@tonic-gate 		/*
1553*7c478bd9Sstevel@tonic-gate 		 * If EHCI_QTD_POOL_BOUND flag is set, then unbind
1554*7c478bd9Sstevel@tonic-gate 		 * the handle for QTD pools.
1555*7c478bd9Sstevel@tonic-gate 		 */
1556*7c478bd9Sstevel@tonic-gate 		if ((ehcip->ehci_dma_addr_bind_flag &
1557*7c478bd9Sstevel@tonic-gate 		    EHCI_QTD_POOL_BOUND) == EHCI_QTD_POOL_BOUND) {
1558*7c478bd9Sstevel@tonic-gate 
1559*7c478bd9Sstevel@tonic-gate 			rval = ddi_dma_unbind_handle(
1560*7c478bd9Sstevel@tonic-gate 			    ehcip->ehci_qtd_pool_dma_handle);
1561*7c478bd9Sstevel@tonic-gate 
1562*7c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
1563*7c478bd9Sstevel@tonic-gate 		}
1564*7c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&ehcip->ehci_qtd_pool_mem_handle);
1565*7c478bd9Sstevel@tonic-gate 	}
1566*7c478bd9Sstevel@tonic-gate 
1567*7c478bd9Sstevel@tonic-gate 	/* Free the QTD pool */
1568*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_qtd_pool_dma_handle) {
1569*7c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&ehcip->ehci_qtd_pool_dma_handle);
1570*7c478bd9Sstevel@tonic-gate 	}
1571*7c478bd9Sstevel@tonic-gate 
1572*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_qh_pool_addr && ehcip->ehci_qh_pool_mem_handle) {
1573*7c478bd9Sstevel@tonic-gate 		/*
1574*7c478bd9Sstevel@tonic-gate 		 * If EHCI_QH_POOL_BOUND flag is set, then unbind
1575*7c478bd9Sstevel@tonic-gate 		 * the handle for QH pools.
1576*7c478bd9Sstevel@tonic-gate 		 */
1577*7c478bd9Sstevel@tonic-gate 		if ((ehcip->ehci_dma_addr_bind_flag &
1578*7c478bd9Sstevel@tonic-gate 		    EHCI_QH_POOL_BOUND) == EHCI_QH_POOL_BOUND) {
1579*7c478bd9Sstevel@tonic-gate 
1580*7c478bd9Sstevel@tonic-gate 			rval = ddi_dma_unbind_handle(
1581*7c478bd9Sstevel@tonic-gate 			    ehcip->ehci_qh_pool_dma_handle);
1582*7c478bd9Sstevel@tonic-gate 
1583*7c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
1584*7c478bd9Sstevel@tonic-gate 		}
1585*7c478bd9Sstevel@tonic-gate 
1586*7c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&ehcip->ehci_qh_pool_mem_handle);
1587*7c478bd9Sstevel@tonic-gate 	}
1588*7c478bd9Sstevel@tonic-gate 
1589*7c478bd9Sstevel@tonic-gate 	/* Free the QH pool */
1590*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_qh_pool_dma_handle) {
1591*7c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&ehcip->ehci_qh_pool_dma_handle);
1592*7c478bd9Sstevel@tonic-gate 	}
1593*7c478bd9Sstevel@tonic-gate 
1594*7c478bd9Sstevel@tonic-gate 	/* Free the Periodic frame list table (PFLT) area */
1595*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_periodic_frame_list_tablep &&
1596*7c478bd9Sstevel@tonic-gate 	    ehcip->ehci_pflt_mem_handle) {
1597*7c478bd9Sstevel@tonic-gate 		/*
1598*7c478bd9Sstevel@tonic-gate 		 * If EHCI_PFLT_DMA_BOUND flag is set, then unbind
1599*7c478bd9Sstevel@tonic-gate 		 * the handle for PFLT.
1600*7c478bd9Sstevel@tonic-gate 		 */
1601*7c478bd9Sstevel@tonic-gate 		if ((ehcip->ehci_dma_addr_bind_flag &
1602*7c478bd9Sstevel@tonic-gate 		    EHCI_PFLT_DMA_BOUND) == EHCI_PFLT_DMA_BOUND) {
1603*7c478bd9Sstevel@tonic-gate 
1604*7c478bd9Sstevel@tonic-gate 			rval = ddi_dma_unbind_handle(
1605*7c478bd9Sstevel@tonic-gate 			    ehcip->ehci_pflt_dma_handle);
1606*7c478bd9Sstevel@tonic-gate 
1607*7c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
1608*7c478bd9Sstevel@tonic-gate 		}
1609*7c478bd9Sstevel@tonic-gate 
1610*7c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&ehcip->ehci_pflt_mem_handle);
1611*7c478bd9Sstevel@tonic-gate 	}
1612*7c478bd9Sstevel@tonic-gate 
1613*7c478bd9Sstevel@tonic-gate 	(void) ehci_isoc_cleanup(ehcip);
1614*7c478bd9Sstevel@tonic-gate 
1615*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_pflt_dma_handle) {
1616*7c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&ehcip->ehci_pflt_dma_handle);
1617*7c478bd9Sstevel@tonic-gate 	}
1618*7c478bd9Sstevel@tonic-gate 
1619*7c478bd9Sstevel@tonic-gate 	if (flags & EHCI_INTR) {
1620*7c478bd9Sstevel@tonic-gate 		/* Destroy the mutex */
1621*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&ehcip->ehci_int_mutex);
1622*7c478bd9Sstevel@tonic-gate 
1623*7c478bd9Sstevel@tonic-gate 		/* Destroy the async schedule advance condition variable */
1624*7c478bd9Sstevel@tonic-gate 		cv_destroy(&ehcip->ehci_async_schedule_advance_cv);
1625*7c478bd9Sstevel@tonic-gate 	}
1626*7c478bd9Sstevel@tonic-gate 
1627*7c478bd9Sstevel@tonic-gate 	/* clean up kstat structs */
1628*7c478bd9Sstevel@tonic-gate 	ehci_destroy_stats(ehcip);
1629*7c478bd9Sstevel@tonic-gate 
1630*7c478bd9Sstevel@tonic-gate 	/* Free ehci hcdi ops */
1631*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_hcdi_ops) {
1632*7c478bd9Sstevel@tonic-gate 		usba_free_hcdi_ops(ehcip->ehci_hcdi_ops);
1633*7c478bd9Sstevel@tonic-gate 	}
1634*7c478bd9Sstevel@tonic-gate 
1635*7c478bd9Sstevel@tonic-gate 	if (flags & EHCI_ZALLOC) {
1636*7c478bd9Sstevel@tonic-gate 
1637*7c478bd9Sstevel@tonic-gate 		usb_free_log_hdl(ehcip->ehci_log_hdl);
1638*7c478bd9Sstevel@tonic-gate 
1639*7c478bd9Sstevel@tonic-gate 		/* Remove all properties that might have been created */
1640*7c478bd9Sstevel@tonic-gate 		ddi_prop_remove_all(ehcip->ehci_dip);
1641*7c478bd9Sstevel@tonic-gate 
1642*7c478bd9Sstevel@tonic-gate 		/* Free the soft state */
1643*7c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(ehci_statep,
1644*7c478bd9Sstevel@tonic-gate 			ddi_get_instance(ehcip->ehci_dip));
1645*7c478bd9Sstevel@tonic-gate 	}
1646*7c478bd9Sstevel@tonic-gate 
1647*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1648*7c478bd9Sstevel@tonic-gate }
1649*7c478bd9Sstevel@tonic-gate 
1650*7c478bd9Sstevel@tonic-gate 
1651*7c478bd9Sstevel@tonic-gate /*
1652*7c478bd9Sstevel@tonic-gate  * ehci_cpr_suspend
1653*7c478bd9Sstevel@tonic-gate  */
1654*7c478bd9Sstevel@tonic-gate int
1655*7c478bd9Sstevel@tonic-gate ehci_cpr_suspend(ehci_state_t	*ehcip)
1656*7c478bd9Sstevel@tonic-gate {
1657*7c478bd9Sstevel@tonic-gate 	int	i;
1658*7c478bd9Sstevel@tonic-gate 
1659*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1660*7c478bd9Sstevel@tonic-gate 	    "ehci_cpr_suspend:");
1661*7c478bd9Sstevel@tonic-gate 
1662*7c478bd9Sstevel@tonic-gate 	/* Call into the root hub and suspend it */
1663*7c478bd9Sstevel@tonic-gate 	if (usba_hubdi_detach(ehcip->ehci_dip, DDI_SUSPEND) != DDI_SUCCESS) {
1664*7c478bd9Sstevel@tonic-gate 
1665*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1666*7c478bd9Sstevel@tonic-gate 			"ehci_cpr_suspend: root hub fails to suspend");
1667*7c478bd9Sstevel@tonic-gate 
1668*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1669*7c478bd9Sstevel@tonic-gate 	}
1670*7c478bd9Sstevel@tonic-gate 
1671*7c478bd9Sstevel@tonic-gate 	/* Only root hub's intr pipe should be open at this time */
1672*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
1673*7c478bd9Sstevel@tonic-gate 
1674*7c478bd9Sstevel@tonic-gate 	ASSERT(ehcip->ehci_open_pipe_count == 0);
1675*7c478bd9Sstevel@tonic-gate 
1676*7c478bd9Sstevel@tonic-gate 	/* Just wait till all resources are reclaimed */
1677*7c478bd9Sstevel@tonic-gate 	i = 0;
1678*7c478bd9Sstevel@tonic-gate 	while ((ehcip->ehci_reclaim_list != NULL) && (i++ < 3)) {
1679*7c478bd9Sstevel@tonic-gate 		ehci_handle_endpoint_reclaimation(ehcip);
1680*7c478bd9Sstevel@tonic-gate 		(void) ehci_wait_for_sof(ehcip);
1681*7c478bd9Sstevel@tonic-gate 	}
1682*7c478bd9Sstevel@tonic-gate 	ASSERT(ehcip->ehci_reclaim_list == NULL);
1683*7c478bd9Sstevel@tonic-gate 
1684*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1685*7c478bd9Sstevel@tonic-gate 	    "ehci_cpr_suspend: Disable HC QH list processing");
1686*7c478bd9Sstevel@tonic-gate 
1687*7c478bd9Sstevel@tonic-gate 	/* Disable all EHCI QH list processing */
1688*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_command, (Get_OpReg(ehci_command) &
1689*7c478bd9Sstevel@tonic-gate 	    ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE)));
1690*7c478bd9Sstevel@tonic-gate 
1691*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1692*7c478bd9Sstevel@tonic-gate 	    "ehci_cpr_suspend: Disable HC interrupts");
1693*7c478bd9Sstevel@tonic-gate 
1694*7c478bd9Sstevel@tonic-gate 	/* Disable all EHCI interrupts */
1695*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_interrupt, 0);
1696*7c478bd9Sstevel@tonic-gate 
1697*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1698*7c478bd9Sstevel@tonic-gate 	    "ehci_cpr_suspend: Wait for the next SOF");
1699*7c478bd9Sstevel@tonic-gate 
1700*7c478bd9Sstevel@tonic-gate 	/* Wait for the next SOF */
1701*7c478bd9Sstevel@tonic-gate 	if (ehci_wait_for_sof(ehcip) != USB_SUCCESS) {
1702*7c478bd9Sstevel@tonic-gate 
1703*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1704*7c478bd9Sstevel@tonic-gate 		    "ehci_cpr_suspend: ehci host controller suspend failed");
1705*7c478bd9Sstevel@tonic-gate 
1706*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
1707*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1708*7c478bd9Sstevel@tonic-gate 	}
1709*7c478bd9Sstevel@tonic-gate 
1710*7c478bd9Sstevel@tonic-gate 	/*
1711*7c478bd9Sstevel@tonic-gate 	 * Stop the ehci host controller
1712*7c478bd9Sstevel@tonic-gate 	 * if usb keyboard is not connected.
1713*7c478bd9Sstevel@tonic-gate 	 */
1714*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_polled_kbd_count == 0) {
1715*7c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_command,
1716*7c478bd9Sstevel@tonic-gate 		    Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN);
1717*7c478bd9Sstevel@tonic-gate 	}
1718*7c478bd9Sstevel@tonic-gate 
1719*7c478bd9Sstevel@tonic-gate 	/* Set host controller soft state to suspend */
1720*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_hc_soft_state = EHCI_CTLR_SUSPEND_STATE;
1721*7c478bd9Sstevel@tonic-gate 
1722*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
1723*7c478bd9Sstevel@tonic-gate 
1724*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1725*7c478bd9Sstevel@tonic-gate }
1726*7c478bd9Sstevel@tonic-gate 
1727*7c478bd9Sstevel@tonic-gate 
1728*7c478bd9Sstevel@tonic-gate /*
1729*7c478bd9Sstevel@tonic-gate  * ehci_cpr_resume
1730*7c478bd9Sstevel@tonic-gate  */
1731*7c478bd9Sstevel@tonic-gate int
1732*7c478bd9Sstevel@tonic-gate ehci_cpr_resume(ehci_state_t	*ehcip)
1733*7c478bd9Sstevel@tonic-gate {
1734*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
1735*7c478bd9Sstevel@tonic-gate 
1736*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1737*7c478bd9Sstevel@tonic-gate 	    "ehci_cpr_resume: Restart the controller");
1738*7c478bd9Sstevel@tonic-gate 
1739*7c478bd9Sstevel@tonic-gate 	/* Cleanup ehci specific information across cpr */
1740*7c478bd9Sstevel@tonic-gate 	ehci_cpr_cleanup(ehcip);
1741*7c478bd9Sstevel@tonic-gate 
1742*7c478bd9Sstevel@tonic-gate 	/* Restart the controller */
1743*7c478bd9Sstevel@tonic-gate 	if (ehci_init_ctlr(ehcip) != DDI_SUCCESS) {
1744*7c478bd9Sstevel@tonic-gate 
1745*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1746*7c478bd9Sstevel@tonic-gate 		    "ehci_cpr_resume: ehci host controller resume failed ");
1747*7c478bd9Sstevel@tonic-gate 
1748*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
1749*7c478bd9Sstevel@tonic-gate 
1750*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1751*7c478bd9Sstevel@tonic-gate 	}
1752*7c478bd9Sstevel@tonic-gate 
1753*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
1754*7c478bd9Sstevel@tonic-gate 
1755*7c478bd9Sstevel@tonic-gate 	/* Now resume the root hub */
1756*7c478bd9Sstevel@tonic-gate 	if (usba_hubdi_attach(ehcip->ehci_dip, DDI_RESUME) != DDI_SUCCESS) {
1757*7c478bd9Sstevel@tonic-gate 
1758*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1759*7c478bd9Sstevel@tonic-gate 	}
1760*7c478bd9Sstevel@tonic-gate 
1761*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1762*7c478bd9Sstevel@tonic-gate }
1763*7c478bd9Sstevel@tonic-gate 
1764*7c478bd9Sstevel@tonic-gate 
1765*7c478bd9Sstevel@tonic-gate /*
1766*7c478bd9Sstevel@tonic-gate  * Bandwidth Allocation functions
1767*7c478bd9Sstevel@tonic-gate  */
1768*7c478bd9Sstevel@tonic-gate 
1769*7c478bd9Sstevel@tonic-gate /*
1770*7c478bd9Sstevel@tonic-gate  * ehci_allocate_bandwidth:
1771*7c478bd9Sstevel@tonic-gate  *
1772*7c478bd9Sstevel@tonic-gate  * Figure out whether or not this interval may be supported. Return the index
1773*7c478bd9Sstevel@tonic-gate  * into the  lattice if it can be supported.  Return allocation failure if it
1774*7c478bd9Sstevel@tonic-gate  * can not be supported.
1775*7c478bd9Sstevel@tonic-gate  */
1776*7c478bd9Sstevel@tonic-gate int
1777*7c478bd9Sstevel@tonic-gate ehci_allocate_bandwidth(
1778*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
1779*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
1780*7c478bd9Sstevel@tonic-gate 	uint_t			*pnode,
1781*7c478bd9Sstevel@tonic-gate 	uchar_t			*smask,
1782*7c478bd9Sstevel@tonic-gate 	uchar_t			*cmask)
1783*7c478bd9Sstevel@tonic-gate {
1784*7c478bd9Sstevel@tonic-gate 	int			error = USB_SUCCESS;
1785*7c478bd9Sstevel@tonic-gate 
1786*7c478bd9Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
1787*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1788*7c478bd9Sstevel@tonic-gate 
1789*7c478bd9Sstevel@tonic-gate 	/* Reset the pnode to the last checked pnode */
1790*7c478bd9Sstevel@tonic-gate 	*pnode = 0;
1791*7c478bd9Sstevel@tonic-gate 
1792*7c478bd9Sstevel@tonic-gate 	/* Allocate high speed bandwidth */
1793*7c478bd9Sstevel@tonic-gate 	if ((error = ehci_allocate_high_speed_bandwidth(ehcip,
1794*7c478bd9Sstevel@tonic-gate 	    ph, pnode, smask, cmask)) != USB_SUCCESS) {
1795*7c478bd9Sstevel@tonic-gate 
1796*7c478bd9Sstevel@tonic-gate 		return (error);
1797*7c478bd9Sstevel@tonic-gate 	}
1798*7c478bd9Sstevel@tonic-gate 
1799*7c478bd9Sstevel@tonic-gate 	/*
1800*7c478bd9Sstevel@tonic-gate 	 * For low/full speed usb devices, allocate classic TT bandwidth
1801*7c478bd9Sstevel@tonic-gate 	 * in additional to high speed bandwidth.
1802*7c478bd9Sstevel@tonic-gate 	 */
1803*7c478bd9Sstevel@tonic-gate 	if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) {
1804*7c478bd9Sstevel@tonic-gate 
1805*7c478bd9Sstevel@tonic-gate 		/* Allocate classic TT bandwidth */
1806*7c478bd9Sstevel@tonic-gate 		if ((error = ehci_allocate_classic_tt_bandwidth(
1807*7c478bd9Sstevel@tonic-gate 		    ehcip, ph, *pnode)) != USB_SUCCESS) {
1808*7c478bd9Sstevel@tonic-gate 
1809*7c478bd9Sstevel@tonic-gate 			/* Deallocate high speed bandwidth */
1810*7c478bd9Sstevel@tonic-gate 			ehci_deallocate_high_speed_bandwidth(
1811*7c478bd9Sstevel@tonic-gate 			    ehcip, ph, *pnode, *smask, *cmask);
1812*7c478bd9Sstevel@tonic-gate 		}
1813*7c478bd9Sstevel@tonic-gate 	}
1814*7c478bd9Sstevel@tonic-gate 
1815*7c478bd9Sstevel@tonic-gate 	return (error);
1816*7c478bd9Sstevel@tonic-gate }
1817*7c478bd9Sstevel@tonic-gate 
1818*7c478bd9Sstevel@tonic-gate 
1819*7c478bd9Sstevel@tonic-gate /*
1820*7c478bd9Sstevel@tonic-gate  * ehci_allocate_high_speed_bandwidth:
1821*7c478bd9Sstevel@tonic-gate  *
1822*7c478bd9Sstevel@tonic-gate  * Allocate high speed bandwidth for the low/full/high speed interrupt and
1823*7c478bd9Sstevel@tonic-gate  * isochronous endpoints.
1824*7c478bd9Sstevel@tonic-gate  */
1825*7c478bd9Sstevel@tonic-gate static int
1826*7c478bd9Sstevel@tonic-gate ehci_allocate_high_speed_bandwidth(
1827*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
1828*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
1829*7c478bd9Sstevel@tonic-gate 	uint_t			*pnode,
1830*7c478bd9Sstevel@tonic-gate 	uchar_t			*smask,
1831*7c478bd9Sstevel@tonic-gate 	uchar_t			*cmask)
1832*7c478bd9Sstevel@tonic-gate {
1833*7c478bd9Sstevel@tonic-gate 	uint_t			sbandwidth, cbandwidth;
1834*7c478bd9Sstevel@tonic-gate 	int			interval;
1835*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint = &ph->p_ep;
1836*7c478bd9Sstevel@tonic-gate 	usba_device_t		*child_ud;
1837*7c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status;
1838*7c478bd9Sstevel@tonic-gate 	int			error;
1839*7c478bd9Sstevel@tonic-gate 
1840*7c478bd9Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
1841*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1842*7c478bd9Sstevel@tonic-gate 
1843*7c478bd9Sstevel@tonic-gate 	/* Get child's usba device structure */
1844*7c478bd9Sstevel@tonic-gate 	child_ud = ph->p_usba_device;
1845*7c478bd9Sstevel@tonic-gate 
1846*7c478bd9Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
1847*7c478bd9Sstevel@tonic-gate 
1848*7c478bd9Sstevel@tonic-gate 	/* Get the current usb device's port status */
1849*7c478bd9Sstevel@tonic-gate 	port_status = ph->p_usba_device->usb_port_status;
1850*7c478bd9Sstevel@tonic-gate 
1851*7c478bd9Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
1852*7c478bd9Sstevel@tonic-gate 
1853*7c478bd9Sstevel@tonic-gate 	/*
1854*7c478bd9Sstevel@tonic-gate 	 * Calculate the length in bytes of a transaction on this
1855*7c478bd9Sstevel@tonic-gate 	 * periodic endpoint. Return failure if maximum packet is
1856*7c478bd9Sstevel@tonic-gate 	 * zero.
1857*7c478bd9Sstevel@tonic-gate 	 */
1858*7c478bd9Sstevel@tonic-gate 	error = ehci_compute_high_speed_bandwidth(ehcip, endpoint,
1859*7c478bd9Sstevel@tonic-gate 	    port_status, &sbandwidth, &cbandwidth);
1860*7c478bd9Sstevel@tonic-gate 	if (error != USB_SUCCESS) {
1861*7c478bd9Sstevel@tonic-gate 
1862*7c478bd9Sstevel@tonic-gate 		return (error);
1863*7c478bd9Sstevel@tonic-gate 	}
1864*7c478bd9Sstevel@tonic-gate 
1865*7c478bd9Sstevel@tonic-gate 	/*
1866*7c478bd9Sstevel@tonic-gate 	 * Adjust polling interval to be a power of 2.
1867*7c478bd9Sstevel@tonic-gate 	 * If this interval can't be supported, return
1868*7c478bd9Sstevel@tonic-gate 	 * allocation failure.
1869*7c478bd9Sstevel@tonic-gate 	 */
1870*7c478bd9Sstevel@tonic-gate 	interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
1871*7c478bd9Sstevel@tonic-gate 	if (interval == USB_FAILURE) {
1872*7c478bd9Sstevel@tonic-gate 
1873*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
1874*7c478bd9Sstevel@tonic-gate 	}
1875*7c478bd9Sstevel@tonic-gate 
1876*7c478bd9Sstevel@tonic-gate 	if (port_status == USBA_HIGH_SPEED_DEV) {
1877*7c478bd9Sstevel@tonic-gate 		/* Allocate bandwidth for high speed devices, except ITD */
1878*7c478bd9Sstevel@tonic-gate 		error = ehci_find_bestfit_hs_mask(ehcip, smask, pnode,
1879*7c478bd9Sstevel@tonic-gate 		    endpoint, sbandwidth, interval);
1880*7c478bd9Sstevel@tonic-gate 		*cmask = 0x00;
1881*7c478bd9Sstevel@tonic-gate 
1882*7c478bd9Sstevel@tonic-gate 	} else {
1883*7c478bd9Sstevel@tonic-gate 		if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) ==
1884*7c478bd9Sstevel@tonic-gate 		    USB_EP_ATTR_INTR) {
1885*7c478bd9Sstevel@tonic-gate 
1886*7c478bd9Sstevel@tonic-gate 			/* Allocate bandwidth for low speed interrupt */
1887*7c478bd9Sstevel@tonic-gate 			error = ehci_find_bestfit_ls_intr_mask(ehcip,
1888*7c478bd9Sstevel@tonic-gate 			    smask, cmask, pnode, sbandwidth, cbandwidth,
1889*7c478bd9Sstevel@tonic-gate 			    interval);
1890*7c478bd9Sstevel@tonic-gate 		} else {
1891*7c478bd9Sstevel@tonic-gate 			if ((endpoint->bEndpointAddress &
1892*7c478bd9Sstevel@tonic-gate 			    USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
1893*7c478bd9Sstevel@tonic-gate 
1894*7c478bd9Sstevel@tonic-gate 				/* Allocate bandwidth for sitd in */
1895*7c478bd9Sstevel@tonic-gate 				error = ehci_find_bestfit_sitd_in_mask(ehcip,
1896*7c478bd9Sstevel@tonic-gate 				    smask, cmask, pnode, sbandwidth, cbandwidth,
1897*7c478bd9Sstevel@tonic-gate 				    interval);
1898*7c478bd9Sstevel@tonic-gate 			} else {
1899*7c478bd9Sstevel@tonic-gate 
1900*7c478bd9Sstevel@tonic-gate 				/* Allocate bandwidth for sitd out */
1901*7c478bd9Sstevel@tonic-gate 				error = ehci_find_bestfit_sitd_out_mask(ehcip,
1902*7c478bd9Sstevel@tonic-gate 				    smask, pnode, sbandwidth, interval);
1903*7c478bd9Sstevel@tonic-gate 				*cmask = 0x00;
1904*7c478bd9Sstevel@tonic-gate 			}
1905*7c478bd9Sstevel@tonic-gate 		}
1906*7c478bd9Sstevel@tonic-gate 	}
1907*7c478bd9Sstevel@tonic-gate 
1908*7c478bd9Sstevel@tonic-gate 	if (error != USB_SUCCESS) {
1909*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
1910*7c478bd9Sstevel@tonic-gate 		    "ehci_allocate_high_speed_bandwidth: Reached maximum "
1911*7c478bd9Sstevel@tonic-gate 		    "bandwidth value and cannot allocate bandwidth for a "
1912*7c478bd9Sstevel@tonic-gate 		    "given high-speed periodic endpoint");
1913*7c478bd9Sstevel@tonic-gate 
1914*7c478bd9Sstevel@tonic-gate 		return (USB_NO_BANDWIDTH);
1915*7c478bd9Sstevel@tonic-gate 	}
1916*7c478bd9Sstevel@tonic-gate 
1917*7c478bd9Sstevel@tonic-gate 	return (error);
1918*7c478bd9Sstevel@tonic-gate }
1919*7c478bd9Sstevel@tonic-gate 
1920*7c478bd9Sstevel@tonic-gate 
1921*7c478bd9Sstevel@tonic-gate /*
1922*7c478bd9Sstevel@tonic-gate  * ehci_allocate_classic_tt_speed_bandwidth:
1923*7c478bd9Sstevel@tonic-gate  *
1924*7c478bd9Sstevel@tonic-gate  * Allocate classic TT bandwidth for the low/full speed interrupt and
1925*7c478bd9Sstevel@tonic-gate  * isochronous endpoints.
1926*7c478bd9Sstevel@tonic-gate  */
1927*7c478bd9Sstevel@tonic-gate static int
1928*7c478bd9Sstevel@tonic-gate ehci_allocate_classic_tt_bandwidth(
1929*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
1930*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
1931*7c478bd9Sstevel@tonic-gate 	uint_t			pnode)
1932*7c478bd9Sstevel@tonic-gate {
1933*7c478bd9Sstevel@tonic-gate 	uint_t			bandwidth, min;
1934*7c478bd9Sstevel@tonic-gate 	uint_t			height, leftmost, list;
1935*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint = &ph->p_ep;
1936*7c478bd9Sstevel@tonic-gate 	usba_device_t		*child_ud, *parent_ud;
1937*7c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status;
1938*7c478bd9Sstevel@tonic-gate 	int			i, interval;
1939*7c478bd9Sstevel@tonic-gate 
1940*7c478bd9Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
1941*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1942*7c478bd9Sstevel@tonic-gate 
1943*7c478bd9Sstevel@tonic-gate 	/* Get child's usba device structure */
1944*7c478bd9Sstevel@tonic-gate 	child_ud = ph->p_usba_device;
1945*7c478bd9Sstevel@tonic-gate 
1946*7c478bd9Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
1947*7c478bd9Sstevel@tonic-gate 
1948*7c478bd9Sstevel@tonic-gate 	/* Get the current usb device's port status */
1949*7c478bd9Sstevel@tonic-gate 	port_status = child_ud->usb_port_status;
1950*7c478bd9Sstevel@tonic-gate 
1951*7c478bd9Sstevel@tonic-gate 	/* Get the parent high speed hub's usba device structure */
1952*7c478bd9Sstevel@tonic-gate 	parent_ud = child_ud->usb_hs_hub_usba_dev;
1953*7c478bd9Sstevel@tonic-gate 
1954*7c478bd9Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
1955*7c478bd9Sstevel@tonic-gate 
1956*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
1957*7c478bd9Sstevel@tonic-gate 	    "ehci_allocate_classic_tt_bandwidth: "
1958*7c478bd9Sstevel@tonic-gate 	    "child_ud 0x%p parent_ud 0x%p", child_ud, parent_ud);
1959*7c478bd9Sstevel@tonic-gate 
1960*7c478bd9Sstevel@tonic-gate 	/*
1961*7c478bd9Sstevel@tonic-gate 	 * Calculate the length in bytes of a transaction on this
1962*7c478bd9Sstevel@tonic-gate 	 * periodic endpoint. Return failure if maximum packet is
1963*7c478bd9Sstevel@tonic-gate 	 * zero.
1964*7c478bd9Sstevel@tonic-gate 	 */
1965*7c478bd9Sstevel@tonic-gate 	if (ehci_compute_classic_bandwidth(endpoint,
1966*7c478bd9Sstevel@tonic-gate 	    port_status, &bandwidth) != USB_SUCCESS) {
1967*7c478bd9Sstevel@tonic-gate 
1968*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
1969*7c478bd9Sstevel@tonic-gate 		    "ehci_allocate_classic_tt_bandwidth: Periodic endpoint "
1970*7c478bd9Sstevel@tonic-gate 		    "with zero endpoint maximum packet size is not supported");
1971*7c478bd9Sstevel@tonic-gate 
1972*7c478bd9Sstevel@tonic-gate 		return (USB_NOT_SUPPORTED);
1973*7c478bd9Sstevel@tonic-gate 	}
1974*7c478bd9Sstevel@tonic-gate 
1975*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
1976*7c478bd9Sstevel@tonic-gate 	    "ehci_allocate_classic_tt_bandwidth: bandwidth %d", bandwidth);
1977*7c478bd9Sstevel@tonic-gate 
1978*7c478bd9Sstevel@tonic-gate 	mutex_enter(&parent_ud->usb_mutex);
1979*7c478bd9Sstevel@tonic-gate 
1980*7c478bd9Sstevel@tonic-gate 	/*
1981*7c478bd9Sstevel@tonic-gate 	 * If the length in bytes plus the allocated bandwidth exceeds
1982*7c478bd9Sstevel@tonic-gate 	 * the maximum, return bandwidth allocation failure.
1983*7c478bd9Sstevel@tonic-gate 	 */
1984*7c478bd9Sstevel@tonic-gate 	if ((parent_ud->usb_hs_hub_min_bandwidth + bandwidth) >
1985*7c478bd9Sstevel@tonic-gate 	    FS_PERIODIC_BANDWIDTH) {
1986*7c478bd9Sstevel@tonic-gate 
1987*7c478bd9Sstevel@tonic-gate 		mutex_exit(&parent_ud->usb_mutex);
1988*7c478bd9Sstevel@tonic-gate 
1989*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
1990*7c478bd9Sstevel@tonic-gate 		    "ehci_allocate_classic_tt_bandwidth: Reached maximum "
1991*7c478bd9Sstevel@tonic-gate 		    "bandwidth value and cannot allocate bandwidth for a "
1992*7c478bd9Sstevel@tonic-gate 		    "given low/full speed periodic endpoint");
1993*7c478bd9Sstevel@tonic-gate 
1994*7c478bd9Sstevel@tonic-gate 		return (USB_NO_BANDWIDTH);
1995*7c478bd9Sstevel@tonic-gate 	}
1996*7c478bd9Sstevel@tonic-gate 
1997*7c478bd9Sstevel@tonic-gate 	mutex_exit(&parent_ud->usb_mutex);
1998*7c478bd9Sstevel@tonic-gate 
1999*7c478bd9Sstevel@tonic-gate 	/* Adjust polling interval to be a power of 2 */
2000*7c478bd9Sstevel@tonic-gate 	interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
2001*7c478bd9Sstevel@tonic-gate 
2002*7c478bd9Sstevel@tonic-gate 	/* Find the height in the tree */
2003*7c478bd9Sstevel@tonic-gate 	height = ehci_lattice_height(interval);
2004*7c478bd9Sstevel@tonic-gate 
2005*7c478bd9Sstevel@tonic-gate 	/* Find the leftmost leaf in the subtree specified by the node. */
2006*7c478bd9Sstevel@tonic-gate 	leftmost = ehci_leftmost_leaf(pnode, height);
2007*7c478bd9Sstevel@tonic-gate 
2008*7c478bd9Sstevel@tonic-gate 	mutex_enter(&parent_ud->usb_mutex);
2009*7c478bd9Sstevel@tonic-gate 
2010*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) {
2011*7c478bd9Sstevel@tonic-gate 		list = ehci_index[leftmost + i];
2012*7c478bd9Sstevel@tonic-gate 
2013*7c478bd9Sstevel@tonic-gate 		if ((parent_ud->usb_hs_hub_bandwidth[list] +
2014*7c478bd9Sstevel@tonic-gate 		    bandwidth) > FS_PERIODIC_BANDWIDTH) {
2015*7c478bd9Sstevel@tonic-gate 
2016*7c478bd9Sstevel@tonic-gate 			mutex_exit(&parent_ud->usb_mutex);
2017*7c478bd9Sstevel@tonic-gate 
2018*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
2019*7c478bd9Sstevel@tonic-gate 			    "ehci_allocate_classic_tt_bandwidth: Reached "
2020*7c478bd9Sstevel@tonic-gate 			    "maximum bandwidth value and cannot allocate "
2021*7c478bd9Sstevel@tonic-gate 			    "bandwidth for low/full periodic endpoint");
2022*7c478bd9Sstevel@tonic-gate 
2023*7c478bd9Sstevel@tonic-gate 			return (USB_NO_BANDWIDTH);
2024*7c478bd9Sstevel@tonic-gate 		}
2025*7c478bd9Sstevel@tonic-gate 	}
2026*7c478bd9Sstevel@tonic-gate 
2027*7c478bd9Sstevel@tonic-gate 	/*
2028*7c478bd9Sstevel@tonic-gate 	 * All the leaves for this node must be updated with the bandwidth.
2029*7c478bd9Sstevel@tonic-gate 	 */
2030*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) {
2031*7c478bd9Sstevel@tonic-gate 		list = ehci_index[leftmost + i];
2032*7c478bd9Sstevel@tonic-gate 		parent_ud->usb_hs_hub_bandwidth[list] += bandwidth;
2033*7c478bd9Sstevel@tonic-gate 	}
2034*7c478bd9Sstevel@tonic-gate 
2035*7c478bd9Sstevel@tonic-gate 	/* Find the leaf with the smallest allocated bandwidth */
2036*7c478bd9Sstevel@tonic-gate 	min = parent_ud->usb_hs_hub_bandwidth[0];
2037*7c478bd9Sstevel@tonic-gate 
2038*7c478bd9Sstevel@tonic-gate 	for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) {
2039*7c478bd9Sstevel@tonic-gate 		if (parent_ud->usb_hs_hub_bandwidth[i] < min) {
2040*7c478bd9Sstevel@tonic-gate 			min = parent_ud->usb_hs_hub_bandwidth[i];
2041*7c478bd9Sstevel@tonic-gate 		}
2042*7c478bd9Sstevel@tonic-gate 	}
2043*7c478bd9Sstevel@tonic-gate 
2044*7c478bd9Sstevel@tonic-gate 	/* Save the minimum for later use */
2045*7c478bd9Sstevel@tonic-gate 	parent_ud->usb_hs_hub_min_bandwidth = min;
2046*7c478bd9Sstevel@tonic-gate 
2047*7c478bd9Sstevel@tonic-gate 	mutex_exit(&parent_ud->usb_mutex);
2048*7c478bd9Sstevel@tonic-gate 
2049*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
2050*7c478bd9Sstevel@tonic-gate }
2051*7c478bd9Sstevel@tonic-gate 
2052*7c478bd9Sstevel@tonic-gate 
2053*7c478bd9Sstevel@tonic-gate /*
2054*7c478bd9Sstevel@tonic-gate  * ehci_deallocate_bandwidth:
2055*7c478bd9Sstevel@tonic-gate  *
2056*7c478bd9Sstevel@tonic-gate  * Deallocate bandwidth for the given node in the lattice and the length
2057*7c478bd9Sstevel@tonic-gate  * of transfer.
2058*7c478bd9Sstevel@tonic-gate  */
2059*7c478bd9Sstevel@tonic-gate void
2060*7c478bd9Sstevel@tonic-gate ehci_deallocate_bandwidth(
2061*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
2062*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
2063*7c478bd9Sstevel@tonic-gate 	uint_t			pnode,
2064*7c478bd9Sstevel@tonic-gate 	uchar_t			smask,
2065*7c478bd9Sstevel@tonic-gate 	uchar_t			cmask)
2066*7c478bd9Sstevel@tonic-gate {
2067*7c478bd9Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
2068*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
2069*7c478bd9Sstevel@tonic-gate 
2070*7c478bd9Sstevel@tonic-gate 	ehci_deallocate_high_speed_bandwidth(ehcip, ph, pnode, smask, cmask);
2071*7c478bd9Sstevel@tonic-gate 
2072*7c478bd9Sstevel@tonic-gate 	/*
2073*7c478bd9Sstevel@tonic-gate 	 * For low/full speed usb devices, deallocate classic TT bandwidth
2074*7c478bd9Sstevel@tonic-gate 	 * in additional to high speed bandwidth.
2075*7c478bd9Sstevel@tonic-gate 	 */
2076*7c478bd9Sstevel@tonic-gate 	if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) {
2077*7c478bd9Sstevel@tonic-gate 
2078*7c478bd9Sstevel@tonic-gate 		/* Deallocate classic TT bandwidth */
2079*7c478bd9Sstevel@tonic-gate 		ehci_deallocate_classic_tt_bandwidth(ehcip, ph, pnode);
2080*7c478bd9Sstevel@tonic-gate 	}
2081*7c478bd9Sstevel@tonic-gate }
2082*7c478bd9Sstevel@tonic-gate 
2083*7c478bd9Sstevel@tonic-gate 
2084*7c478bd9Sstevel@tonic-gate /*
2085*7c478bd9Sstevel@tonic-gate  * ehci_deallocate_high_speed_bandwidth:
2086*7c478bd9Sstevel@tonic-gate  *
2087*7c478bd9Sstevel@tonic-gate  * Deallocate high speed bandwidth of a interrupt or isochronous endpoint.
2088*7c478bd9Sstevel@tonic-gate  */
2089*7c478bd9Sstevel@tonic-gate static void
2090*7c478bd9Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth(
2091*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
2092*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
2093*7c478bd9Sstevel@tonic-gate 	uint_t			pnode,
2094*7c478bd9Sstevel@tonic-gate 	uchar_t			smask,
2095*7c478bd9Sstevel@tonic-gate 	uchar_t			cmask)
2096*7c478bd9Sstevel@tonic-gate {
2097*7c478bd9Sstevel@tonic-gate 	uint_t			height, leftmost;
2098*7c478bd9Sstevel@tonic-gate 	uint_t			list_count;
2099*7c478bd9Sstevel@tonic-gate 	uint_t			sbandwidth, cbandwidth;
2100*7c478bd9Sstevel@tonic-gate 	int			interval;
2101*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint = &ph->p_ep;
2102*7c478bd9Sstevel@tonic-gate 	usba_device_t		*child_ud;
2103*7c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status;
2104*7c478bd9Sstevel@tonic-gate 
2105*7c478bd9Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
2106*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
2107*7c478bd9Sstevel@tonic-gate 
2108*7c478bd9Sstevel@tonic-gate 	/* Get child's usba device structure */
2109*7c478bd9Sstevel@tonic-gate 	child_ud = ph->p_usba_device;
2110*7c478bd9Sstevel@tonic-gate 
2111*7c478bd9Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
2112*7c478bd9Sstevel@tonic-gate 
2113*7c478bd9Sstevel@tonic-gate 	/* Get the current usb device's port status */
2114*7c478bd9Sstevel@tonic-gate 	port_status = ph->p_usba_device->usb_port_status;
2115*7c478bd9Sstevel@tonic-gate 
2116*7c478bd9Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
2117*7c478bd9Sstevel@tonic-gate 
2118*7c478bd9Sstevel@tonic-gate 	(void) ehci_compute_high_speed_bandwidth(ehcip, endpoint,
2119*7c478bd9Sstevel@tonic-gate 	    port_status, &sbandwidth, &cbandwidth);
2120*7c478bd9Sstevel@tonic-gate 
2121*7c478bd9Sstevel@tonic-gate 	/* Adjust polling interval to be a power of 2 */
2122*7c478bd9Sstevel@tonic-gate 	interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
2123*7c478bd9Sstevel@tonic-gate 
2124*7c478bd9Sstevel@tonic-gate 	/* Find the height in the tree */
2125*7c478bd9Sstevel@tonic-gate 	height = ehci_lattice_height(interval);
2126*7c478bd9Sstevel@tonic-gate 
2127*7c478bd9Sstevel@tonic-gate 	/*
2128*7c478bd9Sstevel@tonic-gate 	 * Find the leftmost leaf in the subtree specified by the node
2129*7c478bd9Sstevel@tonic-gate 	 */
2130*7c478bd9Sstevel@tonic-gate 	leftmost = ehci_leftmost_leaf(pnode, height);
2131*7c478bd9Sstevel@tonic-gate 
2132*7c478bd9Sstevel@tonic-gate 	list_count = EHCI_NUM_INTR_QH_LISTS/interval;
2133*7c478bd9Sstevel@tonic-gate 
2134*7c478bd9Sstevel@tonic-gate 	/* Delete the bandwidth from the appropriate lists */
2135*7c478bd9Sstevel@tonic-gate 	if (port_status == USBA_HIGH_SPEED_DEV) {
2136*7c478bd9Sstevel@tonic-gate 
2137*7c478bd9Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, -sbandwidth,
2138*7c478bd9Sstevel@tonic-gate 		    leftmost, list_count, smask);
2139*7c478bd9Sstevel@tonic-gate 	} else {
2140*7c478bd9Sstevel@tonic-gate 		if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) ==
2141*7c478bd9Sstevel@tonic-gate 		    USB_EP_ATTR_INTR) {
2142*7c478bd9Sstevel@tonic-gate 
2143*7c478bd9Sstevel@tonic-gate 			ehci_update_bw_availability(ehcip, -sbandwidth,
2144*7c478bd9Sstevel@tonic-gate 			    leftmost, list_count, smask);
2145*7c478bd9Sstevel@tonic-gate 			ehci_update_bw_availability(ehcip, -cbandwidth,
2146*7c478bd9Sstevel@tonic-gate 			    leftmost, list_count, cmask);
2147*7c478bd9Sstevel@tonic-gate 		} else {
2148*7c478bd9Sstevel@tonic-gate 			if ((endpoint->bEndpointAddress &
2149*7c478bd9Sstevel@tonic-gate 			    USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
2150*7c478bd9Sstevel@tonic-gate 
2151*7c478bd9Sstevel@tonic-gate 				ehci_update_bw_availability(ehcip, -sbandwidth,
2152*7c478bd9Sstevel@tonic-gate 				    leftmost, list_count, smask);
2153*7c478bd9Sstevel@tonic-gate 				ehci_update_bw_availability(ehcip,
2154*7c478bd9Sstevel@tonic-gate 				    -MAX_UFRAME_SITD_XFER, leftmost,
2155*7c478bd9Sstevel@tonic-gate 				    list_count, cmask);
2156*7c478bd9Sstevel@tonic-gate 			} else {
2157*7c478bd9Sstevel@tonic-gate 
2158*7c478bd9Sstevel@tonic-gate 				ehci_update_bw_availability(ehcip,
2159*7c478bd9Sstevel@tonic-gate 				    -MAX_UFRAME_SITD_XFER, leftmost,
2160*7c478bd9Sstevel@tonic-gate 				    list_count, smask);
2161*7c478bd9Sstevel@tonic-gate 			}
2162*7c478bd9Sstevel@tonic-gate 		}
2163*7c478bd9Sstevel@tonic-gate 	}
2164*7c478bd9Sstevel@tonic-gate }
2165*7c478bd9Sstevel@tonic-gate 
2166*7c478bd9Sstevel@tonic-gate /*
2167*7c478bd9Sstevel@tonic-gate  * ehci_deallocate_classic_tt_bandwidth:
2168*7c478bd9Sstevel@tonic-gate  *
2169*7c478bd9Sstevel@tonic-gate  * Deallocate high speed bandwidth of a interrupt or isochronous endpoint.
2170*7c478bd9Sstevel@tonic-gate  */
2171*7c478bd9Sstevel@tonic-gate static void
2172*7c478bd9Sstevel@tonic-gate ehci_deallocate_classic_tt_bandwidth(
2173*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
2174*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
2175*7c478bd9Sstevel@tonic-gate 	uint_t			pnode)
2176*7c478bd9Sstevel@tonic-gate {
2177*7c478bd9Sstevel@tonic-gate 	uint_t			bandwidth, height, leftmost, list, min;
2178*7c478bd9Sstevel@tonic-gate 	int			i, interval;
2179*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint = &ph->p_ep;
2180*7c478bd9Sstevel@tonic-gate 	usba_device_t		*child_ud, *parent_ud;
2181*7c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status;
2182*7c478bd9Sstevel@tonic-gate 
2183*7c478bd9Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
2184*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
2185*7c478bd9Sstevel@tonic-gate 
2186*7c478bd9Sstevel@tonic-gate 	/* Get child's usba device structure */
2187*7c478bd9Sstevel@tonic-gate 	child_ud = ph->p_usba_device;
2188*7c478bd9Sstevel@tonic-gate 
2189*7c478bd9Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
2190*7c478bd9Sstevel@tonic-gate 
2191*7c478bd9Sstevel@tonic-gate 	/* Get the current usb device's port status */
2192*7c478bd9Sstevel@tonic-gate 	port_status = child_ud->usb_port_status;
2193*7c478bd9Sstevel@tonic-gate 
2194*7c478bd9Sstevel@tonic-gate 	/* Get the parent high speed hub's usba device structure */
2195*7c478bd9Sstevel@tonic-gate 	parent_ud = child_ud->usb_hs_hub_usba_dev;
2196*7c478bd9Sstevel@tonic-gate 
2197*7c478bd9Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
2198*7c478bd9Sstevel@tonic-gate 
2199*7c478bd9Sstevel@tonic-gate 	/* Obtain the bandwidth */
2200*7c478bd9Sstevel@tonic-gate 	(void) ehci_compute_classic_bandwidth(endpoint,
2201*7c478bd9Sstevel@tonic-gate 	    port_status, &bandwidth);
2202*7c478bd9Sstevel@tonic-gate 
2203*7c478bd9Sstevel@tonic-gate 	/* Adjust polling interval to be a power of 2 */
2204*7c478bd9Sstevel@tonic-gate 	interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
2205*7c478bd9Sstevel@tonic-gate 
2206*7c478bd9Sstevel@tonic-gate 	/* Find the height in the tree */
2207*7c478bd9Sstevel@tonic-gate 	height = ehci_lattice_height(interval);
2208*7c478bd9Sstevel@tonic-gate 
2209*7c478bd9Sstevel@tonic-gate 	/* Find the leftmost leaf in the subtree specified by the node */
2210*7c478bd9Sstevel@tonic-gate 	leftmost = ehci_leftmost_leaf(pnode, height);
2211*7c478bd9Sstevel@tonic-gate 
2212*7c478bd9Sstevel@tonic-gate 	mutex_enter(&parent_ud->usb_mutex);
2213*7c478bd9Sstevel@tonic-gate 
2214*7c478bd9Sstevel@tonic-gate 	/* Delete the bandwidth from the appropriate lists */
2215*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) {
2216*7c478bd9Sstevel@tonic-gate 		list = ehci_index[leftmost + i];
2217*7c478bd9Sstevel@tonic-gate 		parent_ud->usb_hs_hub_bandwidth[list] -= bandwidth;
2218*7c478bd9Sstevel@tonic-gate 	}
2219*7c478bd9Sstevel@tonic-gate 
2220*7c478bd9Sstevel@tonic-gate 	/* Find the leaf with the smallest allocated bandwidth */
2221*7c478bd9Sstevel@tonic-gate 	min = parent_ud->usb_hs_hub_bandwidth[0];
2222*7c478bd9Sstevel@tonic-gate 
2223*7c478bd9Sstevel@tonic-gate 	for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) {
2224*7c478bd9Sstevel@tonic-gate 		if (parent_ud->usb_hs_hub_bandwidth[i] < min) {
2225*7c478bd9Sstevel@tonic-gate 			min = parent_ud->usb_hs_hub_bandwidth[i];
2226*7c478bd9Sstevel@tonic-gate 		}
2227*7c478bd9Sstevel@tonic-gate 	}
2228*7c478bd9Sstevel@tonic-gate 
2229*7c478bd9Sstevel@tonic-gate 	/* Save the minimum for later use */
2230*7c478bd9Sstevel@tonic-gate 	parent_ud->usb_hs_hub_min_bandwidth = min;
2231*7c478bd9Sstevel@tonic-gate 
2232*7c478bd9Sstevel@tonic-gate 	mutex_exit(&parent_ud->usb_mutex);
2233*7c478bd9Sstevel@tonic-gate }
2234*7c478bd9Sstevel@tonic-gate 
2235*7c478bd9Sstevel@tonic-gate 
2236*7c478bd9Sstevel@tonic-gate /*
2237*7c478bd9Sstevel@tonic-gate  * ehci_compute_high_speed_bandwidth:
2238*7c478bd9Sstevel@tonic-gate  *
2239*7c478bd9Sstevel@tonic-gate  * Given a periodic endpoint (interrupt or isochronous) determine the total
2240*7c478bd9Sstevel@tonic-gate  * bandwidth for one transaction. The EHCI host controller traverses the
2241*7c478bd9Sstevel@tonic-gate  * endpoint descriptor lists on a first-come-first-serve basis. When the HC
2242*7c478bd9Sstevel@tonic-gate  * services an endpoint, only a single transaction attempt is made. The  HC
2243*7c478bd9Sstevel@tonic-gate  * moves to the next Endpoint Descriptor after the first transaction attempt
2244*7c478bd9Sstevel@tonic-gate  * rather than finishing the entire Transfer Descriptor. Therefore, when  a
2245*7c478bd9Sstevel@tonic-gate  * Transfer Descriptor is inserted into the lattice, we will only count the
2246*7c478bd9Sstevel@tonic-gate  * number of bytes for one transaction.
2247*7c478bd9Sstevel@tonic-gate  *
2248*7c478bd9Sstevel@tonic-gate  * The following are the formulas used for  calculating bandwidth in  terms
2249*7c478bd9Sstevel@tonic-gate  * bytes and it is for the single USB high speed transaction.  The protocol
2250*7c478bd9Sstevel@tonic-gate  * overheads will be different for each of type of USB transfer & all these
2251*7c478bd9Sstevel@tonic-gate  * formulas & protocol overheads are derived from the 5.11.3 section of the
2252*7c478bd9Sstevel@tonic-gate  * USB 2.0 Specification.
2253*7c478bd9Sstevel@tonic-gate  *
2254*7c478bd9Sstevel@tonic-gate  * High-Speed:
2255*7c478bd9Sstevel@tonic-gate  *		Protocol overhead + ((MaxPktSz * 7)/6) + Host_Delay
2256*7c478bd9Sstevel@tonic-gate  *
2257*7c478bd9Sstevel@tonic-gate  * Split Transaction: (Low/Full speed devices connected behind usb2.0 hub)
2258*7c478bd9Sstevel@tonic-gate  *
2259*7c478bd9Sstevel@tonic-gate  *		Protocol overhead + Split transaction overhead +
2260*7c478bd9Sstevel@tonic-gate  *			((MaxPktSz * 7)/6) + Host_Delay;
2261*7c478bd9Sstevel@tonic-gate  */
2262*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
2263*7c478bd9Sstevel@tonic-gate static int
2264*7c478bd9Sstevel@tonic-gate ehci_compute_high_speed_bandwidth(
2265*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
2266*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint,
2267*7c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status,
2268*7c478bd9Sstevel@tonic-gate 	uint_t			*sbandwidth,
2269*7c478bd9Sstevel@tonic-gate 	uint_t			*cbandwidth)
2270*7c478bd9Sstevel@tonic-gate {
2271*7c478bd9Sstevel@tonic-gate 	ushort_t		maxpacketsize = endpoint->wMaxPacketSize;
2272*7c478bd9Sstevel@tonic-gate 
2273*7c478bd9Sstevel@tonic-gate 	/* Return failure if endpoint maximum packet is zero */
2274*7c478bd9Sstevel@tonic-gate 	if (maxpacketsize == 0) {
2275*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
2276*7c478bd9Sstevel@tonic-gate 		    "ehci_allocate_high_speed_bandwidth: Periodic endpoint "
2277*7c478bd9Sstevel@tonic-gate 		    "with zero endpoint maximum packet size is not supported");
2278*7c478bd9Sstevel@tonic-gate 
2279*7c478bd9Sstevel@tonic-gate 		return (USB_NOT_SUPPORTED);
2280*7c478bd9Sstevel@tonic-gate 	}
2281*7c478bd9Sstevel@tonic-gate 
2282*7c478bd9Sstevel@tonic-gate 	/* Add bit-stuffing overhead */
2283*7c478bd9Sstevel@tonic-gate 	maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6);
2284*7c478bd9Sstevel@tonic-gate 
2285*7c478bd9Sstevel@tonic-gate 	/* Add Host Controller specific delay to required bandwidth */
2286*7c478bd9Sstevel@tonic-gate 	*sbandwidth = EHCI_HOST_CONTROLLER_DELAY;
2287*7c478bd9Sstevel@tonic-gate 
2288*7c478bd9Sstevel@tonic-gate 	/* Add xfer specific protocol overheads */
2289*7c478bd9Sstevel@tonic-gate 	if ((endpoint->bmAttributes &
2290*7c478bd9Sstevel@tonic-gate 	    USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) {
2291*7c478bd9Sstevel@tonic-gate 		/* High speed interrupt transaction */
2292*7c478bd9Sstevel@tonic-gate 		*sbandwidth += HS_NON_ISOC_PROTO_OVERHEAD;
2293*7c478bd9Sstevel@tonic-gate 	} else {
2294*7c478bd9Sstevel@tonic-gate 		/* Isochronous transaction */
2295*7c478bd9Sstevel@tonic-gate 		*sbandwidth += HS_ISOC_PROTO_OVERHEAD;
2296*7c478bd9Sstevel@tonic-gate 	}
2297*7c478bd9Sstevel@tonic-gate 
2298*7c478bd9Sstevel@tonic-gate 	/*
2299*7c478bd9Sstevel@tonic-gate 	 * For low/full speed devices, add split transaction specific
2300*7c478bd9Sstevel@tonic-gate 	 * overheads.
2301*7c478bd9Sstevel@tonic-gate 	 */
2302*7c478bd9Sstevel@tonic-gate 	if (port_status != USBA_HIGH_SPEED_DEV) {
2303*7c478bd9Sstevel@tonic-gate 		/*
2304*7c478bd9Sstevel@tonic-gate 		 * Add start and complete split transaction
2305*7c478bd9Sstevel@tonic-gate 		 * tokens overheads.
2306*7c478bd9Sstevel@tonic-gate 		 */
2307*7c478bd9Sstevel@tonic-gate 		*cbandwidth = *sbandwidth + COMPLETE_SPLIT_OVERHEAD;
2308*7c478bd9Sstevel@tonic-gate 		*sbandwidth += START_SPLIT_OVERHEAD;
2309*7c478bd9Sstevel@tonic-gate 
2310*7c478bd9Sstevel@tonic-gate 		/* Add data overhead depending on data direction */
2311*7c478bd9Sstevel@tonic-gate 		if ((endpoint->bEndpointAddress &
2312*7c478bd9Sstevel@tonic-gate 		    USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
2313*7c478bd9Sstevel@tonic-gate 			*cbandwidth += maxpacketsize;
2314*7c478bd9Sstevel@tonic-gate 		} else {
2315*7c478bd9Sstevel@tonic-gate 			if ((endpoint->bmAttributes &
2316*7c478bd9Sstevel@tonic-gate 			    USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) {
2317*7c478bd9Sstevel@tonic-gate 				/* There is no compete splits for out */
2318*7c478bd9Sstevel@tonic-gate 				*cbandwidth = 0;
2319*7c478bd9Sstevel@tonic-gate 			}
2320*7c478bd9Sstevel@tonic-gate 			*sbandwidth += maxpacketsize;
2321*7c478bd9Sstevel@tonic-gate 		}
2322*7c478bd9Sstevel@tonic-gate 	} else {
2323*7c478bd9Sstevel@tonic-gate 		uint_t		xactions;
2324*7c478bd9Sstevel@tonic-gate 
2325*7c478bd9Sstevel@tonic-gate 		/* Get the max transactions per microframe */
2326*7c478bd9Sstevel@tonic-gate 		xactions = ((maxpacketsize & USB_EP_MAX_XACTS_MASK) >>
2327*7c478bd9Sstevel@tonic-gate 		    USB_EP_MAX_XACTS_SHIFT) + 1;
2328*7c478bd9Sstevel@tonic-gate 
2329*7c478bd9Sstevel@tonic-gate 		/* High speed transaction */
2330*7c478bd9Sstevel@tonic-gate 		*sbandwidth += maxpacketsize;
2331*7c478bd9Sstevel@tonic-gate 
2332*7c478bd9Sstevel@tonic-gate 		/* Calculate bandwidth per micro-frame */
2333*7c478bd9Sstevel@tonic-gate 		*sbandwidth *= xactions;
2334*7c478bd9Sstevel@tonic-gate 
2335*7c478bd9Sstevel@tonic-gate 		*cbandwidth = 0;
2336*7c478bd9Sstevel@tonic-gate 	}
2337*7c478bd9Sstevel@tonic-gate 
2338*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
2339*7c478bd9Sstevel@tonic-gate 	    "ehci_allocate_high_speed_bandwidth: "
2340*7c478bd9Sstevel@tonic-gate 	    "Start split bandwidth %d Complete split bandwidth %d",
2341*7c478bd9Sstevel@tonic-gate 	    *sbandwidth, *cbandwidth);
2342*7c478bd9Sstevel@tonic-gate 
2343*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
2344*7c478bd9Sstevel@tonic-gate }
2345*7c478bd9Sstevel@tonic-gate 
2346*7c478bd9Sstevel@tonic-gate 
2347*7c478bd9Sstevel@tonic-gate /*
2348*7c478bd9Sstevel@tonic-gate  * ehci_compute_classic_bandwidth:
2349*7c478bd9Sstevel@tonic-gate  *
2350*7c478bd9Sstevel@tonic-gate  * Given a periodic endpoint (interrupt or isochronous) determine the total
2351*7c478bd9Sstevel@tonic-gate  * bandwidth for one transaction. The EHCI host controller traverses the
2352*7c478bd9Sstevel@tonic-gate  * endpoint descriptor lists on a first-come-first-serve basis. When the HC
2353*7c478bd9Sstevel@tonic-gate  * services an endpoint, only a single transaction attempt is made. The  HC
2354*7c478bd9Sstevel@tonic-gate  * moves to the next Endpoint Descriptor after the first transaction attempt
2355*7c478bd9Sstevel@tonic-gate  * rather than finishing the entire Transfer Descriptor. Therefore, when  a
2356*7c478bd9Sstevel@tonic-gate  * Transfer Descriptor is inserted into the lattice, we will only count the
2357*7c478bd9Sstevel@tonic-gate  * number of bytes for one transaction.
2358*7c478bd9Sstevel@tonic-gate  *
2359*7c478bd9Sstevel@tonic-gate  * The following are the formulas used for  calculating bandwidth in  terms
2360*7c478bd9Sstevel@tonic-gate  * bytes and it is for the single USB high speed transaction.  The protocol
2361*7c478bd9Sstevel@tonic-gate  * overheads will be different for each of type of USB transfer & all these
2362*7c478bd9Sstevel@tonic-gate  * formulas & protocol overheads are derived from the 5.11.3 section of the
2363*7c478bd9Sstevel@tonic-gate  * USB 2.0 Specification.
2364*7c478bd9Sstevel@tonic-gate  *
2365*7c478bd9Sstevel@tonic-gate  * Low-Speed:
2366*7c478bd9Sstevel@tonic-gate  *		Protocol overhead + Hub LS overhead +
2367*7c478bd9Sstevel@tonic-gate  *		(Low Speed clock * ((MaxPktSz * 7)/6)) + TT_Delay
2368*7c478bd9Sstevel@tonic-gate  *
2369*7c478bd9Sstevel@tonic-gate  * Full-Speed:
2370*7c478bd9Sstevel@tonic-gate  *		Protocol overhead + ((MaxPktSz * 7)/6) + TT_Delay
2371*7c478bd9Sstevel@tonic-gate  */
2372*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
2373*7c478bd9Sstevel@tonic-gate static int
2374*7c478bd9Sstevel@tonic-gate ehci_compute_classic_bandwidth(
2375*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint,
2376*7c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status,
2377*7c478bd9Sstevel@tonic-gate 	uint_t			*bandwidth)
2378*7c478bd9Sstevel@tonic-gate {
2379*7c478bd9Sstevel@tonic-gate 	ushort_t		maxpacketsize = endpoint->wMaxPacketSize;
2380*7c478bd9Sstevel@tonic-gate 
2381*7c478bd9Sstevel@tonic-gate 	/*
2382*7c478bd9Sstevel@tonic-gate 	 * If endpoint maximum packet is zero, then return immediately.
2383*7c478bd9Sstevel@tonic-gate 	 */
2384*7c478bd9Sstevel@tonic-gate 	if (maxpacketsize == 0) {
2385*7c478bd9Sstevel@tonic-gate 
2386*7c478bd9Sstevel@tonic-gate 		return (USB_NOT_SUPPORTED);
2387*7c478bd9Sstevel@tonic-gate 	}
2388*7c478bd9Sstevel@tonic-gate 
2389*7c478bd9Sstevel@tonic-gate 	/* Add TT delay to required bandwidth */
2390*7c478bd9Sstevel@tonic-gate 	*bandwidth = TT_DELAY;
2391*7c478bd9Sstevel@tonic-gate 
2392*7c478bd9Sstevel@tonic-gate 	/* Add bit-stuffing overhead */
2393*7c478bd9Sstevel@tonic-gate 	maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6);
2394*7c478bd9Sstevel@tonic-gate 
2395*7c478bd9Sstevel@tonic-gate 	switch (port_status) {
2396*7c478bd9Sstevel@tonic-gate 	case USBA_LOW_SPEED_DEV:
2397*7c478bd9Sstevel@tonic-gate 		/* Low speed interrupt transaction */
2398*7c478bd9Sstevel@tonic-gate 		*bandwidth += (LOW_SPEED_PROTO_OVERHEAD +
2399*7c478bd9Sstevel@tonic-gate 		    HUB_LOW_SPEED_PROTO_OVERHEAD +
2400*7c478bd9Sstevel@tonic-gate 		    (LOW_SPEED_CLOCK * maxpacketsize));
2401*7c478bd9Sstevel@tonic-gate 		break;
2402*7c478bd9Sstevel@tonic-gate 	case USBA_FULL_SPEED_DEV:
2403*7c478bd9Sstevel@tonic-gate 		/* Full speed transaction */
2404*7c478bd9Sstevel@tonic-gate 		*bandwidth += maxpacketsize;
2405*7c478bd9Sstevel@tonic-gate 
2406*7c478bd9Sstevel@tonic-gate 		/* Add xfer specific protocol overheads */
2407*7c478bd9Sstevel@tonic-gate 		if ((endpoint->bmAttributes &
2408*7c478bd9Sstevel@tonic-gate 		    USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) {
2409*7c478bd9Sstevel@tonic-gate 			/* Full speed interrupt transaction */
2410*7c478bd9Sstevel@tonic-gate 			*bandwidth += FS_NON_ISOC_PROTO_OVERHEAD;
2411*7c478bd9Sstevel@tonic-gate 		} else {
2412*7c478bd9Sstevel@tonic-gate 			/* Isochronous and input transaction */
2413*7c478bd9Sstevel@tonic-gate 			if ((endpoint->bEndpointAddress &
2414*7c478bd9Sstevel@tonic-gate 			    USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
2415*7c478bd9Sstevel@tonic-gate 				*bandwidth += FS_ISOC_INPUT_PROTO_OVERHEAD;
2416*7c478bd9Sstevel@tonic-gate 			} else {
2417*7c478bd9Sstevel@tonic-gate 				/* Isochronous and output transaction */
2418*7c478bd9Sstevel@tonic-gate 				*bandwidth += FS_ISOC_OUTPUT_PROTO_OVERHEAD;
2419*7c478bd9Sstevel@tonic-gate 			}
2420*7c478bd9Sstevel@tonic-gate 		}
2421*7c478bd9Sstevel@tonic-gate 		break;
2422*7c478bd9Sstevel@tonic-gate 	}
2423*7c478bd9Sstevel@tonic-gate 
2424*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
2425*7c478bd9Sstevel@tonic-gate }
2426*7c478bd9Sstevel@tonic-gate 
2427*7c478bd9Sstevel@tonic-gate 
2428*7c478bd9Sstevel@tonic-gate /*
2429*7c478bd9Sstevel@tonic-gate  * ehci_adjust_polling_interval:
2430*7c478bd9Sstevel@tonic-gate  *
2431*7c478bd9Sstevel@tonic-gate  * Adjust bandwidth according usb device speed.
2432*7c478bd9Sstevel@tonic-gate  */
2433*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
2434*7c478bd9Sstevel@tonic-gate int
2435*7c478bd9Sstevel@tonic-gate ehci_adjust_polling_interval(
2436*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
2437*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint,
2438*7c478bd9Sstevel@tonic-gate 	usb_port_status_t	port_status)
2439*7c478bd9Sstevel@tonic-gate {
2440*7c478bd9Sstevel@tonic-gate 	uint_t			interval;
2441*7c478bd9Sstevel@tonic-gate 	int			i = 0;
2442*7c478bd9Sstevel@tonic-gate 
2443*7c478bd9Sstevel@tonic-gate 	/* Get the polling interval */
2444*7c478bd9Sstevel@tonic-gate 	interval = endpoint->bInterval;
2445*7c478bd9Sstevel@tonic-gate 
2446*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
2447*7c478bd9Sstevel@tonic-gate 	    "ehci_adjust_polling_interval: Polling interval 0x%x", interval);
2448*7c478bd9Sstevel@tonic-gate 
2449*7c478bd9Sstevel@tonic-gate 	/*
2450*7c478bd9Sstevel@tonic-gate 	 * According USB 2.0 Specifications, a high-speed endpoint's
2451*7c478bd9Sstevel@tonic-gate 	 * polling intervals are specified interms of 125us or micro
2452*7c478bd9Sstevel@tonic-gate 	 * frame, where as full/low endpoint's polling intervals are
2453*7c478bd9Sstevel@tonic-gate 	 * specified in milliseconds.
2454*7c478bd9Sstevel@tonic-gate 	 *
2455*7c478bd9Sstevel@tonic-gate 	 * A high speed interrupt/isochronous endpoints can specify
2456*7c478bd9Sstevel@tonic-gate 	 * desired polling interval between 1 to 16 micro-frames,
2457*7c478bd9Sstevel@tonic-gate 	 * where as full/low endpoints can specify between 1 to 255
2458*7c478bd9Sstevel@tonic-gate 	 * milliseconds.
2459*7c478bd9Sstevel@tonic-gate 	 */
2460*7c478bd9Sstevel@tonic-gate 	switch (port_status) {
2461*7c478bd9Sstevel@tonic-gate 	case USBA_LOW_SPEED_DEV:
2462*7c478bd9Sstevel@tonic-gate 		/*
2463*7c478bd9Sstevel@tonic-gate 		 * Low speed  endpoints are limited to	specifying
2464*7c478bd9Sstevel@tonic-gate 		 * only 8ms to 255ms in this driver. If a device
2465*7c478bd9Sstevel@tonic-gate 		 * reports a polling interval that is less than 8ms,
2466*7c478bd9Sstevel@tonic-gate 		 * it will use 8 ms instead.
2467*7c478bd9Sstevel@tonic-gate 		 */
2468*7c478bd9Sstevel@tonic-gate 		if (interval < LS_MIN_POLL_INTERVAL) {
2469*7c478bd9Sstevel@tonic-gate 
2470*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
2471*7c478bd9Sstevel@tonic-gate 			    "Low speed endpoint's poll interval of %d ms "
2472*7c478bd9Sstevel@tonic-gate 			    "is below threshold. Rounding up to %d ms",
2473*7c478bd9Sstevel@tonic-gate 			    interval, LS_MIN_POLL_INTERVAL);
2474*7c478bd9Sstevel@tonic-gate 
2475*7c478bd9Sstevel@tonic-gate 			interval = LS_MIN_POLL_INTERVAL;
2476*7c478bd9Sstevel@tonic-gate 		}
2477*7c478bd9Sstevel@tonic-gate 
2478*7c478bd9Sstevel@tonic-gate 		/*
2479*7c478bd9Sstevel@tonic-gate 		 * Return an error if the polling interval is greater
2480*7c478bd9Sstevel@tonic-gate 		 * than 255ms.
2481*7c478bd9Sstevel@tonic-gate 		 */
2482*7c478bd9Sstevel@tonic-gate 		if (interval > LS_MAX_POLL_INTERVAL) {
2483*7c478bd9Sstevel@tonic-gate 
2484*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
2485*7c478bd9Sstevel@tonic-gate 			    "Low speed endpoint's poll interval is "
2486*7c478bd9Sstevel@tonic-gate 			    "greater than %d ms", LS_MAX_POLL_INTERVAL);
2487*7c478bd9Sstevel@tonic-gate 
2488*7c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
2489*7c478bd9Sstevel@tonic-gate 		}
2490*7c478bd9Sstevel@tonic-gate 		break;
2491*7c478bd9Sstevel@tonic-gate 
2492*7c478bd9Sstevel@tonic-gate 	case USBA_FULL_SPEED_DEV:
2493*7c478bd9Sstevel@tonic-gate 		/*
2494*7c478bd9Sstevel@tonic-gate 		 * Return an error if the polling interval is less
2495*7c478bd9Sstevel@tonic-gate 		 * than 1ms and greater than 255ms.
2496*7c478bd9Sstevel@tonic-gate 		 */
2497*7c478bd9Sstevel@tonic-gate 		if ((interval < FS_MIN_POLL_INTERVAL) &&
2498*7c478bd9Sstevel@tonic-gate 		    (interval > FS_MAX_POLL_INTERVAL)) {
2499*7c478bd9Sstevel@tonic-gate 
2500*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
2501*7c478bd9Sstevel@tonic-gate 			    "Full speed endpoint's poll interval must "
2502*7c478bd9Sstevel@tonic-gate 			    "be between %d and %d ms", FS_MIN_POLL_INTERVAL,
2503*7c478bd9Sstevel@tonic-gate 			    FS_MAX_POLL_INTERVAL);
2504*7c478bd9Sstevel@tonic-gate 
2505*7c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
2506*7c478bd9Sstevel@tonic-gate 		}
2507*7c478bd9Sstevel@tonic-gate 		break;
2508*7c478bd9Sstevel@tonic-gate 	case USBA_HIGH_SPEED_DEV:
2509*7c478bd9Sstevel@tonic-gate 		/*
2510*7c478bd9Sstevel@tonic-gate 		 * Return an error if the polling interval is less 1
2511*7c478bd9Sstevel@tonic-gate 		 * and greater than 16. Convert this value to 125us
2512*7c478bd9Sstevel@tonic-gate 		 * units using 2^(bInterval -1). refer usb 2.0 spec
2513*7c478bd9Sstevel@tonic-gate 		 * page 51 for details.
2514*7c478bd9Sstevel@tonic-gate 		 */
2515*7c478bd9Sstevel@tonic-gate 		if ((interval < HS_MIN_POLL_INTERVAL) &&
2516*7c478bd9Sstevel@tonic-gate 		    (interval > HS_MAX_POLL_INTERVAL)) {
2517*7c478bd9Sstevel@tonic-gate 
2518*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
2519*7c478bd9Sstevel@tonic-gate 			    "High speed endpoint's poll interval "
2520*7c478bd9Sstevel@tonic-gate 			    "must be between %d and %d units",
2521*7c478bd9Sstevel@tonic-gate 			    HS_MIN_POLL_INTERVAL, HS_MAX_POLL_INTERVAL);
2522*7c478bd9Sstevel@tonic-gate 
2523*7c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
2524*7c478bd9Sstevel@tonic-gate 		}
2525*7c478bd9Sstevel@tonic-gate 
2526*7c478bd9Sstevel@tonic-gate 		/* Adjust high speed device polling interval */
2527*7c478bd9Sstevel@tonic-gate 		interval =
2528*7c478bd9Sstevel@tonic-gate 		    ehci_adjust_high_speed_polling_interval(ehcip, endpoint);
2529*7c478bd9Sstevel@tonic-gate 
2530*7c478bd9Sstevel@tonic-gate 		break;
2531*7c478bd9Sstevel@tonic-gate 	}
2532*7c478bd9Sstevel@tonic-gate 
2533*7c478bd9Sstevel@tonic-gate 	/*
2534*7c478bd9Sstevel@tonic-gate 	 * If polling interval is greater than 32ms,
2535*7c478bd9Sstevel@tonic-gate 	 * adjust polling interval equal to 32ms.
2536*7c478bd9Sstevel@tonic-gate 	 */
2537*7c478bd9Sstevel@tonic-gate 	if (interval > EHCI_NUM_INTR_QH_LISTS) {
2538*7c478bd9Sstevel@tonic-gate 		interval = EHCI_NUM_INTR_QH_LISTS;
2539*7c478bd9Sstevel@tonic-gate 	}
2540*7c478bd9Sstevel@tonic-gate 
2541*7c478bd9Sstevel@tonic-gate 	/*
2542*7c478bd9Sstevel@tonic-gate 	 * Find the nearest power of 2 that's less
2543*7c478bd9Sstevel@tonic-gate 	 * than interval.
2544*7c478bd9Sstevel@tonic-gate 	 */
2545*7c478bd9Sstevel@tonic-gate 	while ((ehci_pow_2(i)) <= interval) {
2546*7c478bd9Sstevel@tonic-gate 		i++;
2547*7c478bd9Sstevel@tonic-gate 	}
2548*7c478bd9Sstevel@tonic-gate 
2549*7c478bd9Sstevel@tonic-gate 	return (ehci_pow_2((i - 1)));
2550*7c478bd9Sstevel@tonic-gate }
2551*7c478bd9Sstevel@tonic-gate 
2552*7c478bd9Sstevel@tonic-gate 
2553*7c478bd9Sstevel@tonic-gate /*
2554*7c478bd9Sstevel@tonic-gate  * ehci_adjust_high_speed_polling_interval:
2555*7c478bd9Sstevel@tonic-gate  */
2556*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
2557*7c478bd9Sstevel@tonic-gate static int
2558*7c478bd9Sstevel@tonic-gate ehci_adjust_high_speed_polling_interval(
2559*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
2560*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint)
2561*7c478bd9Sstevel@tonic-gate {
2562*7c478bd9Sstevel@tonic-gate 	uint_t			interval;
2563*7c478bd9Sstevel@tonic-gate 
2564*7c478bd9Sstevel@tonic-gate 	/* Get the polling interval */
2565*7c478bd9Sstevel@tonic-gate 	interval = ehci_pow_2(endpoint->bInterval - 1);
2566*7c478bd9Sstevel@tonic-gate 
2567*7c478bd9Sstevel@tonic-gate 	/*
2568*7c478bd9Sstevel@tonic-gate 	 * Convert polling interval from micro seconds
2569*7c478bd9Sstevel@tonic-gate 	 * to milli seconds.
2570*7c478bd9Sstevel@tonic-gate 	 */
2571*7c478bd9Sstevel@tonic-gate 	if (interval <= EHCI_MAX_UFRAMES) {
2572*7c478bd9Sstevel@tonic-gate 		interval = 1;
2573*7c478bd9Sstevel@tonic-gate 	} else {
2574*7c478bd9Sstevel@tonic-gate 		interval = interval/EHCI_MAX_UFRAMES;
2575*7c478bd9Sstevel@tonic-gate 	}
2576*7c478bd9Sstevel@tonic-gate 
2577*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
2578*7c478bd9Sstevel@tonic-gate 	    "ehci_adjust_high_speed_polling_interval: "
2579*7c478bd9Sstevel@tonic-gate 	    "High speed adjusted interval 0x%x", interval);
2580*7c478bd9Sstevel@tonic-gate 
2581*7c478bd9Sstevel@tonic-gate 	return (interval);
2582*7c478bd9Sstevel@tonic-gate }
2583*7c478bd9Sstevel@tonic-gate 
2584*7c478bd9Sstevel@tonic-gate 
2585*7c478bd9Sstevel@tonic-gate /*
2586*7c478bd9Sstevel@tonic-gate  * ehci_lattice_height:
2587*7c478bd9Sstevel@tonic-gate  *
2588*7c478bd9Sstevel@tonic-gate  * Given the requested bandwidth, find the height in the tree at which the
2589*7c478bd9Sstevel@tonic-gate  * nodes for this bandwidth fall.  The height is measured as the number of
2590*7c478bd9Sstevel@tonic-gate  * nodes from the leaf to the level specified by bandwidth The root of the
2591*7c478bd9Sstevel@tonic-gate  * tree is at height TREE_HEIGHT.
2592*7c478bd9Sstevel@tonic-gate  */
2593*7c478bd9Sstevel@tonic-gate static uint_t
2594*7c478bd9Sstevel@tonic-gate ehci_lattice_height(uint_t interval)
2595*7c478bd9Sstevel@tonic-gate {
2596*7c478bd9Sstevel@tonic-gate 	return (TREE_HEIGHT - (ehci_log_2(interval)));
2597*7c478bd9Sstevel@tonic-gate }
2598*7c478bd9Sstevel@tonic-gate 
2599*7c478bd9Sstevel@tonic-gate 
2600*7c478bd9Sstevel@tonic-gate /*
2601*7c478bd9Sstevel@tonic-gate  * ehci_lattice_parent:
2602*7c478bd9Sstevel@tonic-gate  *
2603*7c478bd9Sstevel@tonic-gate  * Given a node in the lattice, find the index of the parent node
2604*7c478bd9Sstevel@tonic-gate  */
2605*7c478bd9Sstevel@tonic-gate static uint_t
2606*7c478bd9Sstevel@tonic-gate ehci_lattice_parent(uint_t node)
2607*7c478bd9Sstevel@tonic-gate {
2608*7c478bd9Sstevel@tonic-gate 	if ((node % 2) == 0) {
2609*7c478bd9Sstevel@tonic-gate 
2610*7c478bd9Sstevel@tonic-gate 		return ((node/2) - 1);
2611*7c478bd9Sstevel@tonic-gate 	} else {
2612*7c478bd9Sstevel@tonic-gate 
2613*7c478bd9Sstevel@tonic-gate 		return ((node + 1)/2 - 1);
2614*7c478bd9Sstevel@tonic-gate 	}
2615*7c478bd9Sstevel@tonic-gate }
2616*7c478bd9Sstevel@tonic-gate 
2617*7c478bd9Sstevel@tonic-gate 
2618*7c478bd9Sstevel@tonic-gate /*
2619*7c478bd9Sstevel@tonic-gate  * ehci_find_periodic_node:
2620*7c478bd9Sstevel@tonic-gate  *
2621*7c478bd9Sstevel@tonic-gate  * Based on the "real" array leaf node and interval, get the periodic node.
2622*7c478bd9Sstevel@tonic-gate  */
2623*7c478bd9Sstevel@tonic-gate static uint_t
2624*7c478bd9Sstevel@tonic-gate ehci_find_periodic_node(uint_t leaf, int interval) {
2625*7c478bd9Sstevel@tonic-gate 	uint_t	lattice_leaf;
2626*7c478bd9Sstevel@tonic-gate 	uint_t	height = ehci_lattice_height(interval);
2627*7c478bd9Sstevel@tonic-gate 	uint_t	pnode;
2628*7c478bd9Sstevel@tonic-gate 	int	i;
2629*7c478bd9Sstevel@tonic-gate 
2630*7c478bd9Sstevel@tonic-gate 	/* Get the leaf number in the lattice */
2631*7c478bd9Sstevel@tonic-gate 	lattice_leaf = leaf + EHCI_NUM_INTR_QH_LISTS - 1;
2632*7c478bd9Sstevel@tonic-gate 
2633*7c478bd9Sstevel@tonic-gate 	/* Get the node in the lattice based on the height and leaf */
2634*7c478bd9Sstevel@tonic-gate 	pnode = lattice_leaf;
2635*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < height; i++) {
2636*7c478bd9Sstevel@tonic-gate 		pnode = ehci_lattice_parent(pnode);
2637*7c478bd9Sstevel@tonic-gate 	}
2638*7c478bd9Sstevel@tonic-gate 
2639*7c478bd9Sstevel@tonic-gate 	return (pnode);
2640*7c478bd9Sstevel@tonic-gate }
2641*7c478bd9Sstevel@tonic-gate 
2642*7c478bd9Sstevel@tonic-gate 
2643*7c478bd9Sstevel@tonic-gate /*
2644*7c478bd9Sstevel@tonic-gate  * ehci_leftmost_leaf:
2645*7c478bd9Sstevel@tonic-gate  *
2646*7c478bd9Sstevel@tonic-gate  * Find the leftmost leaf in the subtree specified by the node. Height refers
2647*7c478bd9Sstevel@tonic-gate  * to number of nodes from the bottom of the tree to the node,	including the
2648*7c478bd9Sstevel@tonic-gate  * node.
2649*7c478bd9Sstevel@tonic-gate  *
2650*7c478bd9Sstevel@tonic-gate  * The formula for a zero based tree is:
2651*7c478bd9Sstevel@tonic-gate  *     2^H * Node + 2^H - 1
2652*7c478bd9Sstevel@tonic-gate  * The leaf of the tree is an array, convert the number for the array.
2653*7c478bd9Sstevel@tonic-gate  *     Subtract the size of nodes not in the array
2654*7c478bd9Sstevel@tonic-gate  *     2^H * Node + 2^H - 1 - (EHCI_NUM_INTR_QH_LISTS - 1) =
2655*7c478bd9Sstevel@tonic-gate  *     2^H * Node + 2^H - EHCI_NUM_INTR_QH_LISTS =
2656*7c478bd9Sstevel@tonic-gate  *     2^H * (Node + 1) - EHCI_NUM_INTR_QH_LISTS
2657*7c478bd9Sstevel@tonic-gate  *	   0
2658*7c478bd9Sstevel@tonic-gate  *	 1   2
2659*7c478bd9Sstevel@tonic-gate  *	0 1 2 3
2660*7c478bd9Sstevel@tonic-gate  */
2661*7c478bd9Sstevel@tonic-gate static uint_t
2662*7c478bd9Sstevel@tonic-gate ehci_leftmost_leaf(
2663*7c478bd9Sstevel@tonic-gate 	uint_t	node,
2664*7c478bd9Sstevel@tonic-gate 	uint_t	height)
2665*7c478bd9Sstevel@tonic-gate {
2666*7c478bd9Sstevel@tonic-gate 	return ((ehci_pow_2(height) * (node + 1)) - EHCI_NUM_INTR_QH_LISTS);
2667*7c478bd9Sstevel@tonic-gate }
2668*7c478bd9Sstevel@tonic-gate 
2669*7c478bd9Sstevel@tonic-gate 
2670*7c478bd9Sstevel@tonic-gate /*
2671*7c478bd9Sstevel@tonic-gate  * ehci_pow_2:
2672*7c478bd9Sstevel@tonic-gate  *
2673*7c478bd9Sstevel@tonic-gate  * Compute 2 to the power
2674*7c478bd9Sstevel@tonic-gate  */
2675*7c478bd9Sstevel@tonic-gate static uint_t
2676*7c478bd9Sstevel@tonic-gate ehci_pow_2(uint_t x)
2677*7c478bd9Sstevel@tonic-gate {
2678*7c478bd9Sstevel@tonic-gate 	if (x == 0) {
2679*7c478bd9Sstevel@tonic-gate 
2680*7c478bd9Sstevel@tonic-gate 		return (1);
2681*7c478bd9Sstevel@tonic-gate 	} else {
2682*7c478bd9Sstevel@tonic-gate 
2683*7c478bd9Sstevel@tonic-gate 		return (2 << (x - 1));
2684*7c478bd9Sstevel@tonic-gate 	}
2685*7c478bd9Sstevel@tonic-gate }
2686*7c478bd9Sstevel@tonic-gate 
2687*7c478bd9Sstevel@tonic-gate 
2688*7c478bd9Sstevel@tonic-gate /*
2689*7c478bd9Sstevel@tonic-gate  * ehci_log_2:
2690*7c478bd9Sstevel@tonic-gate  *
2691*7c478bd9Sstevel@tonic-gate  * Compute log base 2 of x
2692*7c478bd9Sstevel@tonic-gate  */
2693*7c478bd9Sstevel@tonic-gate static uint_t
2694*7c478bd9Sstevel@tonic-gate ehci_log_2(uint_t x)
2695*7c478bd9Sstevel@tonic-gate {
2696*7c478bd9Sstevel@tonic-gate 	int i = 0;
2697*7c478bd9Sstevel@tonic-gate 
2698*7c478bd9Sstevel@tonic-gate 	while (x != 1) {
2699*7c478bd9Sstevel@tonic-gate 		x = x >> 1;
2700*7c478bd9Sstevel@tonic-gate 		i++;
2701*7c478bd9Sstevel@tonic-gate 	}
2702*7c478bd9Sstevel@tonic-gate 
2703*7c478bd9Sstevel@tonic-gate 	return (i);
2704*7c478bd9Sstevel@tonic-gate }
2705*7c478bd9Sstevel@tonic-gate 
2706*7c478bd9Sstevel@tonic-gate 
2707*7c478bd9Sstevel@tonic-gate /*
2708*7c478bd9Sstevel@tonic-gate  * ehci_find_bestfit_hs_mask:
2709*7c478bd9Sstevel@tonic-gate  *
2710*7c478bd9Sstevel@tonic-gate  * Find the smask and cmask in the bandwidth allocation, and update the
2711*7c478bd9Sstevel@tonic-gate  * bandwidth allocation.
2712*7c478bd9Sstevel@tonic-gate  */
2713*7c478bd9Sstevel@tonic-gate static int
2714*7c478bd9Sstevel@tonic-gate ehci_find_bestfit_hs_mask(
2715*7c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
2716*7c478bd9Sstevel@tonic-gate 	uchar_t		*smask,
2717*7c478bd9Sstevel@tonic-gate 	uint_t		*pnode,
2718*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t	*endpoint,
2719*7c478bd9Sstevel@tonic-gate 	uint_t		bandwidth,
2720*7c478bd9Sstevel@tonic-gate 	int		interval)
2721*7c478bd9Sstevel@tonic-gate {
2722*7c478bd9Sstevel@tonic-gate 	int		i;
2723*7c478bd9Sstevel@tonic-gate 	uint_t		elements, index;
2724*7c478bd9Sstevel@tonic-gate 	int		array_leaf, best_array_leaf;
2725*7c478bd9Sstevel@tonic-gate 	uint_t		node_bandwidth, best_node_bandwidth;
2726*7c478bd9Sstevel@tonic-gate 	uint_t		leaf_count;
2727*7c478bd9Sstevel@tonic-gate 	uchar_t		bw_mask;
2728*7c478bd9Sstevel@tonic-gate 	uchar_t		best_smask;
2729*7c478bd9Sstevel@tonic-gate 
2730*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
2731*7c478bd9Sstevel@tonic-gate 	    "ehci_find_bestfit_hs_mask: ");
2732*7c478bd9Sstevel@tonic-gate 
2733*7c478bd9Sstevel@tonic-gate 	/* Get all the valid smasks */
2734*7c478bd9Sstevel@tonic-gate 	switch (ehci_pow_2(endpoint->bInterval - 1)) {
2735*7c478bd9Sstevel@tonic-gate 	case EHCI_INTR_1US_POLL:
2736*7c478bd9Sstevel@tonic-gate 		index = EHCI_1US_MASK_INDEX;
2737*7c478bd9Sstevel@tonic-gate 		elements = EHCI_INTR_1US_POLL;
2738*7c478bd9Sstevel@tonic-gate 		break;
2739*7c478bd9Sstevel@tonic-gate 	case EHCI_INTR_2US_POLL:
2740*7c478bd9Sstevel@tonic-gate 		index = EHCI_2US_MASK_INDEX;
2741*7c478bd9Sstevel@tonic-gate 		elements = EHCI_INTR_2US_POLL;
2742*7c478bd9Sstevel@tonic-gate 		break;
2743*7c478bd9Sstevel@tonic-gate 	case EHCI_INTR_4US_POLL:
2744*7c478bd9Sstevel@tonic-gate 		index = EHCI_4US_MASK_INDEX;
2745*7c478bd9Sstevel@tonic-gate 		elements = EHCI_INTR_4US_POLL;
2746*7c478bd9Sstevel@tonic-gate 		break;
2747*7c478bd9Sstevel@tonic-gate 	case EHCI_INTR_XUS_POLL:
2748*7c478bd9Sstevel@tonic-gate 	default:
2749*7c478bd9Sstevel@tonic-gate 		index = EHCI_XUS_MASK_INDEX;
2750*7c478bd9Sstevel@tonic-gate 		elements = EHCI_INTR_XUS_POLL;
2751*7c478bd9Sstevel@tonic-gate 		break;
2752*7c478bd9Sstevel@tonic-gate 	}
2753*7c478bd9Sstevel@tonic-gate 
2754*7c478bd9Sstevel@tonic-gate 	leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
2755*7c478bd9Sstevel@tonic-gate 
2756*7c478bd9Sstevel@tonic-gate 	/*
2757*7c478bd9Sstevel@tonic-gate 	 * Because of the way the leaves are setup, we will automatically
2758*7c478bd9Sstevel@tonic-gate 	 * hit the leftmost leaf of every possible node with this interval.
2759*7c478bd9Sstevel@tonic-gate 	 */
2760*7c478bd9Sstevel@tonic-gate 	best_smask = 0x00;
2761*7c478bd9Sstevel@tonic-gate 	best_node_bandwidth = 0;
2762*7c478bd9Sstevel@tonic-gate 	for (array_leaf = 0; array_leaf < interval; array_leaf++) {
2763*7c478bd9Sstevel@tonic-gate 		/* Find the bandwidth mask */
2764*7c478bd9Sstevel@tonic-gate 		node_bandwidth = ehci_calculate_bw_availability_mask(ehcip,
2765*7c478bd9Sstevel@tonic-gate 		    bandwidth, ehci_index[array_leaf], leaf_count, &bw_mask);
2766*7c478bd9Sstevel@tonic-gate 
2767*7c478bd9Sstevel@tonic-gate 		/*
2768*7c478bd9Sstevel@tonic-gate 		 * If this node cannot support our requirements skip to the
2769*7c478bd9Sstevel@tonic-gate 		 * next leaf.
2770*7c478bd9Sstevel@tonic-gate 		 */
2771*7c478bd9Sstevel@tonic-gate 		if (bw_mask == 0x00) {
2772*7c478bd9Sstevel@tonic-gate 			continue;
2773*7c478bd9Sstevel@tonic-gate 		}
2774*7c478bd9Sstevel@tonic-gate 
2775*7c478bd9Sstevel@tonic-gate 		/*
2776*7c478bd9Sstevel@tonic-gate 		 * Now make sure our bandwidth requirements can be
2777*7c478bd9Sstevel@tonic-gate 		 * satisfied with one of smasks in this node.
2778*7c478bd9Sstevel@tonic-gate 		 */
2779*7c478bd9Sstevel@tonic-gate 		*smask = 0x00;
2780*7c478bd9Sstevel@tonic-gate 		for (i = index; i < (index + elements); i++) {
2781*7c478bd9Sstevel@tonic-gate 			/* Check the start split mask value */
2782*7c478bd9Sstevel@tonic-gate 			if (ehci_start_split_mask[index] & bw_mask) {
2783*7c478bd9Sstevel@tonic-gate 				*smask = ehci_start_split_mask[index];
2784*7c478bd9Sstevel@tonic-gate 				break;
2785*7c478bd9Sstevel@tonic-gate 			}
2786*7c478bd9Sstevel@tonic-gate 		}
2787*7c478bd9Sstevel@tonic-gate 
2788*7c478bd9Sstevel@tonic-gate 		/*
2789*7c478bd9Sstevel@tonic-gate 		 * If an appropriate smask is found save the information if:
2790*7c478bd9Sstevel@tonic-gate 		 * o best_smask has not been found yet.
2791*7c478bd9Sstevel@tonic-gate 		 * - or -
2792*7c478bd9Sstevel@tonic-gate 		 * o This is the node with the least amount of bandwidth
2793*7c478bd9Sstevel@tonic-gate 		 */
2794*7c478bd9Sstevel@tonic-gate 		if ((*smask != 0x00) &&
2795*7c478bd9Sstevel@tonic-gate 		    ((best_smask == 0x00) ||
2796*7c478bd9Sstevel@tonic-gate 			(best_node_bandwidth > node_bandwidth))) {
2797*7c478bd9Sstevel@tonic-gate 
2798*7c478bd9Sstevel@tonic-gate 			best_node_bandwidth = node_bandwidth;
2799*7c478bd9Sstevel@tonic-gate 			best_array_leaf = array_leaf;
2800*7c478bd9Sstevel@tonic-gate 			best_smask = *smask;
2801*7c478bd9Sstevel@tonic-gate 		}
2802*7c478bd9Sstevel@tonic-gate 	}
2803*7c478bd9Sstevel@tonic-gate 
2804*7c478bd9Sstevel@tonic-gate 	/*
2805*7c478bd9Sstevel@tonic-gate 	 * If we find node that can handle the bandwidth populate the
2806*7c478bd9Sstevel@tonic-gate 	 * appropriate variables and return success.
2807*7c478bd9Sstevel@tonic-gate 	 */
2808*7c478bd9Sstevel@tonic-gate 	if (best_smask) {
2809*7c478bd9Sstevel@tonic-gate 		*smask = best_smask;
2810*7c478bd9Sstevel@tonic-gate 		*pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
2811*7c478bd9Sstevel@tonic-gate 		    interval);
2812*7c478bd9Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, bandwidth,
2813*7c478bd9Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_smask);
2814*7c478bd9Sstevel@tonic-gate 
2815*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
2816*7c478bd9Sstevel@tonic-gate 	}
2817*7c478bd9Sstevel@tonic-gate 
2818*7c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
2819*7c478bd9Sstevel@tonic-gate }
2820*7c478bd9Sstevel@tonic-gate 
2821*7c478bd9Sstevel@tonic-gate 
2822*7c478bd9Sstevel@tonic-gate /*
2823*7c478bd9Sstevel@tonic-gate  * ehci_find_bestfit_ls_intr_mask:
2824*7c478bd9Sstevel@tonic-gate  *
2825*7c478bd9Sstevel@tonic-gate  * Find the smask and cmask in the bandwidth allocation.
2826*7c478bd9Sstevel@tonic-gate  */
2827*7c478bd9Sstevel@tonic-gate static int
2828*7c478bd9Sstevel@tonic-gate ehci_find_bestfit_ls_intr_mask(
2829*7c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
2830*7c478bd9Sstevel@tonic-gate 	uchar_t		*smask,
2831*7c478bd9Sstevel@tonic-gate 	uchar_t		*cmask,
2832*7c478bd9Sstevel@tonic-gate 	uint_t		*pnode,
2833*7c478bd9Sstevel@tonic-gate 	uint_t		sbandwidth,
2834*7c478bd9Sstevel@tonic-gate 	uint_t		cbandwidth,
2835*7c478bd9Sstevel@tonic-gate 	int		interval)
2836*7c478bd9Sstevel@tonic-gate {
2837*7c478bd9Sstevel@tonic-gate 	int		i;
2838*7c478bd9Sstevel@tonic-gate 	uint_t		elements, index;
2839*7c478bd9Sstevel@tonic-gate 	int		array_leaf, best_array_leaf;
2840*7c478bd9Sstevel@tonic-gate 	uint_t		node_sbandwidth, node_cbandwidth;
2841*7c478bd9Sstevel@tonic-gate 	uint_t		best_node_bandwidth;
2842*7c478bd9Sstevel@tonic-gate 	uint_t		leaf_count;
2843*7c478bd9Sstevel@tonic-gate 	uchar_t		bw_smask, bw_cmask;
2844*7c478bd9Sstevel@tonic-gate 	uchar_t		best_smask, best_cmask;
2845*7c478bd9Sstevel@tonic-gate 
2846*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
2847*7c478bd9Sstevel@tonic-gate 	    "ehci_find_bestfit_ls_intr_mask: ");
2848*7c478bd9Sstevel@tonic-gate 
2849*7c478bd9Sstevel@tonic-gate 	/* For low and full speed devices */
2850*7c478bd9Sstevel@tonic-gate 	index = EHCI_XUS_MASK_INDEX;
2851*7c478bd9Sstevel@tonic-gate 	elements = EHCI_INTR_4MS_POLL;
2852*7c478bd9Sstevel@tonic-gate 
2853*7c478bd9Sstevel@tonic-gate 	leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
2854*7c478bd9Sstevel@tonic-gate 
2855*7c478bd9Sstevel@tonic-gate 	/*
2856*7c478bd9Sstevel@tonic-gate 	 * Because of the way the leaves are setup, we will automatically
2857*7c478bd9Sstevel@tonic-gate 	 * hit the leftmost leaf of every possible node with this interval.
2858*7c478bd9Sstevel@tonic-gate 	 */
2859*7c478bd9Sstevel@tonic-gate 	best_smask = 0x00;
2860*7c478bd9Sstevel@tonic-gate 	best_node_bandwidth = 0;
2861*7c478bd9Sstevel@tonic-gate 	for (array_leaf = 0; array_leaf < interval; array_leaf++) {
2862*7c478bd9Sstevel@tonic-gate 		/* Find the bandwidth mask */
2863*7c478bd9Sstevel@tonic-gate 		node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip,
2864*7c478bd9Sstevel@tonic-gate 		    sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask);
2865*7c478bd9Sstevel@tonic-gate 		node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip,
2866*7c478bd9Sstevel@tonic-gate 		    cbandwidth, ehci_index[array_leaf], leaf_count, &bw_cmask);
2867*7c478bd9Sstevel@tonic-gate 
2868*7c478bd9Sstevel@tonic-gate 		/*
2869*7c478bd9Sstevel@tonic-gate 		 * If this node cannot support our requirements skip to the
2870*7c478bd9Sstevel@tonic-gate 		 * next leaf.
2871*7c478bd9Sstevel@tonic-gate 		 */
2872*7c478bd9Sstevel@tonic-gate 		if ((bw_smask == 0x00) || (bw_cmask == 0x00)) {
2873*7c478bd9Sstevel@tonic-gate 			continue;
2874*7c478bd9Sstevel@tonic-gate 		}
2875*7c478bd9Sstevel@tonic-gate 
2876*7c478bd9Sstevel@tonic-gate 		/*
2877*7c478bd9Sstevel@tonic-gate 		 * Now make sure our bandwidth requirements can be
2878*7c478bd9Sstevel@tonic-gate 		 * satisfied with one of smasks in this node.
2879*7c478bd9Sstevel@tonic-gate 		 */
2880*7c478bd9Sstevel@tonic-gate 		*smask = 0x00;
2881*7c478bd9Sstevel@tonic-gate 		*cmask = 0x00;
2882*7c478bd9Sstevel@tonic-gate 		for (i = index; i < (index + elements); i++) {
2883*7c478bd9Sstevel@tonic-gate 			/* Check the start split mask value */
2884*7c478bd9Sstevel@tonic-gate 			if ((ehci_start_split_mask[index] & bw_smask) &&
2885*7c478bd9Sstevel@tonic-gate 			    (ehci_intr_complete_split_mask[index] & bw_cmask)) {
2886*7c478bd9Sstevel@tonic-gate 				*smask = ehci_start_split_mask[index];
2887*7c478bd9Sstevel@tonic-gate 				*cmask = ehci_intr_complete_split_mask[index];
2888*7c478bd9Sstevel@tonic-gate 				break;
2889*7c478bd9Sstevel@tonic-gate 			}
2890*7c478bd9Sstevel@tonic-gate 		}
2891*7c478bd9Sstevel@tonic-gate 
2892*7c478bd9Sstevel@tonic-gate 		/*
2893*7c478bd9Sstevel@tonic-gate 		 * If an appropriate smask is found save the information if:
2894*7c478bd9Sstevel@tonic-gate 		 * o best_smask has not been found yet.
2895*7c478bd9Sstevel@tonic-gate 		 * - or -
2896*7c478bd9Sstevel@tonic-gate 		 * o This is the node with the least amount of bandwidth
2897*7c478bd9Sstevel@tonic-gate 		 */
2898*7c478bd9Sstevel@tonic-gate 		if ((*smask != 0x00) &&
2899*7c478bd9Sstevel@tonic-gate 		    ((best_smask == 0x00) ||
2900*7c478bd9Sstevel@tonic-gate 			(best_node_bandwidth >
2901*7c478bd9Sstevel@tonic-gate 			    (node_sbandwidth + node_cbandwidth)))) {
2902*7c478bd9Sstevel@tonic-gate 			best_node_bandwidth = node_sbandwidth + node_cbandwidth;
2903*7c478bd9Sstevel@tonic-gate 			best_array_leaf = array_leaf;
2904*7c478bd9Sstevel@tonic-gate 			best_smask = *smask;
2905*7c478bd9Sstevel@tonic-gate 			best_cmask = *cmask;
2906*7c478bd9Sstevel@tonic-gate 		}
2907*7c478bd9Sstevel@tonic-gate 	}
2908*7c478bd9Sstevel@tonic-gate 
2909*7c478bd9Sstevel@tonic-gate 	/*
2910*7c478bd9Sstevel@tonic-gate 	 * If we find node that can handle the bandwidth populate the
2911*7c478bd9Sstevel@tonic-gate 	 * appropriate variables and return success.
2912*7c478bd9Sstevel@tonic-gate 	 */
2913*7c478bd9Sstevel@tonic-gate 	if (best_smask) {
2914*7c478bd9Sstevel@tonic-gate 		*smask = best_smask;
2915*7c478bd9Sstevel@tonic-gate 		*cmask = best_cmask;
2916*7c478bd9Sstevel@tonic-gate 		*pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
2917*7c478bd9Sstevel@tonic-gate 		    interval);
2918*7c478bd9Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, sbandwidth,
2919*7c478bd9Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_smask);
2920*7c478bd9Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, cbandwidth,
2921*7c478bd9Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_cmask);
2922*7c478bd9Sstevel@tonic-gate 
2923*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
2924*7c478bd9Sstevel@tonic-gate 	}
2925*7c478bd9Sstevel@tonic-gate 
2926*7c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
2927*7c478bd9Sstevel@tonic-gate }
2928*7c478bd9Sstevel@tonic-gate 
2929*7c478bd9Sstevel@tonic-gate 
2930*7c478bd9Sstevel@tonic-gate /*
2931*7c478bd9Sstevel@tonic-gate  * ehci_find_bestfit_sitd_in_mask:
2932*7c478bd9Sstevel@tonic-gate  *
2933*7c478bd9Sstevel@tonic-gate  * Find the smask and cmask in the bandwidth allocation.
2934*7c478bd9Sstevel@tonic-gate  */
2935*7c478bd9Sstevel@tonic-gate static int
2936*7c478bd9Sstevel@tonic-gate ehci_find_bestfit_sitd_in_mask(
2937*7c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
2938*7c478bd9Sstevel@tonic-gate 	uchar_t		*smask,
2939*7c478bd9Sstevel@tonic-gate 	uchar_t		*cmask,
2940*7c478bd9Sstevel@tonic-gate 	uint_t		*pnode,
2941*7c478bd9Sstevel@tonic-gate 	uint_t		sbandwidth,
2942*7c478bd9Sstevel@tonic-gate 	uint_t		cbandwidth,
2943*7c478bd9Sstevel@tonic-gate 	int		interval)
2944*7c478bd9Sstevel@tonic-gate {
2945*7c478bd9Sstevel@tonic-gate 	int		i, uFrames, found;
2946*7c478bd9Sstevel@tonic-gate 	int		array_leaf, best_array_leaf;
2947*7c478bd9Sstevel@tonic-gate 	uint_t		node_sbandwidth, node_cbandwidth;
2948*7c478bd9Sstevel@tonic-gate 	uint_t		best_node_bandwidth;
2949*7c478bd9Sstevel@tonic-gate 	uint_t		leaf_count;
2950*7c478bd9Sstevel@tonic-gate 	uchar_t		bw_smask, bw_cmask;
2951*7c478bd9Sstevel@tonic-gate 	uchar_t		best_smask, best_cmask;
2952*7c478bd9Sstevel@tonic-gate 
2953*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
2954*7c478bd9Sstevel@tonic-gate 	    "ehci_find_bestfit_sitd_in_mask: ");
2955*7c478bd9Sstevel@tonic-gate 
2956*7c478bd9Sstevel@tonic-gate 	leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
2957*7c478bd9Sstevel@tonic-gate 
2958*7c478bd9Sstevel@tonic-gate 	/*
2959*7c478bd9Sstevel@tonic-gate 	 * Because of the way the leaves are setup, we will automatically
2960*7c478bd9Sstevel@tonic-gate 	 * hit the leftmost leaf of every possible node with this interval.
2961*7c478bd9Sstevel@tonic-gate 	 * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame.
2962*7c478bd9Sstevel@tonic-gate 	 */
2963*7c478bd9Sstevel@tonic-gate 	/*
2964*7c478bd9Sstevel@tonic-gate 	 * Need to add an additional 2 uFrames, if the "L"ast
2965*7c478bd9Sstevel@tonic-gate 	 * complete split is before uFrame 6.  See section
2966*7c478bd9Sstevel@tonic-gate 	 * 11.8.4 in USB 2.0 Spec.  Currently we do not support
2967*7c478bd9Sstevel@tonic-gate 	 * the "Back Ptr" which means we support on IN of
2968*7c478bd9Sstevel@tonic-gate 	 * ~4*MAX_UFRAME_SITD_XFER bandwidth/
2969*7c478bd9Sstevel@tonic-gate 	 */
2970*7c478bd9Sstevel@tonic-gate 	uFrames = (cbandwidth / MAX_UFRAME_SITD_XFER) + 2;
2971*7c478bd9Sstevel@tonic-gate 	if (cbandwidth % MAX_UFRAME_SITD_XFER) {
2972*7c478bd9Sstevel@tonic-gate 		uFrames++;
2973*7c478bd9Sstevel@tonic-gate 	}
2974*7c478bd9Sstevel@tonic-gate 	if (uFrames > 6) {
2975*7c478bd9Sstevel@tonic-gate 
2976*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
2977*7c478bd9Sstevel@tonic-gate 	}
2978*7c478bd9Sstevel@tonic-gate 	*smask = 0x1;
2979*7c478bd9Sstevel@tonic-gate 	*cmask = 0x00;
2980*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < uFrames; i++) {
2981*7c478bd9Sstevel@tonic-gate 		*cmask = *cmask << 1;
2982*7c478bd9Sstevel@tonic-gate 		*cmask |= 0x1;
2983*7c478bd9Sstevel@tonic-gate 	}
2984*7c478bd9Sstevel@tonic-gate 	/* cmask must start 2 frames after the smask */
2985*7c478bd9Sstevel@tonic-gate 	*cmask = *cmask << 2;
2986*7c478bd9Sstevel@tonic-gate 
2987*7c478bd9Sstevel@tonic-gate 	found = 0;
2988*7c478bd9Sstevel@tonic-gate 	best_smask = 0x00;
2989*7c478bd9Sstevel@tonic-gate 	best_node_bandwidth = 0;
2990*7c478bd9Sstevel@tonic-gate 	for (array_leaf = 0; array_leaf < interval; array_leaf++) {
2991*7c478bd9Sstevel@tonic-gate 		node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip,
2992*7c478bd9Sstevel@tonic-gate 		    sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask);
2993*7c478bd9Sstevel@tonic-gate 		node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip,
2994*7c478bd9Sstevel@tonic-gate 		    MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count,
2995*7c478bd9Sstevel@tonic-gate 		    &bw_cmask);
2996*7c478bd9Sstevel@tonic-gate 
2997*7c478bd9Sstevel@tonic-gate 		/*
2998*7c478bd9Sstevel@tonic-gate 		 * If this node cannot support our requirements skip to the
2999*7c478bd9Sstevel@tonic-gate 		 * next leaf.
3000*7c478bd9Sstevel@tonic-gate 		 */
3001*7c478bd9Sstevel@tonic-gate 		if ((bw_smask == 0x00) || (bw_cmask == 0x00)) {
3002*7c478bd9Sstevel@tonic-gate 			continue;
3003*7c478bd9Sstevel@tonic-gate 		}
3004*7c478bd9Sstevel@tonic-gate 
3005*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < (EHCI_MAX_UFRAMES - uFrames - 2); i++) {
3006*7c478bd9Sstevel@tonic-gate 			if ((*smask & bw_smask) && (*cmask & bw_cmask)) {
3007*7c478bd9Sstevel@tonic-gate 				found = 1;
3008*7c478bd9Sstevel@tonic-gate 				break;
3009*7c478bd9Sstevel@tonic-gate 			}
3010*7c478bd9Sstevel@tonic-gate 			*smask = *smask << 1;
3011*7c478bd9Sstevel@tonic-gate 			*cmask = *cmask << 1;
3012*7c478bd9Sstevel@tonic-gate 		}
3013*7c478bd9Sstevel@tonic-gate 
3014*7c478bd9Sstevel@tonic-gate 		/*
3015*7c478bd9Sstevel@tonic-gate 		 * If an appropriate smask is found save the information if:
3016*7c478bd9Sstevel@tonic-gate 		 * o best_smask has not been found yet.
3017*7c478bd9Sstevel@tonic-gate 		 * - or -
3018*7c478bd9Sstevel@tonic-gate 		 * o This is the node with the least amount of bandwidth
3019*7c478bd9Sstevel@tonic-gate 		 */
3020*7c478bd9Sstevel@tonic-gate 		if (found &&
3021*7c478bd9Sstevel@tonic-gate 		    ((best_smask == 0x00) ||
3022*7c478bd9Sstevel@tonic-gate 			(best_node_bandwidth >
3023*7c478bd9Sstevel@tonic-gate 			    (node_sbandwidth + node_cbandwidth)))) {
3024*7c478bd9Sstevel@tonic-gate 			best_node_bandwidth = node_sbandwidth + node_cbandwidth;
3025*7c478bd9Sstevel@tonic-gate 			best_array_leaf = array_leaf;
3026*7c478bd9Sstevel@tonic-gate 			best_smask = *smask;
3027*7c478bd9Sstevel@tonic-gate 			best_cmask = *cmask;
3028*7c478bd9Sstevel@tonic-gate 		}
3029*7c478bd9Sstevel@tonic-gate 	}
3030*7c478bd9Sstevel@tonic-gate 
3031*7c478bd9Sstevel@tonic-gate 	/*
3032*7c478bd9Sstevel@tonic-gate 	 * If we find node that can handle the bandwidth populate the
3033*7c478bd9Sstevel@tonic-gate 	 * appropriate variables and return success.
3034*7c478bd9Sstevel@tonic-gate 	 */
3035*7c478bd9Sstevel@tonic-gate 	if (best_smask) {
3036*7c478bd9Sstevel@tonic-gate 		*smask = best_smask;
3037*7c478bd9Sstevel@tonic-gate 		*cmask = best_cmask;
3038*7c478bd9Sstevel@tonic-gate 		*pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
3039*7c478bd9Sstevel@tonic-gate 		    interval);
3040*7c478bd9Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, sbandwidth,
3041*7c478bd9Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_smask);
3042*7c478bd9Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER,
3043*7c478bd9Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_cmask);
3044*7c478bd9Sstevel@tonic-gate 
3045*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
3046*7c478bd9Sstevel@tonic-gate 	}
3047*7c478bd9Sstevel@tonic-gate 
3048*7c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
3049*7c478bd9Sstevel@tonic-gate }
3050*7c478bd9Sstevel@tonic-gate 
3051*7c478bd9Sstevel@tonic-gate 
3052*7c478bd9Sstevel@tonic-gate /*
3053*7c478bd9Sstevel@tonic-gate  * ehci_find_bestfit_sitd_out_mask:
3054*7c478bd9Sstevel@tonic-gate  *
3055*7c478bd9Sstevel@tonic-gate  * Find the smask in the bandwidth allocation.
3056*7c478bd9Sstevel@tonic-gate  */
3057*7c478bd9Sstevel@tonic-gate static int
3058*7c478bd9Sstevel@tonic-gate ehci_find_bestfit_sitd_out_mask(
3059*7c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
3060*7c478bd9Sstevel@tonic-gate 	uchar_t		*smask,
3061*7c478bd9Sstevel@tonic-gate 	uint_t		*pnode,
3062*7c478bd9Sstevel@tonic-gate 	uint_t		sbandwidth,
3063*7c478bd9Sstevel@tonic-gate 	int		interval)
3064*7c478bd9Sstevel@tonic-gate {
3065*7c478bd9Sstevel@tonic-gate 	int		i, uFrames, found;
3066*7c478bd9Sstevel@tonic-gate 	int		array_leaf, best_array_leaf;
3067*7c478bd9Sstevel@tonic-gate 	uint_t		node_sbandwidth;
3068*7c478bd9Sstevel@tonic-gate 	uint_t		best_node_bandwidth;
3069*7c478bd9Sstevel@tonic-gate 	uint_t		leaf_count;
3070*7c478bd9Sstevel@tonic-gate 	uchar_t		bw_smask;
3071*7c478bd9Sstevel@tonic-gate 	uchar_t		best_smask;
3072*7c478bd9Sstevel@tonic-gate 
3073*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
3074*7c478bd9Sstevel@tonic-gate 	    "ehci_find_bestfit_sitd_out_mask: ");
3075*7c478bd9Sstevel@tonic-gate 
3076*7c478bd9Sstevel@tonic-gate 	leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
3077*7c478bd9Sstevel@tonic-gate 
3078*7c478bd9Sstevel@tonic-gate 	/*
3079*7c478bd9Sstevel@tonic-gate 	 * Because of the way the leaves are setup, we will automatically
3080*7c478bd9Sstevel@tonic-gate 	 * hit the leftmost leaf of every possible node with this interval.
3081*7c478bd9Sstevel@tonic-gate 	 * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame.
3082*7c478bd9Sstevel@tonic-gate 	 */
3083*7c478bd9Sstevel@tonic-gate 	*smask = 0x00;
3084*7c478bd9Sstevel@tonic-gate 	uFrames = sbandwidth / MAX_UFRAME_SITD_XFER;
3085*7c478bd9Sstevel@tonic-gate 	if (sbandwidth % MAX_UFRAME_SITD_XFER) {
3086*7c478bd9Sstevel@tonic-gate 		uFrames++;
3087*7c478bd9Sstevel@tonic-gate 	}
3088*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < uFrames; i++) {
3089*7c478bd9Sstevel@tonic-gate 		*smask = *smask << 1;
3090*7c478bd9Sstevel@tonic-gate 		*smask |= 0x1;
3091*7c478bd9Sstevel@tonic-gate 	}
3092*7c478bd9Sstevel@tonic-gate 
3093*7c478bd9Sstevel@tonic-gate 	found = 0;
3094*7c478bd9Sstevel@tonic-gate 	best_smask = 0x00;
3095*7c478bd9Sstevel@tonic-gate 	best_node_bandwidth = 0;
3096*7c478bd9Sstevel@tonic-gate 	for (array_leaf = 0; array_leaf < interval; array_leaf++) {
3097*7c478bd9Sstevel@tonic-gate 		node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip,
3098*7c478bd9Sstevel@tonic-gate 		    MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count,
3099*7c478bd9Sstevel@tonic-gate 		    &bw_smask);
3100*7c478bd9Sstevel@tonic-gate 
3101*7c478bd9Sstevel@tonic-gate 		/*
3102*7c478bd9Sstevel@tonic-gate 		 * If this node cannot support our requirements skip to the
3103*7c478bd9Sstevel@tonic-gate 		 * next leaf.
3104*7c478bd9Sstevel@tonic-gate 		 */
3105*7c478bd9Sstevel@tonic-gate 		if (bw_smask == 0x00) {
3106*7c478bd9Sstevel@tonic-gate 			continue;
3107*7c478bd9Sstevel@tonic-gate 		}
3108*7c478bd9Sstevel@tonic-gate 
3109*7c478bd9Sstevel@tonic-gate 		/* You cannot have a start split on the 8th uFrame */
3110*7c478bd9Sstevel@tonic-gate 		for (i = 0; (*smask & 0x80) == 0; i++) {
3111*7c478bd9Sstevel@tonic-gate 			if (*smask & bw_smask) {
3112*7c478bd9Sstevel@tonic-gate 				found = 1;
3113*7c478bd9Sstevel@tonic-gate 				break;
3114*7c478bd9Sstevel@tonic-gate 			}
3115*7c478bd9Sstevel@tonic-gate 			*smask = *smask << 1;
3116*7c478bd9Sstevel@tonic-gate 		}
3117*7c478bd9Sstevel@tonic-gate 
3118*7c478bd9Sstevel@tonic-gate 		/*
3119*7c478bd9Sstevel@tonic-gate 		 * If an appropriate smask is found save the information if:
3120*7c478bd9Sstevel@tonic-gate 		 * o best_smask has not been found yet.
3121*7c478bd9Sstevel@tonic-gate 		 * - or -
3122*7c478bd9Sstevel@tonic-gate 		 * o This is the node with the least amount of bandwidth
3123*7c478bd9Sstevel@tonic-gate 		 */
3124*7c478bd9Sstevel@tonic-gate 		if (found &&
3125*7c478bd9Sstevel@tonic-gate 		    ((best_smask == 0x00) ||
3126*7c478bd9Sstevel@tonic-gate 			(best_node_bandwidth > node_sbandwidth))) {
3127*7c478bd9Sstevel@tonic-gate 			best_node_bandwidth = node_sbandwidth;
3128*7c478bd9Sstevel@tonic-gate 			best_array_leaf = array_leaf;
3129*7c478bd9Sstevel@tonic-gate 			best_smask = *smask;
3130*7c478bd9Sstevel@tonic-gate 		}
3131*7c478bd9Sstevel@tonic-gate 	}
3132*7c478bd9Sstevel@tonic-gate 
3133*7c478bd9Sstevel@tonic-gate 	/*
3134*7c478bd9Sstevel@tonic-gate 	 * If we find node that can handle the bandwidth populate the
3135*7c478bd9Sstevel@tonic-gate 	 * appropriate variables and return success.
3136*7c478bd9Sstevel@tonic-gate 	 */
3137*7c478bd9Sstevel@tonic-gate 	if (best_smask) {
3138*7c478bd9Sstevel@tonic-gate 		*smask = best_smask;
3139*7c478bd9Sstevel@tonic-gate 		*pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
3140*7c478bd9Sstevel@tonic-gate 		    interval);
3141*7c478bd9Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER,
3142*7c478bd9Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_smask);
3143*7c478bd9Sstevel@tonic-gate 
3144*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
3145*7c478bd9Sstevel@tonic-gate 	}
3146*7c478bd9Sstevel@tonic-gate 
3147*7c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
3148*7c478bd9Sstevel@tonic-gate }
3149*7c478bd9Sstevel@tonic-gate 
3150*7c478bd9Sstevel@tonic-gate 
3151*7c478bd9Sstevel@tonic-gate /*
3152*7c478bd9Sstevel@tonic-gate  * ehci_calculate_bw_availability_mask:
3153*7c478bd9Sstevel@tonic-gate  *
3154*7c478bd9Sstevel@tonic-gate  * Returns the "total bandwidth used" in this node.
3155*7c478bd9Sstevel@tonic-gate  * Populates bw_mask with the uFrames that can support the bandwidth.
3156*7c478bd9Sstevel@tonic-gate  *
3157*7c478bd9Sstevel@tonic-gate  * If all the Frames cannot support this bandwidth, then bw_mask
3158*7c478bd9Sstevel@tonic-gate  * will return 0x00 and the "total bandwidth used" will be invalid.
3159*7c478bd9Sstevel@tonic-gate  */
3160*7c478bd9Sstevel@tonic-gate static uint_t
3161*7c478bd9Sstevel@tonic-gate ehci_calculate_bw_availability_mask(
3162*7c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
3163*7c478bd9Sstevel@tonic-gate 	uint_t		bandwidth,
3164*7c478bd9Sstevel@tonic-gate 	int		leaf,
3165*7c478bd9Sstevel@tonic-gate 	int		leaf_count,
3166*7c478bd9Sstevel@tonic-gate 	uchar_t		*bw_mask)
3167*7c478bd9Sstevel@tonic-gate {
3168*7c478bd9Sstevel@tonic-gate 	int			i, j;
3169*7c478bd9Sstevel@tonic-gate 	uchar_t			bw_uframe;
3170*7c478bd9Sstevel@tonic-gate 	int			uframe_total;
3171*7c478bd9Sstevel@tonic-gate 	ehci_frame_bandwidth_t	*fbp;
3172*7c478bd9Sstevel@tonic-gate 	uint_t			total_bandwidth = 0;
3173*7c478bd9Sstevel@tonic-gate 
3174*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
3175*7c478bd9Sstevel@tonic-gate 	    "ehci_calculate_bw_availability_mask: leaf %d leaf count %d",
3176*7c478bd9Sstevel@tonic-gate 	    leaf, leaf_count);
3177*7c478bd9Sstevel@tonic-gate 
3178*7c478bd9Sstevel@tonic-gate 	/* Start by saying all uFrames are available */
3179*7c478bd9Sstevel@tonic-gate 	*bw_mask = 0xFF;
3180*7c478bd9Sstevel@tonic-gate 
3181*7c478bd9Sstevel@tonic-gate 	for (i = 0; (i < leaf_count) || (*bw_mask == 0x00); i++) {
3182*7c478bd9Sstevel@tonic-gate 		fbp = &ehcip->ehci_frame_bandwidth[leaf + i];
3183*7c478bd9Sstevel@tonic-gate 
3184*7c478bd9Sstevel@tonic-gate 		total_bandwidth += fbp->ehci_allocated_frame_bandwidth;
3185*7c478bd9Sstevel@tonic-gate 
3186*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < EHCI_MAX_UFRAMES; j++) {
3187*7c478bd9Sstevel@tonic-gate 			/*
3188*7c478bd9Sstevel@tonic-gate 			 * If the uFrame in bw_mask is available check to see if
3189*7c478bd9Sstevel@tonic-gate 			 * it can support the additional bandwidth.
3190*7c478bd9Sstevel@tonic-gate 			 */
3191*7c478bd9Sstevel@tonic-gate 			bw_uframe = (*bw_mask & (0x1 << j));
3192*7c478bd9Sstevel@tonic-gate 			uframe_total =
3193*7c478bd9Sstevel@tonic-gate 			    fbp->ehci_micro_frame_bandwidth[j] +
3194*7c478bd9Sstevel@tonic-gate 			    bandwidth;
3195*7c478bd9Sstevel@tonic-gate 			if ((bw_uframe) &&
3196*7c478bd9Sstevel@tonic-gate 			    (uframe_total > HS_PERIODIC_BANDWIDTH)) {
3197*7c478bd9Sstevel@tonic-gate 				*bw_mask = *bw_mask & ~bw_uframe;
3198*7c478bd9Sstevel@tonic-gate 			}
3199*7c478bd9Sstevel@tonic-gate 		}
3200*7c478bd9Sstevel@tonic-gate 	}
3201*7c478bd9Sstevel@tonic-gate 
3202*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
3203*7c478bd9Sstevel@tonic-gate 	    "ehci_calculate_bw_availability_mask: bandwidth mask 0x%x",
3204*7c478bd9Sstevel@tonic-gate 	    *bw_mask);
3205*7c478bd9Sstevel@tonic-gate 
3206*7c478bd9Sstevel@tonic-gate 	return (total_bandwidth);
3207*7c478bd9Sstevel@tonic-gate }
3208*7c478bd9Sstevel@tonic-gate 
3209*7c478bd9Sstevel@tonic-gate 
3210*7c478bd9Sstevel@tonic-gate /*
3211*7c478bd9Sstevel@tonic-gate  * ehci_update_bw_availability:
3212*7c478bd9Sstevel@tonic-gate  *
3213*7c478bd9Sstevel@tonic-gate  * The leftmost leaf needs to be in terms of array position and
3214*7c478bd9Sstevel@tonic-gate  * not the actual lattice position.
3215*7c478bd9Sstevel@tonic-gate  */
3216*7c478bd9Sstevel@tonic-gate static void
3217*7c478bd9Sstevel@tonic-gate ehci_update_bw_availability(
3218*7c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
3219*7c478bd9Sstevel@tonic-gate 	int		bandwidth,
3220*7c478bd9Sstevel@tonic-gate 	int		leftmost_leaf,
3221*7c478bd9Sstevel@tonic-gate 	int		leaf_count,
3222*7c478bd9Sstevel@tonic-gate 	uchar_t		mask)
3223*7c478bd9Sstevel@tonic-gate {
3224*7c478bd9Sstevel@tonic-gate 	int			i, j;
3225*7c478bd9Sstevel@tonic-gate 	ehci_frame_bandwidth_t	*fbp;
3226*7c478bd9Sstevel@tonic-gate 	int			uFrame_bandwidth[8];
3227*7c478bd9Sstevel@tonic-gate 
3228*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3229*7c478bd9Sstevel@tonic-gate 	    "ehci_update_bw_availability: "
3230*7c478bd9Sstevel@tonic-gate 	    "leaf %d count %d bandwidth 0x%x mask 0x%x",
3231*7c478bd9Sstevel@tonic-gate 	    leftmost_leaf, leaf_count, bandwidth, mask);
3232*7c478bd9Sstevel@tonic-gate 
3233*7c478bd9Sstevel@tonic-gate 	ASSERT(leftmost_leaf < 32);
3234*7c478bd9Sstevel@tonic-gate 	ASSERT(leftmost_leaf >= 0);
3235*7c478bd9Sstevel@tonic-gate 
3236*7c478bd9Sstevel@tonic-gate 	for (j = 0; j < EHCI_MAX_UFRAMES; j++) {
3237*7c478bd9Sstevel@tonic-gate 		if (mask & 0x1) {
3238*7c478bd9Sstevel@tonic-gate 			uFrame_bandwidth[j] = bandwidth;
3239*7c478bd9Sstevel@tonic-gate 		} else {
3240*7c478bd9Sstevel@tonic-gate 			uFrame_bandwidth[j] = 0;
3241*7c478bd9Sstevel@tonic-gate 		}
3242*7c478bd9Sstevel@tonic-gate 
3243*7c478bd9Sstevel@tonic-gate 		mask = mask >> 1;
3244*7c478bd9Sstevel@tonic-gate 	}
3245*7c478bd9Sstevel@tonic-gate 
3246*7c478bd9Sstevel@tonic-gate 	/* Updated all the effected leafs with the bandwidth */
3247*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < leaf_count; i++) {
3248*7c478bd9Sstevel@tonic-gate 		fbp = &ehcip->ehci_frame_bandwidth[leftmost_leaf + i];
3249*7c478bd9Sstevel@tonic-gate 
3250*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < EHCI_MAX_UFRAMES; j++) {
3251*7c478bd9Sstevel@tonic-gate 			fbp->ehci_micro_frame_bandwidth[j] +=
3252*7c478bd9Sstevel@tonic-gate 			    uFrame_bandwidth[j];
3253*7c478bd9Sstevel@tonic-gate 			fbp->ehci_allocated_frame_bandwidth +=
3254*7c478bd9Sstevel@tonic-gate 			    uFrame_bandwidth[j];
3255*7c478bd9Sstevel@tonic-gate 		}
3256*7c478bd9Sstevel@tonic-gate 	}
3257*7c478bd9Sstevel@tonic-gate }
3258*7c478bd9Sstevel@tonic-gate 
3259*7c478bd9Sstevel@tonic-gate /*
3260*7c478bd9Sstevel@tonic-gate  * Miscellaneous functions
3261*7c478bd9Sstevel@tonic-gate  */
3262*7c478bd9Sstevel@tonic-gate 
3263*7c478bd9Sstevel@tonic-gate /*
3264*7c478bd9Sstevel@tonic-gate  * ehci_obtain_state:
3265*7c478bd9Sstevel@tonic-gate  *
3266*7c478bd9Sstevel@tonic-gate  * NOTE: This function is also called from POLLED MODE.
3267*7c478bd9Sstevel@tonic-gate  */
3268*7c478bd9Sstevel@tonic-gate ehci_state_t *
3269*7c478bd9Sstevel@tonic-gate ehci_obtain_state(dev_info_t	*dip)
3270*7c478bd9Sstevel@tonic-gate {
3271*7c478bd9Sstevel@tonic-gate 	int			instance = ddi_get_instance(dip);
3272*7c478bd9Sstevel@tonic-gate 
3273*7c478bd9Sstevel@tonic-gate 	ehci_state_t *state = ddi_get_soft_state(ehci_statep, instance);
3274*7c478bd9Sstevel@tonic-gate 
3275*7c478bd9Sstevel@tonic-gate 	ASSERT(state != NULL);
3276*7c478bd9Sstevel@tonic-gate 
3277*7c478bd9Sstevel@tonic-gate 	return (state);
3278*7c478bd9Sstevel@tonic-gate }
3279*7c478bd9Sstevel@tonic-gate 
3280*7c478bd9Sstevel@tonic-gate 
3281*7c478bd9Sstevel@tonic-gate /*
3282*7c478bd9Sstevel@tonic-gate  * ehci_state_is_operational:
3283*7c478bd9Sstevel@tonic-gate  *
3284*7c478bd9Sstevel@tonic-gate  * Check the Host controller state and return proper values.
3285*7c478bd9Sstevel@tonic-gate  */
3286*7c478bd9Sstevel@tonic-gate int
3287*7c478bd9Sstevel@tonic-gate ehci_state_is_operational(ehci_state_t	*ehcip)
3288*7c478bd9Sstevel@tonic-gate {
3289*7c478bd9Sstevel@tonic-gate 	int	val;
3290*7c478bd9Sstevel@tonic-gate 
3291*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
3292*7c478bd9Sstevel@tonic-gate 
3293*7c478bd9Sstevel@tonic-gate 	switch (ehcip->ehci_hc_soft_state) {
3294*7c478bd9Sstevel@tonic-gate 	case EHCI_CTLR_INIT_STATE:
3295*7c478bd9Sstevel@tonic-gate 	case EHCI_CTLR_SUSPEND_STATE:
3296*7c478bd9Sstevel@tonic-gate 		val = USB_FAILURE;
3297*7c478bd9Sstevel@tonic-gate 		break;
3298*7c478bd9Sstevel@tonic-gate 	case EHCI_CTLR_OPERATIONAL_STATE:
3299*7c478bd9Sstevel@tonic-gate 		val = USB_SUCCESS;
3300*7c478bd9Sstevel@tonic-gate 		break;
3301*7c478bd9Sstevel@tonic-gate 	case EHCI_CTLR_ERROR_STATE:
3302*7c478bd9Sstevel@tonic-gate 		val = USB_HC_HARDWARE_ERROR;
3303*7c478bd9Sstevel@tonic-gate 		break;
3304*7c478bd9Sstevel@tonic-gate 	default:
3305*7c478bd9Sstevel@tonic-gate 		val = USB_FAILURE;
3306*7c478bd9Sstevel@tonic-gate 		break;
3307*7c478bd9Sstevel@tonic-gate 	}
3308*7c478bd9Sstevel@tonic-gate 
3309*7c478bd9Sstevel@tonic-gate 	return (val);
3310*7c478bd9Sstevel@tonic-gate }
3311*7c478bd9Sstevel@tonic-gate 
3312*7c478bd9Sstevel@tonic-gate 
3313*7c478bd9Sstevel@tonic-gate /*
3314*7c478bd9Sstevel@tonic-gate  * ehci_do_soft_reset
3315*7c478bd9Sstevel@tonic-gate  *
3316*7c478bd9Sstevel@tonic-gate  * Do soft reset of ehci host controller.
3317*7c478bd9Sstevel@tonic-gate  */
3318*7c478bd9Sstevel@tonic-gate int
3319*7c478bd9Sstevel@tonic-gate ehci_do_soft_reset(ehci_state_t	*ehcip)
3320*7c478bd9Sstevel@tonic-gate {
3321*7c478bd9Sstevel@tonic-gate 	usb_frame_number_t	before_frame_number, after_frame_number;
3322*7c478bd9Sstevel@tonic-gate 	ehci_regs_t		*ehci_save_regs;
3323*7c478bd9Sstevel@tonic-gate 
3324*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
3325*7c478bd9Sstevel@tonic-gate 
3326*7c478bd9Sstevel@tonic-gate 	/* Increment host controller error count */
3327*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_hc_error++;
3328*7c478bd9Sstevel@tonic-gate 
3329*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
3330*7c478bd9Sstevel@tonic-gate 	    "ehci_do_soft_reset:"
3331*7c478bd9Sstevel@tonic-gate 	    "Reset ehci host controller 0x%x", ehcip->ehci_hc_error);
3332*7c478bd9Sstevel@tonic-gate 
3333*7c478bd9Sstevel@tonic-gate 	/*
3334*7c478bd9Sstevel@tonic-gate 	 * Allocate space for saving current Host Controller
3335*7c478bd9Sstevel@tonic-gate 	 * registers. Don't do any recovery if allocation
3336*7c478bd9Sstevel@tonic-gate 	 * fails.
3337*7c478bd9Sstevel@tonic-gate 	 */
3338*7c478bd9Sstevel@tonic-gate 	ehci_save_regs = (ehci_regs_t *)
3339*7c478bd9Sstevel@tonic-gate 	    kmem_zalloc(sizeof (ehci_regs_t), KM_NOSLEEP);
3340*7c478bd9Sstevel@tonic-gate 
3341*7c478bd9Sstevel@tonic-gate 	if (ehci_save_regs == NULL) {
3342*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR,  ehcip->ehci_log_hdl,
3343*7c478bd9Sstevel@tonic-gate 		    "ehci_do_soft_reset: kmem_zalloc failed");
3344*7c478bd9Sstevel@tonic-gate 
3345*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
3346*7c478bd9Sstevel@tonic-gate 	}
3347*7c478bd9Sstevel@tonic-gate 
3348*7c478bd9Sstevel@tonic-gate 	/* Save current ehci registers */
3349*7c478bd9Sstevel@tonic-gate 	ehci_save_regs->ehci_command = Get_OpReg(ehci_command);
3350*7c478bd9Sstevel@tonic-gate 	ehci_save_regs->ehci_interrupt = Get_OpReg(ehci_interrupt);
3351*7c478bd9Sstevel@tonic-gate 	ehci_save_regs->ehci_ctrl_segment = Get_OpReg(ehci_ctrl_segment);
3352*7c478bd9Sstevel@tonic-gate 	ehci_save_regs->ehci_async_list_addr = Get_OpReg(ehci_async_list_addr);
3353*7c478bd9Sstevel@tonic-gate 	ehci_save_regs->ehci_config_flag = Get_OpReg(ehci_config_flag);
3354*7c478bd9Sstevel@tonic-gate 	ehci_save_regs->ehci_periodic_list_base =
3355*7c478bd9Sstevel@tonic-gate 	    Get_OpReg(ehci_periodic_list_base);
3356*7c478bd9Sstevel@tonic-gate 
3357*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
3358*7c478bd9Sstevel@tonic-gate 	    "ehci_do_soft_reset: Save reg = 0x%p", ehci_save_regs);
3359*7c478bd9Sstevel@tonic-gate 
3360*7c478bd9Sstevel@tonic-gate 	/* Disable all list processing and interrupts */
3361*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_command, Get_OpReg(ehci_command) &
3362*7c478bd9Sstevel@tonic-gate 	    ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE));
3363*7c478bd9Sstevel@tonic-gate 
3364*7c478bd9Sstevel@tonic-gate 	/* Disable all EHCI interrupts */
3365*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_interrupt, 0);
3366*7c478bd9Sstevel@tonic-gate 
3367*7c478bd9Sstevel@tonic-gate 	/* Wait for few milliseconds */
3368*7c478bd9Sstevel@tonic-gate 	drv_usecwait(EHCI_SOF_TIMEWAIT);
3369*7c478bd9Sstevel@tonic-gate 
3370*7c478bd9Sstevel@tonic-gate 	/* Do light soft reset of ehci host controller */
3371*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_command,
3372*7c478bd9Sstevel@tonic-gate 	    Get_OpReg(ehci_command) | EHCI_CMD_LIGHT_HC_RESET);
3373*7c478bd9Sstevel@tonic-gate 
3374*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
3375*7c478bd9Sstevel@tonic-gate 	    "ehci_do_soft_reset: Reset in progress");
3376*7c478bd9Sstevel@tonic-gate 
3377*7c478bd9Sstevel@tonic-gate 	/* Wait for reset to complete */
3378*7c478bd9Sstevel@tonic-gate 	drv_usecwait(EHCI_RESET_TIMEWAIT);
3379*7c478bd9Sstevel@tonic-gate 
3380*7c478bd9Sstevel@tonic-gate 	/*
3381*7c478bd9Sstevel@tonic-gate 	 * Restore previous saved EHCI register value
3382*7c478bd9Sstevel@tonic-gate 	 * into the current EHCI registers.
3383*7c478bd9Sstevel@tonic-gate 	 */
3384*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_ctrl_segment, (uint32_t)
3385*7c478bd9Sstevel@tonic-gate 		ehci_save_regs->ehci_ctrl_segment);
3386*7c478bd9Sstevel@tonic-gate 
3387*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_periodic_list_base, (uint32_t)
3388*7c478bd9Sstevel@tonic-gate 		ehci_save_regs->ehci_periodic_list_base);
3389*7c478bd9Sstevel@tonic-gate 
3390*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_async_list_addr, (uint32_t)
3391*7c478bd9Sstevel@tonic-gate 		ehci_save_regs->ehci_async_list_addr);
3392*7c478bd9Sstevel@tonic-gate 
3393*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_config_flag, (uint32_t)
3394*7c478bd9Sstevel@tonic-gate 		ehci_save_regs->ehci_config_flag);
3395*7c478bd9Sstevel@tonic-gate 
3396*7c478bd9Sstevel@tonic-gate 	/* Enable both Asynchronous and Periodic Schedule if necessary */
3397*7c478bd9Sstevel@tonic-gate 	ehci_toggle_scheduler(ehcip);
3398*7c478bd9Sstevel@tonic-gate 
3399*7c478bd9Sstevel@tonic-gate 	/*
3400*7c478bd9Sstevel@tonic-gate 	 * Set ehci_interrupt to enable all interrupts except Root
3401*7c478bd9Sstevel@tonic-gate 	 * Hub Status change and frame list rollover interrupts.
3402*7c478bd9Sstevel@tonic-gate 	 */
3403*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR |
3404*7c478bd9Sstevel@tonic-gate 	    EHCI_INTR_FRAME_LIST_ROLLOVER |
3405*7c478bd9Sstevel@tonic-gate 	    EHCI_INTR_USB_ERROR |
3406*7c478bd9Sstevel@tonic-gate 	    EHCI_INTR_USB);
3407*7c478bd9Sstevel@tonic-gate 
3408*7c478bd9Sstevel@tonic-gate 	/*
3409*7c478bd9Sstevel@tonic-gate 	 * Deallocate the space that allocated for saving
3410*7c478bd9Sstevel@tonic-gate 	 * HC registers.
3411*7c478bd9Sstevel@tonic-gate 	 */
3412*7c478bd9Sstevel@tonic-gate 	kmem_free((void *) ehci_save_regs, sizeof (ehci_regs_t));
3413*7c478bd9Sstevel@tonic-gate 
3414*7c478bd9Sstevel@tonic-gate 	/*
3415*7c478bd9Sstevel@tonic-gate 	 * Set the desired interrupt threshold, frame list size (if
3416*7c478bd9Sstevel@tonic-gate 	 * applicable) and turn EHCI host controller.
3417*7c478bd9Sstevel@tonic-gate 	 */
3418*7c478bd9Sstevel@tonic-gate 	Set_OpReg(ehci_command, ((Get_OpReg(ehci_command) &
3419*7c478bd9Sstevel@tonic-gate 	    ~EHCI_CMD_INTR_THRESHOLD) |
3420*7c478bd9Sstevel@tonic-gate 	    (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN)));
3421*7c478bd9Sstevel@tonic-gate 
3422*7c478bd9Sstevel@tonic-gate 	/* Wait 10ms for EHCI to start sending SOF */
3423*7c478bd9Sstevel@tonic-gate 	drv_usecwait(EHCI_RESET_TIMEWAIT);
3424*7c478bd9Sstevel@tonic-gate 
3425*7c478bd9Sstevel@tonic-gate 	/*
3426*7c478bd9Sstevel@tonic-gate 	 * Get the current usb frame number before waiting for
3427*7c478bd9Sstevel@tonic-gate 	 * few milliseconds.
3428*7c478bd9Sstevel@tonic-gate 	 */
3429*7c478bd9Sstevel@tonic-gate 	before_frame_number = ehci_get_current_frame_number(ehcip);
3430*7c478bd9Sstevel@tonic-gate 
3431*7c478bd9Sstevel@tonic-gate 	/* Wait for few milliseconds */
3432*7c478bd9Sstevel@tonic-gate 	drv_usecwait(EHCI_SOF_TIMEWAIT);
3433*7c478bd9Sstevel@tonic-gate 
3434*7c478bd9Sstevel@tonic-gate 	/*
3435*7c478bd9Sstevel@tonic-gate 	 * Get the current usb frame number after waiting for
3436*7c478bd9Sstevel@tonic-gate 	 * few milliseconds.
3437*7c478bd9Sstevel@tonic-gate 	 */
3438*7c478bd9Sstevel@tonic-gate 	after_frame_number = ehci_get_current_frame_number(ehcip);
3439*7c478bd9Sstevel@tonic-gate 
3440*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
3441*7c478bd9Sstevel@tonic-gate 	    "ehci_do_soft_reset: Before Frame Number 0x%llx "
3442*7c478bd9Sstevel@tonic-gate 	    "After Frame Number 0x%llx",
3443*7c478bd9Sstevel@tonic-gate 	    before_frame_number, after_frame_number);
3444*7c478bd9Sstevel@tonic-gate 
3445*7c478bd9Sstevel@tonic-gate 	if ((after_frame_number <= before_frame_number) &&
3446*7c478bd9Sstevel@tonic-gate 	    (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) {
3447*7c478bd9Sstevel@tonic-gate 
3448*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
3449*7c478bd9Sstevel@tonic-gate 		    "ehci_do_soft_reset: Soft reset failed");
3450*7c478bd9Sstevel@tonic-gate 
3451*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
3452*7c478bd9Sstevel@tonic-gate 	}
3453*7c478bd9Sstevel@tonic-gate 
3454*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
3455*7c478bd9Sstevel@tonic-gate }
3456*7c478bd9Sstevel@tonic-gate 
3457*7c478bd9Sstevel@tonic-gate 
3458*7c478bd9Sstevel@tonic-gate /*
3459*7c478bd9Sstevel@tonic-gate  * ehci_get_xfer_attrs:
3460*7c478bd9Sstevel@tonic-gate  *
3461*7c478bd9Sstevel@tonic-gate  * Get the attributes of a particular xfer.
3462*7c478bd9Sstevel@tonic-gate  *
3463*7c478bd9Sstevel@tonic-gate  * NOTE: This function is also called from POLLED MODE.
3464*7c478bd9Sstevel@tonic-gate  */
3465*7c478bd9Sstevel@tonic-gate usb_req_attrs_t
3466*7c478bd9Sstevel@tonic-gate ehci_get_xfer_attrs(
3467*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
3468*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
3469*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw)
3470*7c478bd9Sstevel@tonic-gate {
3471*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &pp->pp_pipe_handle->p_ep;
3472*7c478bd9Sstevel@tonic-gate 	usb_req_attrs_t		attrs = USB_ATTRS_NONE;
3473*7c478bd9Sstevel@tonic-gate 
3474*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3475*7c478bd9Sstevel@tonic-gate 	    "ehci_get_xfer_attrs:");
3476*7c478bd9Sstevel@tonic-gate 
3477*7c478bd9Sstevel@tonic-gate 	switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
3478*7c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
3479*7c478bd9Sstevel@tonic-gate 		attrs = ((usb_ctrl_req_t *)
3480*7c478bd9Sstevel@tonic-gate 		    tw->tw_curr_xfer_reqp)->ctrl_attributes;
3481*7c478bd9Sstevel@tonic-gate 		break;
3482*7c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
3483*7c478bd9Sstevel@tonic-gate 		attrs = ((usb_bulk_req_t *)
3484*7c478bd9Sstevel@tonic-gate 		    tw->tw_curr_xfer_reqp)->bulk_attributes;
3485*7c478bd9Sstevel@tonic-gate 		break;
3486*7c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
3487*7c478bd9Sstevel@tonic-gate 		attrs = ((usb_intr_req_t *)
3488*7c478bd9Sstevel@tonic-gate 		    tw->tw_curr_xfer_reqp)->intr_attributes;
3489*7c478bd9Sstevel@tonic-gate 		break;
3490*7c478bd9Sstevel@tonic-gate 	}
3491*7c478bd9Sstevel@tonic-gate 
3492*7c478bd9Sstevel@tonic-gate 	return (attrs);
3493*7c478bd9Sstevel@tonic-gate }
3494*7c478bd9Sstevel@tonic-gate 
3495*7c478bd9Sstevel@tonic-gate 
3496*7c478bd9Sstevel@tonic-gate /*
3497*7c478bd9Sstevel@tonic-gate  * ehci_get_current_frame_number:
3498*7c478bd9Sstevel@tonic-gate  *
3499*7c478bd9Sstevel@tonic-gate  * Get the current software based usb frame number.
3500*7c478bd9Sstevel@tonic-gate  */
3501*7c478bd9Sstevel@tonic-gate usb_frame_number_t
3502*7c478bd9Sstevel@tonic-gate ehci_get_current_frame_number(ehci_state_t *ehcip)
3503*7c478bd9Sstevel@tonic-gate {
3504*7c478bd9Sstevel@tonic-gate 	usb_frame_number_t	usb_frame_number;
3505*7c478bd9Sstevel@tonic-gate 	usb_frame_number_t	ehci_fno, micro_frame_number;
3506*7c478bd9Sstevel@tonic-gate 
3507*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
3508*7c478bd9Sstevel@tonic-gate 
3509*7c478bd9Sstevel@tonic-gate 	ehci_fno = ehcip->ehci_fno;
3510*7c478bd9Sstevel@tonic-gate 	micro_frame_number = Get_OpReg(ehci_frame_index) & 0x3FFF;
3511*7c478bd9Sstevel@tonic-gate 
3512*7c478bd9Sstevel@tonic-gate 	/*
3513*7c478bd9Sstevel@tonic-gate 	 * Calculate current software based usb frame number.
3514*7c478bd9Sstevel@tonic-gate 	 *
3515*7c478bd9Sstevel@tonic-gate 	 * This code accounts for the fact that frame number is
3516*7c478bd9Sstevel@tonic-gate 	 * updated by the Host Controller before the ehci driver
3517*7c478bd9Sstevel@tonic-gate 	 * gets an FrameListRollover interrupt that will adjust
3518*7c478bd9Sstevel@tonic-gate 	 * Frame higher part.
3519*7c478bd9Sstevel@tonic-gate 	 *
3520*7c478bd9Sstevel@tonic-gate 	 * Refer ehci specification 1.0, section 2.3.2, page 21.
3521*7c478bd9Sstevel@tonic-gate 	 */
3522*7c478bd9Sstevel@tonic-gate 	micro_frame_number = ((micro_frame_number & 0x1FFF) |
3523*7c478bd9Sstevel@tonic-gate 	    ehci_fno) + (((micro_frame_number & 0x3FFF) ^
3524*7c478bd9Sstevel@tonic-gate 	    ehci_fno) & 0x2000);
3525*7c478bd9Sstevel@tonic-gate 
3526*7c478bd9Sstevel@tonic-gate 	/*
3527*7c478bd9Sstevel@tonic-gate 	 * Micro Frame number is equivalent to 125 usec. Eight
3528*7c478bd9Sstevel@tonic-gate 	 * Micro Frame numbers are equivalent to one millsecond
3529*7c478bd9Sstevel@tonic-gate 	 * or one usb frame number.
3530*7c478bd9Sstevel@tonic-gate 	 */
3531*7c478bd9Sstevel@tonic-gate 	usb_frame_number = micro_frame_number >>
3532*7c478bd9Sstevel@tonic-gate 	    EHCI_uFRAMES_PER_USB_FRAME_SHIFT;
3533*7c478bd9Sstevel@tonic-gate 
3534*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3535*7c478bd9Sstevel@tonic-gate 	    "ehci_get_current_frame_number: "
3536*7c478bd9Sstevel@tonic-gate 	    "Current usb uframe number = 0x%llx "
3537*7c478bd9Sstevel@tonic-gate 	    "Current usb frame number  = 0x%llx",
3538*7c478bd9Sstevel@tonic-gate 	    micro_frame_number, usb_frame_number);
3539*7c478bd9Sstevel@tonic-gate 
3540*7c478bd9Sstevel@tonic-gate 	return (usb_frame_number);
3541*7c478bd9Sstevel@tonic-gate }
3542*7c478bd9Sstevel@tonic-gate 
3543*7c478bd9Sstevel@tonic-gate 
3544*7c478bd9Sstevel@tonic-gate /*
3545*7c478bd9Sstevel@tonic-gate  * ehci_cpr_cleanup:
3546*7c478bd9Sstevel@tonic-gate  *
3547*7c478bd9Sstevel@tonic-gate  * Cleanup ehci state and other ehci specific informations across
3548*7c478bd9Sstevel@tonic-gate  * Check Point Resume (CPR).
3549*7c478bd9Sstevel@tonic-gate  */
3550*7c478bd9Sstevel@tonic-gate static	void
3551*7c478bd9Sstevel@tonic-gate ehci_cpr_cleanup(ehci_state_t *ehcip)
3552*7c478bd9Sstevel@tonic-gate {
3553*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
3554*7c478bd9Sstevel@tonic-gate 
3555*7c478bd9Sstevel@tonic-gate 	/* Reset software part of usb frame number */
3556*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_fno = 0;
3557*7c478bd9Sstevel@tonic-gate }
3558*7c478bd9Sstevel@tonic-gate 
3559*7c478bd9Sstevel@tonic-gate 
3560*7c478bd9Sstevel@tonic-gate /*
3561*7c478bd9Sstevel@tonic-gate  * ehci_wait_for_sof:
3562*7c478bd9Sstevel@tonic-gate  *
3563*7c478bd9Sstevel@tonic-gate  * Wait for couple of SOF interrupts
3564*7c478bd9Sstevel@tonic-gate  */
3565*7c478bd9Sstevel@tonic-gate int
3566*7c478bd9Sstevel@tonic-gate ehci_wait_for_sof(ehci_state_t	*ehcip)
3567*7c478bd9Sstevel@tonic-gate {
3568*7c478bd9Sstevel@tonic-gate 	usb_frame_number_t	before_frame_number, after_frame_number;
3569*7c478bd9Sstevel@tonic-gate 	int			error = USB_SUCCESS;
3570*7c478bd9Sstevel@tonic-gate 
3571*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS,
3572*7c478bd9Sstevel@tonic-gate 	    ehcip->ehci_log_hdl, "ehci_wait_for_sof");
3573*7c478bd9Sstevel@tonic-gate 
3574*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
3575*7c478bd9Sstevel@tonic-gate 
3576*7c478bd9Sstevel@tonic-gate 	error = ehci_state_is_operational(ehcip);
3577*7c478bd9Sstevel@tonic-gate 
3578*7c478bd9Sstevel@tonic-gate 	if (error != USB_SUCCESS) {
3579*7c478bd9Sstevel@tonic-gate 
3580*7c478bd9Sstevel@tonic-gate 		return (error);
3581*7c478bd9Sstevel@tonic-gate 	}
3582*7c478bd9Sstevel@tonic-gate 
3583*7c478bd9Sstevel@tonic-gate 	/* Get the current usb frame number before waiting for two SOFs */
3584*7c478bd9Sstevel@tonic-gate 	before_frame_number = ehci_get_current_frame_number(ehcip);
3585*7c478bd9Sstevel@tonic-gate 
3586*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
3587*7c478bd9Sstevel@tonic-gate 
3588*7c478bd9Sstevel@tonic-gate 	/* Wait for few milliseconds */
3589*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(EHCI_SOF_TIMEWAIT));
3590*7c478bd9Sstevel@tonic-gate 
3591*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
3592*7c478bd9Sstevel@tonic-gate 
3593*7c478bd9Sstevel@tonic-gate 	/* Get the current usb frame number after woken up */
3594*7c478bd9Sstevel@tonic-gate 	after_frame_number = ehci_get_current_frame_number(ehcip);
3595*7c478bd9Sstevel@tonic-gate 
3596*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3597*7c478bd9Sstevel@tonic-gate 	    "ehci_wait_for_sof: framenumber: before 0x%llx "
3598*7c478bd9Sstevel@tonic-gate 	    "after 0x%llx", before_frame_number, after_frame_number);
3599*7c478bd9Sstevel@tonic-gate 
3600*7c478bd9Sstevel@tonic-gate 	/* Return failure, if usb frame number has not been changed */
3601*7c478bd9Sstevel@tonic-gate 	if (after_frame_number <= before_frame_number) {
3602*7c478bd9Sstevel@tonic-gate 
3603*7c478bd9Sstevel@tonic-gate 		if ((ehci_do_soft_reset(ehcip)) != USB_SUCCESS) {
3604*7c478bd9Sstevel@tonic-gate 
3605*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L0(PRINT_MASK_LISTS,
3606*7c478bd9Sstevel@tonic-gate 			    ehcip->ehci_log_hdl, "No SOF interrupts");
3607*7c478bd9Sstevel@tonic-gate 
3608*7c478bd9Sstevel@tonic-gate 			/* Set host controller soft state to error */
3609*7c478bd9Sstevel@tonic-gate 			ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE;
3610*7c478bd9Sstevel@tonic-gate 
3611*7c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
3612*7c478bd9Sstevel@tonic-gate 		}
3613*7c478bd9Sstevel@tonic-gate 
3614*7c478bd9Sstevel@tonic-gate 		/* Get new usb frame number */
3615*7c478bd9Sstevel@tonic-gate 		after_frame_number = before_frame_number =
3616*7c478bd9Sstevel@tonic-gate 		    ehci_get_current_frame_number(ehcip);
3617*7c478bd9Sstevel@tonic-gate 	}
3618*7c478bd9Sstevel@tonic-gate 
3619*7c478bd9Sstevel@tonic-gate 	ASSERT(after_frame_number > before_frame_number);
3620*7c478bd9Sstevel@tonic-gate 
3621*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
3622*7c478bd9Sstevel@tonic-gate }
3623*7c478bd9Sstevel@tonic-gate 
3624*7c478bd9Sstevel@tonic-gate 
3625*7c478bd9Sstevel@tonic-gate /*
3626*7c478bd9Sstevel@tonic-gate  * ehci_toggle_scheduler:
3627*7c478bd9Sstevel@tonic-gate  *
3628*7c478bd9Sstevel@tonic-gate  * Turn scheduler based on pipe open count.
3629*7c478bd9Sstevel@tonic-gate  */
3630*7c478bd9Sstevel@tonic-gate void
3631*7c478bd9Sstevel@tonic-gate ehci_toggle_scheduler(ehci_state_t *ehcip) {
3632*7c478bd9Sstevel@tonic-gate 	uint_t	temp_reg, cmd_reg;
3633*7c478bd9Sstevel@tonic-gate 
3634*7c478bd9Sstevel@tonic-gate 	cmd_reg = Get_OpReg(ehci_command);
3635*7c478bd9Sstevel@tonic-gate 	temp_reg = cmd_reg;
3636*7c478bd9Sstevel@tonic-gate 
3637*7c478bd9Sstevel@tonic-gate 	/*
3638*7c478bd9Sstevel@tonic-gate 	 * Enable/Disable asynchronous scheduler, and
3639*7c478bd9Sstevel@tonic-gate 	 * turn on/off async list door bell
3640*7c478bd9Sstevel@tonic-gate 	 */
3641*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_open_async_count) {
3642*7c478bd9Sstevel@tonic-gate 		if (!(cmd_reg & EHCI_CMD_ASYNC_SCHED_ENABLE)) {
3643*7c478bd9Sstevel@tonic-gate 			/*
3644*7c478bd9Sstevel@tonic-gate 			 * For some reason this address might get nulled out by
3645*7c478bd9Sstevel@tonic-gate 			 * the ehci chip. Set it here just in case it is null.
3646*7c478bd9Sstevel@tonic-gate 			 */
3647*7c478bd9Sstevel@tonic-gate 			Set_OpReg(ehci_async_list_addr,
3648*7c478bd9Sstevel@tonic-gate 			    ehci_qh_cpu_to_iommu(ehcip,
3649*7c478bd9Sstevel@tonic-gate 				ehcip->ehci_head_of_async_sched_list));
3650*7c478bd9Sstevel@tonic-gate 		}
3651*7c478bd9Sstevel@tonic-gate 		cmd_reg |= EHCI_CMD_ASYNC_SCHED_ENABLE;
3652*7c478bd9Sstevel@tonic-gate 	} else {
3653*7c478bd9Sstevel@tonic-gate 		cmd_reg &= ~EHCI_CMD_ASYNC_SCHED_ENABLE;
3654*7c478bd9Sstevel@tonic-gate 	}
3655*7c478bd9Sstevel@tonic-gate 
3656*7c478bd9Sstevel@tonic-gate 	if (ehcip->ehci_open_periodic_count) {
3657*7c478bd9Sstevel@tonic-gate 		if (!(cmd_reg & EHCI_CMD_PERIODIC_SCHED_ENABLE)) {
3658*7c478bd9Sstevel@tonic-gate 			/*
3659*7c478bd9Sstevel@tonic-gate 			 * For some reason this address get's nulled out by
3660*7c478bd9Sstevel@tonic-gate 			 * the ehci chip. Set it here just in case it is null.
3661*7c478bd9Sstevel@tonic-gate 			 */
3662*7c478bd9Sstevel@tonic-gate 			Set_OpReg(ehci_periodic_list_base,
3663*7c478bd9Sstevel@tonic-gate 			    (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address &
3664*7c478bd9Sstevel@tonic-gate 				0xFFFFF000));
3665*7c478bd9Sstevel@tonic-gate 		}
3666*7c478bd9Sstevel@tonic-gate 		cmd_reg |= EHCI_CMD_PERIODIC_SCHED_ENABLE;
3667*7c478bd9Sstevel@tonic-gate 	} else {
3668*7c478bd9Sstevel@tonic-gate 		cmd_reg &= ~EHCI_CMD_PERIODIC_SCHED_ENABLE;
3669*7c478bd9Sstevel@tonic-gate 	}
3670*7c478bd9Sstevel@tonic-gate 
3671*7c478bd9Sstevel@tonic-gate 	/* Just an optimization */
3672*7c478bd9Sstevel@tonic-gate 	if (temp_reg != cmd_reg) {
3673*7c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_command, cmd_reg);
3674*7c478bd9Sstevel@tonic-gate 	}
3675*7c478bd9Sstevel@tonic-gate }
3676*7c478bd9Sstevel@tonic-gate 
3677*7c478bd9Sstevel@tonic-gate /*
3678*7c478bd9Sstevel@tonic-gate  * ehci print functions
3679*7c478bd9Sstevel@tonic-gate  */
3680*7c478bd9Sstevel@tonic-gate 
3681*7c478bd9Sstevel@tonic-gate /*
3682*7c478bd9Sstevel@tonic-gate  * ehci_print_caps:
3683*7c478bd9Sstevel@tonic-gate  */
3684*7c478bd9Sstevel@tonic-gate void
3685*7c478bd9Sstevel@tonic-gate ehci_print_caps(ehci_state_t	*ehcip)
3686*7c478bd9Sstevel@tonic-gate {
3687*7c478bd9Sstevel@tonic-gate 	uint_t			i;
3688*7c478bd9Sstevel@tonic-gate 
3689*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3690*7c478bd9Sstevel@tonic-gate 	    "\n\tUSB 2.0 Host Controller Characteristics\n");
3691*7c478bd9Sstevel@tonic-gate 
3692*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3693*7c478bd9Sstevel@tonic-gate 	    "Caps Length: 0x%x Version: 0x%x\n",
3694*7c478bd9Sstevel@tonic-gate 	    Get_8Cap(ehci_caps_length), Get_16Cap(ehci_version));
3695*7c478bd9Sstevel@tonic-gate 
3696*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3697*7c478bd9Sstevel@tonic-gate 	    "Structural Parameters\n");
3698*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3699*7c478bd9Sstevel@tonic-gate 	    "Port indicators: %s", (Get_Cap(ehci_hcs_params) &
3700*7c478bd9Sstevel@tonic-gate 	    EHCI_HCS_PORT_INDICATOR) ? "Yes" : "No");
3701*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3702*7c478bd9Sstevel@tonic-gate 	    "No of Classic host controllers: 0x%x",
3703*7c478bd9Sstevel@tonic-gate 	    (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_COMP_CTRLS)
3704*7c478bd9Sstevel@tonic-gate 	    >> EHCI_HCS_NUM_COMP_CTRL_SHIFT);
3705*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3706*7c478bd9Sstevel@tonic-gate 	    "No of ports per Classic host controller: 0x%x",
3707*7c478bd9Sstevel@tonic-gate 	    (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS_CC)
3708*7c478bd9Sstevel@tonic-gate 	    >> EHCI_HCS_NUM_PORTS_CC_SHIFT);
3709*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3710*7c478bd9Sstevel@tonic-gate 	    "Port routing rules: %s", (Get_Cap(ehci_hcs_params) &
3711*7c478bd9Sstevel@tonic-gate 	    EHCI_HCS_PORT_ROUTING_RULES) ? "Yes" : "No");
3712*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3713*7c478bd9Sstevel@tonic-gate 	    "Port power control: %s", (Get_Cap(ehci_hcs_params) &
3714*7c478bd9Sstevel@tonic-gate 	    EHCI_HCS_PORT_POWER_CONTROL) ? "Yes" : "No");
3715*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3716*7c478bd9Sstevel@tonic-gate 	    "No of root hub ports: 0x%x\n",
3717*7c478bd9Sstevel@tonic-gate 	    Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS);
3718*7c478bd9Sstevel@tonic-gate 
3719*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3720*7c478bd9Sstevel@tonic-gate 	    "Capability Parameters\n");
3721*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3722*7c478bd9Sstevel@tonic-gate 	    "EHCI extended capability: %s", (Get_Cap(ehci_hcc_params) &
3723*7c478bd9Sstevel@tonic-gate 	    EHCI_HCC_EECP) ? "Yes" : "No");
3724*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3725*7c478bd9Sstevel@tonic-gate 	    "Isoch schedule threshold: 0x%x",
3726*7c478bd9Sstevel@tonic-gate 	    Get_Cap(ehci_hcc_params) & EHCI_HCC_ISOCH_SCHED_THRESHOLD);
3727*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3728*7c478bd9Sstevel@tonic-gate 	    "Async schedule park capability: %s", (Get_Cap(ehci_hcc_params) &
3729*7c478bd9Sstevel@tonic-gate 	    EHCI_HCC_ASYNC_SCHED_PARK_CAP) ? "Yes" : "No");
3730*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3731*7c478bd9Sstevel@tonic-gate 	    "Programmable frame list flag: %s", (Get_Cap(ehci_hcc_params) &
3732*7c478bd9Sstevel@tonic-gate 	    EHCI_HCC_PROG_FRAME_LIST_FLAG) ? "256/512/1024" : "1024");
3733*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3734*7c478bd9Sstevel@tonic-gate 	    "64bit addressing capability: %s\n", (Get_Cap(ehci_hcc_params) &
3735*7c478bd9Sstevel@tonic-gate 	    EHCI_HCC_64BIT_ADDR_CAP) ? "Yes" : "No");
3736*7c478bd9Sstevel@tonic-gate 
3737*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3738*7c478bd9Sstevel@tonic-gate 	    "Classic Port Route Description");
3739*7c478bd9Sstevel@tonic-gate 
3740*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) {
3741*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3742*7c478bd9Sstevel@tonic-gate 		    "\tPort Route 0x%x: 0x%x", i, Get_8Cap(ehci_port_route[i]));
3743*7c478bd9Sstevel@tonic-gate 	}
3744*7c478bd9Sstevel@tonic-gate }
3745*7c478bd9Sstevel@tonic-gate 
3746*7c478bd9Sstevel@tonic-gate 
3747*7c478bd9Sstevel@tonic-gate /*
3748*7c478bd9Sstevel@tonic-gate  * ehci_print_regs:
3749*7c478bd9Sstevel@tonic-gate  */
3750*7c478bd9Sstevel@tonic-gate void
3751*7c478bd9Sstevel@tonic-gate ehci_print_regs(ehci_state_t	*ehcip)
3752*7c478bd9Sstevel@tonic-gate {
3753*7c478bd9Sstevel@tonic-gate 	uint_t			i;
3754*7c478bd9Sstevel@tonic-gate 
3755*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3756*7c478bd9Sstevel@tonic-gate 	    "\n\tEHCI%d Operational Registers\n",
3757*7c478bd9Sstevel@tonic-gate 	    ddi_get_instance(ehcip->ehci_dip));
3758*7c478bd9Sstevel@tonic-gate 
3759*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3760*7c478bd9Sstevel@tonic-gate 	    "Command: 0x%x Status: 0x%x",
3761*7c478bd9Sstevel@tonic-gate 	    Get_OpReg(ehci_command), Get_OpReg(ehci_status));
3762*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3763*7c478bd9Sstevel@tonic-gate 	    "Interrupt: 0x%x Frame Index: 0x%x",
3764*7c478bd9Sstevel@tonic-gate 	    Get_OpReg(ehci_interrupt), Get_OpReg(ehci_frame_index));
3765*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3766*7c478bd9Sstevel@tonic-gate 	    "Control Segment: 0x%x Periodic List Base: 0x%x",
3767*7c478bd9Sstevel@tonic-gate 	    Get_OpReg(ehci_ctrl_segment), Get_OpReg(ehci_periodic_list_base));
3768*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3769*7c478bd9Sstevel@tonic-gate 	    "Async List Addr: 0x%x Config Flag: 0x%x",
3770*7c478bd9Sstevel@tonic-gate 	    Get_OpReg(ehci_async_list_addr), Get_OpReg(ehci_config_flag));
3771*7c478bd9Sstevel@tonic-gate 
3772*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3773*7c478bd9Sstevel@tonic-gate 	    "Root Hub Port Status");
3774*7c478bd9Sstevel@tonic-gate 
3775*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) {
3776*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3777*7c478bd9Sstevel@tonic-gate 		    "\tPort Status 0x%x: 0x%x ", i,
3778*7c478bd9Sstevel@tonic-gate 		    Get_OpReg(ehci_rh_port_status[i]));
3779*7c478bd9Sstevel@tonic-gate 	}
3780*7c478bd9Sstevel@tonic-gate }
3781*7c478bd9Sstevel@tonic-gate 
3782*7c478bd9Sstevel@tonic-gate 
3783*7c478bd9Sstevel@tonic-gate /*
3784*7c478bd9Sstevel@tonic-gate  * ehci_print_qh:
3785*7c478bd9Sstevel@tonic-gate  */
3786*7c478bd9Sstevel@tonic-gate void
3787*7c478bd9Sstevel@tonic-gate ehci_print_qh(
3788*7c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
3789*7c478bd9Sstevel@tonic-gate 	ehci_qh_t	*qh)
3790*7c478bd9Sstevel@tonic-gate {
3791*7c478bd9Sstevel@tonic-gate 	uint_t		i;
3792*7c478bd9Sstevel@tonic-gate 
3793*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3794*7c478bd9Sstevel@tonic-gate 	    "ehci_print_qh: qh = 0x%p", (void *)qh);
3795*7c478bd9Sstevel@tonic-gate 
3796*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3797*7c478bd9Sstevel@tonic-gate 	    "\tqh_link_ptr: 0x%x ", Get_QH(qh->qh_link_ptr));
3798*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3799*7c478bd9Sstevel@tonic-gate 	    "\tqh_ctrl: 0x%x ", Get_QH(qh->qh_ctrl));
3800*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3801*7c478bd9Sstevel@tonic-gate 	    "\tqh_split_ctrl: 0x%x ", Get_QH(qh->qh_split_ctrl));
3802*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3803*7c478bd9Sstevel@tonic-gate 	    "\tqh_curr_qtd: 0x%x ", Get_QH(qh->qh_curr_qtd));
3804*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3805*7c478bd9Sstevel@tonic-gate 	    "\tqh_next_qtd: 0x%x ", Get_QH(qh->qh_next_qtd));
3806*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3807*7c478bd9Sstevel@tonic-gate 	    "\tqh_alt_next_qtd: 0x%x ", Get_QH(qh->qh_alt_next_qtd));
3808*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3809*7c478bd9Sstevel@tonic-gate 	    "\tqh_status: 0x%x ", Get_QH(qh->qh_status));
3810*7c478bd9Sstevel@tonic-gate 
3811*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 5; i++) {
3812*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3813*7c478bd9Sstevel@tonic-gate 		    "\tqh_buf[%d]: 0x%x ", i, Get_QH(qh->qh_buf[i]));
3814*7c478bd9Sstevel@tonic-gate 	}
3815*7c478bd9Sstevel@tonic-gate 
3816*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 5; i++) {
3817*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3818*7c478bd9Sstevel@tonic-gate 		    "\tqh_buf_high[%d]: 0x%x ",
3819*7c478bd9Sstevel@tonic-gate 		    i, Get_QH(qh->qh_buf_high[i]));
3820*7c478bd9Sstevel@tonic-gate 	}
3821*7c478bd9Sstevel@tonic-gate 
3822*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3823*7c478bd9Sstevel@tonic-gate 	    "\tqh_dummy_qtd: 0x%x ", Get_QH(qh->qh_dummy_qtd));
3824*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3825*7c478bd9Sstevel@tonic-gate 	    "\tqh_prev: 0x%x ", Get_QH(qh->qh_prev));
3826*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3827*7c478bd9Sstevel@tonic-gate 	    "\tqh_state: 0x%x ", Get_QH(qh->qh_state));
3828*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3829*7c478bd9Sstevel@tonic-gate 	    "\tqh_reclaim_next: 0x%x ", Get_QH(qh->qh_reclaim_next));
3830*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3831*7c478bd9Sstevel@tonic-gate 	    "\tqh_reclaim_frame: 0x%x ", Get_QH(qh->qh_reclaim_frame));
3832*7c478bd9Sstevel@tonic-gate }
3833*7c478bd9Sstevel@tonic-gate 
3834*7c478bd9Sstevel@tonic-gate 
3835*7c478bd9Sstevel@tonic-gate /*
3836*7c478bd9Sstevel@tonic-gate  * ehci_print_qtd:
3837*7c478bd9Sstevel@tonic-gate  */
3838*7c478bd9Sstevel@tonic-gate void
3839*7c478bd9Sstevel@tonic-gate ehci_print_qtd(
3840*7c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
3841*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t	*qtd)
3842*7c478bd9Sstevel@tonic-gate {
3843*7c478bd9Sstevel@tonic-gate 	uint_t		i;
3844*7c478bd9Sstevel@tonic-gate 
3845*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3846*7c478bd9Sstevel@tonic-gate 	    "ehci_print_qtd: qtd = 0x%p", (void *)qtd);
3847*7c478bd9Sstevel@tonic-gate 
3848*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3849*7c478bd9Sstevel@tonic-gate 	    "\tqtd_next_qtd: 0x%x ", Get_QTD(qtd->qtd_next_qtd));
3850*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3851*7c478bd9Sstevel@tonic-gate 	    "\tqtd_alt_next_qtd: 0x%x ", Get_QTD(qtd->qtd_alt_next_qtd));
3852*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3853*7c478bd9Sstevel@tonic-gate 	    "\tqtd_ctrl: 0x%x ", Get_QTD(qtd->qtd_ctrl));
3854*7c478bd9Sstevel@tonic-gate 
3855*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 5; i++) {
3856*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3857*7c478bd9Sstevel@tonic-gate 		    "\tqtd_buf[%d]: 0x%x ", i, Get_QTD(qtd->qtd_buf[i]));
3858*7c478bd9Sstevel@tonic-gate 	}
3859*7c478bd9Sstevel@tonic-gate 
3860*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 5; i++) {
3861*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3862*7c478bd9Sstevel@tonic-gate 		    "\tqtd_buf_high[%d]: 0x%x ",
3863*7c478bd9Sstevel@tonic-gate 		    i, Get_QTD(qtd->qtd_buf_high[i]));
3864*7c478bd9Sstevel@tonic-gate 	}
3865*7c478bd9Sstevel@tonic-gate 
3866*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3867*7c478bd9Sstevel@tonic-gate 	    "\tqtd_trans_wrapper: 0x%x ", Get_QTD(qtd->qtd_trans_wrapper));
3868*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3869*7c478bd9Sstevel@tonic-gate 	    "\tqtd_tw_next_qtd: 0x%x ", Get_QTD(qtd->qtd_tw_next_qtd));
3870*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3871*7c478bd9Sstevel@tonic-gate 	    "\tqtd_active_qtd_next: 0x%x ", Get_QTD(qtd->qtd_active_qtd_next));
3872*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3873*7c478bd9Sstevel@tonic-gate 	    "\tqtd_active_qtd_prev: 0x%x ", Get_QTD(qtd->qtd_active_qtd_prev));
3874*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3875*7c478bd9Sstevel@tonic-gate 	    "\tqtd_state: 0x%x ", Get_QTD(qtd->qtd_state));
3876*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3877*7c478bd9Sstevel@tonic-gate 	    "\tqtd_ctrl_phase: 0x%x ", Get_QTD(qtd->qtd_ctrl_phase));
3878*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3879*7c478bd9Sstevel@tonic-gate 	    "\tqtd_xfer_addr: 0x%x ", Get_QTD(qtd->qtd_xfer_addr));
3880*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
3881*7c478bd9Sstevel@tonic-gate 	    "\tqtd_xfer_len: 0x%x ", Get_QTD(qtd->qtd_xfer_len));
3882*7c478bd9Sstevel@tonic-gate }
3883*7c478bd9Sstevel@tonic-gate 
3884*7c478bd9Sstevel@tonic-gate /*
3885*7c478bd9Sstevel@tonic-gate  * ehci kstat functions
3886*7c478bd9Sstevel@tonic-gate  */
3887*7c478bd9Sstevel@tonic-gate 
3888*7c478bd9Sstevel@tonic-gate /*
3889*7c478bd9Sstevel@tonic-gate  * ehci_create_stats:
3890*7c478bd9Sstevel@tonic-gate  *
3891*7c478bd9Sstevel@tonic-gate  * Allocate and initialize the ehci kstat structures
3892*7c478bd9Sstevel@tonic-gate  */
3893*7c478bd9Sstevel@tonic-gate void
3894*7c478bd9Sstevel@tonic-gate ehci_create_stats(ehci_state_t	*ehcip)
3895*7c478bd9Sstevel@tonic-gate {
3896*7c478bd9Sstevel@tonic-gate 	char			kstatname[KSTAT_STRLEN];
3897*7c478bd9Sstevel@tonic-gate 	const char		*dname = ddi_driver_name(ehcip->ehci_dip);
3898*7c478bd9Sstevel@tonic-gate 	char			*usbtypes[USB_N_COUNT_KSTATS] =
3899*7c478bd9Sstevel@tonic-gate 				    {"ctrl", "isoch", "bulk", "intr"};
3900*7c478bd9Sstevel@tonic-gate 	uint_t			instance = ehcip->ehci_instance;
3901*7c478bd9Sstevel@tonic-gate 	ehci_intrs_stats_t	*isp;
3902*7c478bd9Sstevel@tonic-gate 	int			i;
3903*7c478bd9Sstevel@tonic-gate 
3904*7c478bd9Sstevel@tonic-gate 	if (EHCI_INTRS_STATS(ehcip) == NULL) {
3905*7c478bd9Sstevel@tonic-gate 		(void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,intrs",
3906*7c478bd9Sstevel@tonic-gate 		    dname, instance);
3907*7c478bd9Sstevel@tonic-gate 		EHCI_INTRS_STATS(ehcip) = kstat_create("usba", instance,
3908*7c478bd9Sstevel@tonic-gate 		    kstatname, "usb_interrupts", KSTAT_TYPE_NAMED,
3909*7c478bd9Sstevel@tonic-gate 		    sizeof (ehci_intrs_stats_t) / sizeof (kstat_named_t),
3910*7c478bd9Sstevel@tonic-gate 		    KSTAT_FLAG_PERSISTENT);
3911*7c478bd9Sstevel@tonic-gate 
3912*7c478bd9Sstevel@tonic-gate 		if (EHCI_INTRS_STATS(ehcip)) {
3913*7c478bd9Sstevel@tonic-gate 			isp = EHCI_INTRS_STATS_DATA(ehcip);
3914*7c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_total,
3915*7c478bd9Sstevel@tonic-gate 			    "Interrupts Total", KSTAT_DATA_UINT64);
3916*7c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_not_claimed,
3917*7c478bd9Sstevel@tonic-gate 			    "Not Claimed", KSTAT_DATA_UINT64);
3918*7c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_async_sched_status,
3919*7c478bd9Sstevel@tonic-gate 			    "Async schedule status", KSTAT_DATA_UINT64);
3920*7c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_periodic_sched_status,
3921*7c478bd9Sstevel@tonic-gate 			    "Periodic sched status", KSTAT_DATA_UINT64);
3922*7c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_empty_async_schedule,
3923*7c478bd9Sstevel@tonic-gate 			    "Empty async schedule", KSTAT_DATA_UINT64);
3924*7c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_host_ctrl_halted,
3925*7c478bd9Sstevel@tonic-gate 			    "Host controller Halted", KSTAT_DATA_UINT64);
3926*7c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_async_advance_intr,
3927*7c478bd9Sstevel@tonic-gate 			    "Intr on async advance", KSTAT_DATA_UINT64);
3928*7c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_host_system_error_intr,
3929*7c478bd9Sstevel@tonic-gate 			    "Host system error", KSTAT_DATA_UINT64);
3930*7c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_frm_list_rollover_intr,
3931*7c478bd9Sstevel@tonic-gate 			    "Frame list rollover", KSTAT_DATA_UINT64);
3932*7c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_rh_port_change_intr,
3933*7c478bd9Sstevel@tonic-gate 			    "Port change detect", KSTAT_DATA_UINT64);
3934*7c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_usb_error_intr,
3935*7c478bd9Sstevel@tonic-gate 			    "USB error interrupt", KSTAT_DATA_UINT64);
3936*7c478bd9Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_usb_intr,
3937*7c478bd9Sstevel@tonic-gate 			    "USB interrupt", KSTAT_DATA_UINT64);
3938*7c478bd9Sstevel@tonic-gate 
3939*7c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS(ehcip)->ks_private = ehcip;
3940*7c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS(ehcip)->ks_update = nulldev;
3941*7c478bd9Sstevel@tonic-gate 			kstat_install(EHCI_INTRS_STATS(ehcip));
3942*7c478bd9Sstevel@tonic-gate 		}
3943*7c478bd9Sstevel@tonic-gate 	}
3944*7c478bd9Sstevel@tonic-gate 
3945*7c478bd9Sstevel@tonic-gate 	if (EHCI_TOTAL_STATS(ehcip) == NULL) {
3946*7c478bd9Sstevel@tonic-gate 		(void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,total",
3947*7c478bd9Sstevel@tonic-gate 		    dname, instance);
3948*7c478bd9Sstevel@tonic-gate 		EHCI_TOTAL_STATS(ehcip) = kstat_create("usba", instance,
3949*7c478bd9Sstevel@tonic-gate 		    kstatname, "usb_byte_count", KSTAT_TYPE_IO, 1,
3950*7c478bd9Sstevel@tonic-gate 		    KSTAT_FLAG_PERSISTENT);
3951*7c478bd9Sstevel@tonic-gate 
3952*7c478bd9Sstevel@tonic-gate 		if (EHCI_TOTAL_STATS(ehcip)) {
3953*7c478bd9Sstevel@tonic-gate 			kstat_install(EHCI_TOTAL_STATS(ehcip));
3954*7c478bd9Sstevel@tonic-gate 		}
3955*7c478bd9Sstevel@tonic-gate 	}
3956*7c478bd9Sstevel@tonic-gate 
3957*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < USB_N_COUNT_KSTATS; i++) {
3958*7c478bd9Sstevel@tonic-gate 		if (ehcip->ehci_count_stats[i] == NULL) {
3959*7c478bd9Sstevel@tonic-gate 			(void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,%s",
3960*7c478bd9Sstevel@tonic-gate 			    dname, instance, usbtypes[i]);
3961*7c478bd9Sstevel@tonic-gate 			ehcip->ehci_count_stats[i] = kstat_create("usba",
3962*7c478bd9Sstevel@tonic-gate 			    instance, kstatname, "usb_byte_count",
3963*7c478bd9Sstevel@tonic-gate 			    KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
3964*7c478bd9Sstevel@tonic-gate 
3965*7c478bd9Sstevel@tonic-gate 			if (ehcip->ehci_count_stats[i]) {
3966*7c478bd9Sstevel@tonic-gate 				kstat_install(ehcip->ehci_count_stats[i]);
3967*7c478bd9Sstevel@tonic-gate 			}
3968*7c478bd9Sstevel@tonic-gate 		}
3969*7c478bd9Sstevel@tonic-gate 	}
3970*7c478bd9Sstevel@tonic-gate }
3971*7c478bd9Sstevel@tonic-gate 
3972*7c478bd9Sstevel@tonic-gate 
3973*7c478bd9Sstevel@tonic-gate /*
3974*7c478bd9Sstevel@tonic-gate  * ehci_destroy_stats:
3975*7c478bd9Sstevel@tonic-gate  *
3976*7c478bd9Sstevel@tonic-gate  * Clean up ehci kstat structures
3977*7c478bd9Sstevel@tonic-gate  */
3978*7c478bd9Sstevel@tonic-gate void
3979*7c478bd9Sstevel@tonic-gate ehci_destroy_stats(ehci_state_t	*ehcip)
3980*7c478bd9Sstevel@tonic-gate {
3981*7c478bd9Sstevel@tonic-gate 	int	i;
3982*7c478bd9Sstevel@tonic-gate 
3983*7c478bd9Sstevel@tonic-gate 	if (EHCI_INTRS_STATS(ehcip)) {
3984*7c478bd9Sstevel@tonic-gate 		kstat_delete(EHCI_INTRS_STATS(ehcip));
3985*7c478bd9Sstevel@tonic-gate 		EHCI_INTRS_STATS(ehcip) = NULL;
3986*7c478bd9Sstevel@tonic-gate 	}
3987*7c478bd9Sstevel@tonic-gate 
3988*7c478bd9Sstevel@tonic-gate 	if (EHCI_TOTAL_STATS(ehcip)) {
3989*7c478bd9Sstevel@tonic-gate 		kstat_delete(EHCI_TOTAL_STATS(ehcip));
3990*7c478bd9Sstevel@tonic-gate 		EHCI_TOTAL_STATS(ehcip) = NULL;
3991*7c478bd9Sstevel@tonic-gate 	}
3992*7c478bd9Sstevel@tonic-gate 
3993*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < USB_N_COUNT_KSTATS; i++) {
3994*7c478bd9Sstevel@tonic-gate 		if (ehcip->ehci_count_stats[i]) {
3995*7c478bd9Sstevel@tonic-gate 			kstat_delete(ehcip->ehci_count_stats[i]);
3996*7c478bd9Sstevel@tonic-gate 			ehcip->ehci_count_stats[i] = NULL;
3997*7c478bd9Sstevel@tonic-gate 		}
3998*7c478bd9Sstevel@tonic-gate 	}
3999*7c478bd9Sstevel@tonic-gate }
4000*7c478bd9Sstevel@tonic-gate 
4001*7c478bd9Sstevel@tonic-gate 
4002*7c478bd9Sstevel@tonic-gate /*
4003*7c478bd9Sstevel@tonic-gate  * ehci_do_intrs_stats:
4004*7c478bd9Sstevel@tonic-gate  *
4005*7c478bd9Sstevel@tonic-gate  * ehci status information
4006*7c478bd9Sstevel@tonic-gate  */
4007*7c478bd9Sstevel@tonic-gate void
4008*7c478bd9Sstevel@tonic-gate ehci_do_intrs_stats(
4009*7c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
4010*7c478bd9Sstevel@tonic-gate 	int		val)
4011*7c478bd9Sstevel@tonic-gate {
4012*7c478bd9Sstevel@tonic-gate 	if (EHCI_INTRS_STATS(ehcip)) {
4013*7c478bd9Sstevel@tonic-gate 		EHCI_INTRS_STATS_DATA(ehcip)->ehci_sts_total.value.ui64++;
4014*7c478bd9Sstevel@tonic-gate 		switch (val) {
4015*7c478bd9Sstevel@tonic-gate 		case EHCI_STS_ASYNC_SCHED_STATUS:
4016*7c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
4017*7c478bd9Sstevel@tonic-gate 			    ehci_sts_async_sched_status.value.ui64++;
4018*7c478bd9Sstevel@tonic-gate 			break;
4019*7c478bd9Sstevel@tonic-gate 		case EHCI_STS_PERIODIC_SCHED_STATUS:
4020*7c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
4021*7c478bd9Sstevel@tonic-gate 			    ehci_sts_periodic_sched_status.value.ui64++;
4022*7c478bd9Sstevel@tonic-gate 			break;
4023*7c478bd9Sstevel@tonic-gate 		case EHCI_STS_EMPTY_ASYNC_SCHEDULE:
4024*7c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
4025*7c478bd9Sstevel@tonic-gate 			    ehci_sts_empty_async_schedule.value.ui64++;
4026*7c478bd9Sstevel@tonic-gate 			break;
4027*7c478bd9Sstevel@tonic-gate 		case EHCI_STS_HOST_CTRL_HALTED:
4028*7c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
4029*7c478bd9Sstevel@tonic-gate 			    ehci_sts_host_ctrl_halted.value.ui64++;
4030*7c478bd9Sstevel@tonic-gate 			break;
4031*7c478bd9Sstevel@tonic-gate 		case EHCI_STS_ASYNC_ADVANCE_INTR:
4032*7c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
4033*7c478bd9Sstevel@tonic-gate 			    ehci_sts_async_advance_intr.value.ui64++;
4034*7c478bd9Sstevel@tonic-gate 			break;
4035*7c478bd9Sstevel@tonic-gate 		case EHCI_STS_HOST_SYSTEM_ERROR_INTR:
4036*7c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
4037*7c478bd9Sstevel@tonic-gate 			    ehci_sts_host_system_error_intr.value.ui64++;
4038*7c478bd9Sstevel@tonic-gate 			break;
4039*7c478bd9Sstevel@tonic-gate 		case EHCI_STS_FRM_LIST_ROLLOVER_INTR:
4040*7c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
4041*7c478bd9Sstevel@tonic-gate 			    ehci_sts_frm_list_rollover_intr.value.ui64++;
4042*7c478bd9Sstevel@tonic-gate 			break;
4043*7c478bd9Sstevel@tonic-gate 		case EHCI_STS_RH_PORT_CHANGE_INTR:
4044*7c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
4045*7c478bd9Sstevel@tonic-gate 			    ehci_sts_rh_port_change_intr.value.ui64++;
4046*7c478bd9Sstevel@tonic-gate 			break;
4047*7c478bd9Sstevel@tonic-gate 		case EHCI_STS_USB_ERROR_INTR:
4048*7c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
4049*7c478bd9Sstevel@tonic-gate 			    ehci_sts_usb_error_intr.value.ui64++;
4050*7c478bd9Sstevel@tonic-gate 			break;
4051*7c478bd9Sstevel@tonic-gate 		case EHCI_STS_USB_INTR:
4052*7c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
4053*7c478bd9Sstevel@tonic-gate 			    ehci_sts_usb_intr.value.ui64++;
4054*7c478bd9Sstevel@tonic-gate 			break;
4055*7c478bd9Sstevel@tonic-gate 		default:
4056*7c478bd9Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
4057*7c478bd9Sstevel@tonic-gate 			    ehci_sts_not_claimed.value.ui64++;
4058*7c478bd9Sstevel@tonic-gate 			break;
4059*7c478bd9Sstevel@tonic-gate 		}
4060*7c478bd9Sstevel@tonic-gate 	}
4061*7c478bd9Sstevel@tonic-gate }
4062*7c478bd9Sstevel@tonic-gate 
4063*7c478bd9Sstevel@tonic-gate 
4064*7c478bd9Sstevel@tonic-gate /*
4065*7c478bd9Sstevel@tonic-gate  * ehci_do_byte_stats:
4066*7c478bd9Sstevel@tonic-gate  *
4067*7c478bd9Sstevel@tonic-gate  * ehci data xfer information
4068*7c478bd9Sstevel@tonic-gate  */
4069*7c478bd9Sstevel@tonic-gate void
4070*7c478bd9Sstevel@tonic-gate ehci_do_byte_stats(
4071*7c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
4072*7c478bd9Sstevel@tonic-gate 	size_t		len,
4073*7c478bd9Sstevel@tonic-gate 	uint8_t		attr,
4074*7c478bd9Sstevel@tonic-gate 	uint8_t		addr)
4075*7c478bd9Sstevel@tonic-gate {
4076*7c478bd9Sstevel@tonic-gate 	uint8_t 	type = attr & USB_EP_ATTR_MASK;
4077*7c478bd9Sstevel@tonic-gate 	uint8_t 	dir = addr & USB_EP_DIR_MASK;
4078*7c478bd9Sstevel@tonic-gate 
4079*7c478bd9Sstevel@tonic-gate 	if (dir == USB_EP_DIR_IN) {
4080*7c478bd9Sstevel@tonic-gate 		EHCI_TOTAL_STATS_DATA(ehcip)->reads++;
4081*7c478bd9Sstevel@tonic-gate 		EHCI_TOTAL_STATS_DATA(ehcip)->nread += len;
4082*7c478bd9Sstevel@tonic-gate 		switch (type) {
4083*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_CONTROL:
4084*7c478bd9Sstevel@tonic-gate 				EHCI_CTRL_STATS(ehcip)->reads++;
4085*7c478bd9Sstevel@tonic-gate 				EHCI_CTRL_STATS(ehcip)->nread += len;
4086*7c478bd9Sstevel@tonic-gate 				break;
4087*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_BULK:
4088*7c478bd9Sstevel@tonic-gate 				EHCI_BULK_STATS(ehcip)->reads++;
4089*7c478bd9Sstevel@tonic-gate 				EHCI_BULK_STATS(ehcip)->nread += len;
4090*7c478bd9Sstevel@tonic-gate 				break;
4091*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_INTR:
4092*7c478bd9Sstevel@tonic-gate 				EHCI_INTR_STATS(ehcip)->reads++;
4093*7c478bd9Sstevel@tonic-gate 				EHCI_INTR_STATS(ehcip)->nread += len;
4094*7c478bd9Sstevel@tonic-gate 				break;
4095*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_ISOCH:
4096*7c478bd9Sstevel@tonic-gate 				EHCI_ISOC_STATS(ehcip)->reads++;
4097*7c478bd9Sstevel@tonic-gate 				EHCI_ISOC_STATS(ehcip)->nread += len;
4098*7c478bd9Sstevel@tonic-gate 				break;
4099*7c478bd9Sstevel@tonic-gate 		}
4100*7c478bd9Sstevel@tonic-gate 	} else if (dir == USB_EP_DIR_OUT) {
4101*7c478bd9Sstevel@tonic-gate 		EHCI_TOTAL_STATS_DATA(ehcip)->writes++;
4102*7c478bd9Sstevel@tonic-gate 		EHCI_TOTAL_STATS_DATA(ehcip)->nwritten += len;
4103*7c478bd9Sstevel@tonic-gate 		switch (type) {
4104*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_CONTROL:
4105*7c478bd9Sstevel@tonic-gate 				EHCI_CTRL_STATS(ehcip)->writes++;
4106*7c478bd9Sstevel@tonic-gate 				EHCI_CTRL_STATS(ehcip)->nwritten += len;
4107*7c478bd9Sstevel@tonic-gate 				break;
4108*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_BULK:
4109*7c478bd9Sstevel@tonic-gate 				EHCI_BULK_STATS(ehcip)->writes++;
4110*7c478bd9Sstevel@tonic-gate 				EHCI_BULK_STATS(ehcip)->nwritten += len;
4111*7c478bd9Sstevel@tonic-gate 				break;
4112*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_INTR:
4113*7c478bd9Sstevel@tonic-gate 				EHCI_INTR_STATS(ehcip)->writes++;
4114*7c478bd9Sstevel@tonic-gate 				EHCI_INTR_STATS(ehcip)->nwritten += len;
4115*7c478bd9Sstevel@tonic-gate 				break;
4116*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_ISOCH:
4117*7c478bd9Sstevel@tonic-gate 				EHCI_ISOC_STATS(ehcip)->writes++;
4118*7c478bd9Sstevel@tonic-gate 				EHCI_ISOC_STATS(ehcip)->nwritten += len;
4119*7c478bd9Sstevel@tonic-gate 				break;
4120*7c478bd9Sstevel@tonic-gate 		}
4121*7c478bd9Sstevel@tonic-gate 	}
4122*7c478bd9Sstevel@tonic-gate }
4123