17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53b00f311Syq  * Common Development and Distribution License (the "License").
63b00f311Syq  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21dfbb3a42SRaymond Chen 
227c478bd9Sstevel@tonic-gate /*
23dfbb3a42SRaymond Chen  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
249a48f6c4SRobert Mustacchi  * Copyright (c) 2018, Joyent, Inc.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * EHCI Host Controller Driver (EHCI)
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  * The EHCI driver is a software driver which interfaces to the Universal
317c478bd9Sstevel@tonic-gate  * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
327c478bd9Sstevel@tonic-gate  * the Host Controller is defined by the EHCI Host Controller Interface.
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * This module contains the main EHCI driver code which handles all USB
357c478bd9Sstevel@tonic-gate  * transfers, bandwidth allocations and other general functionalities.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h>
397c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_isoch.h>
407c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h>
417c478bd9Sstevel@tonic-gate 
429c75c6bfSgovinda /*
439c75c6bfSgovinda  * EHCI MSI tunable:
449c75c6bfSgovinda  *
459c75c6bfSgovinda  * By default MSI is enabled on all supported platforms except for the
469c75c6bfSgovinda  * EHCI controller of ULI1575 South bridge.
479c75c6bfSgovinda  */
489c75c6bfSgovinda boolean_t ehci_enable_msi = B_TRUE;
499c75c6bfSgovinda 
507c478bd9Sstevel@tonic-gate /* Pointer to the state structure */
517c478bd9Sstevel@tonic-gate extern void *ehci_statep;
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate extern void ehci_handle_endpoint_reclaimation(ehci_state_t *);
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate extern uint_t ehci_vt62x2_workaround;
562df1fe9cSrandyf extern int force_ehci_off;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /* Adjustable variables for the size of the pools */
597c478bd9Sstevel@tonic-gate int ehci_qh_pool_size = EHCI_QH_POOL_SIZE;
607c478bd9Sstevel@tonic-gate int ehci_qtd_pool_size = EHCI_QTD_POOL_SIZE;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * Initialize the values which the order of 32ms intr qh are executed
647c478bd9Sstevel@tonic-gate  * by the host controller in the lattice tree.
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate static uchar_t ehci_index[EHCI_NUM_INTR_QH_LISTS] =
677c478bd9Sstevel@tonic-gate 	{0x00, 0x10, 0x08, 0x18,
687c478bd9Sstevel@tonic-gate 	0x04, 0x14, 0x0c, 0x1c,
697c478bd9Sstevel@tonic-gate 	0x02, 0x12, 0x0a, 0x1a,
707c478bd9Sstevel@tonic-gate 	0x06, 0x16, 0x0e, 0x1e,
717c478bd9Sstevel@tonic-gate 	0x01, 0x11, 0x09, 0x19,
727c478bd9Sstevel@tonic-gate 	0x05, 0x15, 0x0d, 0x1d,
737c478bd9Sstevel@tonic-gate 	0x03, 0x13, 0x0b, 0x1b,
747c478bd9Sstevel@tonic-gate 	0x07, 0x17, 0x0f, 0x1f};
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate  * Initialize the values which are used to calculate start split mask
787c478bd9Sstevel@tonic-gate  * for the low/full/high speed interrupt and isochronous endpoints.
797c478bd9Sstevel@tonic-gate  */
807c478bd9Sstevel@tonic-gate static uint_t ehci_start_split_mask[15] = {
817c478bd9Sstevel@tonic-gate 		/*
827c478bd9Sstevel@tonic-gate 		 * For high/full/low speed usb devices. For high speed
837c478bd9Sstevel@tonic-gate 		 * device with polling interval greater than or equal
847c478bd9Sstevel@tonic-gate 		 * to 8us (125us).
857c478bd9Sstevel@tonic-gate 		 */
867c478bd9Sstevel@tonic-gate 		0x01,	/* 00000001 */
877c478bd9Sstevel@tonic-gate 		0x02,	/* 00000010 */
887c478bd9Sstevel@tonic-gate 		0x04,	/* 00000100 */
897c478bd9Sstevel@tonic-gate 		0x08,	/* 00001000 */
907c478bd9Sstevel@tonic-gate 		0x10,	/* 00010000 */
917c478bd9Sstevel@tonic-gate 		0x20,	/* 00100000 */
927c478bd9Sstevel@tonic-gate 		0x40,	/* 01000000 */
937c478bd9Sstevel@tonic-gate 		0x80,	/* 10000000 */
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 		/* Only for high speed devices with polling interval 4us */
967c478bd9Sstevel@tonic-gate 		0x11,	/* 00010001 */
977c478bd9Sstevel@tonic-gate 		0x22,	/* 00100010 */
987c478bd9Sstevel@tonic-gate 		0x44,	/* 01000100 */
997c478bd9Sstevel@tonic-gate 		0x88,	/* 10001000 */
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 		/* Only for high speed devices with polling interval 2us */
1027c478bd9Sstevel@tonic-gate 		0x55,	/* 01010101 */
1037c478bd9Sstevel@tonic-gate 		0xaa,	/* 10101010 */
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 		/* Only for high speed devices with polling interval 1us */
1067c478bd9Sstevel@tonic-gate 		0xff	/* 11111111 */
1077c478bd9Sstevel@tonic-gate };
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate /*
1107c478bd9Sstevel@tonic-gate  * Initialize the values which are used to calculate complete split mask
1117c478bd9Sstevel@tonic-gate  * for the low/full speed interrupt and isochronous endpoints.
1127c478bd9Sstevel@tonic-gate  */
1137c478bd9Sstevel@tonic-gate static uint_t ehci_intr_complete_split_mask[7] = {
1147c478bd9Sstevel@tonic-gate 		/* Only full/low speed devices */
1157c478bd9Sstevel@tonic-gate 		0x1c,	/* 00011100 */
1167c478bd9Sstevel@tonic-gate 		0x38,	/* 00111000 */
1177c478bd9Sstevel@tonic-gate 		0x70,	/* 01110000 */
1187c478bd9Sstevel@tonic-gate 		0xe0,	/* 11100000 */
1197c478bd9Sstevel@tonic-gate 		0x00,	/* Need FSTN feature */
1207c478bd9Sstevel@tonic-gate 		0x00,	/* Need FSTN feature */
1217c478bd9Sstevel@tonic-gate 		0x00	/* Need FSTN feature */
1227c478bd9Sstevel@tonic-gate };
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * EHCI Internal Function Prototypes
1277c478bd9Sstevel@tonic-gate  */
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) initialization functions */
1307c478bd9Sstevel@tonic-gate void		ehci_set_dma_attributes(ehci_state_t	*ehcip);
1317c478bd9Sstevel@tonic-gate int		ehci_allocate_pools(ehci_state_t	*ehcip);
1327c478bd9Sstevel@tonic-gate void		ehci_decode_ddi_dma_addr_bind_handle_result(
1337c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1347c478bd9Sstevel@tonic-gate 				int			result);
1357c478bd9Sstevel@tonic-gate int		ehci_map_regs(ehci_state_t		*ehcip);
1367c478bd9Sstevel@tonic-gate int		ehci_register_intrs_and_init_mutex(
1377c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
1389c75c6bfSgovinda static int	ehci_add_intrs(ehci_state_t		*ehcip,
1399c75c6bfSgovinda 				int			intr_type);
1403b00f311Syq int		ehci_init_ctlr(ehci_state_t		*ehcip,
1413b00f311Syq 				int			init_type);
1427c478bd9Sstevel@tonic-gate static int	ehci_take_control(ehci_state_t		*ehcip);
1437c478bd9Sstevel@tonic-gate static int	ehci_init_periodic_frame_lst_table(
1447c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
1457c478bd9Sstevel@tonic-gate static void	ehci_build_interrupt_lattice(
1467c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
1477c478bd9Sstevel@tonic-gate usba_hcdi_ops_t *ehci_alloc_hcdi_ops(ehci_state_t	*ehcip);
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /* Host Controller Driver (HCD) deinitialization functions */
1507c478bd9Sstevel@tonic-gate int		ehci_cleanup(ehci_state_t		*ehcip);
1519c75c6bfSgovinda static void	ehci_rem_intrs(ehci_state_t		*ehcip);
1527c478bd9Sstevel@tonic-gate int		ehci_cpr_suspend(ehci_state_t		*ehcip);
1537c478bd9Sstevel@tonic-gate int		ehci_cpr_resume(ehci_state_t		*ehcip);
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /* Bandwidth Allocation functions */
1567c478bd9Sstevel@tonic-gate int		ehci_allocate_bandwidth(ehci_state_t	*ehcip,
1577c478bd9Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
1587c478bd9Sstevel@tonic-gate 				uint_t			*pnode,
1597c478bd9Sstevel@tonic-gate 				uchar_t			*smask,
1607c478bd9Sstevel@tonic-gate 				uchar_t			*cmask);
1617c478bd9Sstevel@tonic-gate static int	ehci_allocate_high_speed_bandwidth(
1627c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1637c478bd9Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
1647c478bd9Sstevel@tonic-gate 				uint_t			*hnode,
1657c478bd9Sstevel@tonic-gate 				uchar_t			*smask,
1667c478bd9Sstevel@tonic-gate 				uchar_t			*cmask);
1677c478bd9Sstevel@tonic-gate static int	ehci_allocate_classic_tt_bandwidth(
1687c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1697c478bd9Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
1707c478bd9Sstevel@tonic-gate 				uint_t			pnode);
1717c478bd9Sstevel@tonic-gate void		ehci_deallocate_bandwidth(ehci_state_t	*ehcip,
1727c478bd9Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
1737c478bd9Sstevel@tonic-gate 				uint_t			pnode,
1747c478bd9Sstevel@tonic-gate 				uchar_t			smask,
1757c478bd9Sstevel@tonic-gate 				uchar_t			cmask);
1767c478bd9Sstevel@tonic-gate static void	ehci_deallocate_high_speed_bandwidth(
1777c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1787c478bd9Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
1797c478bd9Sstevel@tonic-gate 				uint_t			hnode,
1807c478bd9Sstevel@tonic-gate 				uchar_t			smask,
1817c478bd9Sstevel@tonic-gate 				uchar_t			cmask);
1827c478bd9Sstevel@tonic-gate static void	ehci_deallocate_classic_tt_bandwidth(
1837c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1847c478bd9Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
1857c478bd9Sstevel@tonic-gate 				uint_t			pnode);
1867c478bd9Sstevel@tonic-gate static int	ehci_compute_high_speed_bandwidth(
1877c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1887c478bd9Sstevel@tonic-gate 				usb_ep_descr_t		*endpoint,
1897c478bd9Sstevel@tonic-gate 				usb_port_status_t	port_status,
1907c478bd9Sstevel@tonic-gate 				uint_t			*sbandwidth,
1917c478bd9Sstevel@tonic-gate 				uint_t			*cbandwidth);
1927c478bd9Sstevel@tonic-gate static int	ehci_compute_classic_bandwidth(
1937c478bd9Sstevel@tonic-gate 				usb_ep_descr_t		*endpoint,
1947c478bd9Sstevel@tonic-gate 				usb_port_status_t	port_status,
1957c478bd9Sstevel@tonic-gate 				uint_t			*bandwidth);
1967c478bd9Sstevel@tonic-gate int		ehci_adjust_polling_interval(
1977c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1987c478bd9Sstevel@tonic-gate 				usb_ep_descr_t		*endpoint,
1997c478bd9Sstevel@tonic-gate 				usb_port_status_t	port_status);
2007c478bd9Sstevel@tonic-gate static int	ehci_adjust_high_speed_polling_interval(
2017c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
2027c478bd9Sstevel@tonic-gate 				usb_ep_descr_t		*endpoint);
2037c478bd9Sstevel@tonic-gate static uint_t	ehci_lattice_height(uint_t		interval);
2047c478bd9Sstevel@tonic-gate static uint_t	ehci_lattice_parent(uint_t		node);
2057c478bd9Sstevel@tonic-gate static uint_t	ehci_find_periodic_node(
2067c478bd9Sstevel@tonic-gate 				uint_t			leaf,
2077c478bd9Sstevel@tonic-gate 				int			interval);
2087c478bd9Sstevel@tonic-gate static uint_t	ehci_leftmost_leaf(uint_t		node,
2097c478bd9Sstevel@tonic-gate 				uint_t			height);
2107c478bd9Sstevel@tonic-gate static uint_t	ehci_pow_2(uint_t x);
2117c478bd9Sstevel@tonic-gate static uint_t	ehci_log_2(uint_t x);
2127c478bd9Sstevel@tonic-gate static int	ehci_find_bestfit_hs_mask(
2137c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
2147c478bd9Sstevel@tonic-gate 				uchar_t			*smask,
2157c478bd9Sstevel@tonic-gate 				uint_t			*pnode,
2167c478bd9Sstevel@tonic-gate 				usb_ep_descr_t		*endpoint,
2177c478bd9Sstevel@tonic-gate 				uint_t			bandwidth,
2187c478bd9Sstevel@tonic-gate 				int			interval);
2197c478bd9Sstevel@tonic-gate static int	ehci_find_bestfit_ls_intr_mask(
2207c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
2217c478bd9Sstevel@tonic-gate 				uchar_t			*smask,
2227c478bd9Sstevel@tonic-gate 				uchar_t			*cmask,
2237c478bd9Sstevel@tonic-gate 				uint_t			*pnode,
2247c478bd9Sstevel@tonic-gate 				uint_t			sbandwidth,
2257c478bd9Sstevel@tonic-gate 				uint_t			cbandwidth,
2267c478bd9Sstevel@tonic-gate 				int			interval);
2277c478bd9Sstevel@tonic-gate static int	ehci_find_bestfit_sitd_in_mask(
2287c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
2297c478bd9Sstevel@tonic-gate 				uchar_t			*smask,
2307c478bd9Sstevel@tonic-gate 				uchar_t			*cmask,
2317c478bd9Sstevel@tonic-gate 				uint_t			*pnode,
2327c478bd9Sstevel@tonic-gate 				uint_t			sbandwidth,
2337c478bd9Sstevel@tonic-gate 				uint_t			cbandwidth,
2347c478bd9Sstevel@tonic-gate 				int			interval);
2357c478bd9Sstevel@tonic-gate static int	ehci_find_bestfit_sitd_out_mask(
2367c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
2377c478bd9Sstevel@tonic-gate 				uchar_t			*smask,
2387c478bd9Sstevel@tonic-gate 				uint_t			*pnode,
2397c478bd9Sstevel@tonic-gate 				uint_t			sbandwidth,
2407c478bd9Sstevel@tonic-gate 				int			interval);
2417c478bd9Sstevel@tonic-gate static uint_t	ehci_calculate_bw_availability_mask(
2427c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
2437c478bd9Sstevel@tonic-gate 				uint_t			bandwidth,
2447c478bd9Sstevel@tonic-gate 				int			leaf,
2457c478bd9Sstevel@tonic-gate 				int			leaf_count,
2467c478bd9Sstevel@tonic-gate 				uchar_t			*bw_mask);
2477c478bd9Sstevel@tonic-gate static void	ehci_update_bw_availability(
2487c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
2497c478bd9Sstevel@tonic-gate 				int			bandwidth,
2507c478bd9Sstevel@tonic-gate 				int			leftmost_leaf,
2517c478bd9Sstevel@tonic-gate 				int			leaf_count,
2527c478bd9Sstevel@tonic-gate 				uchar_t			mask);
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate /* Miscellaneous functions */
2557c478bd9Sstevel@tonic-gate ehci_state_t	*ehci_obtain_state(
2567c478bd9Sstevel@tonic-gate 				dev_info_t		*dip);
2577c478bd9Sstevel@tonic-gate int		ehci_state_is_operational(
2587c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
2597c478bd9Sstevel@tonic-gate int		ehci_do_soft_reset(
2607c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
2617c478bd9Sstevel@tonic-gate usb_req_attrs_t ehci_get_xfer_attrs(ehci_state_t	*ehcip,
2627c478bd9Sstevel@tonic-gate 				ehci_pipe_private_t	*pp,
2637c478bd9Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw);
2647c478bd9Sstevel@tonic-gate usb_frame_number_t ehci_get_current_frame_number(
2657c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
2667c478bd9Sstevel@tonic-gate static void	ehci_cpr_cleanup(
2677c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
2687c478bd9Sstevel@tonic-gate int		ehci_wait_for_sof(
2697c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
2707c478bd9Sstevel@tonic-gate void		ehci_toggle_scheduler(
2717c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
2727c478bd9Sstevel@tonic-gate void		ehci_print_caps(ehci_state_t		*ehcip);
2737c478bd9Sstevel@tonic-gate void		ehci_print_regs(ehci_state_t		*ehcip);
2747c478bd9Sstevel@tonic-gate void		ehci_print_qh(ehci_state_t		*ehcip,
2757c478bd9Sstevel@tonic-gate 				ehci_qh_t		*qh);
2767c478bd9Sstevel@tonic-gate void		ehci_print_qtd(ehci_state_t		*ehcip,
2777c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd);
2787c478bd9Sstevel@tonic-gate void		ehci_create_stats(ehci_state_t		*ehcip);
2797c478bd9Sstevel@tonic-gate void		ehci_destroy_stats(ehci_state_t		*ehcip);
2807c478bd9Sstevel@tonic-gate void		ehci_do_intrs_stats(ehci_state_t	*ehcip,
2817c478bd9Sstevel@tonic-gate 				int		val);
2827c478bd9Sstevel@tonic-gate void		ehci_do_byte_stats(ehci_state_t		*ehcip,
2837c478bd9Sstevel@tonic-gate 				size_t		len,
2847c478bd9Sstevel@tonic-gate 				uint8_t		attr,
2857c478bd9Sstevel@tonic-gate 				uint8_t		addr);
2867c478bd9Sstevel@tonic-gate 
2874610e4a0Sfrits /*
2884610e4a0Sfrits  * check if this ehci controller can support PM
2894610e4a0Sfrits  */
2904610e4a0Sfrits int
ehci_hcdi_pm_support(dev_info_t * dip)2914610e4a0Sfrits ehci_hcdi_pm_support(dev_info_t *dip)
2924610e4a0Sfrits {
2934610e4a0Sfrits 	ehci_state_t *ehcip = ddi_get_soft_state(ehci_statep,
29429aca3ebSlc 	    ddi_get_instance(dip));
2954610e4a0Sfrits 
2964610e4a0Sfrits 	if (((ehcip->ehci_vendor_id == PCI_VENDOR_NEC_COMBO) &&
2974610e4a0Sfrits 	    (ehcip->ehci_device_id == PCI_DEVICE_NEC_COMBO)) ||
2984610e4a0Sfrits 
2994610e4a0Sfrits 	    ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
3004610e4a0Sfrits 	    (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) ||
3014610e4a0Sfrits 
3024610e4a0Sfrits 	    (ehcip->ehci_vendor_id == PCI_VENDOR_VIA)) {
3034610e4a0Sfrits 
3044610e4a0Sfrits 		return (USB_SUCCESS);
3054610e4a0Sfrits 	}
3064610e4a0Sfrits 
3074610e4a0Sfrits 	return (USB_FAILURE);
3084610e4a0Sfrits }
3094610e4a0Sfrits 
3103ceb94daSbc void
ehci_dma_attr_workaround(ehci_state_t * ehcip)3113ceb94daSbc ehci_dma_attr_workaround(ehci_state_t	*ehcip)
3123ceb94daSbc {
3133ceb94daSbc 	/*
3143ceb94daSbc 	 * Some Nvidia chips can not handle qh dma address above 2G.
3153ceb94daSbc 	 * The bit 31 of the dma address might be omitted and it will
3163ceb94daSbc 	 * cause system crash or other unpredicable result. So force
3173ceb94daSbc 	 * the dma address allocated below 2G to make ehci work.
3183ceb94daSbc 	 */
3193ceb94daSbc 	if (PCI_VENDOR_NVIDIA == ehcip->ehci_vendor_id) {
3203ceb94daSbc 		switch (ehcip->ehci_device_id) {
3213ceb94daSbc 			case PCI_DEVICE_NVIDIA_CK804:
3222259743eSbinzi cao - Sun Microsystems - Beijing China 			case PCI_DEVICE_NVIDIA_MCP04:
3233ceb94daSbc 				USB_DPRINTF_L2(PRINT_MASK_ATTA,
3243ceb94daSbc 				    ehcip->ehci_log_hdl,
3253ceb94daSbc 				    "ehci_dma_attr_workaround: NVIDIA dma "
3263ceb94daSbc 				    "workaround enabled, force dma address "
3273ceb94daSbc 				    "to be allocated below 2G");
3283ceb94daSbc 				ehcip->ehci_dma_attr.dma_attr_addr_hi =
3293ceb94daSbc 				    0x7fffffffull;
3303ceb94daSbc 				break;
3313ceb94daSbc 			default:
3323ceb94daSbc 				break;
3333ceb94daSbc 
3343ceb94daSbc 		}
3353ceb94daSbc 	}
3363ceb94daSbc }
3374610e4a0Sfrits 
3387c478bd9Sstevel@tonic-gate /*
3397c478bd9Sstevel@tonic-gate  * Host Controller Driver (HCD) initialization functions
3407c478bd9Sstevel@tonic-gate  */
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate /*
3437c478bd9Sstevel@tonic-gate  * ehci_set_dma_attributes:
3447c478bd9Sstevel@tonic-gate  *
3457c478bd9Sstevel@tonic-gate  * Set the limits in the DMA attributes structure. Most of the values used
3467c478bd9Sstevel@tonic-gate  * in the  DMA limit structures are the default values as specified by	the
3477c478bd9Sstevel@tonic-gate  * Writing PCI device drivers document.
3487c478bd9Sstevel@tonic-gate  */
3497c478bd9Sstevel@tonic-gate void
ehci_set_dma_attributes(ehci_state_t * ehcip)3507c478bd9Sstevel@tonic-gate ehci_set_dma_attributes(ehci_state_t	*ehcip)
3517c478bd9Sstevel@tonic-gate {
3527c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3537c478bd9Sstevel@tonic-gate 	    "ehci_set_dma_attributes:");
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	/* Initialize the DMA attributes */
3567c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_version = DMA_ATTR_V0;
3577c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_addr_lo = 0x00000000ull;
3587c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_addr_hi = 0xfffffffeull;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	/* 32 bit addressing */
3617c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_count_max = EHCI_DMA_ATTR_COUNT_MAX;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	/* Byte alignment */
3647c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	/*
3677c478bd9Sstevel@tonic-gate 	 * Since PCI  specification is byte alignment, the
3687c478bd9Sstevel@tonic-gate 	 * burst size field should be set to 1 for PCI devices.
3697c478bd9Sstevel@tonic-gate 	 */
3707c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_burstsizes = 0x1;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_minxfer = 0x1;
3737c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_maxxfer = EHCI_DMA_ATTR_MAX_XFER;
3747c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_seg = 0xffffffffull;
3757c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_sgllen = 1;
3767c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_granular = EHCI_DMA_ATTR_GRANULAR;
3777c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_flags = 0;
3783ceb94daSbc 	ehci_dma_attr_workaround(ehcip);
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate /*
3837c478bd9Sstevel@tonic-gate  * ehci_allocate_pools:
3847c478bd9Sstevel@tonic-gate  *
3857c478bd9Sstevel@tonic-gate  * Allocate the system memory for the Endpoint Descriptor (QH) and for the
3867c478bd9Sstevel@tonic-gate  * Transfer Descriptor (QTD) pools. Both QH and QTD structures must be aligned
3877c478bd9Sstevel@tonic-gate  * to a 16 byte boundary.
3887c478bd9Sstevel@tonic-gate  */
3897c478bd9Sstevel@tonic-gate int
ehci_allocate_pools(ehci_state_t * ehcip)3907c478bd9Sstevel@tonic-gate ehci_allocate_pools(ehci_state_t	*ehcip)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t		dev_attr;
3937c478bd9Sstevel@tonic-gate 	size_t				real_length;
3947c478bd9Sstevel@tonic-gate 	int				result;
3957c478bd9Sstevel@tonic-gate 	uint_t				ccount;
3967c478bd9Sstevel@tonic-gate 	int				i;
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3997c478bd9Sstevel@tonic-gate 	    "ehci_allocate_pools:");
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	/* The host controller will be little endian */
4027c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_version	= DDI_DEVICE_ATTR_V0;
4037c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
4047c478bd9Sstevel@tonic-gate 	dev_attr.devacc_attr_dataorder	= DDI_STRICTORDER_ACC;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	/* Byte alignment */
4077c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_TD_QH_ALIGNMENT;
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	/* Allocate the QTD pool DMA handle */
4107c478bd9Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr,
41129aca3ebSlc 	    DDI_DMA_SLEEP, 0,
41229aca3ebSlc 	    &ehcip->ehci_qtd_pool_dma_handle) != DDI_SUCCESS) {
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 		goto failure;
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	/* Allocate the memory for the QTD pool */
4187c478bd9Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(ehcip->ehci_qtd_pool_dma_handle,
41929aca3ebSlc 	    ehci_qtd_pool_size * sizeof (ehci_qtd_t),
42029aca3ebSlc 	    &dev_attr,
42129aca3ebSlc 	    DDI_DMA_CONSISTENT,
42229aca3ebSlc 	    DDI_DMA_SLEEP,
42329aca3ebSlc 	    0,
42429aca3ebSlc 	    (caddr_t *)&ehcip->ehci_qtd_pool_addr,
42529aca3ebSlc 	    &real_length,
42629aca3ebSlc 	    &ehcip->ehci_qtd_pool_mem_handle)) {
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 		goto failure;
4297c478bd9Sstevel@tonic-gate 	}
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	/* Map the QTD pool into the I/O address space */
4327c478bd9Sstevel@tonic-gate 	result = ddi_dma_addr_bind_handle(
43329aca3ebSlc 	    ehcip->ehci_qtd_pool_dma_handle,
43429aca3ebSlc 	    NULL,
43529aca3ebSlc 	    (caddr_t)ehcip->ehci_qtd_pool_addr,
43629aca3ebSlc 	    real_length,
43729aca3ebSlc 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
43829aca3ebSlc 	    DDI_DMA_SLEEP,
43929aca3ebSlc 	    NULL,
44029aca3ebSlc 	    &ehcip->ehci_qtd_pool_cookie,
44129aca3ebSlc 	    &ccount);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	bzero((void *)ehcip->ehci_qtd_pool_addr,
44429aca3ebSlc 	    ehci_qtd_pool_size * sizeof (ehci_qtd_t));
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	/* Process the result */
4477c478bd9Sstevel@tonic-gate 	if (result == DDI_DMA_MAPPED) {
4487c478bd9Sstevel@tonic-gate 		/* The cookie count should be 1 */
4497c478bd9Sstevel@tonic-gate 		if (ccount != 1) {
4507c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4517c478bd9Sstevel@tonic-gate 			    "ehci_allocate_pools: More than 1 cookie");
4527c478bd9Sstevel@tonic-gate 
45315c07adcSJohn Levon 			goto failure;
4547c478bd9Sstevel@tonic-gate 		}
4557c478bd9Sstevel@tonic-gate 	} else {
4567c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4577c478bd9Sstevel@tonic-gate 		    "ehci_allocate_pools: Result = %d", result);
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 		ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 		goto failure;
4627c478bd9Sstevel@tonic-gate 	}
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	/*
4657c478bd9Sstevel@tonic-gate 	 * DMA addresses for QTD pools are bound
4667c478bd9Sstevel@tonic-gate 	 */
4677c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_addr_bind_flag |= EHCI_QTD_POOL_BOUND;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	/* Initialize the QTD pool */
4707c478bd9Sstevel@tonic-gate 	for (i = 0; i < ehci_qtd_pool_size; i ++) {
4717c478bd9Sstevel@tonic-gate 		Set_QTD(ehcip->ehci_qtd_pool_addr[i].
4727c478bd9Sstevel@tonic-gate 		    qtd_state, EHCI_QTD_FREE);
4737c478bd9Sstevel@tonic-gate 	}
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	/* Allocate the QTD pool DMA handle */
4767c478bd9Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(ehcip->ehci_dip,
47729aca3ebSlc 	    &ehcip->ehci_dma_attr,
47829aca3ebSlc 	    DDI_DMA_SLEEP,
47929aca3ebSlc 	    0,
48029aca3ebSlc 	    &ehcip->ehci_qh_pool_dma_handle) != DDI_SUCCESS) {
4813ceb94daSbc 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4823ceb94daSbc 		    "ehci_allocate_pools: ddi_dma_alloc_handle failed");
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 		goto failure;
4857c478bd9Sstevel@tonic-gate 	}
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	/* Allocate the memory for the QH pool */
4887c478bd9Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(ehcip->ehci_qh_pool_dma_handle,
48929aca3ebSlc 	    ehci_qh_pool_size * sizeof (ehci_qh_t),
49029aca3ebSlc 	    &dev_attr,
49129aca3ebSlc 	    DDI_DMA_CONSISTENT,
49229aca3ebSlc 	    DDI_DMA_SLEEP,
49329aca3ebSlc 	    0,
49429aca3ebSlc 	    (caddr_t *)&ehcip->ehci_qh_pool_addr,
49529aca3ebSlc 	    &real_length,
49629aca3ebSlc 	    &ehcip->ehci_qh_pool_mem_handle) != DDI_SUCCESS) {
4973ceb94daSbc 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4983ceb94daSbc 		    "ehci_allocate_pools: ddi_dma_mem_alloc failed");
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 		goto failure;
5017c478bd9Sstevel@tonic-gate 	}
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	result = ddi_dma_addr_bind_handle(ehcip->ehci_qh_pool_dma_handle,
50429aca3ebSlc 	    NULL,
50529aca3ebSlc 	    (caddr_t)ehcip->ehci_qh_pool_addr,
50629aca3ebSlc 	    real_length,
50729aca3ebSlc 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
50829aca3ebSlc 	    DDI_DMA_SLEEP,
50929aca3ebSlc 	    NULL,
51029aca3ebSlc 	    &ehcip->ehci_qh_pool_cookie,
51129aca3ebSlc 	    &ccount);
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	bzero((void *)ehcip->ehci_qh_pool_addr,
51429aca3ebSlc 	    ehci_qh_pool_size * sizeof (ehci_qh_t));
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	/* Process the result */
5177c478bd9Sstevel@tonic-gate 	if (result == DDI_DMA_MAPPED) {
5187c478bd9Sstevel@tonic-gate 		/* The cookie count should be 1 */
5197c478bd9Sstevel@tonic-gate 		if (ccount != 1) {
5207c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
5217c478bd9Sstevel@tonic-gate 			    "ehci_allocate_pools: More than 1 cookie");
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 			goto failure;
5247c478bd9Sstevel@tonic-gate 		}
5257c478bd9Sstevel@tonic-gate 	} else {
5267c478bd9Sstevel@tonic-gate 		ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 		goto failure;
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	/*
5327c478bd9Sstevel@tonic-gate 	 * DMA addresses for QH pools are bound
5337c478bd9Sstevel@tonic-gate 	 */
5347c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_addr_bind_flag |= EHCI_QH_POOL_BOUND;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	/* Initialize the QH pool */
5377c478bd9Sstevel@tonic-gate 	for (i = 0; i < ehci_qh_pool_size; i ++) {
5387c478bd9Sstevel@tonic-gate 		Set_QH(ehcip->ehci_qh_pool_addr[i].qh_state, EHCI_QH_FREE);
5397c478bd9Sstevel@tonic-gate 	}
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	/* Byte alignment */
5427c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate failure:
5477c478bd9Sstevel@tonic-gate 	/* Byte alignment */
5487c478bd9Sstevel@tonic-gate 	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate /*
5557c478bd9Sstevel@tonic-gate  * ehci_decode_ddi_dma_addr_bind_handle_result:
5567c478bd9Sstevel@tonic-gate  *
5577c478bd9Sstevel@tonic-gate  * Process the return values of ddi_dma_addr_bind_handle()
5587c478bd9Sstevel@tonic-gate  */
5597c478bd9Sstevel@tonic-gate void
ehci_decode_ddi_dma_addr_bind_handle_result(ehci_state_t * ehcip,int result)5607c478bd9Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(
5617c478bd9Sstevel@tonic-gate 	ehci_state_t	*ehcip,
5627c478bd9Sstevel@tonic-gate 	int		result)
5637c478bd9Sstevel@tonic-gate {
5647c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L2(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
5657c478bd9Sstevel@tonic-gate 	    "ehci_decode_ddi_dma_addr_bind_handle_result:");
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	switch (result) {
5687c478bd9Sstevel@tonic-gate 	case DDI_DMA_PARTIAL_MAP:
5697c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl,
5707c478bd9Sstevel@tonic-gate 		    "Partial transfers not allowed");
5717c478bd9Sstevel@tonic-gate 		break;
5727c478bd9Sstevel@tonic-gate 	case DDI_DMA_INUSE:
5737c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
5747c478bd9Sstevel@tonic-gate 		    "Handle is in use");
5757c478bd9Sstevel@tonic-gate 		break;
5767c478bd9Sstevel@tonic-gate 	case DDI_DMA_NORESOURCES:
5777c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
5787c478bd9Sstevel@tonic-gate 		    "No resources");
5797c478bd9Sstevel@tonic-gate 		break;
5807c478bd9Sstevel@tonic-gate 	case DDI_DMA_NOMAPPING:
5817c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
5827c478bd9Sstevel@tonic-gate 		    "No mapping");
5837c478bd9Sstevel@tonic-gate 		break;
5847c478bd9Sstevel@tonic-gate 	case DDI_DMA_TOOBIG:
5857c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
5867c478bd9Sstevel@tonic-gate 		    "Object is too big");
5877c478bd9Sstevel@tonic-gate 		break;
5887c478bd9Sstevel@tonic-gate 	default:
5897c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL,	ehcip->ehci_log_hdl,
5907c478bd9Sstevel@tonic-gate 		    "Unknown dma error");
5917c478bd9Sstevel@tonic-gate 	}
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate /*
5967c478bd9Sstevel@tonic-gate  * ehci_map_regs:
5977c478bd9Sstevel@tonic-gate  *
5987c478bd9Sstevel@tonic-gate  * The Host Controller (HC) contains a set of on-chip operational registers
5997c478bd9Sstevel@tonic-gate  * and which should be mapped into a non-cacheable portion of the  system
6007c478bd9Sstevel@tonic-gate  * addressable space.
6017c478bd9Sstevel@tonic-gate  */
6027c478bd9Sstevel@tonic-gate int
ehci_map_regs(ehci_state_t * ehcip)6037c478bd9Sstevel@tonic-gate ehci_map_regs(ehci_state_t	*ehcip)
6047c478bd9Sstevel@tonic-gate {
6057c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t	attr;
6067c478bd9Sstevel@tonic-gate 	uint16_t		cmd_reg;
6077c478bd9Sstevel@tonic-gate 	uint_t			length;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_map_regs:");
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	/* Check to make sure we have memory access */
6127c478bd9Sstevel@tonic-gate 	if (pci_config_setup(ehcip->ehci_dip,
61329aca3ebSlc 	    &ehcip->ehci_config_handle) != DDI_SUCCESS) {
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6167c478bd9Sstevel@tonic-gate 		    "ehci_map_regs: Config error");
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6197c478bd9Sstevel@tonic-gate 	}
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	/* Make sure Memory Access Enable is set */
6227c478bd9Sstevel@tonic-gate 	cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM);
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	if (!(cmd_reg & PCI_COMM_MAE)) {
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6277c478bd9Sstevel@tonic-gate 		    "ehci_map_regs: Memory base address access disabled");
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6307c478bd9Sstevel@tonic-gate 	}
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	/* The host controller will be little endian */
6337c478bd9Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
6347c478bd9Sstevel@tonic-gate 	attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
6357c478bd9Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	/* Map in EHCI Capability registers */
6387c478bd9Sstevel@tonic-gate 	if (ddi_regs_map_setup(ehcip->ehci_dip, 1,
6397c478bd9Sstevel@tonic-gate 	    (caddr_t *)&ehcip->ehci_capsp, 0,
6407c478bd9Sstevel@tonic-gate 	    sizeof (ehci_caps_t), &attr,
6417c478bd9Sstevel@tonic-gate 	    &ehcip->ehci_caps_handle) != DDI_SUCCESS) {
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6447c478bd9Sstevel@tonic-gate 		    "ehci_map_regs: Map setup error");
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6477c478bd9Sstevel@tonic-gate 	}
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	length = ddi_get8(ehcip->ehci_caps_handle,
6507c478bd9Sstevel@tonic-gate 	    (uint8_t *)&ehcip->ehci_capsp->ehci_caps_length);
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	/* Free the original mapping */
6537c478bd9Sstevel@tonic-gate 	ddi_regs_map_free(&ehcip->ehci_caps_handle);
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	/* Re-map in EHCI Capability and Operational registers */
6567c478bd9Sstevel@tonic-gate 	if (ddi_regs_map_setup(ehcip->ehci_dip, 1,
6577c478bd9Sstevel@tonic-gate 	    (caddr_t *)&ehcip->ehci_capsp, 0,
6587c478bd9Sstevel@tonic-gate 	    length + sizeof (ehci_regs_t), &attr,
6597c478bd9Sstevel@tonic-gate 	    &ehcip->ehci_caps_handle) != DDI_SUCCESS) {
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6627c478bd9Sstevel@tonic-gate 		    "ehci_map_regs: Map setup error");
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	/* Get the pointer to EHCI Operational Register */
6687c478bd9Sstevel@tonic-gate 	ehcip->ehci_regsp = (ehci_regs_t *)
6697c478bd9Sstevel@tonic-gate 	    ((uintptr_t)ehcip->ehci_capsp + length);
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6727c478bd9Sstevel@tonic-gate 	    "ehci_map_regs: Capsp 0x%p Regsp 0x%p\n",
673112116d8Sfb 	    (void *)ehcip->ehci_capsp, (void *)ehcip->ehci_regsp);
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate 
67828cdc3d7Sszhou /*
67928cdc3d7Sszhou  * The following simulated polling is for debugging purposes only.
68028cdc3d7Sszhou  * It is activated on x86 by setting usb-polling=true in GRUB or ehci.conf.
68128cdc3d7Sszhou  */
68228cdc3d7Sszhou static int
ehci_is_polled(dev_info_t * dip)68328cdc3d7Sszhou ehci_is_polled(dev_info_t *dip)
68428cdc3d7Sszhou {
68528cdc3d7Sszhou 	int ret;
68628cdc3d7Sszhou 	char *propval;
68728cdc3d7Sszhou 
68828cdc3d7Sszhou 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
68928cdc3d7Sszhou 	    "usb-polling", &propval) != DDI_SUCCESS)
69028cdc3d7Sszhou 
69128cdc3d7Sszhou 		return (0);
69228cdc3d7Sszhou 
69328cdc3d7Sszhou 	ret = (strcmp(propval, "true") == 0);
69428cdc3d7Sszhou 	ddi_prop_free(propval);
69528cdc3d7Sszhou 
69628cdc3d7Sszhou 	return (ret);
69728cdc3d7Sszhou }
69828cdc3d7Sszhou 
69928cdc3d7Sszhou static void
ehci_poll_intr(void * arg)70028cdc3d7Sszhou ehci_poll_intr(void *arg)
70128cdc3d7Sszhou {
70228cdc3d7Sszhou 	/* poll every msec */
70328cdc3d7Sszhou 	for (;;) {
70428cdc3d7Sszhou 		(void) ehci_intr(arg, NULL);
70528cdc3d7Sszhou 		delay(drv_usectohz(1000));
70628cdc3d7Sszhou 	}
70728cdc3d7Sszhou }
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate /*
7107c478bd9Sstevel@tonic-gate  * ehci_register_intrs_and_init_mutex:
7117c478bd9Sstevel@tonic-gate  *
7127c478bd9Sstevel@tonic-gate  * Register interrupts and initialize each mutex and condition variables
7137c478bd9Sstevel@tonic-gate  */
7147c478bd9Sstevel@tonic-gate int
ehci_register_intrs_and_init_mutex(ehci_state_t * ehcip)7157c478bd9Sstevel@tonic-gate ehci_register_intrs_and_init_mutex(ehci_state_t	*ehcip)
7167c478bd9Sstevel@tonic-gate {
7179c75c6bfSgovinda 	int	intr_types;
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate #if defined(__x86)
7207c478bd9Sstevel@tonic-gate 	uint8_t iline;
7217c478bd9Sstevel@tonic-gate #endif
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7247c478bd9Sstevel@tonic-gate 	    "ehci_register_intrs_and_init_mutex:");
7257c478bd9Sstevel@tonic-gate 
7269c75c6bfSgovinda 	/*
7279c75c6bfSgovinda 	 * There is a known MSI hardware bug with the EHCI controller
7289c75c6bfSgovinda 	 * of ULI1575 southbridge. Hence MSI is disabled for this chip.
7299c75c6bfSgovinda 	 */
7309c75c6bfSgovinda 	if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
7319c75c6bfSgovinda 	    (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) {
7329c75c6bfSgovinda 		ehcip->ehci_msi_enabled = B_FALSE;
7339c75c6bfSgovinda 	} else {
7349c75c6bfSgovinda 		/* Set the MSI enable flag from the global EHCI MSI tunable */
7359c75c6bfSgovinda 		ehcip->ehci_msi_enabled = ehci_enable_msi;
7369c75c6bfSgovinda 	}
7379c75c6bfSgovinda 
73828cdc3d7Sszhou 	/* launch polling thread instead of enabling pci interrupt */
73928cdc3d7Sszhou 	if (ehci_is_polled(ehcip->ehci_dip)) {
74028cdc3d7Sszhou 		extern pri_t maxclsyspri;
74128cdc3d7Sszhou 
7428668df41Slg 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
74328cdc3d7Sszhou 		    "ehci_register_intrs_and_init_mutex: "
74428cdc3d7Sszhou 		    "running in simulated polled mode");
74528cdc3d7Sszhou 
74628cdc3d7Sszhou 		(void) thread_create(NULL, 0, ehci_poll_intr, ehcip, 0, &p0,
74728cdc3d7Sszhou 		    TS_RUN, maxclsyspri);
74828cdc3d7Sszhou 
74928cdc3d7Sszhou 		goto skip_intr;
75028cdc3d7Sszhou 	}
75128cdc3d7Sszhou 
7527c478bd9Sstevel@tonic-gate #if defined(__x86)
7537c478bd9Sstevel@tonic-gate 	/*
7547c478bd9Sstevel@tonic-gate 	 * Make sure that the interrupt pin is connected to the
7557c478bd9Sstevel@tonic-gate 	 * interrupt controller on x86.	 Interrupt line 255 means
7567c478bd9Sstevel@tonic-gate 	 * "unknown" or "not connected" (PCI spec 6.2.4, footnote 43).
7574610e4a0Sfrits 	 * If we would return failure when interrupt line equals 255, then
758f87a10b6Syq 	 * high speed devices will be routed to companion host controllers.
7594610e4a0Sfrits 	 * However, it is not necessary to return failure here, and
7604610e4a0Sfrits 	 * o/uhci codes don't check the interrupt line either.
7614610e4a0Sfrits 	 * But it's good to log a message here for debug purposes.
7627c478bd9Sstevel@tonic-gate 	 */
7637c478bd9Sstevel@tonic-gate 	iline = pci_config_get8(ehcip->ehci_config_handle,
7647c478bd9Sstevel@tonic-gate 	    PCI_CONF_ILINE);
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	if (iline == 255) {
7677c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7687c478bd9Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
7697c478bd9Sstevel@tonic-gate 		    "interrupt line value out of range (%d)",
7707c478bd9Sstevel@tonic-gate 		    iline);
7717c478bd9Sstevel@tonic-gate 	}
7727c478bd9Sstevel@tonic-gate #endif	/* __x86 */
7737c478bd9Sstevel@tonic-gate 
7749c75c6bfSgovinda 	/* Get supported interrupt types */
7759c75c6bfSgovinda 	if (ddi_intr_get_supported_types(ehcip->ehci_dip,
7769c75c6bfSgovinda 	    &intr_types) != DDI_SUCCESS) {
7777c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7787c478bd9Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
7799c75c6bfSgovinda 		    "ddi_intr_get_supported_types failed");
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7827c478bd9Sstevel@tonic-gate 	}
7837c478bd9Sstevel@tonic-gate 
7849c75c6bfSgovinda 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7859c75c6bfSgovinda 	    "ehci_register_intrs_and_init_mutex: "
7869c75c6bfSgovinda 	    "supported interrupt types 0x%x", intr_types);
7879c75c6bfSgovinda 
7889c75c6bfSgovinda 	if ((intr_types & DDI_INTR_TYPE_MSI) && ehcip->ehci_msi_enabled) {
7899c75c6bfSgovinda 		if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_MSI)
7909c75c6bfSgovinda 		    != DDI_SUCCESS) {
7919c75c6bfSgovinda 			USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7929c75c6bfSgovinda 			    "ehci_register_intrs_and_init_mutex: MSI "
7939c75c6bfSgovinda 			    "registration failed, trying FIXED interrupt \n");
7949c75c6bfSgovinda 		} else {
7959c75c6bfSgovinda 			USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7969c75c6bfSgovinda 			    "ehci_register_intrs_and_init_mutex: "
7979c75c6bfSgovinda 			    "Using MSI interrupt type\n");
7989c75c6bfSgovinda 
7999c75c6bfSgovinda 			ehcip->ehci_intr_type = DDI_INTR_TYPE_MSI;
8009c75c6bfSgovinda 			ehcip->ehci_flags |= EHCI_INTR;
8019c75c6bfSgovinda 		}
8029c75c6bfSgovinda 	}
8037c478bd9Sstevel@tonic-gate 
8049c75c6bfSgovinda 	if ((!(ehcip->ehci_flags & EHCI_INTR)) &&
8059c75c6bfSgovinda 	    (intr_types & DDI_INTR_TYPE_FIXED)) {
8069c75c6bfSgovinda 		if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_FIXED)
8079c75c6bfSgovinda 		    != DDI_SUCCESS) {
8089c75c6bfSgovinda 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8099c75c6bfSgovinda 			    "ehci_register_intrs_and_init_mutex: "
8109c75c6bfSgovinda 			    "FIXED interrupt registration failed\n");
8119c75c6bfSgovinda 
8129c75c6bfSgovinda 			return (DDI_FAILURE);
8139c75c6bfSgovinda 		}
8149c75c6bfSgovinda 
8159c75c6bfSgovinda 		USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8167c478bd9Sstevel@tonic-gate 		    "ehci_register_intrs_and_init_mutex: "
8179c75c6bfSgovinda 		    "Using FIXED interrupt type\n");
8189c75c6bfSgovinda 
8199c75c6bfSgovinda 		ehcip->ehci_intr_type = DDI_INTR_TYPE_FIXED;
8209c75c6bfSgovinda 		ehcip->ehci_flags |= EHCI_INTR;
8219c75c6bfSgovinda 	}
8229c75c6bfSgovinda 
82328cdc3d7Sszhou skip_intr:
8249c75c6bfSgovinda 	/* Create prototype for advance on async schedule */
8259c75c6bfSgovinda 	cv_init(&ehcip->ehci_async_schedule_advance_cv,
8269c75c6bfSgovinda 	    NULL, CV_DRIVER, NULL);
8279c75c6bfSgovinda 
8289c75c6bfSgovinda 	return (DDI_SUCCESS);
8299c75c6bfSgovinda }
8309c75c6bfSgovinda 
8319c75c6bfSgovinda 
8329c75c6bfSgovinda /*
8339c75c6bfSgovinda  * ehci_add_intrs:
8349c75c6bfSgovinda  *
8359c75c6bfSgovinda  * Register FIXED or MSI interrupts.
8369c75c6bfSgovinda  */
8379c75c6bfSgovinda static int
ehci_add_intrs(ehci_state_t * ehcip,int intr_type)8389a48f6c4SRobert Mustacchi ehci_add_intrs(ehci_state_t *ehcip, int intr_type)
8399c75c6bfSgovinda {
8409c75c6bfSgovinda 	int	actual, avail, intr_size, count = 0;
84129aca3ebSlc 	int	i, flag, ret;
8429c75c6bfSgovinda 
8439c75c6bfSgovinda 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8449c75c6bfSgovinda 	    "ehci_add_intrs: interrupt type 0x%x", intr_type);
8459c75c6bfSgovinda 
8469c75c6bfSgovinda 	/* Get number of interrupts */
8479c75c6bfSgovinda 	ret = ddi_intr_get_nintrs(ehcip->ehci_dip, intr_type, &count);
8489c75c6bfSgovinda 	if ((ret != DDI_SUCCESS) || (count == 0)) {
8499c75c6bfSgovinda 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8509c75c6bfSgovinda 		    "ehci_add_intrs: ddi_intr_get_nintrs() failure, "
8519c75c6bfSgovinda 		    "ret: %d, count: %d", ret, count);
8529c75c6bfSgovinda 
8539c75c6bfSgovinda 		return (DDI_FAILURE);
8549c75c6bfSgovinda 	}
8559c75c6bfSgovinda 
8569c75c6bfSgovinda 	/* Get number of available interrupts */
8579c75c6bfSgovinda 	ret = ddi_intr_get_navail(ehcip->ehci_dip, intr_type, &avail);
8589c75c6bfSgovinda 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
8599c75c6bfSgovinda 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8609c75c6bfSgovinda 		    "ehci_add_intrs: ddi_intr_get_navail() failure, "
8619c75c6bfSgovinda 		    "ret: %d, count: %d", ret, count);
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8647c478bd9Sstevel@tonic-gate 	}
8657c478bd9Sstevel@tonic-gate 
8669c75c6bfSgovinda 	if (avail < count) {
8679c75c6bfSgovinda 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8689c75c6bfSgovinda 		    "ehci_add_intrs: ehci_add_intrs: nintrs () "
8699c75c6bfSgovinda 		    "returned %d, navail returned %d\n", count, avail);
8709c75c6bfSgovinda 	}
8719c75c6bfSgovinda 
8729c75c6bfSgovinda 	/* Allocate an array of interrupt handles */
8739c75c6bfSgovinda 	intr_size = count * sizeof (ddi_intr_handle_t);
8749c75c6bfSgovinda 	ehcip->ehci_htable = kmem_zalloc(intr_size, KM_SLEEP);
8759c75c6bfSgovinda 
8769c75c6bfSgovinda 	flag = (intr_type == DDI_INTR_TYPE_MSI) ?
8779c75c6bfSgovinda 	    DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL;
8789c75c6bfSgovinda 
8799c75c6bfSgovinda 	/* call ddi_intr_alloc() */
8807c478bd9Sstevel@tonic-gate 	ret = ddi_intr_alloc(ehcip->ehci_dip, ehcip->ehci_htable,
8819c75c6bfSgovinda 	    intr_type, 0, count, &actual, flag);
8827c478bd9Sstevel@tonic-gate 
8839c75c6bfSgovinda 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
8847c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8859c75c6bfSgovinda 		    "ehci_add_intrs: ddi_intr_alloc() failed %d", ret);
8867c478bd9Sstevel@tonic-gate 
8879c75c6bfSgovinda 		kmem_free(ehcip->ehci_htable, intr_size);
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8907c478bd9Sstevel@tonic-gate 	}
8917c478bd9Sstevel@tonic-gate 
8929c75c6bfSgovinda 	if (actual < count) {
8939c75c6bfSgovinda 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
8949c75c6bfSgovinda 		    "ehci_add_intrs: Requested: %d, Received: %d\n",
8959c75c6bfSgovinda 		    count, actual);
8969c75c6bfSgovinda 
8979c75c6bfSgovinda 		for (i = 0; i < actual; i++)
8989c75c6bfSgovinda 			(void) ddi_intr_free(ehcip->ehci_htable[i]);
8999c75c6bfSgovinda 
9009c75c6bfSgovinda 		kmem_free(ehcip->ehci_htable, intr_size);
9019c75c6bfSgovinda 
9029c75c6bfSgovinda 		return (