xref: /onnv-gate/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c (revision 12886:2e278bf762e0)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51458Syq193411  * Common Development and Distribution License (the "License").
61458Syq193411  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
2112733SRaymond.Chen@Sun.COM 
220Sstevel@tonic-gate /*
2312733SRaymond.Chen@Sun.COM  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * EHCI Host Controller Driver (EHCI)
280Sstevel@tonic-gate  *
290Sstevel@tonic-gate  * The EHCI driver is a software driver which interfaces to the Universal
300Sstevel@tonic-gate  * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
310Sstevel@tonic-gate  * the Host Controller is defined by the EHCI Host Controller Interface.
320Sstevel@tonic-gate  *
330Sstevel@tonic-gate  * This module contains the main EHCI driver code which handles all USB
340Sstevel@tonic-gate  * transfers, bandwidth allocations and other general functionalities.
350Sstevel@tonic-gate  */
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h>
380Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_isoch.h>
390Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h>
400Sstevel@tonic-gate 
41965Sgovinda /*
42965Sgovinda  * EHCI MSI tunable:
43965Sgovinda  *
44965Sgovinda  * By default MSI is enabled on all supported platforms except for the
45965Sgovinda  * EHCI controller of ULI1575 South bridge.
46965Sgovinda  */
47965Sgovinda boolean_t ehci_enable_msi = B_TRUE;
48965Sgovinda 
490Sstevel@tonic-gate /* Pointer to the state structure */
500Sstevel@tonic-gate extern void *ehci_statep;
510Sstevel@tonic-gate 
520Sstevel@tonic-gate extern void ehci_handle_endpoint_reclaimation(ehci_state_t *);
530Sstevel@tonic-gate 
540Sstevel@tonic-gate extern uint_t ehci_vt62x2_workaround;
555295Srandyf extern int force_ehci_off;
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /* Adjustable variables for the size of the pools */
580Sstevel@tonic-gate int ehci_qh_pool_size = EHCI_QH_POOL_SIZE;
590Sstevel@tonic-gate int ehci_qtd_pool_size = EHCI_QTD_POOL_SIZE;
600Sstevel@tonic-gate 
610Sstevel@tonic-gate /*
620Sstevel@tonic-gate  * Initialize the values which the order of 32ms intr qh are executed
630Sstevel@tonic-gate  * by the host controller in the lattice tree.
640Sstevel@tonic-gate  */
650Sstevel@tonic-gate static uchar_t ehci_index[EHCI_NUM_INTR_QH_LISTS] =
660Sstevel@tonic-gate 	{0x00, 0x10, 0x08, 0x18,
670Sstevel@tonic-gate 	0x04, 0x14, 0x0c, 0x1c,
680Sstevel@tonic-gate 	0x02, 0x12, 0x0a, 0x1a,
690Sstevel@tonic-gate 	0x06, 0x16, 0x0e, 0x1e,
700Sstevel@tonic-gate 	0x01, 0x11, 0x09, 0x19,
710Sstevel@tonic-gate 	0x05, 0x15, 0x0d, 0x1d,
720Sstevel@tonic-gate 	0x03, 0x13, 0x0b, 0x1b,
730Sstevel@tonic-gate 	0x07, 0x17, 0x0f, 0x1f};
740Sstevel@tonic-gate 
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate  * Initialize the values which are used to calculate start split mask
770Sstevel@tonic-gate  * for the low/full/high speed interrupt and isochronous endpoints.
780Sstevel@tonic-gate  */
790Sstevel@tonic-gate static uint_t ehci_start_split_mask[15] = {
800Sstevel@tonic-gate 		/*
810Sstevel@tonic-gate 		 * For high/full/low speed usb devices. For high speed
820Sstevel@tonic-gate 		 * device with polling interval greater than or equal
830Sstevel@tonic-gate 		 * to 8us (125us).
840Sstevel@tonic-gate 		 */
850Sstevel@tonic-gate 		0x01,	/* 00000001 */
860Sstevel@tonic-gate 		0x02,	/* 00000010 */
870Sstevel@tonic-gate 		0x04,	/* 00000100 */
880Sstevel@tonic-gate 		0x08,	/* 00001000 */
890Sstevel@tonic-gate 		0x10,	/* 00010000 */
900Sstevel@tonic-gate 		0x20,	/* 00100000 */
910Sstevel@tonic-gate 		0x40,	/* 01000000 */
920Sstevel@tonic-gate 		0x80,	/* 10000000 */
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 		/* Only for high speed devices with polling interval 4us */
950Sstevel@tonic-gate 		0x11,	/* 00010001 */
960Sstevel@tonic-gate 		0x22,	/* 00100010 */
970Sstevel@tonic-gate 		0x44,	/* 01000100 */
980Sstevel@tonic-gate 		0x88,	/* 10001000 */
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 		/* Only for high speed devices with polling interval 2us */
1010Sstevel@tonic-gate 		0x55,	/* 01010101 */
1020Sstevel@tonic-gate 		0xaa,	/* 10101010 */
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 		/* Only for high speed devices with polling interval 1us */
1050Sstevel@tonic-gate 		0xff	/* 11111111 */
1060Sstevel@tonic-gate };
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate  * Initialize the values which are used to calculate complete split mask
1100Sstevel@tonic-gate  * for the low/full speed interrupt and isochronous endpoints.
1110Sstevel@tonic-gate  */
1120Sstevel@tonic-gate static uint_t ehci_intr_complete_split_mask[7] = {
1130Sstevel@tonic-gate 		/* Only full/low speed devices */
1140Sstevel@tonic-gate 		0x1c,	/* 00011100 */
1150Sstevel@tonic-gate 		0x38,	/* 00111000 */
1160Sstevel@tonic-gate 		0x70,	/* 01110000 */
1170Sstevel@tonic-gate 		0xe0,	/* 11100000 */
1180Sstevel@tonic-gate 		0x00,	/* Need FSTN feature */
1190Sstevel@tonic-gate 		0x00,	/* Need FSTN feature */
1200Sstevel@tonic-gate 		0x00	/* Need FSTN feature */
1210Sstevel@tonic-gate };
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate  * EHCI Internal Function Prototypes
1260Sstevel@tonic-gate  */
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate /* Host Controller Driver (HCD) initialization functions */
1290Sstevel@tonic-gate void		ehci_set_dma_attributes(ehci_state_t	*ehcip);
1300Sstevel@tonic-gate int		ehci_allocate_pools(ehci_state_t	*ehcip);
1310Sstevel@tonic-gate void		ehci_decode_ddi_dma_addr_bind_handle_result(
1320Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1330Sstevel@tonic-gate 				int			result);
1340Sstevel@tonic-gate int		ehci_map_regs(ehci_state_t		*ehcip);
1350Sstevel@tonic-gate int		ehci_register_intrs_and_init_mutex(
1360Sstevel@tonic-gate 				ehci_state_t		*ehcip);
137965Sgovinda static int	ehci_add_intrs(ehci_state_t		*ehcip,
138965Sgovinda 				int			intr_type);
1391458Syq193411 int		ehci_init_ctlr(ehci_state_t		*ehcip,
1401458Syq193411 				int			init_type);
1410Sstevel@tonic-gate static int	ehci_take_control(ehci_state_t		*ehcip);
1420Sstevel@tonic-gate static int	ehci_init_periodic_frame_lst_table(
1430Sstevel@tonic-gate 				ehci_state_t		*ehcip);
1440Sstevel@tonic-gate static void	ehci_build_interrupt_lattice(
1450Sstevel@tonic-gate 				ehci_state_t		*ehcip);
1460Sstevel@tonic-gate usba_hcdi_ops_t *ehci_alloc_hcdi_ops(ehci_state_t	*ehcip);
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate /* Host Controller Driver (HCD) deinitialization functions */
1490Sstevel@tonic-gate int		ehci_cleanup(ehci_state_t		*ehcip);
150965Sgovinda static void	ehci_rem_intrs(ehci_state_t		*ehcip);
1510Sstevel@tonic-gate int		ehci_cpr_suspend(ehci_state_t		*ehcip);
1520Sstevel@tonic-gate int		ehci_cpr_resume(ehci_state_t		*ehcip);
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate /* Bandwidth Allocation functions */
1550Sstevel@tonic-gate int		ehci_allocate_bandwidth(ehci_state_t	*ehcip,
1560Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
1570Sstevel@tonic-gate 				uint_t			*pnode,
1580Sstevel@tonic-gate 				uchar_t			*smask,
1590Sstevel@tonic-gate 				uchar_t			*cmask);
1600Sstevel@tonic-gate static int	ehci_allocate_high_speed_bandwidth(
1610Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1620Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
1630Sstevel@tonic-gate 				uint_t			*hnode,
1640Sstevel@tonic-gate 				uchar_t			*smask,
1650Sstevel@tonic-gate 				uchar_t			*cmask);
1660Sstevel@tonic-gate static int	ehci_allocate_classic_tt_bandwidth(
1670Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1680Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
1690Sstevel@tonic-gate 				uint_t			pnode);
1700Sstevel@tonic-gate void		ehci_deallocate_bandwidth(ehci_state_t	*ehcip,
1710Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
1720Sstevel@tonic-gate 				uint_t			pnode,
1730Sstevel@tonic-gate 				uchar_t			smask,
1740Sstevel@tonic-gate 				uchar_t			cmask);
1750Sstevel@tonic-gate static void	ehci_deallocate_high_speed_bandwidth(
1760Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1770Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
1780Sstevel@tonic-gate 				uint_t			hnode,
1790Sstevel@tonic-gate 				uchar_t			smask,
1800Sstevel@tonic-gate 				uchar_t			cmask);
1810Sstevel@tonic-gate static void	ehci_deallocate_classic_tt_bandwidth(
1820Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1830Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
1840Sstevel@tonic-gate 				uint_t			pnode);
1850Sstevel@tonic-gate static int	ehci_compute_high_speed_bandwidth(
1860Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1870Sstevel@tonic-gate 				usb_ep_descr_t		*endpoint,
1880Sstevel@tonic-gate 				usb_port_status_t	port_status,
1890Sstevel@tonic-gate 				uint_t			*sbandwidth,
1900Sstevel@tonic-gate 				uint_t			*cbandwidth);
1910Sstevel@tonic-gate static int	ehci_compute_classic_bandwidth(
1920Sstevel@tonic-gate 				usb_ep_descr_t		*endpoint,
1930Sstevel@tonic-gate 				usb_port_status_t	port_status,
1940Sstevel@tonic-gate 				uint_t			*bandwidth);
1950Sstevel@tonic-gate int		ehci_adjust_polling_interval(
1960Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1970Sstevel@tonic-gate 				usb_ep_descr_t		*endpoint,
1980Sstevel@tonic-gate 				usb_port_status_t	port_status);
1990Sstevel@tonic-gate static int	ehci_adjust_high_speed_polling_interval(
2000Sstevel@tonic-gate 				ehci_state_t		*ehcip,
2010Sstevel@tonic-gate 				usb_ep_descr_t		*endpoint);
2020Sstevel@tonic-gate static uint_t	ehci_lattice_height(uint_t		interval);
2030Sstevel@tonic-gate static uint_t	ehci_lattice_parent(uint_t		node);
2040Sstevel@tonic-gate static uint_t	ehci_find_periodic_node(
2050Sstevel@tonic-gate 				uint_t			leaf,
2060Sstevel@tonic-gate 				int			interval);
2070Sstevel@tonic-gate static uint_t	ehci_leftmost_leaf(uint_t		node,
2080Sstevel@tonic-gate 				uint_t			height);
2090Sstevel@tonic-gate static uint_t	ehci_pow_2(uint_t x);
2100Sstevel@tonic-gate static uint_t	ehci_log_2(uint_t x);
2110Sstevel@tonic-gate static int	ehci_find_bestfit_hs_mask(
2120Sstevel@tonic-gate 				ehci_state_t		*ehcip,
2130Sstevel@tonic-gate 				uchar_t			*smask,
2140Sstevel@tonic-gate 				uint_t			*pnode,
2150Sstevel@tonic-gate 				usb_ep_descr_t		*endpoint,
2160Sstevel@tonic-gate 				uint_t			bandwidth,
2170Sstevel@tonic-gate 				int			interval);
2180Sstevel@tonic-gate static int	ehci_find_bestfit_ls_intr_mask(
2190Sstevel@tonic-gate 				ehci_state_t		*ehcip,
2200Sstevel@tonic-gate 				uchar_t			*smask,
2210Sstevel@tonic-gate 				uchar_t			*cmask,
2220Sstevel@tonic-gate 				uint_t			*pnode,
2230Sstevel@tonic-gate 				uint_t			sbandwidth,
2240Sstevel@tonic-gate 				uint_t			cbandwidth,
2250Sstevel@tonic-gate 				int			interval);
2260Sstevel@tonic-gate static int	ehci_find_bestfit_sitd_in_mask(
2270Sstevel@tonic-gate 				ehci_state_t		*ehcip,
2280Sstevel@tonic-gate 				uchar_t			*smask,
2290Sstevel@tonic-gate 				uchar_t			*cmask,
2300Sstevel@tonic-gate 				uint_t			*pnode,
2310Sstevel@tonic-gate 				uint_t			sbandwidth,
2320Sstevel@tonic-gate 				uint_t			cbandwidth,
2330Sstevel@tonic-gate 				int			interval);
2340Sstevel@tonic-gate static int	ehci_find_bestfit_sitd_out_mask(
2350Sstevel@tonic-gate 				ehci_state_t		*ehcip,
2360Sstevel@tonic-gate 				uchar_t			*smask,
2370Sstevel@tonic-gate 				uint_t			*pnode,
2380Sstevel@tonic-gate 				uint_t			sbandwidth,
2390Sstevel@tonic-gate 				int			interval);
2400Sstevel@tonic-gate static uint_t	ehci_calculate_bw_availability_mask(
2410Sstevel@tonic-gate 				ehci_state_t		*ehcip,
2420Sstevel@tonic-gate 				uint_t			bandwidth,
2430Sstevel@tonic-gate 				int			leaf,
2440Sstevel@tonic-gate 				int			leaf_count,
2450Sstevel@tonic-gate 				uchar_t			*bw_mask);
2460Sstevel@tonic-gate static void	ehci_update_bw_availability(
2470Sstevel@tonic-gate 				ehci_state_t		*ehcip,
2480Sstevel@tonic-gate 				int			bandwidth,
2490Sstevel@tonic-gate 				int			leftmost_leaf,
2500Sstevel@tonic-gate 				int			leaf_count,
2510Sstevel@tonic-gate 				uchar_t			mask);
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate /* Miscellaneous functions */
2540Sstevel@tonic-gate ehci_state_t	*ehci_obtain_state(
2550Sstevel@tonic-gate 				dev_info_t		*dip);
2560Sstevel@tonic-gate int		ehci_state_is_operational(
2570Sstevel@tonic-gate 				ehci_state_t		*ehcip);
2580Sstevel@tonic-gate int		ehci_do_soft_reset(
2590Sstevel@tonic-gate 				ehci_state_t		*ehcip);
2600Sstevel@tonic-gate usb_req_attrs_t ehci_get_xfer_attrs(ehci_state_t	*ehcip,
2610Sstevel@tonic-gate 				ehci_pipe_private_t	*pp,
2620Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw);
2630Sstevel@tonic-gate usb_frame_number_t ehci_get_current_frame_number(
2640Sstevel@tonic-gate 				ehci_state_t		*ehcip);
2650Sstevel@tonic-gate static void	ehci_cpr_cleanup(
2660Sstevel@tonic-gate 				ehci_state_t		*ehcip);
2670Sstevel@tonic-gate int		ehci_wait_for_sof(
2680Sstevel@tonic-gate 				ehci_state_t		*ehcip);
2690Sstevel@tonic-gate void		ehci_toggle_scheduler(
2700Sstevel@tonic-gate 				ehci_state_t		*ehcip);
2710Sstevel@tonic-gate void		ehci_print_caps(ehci_state_t		*ehcip);
2720Sstevel@tonic-gate void		ehci_print_regs(ehci_state_t		*ehcip);
2730Sstevel@tonic-gate void		ehci_print_qh(ehci_state_t		*ehcip,
2740Sstevel@tonic-gate 				ehci_qh_t		*qh);
2750Sstevel@tonic-gate void		ehci_print_qtd(ehci_state_t		*ehcip,
2760Sstevel@tonic-gate 				ehci_qtd_t		*qtd);
2770Sstevel@tonic-gate void		ehci_create_stats(ehci_state_t		*ehcip);
2780Sstevel@tonic-gate void		ehci_destroy_stats(ehci_state_t		*ehcip);
2790Sstevel@tonic-gate void		ehci_do_intrs_stats(ehci_state_t	*ehcip,
2800Sstevel@tonic-gate 				int		val);
2810Sstevel@tonic-gate void		ehci_do_byte_stats(ehci_state_t		*ehcip,
2820Sstevel@tonic-gate 				size_t		len,
2830Sstevel@tonic-gate 				uint8_t		attr,
2840Sstevel@tonic-gate 				uint8_t		addr);
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate /*
287880Sfrits  * check if this ehci controller can support PM
288880Sfrits  */
289880Sfrits int
ehci_hcdi_pm_support(dev_info_t * dip)290880Sfrits ehci_hcdi_pm_support(dev_info_t *dip)
291880Sfrits {
292880Sfrits 	ehci_state_t *ehcip = ddi_get_soft_state(ehci_statep,
2935767Slc152243 	    ddi_get_instance(dip));
294880Sfrits 
295880Sfrits 	if (((ehcip->ehci_vendor_id == PCI_VENDOR_NEC_COMBO) &&
296880Sfrits 	    (ehcip->ehci_device_id == PCI_DEVICE_NEC_COMBO)) ||
297880Sfrits 
298880Sfrits 	    ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
299880Sfrits 	    (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) ||
300880Sfrits 
301880Sfrits 	    (ehcip->ehci_vendor_id == PCI_VENDOR_VIA)) {
302880Sfrits 
303880Sfrits 		return (USB_SUCCESS);
304880Sfrits 	}
305880Sfrits 
306880Sfrits 	return (USB_FAILURE);
307880Sfrits }
308880Sfrits 
3097293Sbc224572 void
ehci_dma_attr_workaround(ehci_state_t * ehcip)3107293Sbc224572 ehci_dma_attr_workaround(ehci_state_t	*ehcip)
3117293Sbc224572 {
3127293Sbc224572 	/*
3137293Sbc224572 	 * Some Nvidia chips can not handle qh dma address above 2G.
3147293Sbc224572 	 * The bit 31 of the dma address might be omitted and it will
3157293Sbc224572 	 * cause system crash or other unpredicable result. So force
3167293Sbc224572 	 * the dma address allocated below 2G to make ehci work.
3177293Sbc224572 	 */
3187293Sbc224572 	if (PCI_VENDOR_NVIDIA == ehcip->ehci_vendor_id) {
3197293Sbc224572 		switch (ehcip->ehci_device_id) {
3207293Sbc224572 			case PCI_DEVICE_NVIDIA_CK804:
3217669SBinzi.Cao@Sun.COM 			case PCI_DEVICE_NVIDIA_MCP04:
3227293Sbc224572 				USB_DPRINTF_L2(PRINT_MASK_ATTA,
3237293Sbc224572 				    ehcip->ehci_log_hdl,
3247293Sbc224572 				    "ehci_dma_attr_workaround: NVIDIA dma "
3257293Sbc224572 				    "workaround enabled, force dma address "
3267293Sbc224572 				    "to be allocated below 2G");
3277293Sbc224572 				ehcip->ehci_dma_attr.dma_attr_addr_hi =
3287293Sbc224572 				    0x7fffffffull;
3297293Sbc224572 				break;
3307293Sbc224572 			default:
3317293Sbc224572 				break;
3327293Sbc224572 
3337293Sbc224572 		}
3347293Sbc224572 	}
3357293Sbc224572 }
336880Sfrits 
337880Sfrits /*
3380Sstevel@tonic-gate  * Host Controller Driver (HCD) initialization functions
3390Sstevel@tonic-gate  */
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate /*
3420Sstevel@tonic-gate  * ehci_set_dma_attributes:
3430Sstevel@tonic-gate  *
3440Sstevel@tonic-gate  * Set the limits in the DMA attributes structure. Most of the values used
3450Sstevel@tonic-gate  * in the  DMA limit structures are the default values as specified by	the
3460Sstevel@tonic-gate  * Writing PCI device drivers document.
3470Sstevel@tonic-gate  */
3480Sstevel@tonic-gate void
ehci_set_dma_attributes(ehci_state_t * ehcip)3490Sstevel@tonic-gate ehci_set_dma_attributes(ehci_state_t	*ehcip)
3500Sstevel@tonic-gate {
3510Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3520Sstevel@tonic-gate 	    "ehci_set_dma_attributes:");
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	/* Initialize the DMA attributes */
3550Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_version = DMA_ATTR_V0;
3560Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_addr_lo = 0x00000000ull;
3570Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_addr_hi = 0xfffffffeull;
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	/* 32 bit addressing */
3600Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_count_max = EHCI_DMA_ATTR_COUNT_MAX;
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	/* Byte alignment */
3630Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	/*
3660Sstevel@tonic-gate 	 * Since PCI  specification is byte alignment, the
3670Sstevel@tonic-gate 	 * burst size field should be set to 1 for PCI devices.
3680Sstevel@tonic-gate 	 */
3690Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_burstsizes = 0x1;
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_minxfer = 0x1;
3720Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_maxxfer = EHCI_DMA_ATTR_MAX_XFER;
3730Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_seg = 0xffffffffull;
3740Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_sgllen = 1;
3750Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_granular = EHCI_DMA_ATTR_GRANULAR;
3760Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_flags = 0;
3777293Sbc224572 	ehci_dma_attr_workaround(ehcip);
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate /*
3820Sstevel@tonic-gate  * ehci_allocate_pools:
3830Sstevel@tonic-gate  *
3840Sstevel@tonic-gate  * Allocate the system memory for the Endpoint Descriptor (QH) and for the
3850Sstevel@tonic-gate  * Transfer Descriptor (QTD) pools. Both QH and QTD structures must be aligned
3860Sstevel@tonic-gate  * to a 16 byte boundary.
3870Sstevel@tonic-gate  */
3880Sstevel@tonic-gate int
ehci_allocate_pools(ehci_state_t * ehcip)3890Sstevel@tonic-gate ehci_allocate_pools(ehci_state_t	*ehcip)
3900Sstevel@tonic-gate {
3910Sstevel@tonic-gate 	ddi_device_acc_attr_t		dev_attr;
3920Sstevel@tonic-gate 	size_t				real_length;
3930Sstevel@tonic-gate 	int				result;
3940Sstevel@tonic-gate 	uint_t				ccount;
3950Sstevel@tonic-gate 	int				i;
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3980Sstevel@tonic-gate 	    "ehci_allocate_pools:");
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	/* The host controller will be little endian */
4010Sstevel@tonic-gate 	dev_attr.devacc_attr_version	= DDI_DEVICE_ATTR_V0;
4020Sstevel@tonic-gate 	dev_attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
4030Sstevel@tonic-gate 	dev_attr.devacc_attr_dataorder	= DDI_STRICTORDER_ACC;
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	/* Byte alignment */
4060Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_TD_QH_ALIGNMENT;
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	/* Allocate the QTD pool DMA handle */
4090Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr,
4105767Slc152243 	    DDI_DMA_SLEEP, 0,
4115767Slc152243 	    &ehcip->ehci_qtd_pool_dma_handle) != DDI_SUCCESS) {
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 		goto failure;
4140Sstevel@tonic-gate 	}
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	/* Allocate the memory for the QTD pool */
4170Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(ehcip->ehci_qtd_pool_dma_handle,
4185767Slc152243 	    ehci_qtd_pool_size * sizeof (ehci_qtd_t),
4195767Slc152243 	    &dev_attr,
4205767Slc152243 	    DDI_DMA_CONSISTENT,
4215767Slc152243 	    DDI_DMA_SLEEP,
4225767Slc152243 	    0,
4235767Slc152243 	    (caddr_t *)&ehcip->ehci_qtd_pool_addr,
4245767Slc152243 	    &real_length,
4255767Slc152243 	    &ehcip->ehci_qtd_pool_mem_handle)) {
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 		goto failure;
4280Sstevel@tonic-gate 	}
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	/* Map the QTD pool into the I/O address space */
4310Sstevel@tonic-gate 	result = ddi_dma_addr_bind_handle(
4325767Slc152243 	    ehcip->ehci_qtd_pool_dma_handle,
4335767Slc152243 	    NULL,
4345767Slc152243 	    (caddr_t)ehcip->ehci_qtd_pool_addr,
4355767Slc152243 	    real_length,
4365767Slc152243 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
4375767Slc152243 	    DDI_DMA_SLEEP,
4385767Slc152243 	    NULL,
4395767Slc152243 	    &ehcip->ehci_qtd_pool_cookie,
4405767Slc152243 	    &ccount);
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	bzero((void *)ehcip->ehci_qtd_pool_addr,
4435767Slc152243 	    ehci_qtd_pool_size * sizeof (ehci_qtd_t));
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	/* Process the result */
4460Sstevel@tonic-gate 	if (result == DDI_DMA_MAPPED) {
4470Sstevel@tonic-gate 		/* The cookie count should be 1 */
4480Sstevel@tonic-gate 		if (ccount != 1) {
4490Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4500Sstevel@tonic-gate 			    "ehci_allocate_pools: More than 1 cookie");
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 		goto failure;
4530Sstevel@tonic-gate 		}
4540Sstevel@tonic-gate 	} else {
4550Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4560Sstevel@tonic-gate 		    "ehci_allocate_pools: Result = %d", result);
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 		ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 		goto failure;
4610Sstevel@tonic-gate 	}
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	/*
4640Sstevel@tonic-gate 	 * DMA addresses for QTD pools are bound
4650Sstevel@tonic-gate 	 */
4660Sstevel@tonic-gate 	ehcip->ehci_dma_addr_bind_flag |= EHCI_QTD_POOL_BOUND;
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	/* Initialize the QTD pool */
4690Sstevel@tonic-gate 	for (i = 0; i < ehci_qtd_pool_size; i ++) {
4700Sstevel@tonic-gate 		Set_QTD(ehcip->ehci_qtd_pool_addr[i].
4710Sstevel@tonic-gate 		    qtd_state, EHCI_QTD_FREE);
4720Sstevel@tonic-gate 	}
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	/* Allocate the QTD pool DMA handle */
4750Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(ehcip->ehci_dip,
4765767Slc152243 	    &ehcip->ehci_dma_attr,
4775767Slc152243 	    DDI_DMA_SLEEP,
4785767Slc152243 	    0,
4795767Slc152243 	    &ehcip->ehci_qh_pool_dma_handle) != DDI_SUCCESS) {
4807293Sbc224572 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4817293Sbc224572 		    "ehci_allocate_pools: ddi_dma_alloc_handle failed");
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 		goto failure;
4840Sstevel@tonic-gate 	}
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	/* Allocate the memory for the QH pool */
4870Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(ehcip->ehci_qh_pool_dma_handle,
4885767Slc152243 	    ehci_qh_pool_size * sizeof (ehci_qh_t),
4895767Slc152243 	    &dev_attr,
4905767Slc152243 	    DDI_DMA_CONSISTENT,
4915767Slc152243 	    DDI_DMA_SLEEP,
4925767Slc152243 	    0,
4935767Slc152243 	    (caddr_t *)&ehcip->ehci_qh_pool_addr,
4945767Slc152243 	    &real_length,
4955767Slc152243 	    &ehcip->ehci_qh_pool_mem_handle) != DDI_SUCCESS) {
4967293Sbc224572 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4977293Sbc224572 		    "ehci_allocate_pools: ddi_dma_mem_alloc failed");
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 		goto failure;
5000Sstevel@tonic-gate 	}
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	result = ddi_dma_addr_bind_handle(ehcip->ehci_qh_pool_dma_handle,
5035767Slc152243 	    NULL,
5045767Slc152243 	    (caddr_t)ehcip->ehci_qh_pool_addr,
5055767Slc152243 	    real_length,
5065767Slc152243 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
5075767Slc152243 	    DDI_DMA_SLEEP,
5085767Slc152243 	    NULL,
5095767Slc152243 	    &ehcip->ehci_qh_pool_cookie,
5105767Slc152243 	    &ccount);
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	bzero((void *)ehcip->ehci_qh_pool_addr,
5135767Slc152243 	    ehci_qh_pool_size * sizeof (ehci_qh_t));
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	/* Process the result */
5160Sstevel@tonic-gate 	if (result == DDI_DMA_MAPPED) {
5170Sstevel@tonic-gate 		/* The cookie count should be 1 */
5180Sstevel@tonic-gate 		if (ccount != 1) {
5190Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
5200Sstevel@tonic-gate 			    "ehci_allocate_pools: More than 1 cookie");
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 			goto failure;
5230Sstevel@tonic-gate 		}
5240Sstevel@tonic-gate 	} else {
5250Sstevel@tonic-gate 		ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 		goto failure;
5280Sstevel@tonic-gate 	}
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	/*
5310Sstevel@tonic-gate 	 * DMA addresses for QH pools are bound
5320Sstevel@tonic-gate 	 */
5330Sstevel@tonic-gate 	ehcip->ehci_dma_addr_bind_flag |= EHCI_QH_POOL_BOUND;
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	/* Initialize the QH pool */
5360Sstevel@tonic-gate 	for (i = 0; i < ehci_qh_pool_size; i ++) {
5370Sstevel@tonic-gate 		Set_QH(ehcip->ehci_qh_pool_addr[i].qh_state, EHCI_QH_FREE);
5380Sstevel@tonic-gate 	}
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	/* Byte alignment */
5410Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	return (DDI_SUCCESS);
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate failure:
5460Sstevel@tonic-gate 	/* Byte alignment */
5470Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	return (DDI_FAILURE);
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate /*
5540Sstevel@tonic-gate  * ehci_decode_ddi_dma_addr_bind_handle_result:
5550Sstevel@tonic-gate  *
5560Sstevel@tonic-gate  * Process the return values of ddi_dma_addr_bind_handle()
5570Sstevel@tonic-gate  */
5580Sstevel@tonic-gate void
ehci_decode_ddi_dma_addr_bind_handle_result(ehci_state_t * ehcip,int result)5590Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(
5600Sstevel@tonic-gate 	ehci_state_t	*ehcip,
5610Sstevel@tonic-gate 	int		result)
5620Sstevel@tonic-gate {
5630Sstevel@tonic-gate 	USB_DPRINTF_L2(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
5640Sstevel@tonic-gate 	    "ehci_decode_ddi_dma_addr_bind_handle_result:");
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	switch (result) {
5670Sstevel@tonic-gate 	case DDI_DMA_PARTIAL_MAP:
5680Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl,
5690Sstevel@tonic-gate 		    "Partial transfers not allowed");
5700Sstevel@tonic-gate 		break;
5710Sstevel@tonic-gate 	case DDI_DMA_INUSE:
5720Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
5730Sstevel@tonic-gate 		    "Handle is in use");
5740Sstevel@tonic-gate 		break;
5750Sstevel@tonic-gate 	case DDI_DMA_NORESOURCES:
5760Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
5770Sstevel@tonic-gate 		    "No resources");
5780Sstevel@tonic-gate 		break;
5790Sstevel@tonic-gate 	case DDI_DMA_NOMAPPING:
5800Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
5810Sstevel@tonic-gate 		    "No mapping");
5820Sstevel@tonic-gate 		break;
5830Sstevel@tonic-gate 	case DDI_DMA_TOOBIG:
5840Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
5850Sstevel@tonic-gate 		    "Object is too big");
5860Sstevel@tonic-gate 		break;
5870Sstevel@tonic-gate 	default:
5880Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
5890Sstevel@tonic-gate 		    "Unknown dma error");
5900Sstevel@tonic-gate 	}
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate /*
5950Sstevel@tonic-gate  * ehci_map_regs:
5960Sstevel@tonic-gate  *
5970Sstevel@tonic-gate  * The Host Controller (HC) contains a set of on-chip operational registers
5980Sstevel@tonic-gate  * and which should be mapped into a non-cacheable portion of the  system
5990Sstevel@tonic-gate  * addressable space.
6000Sstevel@tonic-gate  */
6010Sstevel@tonic-gate int
ehci_map_regs(ehci_state_t * ehcip)6020Sstevel@tonic-gate ehci_map_regs(ehci_state_t	*ehcip)
6030Sstevel@tonic-gate {
6040Sstevel@tonic-gate 	ddi_device_acc_attr_t	attr;
6050Sstevel@tonic-gate 	uint16_t		cmd_reg;
6060Sstevel@tonic-gate 	uint_t			length;
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_map_regs:");
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	/* Check to make sure we have memory access */
6110Sstevel@tonic-gate 	if (pci_config_setup(ehcip->ehci_dip,
6125767Slc152243 	    &ehcip->ehci_config_handle) != DDI_SUCCESS) {
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6150Sstevel@tonic-gate 		    "ehci_map_regs: Config error");
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 		return (DDI_FAILURE);
6180Sstevel@tonic-gate 	}
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	/* Make sure Memory Access Enable is set */
6210Sstevel@tonic-gate 	cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	if (!(cmd_reg & PCI_COMM_MAE)) {
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6260Sstevel@tonic-gate 		    "ehci_map_regs: Memory base address access disabled");
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 		return (DDI_FAILURE);
6290Sstevel@tonic-gate 	}
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	/* The host controller will be little endian */
6320Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
6330Sstevel@tonic-gate 	attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
6340Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	/* Map in EHCI Capability registers */
6370Sstevel@tonic-gate 	if (ddi_regs_map_setup(ehcip->ehci_dip, 1,
6380Sstevel@tonic-gate 	    (caddr_t *)&ehcip->ehci_capsp, 0,
6390Sstevel@tonic-gate 	    sizeof (ehci_caps_t), &attr,
6400Sstevel@tonic-gate 	    &ehcip->ehci_caps_handle) != DDI_SUCCESS) {
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6430Sstevel@tonic-gate 		    "ehci_map_regs: Map setup error");
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 		return (DDI_FAILURE);
6460Sstevel@tonic-gate 	}
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	length = ddi_get8(ehcip->ehci_caps_handle,
6490Sstevel@tonic-gate 	    (uint8_t *)&ehcip->ehci_capsp->ehci_caps_length);
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	/* Free the original mapping */
6520Sstevel@tonic-gate 	ddi_regs_map_free(&ehcip->ehci_caps_handle);
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	/* Re-map in EHCI Capability and Operational registers */
6550Sstevel@tonic-gate 	if (ddi_regs_map_setup(ehcip->ehci_dip, 1,
6560Sstevel@tonic-gate 	    (caddr_t *)&ehcip->ehci_capsp, 0,
6570Sstevel@tonic-gate 	    length + sizeof (ehci_regs_t), &attr,
6580Sstevel@tonic-gate 	    &ehcip->ehci_caps_handle) != DDI_SUCCESS) {
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6610Sstevel@tonic-gate 		    "ehci_map_regs: Map setup error");
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 		return (DDI_FAILURE);
6640Sstevel@tonic-gate 	}
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	/* Get the pointer to EHCI Operational Register */
6670Sstevel@tonic-gate 	ehcip->ehci_regsp = (ehci_regs_t *)
6680Sstevel@tonic-gate 	    ((uintptr_t)ehcip->ehci_capsp + length);
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6710Sstevel@tonic-gate 	    "ehci_map_regs: Capsp 0x%p Regsp 0x%p\n",
6726898Sfb209375 	    (void *)ehcip->ehci_capsp, (void *)ehcip->ehci_regsp);
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	return (DDI_SUCCESS);
6750Sstevel@tonic-gate }
6760Sstevel@tonic-gate 
6772191Sszhou /*
6782191Sszhou  * The following simulated polling is for debugging purposes only.
6792191Sszhou  * It is activated on x86 by setting usb-polling=true in GRUB or ehci.conf.
6802191Sszhou  */
6812191Sszhou static int
ehci_is_polled(dev_info_t * dip)6822191Sszhou ehci_is_polled(dev_info_t *dip)
6832191Sszhou {
6842191Sszhou 	int ret;
6852191Sszhou 	char *propval;
6862191Sszhou 
6872191Sszhou 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
6882191Sszhou 	    "usb-polling", &propval) != DDI_SUCCESS)
6892191Sszhou 
6902191Sszhou 		return (0);
6912191Sszhou 
6922191Sszhou 	ret = (strcmp(propval, "true") == 0);
6932191Sszhou 	ddi_prop_free(propval);
6942191Sszhou 
6952191Sszhou 	return (ret);
6962191Sszhou }
6972191Sszhou 
6982191Sszhou static void
ehci_poll_intr(void * arg)6992191Sszhou ehci_poll_intr(void *arg)
7002191Sszhou {
7012191Sszhou 	/* poll every msec */
7022191Sszhou 	for (;;) {
7032191Sszhou 		(void) ehci_intr(arg, NULL);
7042191Sszhou 		delay(drv_usectohz(1000));
7052191Sszhou 	}
7062191Sszhou }
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate /*
7090Sstevel@tonic-gate  * ehci_register_intrs_and_init_mutex:
7100Sstevel@tonic-gate  *
7110Sstevel@tonic-gate  * Register interrupts and initialize each mutex and condition variables
7120Sstevel@tonic-gate  */
7130Sstevel@tonic-gate int
ehci_register_intrs_and_init_mutex(ehci_state_t * ehcip)7140Sstevel@tonic-gate ehci_register_intrs_and_init_mutex(ehci_state_t	*ehcip)
7150Sstevel@tonic-gate {
716965Sgovinda 	int	intr_types;
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate #if defined(__x86)
7190Sstevel@tonic-gate 	uint8_t iline;
7200Sstevel@tonic-gate #endif
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7230Sstevel@tonic-gate 	    "ehci_register_intrs_and_init_mutex:");
7240Sstevel@tonic-gate 
725965Sgovinda 	/*
726965Sgovinda 	 * There is a known MSI hardware bug with the EHCI controller
727965Sgovinda 	 * of ULI1575 southbridge. Hence MSI is disabled for this chip.
728965Sgovinda 	 */
729965Sgovinda 	if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
730965Sgovinda 	    (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) {
731965Sgovinda 		ehcip->ehci_msi_enabled = B_FALSE;
732965Sgovinda 	} else {
733965Sgovinda 		/* Set the MSI enable flag from the global EHCI MSI tunable */
734965Sgovinda 		ehcip->ehci_msi_enabled = ehci_enable_msi;
735965Sgovinda 	}
736965Sgovinda 
7372191Sszhou 	/* launch polling thread instead of enabling pci interrupt */
7382191Sszhou 	if (ehci_is_polled(ehcip->ehci_dip)) {
7392191Sszhou 		extern pri_t maxclsyspri;
7402191Sszhou 
7413435Slg150142 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7422191Sszhou 		    "ehci_register_intrs_and_init_mutex: "
7432191Sszhou 		    "running in simulated polled mode");
7442191Sszhou 
7452191Sszhou 		(void) thread_create(NULL, 0, ehci_poll_intr, ehcip, 0, &p0,
7462191Sszhou 		    TS_RUN, maxclsyspri);
7472191Sszhou 
7482191Sszhou 		goto skip_intr;
7492191Sszhou 	}
7502191Sszhou 
7510Sstevel@tonic-gate #if defined(__x86)
7520Sstevel@tonic-gate 	/*
7530Sstevel@tonic-gate 	 * Make sure that the interrupt pin is connected to the
7540Sstevel@tonic-gate 	 * interrupt controller on x86.	 Interrupt line 255 means
7550Sstevel@tonic-gate 	 * "unknown" or "not connected" (PCI spec 6.2.4, footnote 43).
756880Sfrits 	 * If we would return failure when interrupt line equals 255, then
757828Syq193411 	 * high speed devices will be routed to companion host controllers.
758880Sfrits 	 * However, it is not necessary to return failure here, and
759880Sfrits 	 * o/uhci codes don't check the interrupt line either.
760880Sfrits 	 * But it's good to log a message here for debug purposes.
7610Sstevel@tonic-gate 	 */
7620Sstevel@tonic-gate 	iline = pci_config_get8(ehcip->ehci_config_handle,
7630Sstevel@tonic-gate 	    PCI_CONF_ILINE);
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	if (iline == 255) {
7660Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7670Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
7680Sstevel@tonic-gate 		    "interrupt line value out of range (%d)",
7690Sstevel@tonic-gate 		    iline);
7700Sstevel@tonic-gate 	}
7710Sstevel@tonic-gate #endif	/* __x86 */
7720Sstevel@tonic-gate 
773965Sgovinda 	/* Get supported interrupt types */
774965Sgovinda 	if (ddi_intr_get_supported_types(ehcip->ehci_dip,
775965Sgovinda 	    &intr_types) != DDI_SUCCESS) {
7760Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7770Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
778965Sgovinda 		    "ddi_intr_get_supported_types failed");
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 		return (DDI_FAILURE);
7810Sstevel@tonic-gate 	}
7820Sstevel@tonic-gate 
783965Sgovinda 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
784965Sgovinda 	    "ehci_register_intrs_and_init_mutex: "
785965Sgovinda 	    "supported interrupt types 0x%x", intr_types);
786965Sgovinda 
787965Sgovinda 	if ((intr_types & DDI_INTR_TYPE_MSI) && ehcip->ehci_msi_enabled) {
788965Sgovinda 		if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_MSI)
789965Sgovinda 		    != DDI_SUCCESS) {
790965Sgovinda 			USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
791965Sgovinda 			    "ehci_register_intrs_and_init_mutex: MSI "
792965Sgovinda 			    "registration failed, trying FIXED interrupt \n");
793965Sgovinda 		} else {
794965Sgovinda 			USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
795965Sgovinda 			    "ehci_register_intrs_and_init_mutex: "
796965Sgovinda 			    "Using MSI interrupt type\n");
797965Sgovinda 
798965Sgovinda 			ehcip->ehci_intr_type = DDI_INTR_TYPE_MSI;
799965Sgovinda 			ehcip->ehci_flags |= EHCI_INTR;
800965Sgovinda 		}
801965Sgovinda 	}
802965Sgovinda 
803965Sgovinda 	if ((!(ehcip->ehci_flags & EHCI_INTR)) &&
804965Sgovinda 	    (intr_types & DDI_INTR_TYPE_FIXED)) {
805965Sgovinda 		if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_FIXED)
806965Sgovinda 		    != DDI_SUCCESS) {
807965Sgovinda 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
808965Sgovinda 			    "ehci_register_intrs_and_init_mutex: "
809965Sgovinda 			    "FIXED interrupt registration failed\n");
810965Sgovinda 
811965Sgovinda 			return (DDI_FAILURE);
812965Sgovinda 		}
813965Sgovinda 
814965Sgovinda 		USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
815965Sgovinda 		    "ehci_register_intrs_and_init_mutex: "
816965Sgovinda 		    "Using FIXED interrupt type\n");
817965Sgovinda 
818965Sgovinda 		ehcip->ehci_intr_type = DDI_INTR_TYPE_FIXED;
819965Sgovinda 		ehcip->ehci_flags |= EHCI_INTR;
820965Sgovinda 	}
821965Sgovinda 
8222191Sszhou skip_intr:
823965Sgovinda 	/* Create prototype for advance on async schedule */
824965Sgovinda 	cv_init(&ehcip->ehci_async_schedule_advance_cv,
825965Sgovinda 	    NULL, CV_DRIVER, NULL);
826965Sgovinda 
827965Sgovinda 	return (DDI_SUCCESS);
828965Sgovinda }
829965Sgovinda 
830965Sgovinda 
831965Sgovinda /*
832965Sgovinda  * ehci_add_intrs:
833965Sgovinda  *
834965Sgovinda  * Register FIXED or MSI interrupts.
835965Sgovinda  */
836965Sgovinda static int
ehci_add_intrs(ehci_state_t * ehcip,int intr_type)837965Sgovinda ehci_add_intrs(ehci_state_t	*ehcip,
838965Sgovinda 		int		intr_type)
839965Sgovinda {
840965Sgovinda 	int	actual, avail, intr_size, count = 0;
8415767Slc152243 	int	i, flag, ret;
842965Sgovinda 
843965Sgovinda 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
844965Sgovinda 	    "ehci_add_intrs: interrupt type 0x%x", intr_type);
845965Sgovinda 
846965Sgovinda 	/* Get number of interrupts */
847965Sgovinda 	ret = ddi_intr_get_nintrs(ehcip->ehci_dip, intr_type, &count);
848965Sgovinda 	if ((ret != DDI_SUCCESS) || (count == 0)) {
8490Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
850965Sgovinda 		    "ehci_add_intrs: ddi_intr_get_nintrs() failure, "
851965Sgovinda 		    "ret: %d, count: %d", ret, count);
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 		return (DDI_FAILURE);
8540Sstevel@tonic-gate 	}
8550Sstevel@tonic-gate 
856965Sgovinda 	/* Get number of available interrupts */
857965Sgovinda 	ret = ddi_intr_get_navail(ehcip->ehci_dip, intr_type, &avail);
858965Sgovinda 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
8590Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
860965Sgovinda 		    "ehci_add_intrs: ddi_intr_get_navail() failure, "
861965Sgovinda 		    "ret: %d, count: %d", ret, count);
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 		return (DDI_FAILURE);
8640Sstevel@tonic-gate 	}
8650Sstevel@tonic-gate 
866965Sgovinda 	if (avail < count) {
867965Sgovinda 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
868965Sgovinda 		    "ehci_add_intrs: ehci_add_intrs: nintrs () "
869965Sgovinda 		    "returned %d, navail returned %d\n", count, avail);
870965Sgovinda 	}
871965Sgovinda 
872965Sgovinda 	/* Allocate an array of interrupt handles */
873965Sgovinda 	intr_size = count * sizeof (ddi_intr_handle_t);
874965Sgovinda 	ehcip->ehci_htable = kmem_zalloc(intr_size, KM_SLEEP);
875965Sgovinda 
876965Sgovinda 	flag = (intr_type == DDI_INTR_TYPE_MSI) ?
877965Sgovinda 	    DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL;
878965Sgovinda 
879965Sgovinda 	/* call ddi_intr_alloc() */
880965Sgovinda 	ret = ddi_intr_alloc(ehcip->ehci_dip, ehcip->ehci_htable,
881965Sgovinda 	    intr_type, 0, count, &actual, flag);
882965Sgovinda 
883965Sgovinda 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
884965Sgovinda 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
885965Sgovinda 		    "ehci_add_intrs: ddi_intr_alloc() failed %d", ret);
886965Sgovinda 
887965Sgovinda 		kmem_free(ehcip->ehci_htable, intr_size);
888965Sgovinda 
889965Sgovinda 		return (DDI_FAILURE);
890965Sgovinda 	}
891965Sgovinda 
892965Sgovinda 	if (actual < count) {
893965Sgovinda 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
894965Sgovinda 		    "ehci_add_intrs: Requested: %d, Received: %d\n",
895965Sgovinda 		    count, actual);
896965Sgovinda 
897965Sgovinda 		for (i = 0; i < actual; i++)
898965Sgovinda 			(void) ddi_intr_free(ehcip->ehci_htable[i]);
899965Sgovinda 
900965Sgovinda 		kmem_free(ehcip->ehci_htable, intr_size);
901965Sgovinda 
902965Sgovinda 		return (DDI_FAILURE);
903965Sgovinda 	}
904965Sgovinda 
905965Sgovinda 	ehcip->ehci_intr_cnt = actual;
906965Sgovinda 
907965Sgovinda 	if ((ret = ddi_intr_get_pri(ehcip->ehci_htable[0],
908965Sgovinda 	    &ehcip->ehci_intr_pri)) != DDI_SUCCESS) {
909965Sgovinda 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
910965Sgovinda 		    "ehci_add_intrs: ddi_intr_get_pri() failed %d", ret);
911965Sgovinda 
912965Sgovinda 		for (i = 0; i < actual; i++)
913965Sgovinda 			(void) ddi_intr_free(ehcip->ehci_htable[i]);
914965Sgovinda 
915965Sgovinda 		kmem_free(ehcip->ehci_htable, intr_size);
916965Sgovinda 
917965Sgovinda 		return (DDI_FAILURE);
918965Sgovinda 	}
919965Sgovinda 
920965Sgovinda 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
921965Sgovinda 	    "ehci_add_intrs: Supported Interrupt priority 0x%x",
922965Sgovinda 	    ehcip->ehci_intr_pri);
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	/* Test for high level mutex */
9250Sstevel@tonic-gate 	if (ehcip->ehci_intr_pri >= ddi_intr_get_hilevel_pri()) {
9260Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
927965Sgovinda 		    "ehci_add_intrs: Hi level interrupt not supported");
928965Sgovinda 
929965Sgovinda 		for (i = 0; i < actual; i++)
930965Sgovinda 			(void) ddi_intr_free(ehcip->ehci_htable[i]);
931965Sgovinda 
932965Sgovinda 		kmem_free(ehcip->ehci_htable, intr_size);
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 		return (DDI_FAILURE);
9350Sstevel@tonic-gate 	}
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	/* Initialize the mutex */
9380Sstevel@tonic-gate 	mutex_init(&ehcip->ehci_int_mutex, NULL, MUTEX_DRIVER,
939693Sgovinda 	    DDI_INTR_PRI(ehcip->ehci_intr_pri));
9400Sstevel@tonic-gate 
941965Sgovinda 	/* Call ddi_intr_add_handler() */
942965Sgovinda 	for (i = 0; i < actual; i++) {
943965Sgovinda 		if ((ret = ddi_intr_add_handler(ehcip->ehci_htable[i],
944965Sgovinda 		    ehci_intr, (caddr_t)ehcip,
945965Sgovinda 		    (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
946965Sgovinda 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
947965Sgovinda 			    "ehci_add_intrs:ddi_intr_add_handler() "
948965Sgovinda 			    "failed %d", ret);
949965Sgovinda 
950965Sgovinda 			for (i = 0; i < actual; i++)
951965Sgovinda 				(void) ddi_intr_free(ehcip->ehci_htable[i]);
952965Sgovinda 
953965Sgovinda 			mutex_destroy(&ehcip->ehci_int_mutex);
954965Sgovinda 			kmem_free(ehcip->ehci_htable, intr_size);
955965Sgovinda 
956965Sgovinda 			return (DDI_FAILURE);
957965Sgovinda 		}
958965Sgovinda 	}
959965Sgovinda 
960965Sgovinda 	if ((ret = ddi_intr_get_cap(ehcip->ehci_htable[0],
961965Sgovinda 	    &ehcip->ehci_intr_cap)) != DDI_SUCCESS) {
9620Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
963965Sgovinda 		    "ehci_add_intrs: ddi_intr_get_cap() failed %d", ret);
964965Sgovinda 
965965Sgovinda 		for (i = 0; i < actual; i++) {
966965Sgovinda 			(void) ddi_intr_remove_handler(ehcip->ehci_htable[i]);
967965Sgovinda 			(void) ddi_intr_free(ehcip->ehci_htable[i]);
968965Sgovinda 		}
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 		mutex_destroy(&ehcip->ehci_int_mutex);
971965Sgovinda 		kmem_free(ehcip->ehci_htable, intr_size);
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 		return (DDI_FAILURE);
9740Sstevel@tonic-gate 	}
9750Sstevel@tonic-gate 
976965Sgovinda 	/* Enable all interrupts */
977965Sgovinda 	if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) {
978965Sgovinda 		/* Call ddi_intr_block_enable() for MSI interrupts */
979965Sgovinda 		(void) ddi_intr_block_enable(ehcip->ehci_htable,
980965Sgovinda 		    ehcip->ehci_intr_cnt);
981965Sgovinda 	} else {
982965Sgovinda 		/* Call ddi_intr_enable for MSI or FIXED interrupts */
983965Sgovinda 		for (i = 0; i < ehcip->ehci_intr_cnt; i++)
984965Sgovinda 			(void) ddi_intr_enable(ehcip->ehci_htable[i]);
9850Sstevel@tonic-gate 	}
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	return (DDI_SUCCESS);
9880Sstevel@tonic-gate }
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate /*
9921458Syq193411  * ehci_init_hardware
9930Sstevel@tonic-gate  *
9941458Syq193411  * take control from BIOS, reset EHCI host controller, and check version, etc.
9950Sstevel@tonic-gate  */
9960Sstevel@tonic-gate int
ehci_init_hardware(ehci_state_t * ehcip)9971458Syq193411 ehci_init_hardware(ehci_state_t	*ehcip)
9980Sstevel@tonic-gate {
9990Sstevel@tonic-gate 	int			revision;
10000Sstevel@tonic-gate 	uint16_t		cmd_reg;
10010Sstevel@tonic-gate 	int			abort_on_BIOS_take_over_failure;
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	/* Take control from the BIOS */
10040Sstevel@tonic-gate 	if (ehci_take_control(ehcip) != USB_SUCCESS) {
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 		/* read .conf file properties */
10070Sstevel@tonic-gate 		abort_on_BIOS_take_over_failure =
10085767Slc152243 		    ddi_prop_get_int(DDI_DEV_T_ANY,
10095767Slc152243 		    ehcip->ehci_dip, DDI_PROP_DONTPASS,
10105767Slc152243 		    "abort-on-BIOS-take-over-failure", 0);
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 		if (abort_on_BIOS_take_over_failure) {
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
10150Sstevel@tonic-gate 			    "Unable to take control from BIOS.");
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 			return (DDI_FAILURE);
10180Sstevel@tonic-gate 		}
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
10210Sstevel@tonic-gate 		    "Unable to take control from BIOS. Failure is ignored.");
10220Sstevel@tonic-gate 	}
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	/* set Memory Master Enable */
10250Sstevel@tonic-gate 	cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM);
10260Sstevel@tonic-gate 	cmd_reg |= (PCI_COMM_MAE | PCI_COMM_ME);
10270Sstevel@tonic-gate 	pci_config_put16(ehcip->ehci_config_handle, PCI_CONF_COMM, cmd_reg);
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	/* Reset the EHCI host controller */
10300Sstevel@tonic-gate 	Set_OpReg(ehci_command,
10310Sstevel@tonic-gate 	    Get_OpReg(ehci_command) | EHCI_CMD_HOST_CTRL_RESET);
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	/* Wait 10ms for reset to complete */
10340Sstevel@tonic-gate 	drv_usecwait(EHCI_RESET_TIMEWAIT);
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 	ASSERT(Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED);
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 	/* Verify the version number */
10390Sstevel@tonic-gate 	revision = Get_16Cap(ehci_version);
10400Sstevel@tonic-gate 
10411458Syq193411 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
10421458Syq193411 	    "ehci_init_hardware: Revision 0x%x", revision);
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	/*
10450Sstevel@tonic-gate 	 * EHCI driver supports EHCI host controllers compliant to
10460Sstevel@tonic-gate 	 * 0.95 and higher revisions of EHCI specifications.
10470Sstevel@tonic-gate 	 */
10480Sstevel@tonic-gate 	if (revision < EHCI_REVISION_0_95) {
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 		USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
10510Sstevel@tonic-gate 		    "Revision 0x%x is not supported", revision);
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 		return (DDI_FAILURE);
10540Sstevel@tonic-gate 	}
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 	if (ehcip->ehci_hc_soft_state == EHCI_CTLR_INIT_STATE) {
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 		/* Initialize the Frame list base address area */
10590Sstevel@tonic-gate 		if (ehci_init_periodic_frame_lst_table(ehcip) != DDI_SUCCESS) {
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 			return (DDI_FAILURE);
10620Sstevel@tonic-gate 		}
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 		/*
10650Sstevel@tonic-gate 		 * For performance reasons, do not insert anything into the
10660Sstevel@tonic-gate 		 * asynchronous list or activate the asynch list schedule until
10670Sstevel@tonic-gate 		 * there is a valid QH.
10680Sstevel@tonic-gate 		 */
10690Sstevel@tonic-gate 		ehcip->ehci_head_of_async_sched_list = NULL;
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 		if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) &&
10720Sstevel@tonic-gate 		    (ehci_vt62x2_workaround & EHCI_VIA_ASYNC_SCHEDULE)) {
10730Sstevel@tonic-gate 			/*
10740Sstevel@tonic-gate 			 * The driver is unable to reliably stop the asynch
10750Sstevel@tonic-gate 			 * list schedule on VIA VT6202 controllers, so we
10760Sstevel@tonic-gate 			 * always keep a dummy QH on the list.
10770Sstevel@tonic-gate 			 */
10780Sstevel@tonic-gate 			ehci_qh_t *dummy_async_qh =
10790Sstevel@tonic-gate 			    ehci_alloc_qh(ehcip, NULL, NULL);
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 			Set_QH(dummy_async_qh->qh_link_ptr,
10820Sstevel@tonic-gate 			    ((ehci_qh_cpu_to_iommu(ehcip, dummy_async_qh) &
10830Sstevel@tonic-gate 			    EHCI_QH_LINK_PTR) | EHCI_QH_LINK_REF_QH));
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 			/* Set this QH to be the "head" of the circular list */
10860Sstevel@tonic-gate 			Set_QH(dummy_async_qh->qh_ctrl,
10870Sstevel@tonic-gate 			    Get_QH(dummy_async_qh->qh_ctrl) |
10880Sstevel@tonic-gate 			    EHCI_QH_CTRL_RECLAIM_HEAD);
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 			Set_QH(dummy_async_qh->qh_next_qtd,
10910Sstevel@tonic-gate 			    EHCI_QH_NEXT_QTD_PTR_VALID);
10920Sstevel@tonic-gate 			Set_QH(dummy_async_qh->qh_alt_next_qtd,
10930Sstevel@tonic-gate 			    EHCI_QH_ALT_NEXT_QTD_PTR_VALID);
10940Sstevel@tonic-gate 
10950Sstevel@tonic-gate 			ehcip->ehci_head_of_async_sched_list = dummy_async_qh;
10960Sstevel@tonic-gate 			ehcip->ehci_open_async_count++;
109712733SRaymond.Chen@Sun.COM 			ehcip->ehci_async_req_count++;
10980Sstevel@tonic-gate 		}
10990Sstevel@tonic-gate 	}
11000Sstevel@tonic-gate 
11011458Syq193411 	return (DDI_SUCCESS);
11021458Syq193411 }
11031458Syq193411 
11041458Syq193411 
11051458Syq193411 /*
11061458Syq193411  * ehci_init_workaround
11071458Syq193411  *
11081458Syq193411  * some workarounds during initializing ehci
11091458Syq193411  */
11101458Syq193411 int
ehci_init_workaround(ehci_state_t * ehcip)11111458Syq193411 ehci_init_workaround(ehci_state_t	*ehcip)
11121458Syq193411 {
11130Sstevel@tonic-gate 	/*
11140Sstevel@tonic-gate 	 * Acer Labs Inc. M5273 EHCI controller does not send
11150Sstevel@tonic-gate 	 * interrupts unless the Root hub ports are routed to the EHCI
11160Sstevel@tonic-gate 	 * host controller; so route the ports now, before we test for
11170Sstevel@tonic-gate 	 * the presence of SOFs interrupts.
11180Sstevel@tonic-gate 	 */
11190Sstevel@tonic-gate 	if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) {
11205767Slc152243 		/* Route all Root hub ports to EHCI host controller */
11215767Slc152243 		Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI);
11220Sstevel@tonic-gate 	}
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate 	/*
11250Sstevel@tonic-gate 	 * VIA chips have some issues and may not work reliably.
1126122Shx149380 	 * Revisions >= 0x80 are part of a southbridge and appear
1127122Shx149380 	 * to be reliable with the workaround.
1128880Sfrits 	 * For revisions < 0x80, if we	were bound using class
1129122Shx149380 	 * complain, else proceed. This will allow the user to
1130122Shx149380 	 * bind ehci specifically to this chip and not have the
1131122Shx149380 	 * warnings
11320Sstevel@tonic-gate 	 */
1133122Shx149380 	if (ehcip->ehci_vendor_id == PCI_VENDOR_VIA) {
1134122Shx149380 
11355767Slc152243 		if (ehcip->ehci_rev_id >= PCI_VIA_REVISION_6212) {
1136122Shx149380 
11375773Sqz150045 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11385773Sqz150045 			    "ehci_init_workaround: Applying VIA workarounds "
11395773Sqz150045 			    "for the 6212 chip.");
1140122Shx149380 
11415767Slc152243 		} else if (strcmp(DEVI(ehcip->ehci_dip)->devi_binding_name,
11425773Sqz150045 		    "pciclass,0c0320") == 0) {
11435773Sqz150045 
11445773Sqz150045 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11455773Sqz150045 			    "Due to recently discovered incompatibilities");
11465773Sqz150045 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11475773Sqz150045 			    "with this USB controller, USB2.x transfer");
11485773Sqz150045 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11495773Sqz150045 			    "support has been disabled. This device will");
11505773Sqz150045 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11515773Sqz150045 			    "continue to function as a USB1.x controller.");
11525773Sqz150045 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11535773Sqz150045 			    "If you are interested in enabling USB2.x");
11545773Sqz150045 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11555773Sqz150045 			    "support please, refer to the ehci(7D) man page.");
11565773Sqz150045 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11575773Sqz150045 			    "Please also refer to www.sun.com/io for");
11585773Sqz150045 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11595773Sqz150045 			    "Solaris Ready products and to");
11605773Sqz150045 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11615773Sqz150045 			    "www.sun.com/bigadmin/hcl for additional");
11625773Sqz150045 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11635773Sqz150045 			    "compatible USB products.");
11645773Sqz150045 
11655773Sqz150045 			return (DDI_FAILURE);
11665773Sqz150045 
11675773Sqz150045 			} else if (ehci_vt62x2_workaround) {
11685773Sqz150045 
11695773Sqz150045 			USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11705773Sqz150045 			    "Applying VIA workarounds");
11715767Slc152243 		}
11720Sstevel@tonic-gate 	}
11730Sstevel@tonic-gate 
11741458Syq193411 	return (DDI_SUCCESS);
11751458Syq193411 }
11761458Syq193411 
11771458Syq193411 
11781458Syq193411 /*
11791458Syq193411  * ehci_init_check_status
11801458Syq193411  *
11811458Syq193411  * Check if EHCI host controller is running
11821458Syq193411  */
11831458Syq193411 int
ehci_init_check_status(ehci_state_t * ehcip)11841458Syq193411 ehci_init_check_status(ehci_state_t	*ehcip)
11851458Syq193411 {
11861458Syq193411 	clock_t			sof_time_wait;
11871458Syq193411 
11880Sstevel@tonic-gate 	/*
11890Sstevel@tonic-gate 	 * Get the number of clock ticks to wait.
11900Sstevel@tonic-gate 	 * This is based on the maximum time it takes for a frame list rollover
11910Sstevel@tonic-gate 	 * and maximum time wait for SOFs to begin.
11920Sstevel@tonic-gate 	 */
11930Sstevel@tonic-gate 	sof_time_wait = drv_usectohz((EHCI_NUM_PERIODIC_FRAME_LISTS * 1000) +
11940Sstevel@tonic-gate 	    EHCI_SOF_TIMEWAIT);
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 	/* Tell the ISR to broadcast ehci_async_schedule_advance_cv */
11970Sstevel@tonic-gate 	ehcip->ehci_flags |= EHCI_CV_INTR;
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 	/* We need to add a delay to allow the chip time to start running */
120011066Srafael.vanoni@sun.com 	(void) cv_reltimedwait(&ehcip->ehci_async_schedule_advance_cv,
120111066Srafael.vanoni@sun.com 	    &ehcip->ehci_int_mutex, sof_time_wait, TR_CLOCK_TICK);
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 	/*
12040Sstevel@tonic-gate 	 * Check EHCI host controller is running, otherwise return failure.
12050Sstevel@tonic-gate 	 */
12060Sstevel@tonic-gate 	if ((ehcip->ehci_flags & EHCI_CV_INTR) ||
12070Sstevel@tonic-gate 	    (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) {
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 		USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
12100Sstevel@tonic-gate 		    "No SOF interrupts have been received, this USB EHCI host"
12110Sstevel@tonic-gate 		    "controller is unusable");
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 		/*
12140Sstevel@tonic-gate 		 * Route all Root hub ports to Classic host
12150Sstevel@tonic-gate 		 * controller, in case this is an unusable ALI M5273
12160Sstevel@tonic-gate 		 * EHCI controller.
12170Sstevel@tonic-gate 		 */
12180Sstevel@tonic-gate 		if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) {
12190Sstevel@tonic-gate 			Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC);
12200Sstevel@tonic-gate 		}
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 		return (DDI_FAILURE);
12230Sstevel@tonic-gate 	}
12240Sstevel@tonic-gate 
12251458Syq193411 	return (DDI_SUCCESS);
12261458Syq193411 }
12271458Syq193411 
12281458Syq193411 
12291458Syq193411 /*
12301458Syq193411  * ehci_init_ctlr:
12311458Syq193411  *
12321458Syq193411  * Initialize the Host Controller (HC).
12331458Syq193411  */
12341458Syq193411 int
ehci_init_ctlr(ehci_state_t * ehcip,int init_type)12351458Syq193411 ehci_init_ctlr(ehci_state_t	*ehcip,
12361458Syq193411 		int		init_type)
12371458Syq193411 {
12381458Syq193411 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_init_ctlr:");
12391458Syq193411 
12401458Syq193411 	if (init_type == EHCI_NORMAL_INITIALIZATION) {
12411458Syq193411 
12421458Syq193411 		if (ehci_init_hardware(ehcip) != DDI_SUCCESS) {
12431458Syq193411 
12441458Syq193411 			return (DDI_FAILURE);
12451458Syq193411 		}
12461458Syq193411 	}
12471458Syq193411 
12481458Syq193411 	/*
12491458Syq193411 	 * Check for Asynchronous schedule park capability feature. If this
12501458Syq193411 	 * feature is supported, then, program ehci command register with
12511458Syq193411 	 * appropriate values..
12521458Syq193411 	 */
12531458Syq193411 	if (Get_Cap(ehci_hcc_params) & EHCI_HCC_ASYNC_SCHED_PARK_CAP) {
12541458Syq193411 
12551458Syq193411 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
12561458Syq193411 		    "ehci_init_ctlr: Async park mode is supported");
12571458Syq193411 
12581458Syq193411 		Set_OpReg(ehci_command, (Get_OpReg(ehci_command) |
12591458Syq193411 		    (EHCI_CMD_ASYNC_PARK_ENABLE |
12601458Syq193411 		    EHCI_CMD_ASYNC_PARK_COUNT_3)));
12611458Syq193411 	}
12621458Syq193411 
12631458Syq193411 	/*
12641458Syq193411 	 * Check for programmable periodic frame list feature. If this
12651458Syq193411 	 * feature is supported, then, program ehci command register with
12661458Syq193411 	 * 1024 frame list value.
12671458Syq193411 	 */
12681458Syq193411 	if (Get_Cap(ehci_hcc_params) & EHCI_HCC_PROG_FRAME_LIST_FLAG) {
12691458Syq193411 
12701458Syq193411 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
12711458Syq193411 		    "ehci_init_ctlr: Variable programmable periodic "
12721458Syq193411 		    "frame list is supported");
12731458Syq193411 
12741458Syq193411 		Set_OpReg(ehci_command, (Get_OpReg(ehci_command) |
12751458Syq193411 		    EHCI_CMD_FRAME_1024_SIZE));
12761458Syq193411 	}
12771458Syq193411 
12781458Syq193411 	/*
12791458Syq193411 	 * Currently EHCI driver doesn't support 64 bit addressing.
12801458Syq193411 	 *
12811458Syq193411 	 * If we are using 64 bit addressing capability, then, program
12821458Syq193411 	 * ehci_ctrl_segment register with 4 Gigabyte segment where all
12831458Syq193411 	 * of the interface data structures are allocated.
12841458Syq193411 	 */
12851458Syq193411 	if (Get_Cap(ehci_hcc_params) & EHCI_HCC_64BIT_ADDR_CAP) {
12861458Syq193411 
12871458Syq193411 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
12881458Syq193411 		    "ehci_init_ctlr: EHCI driver doesn't support "
12891458Syq193411 		    "64 bit addressing");
12901458Syq193411 	}
12911458Syq193411 
12921458Syq193411 	/* 64 bit addressing is not support */
12931458Syq193411 	Set_OpReg(ehci_ctrl_segment, 0x00000000);
12941458Syq193411 
12951458Syq193411 	/* Turn on/off the schedulers */
12961458Syq193411 	ehci_toggle_scheduler(ehcip);
12971458Syq193411 
12985773Sqz150045 	/* Set host controller soft state to operational */
12995773Sqz150045 	ehcip->ehci_hc_soft_state = EHCI_CTLR_OPERATIONAL_STATE;
13005773Sqz150045 
13011458Syq193411 	/*
13021458Syq193411 	 * Set the Periodic Frame List Base Address register with the
13031458Syq193411 	 * starting physical address of the Periodic Frame List.
13041458Syq193411 	 */
13051458Syq193411 	Set_OpReg(ehci_periodic_list_base,
13061458Syq193411 	    (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address &
13075767Slc152243 	    EHCI_PERIODIC_LIST_BASE));
13081458Syq193411 
13091458Syq193411 	/*
13101458Syq193411 	 * Set ehci_interrupt to enable all interrupts except Root
13111458Syq193411 	 * Hub Status change interrupt.
13121458Syq193411 	 */
13131458Syq193411 	Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR |
13141458Syq193411 	    EHCI_INTR_FRAME_LIST_ROLLOVER | EHCI_INTR_USB_ERROR |
13151458Syq193411 	    EHCI_INTR_USB);
13161458Syq193411 
13171458Syq193411 	/*
13181458Syq193411 	 * Set the desired interrupt threshold and turn on EHCI host controller.
13191458Syq193411 	 */
13201458Syq193411 	Set_OpReg(ehci_command,
13211458Syq193411 	    ((Get_OpReg(ehci_command) & ~EHCI_CMD_INTR_THRESHOLD) |
13225767Slc152243 	    (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN)));
13231458Syq193411 
13241458Syq193411 	ASSERT(Get_OpReg(ehci_command) & EHCI_CMD_HOST_CTRL_RUN);
13251458Syq193411 
13261458Syq193411 	if (init_type == EHCI_NORMAL_INITIALIZATION) {
13271458Syq193411 
13281458Syq193411 		if (ehci_init_workaround(ehcip) != DDI_SUCCESS) {
13291458Syq193411 
13305773Sqz150045 			/* Set host controller soft state to error */
13315773Sqz150045 			ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE;
13325773Sqz150045 
13331458Syq193411 			return (DDI_FAILURE);
13341458Syq193411 		}
13351458Syq193411 
13361458Syq193411 		if (ehci_init_check_status(ehcip) != DDI_SUCCESS) {
13371458Syq193411 
13385773Sqz150045 			/* Set host controller soft state to error */
13395773Sqz150045 			ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE;
13405773Sqz150045 
13411458Syq193411 			return (DDI_FAILURE);
13421458Syq193411 		}
13431458Syq193411 
13441458Syq193411 		USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
13451458Syq193411 		    "ehci_init_ctlr: SOF's have started");
13461458Syq193411 	}
13470Sstevel@tonic-gate 
13480Sstevel@tonic-gate 	/* Route all Root hub ports to EHCI host controller */
13490Sstevel@tonic-gate 	Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI);
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	return (DDI_SUCCESS);
13520Sstevel@tonic-gate }
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate /*
13550Sstevel@tonic-gate  * ehci_take_control:
13560Sstevel@tonic-gate  *
13570Sstevel@tonic-gate  * Handshake to take EHCI control from BIOS if necessary.  Its only valid for
13580Sstevel@tonic-gate  * x86 machines, because sparc doesn't have a BIOS.
13590Sstevel@tonic-gate  * On x86 machine, the take control process includes
13600Sstevel@tonic-gate  *    o get the base address of the extended capability list
13610Sstevel@tonic-gate  *    o find out the capability for handoff synchronization in the list.
13620Sstevel@tonic-gate  *    o check if BIOS has owned the host controller.
13630Sstevel@tonic-gate  *    o set the OS Owned semaphore bit, ask the BIOS to release the ownership.
13640Sstevel@tonic-gate  *    o wait for a constant time and check if BIOS has relinquished control.
13650Sstevel@tonic-gate  */
13660Sstevel@tonic-gate /* ARGSUSED */
13670Sstevel@tonic-gate static int
ehci_take_control(ehci_state_t * ehcip)13680Sstevel@tonic-gate ehci_take_control(ehci_state_t *ehcip)
13690Sstevel@tonic-gate {
13700Sstevel@tonic-gate #if defined(__x86)
13710Sstevel@tonic-gate 	uint32_t		extended_cap;
13720Sstevel@tonic-gate 	uint32_t		extended_cap_offset;
13730Sstevel@tonic-gate 	uint32_t		extended_cap_id;
13740Sstevel@tonic-gate 	uint_t			retry;
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
13770Sstevel@tonic-gate 	    "ehci_take_control:");
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	/*
13800Sstevel@tonic-gate 	 * According EHCI Spec 2.2.4, get EECP base address from HCCPARAMS
13810Sstevel@tonic-gate 	 * register.
13820Sstevel@tonic-gate 	 */
13830Sstevel@tonic-gate 	extended_cap_offset = (Get_Cap(ehci_hcc_params) & EHCI_HCC_EECP) >>
13840Sstevel@tonic-gate 	    EHCI_HCC_EECP_SHIFT;
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 	/*
13870Sstevel@tonic-gate 	 * According EHCI Spec 2.2.4, if the extended capability offset is
13880Sstevel@tonic-gate 	 * less than 40h then its not valid.  This means we don't need to
13890Sstevel@tonic-gate 	 * worry about BIOS handoff.
13900Sstevel@tonic-gate 	 */
13910Sstevel@tonic-gate 	if (extended_cap_offset < EHCI_HCC_EECP_MIN_OFFSET) {
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
13940Sstevel@tonic-gate 		    "ehci_take_control: Hardware doesn't support legacy.");
13950Sstevel@tonic-gate 
13960Sstevel@tonic-gate 		goto success;
13970Sstevel@tonic-gate 	}
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 	/*
14000Sstevel@tonic-gate 	 * According EHCI Spec 2.1.7, A zero offset indicates the
14010Sstevel@tonic-gate 	 * end of the extended capability list.
14020Sstevel@tonic-gate 	 */
14030Sstevel@tonic-gate 	while (extended_cap_offset) {
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 		/* Get the extended capability value. */
14060Sstevel@tonic-gate 		extended_cap = pci_config_get32(ehcip->ehci_config_handle,
14070Sstevel@tonic-gate 		    extended_cap_offset);
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate 		/* Get the capability ID */
14100Sstevel@tonic-gate 		extended_cap_id = (extended_cap & EHCI_EX_CAP_ID) >>
14110Sstevel@tonic-gate 		    EHCI_EX_CAP_ID_SHIFT;
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 		/* Check if the card support legacy */
14140Sstevel@tonic-gate 		if (extended_cap_id == EHCI_EX_CAP_ID_BIOS_HANDOFF) {
14150Sstevel@tonic-gate 			break;
14160Sstevel@tonic-gate 		}
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate 		/* Get the offset of the next capability */
14190Sstevel@tonic-gate 		extended_cap_offset = (extended_cap & EHCI_EX_CAP_NEXT_PTR) >>
14200Sstevel@tonic-gate 		    EHCI_EX_CAP_NEXT_PTR_SHIFT;
14210Sstevel@tonic-gate 	}
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	/*
14240Sstevel@tonic-gate 	 * Unable to find legacy support in hardware's extended capability list.
14250Sstevel@tonic-gate 	 * This means we don't need to worry about BIOS handoff.
14260Sstevel@tonic-gate 	 */
14270Sstevel@tonic-gate 	if (extended_cap_id != EHCI_EX_CAP_ID_BIOS_HANDOFF) {
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
14300Sstevel@tonic-gate 		    "ehci_take_control: Hardware doesn't support legacy");
14310Sstevel@tonic-gate 
14320Sstevel@tonic-gate 		goto success;
14330Sstevel@tonic-gate 	}
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 	/* Check if BIOS has owned it. */
14360Sstevel@tonic-gate 	if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) {
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
14390Sstevel@tonic-gate 		    "ehci_take_control: BIOS does not own EHCI");
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 		goto success;
14420Sstevel@tonic-gate 	}
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 	/*
14450Sstevel@tonic-gate 	 * According EHCI Spec 5.1, The OS driver initiates an ownership
14460Sstevel@tonic-gate 	 * request by setting the OS Owned semaphore to a one. The OS
14470Sstevel@tonic-gate 	 * waits for the BIOS Owned bit to go to a zero before attempting
14480Sstevel@tonic-gate 	 * to use the EHCI controller. The time that OS must wait for BIOS
14490Sstevel@tonic-gate 	 * to respond to the request for ownership is beyond the scope of
14500Sstevel@tonic-gate 	 * this specification.
14510Sstevel@tonic-gate 	 * It waits up to EHCI_TAKEOVER_WAIT_COUNT*EHCI_TAKEOVER_DELAY ms
14520Sstevel@tonic-gate 	 * for BIOS to release the ownership.
14530Sstevel@tonic-gate 	 */
14540Sstevel@tonic-gate 	extended_cap |= EHCI_LEGSUP_OS_OWNED_SEM;
14550Sstevel@tonic-gate 	pci_config_put32(ehcip->ehci_config_handle, extended_cap_offset,
14560Sstevel@tonic-gate 	    extended_cap);
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate 	for (retry = 0; retry < EHCI_TAKEOVER_WAIT_COUNT; retry++) {
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 		/* wait a special interval */
14613138Sfrits #ifndef __lock_lint
14620Sstevel@tonic-gate 		delay(drv_usectohz(EHCI_TAKEOVER_DELAY));
14633138Sfrits #endif
14640Sstevel@tonic-gate 		/* Check to see if the BIOS has released the ownership */
14650Sstevel@tonic-gate 		extended_cap = pci_config_get32(
14660Sstevel@tonic-gate 		    ehcip->ehci_config_handle, extended_cap_offset);
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 		if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) {
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ATTA,
14710Sstevel@tonic-gate 			    ehcip->ehci_log_hdl,
14720Sstevel@tonic-gate 			    "ehci_take_control: BIOS has released "
14730Sstevel@tonic-gate 			    "the ownership. retry = %d", retry);
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate 			goto success;
14760Sstevel@tonic-gate 		}
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 	}
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate 	USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
14810Sstevel@tonic-gate 	    "ehci_take_control: take control from BIOS failed.");
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	return (USB_FAILURE);
14840Sstevel@tonic-gate 
14850Sstevel@tonic-gate success:
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate #endif	/* __x86 */
14880Sstevel@tonic-gate 	return (USB_SUCCESS);
14890Sstevel@tonic-gate }
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate /*
14930Sstevel@tonic-gate  * ehci_init_periodic_frame_list_table :
14940Sstevel@tonic-gate  *
14950Sstevel@tonic-gate  * Allocate the system memory and initialize Host Controller
14960Sstevel@tonic-gate  * Periodic Frame List table area. The starting of the Periodic
14970Sstevel@tonic-gate  * Frame List Table area must be 4096 byte aligned.
14980Sstevel@tonic-gate  */
14990Sstevel@tonic-gate static int
ehci_init_periodic_frame_lst_table(ehci_state_t * ehcip)15000Sstevel@tonic-gate ehci_init_periodic_frame_lst_table(ehci_state_t *ehcip)
15010Sstevel@tonic-gate {
15020Sstevel@tonic-gate 	ddi_device_acc_attr_t	dev_attr;
15030Sstevel@tonic-gate 	size_t			real_length;
15040Sstevel@tonic-gate 	uint_t			ccount;
15050Sstevel@tonic-gate 	int			result;
15060Sstevel@tonic-gate 
15070Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
15100Sstevel@tonic-gate 	    "ehci_init_periodic_frame_lst_table:");
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate 	/* The host controller will be little endian */
15130Sstevel@tonic-gate 	dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
15140Sstevel@tonic-gate 	dev_attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
15150Sstevel@tonic-gate 	dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 	/* Force the required 4K restrictive alignment */
15180Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_PFL_ALIGNMENT;
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate 	/* Create space for the Periodic Frame List */
15210Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr,
15220Sstevel@tonic-gate 	    DDI_DMA_SLEEP, 0, &ehcip->ehci_pflt_dma_handle) != DDI_SUCCESS) {
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 		goto failure;
15250Sstevel@tonic-gate 	}
15260Sstevel@tonic-gate 
15270Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(ehcip->ehci_pflt_dma_handle,
15280Sstevel@tonic-gate 	    sizeof (ehci_periodic_frame_list_t),
15290Sstevel@tonic-gate 	    &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
15300Sstevel@tonic-gate 	    0, (caddr_t *)&ehcip->ehci_periodic_frame_list_tablep,
15310Sstevel@tonic-gate 	    &real_length, &ehcip->ehci_pflt_mem_handle)) {
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 		goto failure;
15340Sstevel@tonic-gate 	}
15350Sstevel@tonic-gate 
15361458Syq193411 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
15370Sstevel@tonic-gate 	    "ehci_init_periodic_frame_lst_table: "
15380Sstevel@tonic-gate 	    "Real length %lu", real_length);
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate 	/* Map the whole Periodic Frame List into the I/O address space */
15410Sstevel@tonic-gate 	result = ddi_dma_addr_bind_handle(ehcip->ehci_pflt_dma_handle,
15420Sstevel@tonic-gate 	    NULL, (caddr_t)ehcip->ehci_periodic_frame_list_tablep,
15430Sstevel@tonic-gate 	    real_length, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
15440Sstevel@tonic-gate 	    DDI_DMA_SLEEP, NULL, &ehcip->ehci_pflt_cookie, &ccount);
15450Sstevel@tonic-gate 
15460Sstevel@tonic-gate 	if (result == DDI_DMA_MAPPED) {
15470Sstevel@tonic-gate 		/* The cookie count should be 1 */
15480Sstevel@tonic-gate 		if (ccount != 1) {
15490Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
15500Sstevel@tonic-gate 			    "ehci_init_periodic_frame_lst_table: "
15510Sstevel@tonic-gate 			    "More than 1 cookie");
15520Sstevel@tonic-gate 
15530Sstevel@tonic-gate 			goto failure;
15540Sstevel@tonic-gate 		}
15550Sstevel@tonic-gate 	} else {
15560Sstevel@tonic-gate 		ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate 		goto failure;
15590Sstevel@tonic-gate 	}
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
15620Sstevel@tonic-gate 	    "ehci_init_periodic_frame_lst_table: virtual 0x%p physical 0x%x",
15630Sstevel@tonic-gate 	    (void *)ehcip->ehci_periodic_frame_list_tablep,
15640Sstevel@tonic-gate 	    ehcip->ehci_pflt_cookie.dmac_address);
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 	/*
15670Sstevel@tonic-gate 	 * DMA addresses for Periodic Frame List are bound.
15680Sstevel@tonic-gate 	 */
15690Sstevel@tonic-gate 	ehcip->ehci_dma_addr_bind_flag |= EHCI_PFLT_DMA_BOUND;
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate 	bzero((void *)ehcip->ehci_periodic_frame_list_tablep, real_length);
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 	/* Initialize the Periodic Frame List */
15740Sstevel@tonic-gate 	ehci_build_interrupt_lattice(ehcip);
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 	/* Reset Byte Alignment to Default */
15770Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 	return (DDI_SUCCESS);
15800Sstevel@tonic-gate failure:
15810Sstevel@tonic-gate 	/* Byte alignment */
15820Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
15830Sstevel@tonic-gate 
15840Sstevel@tonic-gate 	return (DDI_FAILURE);
15850Sstevel@tonic-gate }
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate 
15880Sstevel@tonic-gate /*
15890Sstevel@tonic-gate  * ehci_build_interrupt_lattice:
15900Sstevel@tonic-gate  *
15910Sstevel@tonic-gate  * Construct the interrupt lattice tree using static Endpoint Descriptors
15920Sstevel@tonic-gate  * (QH). This interrupt lattice tree will have total of 32 interrupt  QH
15930Sstevel@tonic-gate  * lists and the Host Controller (HC) processes one interrupt QH list in
15940Sstevel@tonic-gate  * every frame. The Host Controller traverses the periodic schedule by
15950Sstevel@tonic-gate  * constructing an array offset reference from the Periodic List Base Address
15960Sstevel@tonic-gate  * register and bits 12 to 3 of Frame Index register. It fetches the element
15970Sstevel@tonic-gate  * and begins traversing the graph of linked schedule data structures.
15980Sstevel@tonic-gate  */
15990Sstevel@tonic-gate static void
ehci_build_interrupt_lattice(ehci_state_t * ehcip)16000Sstevel@tonic-gate ehci_build_interrupt_lattice(ehci_state_t	*ehcip)
16010Sstevel@tonic-gate {
16020Sstevel@tonic-gate 	ehci_qh_t	*list_array = ehcip->ehci_qh_pool_addr;
16030Sstevel@tonic-gate 	ushort_t	ehci_index[EHCI_NUM_PERIODIC_FRAME_LISTS];
16040Sstevel@tonic-gate 	ehci_periodic_frame_list_t *periodic_frame_list =
16055767Slc152243 	    ehcip->ehci_periodic_frame_list_tablep;
16060Sstevel@tonic-gate 	ushort_t	*temp, num_of_nodes;
16070Sstevel@tonic-gate 	uintptr_t	addr;
16080Sstevel@tonic-gate 	int		i, j, k;
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
16110Sstevel@tonic-gate 	    "ehci_build_interrupt_lattice:");
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 	/*
16140Sstevel@tonic-gate 	 * Reserve the first 63 Endpoint Descriptor (QH) structures
16150Sstevel@tonic-gate 	 * in the pool as static endpoints & these are required for
16160Sstevel@tonic-gate 	 * constructing interrupt lattice tree.
16170Sstevel@tonic-gate 	 */
16180Sstevel@tonic-gate 	for (i = 0; i < EHCI_NUM_STATIC_NODES; i++) {
16190Sstevel@tonic-gate 		Set_QH(list_array[i].qh_state, EHCI_QH_STATIC);
16200Sstevel@tonic-gate 		Set_QH(list_array[i].qh_status, EHCI_QH_STS_HALTED);
16210Sstevel@tonic-gate 		Set_QH(list_array[i].qh_next_qtd, EHCI_QH_NEXT_QTD_PTR_VALID);
16220Sstevel@tonic-gate 		Set_QH(list_array[i].qh_alt_next_qtd,
16230Sstevel@tonic-gate 		    EHCI_QH_ALT_NEXT_QTD_PTR_VALID);
16240Sstevel@tonic-gate 	}
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate 	/*
16270Sstevel@tonic-gate 	 * Make sure that last Endpoint on the periodic frame list terminates
16280Sstevel@tonic-gate 	 * periodic schedule.
16290Sstevel@tonic-gate 	 */
16300Sstevel@tonic-gate 	Set_QH(list_array[0].qh_link_ptr, EHCI_QH_LINK_PTR_VALID);
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate 	/* Build the interrupt lattice tree */
16330Sstevel@tonic-gate 	for (i = 0; i < (EHCI_NUM_STATIC_NODES / 2); i++) {
16340Sstevel@tonic-gate 		/*
16350Sstevel@tonic-gate 		 * The next  pointer in the host controller  endpoint
16360Sstevel@tonic-gate 		 * descriptor must contain an iommu address. Calculate
16370Sstevel@tonic-gate 		 * the offset into the cpu address and add this to the
16380Sstevel@tonic-gate 		 * starting iommu address.
16390Sstevel@tonic-gate 		 */
16400Sstevel@tonic-gate 		addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *)&list_array[i]);
16410Sstevel@tonic-gate 
16420Sstevel@tonic-gate 		Set_QH(list_array[2*i + 1].qh_link_ptr,
16430Sstevel@tonic-gate 		    addr | EHCI_QH_LINK_REF_QH);
16440Sstevel@tonic-gate 		Set_QH(list_array[2*i + 2].qh_link_ptr,
16450Sstevel@tonic-gate 		    addr | EHCI_QH_LINK_REF_QH);
16460Sstevel@tonic-gate 	}
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 	/* Build the tree bottom */
16490Sstevel@tonic-gate 	temp = (unsigned short *)
16500Sstevel@tonic-gate 	    kmem_zalloc(EHCI_NUM_PERIODIC_FRAME_LISTS * 2, KM_SLEEP);
16510Sstevel@tonic-gate 
16520Sstevel@tonic-gate 	num_of_nodes = 1;
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 	/*
16550Sstevel@tonic-gate 	 * Initialize the values which are used for setting up head pointers
16560Sstevel@tonic-gate 	 * for the 32ms scheduling lists which starts from the Periodic Frame
16570Sstevel@tonic-gate 	 * List.
16580Sstevel@tonic-gate 	 */
16590Sstevel@tonic-gate 	for (i = 0; i < ehci_log_2(EHCI_NUM_PERIODIC_FRAME_LISTS); i++) {
16600Sstevel@tonic-gate 		for (j = 0, k = 0; k < num_of_nodes; k++, j++) {
16610Sstevel@tonic-gate 			ehci_index[j++] = temp[k];
16620Sstevel@tonic-gate 			ehci_index[j]	= temp[k] + ehci_pow_2(i);
16630Sstevel@tonic-gate 		}
16640Sstevel@tonic-gate 
16650Sstevel@tonic-gate 		num_of_nodes *= 2;
16660Sstevel@tonic-gate 		for (k = 0; k < num_of_nodes; k++)
16670Sstevel@tonic-gate 			temp[k] = ehci_index[k];
16680Sstevel@tonic-gate 	}
16690Sstevel@tonic-gate 
16700Sstevel@tonic-gate 	kmem_free((void *)temp, (EHCI_NUM_PERIODIC_FRAME_LISTS * 2));
16710Sstevel@tonic-gate 
16720Sstevel@tonic-gate 	/*
16730Sstevel@tonic-gate 	 * Initialize the interrupt list in the Periodic Frame List Table
16740Sstevel@tonic-gate 	 * so that it points to the bottom of the tree.
16750Sstevel@tonic-gate 	 */
16760Sstevel@tonic-gate 	for (i = 0, j = 0; i < ehci_pow_2(TREE_HEIGHT); i++) {
16770Sstevel@tonic-gate 		addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *)
16780Sstevel@tonic-gate 		    (&list_array[((EHCI_NUM_STATIC_NODES + 1) / 2) + i - 1]));
16790Sstevel@tonic-gate 
16800Sstevel@tonic-gate 		ASSERT(addr);
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 		for (k = 0; k < ehci_pow_2(TREE_HEIGHT); k++) {
16830Sstevel@tonic-gate 			Set_PFLT(periodic_frame_list->
16840Sstevel@tonic-gate 			    ehci_periodic_frame_list_table[ehci_index[j++]],
16850Sstevel@tonic-gate 			    (uint32_t)(addr | EHCI_QH_LINK_REF_QH));
16860Sstevel@tonic-gate 		}
16870Sstevel@tonic-gate 	}
16880Sstevel@tonic-gate }
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate /*
16920Sstevel@tonic-gate  * ehci_alloc_hcdi_ops:
16930Sstevel@tonic-gate  *
16940Sstevel@tonic-gate  * The HCDI interfaces or entry points are the software interfaces used by
16950Sstevel@tonic-gate  * the Universal Serial Bus Driver  (USBA) to  access the services of the
16960Sstevel@tonic-gate  * Host Controller Driver (HCD).  During HCD initialization, inform  USBA
16970Sstevel@tonic-gate  * about all available HCDI interfaces or entry points.
16980Sstevel@tonic-gate  */
16990Sstevel@tonic-gate usba_hcdi_ops_t *
ehci_alloc_hcdi_ops(ehci_state_t * ehcip)17000Sstevel@tonic-gate ehci_alloc_hcdi_ops(ehci_state_t	*ehcip)
17010Sstevel@tonic-gate {
17020Sstevel@tonic-gate 	usba_hcdi_ops_t			*usba_hcdi_ops;
17030Sstevel@tonic-gate 
17040Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
17050Sstevel@tonic-gate 	    "ehci_alloc_hcdi_ops:");
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate 	usba_hcdi_ops = usba_alloc_hcdi_ops();
17080Sstevel@tonic-gate 
17090Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_ops_version = HCDI_OPS_VERSION;
17100Sstevel@tonic-gate 
1711880Sfrits 	usba_hcdi_ops->usba_hcdi_pm_support = ehci_hcdi_pm_support;
17120Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_open = ehci_hcdi_pipe_open;
17130Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_close = ehci_hcdi_pipe_close;
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_reset = ehci_hcdi_pipe_reset;
17168945SGuoqing.Zhu@Sun.COM 	usba_hcdi_ops->usba_hcdi_pipe_reset_data_toggle =
17178945SGuoqing.Zhu@Sun.COM 	    ehci_hcdi_pipe_reset_data_toggle;
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_ctrl_xfer = ehci_hcdi_pipe_ctrl_xfer;
17200Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_bulk_xfer = ehci_hcdi_pipe_bulk_xfer;
17210Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_intr_xfer = ehci_hcdi_pipe_intr_xfer;
17220Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_isoc_xfer = ehci_hcdi_pipe_isoc_xfer;
17230Sstevel@tonic-gate 
17240Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_bulk_transfer_size =
17255767Slc152243 	    ehci_hcdi_bulk_transfer_size;
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_stop_intr_polling =
17285767Slc152243 	    ehci_hcdi_pipe_stop_intr_polling;
17290Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_pipe_stop_isoc_polling =
17305767Slc152243 	    ehci_hcdi_pipe_stop_isoc_polling;
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_get_current_frame_number =
17335767Slc152243 	    ehci_hcdi_get_current_frame_number;
17340Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_get_max_isoc_pkts =
17355767Slc152243 	    ehci_hcdi_get_max_isoc_pkts;
17360Sstevel@tonic-gate 
17370Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_console_input_init =
17385767Slc152243 	    ehci_hcdi_polled_input_init;
17390Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_console_input_enter =
17405767Slc152243 	    ehci_hcdi_polled_input_enter;
17410Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_console_read =
17425767Slc152243 	    ehci_hcdi_polled_read;
17430Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_console_input_exit =
17445767Slc152243 	    ehci_hcdi_polled_input_exit;
17450Sstevel@tonic-gate 	usba_hcdi_ops->usba_hcdi_console_input_fini =
17465767Slc152243 	    ehci_hcdi_polled_input_fini;
17479095SZhigang.Lu@Sun.COM 
17489095SZhigang.Lu@Sun.COM 	usba_hcdi_ops->usba_hcdi_console_output_init =
17499095SZhigang.Lu@Sun.COM 	    ehci_hcdi_polled_output_init;
17509095SZhigang.Lu@Sun.COM 	usba_hcdi_ops->usba_hcdi_console_output_enter =
17519095SZhigang.Lu@Sun.COM 	    ehci_hcdi_polled_output_enter;
17529095SZhigang.Lu@Sun.COM 	usba_hcdi_ops->usba_hcdi_console_write =
17539095SZhigang.Lu@Sun.COM 	    ehci_hcdi_polled_write;
17549095SZhigang.Lu@Sun.COM 	usba_hcdi_ops->usba_hcdi_console_output_exit =
17559095SZhigang.Lu@Sun.COM 	    ehci_hcdi_polled_output_exit;
17569095SZhigang.Lu@Sun.COM 	usba_hcdi_ops->usba_hcdi_console_output_fini =
17579095SZhigang.Lu@Sun.COM 	    ehci_hcdi_polled_output_fini;
17580Sstevel@tonic-gate 	return (usba_hcdi_ops);
17590Sstevel@tonic-gate }
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 
17620Sstevel@tonic-gate /*
17630Sstevel@tonic-gate  * Host Controller Driver (HCD) deinitialization functions
17640Sstevel@tonic-gate  */
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate /*
17670Sstevel@tonic-gate  * ehci_cleanup:
17680Sstevel@tonic-gate  *
17690Sstevel@tonic-gate  * Cleanup on attach failure or detach
17700Sstevel@tonic-gate  */
17710Sstevel@tonic-gate int
ehci_cleanup(ehci_state_t * ehcip)17720Sstevel@tonic-gate ehci_cleanup(ehci_state_t	*ehcip)
17730Sstevel@tonic-gate {
17740Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
17750Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
17760Sstevel@tonic-gate 	ehci_qtd_t		*qtd;
17770Sstevel@tonic-gate 	int			i, ctrl, rval;
17780Sstevel@tonic-gate 	int			flags = ehcip->ehci_flags;
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_cleanup:");
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate 	if (flags & EHCI_RHREG) {
17830Sstevel@tonic-gate 		/* Unload the root hub driver */
17840Sstevel@tonic-gate 		if (ehci_unload_root_hub_driver(ehcip) != USB_SUCCESS) {
17850Sstevel@tonic-gate 
17860Sstevel@tonic-gate 			return (DDI_FAILURE);
17870Sstevel@tonic-gate 		}
17880Sstevel@tonic-gate 	}
17890Sstevel@tonic-gate 
17900Sstevel@tonic-gate 	if (flags & EHCI_USBAREG) {
17910Sstevel@tonic-gate 		/* Unregister this HCD instance with USBA */
17920Sstevel@tonic-gate 		usba_hcdi_unregister(ehcip->ehci_dip);
17930Sstevel@tonic-gate 	}
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 	if (flags & EHCI_INTR) {
17960Sstevel@tonic-gate 
17970Sstevel@tonic-gate 		mutex_enter(&ehcip->ehci_int_mutex);
17980Sstevel@tonic-gate 
17990Sstevel@tonic-gate 		/* Disable all EHCI QH list processing */
18000Sstevel@tonic-gate 		Set_OpReg(ehci_command, (Get_OpReg(ehci_command) &
18010Sstevel@tonic-gate 		    ~(EHCI_CMD_ASYNC_SCHED_ENABLE |
18020Sstevel@tonic-gate 		    EHCI_CMD_PERIODIC_SCHED_ENABLE)));
18030Sstevel@tonic-gate 
18040Sstevel@tonic-gate 		/* Disable all EHCI interrupts */
18050Sstevel@tonic-gate 		Set_OpReg(ehci_interrupt, 0);
18060Sstevel@tonic-gate 
18070Sstevel@tonic-gate 		/* wait for the next SOF */
18080Sstevel@tonic-gate 		(void) ehci_wait_for_sof(ehcip);
18090Sstevel@tonic-gate 
1810880Sfrits 		/* Route all Root hub ports to Classic host controller */
1811880Sfrits 		Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC);
1812880Sfrits 
18130Sstevel@tonic-gate 		/* Stop the EHCI host controller */
18140Sstevel@tonic-gate 		Set_OpReg(ehci_command,
18150Sstevel@tonic-gate 		    Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN);
18160Sstevel@tonic-gate 
18175767Slc152243 		mutex_exit(&ehcip->ehci_int_mutex);
18185767Slc152243 
18190Sstevel@tonic-gate 		/* Wait for sometime */
18205767Slc152243 		delay(drv_usectohz(EHCI_TIMEWAIT));
18210Sstevel@tonic-gate 
1822965Sgovinda 		ehci_rem_intrs(ehcip);
18230Sstevel@tonic-gate 	}
18240Sstevel@tonic-gate 
18250Sstevel@tonic-gate 	/* Unmap the EHCI registers */
18260Sstevel@tonic-gate 	if (ehcip->ehci_caps_handle) {
18270Sstevel@tonic-gate 		ddi_regs_map_free(&ehcip->ehci_caps_handle);
18280Sstevel@tonic-gate 	}
18290Sstevel@tonic-gate 
18300Sstevel@tonic-gate 	if (ehcip->ehci_config_handle) {
18310Sstevel@tonic-gate 		pci_config_teardown(&ehcip->ehci_config_handle);
18320Sstevel@tonic-gate 	}
18330Sstevel@tonic-gate 
18340Sstevel@tonic-gate 	/* Free all the buffers */
18350Sstevel@tonic-gate 	if (ehcip->ehci_qtd_pool_addr && ehcip->ehci_qtd_pool_mem_handle) {
18360Sstevel@tonic-gate 		for (i = 0; i < ehci_qtd_pool_size; i ++) {
18370Sstevel@tonic-gate 			qtd = &ehcip->ehci_qtd_pool_addr[i];
18380Sstevel@tonic-gate 			ctrl = Get_QTD(ehcip->
18390Sstevel@tonic-gate 			    ehci_qtd_pool_addr[i].qtd_state);
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate 			if ((ctrl != EHCI_QTD_FREE) &&
18420Sstevel@tonic-gate 			    (ctrl != EHCI_QTD_DUMMY) &&
18430Sstevel@tonic-gate 			    (qtd->qtd_trans_wrapper)) {
18440Sstevel@tonic-gate 
18450Sstevel@tonic-gate 				mutex_enter(&ehcip->ehci_int_mutex);
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate 				tw = (ehci_trans_wrapper_t *)
18485767Slc152243 				    EHCI_LOOKUP_ID((uint32_t)
18495767Slc152243 				    Get_QTD(qtd->qtd_trans_wrapper));
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate 				/* Obtain the pipe private structure */
18520Sstevel@tonic-gate 				pp = tw->tw_pipe_private;
18530Sstevel@tonic-gate 
18540Sstevel@tonic-gate 				/* Stop the the transfer timer */
18550Sstevel@tonic-gate 				ehci_stop_xfer_timer(ehcip, tw,
18565767Slc152243 				    EHCI_REMOVE_XFER_ALWAYS);
18570Sstevel@tonic-gate 
18580Sstevel@tonic-gate 				ehci_deallocate_tw(ehcip, pp, tw);
18590Sstevel@tonic-gate 
18600Sstevel@tonic-gate 				mutex_exit(&ehcip->ehci_int_mutex);
18610Sstevel@tonic-gate 			}
18620Sstevel@tonic-gate 		}
18630Sstevel@tonic-gate 
18640Sstevel@tonic-gate 		/*
18650Sstevel@tonic-gate 		 * If EHCI_QTD_POOL_BOUND flag is set, then unbind
18660Sstevel@tonic-gate 		 * the handle for QTD pools.
18670Sstevel@tonic-gate 		 */
18680Sstevel@tonic-gate 		if ((ehcip->ehci_dma_addr_bind_flag &
18690Sstevel@tonic-gate 		    EHCI_QTD_POOL_BOUND) == EHCI_QTD_POOL_BOUND) {
18700Sstevel@tonic-gate 
18710Sstevel@tonic-gate 			rval = ddi_dma_unbind_handle(
18720Sstevel@tonic-gate 			    ehcip->ehci_qtd_pool_dma_handle);
18730Sstevel@tonic-gate 
18740Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
18750Sstevel@tonic-gate 		}
18760Sstevel@tonic-gate 		ddi_dma_mem_free(&ehcip->ehci_qtd_pool_mem_handle);
18770Sstevel@tonic-gate 	}
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate 	/* Free the QTD pool */
18800Sstevel@tonic-gate 	if (ehcip->ehci_qtd_pool_dma_handle) {
18810Sstevel@tonic-gate 		ddi_dma_free_handle(&ehcip->ehci_qtd_pool_dma_handle);
18820Sstevel@tonic-gate 	}
18830Sstevel@tonic-gate 
18840Sstevel@tonic-gate 	if (ehcip->ehci_qh_pool_addr && ehcip->ehci_qh_pool_mem_handle) {
18850Sstevel@tonic-gate 		/*
18860Sstevel@tonic-gate 		 * If EHCI_QH_POOL_BOUND flag is set, then unbind
18870Sstevel@tonic-gate 		 * the handle for QH pools.
18880Sstevel@tonic-gate 		 */
18890Sstevel@tonic-gate 		if ((ehcip->ehci_dma_addr_bind_flag &
18900Sstevel@tonic-gate 		    EHCI_QH_POOL_BOUND) == EHCI_QH_POOL_BOUND) {
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 			rval = ddi_dma_unbind_handle(
18930Sstevel@tonic-gate 			    ehcip->ehci_qh_pool_dma_handle);
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
18960Sstevel@tonic-gate 		}
18970Sstevel@tonic-gate 
18980Sstevel@tonic-gate 		ddi_dma_mem_free(&ehcip->ehci_qh_pool_mem_handle);
18990Sstevel@tonic-gate 	}
19000Sstevel@tonic-gate 
19010Sstevel@tonic-gate 	/* Free the QH pool */
19020Sstevel@tonic-gate 	if (ehcip->ehci_qh_pool_dma_handle) {
19030Sstevel@tonic-gate 		ddi_dma_free_handle(&ehcip->ehci_qh_pool_dma_handle);
19040Sstevel@tonic-gate 	}
19050Sstevel@tonic-gate 
19060Sstevel@tonic-gate 	/* Free the Periodic frame list table (PFLT) area */
19070Sstevel@tonic-gate 	if (ehcip->ehci_periodic_frame_list_tablep &&
19080Sstevel@tonic-gate 	    ehcip->ehci_pflt_mem_handle) {
19090Sstevel@tonic-gate 		/*
19100Sstevel@tonic-gate 		 * If EHCI_PFLT_DMA_BOUND flag is set, then unbind
19110Sstevel@tonic-gate 		 * the handle for PFLT.
19120Sstevel@tonic-gate 		 */
19130Sstevel@tonic-gate 		if ((ehcip->ehci_dma_addr_bind_flag &
19140Sstevel@tonic-gate 		    EHCI_PFLT_DMA_BOUND) == EHCI_PFLT_DMA_BOUND) {
19150Sstevel@tonic-gate 
19160Sstevel@tonic-gate 			rval = ddi_dma_unbind_handle(
19170Sstevel@tonic-gate 			    ehcip->ehci_pflt_dma_handle);
19180Sstevel@tonic-gate 
19190Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
19200Sstevel@tonic-gate 		}
19210Sstevel@tonic-gate 
19220Sstevel@tonic-gate 		ddi_dma_mem_free(&ehcip->ehci_pflt_mem_handle);
19230Sstevel@tonic-gate 	}
19240Sstevel@tonic-gate 
19250Sstevel@tonic-gate 	(void) ehci_isoc_cleanup(ehcip);
19260Sstevel@tonic-gate 
19270Sstevel@tonic-gate 	if (ehcip->ehci_pflt_dma_handle) {
19280Sstevel@tonic-gate 		ddi_dma_free_handle(&ehcip->ehci_pflt_dma_handle);
19290Sstevel@tonic-gate 	}
19300Sstevel@tonic-gate 
19310Sstevel@tonic-gate 	if (flags & EHCI_INTR) {
19320Sstevel@tonic-gate 		/* Destroy the mutex */
19330Sstevel@tonic-gate 		mutex_destroy(&ehcip->ehci_int_mutex);
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 		/* Destroy the async schedule advance condition variable */
19360Sstevel@tonic-gate 		cv_destroy(&ehcip->ehci_async_schedule_advance_cv);
19370Sstevel@tonic-gate 	}
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate 	/* clean up kstat structs */
19400Sstevel@tonic-gate 	ehci_destroy_stats(ehcip);
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate 	/* Free ehci hcdi ops */
19430Sstevel@tonic-gate 	if (ehcip->ehci_hcdi_ops) {
19440Sstevel@tonic-gate 		usba_free_hcdi_ops(ehcip->ehci_hcdi_ops);
19450Sstevel@tonic-gate 	}
19460Sstevel@tonic-gate 
19470Sstevel@tonic-gate 	if (flags & EHCI_ZALLOC) {
19480Sstevel@tonic-gate 
19490Sstevel@tonic-gate 		usb_free_log_hdl(ehcip->ehci_log_hdl);
19500Sstevel@tonic-gate 
19510Sstevel@tonic-gate 		/* Remove all properties that might have been created */
19520Sstevel@tonic-gate 		ddi_prop_remove_all(ehcip->ehci_dip);
19530Sstevel@tonic-gate 
19540Sstevel@tonic-gate 		/* Free the soft state */
19550Sstevel@tonic-gate 		ddi_soft_state_free(ehci_statep,
19565767Slc152243 		    ddi_get_instance(ehcip->ehci_dip));
19570Sstevel@tonic-gate 	}
19580Sstevel@tonic-gate 
19590Sstevel@tonic-gate 	return (DDI_SUCCESS);
19600Sstevel@tonic-gate }
19610Sstevel@tonic-gate 
19620Sstevel@tonic-gate 
19630Sstevel@tonic-gate /*
1964965Sgovinda  * ehci_rem_intrs:
1965965Sgovinda  *
1966965Sgovinda  * Unregister FIXED or MSI interrupts
1967965Sgovinda  */
1968965Sgovinda static void
ehci_rem_intrs(ehci_state_t * ehcip)1969965Sgovinda ehci_rem_intrs(ehci_state_t	*ehcip)
1970965Sgovinda {
1971965Sgovinda 	int	i;
1972965Sgovinda 
1973965Sgovinda 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1974965Sgovinda 	    "ehci_rem_intrs: interrupt type 0x%x", ehcip->ehci_intr_type);
1975965Sgovinda 
1976965Sgovinda 	/* Disable all interrupts */
1977965Sgovinda 	if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) {
1978965Sgovinda 		(void) ddi_intr_block_disable(ehcip->ehci_htable,
1979965Sgovinda 		    ehcip->ehci_intr_cnt);
1980965Sgovinda 	} else {
1981965Sgovinda 		for (i = 0; i < ehcip->ehci_intr_cnt; i++) {
1982965Sgovinda 			(void) ddi_intr_disable(ehcip->ehci_htable[i]);
1983965Sgovinda 		}
1984965Sgovinda 	}
1985965Sgovinda 
1986965Sgovinda 	/* Call ddi_intr_remove_handler() */
1987965Sgovinda 	for (i = 0; i < ehcip->ehci_intr_cnt; i++) {
1988965Sgovinda 		(void) ddi_intr_remove_handler(ehcip->ehci_htable[i]);
1989965Sgovinda 		(void) ddi_intr_free(ehcip->ehci_htable[i]);
1990965Sgovinda 	}
1991965Sgovinda 
1992965Sgovinda 	kmem_free(ehcip->ehci_htable,
1993965Sgovinda 	    ehcip->ehci_intr_cnt * sizeof (ddi_intr_handle_t));
1994965Sgovinda }
1995965Sgovinda 
1996965Sgovinda 
1997965Sgovinda /*
19980Sstevel@tonic-gate  * ehci_cpr_suspend
19990Sstevel@tonic-gate  */
20000Sstevel@tonic-gate int
ehci_cpr_suspend(ehci_state_t * ehcip)20010Sstevel@tonic-gate ehci_cpr_suspend(ehci_state_t	*ehcip)
20020Sstevel@tonic-gate {
20030Sstevel@tonic-gate 	int	i;
20040Sstevel@tonic-gate 
20050Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20060Sstevel@tonic-gate 	    "ehci_cpr_suspend:");
20070Sstevel@tonic-gate 
20080Sstevel@tonic-gate 	/* Call into the root hub and suspend it */
20090Sstevel@tonic-gate 	if (usba_hubdi_detach(ehcip->ehci_dip, DDI_SUSPEND) != DDI_SUCCESS) {
20100Sstevel@tonic-gate 
20110Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20125767Slc152243 		    "ehci_cpr_suspend: root hub fails to suspend");
20130Sstevel@tonic-gate 
20140Sstevel@tonic-gate 		return (DDI_FAILURE);
20150Sstevel@tonic-gate 	}
20160Sstevel@tonic-gate 
20170Sstevel@tonic-gate 	/* Only root hub's intr pipe should be open at this time */
20180Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
20190Sstevel@tonic-gate 
20200Sstevel@tonic-gate 	ASSERT(ehcip->ehci_open_pipe_count == 0);
20210Sstevel@tonic-gate 
20220Sstevel@tonic-gate 	/* Just wait till all resources are reclaimed */
20230Sstevel@tonic-gate 	i = 0;
20240Sstevel@tonic-gate 	while ((ehcip->ehci_reclaim_list != NULL) && (i++ < 3)) {
20250Sstevel@tonic-gate 		ehci_handle_endpoint_reclaimation(ehcip);
20260Sstevel@tonic-gate 		(void) ehci_wait_for_sof(ehcip);
20270Sstevel@tonic-gate 	}
20280Sstevel@tonic-gate 	ASSERT(ehcip->ehci_reclaim_list == NULL);
20290Sstevel@tonic-gate 
20301458Syq193411 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20310Sstevel@tonic-gate 	    "ehci_cpr_suspend: Disable HC QH list processing");
20320Sstevel@tonic-gate 
20330Sstevel@tonic-gate 	/* Disable all EHCI QH list processing */
20340Sstevel@tonic-gate 	Set_OpReg(ehci_command, (Get_OpReg(ehci_command) &
20350Sstevel@tonic-gate 	    ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE)));
20360Sstevel@tonic-gate 
20371458Syq193411 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20380Sstevel@tonic-gate 	    "ehci_cpr_suspend: Disable HC interrupts");
20390Sstevel@tonic-gate 
20400Sstevel@tonic-gate 	/* Disable all EHCI interrupts */
20410Sstevel@tonic-gate 	Set_OpReg(ehci_interrupt, 0);
20420Sstevel@tonic-gate 
20431458Syq193411 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20440Sstevel@tonic-gate 	    "ehci_cpr_suspend: Wait for the next SOF");
20450Sstevel@tonic-gate 
20460Sstevel@tonic-gate 	/* Wait for the next SOF */
20470Sstevel@tonic-gate 	if (ehci_wait_for_sof(ehcip) != USB_SUCCESS) {
20480Sstevel@tonic-gate 
20490Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20500Sstevel@tonic-gate 		    "ehci_cpr_suspend: ehci host controller suspend failed");
20510Sstevel@tonic-gate 
20520Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
20530Sstevel@tonic-gate 		return (DDI_FAILURE);
20540Sstevel@tonic-gate 	}
20550Sstevel@tonic-gate 
20560Sstevel@tonic-gate 	/*
20570Sstevel@tonic-gate 	 * Stop the ehci host controller
20580Sstevel@tonic-gate 	 * if usb keyboard is not connected.
20590Sstevel@tonic-gate 	 */
20605295Srandyf 	if (ehcip->ehci_polled_kbd_count == 0 || force_ehci_off != 0) {
20610Sstevel@tonic-gate 		Set_OpReg(ehci_command,
20620Sstevel@tonic-gate 		    Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN);
20639827SVincent.Wang@Sun.COM 
20640Sstevel@tonic-gate 	}
20650Sstevel@tonic-gate 
20660Sstevel@tonic-gate 	/* Set host controller soft state to suspend */
20670Sstevel@tonic-gate 	ehcip->ehci_hc_soft_state = EHCI_CTLR_SUSPEND_STATE;
20680Sstevel@tonic-gate 
20690Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
20700Sstevel@tonic-gate 
20710Sstevel@tonic-gate 	return (DDI_SUCCESS);
20720Sstevel@tonic-gate }
20730Sstevel@tonic-gate 
20740Sstevel@tonic-gate 
20750Sstevel@tonic-gate /*
20760Sstevel@tonic-gate  * ehci_cpr_resume
20770Sstevel@tonic-gate  */
20780Sstevel@tonic-gate int
ehci_cpr_resume(ehci_state_t * ehcip)20790Sstevel@tonic-gate ehci_cpr_resume(ehci_state_t	*ehcip)
20800Sstevel@tonic-gate {
20810Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
20820Sstevel@tonic-gate 
20830Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20840Sstevel@tonic-gate 	    "ehci_cpr_resume: Restart the controller");
20850Sstevel@tonic-gate 
20860Sstevel@tonic-gate 	/* Cleanup ehci specific information across cpr */
20870Sstevel@tonic-gate 	ehci_cpr_cleanup(ehcip);
20880Sstevel@tonic-gate 
20890Sstevel@tonic-gate 	/* Restart the controller */
20901458Syq193411 	if (ehci_init_ctlr(ehcip, EHCI_NORMAL_INITIALIZATION) != DDI_SUCCESS) {
20910Sstevel@tonic-gate 
20920Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20930Sstevel@tonic-gate 		    "ehci_cpr_resume: ehci host controller resume failed ");
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
20960Sstevel@tonic-gate 
20970Sstevel@tonic-gate 		return (DDI_FAILURE);
20980Sstevel@tonic-gate 	}
20990Sstevel@tonic-gate 
21000Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
21010Sstevel@tonic-gate 
21020Sstevel@tonic-gate 	/* Now resume the root hub */
21030Sstevel@tonic-gate 	if (usba_hubdi_attach(ehcip->ehci_dip, DDI_RESUME) != DDI_SUCCESS) {
21040Sstevel@tonic-gate 
21050Sstevel@tonic-gate 		return (DDI_FAILURE);
21060Sstevel@tonic-gate 	}
21070Sstevel@tonic-gate 
21080Sstevel@tonic-gate 	return (DDI_SUCCESS);
21090Sstevel@tonic-gate }
21100Sstevel@tonic-gate 
21110Sstevel@tonic-gate 
21120Sstevel@tonic-gate /*
21130Sstevel@tonic-gate  * Bandwidth Allocation functions
21140Sstevel@tonic-gate  */
21150Sstevel@tonic-gate 
21160Sstevel@tonic-gate /*
21170Sstevel@tonic-gate  * ehci_allocate_bandwidth:
21180Sstevel@tonic-gate  *
21190Sstevel@tonic-gate  * Figure out whether or not this interval may be supported. Return the index
21200Sstevel@tonic-gate  * into the  lattice if it can be supported.  Return allocation failure if it
21210Sstevel@tonic-gate  * can not be supported.
21220Sstevel@tonic-gate  */
21230Sstevel@tonic-gate int
ehci_allocate_bandwidth(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,uint_t * pnode,uchar_t * smask,uchar_t * cmask)21240Sstevel@tonic-gate ehci_allocate_bandwidth(
21250Sstevel@tonic-gate 	ehci_state_t		*ehcip,
21260Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
21270Sstevel@tonic-gate 	uint_t			*pnode,
21280Sstevel@tonic-gate 	uchar_t			*smask,
21290Sstevel@tonic-gate 	uchar_t			*cmask)
21300Sstevel@tonic-gate {
21310Sstevel@tonic-gate 	int			error = USB_SUCCESS;
21320Sstevel@tonic-gate 
21330Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
21340Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
21350Sstevel@tonic-gate 
21360Sstevel@tonic-gate 	/* Reset the pnode to the last checked pnode */
21370Sstevel@tonic-gate 	*pnode = 0;
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 	/* Allocate high speed bandwidth */
21400Sstevel@tonic-gate 	if ((error = ehci_allocate_high_speed_bandwidth(ehcip,
21410Sstevel@tonic-gate 	    ph, pnode, smask, cmask)) != USB_SUCCESS) {
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate 		return (error);
21440Sstevel@tonic-gate 	}
21450Sstevel@tonic-gate 
21460Sstevel@tonic-gate 	/*
21470Sstevel@tonic-gate 	 * For low/full speed usb devices, allocate classic TT bandwidth
21480Sstevel@tonic-gate 	 * in additional to high speed bandwidth.
21490Sstevel@tonic-gate 	 */
21500Sstevel@tonic-gate 	if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) {
21510Sstevel@tonic-gate 
21520Sstevel@tonic-gate 		/* Allocate classic TT bandwidth */
21530Sstevel@tonic-gate 		if ((error = ehci_allocate_classic_tt_bandwidth(
21540Sstevel@tonic-gate 		    ehcip, ph, *pnode)) != USB_SUCCESS) {
21550Sstevel@tonic-gate 
21560Sstevel@tonic-gate 			/* Deallocate high speed bandwidth */
21570Sstevel@tonic-gate 			ehci_deallocate_high_speed_bandwidth(
21580Sstevel@tonic-gate 			    ehcip, ph, *pnode, *smask, *cmask);
21590Sstevel@tonic-gate 		}
21600Sstevel@tonic-gate 	}
21610Sstevel@tonic-gate 
21620Sstevel@tonic-gate 	return (error);
21630Sstevel@tonic-gate }
21640Sstevel@tonic-gate 
21650Sstevel@tonic-gate 
21660Sstevel@tonic-gate /*
21670Sstevel@tonic-gate  * ehci_allocate_high_speed_bandwidth:
21680Sstevel@tonic-gate  *
21690Sstevel@tonic-gate  * Allocate high speed bandwidth for the low/full/high speed interrupt and
21700Sstevel@tonic-gate  * isochronous endpoints.
21710Sstevel@tonic-gate  */
21720Sstevel@tonic-gate static int
ehci_allocate_high_speed_bandwidth(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,uint_t * pnode,uchar_t * smask,uchar_t * cmask)21730Sstevel@tonic-gate ehci_allocate_high_speed_bandwidth(
21740Sstevel@tonic-gate 	ehci_state_t		*ehcip,
21750Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
21760Sstevel@tonic-gate 	uint_t			*pnode,
21770Sstevel@tonic-gate 	uchar_t			*smask,
21780Sstevel@tonic-gate 	uchar_t			*cmask)
21790Sstevel@tonic-gate {
21800Sstevel@tonic-gate 	uint_t			sbandwidth, cbandwidth;
21810Sstevel@tonic-gate 	int			interval;
21820Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint = &ph->p_ep;
21830Sstevel@tonic-gate 	usba_device_t		*child_ud;
21840Sstevel@tonic-gate 	usb_port_status_t	port_status;
21850Sstevel@tonic-gate 	int			error;
21860Sstevel@tonic-gate 
21870Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
21880Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
21890Sstevel@tonic-gate 
21900Sstevel@tonic-gate 	/* Get child's usba device structure */
21910Sstevel@tonic-gate 	child_ud = ph->p_usba_device;
21920Sstevel@tonic-gate 
21930Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
21940Sstevel@tonic-gate 
21950Sstevel@tonic-gate 	/* Get the current usb device's port status */
21960Sstevel@tonic-gate 	port_status = ph->p_usba_device->usb_port_status;
21970Sstevel@tonic-gate 
21980Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
21990Sstevel@tonic-gate 
22000Sstevel@tonic-gate 	/*
22010Sstevel@tonic-gate 	 * Calculate the length in bytes of a transaction on this
22020Sstevel@tonic-gate 	 * periodic endpoint. Return failure if maximum packet is
22030Sstevel@tonic-gate 	 * zero.
22040Sstevel@tonic-gate 	 */
22050Sstevel@tonic-gate 	error = ehci_compute_high_speed_bandwidth(ehcip, endpoint,
22060Sstevel@tonic-gate 	    port_status, &sbandwidth, &cbandwidth);
22070Sstevel@tonic-gate 	if (error != USB_SUCCESS) {
22080Sstevel@tonic-gate 
22090Sstevel@tonic-gate 		return (error);
22100Sstevel@tonic-gate 	}
22110Sstevel@tonic-gate 
22120Sstevel@tonic-gate 	/*
22130Sstevel@tonic-gate 	 * Adjust polling interval to be a power of 2.
22140Sstevel@tonic-gate 	 * If this interval can't be supported, return
22150Sstevel@tonic-gate 	 * allocation failure.
22160Sstevel@tonic-gate 	 */
22170Sstevel@tonic-gate 	interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
22180Sstevel@tonic-gate 	if (interval == USB_FAILURE) {
22190Sstevel@tonic-gate 
22200Sstevel@tonic-gate 		return (USB_FAILURE);
22210Sstevel@tonic-gate 	}
22220Sstevel@tonic-gate 
22230Sstevel@tonic-gate 	if (port_status == USBA_HIGH_SPEED_DEV) {
22243255Slg150142 		/* Allocate bandwidth for high speed devices */
22253255Slg150142 		if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) ==
22263255Slg150142 		    USB_EP_ATTR_ISOCH) {
22273255Slg150142 			error = USB_SUCCESS;
22283255Slg150142 		} else {
22293255Slg150142 
22303255Slg150142 			error = ehci_find_bestfit_hs_mask(ehcip, smask, pnode,
22313255Slg150142 			    endpoint, sbandwidth, interval);
22323255Slg150142 		}
22333255Slg150142 
22340Sstevel@tonic-gate 		*cmask = 0x00;
22350Sstevel@tonic-gate 
22360Sstevel@tonic-gate 	} else {
22370Sstevel@tonic-gate 		if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) ==
22380Sstevel@tonic-gate 		    USB_EP_ATTR_INTR) {
22390Sstevel@tonic-gate 
22400Sstevel@tonic-gate 			/* Allocate bandwidth for low speed interrupt */
22410Sstevel@tonic-gate 			error = ehci_find_bestfit_ls_intr_mask(ehcip,
22420Sstevel@tonic-gate 			    smask, cmask, pnode, sbandwidth, cbandwidth,
22430Sstevel@tonic-gate 			    interval);
22440Sstevel@tonic-gate 		} else {
22450Sstevel@tonic-gate 			if ((endpoint->bEndpointAddress &
22460Sstevel@tonic-gate 			    USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
22470Sstevel@tonic-gate 
22480Sstevel@tonic-gate 				/* Allocate bandwidth for sitd in */
22490Sstevel@tonic-gate 				error = ehci_find_bestfit_sitd_in_mask(ehcip,
22500Sstevel@tonic-gate 				    smask, cmask, pnode, sbandwidth, cbandwidth,
22510Sstevel@tonic-gate 				    interval);
22520Sstevel@tonic-gate 			} else {
22530Sstevel@tonic-gate 
22540Sstevel@tonic-gate 				/* Allocate bandwidth for sitd out */
22550Sstevel@tonic-gate 				error = ehci_find_bestfit_sitd_out_mask(ehcip,
22560Sstevel@tonic-gate 				    smask, pnode, sbandwidth, interval);
22570Sstevel@tonic-gate 				*cmask = 0x00;
22580Sstevel@tonic-gate 			}
22590Sstevel@tonic-gate 		}
22600Sstevel@tonic-gate 	}
22610Sstevel@tonic-gate 
22620Sstevel@tonic-gate 	if (error != USB_SUCCESS) {
22630Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
22640Sstevel@tonic-gate 		    "ehci_allocate_high_speed_bandwidth: Reached maximum "
22650Sstevel@tonic-gate 		    "bandwidth value and cannot allocate bandwidth for a "
22660Sstevel@tonic-gate 		    "given high-speed periodic endpoint");
22670Sstevel@tonic-gate 
22680Sstevel@tonic-gate 		return (USB_NO_BANDWIDTH);
22690Sstevel@tonic-gate 	}
22700Sstevel@tonic-gate 
22710Sstevel@tonic-gate 	return (error);
22720Sstevel@tonic-gate }
22730Sstevel@tonic-gate 
22740Sstevel@tonic-gate 
22750Sstevel@tonic-gate /*
22760Sstevel@tonic-gate  * ehci_allocate_classic_tt_speed_bandwidth:
22770Sstevel@tonic-gate  *
22780Sstevel@tonic-gate  * Allocate classic TT bandwidth for the low/full speed interrupt and
22790Sstevel@tonic-gate  * isochronous endpoints.
22800Sstevel@tonic-gate  */
22810Sstevel@tonic-gate static int
ehci_allocate_classic_tt_bandwidth(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,uint_t pnode)22820Sstevel@tonic-gate ehci_allocate_classic_tt_bandwidth(
22830Sstevel@tonic-gate 	ehci_state_t		*ehcip,
22840Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
22850Sstevel@tonic-gate 	uint_t			pnode)
22860Sstevel@tonic-gate {
22870Sstevel@tonic-gate 	uint_t			bandwidth, min;
22880Sstevel@tonic-gate 	uint_t			height, leftmost, list;
22890Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint = &ph->p_ep;
22900Sstevel@tonic-gate 	usba_device_t		*child_ud, *parent_ud;
22910Sstevel@tonic-gate 	usb_port_status_t	port_status;
22920Sstevel@tonic-gate 	int			i, interval;
22930Sstevel@tonic-gate 
22940Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
22950Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
22960Sstevel@tonic-gate 
22970Sstevel@tonic-gate 	/* Get child's usba device structure */
22980Sstevel@tonic-gate 	child_ud = ph->p_usba_device;
22990Sstevel@tonic-gate 
23000Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
23010Sstevel@tonic-gate 
23020Sstevel@tonic-gate 	/* Get the current usb device's port status */
23030Sstevel@tonic-gate 	port_status = child_ud->usb_port_status;
23040Sstevel@tonic-gate 
23050Sstevel@tonic-gate 	/* Get the parent high speed hub's usba device structure */
23060Sstevel@tonic-gate 	parent_ud = child_ud->usb_hs_hub_usba_dev;
23070Sstevel@tonic-gate 
23080Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
23090Sstevel@tonic-gate 
23101458Syq193411 	USB_DPRINTF_L3(PRINT_MASK_BW, ehcip->ehci_log_hdl,
23110Sstevel@tonic-gate 	    "ehci_allocate_classic_tt_bandwidth: "
23126898Sfb209375 	    "child_ud 0x%p parent_ud 0x%p",
23136898Sfb209375 	    (void *)child_ud, (void *)parent_ud);
23140Sstevel@tonic-gate 
23150Sstevel@tonic-gate 	/*
23160Sstevel@tonic-gate 	 * Calculate the length in bytes of a transaction on this
23170Sstevel@tonic-gate 	 * periodic endpoint. Return failure if maximum packet is
23180Sstevel@tonic-gate 	 * zero.
23190Sstevel@tonic-gate 	 */
23200Sstevel@tonic-gate 	if (ehci_compute_classic_bandwidth(endpoint,
23210Sstevel@tonic-gate 	    port_status, &bandwidth) != USB_SUCCESS) {
23220Sstevel@tonic-gate 
23230Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
23240Sstevel@tonic-gate 		    "ehci_allocate_classic_tt_bandwidth: Periodic endpoint "
23250Sstevel@tonic-gate 		    "with zero endpoint maximum packet size is not supported");
23260Sstevel@tonic-gate 
23270Sstevel@tonic-gate 		return (USB_NOT_SUPPORTED);
23280Sstevel@tonic-gate 	}
23290Sstevel@tonic-gate 
23301458Syq193411 	USB_DPRINTF_L3(PRINT_MASK_BW, ehcip->ehci_log_hdl,
23310Sstevel@tonic-gate 	    "ehci_allocate_classic_tt_bandwidth: bandwidth %d", bandwidth);
23320Sstevel@tonic-gate 
23330Sstevel@tonic-gate 	mutex_enter(&parent_ud->usb_mutex);
23340Sstevel@tonic-gate 
23350Sstevel@tonic-gate 	/*
23360Sstevel@tonic-gate 	 * If the length in bytes plus the allocated bandwidth exceeds
23370Sstevel@tonic-gate 	 * the maximum, return bandwidth allocation failure.
23380Sstevel@tonic-gate 	 */
23390Sstevel@tonic-gate 	if ((parent_ud->usb_hs_hub_min_bandwidth + bandwidth) >
23400Sstevel@tonic-gate 	    FS_PERIODIC_BANDWIDTH) {
23410Sstevel@tonic-gate 
23420Sstevel@tonic-gate 		mutex_exit(&parent_ud->usb_mutex);
23430Sstevel@tonic-gate 
23440Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
23450Sstevel@tonic-gate 		    "ehci_allocate_classic_tt_bandwidth: Reached maximum "
23460Sstevel@tonic-gate 		    "bandwidth value and cannot allocate bandwidth for a "
23470Sstevel@tonic-gate 		    "given low/full speed periodic endpoint");
23480Sstevel@tonic-gate 
23490Sstevel@tonic-gate 		return (USB_NO_BANDWIDTH);
23500Sstevel@tonic-gate 	}
23510Sstevel@tonic-gate 
23520Sstevel@tonic-gate 	mutex_exit(&parent_ud->usb_mutex);
23530Sstevel@tonic-gate 
23540Sstevel@tonic-gate 	/* Adjust polling interval to be a power of 2 */
23550Sstevel@tonic-gate 	interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
23560Sstevel@tonic-gate 
23570Sstevel@tonic-gate 	/* Find the height in the tree */
23580Sstevel@tonic-gate 	height = ehci_lattice_height(interval);
23590Sstevel@tonic-gate 
23600Sstevel@tonic-gate 	/* Find the leftmost leaf in the subtree specified by the node. */
23610Sstevel@tonic-gate 	leftmost = ehci_leftmost_leaf(pnode, height);
23620Sstevel@tonic-gate 
23630Sstevel@tonic-gate 	mutex_enter(&parent_ud->usb_mutex);
23640Sstevel@tonic-gate 
23650Sstevel@tonic-gate 	for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) {
23660Sstevel@tonic-gate 		list = ehci_index[leftmost + i];
23670Sstevel@tonic-gate 
23680Sstevel@tonic-gate 		if ((parent_ud->usb_hs_hub_bandwidth[list] +
23690Sstevel@tonic-gate 		    bandwidth) > FS_PERIODIC_BANDWIDTH) {
23700Sstevel@tonic-gate 
23710Sstevel@tonic-gate 			mutex_exit(&parent_ud->usb_mutex);
23720Sstevel@tonic-gate 
23730Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
23740Sstevel@tonic-gate 			    "ehci_allocate_classic_tt_bandwidth: Reached "
23750Sstevel@tonic-gate 			    "maximum bandwidth value and cannot allocate "
23760Sstevel@tonic-gate 			    "bandwidth for low/full periodic endpoint");
23770Sstevel@tonic-gate 
23780Sstevel@tonic-gate 			return (USB_NO_BANDWIDTH);
23790Sstevel@tonic-gate 		}
23800Sstevel@tonic-gate 	}
23810Sstevel@tonic-gate 
23820Sstevel@tonic-gate 	/*
23830Sstevel@tonic-gate 	 * All the leaves for this node must be updated with the bandwidth.
23840Sstevel@tonic-gate 	 */
23850Sstevel@tonic-gate 	for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) {
23860Sstevel@tonic-gate 		list = ehci_index[leftmost + i];
23870Sstevel@tonic-gate 		parent_ud->usb_hs_hub_bandwidth[list] += bandwidth;
23880Sstevel@tonic-gate 	}
23890Sstevel@tonic-gate 
23900Sstevel@tonic-gate 	/* Find the leaf with the smallest allocated bandwidth */
23910Sstevel@tonic-gate 	min = parent_ud->usb_hs_hub_bandwidth[0];
23920Sstevel@tonic-gate 
23930Sstevel@tonic-gate 	for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) {
23940Sstevel@tonic-gate 		if (parent_ud->usb_hs_hub_bandwidth[i] < min) {
23950Sstevel@tonic-gate 			min = parent_ud->usb_hs_hub_bandwidth[i];
23960Sstevel@tonic-gate 		}
23970Sstevel@tonic-gate 	}
23980Sstevel@tonic-gate 
23990Sstevel@tonic-gate 	/* Save the minimum for later use */
24000Sstevel@tonic-gate 	parent_ud->usb_hs_hub_min_bandwidth = min;
24010Sstevel@tonic-gate 
24020Sstevel@tonic-gate 	mutex_exit(&parent_ud->usb_mutex);
24030Sstevel@tonic-gate 
24040Sstevel@tonic-gate 	return (USB_SUCCESS);
24050Sstevel@tonic-gate }
24060Sstevel@tonic-gate 
24070Sstevel@tonic-gate 
24080Sstevel@tonic-gate /*
24090Sstevel@tonic-gate  * ehci_deallocate_bandwidth:
24100Sstevel@tonic-gate  *
24110Sstevel@tonic-gate  * Deallocate bandwidth for the given node in the lattice and the length
24120Sstevel@tonic-gate  * of transfer.
24130Sstevel@tonic-gate  */
24140Sstevel@tonic-gate void
ehci_deallocate_bandwidth(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,uint_t pnode,uchar_t smask,uchar_t cmask)24150Sstevel@tonic-gate ehci_deallocate_bandwidth(
24160Sstevel@tonic-gate 	ehci_state_t		*ehcip,
24170Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
24180Sstevel@tonic-gate 	uint_t			pnode,
24190Sstevel@tonic-gate 	uchar_t			smask,
24200Sstevel@tonic-gate 	uchar_t			cmask)
24210Sstevel@tonic-gate {
24220Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
24230Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
24240Sstevel@tonic-gate 
24250Sstevel@tonic-gate 	ehci_deallocate_high_speed_bandwidth(ehcip, ph, pnode, smask, cmask);
24260Sstevel@tonic-gate 
24270Sstevel@tonic-gate 	/*
24280Sstevel@tonic-gate 	 * For low/full speed usb devices, deallocate classic TT bandwidth
24290Sstevel@tonic-gate 	 * in additional to high speed bandwidth.
24300Sstevel@tonic-gate 	 */
24310Sstevel@tonic-gate 	if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) {
24320Sstevel@tonic-gate 
24330Sstevel@tonic-gate 		/* Deallocate classic TT bandwidth */
24340Sstevel@tonic-gate 		ehci_deallocate_classic_tt_bandwidth(ehcip, ph, pnode);
24350Sstevel@tonic-gate 	}
24360Sstevel@tonic-gate }
24370Sstevel@tonic-gate 
24380Sstevel@tonic-gate 
24390Sstevel@tonic-gate /*
24400Sstevel@tonic-gate  * ehci_deallocate_high_speed_bandwidth:
24410Sstevel@tonic-gate  *
24420Sstevel@tonic-gate  * Deallocate high speed bandwidth of a interrupt or isochronous endpoint.
24430Sstevel@tonic-gate  */
24440Sstevel@tonic-gate static void
ehci_deallocate_high_speed_bandwidth(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,uint_t pnode,uchar_t smask,uchar_t cmask)24450Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth(
24460Sstevel@tonic-gate 	ehci_state_t		*ehcip,
24470Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
24480Sstevel@tonic-gate 	uint_t			pnode,
24490Sstevel@tonic-gate 	uchar_t			smask,
24500Sstevel@tonic-gate 	uchar_t			cmask)
24510Sstevel@tonic-gate {
24520Sstevel@tonic-gate 	uint_t			height, leftmost;
24530Sstevel@tonic-gate 	uint_t			list_count;
24540Sstevel@tonic-gate 	uint_t			sbandwidth, cbandwidth;
24550Sstevel@tonic-gate 	int			interval;
24560Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint = &ph->p_ep;
24570Sstevel@tonic-gate 	usba_device_t		*child_ud;
24580Sstevel@tonic-gate 	usb_port_status_t	port_status;
24590Sstevel@tonic-gate 
24600Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
24610Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
24620Sstevel@tonic-gate 
24630Sstevel@tonic-gate 	/* Get child's usba device structure */
24640Sstevel@tonic-gate 	child_ud = ph->p_usba_device;
24650Sstevel@tonic-gate 
24660Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
24670Sstevel@tonic-gate 
24680Sstevel@tonic-gate 	/* Get the current usb device's port status */
24690Sstevel@tonic-gate 	port_status = ph->p_usba_device->usb_port_status;
24700Sstevel@tonic-gate 
24710Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
24720Sstevel@tonic-gate 
24730Sstevel@tonic-gate 	(void) ehci_compute_high_speed_bandwidth(ehcip, endpoint,
24740Sstevel@tonic-gate 	    port_status, &sbandwidth, &cbandwidth);
24750Sstevel@tonic-gate 
24760Sstevel@tonic-gate 	/* Adjust polling interval to be a power of 2 */
24770Sstevel@tonic-gate 	interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
24780Sstevel@tonic-gate 
24790Sstevel@tonic-gate 	/* Find the height in the tree */
24800Sstevel@tonic-gate 	height = ehci_lattice_height(interval);
24810Sstevel@tonic-gate 
24820Sstevel@tonic-gate 	/*
24830Sstevel@tonic-gate 	 * Find the leftmost leaf in the subtree specified by the node
24840Sstevel@tonic-gate 	 */
24850Sstevel@tonic-gate 	leftmost = ehci_leftmost_leaf(pnode, height);
24860Sstevel@tonic-gate 
24870Sstevel@tonic-gate 	list_count = EHCI_NUM_INTR_QH_LISTS/interval;
24880Sstevel@tonic-gate 
24890Sstevel@tonic-gate 	/* Delete the bandwidth from the appropriate lists */
24900Sstevel@tonic-gate 	if (port_status == USBA_HIGH_SPEED_DEV) {
24910Sstevel@tonic-gate 
24920Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, -sbandwidth,
24930Sstevel@tonic-gate 		    leftmost, list_count, smask);
24940Sstevel@tonic-gate 	} else {
24950Sstevel@tonic-gate 		if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) ==
24960Sstevel@tonic-gate 		    USB_EP_ATTR_INTR) {
24970Sstevel@tonic-gate 
24980Sstevel@tonic-gate 			ehci_update_bw_availability(ehcip, -sbandwidth,
24990Sstevel@tonic-gate 			    leftmost, list_count, smask);
25000Sstevel@tonic-gate 			ehci_update_bw_availability(ehcip, -cbandwidth,
25010Sstevel@tonic-gate 			    leftmost, list_count, cmask);
25020Sstevel@tonic-gate 		} else {
25030Sstevel@tonic-gate 			if ((endpoint->bEndpointAddress &
25040Sstevel@tonic-gate 			    USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
25050Sstevel@tonic-gate 
25060Sstevel@tonic-gate 				ehci_update_bw_availability(ehcip, -sbandwidth,
25070Sstevel@tonic-gate 				    leftmost, list_count, smask);
25080Sstevel@tonic-gate 				ehci_update_bw_availability(ehcip,
25090Sstevel@tonic-gate 				    -MAX_UFRAME_SITD_XFER, leftmost,
25100Sstevel@tonic-gate 				    list_count, cmask);
25110Sstevel@tonic-gate 			} else {
25120Sstevel@tonic-gate 
25130Sstevel@tonic-gate 				ehci_update_bw_availability(ehcip,
25140Sstevel@tonic-gate 				    -MAX_UFRAME_SITD_XFER, leftmost,
25150Sstevel@tonic-gate 				    list_count, smask);
25160Sstevel@tonic-gate 			}
25170Sstevel@tonic-gate 		}
25180Sstevel@tonic-gate 	}
25190Sstevel@tonic-gate }
25200Sstevel@tonic-gate 
25210Sstevel@tonic-gate /*
25220Sstevel@tonic-gate  * ehci_deallocate_classic_tt_bandwidth:
25230Sstevel@tonic-gate  *
25240Sstevel@tonic-gate  * Deallocate high speed bandwidth of a interrupt or isochronous endpoint.
25250Sstevel@tonic-gate  */
25260Sstevel@tonic-gate static void
ehci_deallocate_classic_tt_bandwidth(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,uint_t pnode)25270Sstevel@tonic-gate ehci_deallocate_classic_tt_bandwidth(
25280Sstevel@tonic-gate 	ehci_state_t		*ehcip,
25290Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
25300Sstevel@tonic-gate 	uint_t			pnode)
25310Sstevel@tonic-gate {
25320Sstevel@tonic-gate 	uint_t			bandwidth, height, leftmost, list, min;
25330Sstevel@tonic-gate 	int			i, interval;
25340Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint = &ph->p_ep;
25350Sstevel@tonic-gate 	usba_device_t		*child_ud, *parent_ud;
25360Sstevel@tonic-gate 	usb_port_status_t	port_status;
25370Sstevel@tonic-gate 
25380Sstevel@tonic-gate 	/* This routine is protected by the ehci_int_mutex */
25390Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
25400Sstevel@tonic-gate 
25410Sstevel@tonic-gate 	/* Get child's usba device structure */
25420Sstevel@tonic-gate 	child_ud = ph->p_usba_device;
25430Sstevel@tonic-gate 
25440Sstevel@tonic-gate 	mutex_enter(&child_ud->usb_mutex);
25450Sstevel@tonic-gate 
25460Sstevel@tonic-gate 	/* Get the current usb device's port status */
25470Sstevel@tonic-gate 	port_status = child_ud->usb_port_status;
25480Sstevel@tonic-gate 
25490Sstevel@tonic-gate 	/* Get the parent high speed hub's usba device structure */
25500Sstevel@tonic-gate 	parent_ud = child_ud->usb_hs_hub_usba_dev;
25510Sstevel@tonic-gate 
25520Sstevel@tonic-gate 	mutex_exit(&child_ud->usb_mutex);
25530Sstevel@tonic-gate 
25540Sstevel@tonic-gate 	/* Obtain the bandwidth */
25550Sstevel@tonic-gate 	(void) ehci_compute_classic_bandwidth(endpoint,
25560Sstevel@tonic-gate 	    port_status, &bandwidth);
25570Sstevel@tonic-gate 
25580Sstevel@tonic-gate 	/* Adjust polling interval to be a power of 2 */
25590Sstevel@tonic-gate 	interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
25600Sstevel@tonic-gate 
25610Sstevel@tonic-gate 	/* Find the height in the tree */
25620Sstevel@tonic-gate 	height = ehci_lattice_height(interval);
25630Sstevel@tonic-gate 
25640Sstevel@tonic-gate 	/* Find the leftmost leaf in the subtree specified by the node */
25650Sstevel@tonic-gate 	leftmost = ehci_leftmost_leaf(pnode, height);
25660Sstevel@tonic-gate 
25670Sstevel@tonic-gate 	mutex_enter(&parent_ud->usb_mutex);
25680Sstevel@tonic-gate 
25690Sstevel@tonic-gate 	/* Delete the bandwidth from the appropriate lists */
25700Sstevel@tonic-gate 	for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) {
25710Sstevel@tonic-gate 		list = ehci_index[leftmost + i];
25720Sstevel@tonic-gate 		parent_ud->usb_hs_hub_bandwidth[list] -= bandwidth;
25730Sstevel@tonic-gate 	}
25740Sstevel@tonic-gate 
25750Sstevel@tonic-gate 	/* Find the leaf with the smallest allocated bandwidth */
25760Sstevel@tonic-gate 	min = parent_ud->usb_hs_hub_bandwidth[0];
25770Sstevel@tonic-gate 
25780Sstevel@tonic-gate 	for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) {
25790Sstevel@tonic-gate 		if (parent_ud->usb_hs_hub_bandwidth[i] < min) {
25800Sstevel@tonic-gate 			min = parent_ud->usb_hs_hub_bandwidth[i];
25810Sstevel@tonic-gate 		}
25820Sstevel@tonic-gate 	}
25830Sstevel@tonic-gate 
25840Sstevel@tonic-gate 	/* Save the minimum for later use */
25850Sstevel@tonic-gate 	parent_ud->usb_hs_hub_min_bandwidth = min;
25860Sstevel@tonic-gate 
25870Sstevel@tonic-gate 	mutex_exit(&parent_ud->usb_mutex);
25880Sstevel@tonic-gate }
25890Sstevel@tonic-gate 
25900Sstevel@tonic-gate 
25910Sstevel@tonic-gate /*
25920Sstevel@tonic-gate  * ehci_compute_high_speed_bandwidth:
25930Sstevel@tonic-gate  *
25940Sstevel@tonic-gate  * Given a periodic endpoint (interrupt or isochronous) determine the total
25950Sstevel@tonic-gate  * bandwidth for one transaction. The EHCI host controller traverses the
25960Sstevel@tonic-gate  * endpoint descriptor lists on a first-come-first-serve basis. When the HC
25970Sstevel@tonic-gate  * services an endpoint, only a single transaction attempt is made. The  HC
25980Sstevel@tonic-gate  * moves to the next Endpoint Descriptor after the first transaction attempt
25990Sstevel@tonic-gate  * rather than finishing the entire Transfer Descriptor. Therefore, when  a
26000Sstevel@tonic-gate  * Transfer Descriptor is inserted into the lattice, we will only count the
26010Sstevel@tonic-gate  * number of bytes for one transaction.
26020Sstevel@tonic-gate  *
26030Sstevel@tonic-gate  * The following are the formulas used for  calculating bandwidth in  terms
26040Sstevel@tonic-gate  * bytes and it is for the single USB high speed transaction.  The protocol
26050Sstevel@tonic-gate  * overheads will be different for each of type of USB transfer & all these
26060Sstevel@tonic-gate  * formulas & protocol overheads are derived from the 5.11.3 section of the
26070Sstevel@tonic-gate  * USB 2.0 Specification.
26080Sstevel@tonic-gate  *
26090Sstevel@tonic-gate  * High-Speed:
26100Sstevel@tonic-gate  *		Protocol overhead + ((MaxPktSz * 7)/6) + Host_Delay
26110Sstevel@tonic-gate  *
26120Sstevel@tonic-gate  * Split Transaction: (Low/Full speed devices connected behind usb2.0 hub)
26130Sstevel@tonic-gate  *
26140Sstevel@tonic-gate  *		Protocol overhead + Split transaction overhead +
26150Sstevel@tonic-gate  *			((MaxPktSz * 7)/6) + Host_Delay;
26160Sstevel@tonic-gate  */
26170Sstevel@tonic-gate /* ARGSUSED */
26180Sstevel@tonic-gate static int
ehci_compute_high_speed_bandwidth(ehci_state_t * ehcip,usb_ep_descr_t * endpoint,usb_port_status_t port_status,uint_t * sbandwidth,uint_t * cbandwidth)26190Sstevel@tonic-gate ehci_compute_high_speed_bandwidth(
26200Sstevel@tonic-gate 	ehci_state_t		*ehcip,
26210Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint,
26220Sstevel@tonic-gate 	usb_port_status_t	port_status,
26230Sstevel@tonic-gate 	uint_t			*sbandwidth,
26240Sstevel@tonic-gate 	uint_t			*cbandwidth)
26250Sstevel@tonic-gate {
26260Sstevel@tonic-gate 	ushort_t		maxpacketsize = endpoint->wMaxPacketSize;
26270Sstevel@tonic-gate 
26280Sstevel@tonic-gate 	/* Return failure if endpoint maximum packet is zero */
26290Sstevel@tonic-gate 	if (maxpacketsize == 0) {
26300Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
26310Sstevel@tonic-gate 		    "ehci_allocate_high_speed_bandwidth: Periodic endpoint "
26320Sstevel@tonic-gate 		    "with zero endpoint maximum packet size is not supported");
26330Sstevel@tonic-gate 
26340Sstevel@tonic-gate 		return (USB_NOT_SUPPORTED);
26350Sstevel@tonic-gate 	}
26360Sstevel@tonic-gate 
26370Sstevel@tonic-gate 	/* Add bit-stuffing overhead */
26380Sstevel@tonic-gate 	maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6);
26390Sstevel@tonic-gate 
26400Sstevel@tonic-gate 	/* Add Host Controller specific delay to required bandwidth */
26410Sstevel@tonic-gate 	*sbandwidth = EHCI_HOST_CONTROLLER_DELAY;
26420Sstevel@tonic-gate 
26430Sstevel@tonic-gate 	/* Add xfer specific protocol overheads */
26440Sstevel@tonic-gate 	if ((endpoint->bmAttributes &
26450Sstevel@tonic-gate 	    USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) {
26460Sstevel@tonic-gate 		/* High speed interrupt transaction */
26470Sstevel@tonic-gate 		*sbandwidth += HS_NON_ISOC_PROTO_OVERHEAD;
26480Sstevel@tonic-gate 	} else {
26490Sstevel@tonic-gate 		/* Isochronous transaction */
26500Sstevel@tonic-gate 		*sbandwidth += HS_ISOC_PROTO_OVERHEAD;
26510Sstevel@tonic-gate 	}
26520Sstevel@tonic-gate 
26530Sstevel@tonic-gate 	/*
26540Sstevel@tonic-gate 	 * For low/full speed devices, add split transaction specific
26550Sstevel@tonic-gate 	 * overheads.
26560Sstevel@tonic-gate 	 */
26570Sstevel@tonic-gate 	if (port_status != USBA_HIGH_SPEED_DEV) {
26580Sstevel@tonic-gate 		/*
26590Sstevel@tonic-gate 		 * Add start and complete split transaction
26600Sstevel@tonic-gate 		 * tokens overheads.
26610Sstevel@tonic-gate 		 */
26620Sstevel@tonic-gate 		*cbandwidth = *sbandwidth + COMPLETE_SPLIT_OVERHEAD;
26630Sstevel@tonic-gate 		*sbandwidth += START_SPLIT_OVERHEAD;
26640Sstevel@tonic-gate 
26650Sstevel@tonic-gate 		/* Add data overhead depending on data direction */
26660Sstevel@tonic-gate 		if ((endpoint->bEndpointAddress &
26670Sstevel@tonic-gate 		    USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
26680Sstevel@tonic-gate 			*cbandwidth += maxpacketsize;
26690Sstevel@tonic-gate 		} else {
26700Sstevel@tonic-gate 			if ((endpoint->bmAttributes &
26710Sstevel@tonic-gate 			    USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) {
26720Sstevel@tonic-gate 				/* There is no compete splits for out */
26730Sstevel@tonic-gate 				*cbandwidth = 0;
26740Sstevel@tonic-gate 			}
26750Sstevel@tonic-gate 			*sbandwidth += maxpacketsize;
26760Sstevel@tonic-gate 		}
26770Sstevel@tonic-gate 	} else {
26780Sstevel@tonic-gate 		uint_t		xactions;
26790Sstevel@tonic-gate 
26800Sstevel@tonic-gate 		/* Get the max transactions per microframe */
26810Sstevel@tonic-gate 		xactions = ((maxpacketsize & USB_EP_MAX_XACTS_MASK) >>
26820Sstevel@tonic-gate 		    USB_EP_MAX_XACTS_SHIFT) + 1;
26830Sstevel@tonic-gate 
26840Sstevel@tonic-gate 		/* High speed transaction */
26850Sstevel@tonic-gate 		*sbandwidth += maxpacketsize;
26860Sstevel@tonic-gate 
26870Sstevel@tonic-gate 		/* Calculate bandwidth per micro-frame */
26880Sstevel@tonic-gate 		*sbandwidth *= xactions;
26890Sstevel@tonic-gate 
26900Sstevel@tonic-gate 		*cbandwidth = 0;
26910Sstevel@tonic-gate 	}
26920Sstevel@tonic-gate 
26930Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
26940Sstevel@tonic-gate 	    "ehci_allocate_high_speed_bandwidth: "
26950Sstevel@tonic-gate 	    "Start split bandwidth %d Complete split bandwidth %d",
26960Sstevel@tonic-gate 	    *sbandwidth, *cbandwidth);
26970Sstevel@tonic-gate 
26980Sstevel@tonic-gate 	return (USB_SUCCESS);
26990Sstevel@tonic-gate }
27000Sstevel@tonic-gate 
27010Sstevel@tonic-gate 
27020Sstevel@tonic-gate /*
27030Sstevel@tonic-gate  * ehci_compute_classic_bandwidth:
27040Sstevel@tonic-gate  *
27050Sstevel@tonic-gate  * Given a periodic endpoint (interrupt or isochronous) determine the total
27060Sstevel@tonic-gate  * bandwidth for one transaction. The EHCI host controller traverses the
27070Sstevel@tonic-gate  * endpoint descriptor lists on a first-come-first-serve basis. When the HC
27080Sstevel@tonic-gate  * services an endpoint, only a single transaction attempt is made. The  HC
27090Sstevel@tonic-gate  * moves to the next Endpoint Descriptor after the first transaction attempt
27100Sstevel@tonic-gate  * rather than finishing the entire Transfer Descriptor. Therefore, when  a
27110Sstevel@tonic-gate  * Transfer Descriptor is inserted into the lattice, we will only count the
27120Sstevel@tonic-gate  * number of bytes for one transaction.
27130Sstevel@tonic-gate  *
27140Sstevel@tonic-gate  * The following are the formulas used for  calculating bandwidth in  terms
27150Sstevel@tonic-gate  * bytes and it is for the single USB high speed transaction.  The protocol
27160Sstevel@tonic-gate  * overheads will be different for each of type of USB transfer & all these
27170Sstevel@tonic-gate  * formulas & protocol overheads are derived from the 5.11.3 section of the
27180Sstevel@tonic-gate  * USB 2.0 Specification.
27190Sstevel@tonic-gate  *
27200Sstevel@tonic-gate  * Low-Speed:
27210Sstevel@tonic-gate  *		Protocol overhead + Hub LS overhead +
27220Sstevel@tonic-gate  *		(Low Speed clock * ((MaxPktSz * 7)/6)) + TT_Delay
27230Sstevel@tonic-gate  *
27240Sstevel@tonic-gate  * Full-Speed:
27250Sstevel@tonic-gate  *		Protocol overhead + ((MaxPktSz * 7)/6) + TT_Delay
27260Sstevel@tonic-gate  */
27270Sstevel@tonic-gate /* ARGSUSED */
27280Sstevel@tonic-gate static int
ehci_compute_classic_bandwidth(usb_ep_descr_t * endpoint,usb_port_status_t port_status,uint_t * bandwidth)27290Sstevel@tonic-gate ehci_compute_classic_bandwidth(
27300Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint,
27310Sstevel@tonic-gate 	usb_port_status_t	port_status,
27320Sstevel@tonic-gate 	uint_t			*bandwidth)
27330Sstevel@tonic-gate {
27340Sstevel@tonic-gate 	ushort_t		maxpacketsize = endpoint->wMaxPacketSize;
27350Sstevel@tonic-gate 
27360Sstevel@tonic-gate 	/*
27370Sstevel@tonic-gate 	 * If endpoint maximum packet is zero, then return immediately.
27380Sstevel@tonic-gate 	 */
27390Sstevel@tonic-gate 	if (maxpacketsize == 0) {
27400Sstevel@tonic-gate 
27410Sstevel@tonic-gate 		return (USB_NOT_SUPPORTED);
27420Sstevel@tonic-gate 	}
27430Sstevel@tonic-gate 
27440Sstevel@tonic-gate 	/* Add TT delay to required bandwidth */
27450Sstevel@tonic-gate 	*bandwidth = TT_DELAY;
27460Sstevel@tonic-gate 
27470Sstevel@tonic-gate 	/* Add bit-stuffing overhead */
27480Sstevel@tonic-gate 	maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6);
27490Sstevel@tonic-gate 
27500Sstevel@tonic-gate 	switch (port_status) {
27510Sstevel@tonic-gate 	case USBA_LOW_SPEED_DEV:
27520Sstevel@tonic-gate 		/* Low speed interrupt transaction */
27530Sstevel@tonic-gate 		*bandwidth += (LOW_SPEED_PROTO_OVERHEAD +
27540Sstevel@tonic-gate 		    HUB_LOW_SPEED_PROTO_OVERHEAD +
27550Sstevel@tonic-gate 		    (LOW_SPEED_CLOCK * maxpacketsize));
27560Sstevel@tonic-gate 		break;
27570Sstevel@tonic-gate 	case USBA_FULL_SPEED_DEV:
27580Sstevel@tonic-gate 		/* Full speed transaction */
27590Sstevel@tonic-gate 		*bandwidth += maxpacketsize;
27600Sstevel@tonic-gate 
27610Sstevel@tonic-gate 		/* Add xfer specific protocol overheads */
27620Sstevel@tonic-gate 		if ((endpoint->bmAttributes &
27630Sstevel@tonic-gate 		    USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) {
27640Sstevel@tonic-gate 			/* Full speed interrupt transaction */
27650Sstevel@tonic-gate 			*bandwidth += FS_NON_ISOC_PROTO_OVERHEAD;
27660Sstevel@tonic-gate 		} else {
27670Sstevel@tonic-gate 			/* Isochronous and input transaction */
27680Sstevel@tonic-gate 			if ((endpoint->bEndpointAddress &
27690Sstevel@tonic-gate 			    USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
27700Sstevel@tonic-gate 				*bandwidth += FS_ISOC_INPUT_PROTO_OVERHEAD;
27710Sstevel@tonic-gate 			} else {
27720Sstevel@tonic-gate 				/* Isochronous and output transaction */
27730Sstevel@tonic-gate 				*bandwidth += FS_ISOC_OUTPUT_PROTO_OVERHEAD;
27740Sstevel@tonic-gate 			}
27750Sstevel@tonic-gate 		}
27760Sstevel@tonic-gate 		break;
27770Sstevel@tonic-gate 	}
27780Sstevel@tonic-gate 
27790Sstevel@tonic-gate 	return (USB_SUCCESS);
27800Sstevel@tonic-gate }
27810Sstevel@tonic-gate 
27820Sstevel@tonic-gate 
27830Sstevel@tonic-gate /*
27840Sstevel@tonic-gate  * ehci_adjust_polling_interval:
27850Sstevel@tonic-gate  *
27860Sstevel@tonic-gate  * Adjust bandwidth according usb device speed.
27870Sstevel@tonic-gate  */
27880Sstevel@tonic-gate /* ARGSUSED */
27890Sstevel@tonic-gate int
ehci_adjust_polling_interval(ehci_state_t * ehcip,usb_ep_descr_t * endpoint,usb_port_status_t port_status)27900Sstevel@tonic-gate ehci_adjust_polling_interval(
27910Sstevel@tonic-gate 	ehci_state_t		*ehcip,
27920Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint,
27930Sstevel@tonic-gate 	usb_port_status_t	port_status)
27940Sstevel@tonic-gate {
27950Sstevel@tonic-gate 	uint_t			interval;
27960Sstevel@tonic-gate 	int			i = 0;
27970Sstevel@tonic-gate 
27980Sstevel@tonic-gate 	/* Get the polling interval */
27990Sstevel@tonic-gate 	interval = endpoint->bInterval;
28000Sstevel@tonic-gate 
28010Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
28020Sstevel@tonic-gate 	    "ehci_adjust_polling_interval: Polling interval 0x%x", interval);
28030Sstevel@tonic-gate 
28040Sstevel@tonic-gate 	/*
28050Sstevel@tonic-gate 	 * According USB 2.0 Specifications, a high-speed endpoint's
28060Sstevel@tonic-gate 	 * polling intervals are specified interms of 125us or micro
28070Sstevel@tonic-gate 	 * frame, where as full/low endpoint's polling intervals are
28080Sstevel@tonic-gate 	 * specified in milliseconds.
28090Sstevel@tonic-gate 	 *
28100Sstevel@tonic-gate 	 * A high speed interrupt/isochronous endpoints can specify
28110Sstevel@tonic-gate 	 * desired polling interval between 1 to 16 micro-frames,
28120Sstevel@tonic-gate 	 * where as full/low endpoints can specify between 1 to 255
28130Sstevel@tonic-gate 	 * milliseconds.
28140Sstevel@tonic-gate 	 */
28150Sstevel@tonic-gate 	switch (port_status) {
28160Sstevel@tonic-gate 	case USBA_LOW_SPEED_DEV:
28170Sstevel@tonic-gate 		/*
28180Sstevel@tonic-gate 		 * Low speed  endpoints are limited to	specifying
28190Sstevel@tonic-gate 		 * only 8ms to 255ms in this driver. If a device
28200Sstevel@tonic-gate 		 * reports a polling interval that is less than 8ms,
28210Sstevel@tonic-gate 		 * it will use 8 ms instead.
28220Sstevel@tonic-gate 		 */
28230Sstevel@tonic-gate 		if (interval < LS_MIN_POLL_INTERVAL) {
28240Sstevel@tonic-gate 
28250Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
28260Sstevel@tonic-gate 			    "Low speed endpoint's poll interval of %d ms "
28270Sstevel@tonic-gate 			    "is below threshold. Rounding up to %d ms",
28280Sstevel@tonic-gate 			    interval, LS_MIN_POLL_INTERVAL);
28290Sstevel@tonic-gate 
28300Sstevel@tonic-gate 			interval = LS_MIN_POLL_INTERVAL;
28310Sstevel@tonic-gate 		}
28320Sstevel@tonic-gate 
28330Sstevel@tonic-gate 		/*
28340Sstevel@tonic-gate 		 * Return an error if the polling interval is greater
28350Sstevel@tonic-gate 		 * than 255ms.
28360Sstevel@tonic-gate 		 */
28370Sstevel@tonic-gate 		if (interval > LS_MAX_POLL_INTERVAL) {
28380Sstevel@tonic-gate 
28390Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
28400Sstevel@tonic-gate 			    "Low speed endpoint's poll interval is "
28410Sstevel@tonic-gate 			    "greater than %d ms", LS_MAX_POLL_INTERVAL);
28420Sstevel@tonic-gate 
28430Sstevel@tonic-gate 			return (USB_FAILURE);
28440Sstevel@tonic-gate 		}
28450Sstevel@tonic-gate 		break;
28460Sstevel@tonic-gate 
28470Sstevel@tonic-gate 	case USBA_FULL_SPEED_DEV:
28480Sstevel@tonic-gate 		/*
28490Sstevel@tonic-gate 		 * Return an error if the polling interval is less
28500Sstevel@tonic-gate 		 * than 1ms and greater than 255ms.
28510Sstevel@tonic-gate 		 */
28520Sstevel@tonic-gate 		if ((interval < FS_MIN_POLL_INTERVAL) &&
28530Sstevel@tonic-gate 		    (interval > FS_MAX_POLL_INTERVAL)) {
28540Sstevel@tonic-gate 
28550Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
28560Sstevel@tonic-gate 			    "Full speed endpoint's poll interval must "
28570Sstevel@tonic-gate 			    "be between %d and %d ms", FS_MIN_POLL_INTERVAL,
28580Sstevel@tonic-gate 			    FS_MAX_POLL_INTERVAL);
28590Sstevel@tonic-gate 
28600Sstevel@tonic-gate 			return (USB_FAILURE);
28610Sstevel@tonic-gate 		}
28620Sstevel@tonic-gate 		break;
28630Sstevel@tonic-gate 	case USBA_HIGH_SPEED_DEV:
28640Sstevel@tonic-gate 		/*
28650Sstevel@tonic-gate 		 * Return an error if the polling interval is less 1
28660Sstevel@tonic-gate 		 * and greater than 16. Convert this value to 125us
28670Sstevel@tonic-gate 		 * units using 2^(bInterval -1). refer usb 2.0 spec
28680Sstevel@tonic-gate 		 * page 51 for details.
28690Sstevel@tonic-gate 		 */
28700Sstevel@tonic-gate 		if ((interval < HS_MIN_POLL_INTERVAL) &&
28710Sstevel@tonic-gate 		    (interval > HS_MAX_POLL_INTERVAL)) {
28720Sstevel@tonic-gate 
28730Sstevel@tonic-gate 			USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
28740Sstevel@tonic-gate 			    "High speed endpoint's poll interval "
28750Sstevel@tonic-gate 			    "must be between %d and %d units",
28760Sstevel@tonic-gate 			    HS_MIN_POLL_INTERVAL, HS_MAX_POLL_INTERVAL);
28770Sstevel@tonic-gate 
28780Sstevel@tonic-gate 			return (USB_FAILURE);
28790Sstevel@tonic-gate 		}
28800Sstevel@tonic-gate 
28810Sstevel@tonic-gate 		/* Adjust high speed device polling interval */
28820Sstevel@tonic-gate 		interval =
28830Sstevel@tonic-gate 		    ehci_adjust_high_speed_polling_interval(ehcip, endpoint);
28840Sstevel@tonic-gate 
28850Sstevel@tonic-gate 		break;
28860Sstevel@tonic-gate 	}
28870Sstevel@tonic-gate 
28880Sstevel@tonic-gate 	/*
28890Sstevel@tonic-gate 	 * If polling interval is greater than 32ms,
28900Sstevel@tonic-gate 	 * adjust polling interval equal to 32ms.
28910Sstevel@tonic-gate 	 */
28920Sstevel@tonic-gate 	if (interval > EHCI_NUM_INTR_QH_LISTS) {
28930Sstevel@tonic-gate 		interval = EHCI_NUM_INTR_QH_LISTS;
28940Sstevel@tonic-gate 	}
28950Sstevel@tonic-gate 
28960Sstevel@tonic-gate 	/*
28970Sstevel@tonic-gate 	 * Find the nearest power of 2 that's less
28980Sstevel@tonic-gate 	 * than interval.
28990Sstevel@tonic-gate 	 */
29000Sstevel@tonic-gate 	while ((ehci_pow_2(i)) <= interval) {
29010Sstevel@tonic-gate 		i++;
29020Sstevel@tonic-gate 	}
29030Sstevel@tonic-gate 
29040Sstevel@tonic-gate 	return (ehci_pow_2((i - 1)));
29050Sstevel@tonic-gate }
29060Sstevel@tonic-gate 
29070Sstevel@tonic-gate 
29080Sstevel@tonic-gate /*
29090Sstevel@tonic-gate  * ehci_adjust_high_speed_polling_interval:
29100Sstevel@tonic-gate  */
29110Sstevel@tonic-gate /* ARGSUSED */
29120Sstevel@tonic-gate static int
ehci_adjust_high_speed_polling_interval(ehci_state_t * ehcip,usb_ep_descr_t * endpoint)29130Sstevel@tonic-gate ehci_adjust_high_speed_polling_interval(
29140Sstevel@tonic-gate 	ehci_state_t		*ehcip,
29150Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint)
29160Sstevel@tonic-gate {
29170Sstevel@tonic-gate 	uint_t			interval;
29180Sstevel@tonic-gate 
29190Sstevel@tonic-gate 	/* Get the polling interval */
29200Sstevel@tonic-gate 	interval = ehci_pow_2(endpoint->bInterval - 1);
29210Sstevel@tonic-gate 
29220Sstevel@tonic-gate 	/*
29230Sstevel@tonic-gate 	 * Convert polling interval from micro seconds
29240Sstevel@tonic-gate 	 * to milli seconds.
29250Sstevel@tonic-gate 	 */
29260Sstevel@tonic-gate 	if (interval <= EHCI_MAX_UFRAMES) {
29270Sstevel@tonic-gate 		interval = 1;
29280Sstevel@tonic-gate 	} else {
29290Sstevel@tonic-gate 		interval = interval/EHCI_MAX_UFRAMES;
29300Sstevel@tonic-gate 	}
29310Sstevel@tonic-gate 
29320Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
29330Sstevel@tonic-gate 	    "ehci_adjust_high_speed_polling_interval: "
29340Sstevel@tonic-gate 	    "High speed adjusted interval 0x%x", interval);
29350Sstevel@tonic-gate 
29360Sstevel@tonic-gate 	return (interval);
29370Sstevel@tonic-gate }
29380Sstevel@tonic-gate 
29390Sstevel@tonic-gate 
29400Sstevel@tonic-gate /*
29410Sstevel@tonic-gate  * ehci_lattice_height:
29420Sstevel@tonic-gate  *
29430Sstevel@tonic-gate  * Given the requested bandwidth, find the height in the tree at which the
29440Sstevel@tonic-gate  * nodes for this bandwidth fall.  The height is measured as the number of
29450Sstevel@tonic-gate  * nodes from the leaf to the level specified by bandwidth The root of the
29460Sstevel@tonic-gate  * tree is at height TREE_HEIGHT.
29470Sstevel@tonic-gate  */
29480Sstevel@tonic-gate static uint_t
ehci_lattice_height(uint_t interval)29490Sstevel@tonic-gate ehci_lattice_height(uint_t interval)
29500Sstevel@tonic-gate {
29510Sstevel@tonic-gate 	return (TREE_HEIGHT - (ehci_log_2(interval)));
29520Sstevel@tonic-gate }
29530Sstevel@tonic-gate 
29540Sstevel@tonic-gate 
29550Sstevel@tonic-gate /*
29560Sstevel@tonic-gate  * ehci_lattice_parent:
29570Sstevel@tonic-gate  *
29580Sstevel@tonic-gate  * Given a node in the lattice, find the index of the parent node
29590Sstevel@tonic-gate  */
29600Sstevel@tonic-gate static uint_t
ehci_lattice_parent(uint_t node)29610Sstevel@tonic-gate ehci_lattice_parent(uint_t node)
29620Sstevel@tonic-gate {
29630Sstevel@tonic-gate 	if ((node % 2) == 0) {
29640Sstevel@tonic-gate 
29650Sstevel@tonic-gate 		return ((node/2) - 1);
29660Sstevel@tonic-gate 	} else {
29670Sstevel@tonic-gate 
29680Sstevel@tonic-gate 		return ((node + 1)/2 - 1);
29690Sstevel@tonic-gate 	}
29700Sstevel@tonic-gate }
29710Sstevel@tonic-gate 
29720Sstevel@tonic-gate 
29730Sstevel@tonic-gate /*
29740Sstevel@tonic-gate  * ehci_find_periodic_node:
29750Sstevel@tonic-gate  *
29760Sstevel@tonic-gate  * Based on the "real" array leaf node and interval, get the periodic node.
29770Sstevel@tonic-gate  */
29780Sstevel@tonic-gate static uint_t
ehci_find_periodic_node(uint_t leaf,int interval)29790Sstevel@tonic-gate ehci_find_periodic_node(uint_t leaf, int interval) {
29800Sstevel@tonic-gate 	uint_t	lattice_leaf;
29810Sstevel@tonic-gate 	uint_t	height = ehci_lattice_height(interval);
29820Sstevel@tonic-gate 	uint_t	pnode;
29830Sstevel@tonic-gate 	int	i;
29840Sstevel@tonic-gate 
29850Sstevel@tonic-gate 	/* Get the leaf number in the lattice */
29860Sstevel@tonic-gate 	lattice_leaf = leaf + EHCI_NUM_INTR_QH_LISTS - 1;
29870Sstevel@tonic-gate 
29880Sstevel@tonic-gate 	/* Get the node in the lattice based on the height and leaf */
29890Sstevel@tonic-gate 	pnode = lattice_leaf;
29900Sstevel@tonic-gate 	for (i = 0; i < height; i++) {
29910Sstevel@tonic-gate 		pnode = ehci_lattice_parent(pnode);
29920Sstevel@tonic-gate 	}
29930Sstevel@tonic-gate 
29940Sstevel@tonic-gate 	return (pnode);
29950Sstevel@tonic-gate }
29960Sstevel@tonic-gate 
29970Sstevel@tonic-gate 
29980Sstevel@tonic-gate /*
29990Sstevel@tonic-gate  * ehci_leftmost_leaf:
30000Sstevel@tonic-gate  *
30010Sstevel@tonic-gate  * Find the leftmost leaf in the subtree specified by the node. Height refers
30020Sstevel@tonic-gate  * to number of nodes from the bottom of the tree to the node,	including the
30030Sstevel@tonic-gate  * node.
30040Sstevel@tonic-gate  *
30050Sstevel@tonic-gate  * The formula for a zero based tree is:
30060Sstevel@tonic-gate  *     2^H * Node + 2^H - 1
30070Sstevel@tonic-gate  * The leaf of the tree is an array, convert the number for the array.
30080Sstevel@tonic-gate  *     Subtract the size of nodes not in the array
30090Sstevel@tonic-gate  *     2^H * Node + 2^H - 1 - (EHCI_NUM_INTR_QH_LISTS - 1) =
30100Sstevel@tonic-gate  *     2^H * Node + 2^H - EHCI_NUM_INTR_QH_LISTS =
30110Sstevel@tonic-gate  *     2^H * (Node + 1) - EHCI_NUM_INTR_QH_LISTS
30120Sstevel@tonic-gate  *	   0
30130Sstevel@tonic-gate  *	 1   2
30140Sstevel@tonic-gate  *	0 1 2 3
30150Sstevel@tonic-gate  */
30160Sstevel@tonic-gate static uint_t
ehci_leftmost_leaf(uint_t node,uint_t height)30170Sstevel@tonic-gate ehci_leftmost_leaf(
30180Sstevel@tonic-gate 	uint_t	node,
30190Sstevel@tonic-gate 	uint_t	height)
30200Sstevel@tonic-gate {
30210Sstevel@tonic-gate 	return ((ehci_pow_2(height) * (node + 1)) - EHCI_NUM_INTR_QH_LISTS);
30220Sstevel@tonic-gate }
30230Sstevel@tonic-gate 
30240Sstevel@tonic-gate 
30250Sstevel@tonic-gate /*
30260Sstevel@tonic-gate  * ehci_pow_2:
30270Sstevel@tonic-gate  *
30280Sstevel@tonic-gate  * Compute 2 to the power
30290Sstevel@tonic-gate  */
30300Sstevel@tonic-gate static uint_t
ehci_pow_2(uint_t x)30310Sstevel@tonic-gate ehci_pow_2(uint_t x)
30320Sstevel@tonic-gate {
30330Sstevel@tonic-gate 	if (x == 0) {
30340Sstevel@tonic-gate 
30350Sstevel@tonic-gate 		return (1);
30360Sstevel@tonic-gate 	} else {
30370Sstevel@tonic-gate 
30380Sstevel@tonic-gate 		return (2 << (x - 1));
30390Sstevel@tonic-gate 	}
30400Sstevel@tonic-gate }
30410Sstevel@tonic-gate 
30420Sstevel@tonic-gate 
30430Sstevel@tonic-gate /*
30440Sstevel@tonic-gate  * ehci_log_2:
30450Sstevel@tonic-gate  *
30460Sstevel@tonic-gate  * Compute log base 2 of x
30470Sstevel@tonic-gate  */
30480Sstevel@tonic-gate static uint_t
ehci_log_2(uint_t x)30490Sstevel@tonic-gate ehci_log_2(uint_t x)
30500Sstevel@tonic-gate {
30510Sstevel@tonic-gate 	int i = 0;
30520Sstevel@tonic-gate 
30530Sstevel@tonic-gate 	while (x != 1) {
30540Sstevel@tonic-gate 		x = x >> 1;
30550Sstevel@tonic-gate 		i++;
30560Sstevel@tonic-gate 	}
30570Sstevel@tonic-gate 
30580Sstevel@tonic-gate 	return (i);
30590Sstevel@tonic-gate }
30600Sstevel@tonic-gate 
30610Sstevel@tonic-gate 
30620Sstevel@tonic-gate /*
30630Sstevel@tonic-gate  * ehci_find_bestfit_hs_mask:
30640Sstevel@tonic-gate  *
30650Sstevel@tonic-gate  * Find the smask and cmask in the bandwidth allocation, and update the
30660Sstevel@tonic-gate  * bandwidth allocation.
30670Sstevel@tonic-gate  */
30680Sstevel@tonic-gate static int
ehci_find_bestfit_hs_mask(ehci_state_t * ehcip,uchar_t * smask,uint_t * pnode,usb_ep_descr_t * endpoint,uint_t bandwidth,int interval)30690Sstevel@tonic-gate ehci_find_bestfit_hs_mask(
30700Sstevel@tonic-gate 	ehci_state_t	*ehcip,
30710Sstevel@tonic-gate 	uchar_t		*smask,
30720Sstevel@tonic-gate 	uint_t		*pnode,
30730Sstevel@tonic-gate 	usb_ep_descr_t	*endpoint,
30740Sstevel@tonic-gate 	uint_t		bandwidth,
30750Sstevel@tonic-gate 	int		interval)
30760Sstevel@tonic-gate {
30770Sstevel@tonic-gate 	int		i;
30780Sstevel@tonic-gate 	uint_t		elements, index;
30790Sstevel@tonic-gate 	int		array_leaf, best_array_leaf;
30800Sstevel@tonic-gate 	uint_t		node_bandwidth, best_node_bandwidth;
30810Sstevel@tonic-gate 	uint_t		leaf_count;
30820Sstevel@tonic-gate 	uchar_t		bw_mask;
30830Sstevel@tonic-gate 	uchar_t		best_smask;
30840Sstevel@tonic-gate 
30850Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
30860Sstevel@tonic-gate 	    "ehci_find_bestfit_hs_mask: ");
30870Sstevel@tonic-gate 
30880Sstevel@tonic-gate 	/* Get all the valid smasks */
30890Sstevel@tonic-gate 	switch (ehci_pow_2(endpoint->bInterval - 1)) {
30900Sstevel@tonic-gate 	case EHCI_INTR_1US_POLL:
30910Sstevel@tonic-gate 		index = EHCI_1US_MASK_INDEX;
30920Sstevel@tonic-gate 		elements = EHCI_INTR_1US_POLL;
30930Sstevel@tonic-gate 		break;
30940Sstevel@tonic-gate 	case EHCI_INTR_2US_POLL:
30950Sstevel@tonic-gate 		index = EHCI_2US_MASK_INDEX;
30960Sstevel@tonic-gate 		elements = EHCI_INTR_2US_POLL;
30970Sstevel@tonic-gate 		break;
30980Sstevel@tonic-gate 	case EHCI_INTR_4US_POLL:
30990Sstevel@tonic-gate 		index = EHCI_4US_MASK_INDEX;
31000Sstevel@tonic-gate 		elements = EHCI_INTR_4US_POLL;
31010Sstevel@tonic-gate 		break;
31020Sstevel@tonic-gate 	case EHCI_INTR_XUS_POLL:
31030Sstevel@tonic-gate 	default:
31040Sstevel@tonic-gate 		index = EHCI_XUS_MASK_INDEX;
31050Sstevel@tonic-gate 		elements = EHCI_INTR_XUS_POLL;
31060Sstevel@tonic-gate 		break;
31070Sstevel@tonic-gate 	}
31080Sstevel@tonic-gate 
31090Sstevel@tonic-gate 	leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
31100Sstevel@tonic-gate 
31110Sstevel@tonic-gate 	/*
31120Sstevel@tonic-gate 	 * Because of the way the leaves are setup, we will automatically
31130Sstevel@tonic-gate 	 * hit the leftmost leaf of every possible node with this interval.
31140Sstevel@tonic-gate 	 */
31150Sstevel@tonic-gate 	best_smask = 0x00;
31160Sstevel@tonic-gate 	best_node_bandwidth = 0;
31170Sstevel@tonic-gate 	for (array_leaf = 0; array_leaf < interval; array_leaf++) {
31180Sstevel@tonic-gate 		/* Find the bandwidth mask */
31190Sstevel@tonic-gate 		node_bandwidth = ehci_calculate_bw_availability_mask(ehcip,
31200Sstevel@tonic-gate 		    bandwidth, ehci_index[array_leaf], leaf_count, &bw_mask);
31210Sstevel@tonic-gate 
31220Sstevel@tonic-gate 		/*
31230Sstevel@tonic-gate 		 * If this node cannot support our requirements skip to the
31240Sstevel@tonic-gate 		 * next leaf.
31250Sstevel@tonic-gate 		 */
31260Sstevel@tonic-gate 		if (bw_mask == 0x00) {
31270Sstevel@tonic-gate 			continue;
31280Sstevel@tonic-gate 		}
31290Sstevel@tonic-gate 
31300Sstevel@tonic-gate 		/*
31310Sstevel@tonic-gate 		 * Now make sure our bandwidth requirements can be
31320Sstevel@tonic-gate 		 * satisfied with one of smasks in this node.
31330Sstevel@tonic-gate 		 */
31340Sstevel@tonic-gate 		*smask = 0x00;
31350Sstevel@tonic-gate 		for (i = index; i < (index + elements); i++) {
31360Sstevel@tonic-gate 			/* Check the start split mask value */
31370Sstevel@tonic-gate 			if (ehci_start_split_mask[index] & bw_mask) {
31380Sstevel@tonic-gate 				*smask = ehci_start_split_mask[index];
31390Sstevel@tonic-gate 				break;
31400Sstevel@tonic-gate 			}
31410Sstevel@tonic-gate 		}
31420Sstevel@tonic-gate 
31430Sstevel@tonic-gate 		/*
31440Sstevel@tonic-gate 		 * If an appropriate smask is found save the information if:
31450Sstevel@tonic-gate 		 * o best_smask has not been found yet.
31460Sstevel@tonic-gate 		 * - or -
31470Sstevel@tonic-gate 		 * o This is the node with the least amount of bandwidth
31480Sstevel@tonic-gate 		 */
31490Sstevel@tonic-gate 		if ((*smask != 0x00) &&
31500Sstevel@tonic-gate 		    ((best_smask == 0x00) ||
31515767Slc152243 		    (best_node_bandwidth > node_bandwidth))) {
31520Sstevel@tonic-gate 
31530Sstevel@tonic-gate 			best_node_bandwidth = node_bandwidth;
31540Sstevel@tonic-gate 			best_array_leaf = array_leaf;
31550Sstevel@tonic-gate 			best_smask = *smask;
31560Sstevel@tonic-gate 		}
31570Sstevel@tonic-gate 	}
31580Sstevel@tonic-gate 
31590Sstevel@tonic-gate 	/*
31600Sstevel@tonic-gate 	 * If we find node that can handle the bandwidth populate the
31610Sstevel@tonic-gate 	 * appropriate variables and return success.
31620Sstevel@tonic-gate 	 */
31630Sstevel@tonic-gate 	if (best_smask) {
31640Sstevel@tonic-gate 		*smask = best_smask;
31650Sstevel@tonic-gate 		*pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
31660Sstevel@tonic-gate 		    interval);
31670Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, bandwidth,
31680Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_smask);
31690Sstevel@tonic-gate 
31700Sstevel@tonic-gate 		return (USB_SUCCESS);
31710Sstevel@tonic-gate 	}
31720Sstevel@tonic-gate 
31730Sstevel@tonic-gate 	return (USB_FAILURE);
31740Sstevel@tonic-gate }
31750Sstevel@tonic-gate 
31760Sstevel@tonic-gate 
31770Sstevel@tonic-gate /*
31780Sstevel@tonic-gate  * ehci_find_bestfit_ls_intr_mask:
31790Sstevel@tonic-gate  *
31800Sstevel@tonic-gate  * Find the smask and cmask in the bandwidth allocation.
31810Sstevel@tonic-gate  */
31820Sstevel@tonic-gate static int
ehci_find_bestfit_ls_intr_mask(ehci_state_t * ehcip,uchar_t * smask,uchar_t * cmask,uint_t * pnode,uint_t sbandwidth,uint_t cbandwidth,int interval)31830Sstevel@tonic-gate ehci_find_bestfit_ls_intr_mask(
31840Sstevel@tonic-gate 	ehci_state_t	*ehcip,
31850Sstevel@tonic-gate 	uchar_t		*smask,
31860Sstevel@tonic-gate 	uchar_t		*cmask,
31870Sstevel@tonic-gate 	uint_t		*pnode,
31880Sstevel@tonic-gate 	uint_t		sbandwidth,
31890Sstevel@tonic-gate 	uint_t		cbandwidth,
31900Sstevel@tonic-gate 	int		interval)
31910Sstevel@tonic-gate {
31920Sstevel@tonic-gate 	int		i;
31930Sstevel@tonic-gate 	uint_t		elements, index;
31940Sstevel@tonic-gate 	int		array_leaf, best_array_leaf;
31950Sstevel@tonic-gate 	uint_t		node_sbandwidth, node_cbandwidth;
31960Sstevel@tonic-gate 	uint_t		best_node_bandwidth;
31970Sstevel@tonic-gate 	uint_t		leaf_count;
31980Sstevel@tonic-gate 	uchar_t		bw_smask, bw_cmask;
31990Sstevel@tonic-gate 	uchar_t		best_smask, best_cmask;
32000Sstevel@tonic-gate 
32010Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
32020Sstevel@tonic-gate 	    "ehci_find_bestfit_ls_intr_mask: ");
32030Sstevel@tonic-gate 
32040Sstevel@tonic-gate 	/* For low and full speed devices */
32050Sstevel@tonic-gate 	index = EHCI_XUS_MASK_INDEX;
32060Sstevel@tonic-gate 	elements = EHCI_INTR_4MS_POLL;
32070Sstevel@tonic-gate 
32080Sstevel@tonic-gate 	leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
32090Sstevel@tonic-gate 
32100Sstevel@tonic-gate 	/*
32110Sstevel@tonic-gate 	 * Because of the way the leaves are setup, we will automatically
32120Sstevel@tonic-gate 	 * hit the leftmost leaf of every possible node with this interval.
32130Sstevel@tonic-gate 	 */
32140Sstevel@tonic-gate 	best_smask = 0x00;
32150Sstevel@tonic-gate 	best_node_bandwidth = 0;
32160Sstevel@tonic-gate 	for (array_leaf = 0; array_leaf < interval; array_leaf++) {
32170Sstevel@tonic-gate 		/* Find the bandwidth mask */
32180Sstevel@tonic-gate 		node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip,
32190Sstevel@tonic-gate 		    sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask);
32200Sstevel@tonic-gate 		node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip,
32210Sstevel@tonic-gate 		    cbandwidth, ehci_index[array_leaf], leaf_count, &bw_cmask);
32220Sstevel@tonic-gate 
32230Sstevel@tonic-gate 		/*
32240Sstevel@tonic-gate 		 * If this node cannot support our requirements skip to the
32250Sstevel@tonic-gate 		 * next leaf.
32260Sstevel@tonic-gate 		 */
32270Sstevel@tonic-gate 		if ((bw_smask == 0x00) || (bw_cmask == 0x00)) {
32280Sstevel@tonic-gate 			continue;
32290Sstevel@tonic-gate 		}
32300Sstevel@tonic-gate 
32310Sstevel@tonic-gate 		/*
32320Sstevel@tonic-gate 		 * Now make sure our bandwidth requirements can be
32330Sstevel@tonic-gate 		 * satisfied with one of smasks in this node.
32340Sstevel@tonic-gate 		 */
32350Sstevel@tonic-gate 		*smask = 0x00;
32360Sstevel@tonic-gate 		*cmask = 0x00;
32370Sstevel@tonic-gate 		for (i = index; i < (index + elements); i++) {
32380Sstevel@tonic-gate 			/* Check the start split mask value */
32390Sstevel@tonic-gate 			if ((ehci_start_split_mask[index] & bw_smask) &&
32400Sstevel@tonic-gate 			    (ehci_intr_complete_split_mask[index] & bw_cmask)) {
32410Sstevel@tonic-gate 				*smask = ehci_start_split_mask[index];
32420Sstevel@tonic-gate 				*cmask = ehci_intr_complete_split_mask[index];
32430Sstevel@tonic-gate 				break;
32440Sstevel@tonic-gate 			}
32450Sstevel@tonic-gate 		}
32460Sstevel@tonic-gate 
32470Sstevel@tonic-gate 		/*
32480Sstevel@tonic-gate 		 * If an appropriate smask is found save the information if:
32490Sstevel@tonic-gate 		 * o best_smask has not been found yet.
32500Sstevel@tonic-gate 		 * - or -
32510Sstevel@tonic-gate 		 * o This is the node with the least amount of bandwidth
32520Sstevel@tonic-gate 		 */
32530Sstevel@tonic-gate 		if ((*smask != 0x00) &&
32540Sstevel@tonic-gate 		    ((best_smask == 0x00) ||
32555767Slc152243 		    (best_node_bandwidth >
32565767Slc152243 		    (node_sbandwidth + node_cbandwidth)))) {
32570Sstevel@tonic-gate 			best_node_bandwidth = node_sbandwidth + node_cbandwidth;
32580Sstevel@tonic-gate 			best_array_leaf = array_leaf;
32590Sstevel@tonic-gate 			best_smask = *smask;
32600Sstevel@tonic-gate 			best_cmask = *cmask;
32610Sstevel@tonic-gate 		}
32620Sstevel@tonic-gate 	}
32630Sstevel@tonic-gate 
32640Sstevel@tonic-gate 	/*
32650Sstevel@tonic-gate 	 * If we find node that can handle the bandwidth populate the
32660Sstevel@tonic-gate 	 * appropriate variables and return success.
32670Sstevel@tonic-gate 	 */
32680Sstevel@tonic-gate 	if (best_smask) {
32690Sstevel@tonic-gate 		*smask = best_smask;
32700Sstevel@tonic-gate 		*cmask = best_cmask;
32710Sstevel@tonic-gate 		*pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
32720Sstevel@tonic-gate 		    interval);
32730Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, sbandwidth,
32740Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_smask);
32750Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, cbandwidth,
32760Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_cmask);
32770Sstevel@tonic-gate 
32780Sstevel@tonic-gate 		return (USB_SUCCESS);
32790Sstevel@tonic-gate 	}
32800Sstevel@tonic-gate 
32810Sstevel@tonic-gate 	return (USB_FAILURE);
32820Sstevel@tonic-gate }
32830Sstevel@tonic-gate 
32840Sstevel@tonic-gate 
32850Sstevel@tonic-gate /*
32860Sstevel@tonic-gate  * ehci_find_bestfit_sitd_in_mask:
32870Sstevel@tonic-gate  *
32880Sstevel@tonic-gate  * Find the smask and cmask in the bandwidth allocation.
32890Sstevel@tonic-gate  */
32900Sstevel@tonic-gate static int
ehci_find_bestfit_sitd_in_mask(ehci_state_t * ehcip,uchar_t * smask,uchar_t * cmask,uint_t * pnode,uint_t sbandwidth,uint_t cbandwidth,int interval)32910Sstevel@tonic-gate ehci_find_bestfit_sitd_in_mask(
32920Sstevel@tonic-gate 	ehci_state_t	*ehcip,
32930Sstevel@tonic-gate 	uchar_t		*smask,
32940Sstevel@tonic-gate 	uchar_t		*cmask,
32950Sstevel@tonic-gate 	uint_t		*pnode,
32960Sstevel@tonic-gate 	uint_t		sbandwidth,
32970Sstevel@tonic-gate 	uint_t		cbandwidth,
32980Sstevel@tonic-gate 	int		interval)
32990Sstevel@tonic-gate {
33000Sstevel@tonic-gate 	int		i, uFrames, found;
33010Sstevel@tonic-gate 	int		array_leaf, best_array_leaf;
33020Sstevel@tonic-gate 	uint_t		node_sbandwidth, node_cbandwidth;
33030Sstevel@tonic-gate 	uint_t		best_node_bandwidth;
33040Sstevel@tonic-gate 	uint_t		leaf_count;
33050Sstevel@tonic-gate 	uchar_t		bw_smask, bw_cmask;
33060Sstevel@tonic-gate 	uchar_t		best_smask, best_cmask;
33070Sstevel@tonic-gate 
33080Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
33090Sstevel@tonic-gate 	    "ehci_find_bestfit_sitd_in_mask: ");
33100Sstevel@tonic-gate 
33110Sstevel@tonic-gate 	leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
33120Sstevel@tonic-gate 
33130Sstevel@tonic-gate 	/*
33140Sstevel@tonic-gate 	 * Because of the way the leaves are setup, we will automatically
33150Sstevel@tonic-gate 	 * hit the leftmost leaf of every possible node with this interval.
33160Sstevel@tonic-gate 	 * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame.
33170Sstevel@tonic-gate 	 */
33180Sstevel@tonic-gate 	/*
33190Sstevel@tonic-gate 	 * Need to add an additional 2 uFrames, if the "L"ast
33200Sstevel@tonic-gate 	 * complete split is before uFrame 6.  See section
33210Sstevel@tonic-gate 	 * 11.8.4 in USB 2.0 Spec.  Currently we do not support
33220Sstevel@tonic-gate 	 * the "Back Ptr" which means we support on IN of
33230Sstevel@tonic-gate 	 * ~4*MAX_UFRAME_SITD_XFER bandwidth/
33240Sstevel@tonic-gate 	 */
33250Sstevel@tonic-gate 	uFrames = (cbandwidth / MAX_UFRAME_SITD_XFER) + 2;
33260Sstevel@tonic-gate 	if (cbandwidth % MAX_UFRAME_SITD_XFER) {
33270Sstevel@tonic-gate 		uFrames++;
33280Sstevel@tonic-gate 	}
33290Sstevel@tonic-gate 	if (uFrames > 6) {
33300Sstevel@tonic-gate 
33310Sstevel@tonic-gate 		return (USB_FAILURE);
33320Sstevel@tonic-gate 	}
33330Sstevel@tonic-gate 	*smask = 0x1;
33340Sstevel@tonic-gate 	*cmask = 0x00;
33350Sstevel@tonic-gate 	for (i = 0; i < uFrames; i++) {
33360Sstevel@tonic-gate 		*cmask = *cmask << 1;
33370Sstevel@tonic-gate 		*cmask |= 0x1;
33380Sstevel@tonic-gate 	}
33390Sstevel@tonic-gate 	/* cmask must start 2 frames after the smask */
33400Sstevel@tonic-gate 	*cmask = *cmask << 2;
33410Sstevel@tonic-gate 
33420Sstevel@tonic-gate 	found = 0;
33430Sstevel@tonic-gate 	best_smask = 0x00;
33440Sstevel@tonic-gate 	best_node_bandwidth = 0;
33450Sstevel@tonic-gate 	for (array_leaf = 0; array_leaf < interval; array_leaf++) {
33460Sstevel@tonic-gate 		node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip,
33470Sstevel@tonic-gate 		    sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask);
33480Sstevel@tonic-gate 		node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip,
33490Sstevel@tonic-gate 		    MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count,
33500Sstevel@tonic-gate 		    &bw_cmask);
33510Sstevel@tonic-gate 
33520Sstevel@tonic-gate 		/*
33530Sstevel@tonic-gate 		 * If this node cannot support our requirements skip to the
33540Sstevel@tonic-gate 		 * next leaf.
33550Sstevel@tonic-gate 		 */
33560Sstevel@tonic-gate 		if ((bw_smask == 0x00) || (bw_cmask == 0x00)) {
33570Sstevel@tonic-gate 			continue;
33580Sstevel@tonic-gate 		}
33590Sstevel@tonic-gate 
33600Sstevel@tonic-gate 		for (i = 0; i < (EHCI_MAX_UFRAMES - uFrames - 2); i++) {
33610Sstevel@tonic-gate 			if ((*smask & bw_smask) && (*cmask & bw_cmask)) {
33620Sstevel@tonic-gate 				found = 1;
33630Sstevel@tonic-gate 				break;
33640Sstevel@tonic-gate 			}
33650Sstevel@tonic-gate 			*smask = *smask << 1;
33660Sstevel@tonic-gate 			*cmask = *cmask << 1;
33670Sstevel@tonic-gate 		}
33680Sstevel@tonic-gate 
33690Sstevel@tonic-gate 		/*
33700Sstevel@tonic-gate 		 * If an appropriate smask is found save the information if:
33710Sstevel@tonic-gate 		 * o best_smask has not been found yet.
33720Sstevel@tonic-gate 		 * - or -
33730Sstevel@tonic-gate 		 * o This is the node with the least amount of bandwidth
33740Sstevel@tonic-gate 		 */
33750Sstevel@tonic-gate 		if (found &&
33760Sstevel@tonic-gate 		    ((best_smask == 0x00) ||
33775767Slc152243 		    (best_node_bandwidth >
33785767Slc152243 		    (node_sbandwidth + node_cbandwidth)))) {
33790Sstevel@tonic-gate 			best_node_bandwidth = node_sbandwidth + node_cbandwidth;
33800Sstevel@tonic-gate 			best_array_leaf = array_leaf;
33810Sstevel@tonic-gate 			best_smask = *smask;
33820Sstevel@tonic-gate 			best_cmask = *cmask;
33830Sstevel@tonic-gate 		}
33840Sstevel@tonic-gate 	}
33850Sstevel@tonic-gate 
33860Sstevel@tonic-gate 	/*
33870Sstevel@tonic-gate 	 * If we find node that can handle the bandwidth populate the
33880Sstevel@tonic-gate 	 * appropriate variables and return success.
33890Sstevel@tonic-gate 	 */
33900Sstevel@tonic-gate 	if (best_smask) {
33910Sstevel@tonic-gate 		*smask = best_smask;
33920Sstevel@tonic-gate 		*cmask = best_cmask;
33930Sstevel@tonic-gate 		*pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
33940Sstevel@tonic-gate 		    interval);
33950Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, sbandwidth,
33960Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_smask);
33970Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER,
33980Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_cmask);
33990Sstevel@tonic-gate 
34000Sstevel@tonic-gate 		return (USB_SUCCESS);
34010Sstevel@tonic-gate 	}
34020Sstevel@tonic-gate 
34030Sstevel@tonic-gate 	return (USB_FAILURE);
34040Sstevel@tonic-gate }
34050Sstevel@tonic-gate 
34060Sstevel@tonic-gate 
34070Sstevel@tonic-gate /*
34080Sstevel@tonic-gate  * ehci_find_bestfit_sitd_out_mask:
34090Sstevel@tonic-gate  *
34100Sstevel@tonic-gate  * Find the smask in the bandwidth allocation.
34110Sstevel@tonic-gate  */
34120Sstevel@tonic-gate static int
ehci_find_bestfit_sitd_out_mask(ehci_state_t * ehcip,uchar_t * smask,uint_t * pnode,uint_t sbandwidth,int interval)34130Sstevel@tonic-gate ehci_find_bestfit_sitd_out_mask(
34140Sstevel@tonic-gate 	ehci_state_t	*ehcip,
34150Sstevel@tonic-gate 	uchar_t		*smask,
34160Sstevel@tonic-gate 	uint_t		*pnode,
34170Sstevel@tonic-gate 	uint_t		sbandwidth,
34180Sstevel@tonic-gate 	int		interval)
34190Sstevel@tonic-gate {
34200Sstevel@tonic-gate 	int		i, uFrames, found;
34210Sstevel@tonic-gate 	int		array_leaf, best_array_leaf;
34220Sstevel@tonic-gate 	uint_t		node_sbandwidth;
34230Sstevel@tonic-gate 	uint_t		best_node_bandwidth;
34240Sstevel@tonic-gate 	uint_t		leaf_count;
34250Sstevel@tonic-gate 	uchar_t		bw_smask;
34260Sstevel@tonic-gate 	uchar_t		best_smask;
34270Sstevel@tonic-gate 
34280Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
34290Sstevel@tonic-gate 	    "ehci_find_bestfit_sitd_out_mask: ");
34300Sstevel@tonic-gate 
34310Sstevel@tonic-gate 	leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
34320Sstevel@tonic-gate 
34330Sstevel@tonic-gate 	/*
34340Sstevel@tonic-gate 	 * Because of the way the leaves are setup, we will automatically
34350Sstevel@tonic-gate 	 * hit the leftmost leaf of every possible node with this interval.
34360Sstevel@tonic-gate 	 * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame.
34370Sstevel@tonic-gate 	 */
34380Sstevel@tonic-gate 	*smask = 0x00;
34390Sstevel@tonic-gate 	uFrames = sbandwidth / MAX_UFRAME_SITD_XFER;
34400Sstevel@tonic-gate 	if (sbandwidth % MAX_UFRAME_SITD_XFER) {
34410Sstevel@tonic-gate 		uFrames++;
34420Sstevel@tonic-gate 	}
34430Sstevel@tonic-gate 	for (i = 0; i < uFrames; i++) {
34440Sstevel@tonic-gate 		*smask = *smask << 1;
34450Sstevel@tonic-gate 		*smask |= 0x1;
34460Sstevel@tonic-gate 	}
34470Sstevel@tonic-gate 
34480Sstevel@tonic-gate 	found = 0;
34490Sstevel@tonic-gate 	best_smask = 0x00;
34500Sstevel@tonic-gate 	best_node_bandwidth = 0;
34510Sstevel@tonic-gate 	for (array_leaf = 0; array_leaf < interval; array_leaf++) {
34520Sstevel@tonic-gate 		node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip,
34530Sstevel@tonic-gate 		    MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count,
34540Sstevel@tonic-gate 		    &bw_smask);
34550Sstevel@tonic-gate 
34560Sstevel@tonic-gate 		/*
34570Sstevel@tonic-gate 		 * If this node cannot support our requirements skip to the
34580Sstevel@tonic-gate 		 * next leaf.
34590Sstevel@tonic-gate 		 */
34600Sstevel@tonic-gate 		if (bw_smask == 0x00) {
34610Sstevel@tonic-gate 			continue;
34620Sstevel@tonic-gate 		}
34630Sstevel@tonic-gate 
34640Sstevel@tonic-gate 		/* You cannot have a start split on the 8th uFrame */
34650Sstevel@tonic-gate 		for (i = 0; (*smask & 0x80) == 0; i++) {
34660Sstevel@tonic-gate 			if (*smask & bw_smask) {
34670Sstevel@tonic-gate 				found = 1;
34680Sstevel@tonic-gate 				break;
34690Sstevel@tonic-gate 			}
34700Sstevel@tonic-gate 			*smask = *smask << 1;
34710Sstevel@tonic-gate 		}
34720Sstevel@tonic-gate 
34730Sstevel@tonic-gate 		/*
34740Sstevel@tonic-gate 		 * If an appropriate smask is found save the information if:
34750Sstevel@tonic-gate 		 * o best_smask has not been found yet.
34760Sstevel@tonic-gate 		 * - or -
34770Sstevel@tonic-gate 		 * o This is the node with the least amount of bandwidth
34780Sstevel@tonic-gate 		 */
34790Sstevel@tonic-gate 		if (found &&
34800Sstevel@tonic-gate 		    ((best_smask == 0x00) ||
34815767Slc152243 		    (best_node_bandwidth > node_sbandwidth))) {
34820Sstevel@tonic-gate 			best_node_bandwidth = node_sbandwidth;
34830Sstevel@tonic-gate 			best_array_leaf = array_leaf;
34840Sstevel@tonic-gate 			best_smask = *smask;
34850Sstevel@tonic-gate 		}
34860Sstevel@tonic-gate 	}
34870Sstevel@tonic-gate 
34880Sstevel@tonic-gate 	/*
34890Sstevel@tonic-gate 	 * If we find node that can handle the bandwidth populate the
34900Sstevel@tonic-gate 	 * appropriate variables and return success.
34910Sstevel@tonic-gate 	 */
34920Sstevel@tonic-gate 	if (best_smask) {
34930Sstevel@tonic-gate 		*smask = best_smask;
34940Sstevel@tonic-gate 		*pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
34950Sstevel@tonic-gate 		    interval);
34960Sstevel@tonic-gate 		ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER,
34970Sstevel@tonic-gate 		    ehci_index[best_array_leaf], leaf_count, best_smask);
34980Sstevel@tonic-gate 
34990Sstevel@tonic-gate 		return (USB_SUCCESS);
35000Sstevel@tonic-gate 	}
35010Sstevel@tonic-gate 
35020Sstevel@tonic-gate 	return (USB_FAILURE);
35030Sstevel@tonic-gate }
35040Sstevel@tonic-gate 
35050Sstevel@tonic-gate 
35060Sstevel@tonic-gate /*
35070Sstevel@tonic-gate  * ehci_calculate_bw_availability_mask:
35080Sstevel@tonic-gate  *
35090Sstevel@tonic-gate  * Returns the "total bandwidth used" in this node.
35100Sstevel@tonic-gate  * Populates bw_mask with the uFrames that can support the bandwidth.
35110Sstevel@tonic-gate  *
35120Sstevel@tonic-gate  * If all the Frames cannot support this bandwidth, then bw_mask
35130Sstevel@tonic-gate  * will return 0x00 and the "total bandwidth used" will be invalid.
35140Sstevel@tonic-gate  */
35150Sstevel@tonic-gate static uint_t
ehci_calculate_bw_availability_mask(ehci_state_t * ehcip,uint_t bandwidth,int leaf,int leaf_count,uchar_t * bw_mask)35160Sstevel@tonic-gate ehci_calculate_bw_availability_mask(
35170Sstevel@tonic-gate 	ehci_state_t	*ehcip,
35180Sstevel@tonic-gate 	uint_t		bandwidth,
35190Sstevel@tonic-gate 	int		leaf,
35200Sstevel@tonic-gate 	int		leaf_count,
35210Sstevel@tonic-gate 	uchar_t		*bw_mask)
35220Sstevel@tonic-gate {
35230Sstevel@tonic-gate 	int			i, j;
35240Sstevel@tonic-gate 	uchar_t			bw_uframe;
35250Sstevel@tonic-gate 	int			uframe_total;
35260Sstevel@tonic-gate 	ehci_frame_bandwidth_t	*fbp;
35270Sstevel@tonic-gate 	uint_t			total_bandwidth = 0;
35280Sstevel@tonic-gate 
35290Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
35300Sstevel@tonic-gate 	    "ehci_calculate_bw_availability_mask: leaf %d leaf count %d",
35310Sstevel@tonic-gate 	    leaf, leaf_count);
35320Sstevel@tonic-gate 
35330Sstevel@tonic-gate 	/* Start by saying all uFrames are available */
35340Sstevel@tonic-gate 	*bw_mask = 0xFF;
35350Sstevel@tonic-gate 
35360Sstevel@tonic-gate 	for (i = 0; (i < leaf_count) || (*bw_mask == 0x00); i++) {
35370Sstevel@tonic-gate 		fbp = &ehcip->ehci_frame_bandwidth[leaf + i];
35380Sstevel@tonic-gate 
35390Sstevel@tonic-gate 		total_bandwidth += fbp->ehci_allocated_frame_bandwidth;
35400Sstevel@tonic-gate 
35410Sstevel@tonic-gate 		for (j = 0; j < EHCI_MAX_UFRAMES; j++) {
35420Sstevel@tonic-gate 			/*
35430Sstevel@tonic-gate 			 * If the uFrame in bw_mask is available check to see if
35440Sstevel@tonic-gate 			 * it can support the additional bandwidth.
35450Sstevel@tonic-gate 			 */
35460Sstevel@tonic-gate 			bw_uframe = (*bw_mask & (0x1 << j));
35470Sstevel@tonic-gate 			uframe_total =
35480Sstevel@tonic-gate 			    fbp->ehci_micro_frame_bandwidth[j] +
35490Sstevel@tonic-gate 			    bandwidth;
35500Sstevel@tonic-gate 			if ((bw_uframe) &&
35510Sstevel@tonic-gate 			    (uframe_total > HS_PERIODIC_BANDWIDTH)) {
35520Sstevel@tonic-gate 				*bw_mask = *bw_mask & ~bw_uframe;
35530Sstevel@tonic-gate 			}
35540Sstevel@tonic-gate 		}
35550Sstevel@tonic-gate 	}
35560Sstevel@tonic-gate 
35570Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
35580Sstevel@tonic-gate 	    "ehci_calculate_bw_availability_mask: bandwidth mask 0x%x",
35590Sstevel@tonic-gate 	    *bw_mask);
35600Sstevel@tonic-gate 
35610Sstevel@tonic-gate 	return (total_bandwidth);
35620Sstevel@tonic-gate }
35630Sstevel@tonic-gate 
35640Sstevel@tonic-gate 
35650Sstevel@tonic-gate /*
35660Sstevel@tonic-gate  * ehci_update_bw_availability:
35670Sstevel@tonic-gate  *
35680Sstevel@tonic-gate  * The leftmost leaf needs to be in terms of array position and
35690Sstevel@tonic-gate  * not the actual lattice position.
35700Sstevel@tonic-gate  */
35710Sstevel@tonic-gate static void
ehci_update_bw_availability(ehci_state_t * ehcip,int bandwidth,int leftmost_leaf,int leaf_count,uchar_t mask)35720Sstevel@tonic-gate ehci_update_bw_availability(
35730Sstevel@tonic-gate 	ehci_state_t	*ehcip,
35740Sstevel@tonic-gate 	int		bandwidth,
35750Sstevel@tonic-gate 	int		leftmost_leaf,
35760Sstevel@tonic-gate 	int		leaf_count,
35770Sstevel@tonic-gate 	uchar_t		mask)
35780Sstevel@tonic-gate {
35790Sstevel@tonic-gate 	int			i, j;
35800Sstevel@tonic-gate 	ehci_frame_bandwidth_t	*fbp;
35810Sstevel@tonic-gate 	int			uFrame_bandwidth[8];
35820Sstevel@tonic-gate 
35830Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
35840Sstevel@tonic-gate 	    "ehci_update_bw_availability: "
35850Sstevel@tonic-gate 	    "leaf %d count %d bandwidth 0x%x mask 0x%x",
35860Sstevel@tonic-gate 	    leftmost_leaf, leaf_count, bandwidth, mask);
35870Sstevel@tonic-gate 
35880Sstevel@tonic-gate 	ASSERT(leftmost_leaf < 32);
35890Sstevel@tonic-gate 	ASSERT(leftmost_leaf >= 0);
35900Sstevel@tonic-gate 
35910Sstevel@tonic-gate 	for (j = 0; j < EHCI_MAX_UFRAMES; j++) {
35920Sstevel@tonic-gate 		if (mask & 0x1) {
35930Sstevel@tonic-gate 			uFrame_bandwidth[j] = bandwidth;
35940Sstevel@tonic-gate 		} else {
35950Sstevel@tonic-gate 			uFrame_bandwidth[j] = 0;
35960Sstevel@tonic-gate 		}
35970Sstevel@tonic-gate 
35980Sstevel@tonic-gate 		mask = mask >> 1;
35990Sstevel@tonic-gate 	}
36000Sstevel@tonic-gate 
36010Sstevel@tonic-gate 	/* Updated all the effected leafs with the bandwidth */
36020Sstevel@tonic-gate 	for (i = 0; i < leaf_count; i++) {
36030Sstevel@tonic-gate 		fbp = &ehcip->ehci_frame_bandwidth[leftmost_leaf + i];
36040Sstevel@tonic-gate 
36050Sstevel@tonic-gate 		for (j = 0; j < EHCI_MAX_UFRAMES; j++) {
36060Sstevel@tonic-gate 			fbp->ehci_micro_frame_bandwidth[j] +=
36070Sstevel@tonic-gate 			    uFrame_bandwidth[j];
36080Sstevel@tonic-gate 			fbp->ehci_allocated_frame_bandwidth +=
36090Sstevel@tonic-gate 			    uFrame_bandwidth[j];
36100Sstevel@tonic-gate 		}
36110Sstevel@tonic-gate 	}
36120Sstevel@tonic-gate }
36130Sstevel@tonic-gate 
36140Sstevel@tonic-gate /*
36150Sstevel@tonic-gate  * Miscellaneous functions
36160Sstevel@tonic-gate  */
36170Sstevel@tonic-gate 
36180Sstevel@tonic-gate /*
36190Sstevel@tonic-gate  * ehci_obtain_state:
36200Sstevel@tonic-gate  *
36210Sstevel@tonic-gate  * NOTE: This function is also called from POLLED MODE.
36220Sstevel@tonic-gate  */
36230Sstevel@tonic-gate ehci_state_t *
ehci_obtain_state(dev_info_t * dip)36240Sstevel@tonic-gate ehci_obtain_state(dev_info_t	*dip)
36250Sstevel@tonic-gate {
36260Sstevel@tonic-gate 	int			instance = ddi_get_instance(dip);
36270Sstevel@tonic-gate 
36280Sstevel@tonic-gate 	ehci_state_t *state = ddi_get_soft_state(ehci_statep, instance);
36290Sstevel@tonic-gate 
36300Sstevel@tonic-gate 	ASSERT(state != NULL);
36310Sstevel@tonic-gate 
36320Sstevel@tonic-gate 	return (state);
36330Sstevel@tonic-gate }
36340Sstevel@tonic-gate 
36350Sstevel@tonic-gate 
36360Sstevel@tonic-gate /*
36370Sstevel@tonic-gate  * ehci_state_is_operational:
36380Sstevel@tonic-gate  *
36390Sstevel@tonic-gate  * Check the Host controller state and return proper values.
36400Sstevel@tonic-gate  */
36410Sstevel@tonic-gate int
ehci_state_is_operational(ehci_state_t * ehcip)36420Sstevel@tonic-gate ehci_state_is_operational(ehci_state_t	*ehcip)
36430Sstevel@tonic-gate {
36440Sstevel@tonic-gate 	int	val;
36450Sstevel@tonic-gate 
36460Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
36470Sstevel@tonic-gate 
36480Sstevel@tonic-gate 	switch (ehcip->ehci_hc_soft_state) {
36490Sstevel@tonic-gate 	case EHCI_CTLR_INIT_STATE:
36500Sstevel@tonic-gate 	case EHCI_CTLR_SUSPEND_STATE:
36510Sstevel@tonic-gate 		val = USB_FAILURE;
36520Sstevel@tonic-gate 		break;
36530Sstevel@tonic-gate 	case EHCI_CTLR_OPERATIONAL_STATE:
36540Sstevel@tonic-gate 		val = USB_SUCCESS;
36550Sstevel@tonic-gate 		break;
36560Sstevel@tonic-gate 	case EHCI_CTLR_ERROR_STATE:
36570Sstevel@tonic-gate 		val = USB_HC_HARDWARE_ERROR;
36580Sstevel@tonic-gate 		break;
36590Sstevel@tonic-gate 	default:
36600Sstevel@tonic-gate 		val = USB_FAILURE;
36610Sstevel@tonic-gate 		break;
36620Sstevel@tonic-gate 	}
36630Sstevel@tonic-gate 
36640Sstevel@tonic-gate 	return (val);
36650Sstevel@tonic-gate }
36660Sstevel@tonic-gate 
36670Sstevel@tonic-gate 
36680Sstevel@tonic-gate /*
36690Sstevel@tonic-gate  * ehci_do_soft_reset
36700Sstevel@tonic-gate  *
36710Sstevel@tonic-gate  * Do soft reset of ehci host controller.
36720Sstevel@tonic-gate  */
36730Sstevel@tonic-gate int
ehci_do_soft_reset(ehci_state_t * ehcip)36740Sstevel@tonic-gate ehci_do_soft_reset(ehci_state_t	*ehcip)
36750Sstevel@tonic-gate {
36760Sstevel@tonic-gate 	usb_frame_number_t	before_frame_number, after_frame_number;
36770Sstevel@tonic-gate 	ehci_regs_t		*ehci_save_regs;
36780Sstevel@tonic-gate 
36790Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
36800Sstevel@tonic-gate 
36810Sstevel@tonic-gate 	/* Increment host controller error count */
36820Sstevel@tonic-gate 	ehcip->ehci_hc_error++;
36830Sstevel@tonic-gate 
36840Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
36850Sstevel@tonic-gate 	    "ehci_do_soft_reset:"
36860Sstevel@tonic-gate 	    "Reset ehci host controller 0x%x", ehcip->ehci_hc_error);
36870Sstevel@tonic-gate 
36880Sstevel@tonic-gate 	/*
36890Sstevel@tonic-gate 	 * Allocate space for saving current Host Controller
36900Sstevel@tonic-gate 	 * registers. Don't do any recovery if allocation
36910Sstevel@tonic-gate 	 * fails.
36920Sstevel@tonic-gate 	 */
36930Sstevel@tonic-gate 	ehci_save_regs = (ehci_regs_t *)
36940Sstevel@tonic-gate 	    kmem_zalloc(sizeof (ehci_regs_t), KM_NOSLEEP);
36950Sstevel@tonic-gate 
36960Sstevel@tonic-gate 	if (ehci_save_regs == NULL) {
36970Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR,  ehcip->ehci_log_hdl,
36980Sstevel@tonic-gate 		    "ehci_do_soft_reset: kmem_zalloc failed");
36990Sstevel@tonic-gate 
37000Sstevel@tonic-gate 		return (USB_FAILURE);
37010Sstevel@tonic-gate 	}
37020Sstevel@tonic-gate 
37030Sstevel@tonic-gate 	/* Save current ehci registers */
37040Sstevel@tonic-gate 	ehci_save_regs->ehci_command = Get_OpReg(ehci_command);
37050Sstevel@tonic-gate 	ehci_save_regs->ehci_interrupt = Get_OpReg(ehci_interrupt);
37060Sstevel@tonic-gate 	ehci_save_regs->ehci_ctrl_segment = Get_OpReg(ehci_ctrl_segment);
37070Sstevel@tonic-gate 	ehci_save_regs->ehci_async_list_addr = Get_OpReg(ehci_async_list_addr);
37080Sstevel@tonic-gate 	ehci_save_regs->ehci_config_flag = Get_OpReg(ehci_config_flag);
37090Sstevel@tonic-gate 	ehci_save_regs->ehci_periodic_list_base =
37100Sstevel@tonic-gate 	    Get_OpReg(ehci_periodic_list_base);
37110Sstevel@tonic-gate 
37121458Syq193411 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
37136898Sfb209375 	    "ehci_do_soft_reset: Save reg = 0x%p", (void *)ehci_save_regs);
37140Sstevel@tonic-gate 
37150Sstevel@tonic-gate 	/* Disable all list processing and interrupts */
37160Sstevel@tonic-gate 	Set_OpReg(ehci_command, Get_OpReg(ehci_command) &
37170Sstevel@tonic-gate 	    ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE));
37180Sstevel@tonic-gate 
37190Sstevel@tonic-gate 	/* Disable all EHCI interrupts */
37200Sstevel@tonic-gate 	Set_OpReg(ehci_interrupt, 0);
37210Sstevel@tonic-gate 
37220Sstevel@tonic-gate 	/* Wait for few milliseconds */
37230Sstevel@tonic-gate 	drv_usecwait(EHCI_SOF_TIMEWAIT);
37240Sstevel@tonic-gate 
37250Sstevel@tonic-gate 	/* Do light soft reset of ehci host controller */
37260Sstevel@tonic-gate 	Set_OpReg(ehci_command,
37270Sstevel@tonic-gate 	    Get_OpReg(ehci_command) | EHCI_CMD_LIGHT_HC_RESET);
37280Sstevel@tonic-gate 
37291458Syq193411 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
37300Sstevel@tonic-gate 	    "ehci_do_soft_reset: Reset in progress");
37310Sstevel@tonic-gate 
37320Sstevel@tonic-gate 	/* Wait for reset to complete */
37330Sstevel@tonic-gate 	drv_usecwait(EHCI_RESET_TIMEWAIT);
37340Sstevel@tonic-gate 
37350Sstevel@tonic-gate 	/*
37360Sstevel@tonic-gate 	 * Restore previous saved EHCI register value
37370Sstevel@tonic-gate 	 * into the current EHCI registers.
37380Sstevel@tonic-gate 	 */
37390Sstevel@tonic-gate 	Set_OpReg(ehci_ctrl_segment, (uint32_t)
37405767Slc152243 	    ehci_save_regs->ehci_ctrl_segment);
37410Sstevel@tonic-gate 
37420Sstevel@tonic-gate 	Set_OpReg(ehci_periodic_list_base, (uint32_t)
37435767Slc152243 	    ehci_save_regs->ehci_periodic_list_base);
37440Sstevel@tonic-gate 
37450Sstevel@tonic-gate 	Set_OpReg(ehci_async_list_addr, (uint32_t)
37465767Slc152243 	    ehci_save_regs->ehci_async_list_addr);
37470Sstevel@tonic-gate 
37482225Sgk73471 	/*
37492225Sgk73471 	 * For some reason this register might get nulled out by
37502225Sgk73471 	 * the Uli M1575 South Bridge. To workaround the hardware
37512225Sgk73471 	 * problem, check the value after write and retry if the
37522225Sgk73471 	 * last write fails.
37532225Sgk73471 	 */
37542225Sgk73471 	if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
37552225Sgk73471 	    (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) &&
37562225Sgk73471 	    (ehci_save_regs->ehci_async_list_addr !=
37572225Sgk73471 	    Get_OpReg(ehci_async_list_addr))) {
37582225Sgk73471 		int retry = 0;
37592225Sgk73471 
37602225Sgk73471 		Set_OpRegRetry(ehci_async_list_addr, (uint32_t)
37615767Slc152243 		    ehci_save_regs->ehci_async_list_addr, retry);
37622225Sgk73471 		if (retry >= EHCI_MAX_RETRY) {
37633435Slg150142 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
37642225Sgk73471 			    ehcip->ehci_log_hdl, "ehci_do_soft_reset:"
37652225Sgk73471 			    " ASYNCLISTADDR write failed.");
37662225Sgk73471 
37672225Sgk73471 			return (USB_FAILURE);
37682225Sgk73471 		}
37692225Sgk73471 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
37702225Sgk73471 		    "ehci_do_soft_reset: ASYNCLISTADDR "
37715767Slc152243 		    "write failed, retry=%d", retry);
37722225Sgk73471 	}
37732225Sgk73471 
37740Sstevel@tonic-gate 	Set_OpReg(ehci_config_flag, (uint32_t)
37755767Slc152243 	    ehci_save_regs->ehci_config_flag);
37760Sstevel@tonic-gate 
37770Sstevel@tonic-gate 	/* Enable both Asynchronous and Periodic Schedule if necessary */
37780Sstevel@tonic-gate 	ehci_toggle_scheduler(ehcip);
37790Sstevel@tonic-gate 
37800Sstevel@tonic-gate 	/*
37810Sstevel@tonic-gate 	 * Set ehci_interrupt to enable all interrupts except Root
37820Sstevel@tonic-gate 	 * Hub Status change and frame list rollover interrupts.
37830Sstevel@tonic-gate 	 */
37840Sstevel@tonic-gate 	Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR |
37850Sstevel@tonic-gate 	    EHCI_INTR_FRAME_LIST_ROLLOVER |
37860Sstevel@tonic-gate 	    EHCI_INTR_USB_ERROR |
37870Sstevel@tonic-gate 	    EHCI_INTR_USB);
37880Sstevel@tonic-gate 
37890Sstevel@tonic-gate 	/*
37900Sstevel@tonic-gate 	 * Deallocate the space that allocated for saving
37910Sstevel@tonic-gate 	 * HC registers.
37920Sstevel@tonic-gate 	 */
37930Sstevel@tonic-gate 	kmem_free((void *) ehci_save_regs, sizeof (ehci_regs_t));
37940Sstevel@tonic-gate 
37950Sstevel@tonic-gate 	/*
37960Sstevel@tonic-gate 	 * Set the desired interrupt threshold, frame list size (if
37970Sstevel@tonic-gate 	 * applicable) and turn EHCI host controller.
37980Sstevel@tonic-gate 	 */
37990Sstevel@tonic-gate 	Set_OpReg(ehci_command, ((Get_OpReg(ehci_command) &
38000Sstevel@tonic-gate 	    ~EHCI_CMD_INTR_THRESHOLD) |
38010Sstevel@tonic-gate 	    (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN)));
38020Sstevel@tonic-gate 
38030Sstevel@tonic-gate 	/* Wait 10ms for EHCI to start sending SOF */
38040Sstevel@tonic-gate 	drv_usecwait(EHCI_RESET_TIMEWAIT);
38050Sstevel@tonic-gate 
38060Sstevel@tonic-gate 	/*
38070Sstevel@tonic-gate 	 * Get the current usb frame number before waiting for
38080Sstevel@tonic-gate 	 * few milliseconds.
38090Sstevel@tonic-gate 	 */
38100Sstevel@tonic-gate 	before_frame_number = ehci_get_current_frame_number(ehcip);
38110Sstevel@tonic-gate 
38120Sstevel@tonic-gate 	/* Wait for few milliseconds */
38130Sstevel@tonic-gate 	drv_usecwait(EHCI_SOF_TIMEWAIT);
38140Sstevel@tonic-gate 
38150Sstevel@tonic-gate 	/*
38160Sstevel@tonic-gate 	 * Get the current usb frame number after waiting for
38170Sstevel@tonic-gate 	 * few milliseconds.
38180Sstevel@tonic-gate 	 */
38190Sstevel@tonic-gate 	after_frame_number = ehci_get_current_frame_number(ehcip);
38200Sstevel@tonic-gate 
38210Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
38220Sstevel@tonic-gate 	    "ehci_do_soft_reset: Before Frame Number 0x%llx "
38230Sstevel@tonic-gate 	    "After Frame Number 0x%llx",
38246898Sfb209375 	    (unsigned long long)before_frame_number,
38256898Sfb209375 	    (unsigned long long)after_frame_number);
38260Sstevel@tonic-gate 
38270Sstevel@tonic-gate 	if ((after_frame_number <= before_frame_number) &&
38280Sstevel@tonic-gate 	    (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) {
38290Sstevel@tonic-gate 
38300Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
38310Sstevel@tonic-gate 		    "ehci_do_soft_reset: Soft reset failed");
38320Sstevel@tonic-gate 
38330Sstevel@tonic-gate 		return (USB_FAILURE);
38340Sstevel@tonic-gate 	}
38350Sstevel@tonic-gate 
38360Sstevel@tonic-gate 	return (USB_SUCCESS);
38370Sstevel@tonic-gate }
38380Sstevel@tonic-gate 
38390Sstevel@tonic-gate 
38400Sstevel@tonic-gate /*
38410Sstevel@tonic-gate  * ehci_get_xfer_attrs:
38420Sstevel@tonic-gate  *
38430Sstevel@tonic-gate  * Get the attributes of a particular xfer.
38440Sstevel@tonic-gate  *
38450Sstevel@tonic-gate  * NOTE: This function is also called from POLLED MODE.
38460Sstevel@tonic-gate  */
38470Sstevel@tonic-gate usb_req_attrs_t
ehci_get_xfer_attrs(ehci_state_t * ehcip,ehci_pipe_private_t * pp,ehci_trans_wrapper_t * tw)38480Sstevel@tonic-gate ehci_get_xfer_attrs(
38490Sstevel@tonic-gate 	ehci_state_t		*ehcip,
38500Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
38510Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw)
38520Sstevel@tonic-gate {
38530Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &pp->pp_pipe_handle->p_ep;
38540Sstevel@tonic-gate 	usb_req_attrs_t		attrs = USB_ATTRS_NONE;
38550Sstevel@tonic-gate 
38560Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
38570Sstevel@tonic-gate 	    "ehci_get_xfer_attrs:");
38580Sstevel@tonic-gate 
38590Sstevel@tonic-gate 	switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
38600Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
38610Sstevel@tonic-gate 		attrs = ((usb_ctrl_req_t *)
38620Sstevel@tonic-gate 		    tw->tw_curr_xfer_reqp)->ctrl_attributes;
38630Sstevel@tonic-gate 		break;
38640Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
38650Sstevel@tonic-gate 		attrs = ((usb_bulk_req_t *)
38660Sstevel@tonic-gate 		    tw->tw_curr_xfer_reqp)->bulk_attributes;
38670Sstevel@tonic-gate 		break;
38680Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
38690Sstevel@tonic-gate 		attrs = ((usb_intr_req_t *)
38700Sstevel@tonic-gate 		    tw->tw_curr_xfer_reqp)->intr_attributes;
38710Sstevel@tonic-gate 		break;
38720Sstevel@tonic-gate 	}
38730Sstevel@tonic-gate 
38740Sstevel@tonic-gate 	return (attrs);
38750Sstevel@tonic-gate }
38760Sstevel@tonic-gate 
38770Sstevel@tonic-gate 
38780Sstevel@tonic-gate /*
38790Sstevel@tonic-gate  * ehci_get_current_frame_number:
38800Sstevel@tonic-gate  *
38810Sstevel@tonic-gate  * Get the current software based usb frame number.
38820Sstevel@tonic-gate  */
38830Sstevel@tonic-gate usb_frame_number_t
ehci_get_current_frame_number(ehci_state_t * ehcip)38840Sstevel@tonic-gate ehci_get_current_frame_number(ehci_state_t *ehcip)
38850Sstevel@tonic-gate {
38860Sstevel@tonic-gate 	usb_frame_number_t	usb_frame_number;
38870Sstevel@tonic-gate 	usb_frame_number_t	ehci_fno, micro_frame_number;
38880Sstevel@tonic-gate 
38890Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
38900Sstevel@tonic-gate 
38910Sstevel@tonic-gate 	ehci_fno = ehcip->ehci_fno;
38920Sstevel@tonic-gate 	micro_frame_number = Get_OpReg(ehci_frame_index) & 0x3FFF;
38930Sstevel@tonic-gate 
38940Sstevel@tonic-gate 	/*
38950Sstevel@tonic-gate 	 * Calculate current software based usb frame number.
38960Sstevel@tonic-gate 	 *
38970Sstevel@tonic-gate 	 * This code accounts for the fact that frame number is
38980Sstevel@tonic-gate 	 * updated by the Host Controller before the ehci driver
38990Sstevel@tonic-gate 	 * gets an FrameListRollover interrupt that will adjust
39000Sstevel@tonic-gate 	 * Frame higher part.
39010Sstevel@tonic-gate 	 *
39020Sstevel@tonic-gate 	 * Refer ehci specification 1.0, section 2.3.2, page 21.
39030Sstevel@tonic-gate 	 */
39040Sstevel@tonic-gate 	micro_frame_number = ((micro_frame_number & 0x1FFF) |
39050Sstevel@tonic-gate 	    ehci_fno) + (((micro_frame_number & 0x3FFF) ^
39060Sstevel@tonic-gate 	    ehci_fno) & 0x2000);
39070Sstevel@tonic-gate 
39080Sstevel@tonic-gate 	/*
39090Sstevel@tonic-gate 	 * Micro Frame number is equivalent to 125 usec. Eight
39100Sstevel@tonic-gate 	 * Micro Frame numbers are equivalent to one millsecond
39110Sstevel@tonic-gate 	 * or one usb frame number.
39120Sstevel@tonic-gate 	 */
39130Sstevel@tonic-gate 	usb_frame_number = micro_frame_number >>
39140Sstevel@tonic-gate 	    EHCI_uFRAMES_PER_USB_FRAME_SHIFT;
39150Sstevel@tonic-gate 
39160Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
39170Sstevel@tonic-gate 	    "ehci_get_current_frame_number: "
39180Sstevel@tonic-gate 	    "Current usb uframe number = 0x%llx "
39190Sstevel@tonic-gate 	    "Current usb frame number  = 0x%llx",
39206898Sfb209375 	    (unsigned long long)micro_frame_number,
39216898Sfb209375 	    (unsigned long long)usb_frame_number);
39220Sstevel@tonic-gate 
39230Sstevel@tonic-gate 	return (usb_frame_number);
39240Sstevel@tonic-gate }
39250Sstevel@tonic-gate 
39260Sstevel@tonic-gate 
39270Sstevel@tonic-gate /*
39280Sstevel@tonic-gate  * ehci_cpr_cleanup:
39290Sstevel@tonic-gate  *
39300Sstevel@tonic-gate  * Cleanup ehci state and other ehci specific informations across
39310Sstevel@tonic-gate  * Check Point Resume (CPR).
39320Sstevel@tonic-gate  */
39330Sstevel@tonic-gate static	void
ehci_cpr_cleanup(ehci_state_t * ehcip)39340Sstevel@tonic-gate ehci_cpr_cleanup(ehci_state_t *ehcip)
39350Sstevel@tonic-gate {
39360Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
39370Sstevel@tonic-gate 
39380Sstevel@tonic-gate 	/* Reset software part of usb frame number */
39390Sstevel@tonic-gate 	ehcip->ehci_fno = 0;
39400Sstevel@tonic-gate }
39410Sstevel@tonic-gate 
39420Sstevel@tonic-gate 
39430Sstevel@tonic-gate /*
39440Sstevel@tonic-gate  * ehci_wait_for_sof:
39450Sstevel@tonic-gate  *
39460Sstevel@tonic-gate  * Wait for couple of SOF interrupts
39470Sstevel@tonic-gate  */
39480Sstevel@tonic-gate int
ehci_wait_for_sof(ehci_state_t * ehcip)39490Sstevel@tonic-gate ehci_wait_for_sof(ehci_state_t	*ehcip)
39500Sstevel@tonic-gate {
39510Sstevel@tonic-gate 	usb_frame_number_t	before_frame_number, after_frame_number;
39520Sstevel@tonic-gate 	int			error = USB_SUCCESS;
39530Sstevel@tonic-gate 
39540Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS,
39550Sstevel@tonic-gate 	    ehcip->ehci_log_hdl, "ehci_wait_for_sof");
39560Sstevel@tonic-gate 
39570Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
39580Sstevel@tonic-gate 
39590Sstevel@tonic-gate 	error = ehci_state_is_operational(ehcip);
39600Sstevel@tonic-gate 
39610Sstevel@tonic-gate 	if (error != USB_SUCCESS) {
39620Sstevel@tonic-gate 
39630Sstevel@tonic-gate 		return (error);
39640Sstevel@tonic-gate 	}
39650Sstevel@tonic-gate 
39660Sstevel@tonic-gate 	/* Get the current usb frame number before waiting for two SOFs */
39670Sstevel@tonic-gate 	before_frame_number = ehci_get_current_frame_number(ehcip);
39680Sstevel@tonic-gate 
39690Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
39700Sstevel@tonic-gate 
39710Sstevel@tonic-gate 	/* Wait for few milliseconds */
39720Sstevel@tonic-gate 	delay(drv_usectohz(EHCI_SOF_TIMEWAIT));
39730Sstevel@tonic-gate 
39740Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
39750Sstevel@tonic-gate 
39760Sstevel@tonic-gate 	/* Get the current usb frame number after woken up */
39770Sstevel@tonic-gate 	after_frame_number = ehci_get_current_frame_number(ehcip);
39780Sstevel@tonic-gate 
39790Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
39800Sstevel@tonic-gate 	    "ehci_wait_for_sof: framenumber: before 0x%llx "
39816898Sfb209375 	    "after 0x%llx",
39826898Sfb209375 	    (unsigned long long)before_frame_number,
39836898Sfb209375 	    (unsigned long long)after_frame_number);
39840Sstevel@tonic-gate 
39850Sstevel@tonic-gate 	/* Return failure, if usb frame number has not been changed */
39860Sstevel@tonic-gate 	if (after_frame_number <= before_frame_number) {
39870Sstevel@tonic-gate 
39880Sstevel@tonic-gate 		if ((ehci_do_soft_reset(ehcip)) != USB_SUCCESS) {
39890Sstevel@tonic-gate 
39900Sstevel@tonic-gate 			USB_DPRINTF_L0(PRINT_MASK_LISTS,
39910Sstevel@tonic-gate 			    ehcip->ehci_log_hdl, "No SOF interrupts");
39920Sstevel@tonic-gate 
39930Sstevel@tonic-gate 			/* Set host controller soft state to error */
39940Sstevel@tonic-gate 			ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE;
39950Sstevel@tonic-gate 
39960Sstevel@tonic-gate 			return (USB_FAILURE);
39970Sstevel@tonic-gate 		}
39980Sstevel@tonic-gate 
39990Sstevel@tonic-gate 	}
40000Sstevel@tonic-gate 
40010Sstevel@tonic-gate 	return (USB_SUCCESS);
40020Sstevel@tonic-gate }
40030Sstevel@tonic-gate 
4004*12886SRaymond.Chen@Sun.COM /*
4005*12886SRaymond.Chen@Sun.COM  * Toggle the async/periodic schedule based on opened pipe count.
4006*12886SRaymond.Chen@Sun.COM  * During pipe cleanup(in pipe reset case), the pipe's QH is temporarily
4007*12886SRaymond.Chen@Sun.COM  * disabled. But the TW on the pipe is not freed. In this case, we need
4008*12886SRaymond.Chen@Sun.COM  * to disable async/periodic schedule for some non-compatible hardware.
4009*12886SRaymond.Chen@Sun.COM  * Otherwise, the hardware will overwrite software's configuration of
4010*12886SRaymond.Chen@Sun.COM  * the QH.
4011*12886SRaymond.Chen@Sun.COM  */
4012*12886SRaymond.Chen@Sun.COM void
ehci_toggle_scheduler_on_pipe(ehci_state_t * ehcip)4013*12886SRaymond.Chen@Sun.COM ehci_toggle_scheduler_on_pipe(ehci_state_t *ehcip)
4014*12886SRaymond.Chen@Sun.COM {
4015*12886SRaymond.Chen@Sun.COM 	uint_t  temp_reg, cmd_reg;
4016*12886SRaymond.Chen@Sun.COM 
4017*12886SRaymond.Chen@Sun.COM 	cmd_reg = Get_OpReg(ehci_command);
4018*12886SRaymond.Chen@Sun.COM 	temp_reg = cmd_reg;
4019*12886SRaymond.Chen@Sun.COM 
4020*12886SRaymond.Chen@Sun.COM 	/*
4021*12886SRaymond.Chen@Sun.COM 	 * Enable/Disable asynchronous scheduler, and
4022*12886SRaymond.Chen@Sun.COM 	 * turn on/off async list door bell
4023*12886SRaymond.Chen@Sun.COM 	 */
4024*12886SRaymond.Chen@Sun.COM 	if (ehcip->ehci_open_async_count) {
4025*12886SRaymond.Chen@Sun.COM 		if ((ehcip->ehci_async_req_count > 0) &&
4026*12886SRaymond.Chen@Sun.COM 		    ((cmd_reg & EHCI_CMD_ASYNC_SCHED_ENABLE) == 0)) {
4027*12886SRaymond.Chen@Sun.COM 			/*
4028*12886SRaymond.Chen@Sun.COM 			 * For some reason this address might get nulled out by
4029*12886SRaymond.Chen@Sun.COM 			 * the ehci chip. Set it here just in case it is null.
4030*12886SRaymond.Chen@Sun.COM 			 */
4031*12886SRaymond.Chen@Sun.COM 			Set_OpReg(ehci_async_list_addr,
4032*12886SRaymond.Chen@Sun.COM 			    ehci_qh_cpu_to_iommu(ehcip,
4033*12886SRaymond.Chen@Sun.COM 			    ehcip->ehci_head_of_async_sched_list));
4034*12886SRaymond.Chen@Sun.COM 
4035*12886SRaymond.Chen@Sun.COM 			/*
4036*12886SRaymond.Chen@Sun.COM 			 * For some reason this register might get nulled out by
4037*12886SRaymond.Chen@Sun.COM 			 * the Uli M1575 Southbridge. To workaround the HW
4038*12886SRaymond.Chen@Sun.COM 			 * problem, check the value after write and retry if the
4039*12886SRaymond.Chen@Sun.COM 			 * last write fails.
4040*12886SRaymond.Chen@Sun.COM 			 *
4041*12886SRaymond.Chen@Sun.COM 			 * If the ASYNCLISTADDR remains "stuck" after
4042*12886SRaymond.Chen@Sun.COM 			 * EHCI_MAX_RETRY retries, then the M1575 is broken
4043*12886SRaymond.Chen@Sun.COM 			 * and is stuck in an inconsistent state and is about
4044*12886SRaymond.Chen@Sun.COM 			 * to crash the machine with a trn_oor panic when it
4045*12886SRaymond.Chen@Sun.COM 			 * does a DMA read from 0x0.  It is better to panic
4046*12886SRaymond.Chen@Sun.COM 			 * now rather than wait for the trn_oor crash; this
4047*12886SRaymond.Chen@Sun.COM 			 * way Customer Service will have a clean signature
4048*12886SRaymond.Chen@Sun.COM 			 * that indicts the M1575 chip rather than a
4049*12886SRaymond.Chen@Sun.COM 			 * mysterious and hard-to-diagnose trn_oor panic.
4050*12886SRaymond.Chen@Sun.COM 			 */
4051*12886SRaymond.Chen@Sun.COM 			if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
4052*12886SRaymond.Chen@Sun.COM 			    (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) &&
4053*12886SRaymond.Chen@Sun.COM 			    (ehci_qh_cpu_to_iommu(ehcip,
4054*12886SRaymond.Chen@Sun.COM 			    ehcip->ehci_head_of_async_sched_list) !=
4055*12886SRaymond.Chen@Sun.COM 			    Get_OpReg(ehci_async_list_addr))) {
4056*12886SRaymond.Chen@Sun.COM 				int retry = 0;
4057*12886SRaymond.Chen@Sun.COM 
4058*12886SRaymond.Chen@Sun.COM 				Set_OpRegRetry(ehci_async_list_addr,
4059*12886SRaymond.Chen@Sun.COM 				    ehci_qh_cpu_to_iommu(ehcip,
4060*12886SRaymond.Chen@Sun.COM 				    ehcip->ehci_head_of_async_sched_list),
4061*12886SRaymond.Chen@Sun.COM 				    retry);
4062*12886SRaymond.Chen@Sun.COM 				if (retry >= EHCI_MAX_RETRY)
4063*12886SRaymond.Chen@Sun.COM 					cmn_err(CE_PANIC,
4064*12886SRaymond.Chen@Sun.COM 					    "ehci_toggle_scheduler_on_pipe: "
4065*12886SRaymond.Chen@Sun.COM 					    "ASYNCLISTADDR write failed.");
4066*12886SRaymond.Chen@Sun.COM 
4067*12886SRaymond.Chen@Sun.COM 				USB_DPRINTF_L2(PRINT_MASK_ATTA,
4068*12886SRaymond.Chen@Sun.COM 				    ehcip->ehci_log_hdl,
4069*12886SRaymond.Chen@Sun.COM 				    "ehci_toggle_scheduler_on_pipe:"
4070*12886SRaymond.Chen@Sun.COM 				    " ASYNCLISTADDR write failed, retry=%d",
4071*12886SRaymond.Chen@Sun.COM 				    retry);
4072*12886SRaymond.Chen@Sun.COM 			}
4073*12886SRaymond.Chen@Sun.COM 
4074*12886SRaymond.Chen@Sun.COM 			cmd_reg |= EHCI_CMD_ASYNC_SCHED_ENABLE;
4075*12886SRaymond.Chen@Sun.COM 		}
4076*12886SRaymond.Chen@Sun.COM 	} else {
4077*12886SRaymond.Chen@Sun.COM 		cmd_reg &= ~EHCI_CMD_ASYNC_SCHED_ENABLE;
4078*12886SRaymond.Chen@Sun.COM 	}
4079*12886SRaymond.Chen@Sun.COM 
4080*12886SRaymond.Chen@Sun.COM 	if (ehcip->ehci_open_periodic_count) {
4081*12886SRaymond.Chen@Sun.COM 		if ((ehcip->ehci_periodic_req_count > 0) &&
4082*12886SRaymond.Chen@Sun.COM 		    ((cmd_reg & EHCI_CMD_PERIODIC_SCHED_ENABLE) == 0)) {
4083*12886SRaymond.Chen@Sun.COM 			/*
4084*12886SRaymond.Chen@Sun.COM 			 * For some reason this address get's nulled out by
4085*12886SRaymond.Chen@Sun.COM 			 * the ehci chip. Set it here just in case it is null.
4086*12886SRaymond.Chen@Sun.COM 			 */
4087*12886SRaymond.Chen@Sun.COM 			Set_OpReg(ehci_periodic_list_base,
4088*12886SRaymond.Chen@Sun.COM 			    (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address &
4089*12886SRaymond.Chen@Sun.COM 			    0xFFFFF000));
4090*12886SRaymond.Chen@Sun.COM 			cmd_reg |= EHCI_CMD_PERIODIC_SCHED_ENABLE;
4091*12886SRaymond.Chen@Sun.COM 		}
4092*12886SRaymond.Chen@Sun.COM 	} else {
4093*12886SRaymond.Chen@Sun.COM 		cmd_reg &= ~EHCI_CMD_PERIODIC_SCHED_ENABLE;
4094*12886SRaymond.Chen@Sun.COM 	}
4095*12886SRaymond.Chen@Sun.COM 
4096*12886SRaymond.Chen@Sun.COM 	/* Just an optimization */
4097*12886SRaymond.Chen@Sun.COM 	if (temp_reg != cmd_reg) {
4098*12886SRaymond.Chen@Sun.COM 		Set_OpReg(ehci_command, cmd_reg);
4099*12886SRaymond.Chen@Sun.COM 	}
4100*12886SRaymond.Chen@Sun.COM }
4101*12886SRaymond.Chen@Sun.COM 
41020Sstevel@tonic-gate 
41030Sstevel@tonic-gate /*
41040Sstevel@tonic-gate  * ehci_toggle_scheduler:
41050Sstevel@tonic-gate  *
41060Sstevel@tonic-gate  * Turn scheduler based on pipe open count.
41070Sstevel@tonic-gate  */
41080Sstevel@tonic-gate void
ehci_toggle_scheduler(ehci_state_t * ehcip)410912733SRaymond.Chen@Sun.COM ehci_toggle_scheduler(ehci_state_t *ehcip)
411012733SRaymond.Chen@Sun.COM {
41110Sstevel@tonic-gate 	uint_t	temp_reg, cmd_reg;
41120Sstevel@tonic-gate 
411312733SRaymond.Chen@Sun.COM 	/*
411412733SRaymond.Chen@Sun.COM 	 * For performance optimization, we need to change the bits
411512733SRaymond.Chen@Sun.COM 	 * if (async == 1||async == 0) OR (periodic == 1||periodic == 0)
411612733SRaymond.Chen@Sun.COM 	 *
411712733SRaymond.Chen@Sun.COM 	 * Related bits already enabled if
411812733SRaymond.Chen@Sun.COM 	 *	async and periodic req counts are > 1
411912733SRaymond.Chen@Sun.COM 	 *	OR async req count > 1 & no periodic pipe
412012733SRaymond.Chen@Sun.COM 	 *	OR periodic req count > 1 & no async pipe
412112733SRaymond.Chen@Sun.COM 	 */
412212733SRaymond.Chen@Sun.COM 	if (((ehcip->ehci_async_req_count > 1) &&
412312733SRaymond.Chen@Sun.COM 	    (ehcip->ehci_periodic_req_count > 1)) ||
412412733SRaymond.Chen@Sun.COM 	    ((ehcip->ehci_async_req_count > 1) &&
412512733SRaymond.Chen@Sun.COM 	    (ehcip->ehci_open_periodic_count == 0)) ||
412612733SRaymond.Chen@Sun.COM 	    ((ehcip->ehci_periodic_req_count > 1) &&
412712733SRaymond.Chen@Sun.COM 	    (ehcip->ehci_open_async_count == 0))) {
412812733SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(PRINT_MASK_ATTA,
412912733SRaymond.Chen@Sun.COM 		    ehcip->ehci_log_hdl, "ehci_toggle_scheduler:"
413012733SRaymond.Chen@Sun.COM 		    "async/periodic bits no need to change");
413112733SRaymond.Chen@Sun.COM 
413212733SRaymond.Chen@Sun.COM 		return;
413312733SRaymond.Chen@Sun.COM 	}
413412733SRaymond.Chen@Sun.COM 
41350Sstevel@tonic-gate 	cmd_reg = Get_OpReg(ehci_command);
41360Sstevel@tonic-gate 	temp_reg = cmd_reg;
41370Sstevel@tonic-gate 
41380Sstevel@tonic-gate 	/*
41390Sstevel@tonic-gate 	 * Enable/Disable asynchronous scheduler, and
41400Sstevel@tonic-gate 	 * turn on/off async list door bell
41410Sstevel@tonic-gate 	 */
414212733SRaymond.Chen@Sun.COM 	if (ehcip->ehci_async_req_count > 1) {
414312733SRaymond.Chen@Sun.COM 		/* we already enable the async bit */
414412733SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(PRINT_MASK_ATTA,
414512733SRaymond.Chen@Sun.COM 		    ehcip->ehci_log_hdl, "ehci_toggle_scheduler:"
414612733SRaymond.Chen@Sun.COM 		    "async bit already enabled: cmd_reg=0x%x", cmd_reg);
414712733SRaymond.Chen@Sun.COM 	} else if (ehcip->ehci_async_req_count == 1) {
41480Sstevel@tonic-gate 		if (!(cmd_reg & EHCI_CMD_ASYNC_SCHED_ENABLE)) {
41490Sstevel@tonic-gate 			/*
41500Sstevel@tonic-gate 			 * For some reason this address might get nulled out by
41510Sstevel@tonic-gate 			 * the ehci chip. Set it here just in case it is null.
415212733SRaymond.Chen@Sun.COM 			 * If it's not null, we should not reset the
415312733SRaymond.Chen@Sun.COM 			 * ASYNCLISTADDR, because it's updated by hardware to
415412733SRaymond.Chen@Sun.COM 			 * point to the next queue head to be executed.
41550Sstevel@tonic-gate 			 */
415612733SRaymond.Chen@Sun.COM 			if (!Get_OpReg(ehci_async_list_addr)) {
415712733SRaymond.Chen@Sun.COM 				Set_OpReg(ehci_async_list_addr,
415812733SRaymond.Chen@Sun.COM 				    ehci_qh_cpu_to_iommu(ehcip,
415912733SRaymond.Chen@Sun.COM 				    ehcip->ehci_head_of_async_sched_list));
416012733SRaymond.Chen@Sun.COM 			}
41612225Sgk73471 
41622225Sgk73471 			/*
41632225Sgk73471 			 * For some reason this register might get nulled out by
41642225Sgk73471 			 * the Uli M1575 Southbridge. To workaround the HW
41652225Sgk73471 			 * problem, check the value after write and retry if the
41662225Sgk73471 			 * last write fails.
41672225Sgk73471 			 *
41682225Sgk73471 			 * If the ASYNCLISTADDR remains "stuck" after
41692225Sgk73471 			 * EHCI_MAX_RETRY retries, then the M1575 is broken
41702225Sgk73471 			 * and is stuck in an inconsistent state and is about
41712225Sgk73471 			 * to crash the machine with a trn_oor panic when it
41722225Sgk73471 			 * does a DMA read from 0x0.  It is better to panic
41732225Sgk73471 			 * now rather than wait for the trn_oor crash; this
41742225Sgk73471 			 * way Customer Service will have a clean signature
41752225Sgk73471 			 * that indicts the M1575 chip rather than a
41762225Sgk73471 			 * mysterious and hard-to-diagnose trn_oor panic.
41772225Sgk73471 			 */
41782225Sgk73471 			if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
41792225Sgk73471 			    (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) &&
41802225Sgk73471 			    (ehci_qh_cpu_to_iommu(ehcip,
41812225Sgk73471 			    ehcip->ehci_head_of_async_sched_list) !=
41822225Sgk73471 			    Get_OpReg(ehci_async_list_addr))) {
41832225Sgk73471 				int retry = 0;
41842225Sgk73471 
41852225Sgk73471 				Set_OpRegRetry(ehci_async_list_addr,
41862225Sgk73471 				    ehci_qh_cpu_to_iommu(ehcip,
41872225Sgk73471 				    ehcip->ehci_head_of_async_sched_list),
41882225Sgk73471 				    retry);
41892225Sgk73471 				if (retry >= EHCI_MAX_RETRY)
41902225Sgk73471 					cmn_err(CE_PANIC,
41912225Sgk73471 					    "ehci_toggle_scheduler: "
41922225Sgk73471 					    "ASYNCLISTADDR write failed.");
41932225Sgk73471 
419412733SRaymond.Chen@Sun.COM 				USB_DPRINTF_L3(PRINT_MASK_ATTA,
41952225Sgk73471 				    ehcip->ehci_log_hdl,
41962225Sgk73471 				    "ehci_toggle_scheduler: ASYNCLISTADDR "
419712733SRaymond.Chen@Sun.COM 				    "write failed, retry=%d", retry);
41982225Sgk73471 			}
41990Sstevel@tonic-gate 		}
42000Sstevel@tonic-gate 		cmd_reg |= EHCI_CMD_ASYNC_SCHED_ENABLE;
42010Sstevel@tonic-gate 	} else {
42020Sstevel@tonic-gate 		cmd_reg &= ~EHCI_CMD_ASYNC_SCHED_ENABLE;
42030Sstevel@tonic-gate 	}
42040Sstevel@tonic-gate 
420512733SRaymond.Chen@Sun.COM 	if (ehcip->ehci_periodic_req_count > 1) {
420612733SRaymond.Chen@Sun.COM 		/* we already enable the periodic bit. */
420712733SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(PRINT_MASK_ATTA,
420812733SRaymond.Chen@Sun.COM 		    ehcip->ehci_log_hdl, "ehci_toggle_scheduler:"
420912733SRaymond.Chen@Sun.COM 		    "periodic bit already enabled: cmd_reg=0x%x", cmd_reg);
421012733SRaymond.Chen@Sun.COM 	} else if (ehcip->ehci_periodic_req_count == 1) {
42110Sstevel@tonic-gate 		if (!(cmd_reg & EHCI_CMD_PERIODIC_SCHED_ENABLE)) {
42120Sstevel@tonic-gate 			/*
42130Sstevel@tonic-gate 			 * For some reason this address get's nulled out by
42140Sstevel@tonic-gate 			 * the ehci chip. Set it here just in case it is null.
42150Sstevel@tonic-gate 			 */
42160Sstevel@tonic-gate 			Set_OpReg(ehci_periodic_list_base,
42170Sstevel@tonic-gate 			    (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address &
421812733SRaymond.Chen@Sun.COM 			    0xFFFFF000));
42190Sstevel@tonic-gate 		}
42200Sstevel@tonic-gate 		cmd_reg |= EHCI_CMD_PERIODIC_SCHED_ENABLE;
42210Sstevel@tonic-gate 	} else {
42220Sstevel@tonic-gate 		cmd_reg &= ~EHCI_CMD_PERIODIC_SCHED_ENABLE;
42230Sstevel@tonic-gate 	}
42240Sstevel@tonic-gate 
42250Sstevel@tonic-gate 	/* Just an optimization */
42260Sstevel@tonic-gate 	if (temp_reg != cmd_reg) {
42270Sstevel@tonic-gate 		Set_OpReg(ehci_command, cmd_reg);
422812733SRaymond.Chen@Sun.COM 
422912733SRaymond.Chen@Sun.COM 		/* To make sure the command register is updated correctly */
423012733SRaymond.Chen@Sun.COM 		if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
423112733SRaymond.Chen@Sun.COM 		    (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) {
423212733SRaymond.Chen@Sun.COM 			int retry = 0;
423312733SRaymond.Chen@Sun.COM 
423412733SRaymond.Chen@Sun.COM 			Set_OpRegRetry(ehci_command, cmd_reg, retry);
423512733SRaymond.Chen@Sun.COM 			USB_DPRINTF_L3(PRINT_MASK_ATTA,
423612733SRaymond.Chen@Sun.COM 			    ehcip->ehci_log_hdl,
423712733SRaymond.Chen@Sun.COM 			    "ehci_toggle_scheduler: CMD write failed, retry=%d",
423812733SRaymond.Chen@Sun.COM 			    retry);
423912733SRaymond.Chen@Sun.COM 		}
424012733SRaymond.Chen@Sun.COM 
42410Sstevel@tonic-gate 	}
42420Sstevel@tonic-gate }
42430Sstevel@tonic-gate 
42440Sstevel@tonic-gate /*
42450Sstevel@tonic-gate  * ehci print functions
42460Sstevel@tonic-gate  */
42470Sstevel@tonic-gate 
42480Sstevel@tonic-gate /*
42490Sstevel@tonic-gate  * ehci_print_caps:
42500Sstevel@tonic-gate  */
42510Sstevel@tonic-gate void
ehci_print_caps(ehci_state_t * ehcip)42520Sstevel@tonic-gate ehci_print_caps(ehci_state_t	*ehcip)
42530Sstevel@tonic-gate {
42540Sstevel@tonic-gate 	uint_t			i;
42550Sstevel@tonic-gate 
42560Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42570Sstevel@tonic-gate 	    "\n\tUSB 2.0 Host Controller Characteristics\n");
42580Sstevel@tonic-gate 
42590Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42600Sstevel@tonic-gate 	    "Caps Length: 0x%x Version: 0x%x\n",
42610Sstevel@tonic-gate 	    Get_8Cap(ehci_caps_length), Get_16Cap(ehci_version));
42620Sstevel@tonic-gate 
42630Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42640Sstevel@tonic-gate 	    "Structural Parameters\n");
42650Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42660Sstevel@tonic-gate 	    "Port indicators: %s", (Get_Cap(ehci_hcs_params) &
42670Sstevel@tonic-gate 	    EHCI_HCS_PORT_INDICATOR) ? "Yes" : "No");
42680Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42690Sstevel@tonic-gate 	    "No of Classic host controllers: 0x%x",
42700Sstevel@tonic-gate 	    (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_COMP_CTRLS)
42710Sstevel@tonic-gate 	    >> EHCI_HCS_NUM_COMP_CTRL_SHIFT);
42720Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42730Sstevel@tonic-gate 	    "No of ports per Classic host controller: 0x%x",
42740Sstevel@tonic-gate 	    (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS_CC)
42750Sstevel@tonic-gate 	    >> EHCI_HCS_NUM_PORTS_CC_SHIFT);
42760Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42770Sstevel@tonic-gate 	    "Port routing rules: %s", (Get_Cap(ehci_hcs_params) &
42780Sstevel@tonic-gate 	    EHCI_HCS_PORT_ROUTING_RULES) ? "Yes" : "No");
42790Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42800Sstevel@tonic-gate 	    "Port power control: %s", (Get_Cap(ehci_hcs_params) &
42810Sstevel@tonic-gate 	    EHCI_HCS_PORT_POWER_CONTROL) ? "Yes" : "No");
42820Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42830Sstevel@tonic-gate 	    "No of root hub ports: 0x%x\n",
42840Sstevel@tonic-gate 	    Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS);
42850Sstevel@tonic-gate 
42860Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42870Sstevel@tonic-gate 	    "Capability Parameters\n");
42880Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42890Sstevel@tonic-gate 	    "EHCI extended capability: %s", (Get_Cap(ehci_hcc_params) &
42900Sstevel@tonic-gate 	    EHCI_HCC_EECP) ? "Yes" : "No");
42910Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42920Sstevel@tonic-gate 	    "Isoch schedule threshold: 0x%x",
42930Sstevel@tonic-gate 	    Get_Cap(ehci_hcc_params) & EHCI_HCC_ISOCH_SCHED_THRESHOLD);
42940Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42950Sstevel@tonic-gate 	    "Async schedule park capability: %s", (Get_Cap(ehci_hcc_params) &
42960Sstevel@tonic-gate 	    EHCI_HCC_ASYNC_SCHED_PARK_CAP) ? "Yes" : "No");
42970Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42980Sstevel@tonic-gate 	    "Programmable frame list flag: %s", (Get_Cap(ehci_hcc_params) &
42990Sstevel@tonic-gate 	    EHCI_HCC_PROG_FRAME_LIST_FLAG) ? "256/512/1024" : "1024");
43000Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43010Sstevel@tonic-gate 	    "64bit addressing capability: %s\n", (Get_Cap(ehci_hcc_params) &
43020Sstevel@tonic-gate 	    EHCI_HCC_64BIT_ADDR_CAP) ? "Yes" : "No");
43030Sstevel@tonic-gate 
43040Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43050Sstevel@tonic-gate 	    "Classic Port Route Description");
43060Sstevel@tonic-gate 
43070Sstevel@tonic-gate 	for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) {
43080Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43090Sstevel@tonic-gate 		    "\tPort Route 0x%x: 0x%x", i, Get_8Cap(ehci_port_route[i]));
43100Sstevel@tonic-gate 	}
43110Sstevel@tonic-gate }
43120Sstevel@tonic-gate 
43130Sstevel@tonic-gate 
43140Sstevel@tonic-gate /*
43150Sstevel@tonic-gate  * ehci_print_regs:
43160Sstevel@tonic-gate  */
43170Sstevel@tonic-gate void
ehci_print_regs(ehci_state_t * ehcip)43180Sstevel@tonic-gate ehci_print_regs(ehci_state_t	*ehcip)
43190Sstevel@tonic-gate {
43200Sstevel@tonic-gate 	uint_t			i;
43210Sstevel@tonic-gate 
43220Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43230Sstevel@tonic-gate 	    "\n\tEHCI%d Operational Registers\n",
43240Sstevel@tonic-gate 	    ddi_get_instance(ehcip->ehci_dip));
43250Sstevel@tonic-gate 
43260Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43270Sstevel@tonic-gate 	    "Command: 0x%x Status: 0x%x",
43280Sstevel@tonic-gate 	    Get_OpReg(ehci_command), Get_OpReg(ehci_status));
43290Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43300Sstevel@tonic-gate 	    "Interrupt: 0x%x Frame Index: 0x%x",
43310Sstevel@tonic-gate 	    Get_OpReg(ehci_interrupt), Get_OpReg(ehci_frame_index));
43320Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43330Sstevel@tonic-gate 	    "Control Segment: 0x%x Periodic List Base: 0x%x",
43340Sstevel@tonic-gate 	    Get_OpReg(ehci_ctrl_segment), Get_OpReg(ehci_periodic_list_base));
43350Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43360Sstevel@tonic-gate 	    "Async List Addr: 0x%x Config Flag: 0x%x",
43370Sstevel@tonic-gate 	    Get_OpReg(ehci_async_list_addr), Get_OpReg(ehci_config_flag));
43380Sstevel@tonic-gate 
43390Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43400Sstevel@tonic-gate 	    "Root Hub Port Status");
43410Sstevel@tonic-gate 
43420Sstevel@tonic-gate 	for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) {
43430Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43440Sstevel@tonic-gate 		    "\tPort Status 0x%x: 0x%x ", i,
43450Sstevel@tonic-gate 		    Get_OpReg(ehci_rh_port_status[i]));
43460Sstevel@tonic-gate 	}
43470Sstevel@tonic-gate }
43480Sstevel@tonic-gate 
43490Sstevel@tonic-gate 
43500Sstevel@tonic-gate /*
43510Sstevel@tonic-gate  * ehci_print_qh:
43520Sstevel@tonic-gate  */
43530Sstevel@tonic-gate void
ehci_print_qh(ehci_state_t * ehcip,ehci_qh_t * qh)43540Sstevel@tonic-gate ehci_print_qh(
43550Sstevel@tonic-gate 	ehci_state_t	*ehcip,
43560Sstevel@tonic-gate 	ehci_qh_t	*qh)
43570Sstevel@tonic-gate {
43580Sstevel@tonic-gate 	uint_t		i;
43590Sstevel@tonic-gate 
43600Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43610Sstevel@tonic-gate 	    "ehci_print_qh: qh = 0x%p", (void *)qh);
43620Sstevel@tonic-gate 
43630Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43640Sstevel@tonic-gate 	    "\tqh_link_ptr: 0x%x ", Get_QH(qh->qh_link_ptr));
43650Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43660Sstevel@tonic-gate 	    "\tqh_ctrl: 0x%x ", Get_QH(qh->qh_ctrl));
43670Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43680Sstevel@tonic-gate 	    "\tqh_split_ctrl: 0x%x ", Get_QH(qh->qh_split_ctrl));
43690Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43700Sstevel@tonic-gate 	    "\tqh_curr_qtd: 0x%x ", Get_QH(qh->qh_curr_qtd));
43710Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43720Sstevel@tonic-gate 	    "\tqh_next_qtd: 0x%x ", Get_QH(qh->qh_next_qtd));
43730Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43740Sstevel@tonic-gate 	    "\tqh_alt_next_qtd: 0x%x ", Get_QH(qh->qh_alt_next_qtd));
43750Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43760Sstevel@tonic-gate 	    "\tqh_status: 0x%x ", Get_QH(qh->qh_status));
43770Sstevel@tonic-gate 
43780Sstevel@tonic-gate 	for (i = 0; i < 5; i++) {
43790Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43800Sstevel@tonic-gate 		    "\tqh_buf[%d]: 0x%x ", i, Get_QH(qh->qh_buf[i]));
43810Sstevel@tonic-gate 	}
43820Sstevel@tonic-gate 
43830Sstevel@tonic-gate 	for (i = 0; i < 5; i++) {
43840Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43850Sstevel@tonic-gate 		    "\tqh_buf_high[%d]: 0x%x ",
43860Sstevel@tonic-gate 		    i, Get_QH(qh->qh_buf_high[i]));
43870Sstevel@tonic-gate 	}
43880Sstevel@tonic-gate 
43890Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43900Sstevel@tonic-gate 	    "\tqh_dummy_qtd: 0x%x ", Get_QH(qh->qh_dummy_qtd));
43910Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43920Sstevel@tonic-gate 	    "\tqh_prev: 0x%x ", Get_QH(qh->qh_prev));
43930Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43940Sstevel@tonic-gate 	    "\tqh_state: 0x%x ", Get_QH(qh->qh_state));
43950Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43960Sstevel@tonic-gate 	    "\tqh_reclaim_next: 0x%x ", Get_QH(qh->qh_reclaim_next));
43970Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43980Sstevel@tonic-gate 	    "\tqh_reclaim_frame: 0x%x ", Get_QH(qh->qh_reclaim_frame));
43990Sstevel@tonic-gate }
44000Sstevel@tonic-gate 
44010Sstevel@tonic-gate 
44020Sstevel@tonic-gate /*
44030Sstevel@tonic-gate  * ehci_print_qtd:
44040Sstevel@tonic-gate  */
44050Sstevel@tonic-gate void
ehci_print_qtd(ehci_state_t * ehcip,ehci_qtd_t * qtd)44060Sstevel@tonic-gate ehci_print_qtd(
44070Sstevel@tonic-gate 	ehci_state_t	*ehcip,
44080Sstevel@tonic-gate 	ehci_qtd_t	*qtd)
44090Sstevel@tonic-gate {
44100Sstevel@tonic-gate 	uint_t		i;
44110Sstevel@tonic-gate 
44120Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44130Sstevel@tonic-gate 	    "ehci_print_qtd: qtd = 0x%p", (void *)qtd);
44140Sstevel@tonic-gate 
44150Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44160Sstevel@tonic-gate 	    "\tqtd_next_qtd: 0x%x ", Get_QTD(qtd->qtd_next_qtd));
44170Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44180Sstevel@tonic-gate 	    "\tqtd_alt_next_qtd: 0x%x ", Get_QTD(qtd->qtd_alt_next_qtd));
44190Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44200Sstevel@tonic-gate 	    "\tqtd_ctrl: 0x%x ", Get_QTD(qtd->qtd_ctrl));
44210Sstevel@tonic-gate 
44220Sstevel@tonic-gate 	for (i = 0; i < 5; i++) {
44230Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44240Sstevel@tonic-gate 		    "\tqtd_buf[%d]: 0x%x ", i, Get_QTD(qtd->qtd_buf[i]));
44250Sstevel@tonic-gate 	}
44260Sstevel@tonic-gate 
44270Sstevel@tonic-gate 	for (i = 0; i < 5; i++) {
44280Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44290Sstevel@tonic-gate 		    "\tqtd_buf_high[%d]: 0x%x ",
44300Sstevel@tonic-gate 		    i, Get_QTD(qtd->qtd_buf_high[i]));
44310Sstevel@tonic-gate 	}
44320Sstevel@tonic-gate 
44330Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44340Sstevel@tonic-gate 	    "\tqtd_trans_wrapper: 0x%x ", Get_QTD(qtd->qtd_trans_wrapper));
44350Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44360Sstevel@tonic-gate 	    "\tqtd_tw_next_qtd: 0x%x ", Get_QTD(qtd->qtd_tw_next_qtd));
44370Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44380Sstevel@tonic-gate 	    "\tqtd_active_qtd_next: 0x%x ", Get_QTD(qtd->qtd_active_qtd_next));
44390Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44400Sstevel@tonic-gate 	    "\tqtd_active_qtd_prev: 0x%x ", Get_QTD(qtd->qtd_active_qtd_prev));
44410Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44420Sstevel@tonic-gate 	    "\tqtd_state: 0x%x ", Get_QTD(qtd->qtd_state));
44430Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44440Sstevel@tonic-gate 	    "\tqtd_ctrl_phase: 0x%x ", Get_QTD(qtd->qtd_ctrl_phase));
44450Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44461500Ssl147100 	    "\tqtd_xfer_offs: 0x%x ", Get_QTD(qtd->qtd_xfer_offs));
44470Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44480Sstevel@tonic-gate 	    "\tqtd_xfer_len: 0x%x ", Get_QTD(qtd->qtd_xfer_len));
44490Sstevel@tonic-gate }
44500Sstevel@tonic-gate 
44510Sstevel@tonic-gate /*
44520Sstevel@tonic-gate  * ehci kstat functions
44530Sstevel@tonic-gate  */
44540Sstevel@tonic-gate 
44550Sstevel@tonic-gate /*
44560Sstevel@tonic-gate  * ehci_create_stats:
44570Sstevel@tonic-gate  *
44580Sstevel@tonic-gate  * Allocate and initialize the ehci kstat structures
44590Sstevel@tonic-gate  */
44600Sstevel@tonic-gate void
ehci_create_stats(ehci_state_t * ehcip)44610Sstevel@tonic-gate ehci_create_stats(ehci_state_t	*ehcip)
44620Sstevel@tonic-gate {
44630Sstevel@tonic-gate 	char			kstatname[KSTAT_STRLEN];
44640Sstevel@tonic-gate 	const char		*dname = ddi_driver_name(ehcip->ehci_dip);
44650Sstevel@tonic-gate 	char			*usbtypes[USB_N_COUNT_KSTATS] =
44665767Slc152243 	    {"ctrl", "isoch", "bulk", "intr"};
44670Sstevel@tonic-gate 	uint_t			instance = ehcip->ehci_instance;
44680Sstevel@tonic-gate 	ehci_intrs_stats_t	*isp;
44690Sstevel@tonic-gate 	int			i;
44700Sstevel@tonic-gate 
44710Sstevel@tonic-gate 	if (EHCI_INTRS_STATS(ehcip) == NULL) {
44720Sstevel@tonic-gate 		(void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,intrs",
44730Sstevel@tonic-gate 		    dname, instance);
44740Sstevel@tonic-gate 		EHCI_INTRS_STATS(ehcip) = kstat_create("usba", instance,
44750Sstevel@tonic-gate 		    kstatname, "usb_interrupts", KSTAT_TYPE_NAMED,
44760Sstevel@tonic-gate 		    sizeof (ehci_intrs_stats_t) / sizeof (kstat_named_t),
44770Sstevel@tonic-gate 		    KSTAT_FLAG_PERSISTENT);
44780Sstevel@tonic-gate 
44790Sstevel@tonic-gate 		if (EHCI_INTRS_STATS(ehcip)) {
44800Sstevel@tonic-gate 			isp = EHCI_INTRS_STATS_DATA(ehcip);
44810Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_total,
44820Sstevel@tonic-gate 			    "Interrupts Total", KSTAT_DATA_UINT64);
44830Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_not_claimed,
44840Sstevel@tonic-gate 			    "Not Claimed", KSTAT_DATA_UINT64);
44850Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_async_sched_status,
44860Sstevel@tonic-gate 			    "Async schedule status", KSTAT_DATA_UINT64);
44870Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_periodic_sched_status,
44880Sstevel@tonic-gate 			    "Periodic sched status", KSTAT_DATA_UINT64);
44890Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_empty_async_schedule,
44900Sstevel@tonic-gate 			    "Empty async schedule", KSTAT_DATA_UINT64);
44910Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_host_ctrl_halted,
44920Sstevel@tonic-gate 			    "Host controller Halted", KSTAT_DATA_UINT64);
44930Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_async_advance_intr,
44940Sstevel@tonic-gate 			    "Intr on async advance", KSTAT_DATA_UINT64);
44950Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_host_system_error_intr,
44960Sstevel@tonic-gate 			    "Host system error", KSTAT_DATA_UINT64);
44970Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_frm_list_rollover_intr,
44980Sstevel@tonic-gate 			    "Frame list rollover", KSTAT_DATA_UINT64);
44990Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_rh_port_change_intr,
45000Sstevel@tonic-gate 			    "Port change detect", KSTAT_DATA_UINT64);
45010Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_usb_error_intr,
45020Sstevel@tonic-gate 			    "USB error interrupt", KSTAT_DATA_UINT64);
45030Sstevel@tonic-gate 			kstat_named_init(&isp->ehci_sts_usb_intr,
45040Sstevel@tonic-gate 			    "USB interrupt", KSTAT_DATA_UINT64);
45050Sstevel@tonic-gate 
45060Sstevel@tonic-gate 			EHCI_INTRS_STATS(ehcip)->ks_private = ehcip;
45070Sstevel@tonic-gate 			EHCI_INTRS_STATS(ehcip)->ks_update = nulldev;
45080Sstevel@tonic-gate 			kstat_install(EHCI_INTRS_STATS(ehcip));
45090Sstevel@tonic-gate 		}
45100Sstevel@tonic-gate 	}
45110Sstevel@tonic-gate 
45120Sstevel@tonic-gate 	if (EHCI_TOTAL_STATS(ehcip) == NULL) {
45130Sstevel@tonic-gate 		(void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,total",
45140Sstevel@tonic-gate 		    dname, instance);
45150Sstevel@tonic-gate 		EHCI_TOTAL_STATS(ehcip) = kstat_create("usba", instance,
45160Sstevel@tonic-gate 		    kstatname, "usb_byte_count", KSTAT_TYPE_IO, 1,
45170Sstevel@tonic-gate 		    KSTAT_FLAG_PERSISTENT);
45180Sstevel@tonic-gate 
45190Sstevel@tonic-gate 		if (EHCI_TOTAL_STATS(ehcip)) {
45200Sstevel@tonic-gate 			kstat_install(EHCI_TOTAL_STATS(ehcip));
45210Sstevel@tonic-gate 		}
45220Sstevel@tonic-gate 	}
45230Sstevel@tonic-gate 
45240Sstevel@tonic-gate 	for (i = 0; i < USB_N_COUNT_KSTATS; i++) {
45250Sstevel@tonic-gate 		if (ehcip->ehci_count_stats[i] == NULL) {
45260Sstevel@tonic-gate 			(void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,%s",
45270Sstevel@tonic-gate 			    dname, instance, usbtypes[i]);
45280Sstevel@tonic-gate 			ehcip->ehci_count_stats[i] = kstat_create("usba",
45290Sstevel@tonic-gate 			    instance, kstatname, "usb_byte_count",
45300Sstevel@tonic-gate 			    KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
45310Sstevel@tonic-gate 
45320Sstevel@tonic-gate 			if (ehcip->ehci_count_stats[i]) {
45330Sstevel@tonic-gate 				kstat_install(ehcip->ehci_count_stats[i]);
45340Sstevel@tonic-gate 			}
45350Sstevel@tonic-gate 		}
45360Sstevel@tonic-gate 	}
45370Sstevel@tonic-gate }
45380Sstevel@tonic-gate 
45390Sstevel@tonic-gate 
45400Sstevel@tonic-gate /*
45410Sstevel@tonic-gate  * ehci_destroy_stats:
45420Sstevel@tonic-gate  *
45430Sstevel@tonic-gate  * Clean up ehci kstat structures
45440Sstevel@tonic-gate  */
45450Sstevel@tonic-gate void
ehci_destroy_stats(ehci_state_t * ehcip)45460Sstevel@tonic-gate ehci_destroy_stats(ehci_state_t	*ehcip)
45470Sstevel@tonic-gate {
45480Sstevel@tonic-gate 	int	i;
45490Sstevel@tonic-gate 
45500Sstevel@tonic-gate 	if (EHCI_INTRS_STATS(ehcip)) {
45510Sstevel@tonic-gate 		kstat_delete(EHCI_INTRS_STATS(ehcip));
45520Sstevel@tonic-gate 		EHCI_INTRS_STATS(ehcip) = NULL;
45530Sstevel@tonic-gate 	}
45540Sstevel@tonic-gate 
45550Sstevel@tonic-gate 	if (EHCI_TOTAL_STATS(ehcip)) {
45560Sstevel@tonic-gate 		kstat_delete(EHCI_TOTAL_STATS(ehcip));
45570Sstevel@tonic-gate 		EHCI_TOTAL_STATS(ehcip) = NULL;
45580Sstevel@tonic-gate 	}
45590Sstevel@tonic-gate 
45600Sstevel@tonic-gate 	for (i = 0; i < USB_N_COUNT_KSTATS; i++) {
45610Sstevel@tonic-gate 		if (ehcip->ehci_count_stats[i]) {
45620Sstevel@tonic-gate 			kstat_delete(ehcip->ehci_count_stats[i]);
45630Sstevel@tonic-gate 			ehcip->ehci_count_stats[i] = NULL;
45640Sstevel@tonic-gate 		}
45650Sstevel@tonic-gate 	}
45660Sstevel@tonic-gate }
45670Sstevel@tonic-gate 
45680Sstevel@tonic-gate 
45690Sstevel@tonic-gate /*
45700Sstevel@tonic-gate  * ehci_do_intrs_stats:
45710Sstevel@tonic-gate  *
45720Sstevel@tonic-gate  * ehci status information
45730Sstevel@tonic-gate  */
45740Sstevel@tonic-gate void
ehci_do_intrs_stats(ehci_state_t * ehcip,int val)45750Sstevel@tonic-gate ehci_do_intrs_stats(
45760Sstevel@tonic-gate 	ehci_state_t	*ehcip,
45770Sstevel@tonic-gate 	int		val)
45780Sstevel@tonic-gate {
45790Sstevel@tonic-gate 	if (EHCI_INTRS_STATS(ehcip)) {
45800Sstevel@tonic-gate 		EHCI_INTRS_STATS_DATA(ehcip)->ehci_sts_total.value.ui64++;
45810Sstevel@tonic-gate 		switch (val) {
45820Sstevel@tonic-gate 		case EHCI_STS_ASYNC_SCHED_STATUS:
45830Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
45840Sstevel@tonic-gate 			    ehci_sts_async_sched_status.value.ui64++;
45850Sstevel@tonic-gate 			break;
45860Sstevel@tonic-gate 		case EHCI_STS_PERIODIC_SCHED_STATUS:
45870Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
45880Sstevel@tonic-gate 			    ehci_sts_periodic_sched_status.value.ui64++;
45890Sstevel@tonic-gate 			break;
45900Sstevel@tonic-gate 		case EHCI_STS_EMPTY_ASYNC_SCHEDULE:
45910Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
45920Sstevel@tonic-gate 			    ehci_sts_empty_async_schedule.value.ui64++;
45930Sstevel@tonic-gate 			break;
45940Sstevel@tonic-gate 		case EHCI_STS_HOST_CTRL_HALTED:
45950Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
45960Sstevel@tonic-gate 			    ehci_sts_host_ctrl_halted.value.ui64++;
45970Sstevel@tonic-gate 			break;
45980Sstevel@tonic-gate 		case EHCI_STS_ASYNC_ADVANCE_INTR:
45990Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
46000Sstevel@tonic-gate 			    ehci_sts_async_advance_intr.value.ui64++;
46010Sstevel@tonic-gate 			break;
46020Sstevel@tonic-gate 		case EHCI_STS_HOST_SYSTEM_ERROR_INTR:
46030Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
46040Sstevel@tonic-gate 			    ehci_sts_host_system_error_intr.value.ui64++;
46050Sstevel@tonic-gate 			break;
46060Sstevel@tonic-gate 		case EHCI_STS_FRM_LIST_ROLLOVER_INTR:
46070Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
46080Sstevel@tonic-gate 			    ehci_sts_frm_list_rollover_intr.value.ui64++;
46090Sstevel@tonic-gate 			break;
46100Sstevel@tonic-gate 		case EHCI_STS_RH_PORT_CHANGE_INTR:
46110Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
46120Sstevel@tonic-gate 			    ehci_sts_rh_port_change_intr.value.ui64++;
46130Sstevel@tonic-gate 			break;
46140Sstevel@tonic-gate 		case EHCI_STS_USB_ERROR_INTR:
46150Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
46160Sstevel@tonic-gate 			    ehci_sts_usb_error_intr.value.ui64++;
46170Sstevel@tonic-gate 			break;
46180Sstevel@tonic-gate 		case EHCI_STS_USB_INTR:
46190Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
46200Sstevel@tonic-gate 			    ehci_sts_usb_intr.value.ui64++;
46210Sstevel@tonic-gate 			break;
46220Sstevel@tonic-gate 		default:
46230Sstevel@tonic-gate 			EHCI_INTRS_STATS_DATA(ehcip)->
46240Sstevel@tonic-gate 			    ehci_sts_not_claimed.value.ui64++;
46250Sstevel@tonic-gate 			break;
46260Sstevel@tonic-gate 		}
46270Sstevel@tonic-gate 	}
46280Sstevel@tonic-gate }
46290Sstevel@tonic-gate 
46300Sstevel@tonic-gate 
46310Sstevel@tonic-gate /*
46320Sstevel@tonic-gate  * ehci_do_byte_stats:
46330Sstevel@tonic-gate  *
46340Sstevel@tonic-gate  * ehci data xfer information
46350Sstevel@tonic-gate  */
46360Sstevel@tonic-gate void
ehci_do_byte_stats(ehci_state_t * ehcip,size_t len,uint8_t attr,uint8_t addr)46370Sstevel@tonic-gate ehci_do_byte_stats(
46380Sstevel@tonic-gate 	ehci_state_t	*ehcip,
46390Sstevel@tonic-gate 	size_t		len,
46400Sstevel@tonic-gate 	uint8_t		attr,
46410Sstevel@tonic-gate 	uint8_t		addr)
46420Sstevel@tonic-gate {
46430Sstevel@tonic-gate 	uint8_t 	type = attr & USB_EP_ATTR_MASK;
46440Sstevel@tonic-gate 	uint8_t 	dir = addr & USB_EP_DIR_MASK;
46450Sstevel@tonic-gate 
46460Sstevel@tonic-gate 	if (dir == USB_EP_DIR_IN) {
46470Sstevel@tonic-gate 		EHCI_TOTAL_STATS_DATA(ehcip)->reads++;
46480Sstevel@tonic-gate 		EHCI_TOTAL_STATS_DATA(ehcip)->nread += len;
46490Sstevel@tonic-gate 		switch (type) {
46500Sstevel@tonic-gate 			case USB_EP_ATTR_CONTROL:
46510Sstevel@tonic-gate 				EHCI_CTRL_STATS(ehcip)->reads++;
46520Sstevel@tonic-gate 				EHCI_CTRL_STATS(ehcip)->nread += len;
46530Sstevel@tonic-gate 				break;
46540Sstevel@tonic-gate 			case USB_EP_ATTR_BULK:
46550Sstevel@tonic-gate 				EHCI_BULK_STATS(ehcip)->reads++;
46560Sstevel@tonic-gate 				EHCI_BULK_STATS(ehcip)->nread += len;
46570Sstevel@tonic-gate 				break;
46580Sstevel@tonic-gate 			case USB_EP_ATTR_INTR:
46590Sstevel@tonic-gate 				EHCI_INTR_STATS(ehcip)->reads++;
46600Sstevel@tonic-gate 				EHCI_INTR_STATS(ehcip)->nread += len;
46610Sstevel@tonic-gate 				break;
46620Sstevel@tonic-gate 			case USB_EP_ATTR_ISOCH:
46630Sstevel@tonic-gate 				EHCI_ISOC_STATS(ehcip)->reads++;
46640Sstevel@tonic-gate 				EHCI_ISOC_STATS(ehcip)->nread += len;
46650Sstevel@tonic-gate 				break;
46660Sstevel@tonic-gate 		}
46670Sstevel@tonic-gate 	} else if (dir == USB_EP_DIR_OUT) {
46680Sstevel@tonic-gate 		EHCI_TOTAL_STATS_DATA(ehcip)->writes++;
46690Sstevel@tonic-gate 		EHCI_TOTAL_STATS_DATA(ehcip)->nwritten += len;
46700Sstevel@tonic-gate 		switch (type) {
46710Sstevel@tonic-gate 			case USB_EP_ATTR_CONTROL:
46720Sstevel@tonic-gate 				EHCI_CTRL_STATS(ehcip)->writes++;
46730Sstevel@tonic-gate 				EHCI_CTRL_STATS(ehcip)->nwritten += len;
46740Sstevel@tonic-gate 				break;
46750Sstevel@tonic-gate 			case USB_EP_ATTR_BULK:
46760Sstevel@tonic-gate 				EHCI_BULK_STATS(ehcip)->writes++;
46770Sstevel@tonic-gate 				EHCI_BULK_STATS(ehcip)->nwritten += len;
46780Sstevel@tonic-gate 				break;
46790Sstevel@tonic-gate 			case USB_EP_ATTR_INTR:
46800Sstevel@tonic-gate 				EHCI_INTR_STATS(ehcip)->writes++;
46810Sstevel@tonic-gate 				EHCI_INTR_STATS(ehcip)->nwritten += len;
46820Sstevel@tonic-gate 				break;
46830Sstevel@tonic-gate 			case USB_EP_ATTR_ISOCH:
46840Sstevel@tonic-gate 				EHCI_ISOC_STATS(ehcip)->writes++;
46850Sstevel@tonic-gate 				EHCI_ISOC_STATS(ehcip)->nwritten += len;
46860Sstevel@tonic-gate 				break;
46870Sstevel@tonic-gate 		}
46880Sstevel@tonic-gate 	}
46890Sstevel@tonic-gate }
4690