17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
502acac7sl * Common Development and Distribution License (the "License").
602acac7sl * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
217c478bdstevel@tonic-gate/*
22269552cguoqing zhu - Sun Microsystems - Beijing China * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bdstevel@tonic-gate * Use is subject to license terms.
247c478bdstevel@tonic-gate */
257c478bdstevel@tonic-gate
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate/*
287c478bdstevel@tonic-gate * Open Host Controller Driver (OHCI)
297c478bdstevel@tonic-gate *
307c478bdstevel@tonic-gate * The USB Open Host Controller driver is a software driver which interfaces
317c478bdstevel@tonic-gate * to the Universal Serial Bus layer (USBA) and the USB Open Host Controller.
3229aca3elc * The interface to USB Open Host Controller is defined by the OpenHCI	Host
337c478bdstevel@tonic-gate * Controller Interface.
347c478bdstevel@tonic-gate *
357c478bdstevel@tonic-gate * NOTE:
367c478bdstevel@tonic-gate *
377c478bdstevel@tonic-gate * Currently OHCI driver does not support the following features
387c478bdstevel@tonic-gate *
397c478bdstevel@tonic-gate * - Handle request with multiple TDs under short xfer conditions except for
407c478bdstevel@tonic-gate *   bulk transfers.
417c478bdstevel@tonic-gate */
427c478bdstevel@tonic-gate#include <sys/usb/hcd/openhci/ohcid.h>
437c478bdstevel@tonic-gate
4402acac7sl#include <sys/disp.h>
45d29f5a7zhigang lu - Sun Microsystems - Beijing China#include <sys/strsun.h>
4602acac7sl
477c478bdstevel@tonic-gate/* Pointer to the state structure */
487c478bdstevel@tonic-gatestatic void *ohci_statep;
497c478bdstevel@tonic-gate
502df1fe9randyfint force_ohci_off = 1;
512df1fe9randyf
527c478bdstevel@tonic-gate/* Number of instances */
537c478bdstevel@tonic-gate#define	OHCI_INSTS	1
547c478bdstevel@tonic-gate
557c478bdstevel@tonic-gate/* Adjustable variables for the size of the pools */
564610e4afritsint ohci_ed_pool_size = OHCI_ED_POOL_SIZE;
574610e4afritsint ohci_td_pool_size = OHCI_TD_POOL_SIZE;
587c478bdstevel@tonic-gate
597c478bdstevel@tonic-gate/*
607c478bdstevel@tonic-gate * Initialize the values which are used for setting up head pointers for
617c478bdstevel@tonic-gate * the 32ms scheduling lists which starts from the HCCA.
627c478bdstevel@tonic-gate */
637c478bdstevel@tonic-gatestatic uchar_t ohci_index[NUM_INTR_ED_LISTS / 2] = {0x0, 0x8, 0x4, 0xc,
647c478bdstevel@tonic-gate						0x2, 0xa, 0x6, 0xe,
657c478bdstevel@tonic-gate						0x1, 0x9, 0x5, 0xd,
667c478bdstevel@tonic-gate						0x3, 0xb, 0x7, 0xf};
677c478bdstevel@tonic-gate/* Debugging information */
687c478bdstevel@tonic-gateuint_t ohci_errmask	= (uint_t)PRINT_MASK_ALL;
697c478bdstevel@tonic-gateuint_t ohci_errlevel	= USB_LOG_L2;
707c478bdstevel@tonic-gateuint_t ohci_instance_debug = (uint_t)-1;
717c478bdstevel@tonic-gate
727c478bdstevel@tonic-gate/*
739c75c6bgovinda * OHCI MSI tunable:
749c75c6bgovinda *
759c75c6bgovinda * By default MSI is enabled on all supported platforms.
769c75c6bgovinda */
779c75c6bgovindaboolean_t ohci_enable_msi = B_TRUE;
789c75c6bgovinda
799c75c6bgovinda/*
807c478bdstevel@tonic-gate * HCDI entry points
817c478bdstevel@tonic-gate *
827c478bdstevel@tonic-gate * The Host Controller Driver Interfaces (HCDI) are the software interfaces
837c478bdstevel@tonic-gate * between the Universal Serial Bus Driver (USBA) and the Host	Controller
847c478bdstevel@tonic-gate * Driver (HCD). The HCDI interfaces or entry points are subject to change.
857c478bdstevel@tonic-gate */
867c478bdstevel@tonic-gatestatic int	ohci_hcdi_pipe_open(
877c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
887c478bdstevel@tonic-gate				usb_flags_t		usb_flags);
897c478bdstevel@tonic-gatestatic int	ohci_hcdi_pipe_close(
907c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
917c478bdstevel@tonic-gate				usb_flags_t		usb_flags);
927c478bdstevel@tonic-gatestatic int	ohci_hcdi_pipe_reset(
937c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
947c478bdstevel@tonic-gate				usb_flags_t		usb_flags);
95269552cguoqing zhu - Sun Microsystems - Beijing Chinastatic void	ohci_hcdi_pipe_reset_data_toggle(
96269552cguoqing zhu - Sun Microsystems - Beijing China				usba_pipe_handle_data_t	*ph);
977c478bdstevel@tonic-gatestatic int	ohci_hcdi_pipe_ctrl_xfer(
987c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
997c478bdstevel@tonic-gate				usb_ctrl_req_t		*ctrl_reqp,
1007c478bdstevel@tonic-gate				usb_flags_t		usb_flags);
1017c478bdstevel@tonic-gatestatic int	ohci_hcdi_bulk_transfer_size(
1027c478bdstevel@tonic-gate				usba_device_t		*usba_device,
1037c478bdstevel@tonic-gate				size_t			*size);
1047c478bdstevel@tonic-gatestatic int	ohci_hcdi_pipe_bulk_xfer(
1057c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
1067c478bdstevel@tonic-gate				usb_bulk_req_t		*bulk_reqp,
1077c478bdstevel@tonic-gate				usb_flags_t		usb_flags);
1087c478bdstevel@tonic-gatestatic int	ohci_hcdi_pipe_intr_xfer(
1097c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
1107c478bdstevel@tonic-gate				usb_intr_req_t		*intr_req,
1117c478bdstevel@tonic-gate				usb_flags_t		usb_flags);
1127c478bdstevel@tonic-gatestatic int	ohci_hcdi_pipe_stop_intr_polling(
1137c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
1147c478bdstevel@tonic-gate				usb_flags_t		usb_flags);
115fffe0b3qzstatic int	ohci_hcdi_get_current_frame_number(
116fffe0b3qz				usba_device_t		*usba_device,
117fffe0b3qz				usb_frame_number_t	*frame_number);
118fffe0b3qzstatic int	ohci_hcdi_get_max_isoc_pkts(
119fffe0b3qz				usba_device_t		*usba_device,
120fffe0b3qz				uint_t		*max_isoc_pkts_per_request);
1217c478bdstevel@tonic-gatestatic int	ohci_hcdi_pipe_isoc_xfer(
1227c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
1237c478bdstevel@tonic-gate				usb_isoc_req_t		*isoc_reqp,
1247c478bdstevel@tonic-gate				usb_flags_t		usb_flags);
1257c478bdstevel@tonic-gatestatic int	ohci_hcdi_pipe_stop_isoc_polling(
1267c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
1277c478bdstevel@tonic-gate				usb_flags_t		usb_flags);
1287c478bdstevel@tonic-gate
1297c478bdstevel@tonic-gate/*
1307c478bdstevel@tonic-gate * Internal Function Prototypes
1317c478bdstevel@tonic-gate */
1327c478bdstevel@tonic-gate
1337c478bdstevel@tonic-gate/* Host Controller Driver (HCD) initialization functions */
1347c478bdstevel@tonic-gatestatic void	ohci_set_dma_attributes(ohci_state_t	*ohcip);
1357c478bdstevel@tonic-gatestatic int	ohci_allocate_pools(ohci_state_t	*ohcip);
1367c478bdstevel@tonic-gatestatic void	ohci_decode_ddi_dma_addr_bind_handle_result(
1377c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
1387c478bdstevel@tonic-gate				int			result);
1397c478bdstevel@tonic-gatestatic int	ohci_map_regs(ohci_state_t		*ohcip);
1407c478bdstevel@tonic-gatestatic int	ohci_register_intrs_and_init_mutex(
1417c478bdstevel@tonic-gate				ohci_state_t		*ohcip);
1429c75c6bgovindastatic int	ohci_add_intrs(ohci_state_t		*ohcip,
1439c75c6bgovinda				int			intr_type);
1447c478bdstevel@tonic-gatestatic int	ohci_init_ctlr(ohci_state_t		*ohcip);
1457c478bdstevel@tonic-gatestatic int	ohci_init_hcca(ohci_state_t		*ohcip);
1467c478bdstevel@tonic-gatestatic void	ohci_build_interrupt_lattice(
1477c478bdstevel@tonic-gate				ohci_state_t		*ohcip);
1487c478bdstevel@tonic-gatestatic int	ohci_take_control(ohci_state_t		*ohcip);
1497c478bdstevel@tonic-gatestatic usba_hcdi_ops_t *ohci_alloc_hcdi_ops(
1507c478bdstevel@tonic-gate				ohci_state_t		*ohcip);
1517c478bdstevel@tonic-gate
1527c478bdstevel@tonic-gate/* Host Controller Driver (HCD) deinitialization functions */
1537c478bdstevel@tonic-gatestatic int	ohci_cleanup(ohci_state_t		*ohcip);
1549c75c6bgovindastatic void	ohci_rem_intrs(ohci_state_t		*ohcip);
1557c478bdstevel@tonic-gatestatic int	ohci_cpr_suspend(ohci_state_t		*ohcip);
1567c478bdstevel@tonic-gatestatic int	ohci_cpr_resume(ohci_state_t		*ohcip);
1577c478bdstevel@tonic-gate
1587c478bdstevel@tonic-gate/* Bandwidth Allocation functions */
1597c478bdstevel@tonic-gatestatic int	ohci_allocate_bandwidth(ohci_state_t	*ohcip,
1607c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
1617c478bdstevel@tonic-gate				uint_t			*node);
1627c478bdstevel@tonic-gatestatic void	ohci_deallocate_bandwidth(ohci_state_t	*ohcip,
1637c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph);
1647c478bdstevel@tonic-gatestatic int	ohci_compute_total_bandwidth(
1657c478bdstevel@tonic-gate				usb_ep_descr_t		*endpoint,
1667c478bdstevel@tonic-gate				usb_port_status_t	port_status,
1677c478bdstevel@tonic-gate				uint_t			*bandwidth);
1687c478bdstevel@tonic-gatestatic int	ohci_adjust_polling_interval(
1697c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
1707c478bdstevel@tonic-gate				usb_ep_descr_t		*endpoint,
1717c478bdstevel@tonic-gate				usb_port_status_t	port_status);
1727c478bdstevel@tonic-gatestatic uint_t	ohci_lattice_height(uint_t		interval);
1737c478bdstevel@tonic-gatestatic uint_t	ohci_lattice_parent(uint_t		node);
1747c478bdstevel@tonic-gatestatic uint_t	ohci_leftmost_leaf(uint_t		node,
1757c478bdstevel@tonic-gate				uint_t			height);
1767c478bdstevel@tonic-gatestatic uint_t	ohci_hcca_intr_index(
1777c478bdstevel@tonic-gate				uint_t			node);
1787c478bdstevel@tonic-gatestatic uint_t	ohci_hcca_leaf_index(
1797c478bdstevel@tonic-gate				uint_t			leaf);
1807c478bdstevel@tonic-gatestatic uint_t	ohci_pow_2(uint_t x);
1817c478bdstevel@tonic-gatestatic uint_t	ohci_log_2(uint_t x);
1827c478bdstevel@tonic-gate
1837c478bdstevel@tonic-gate/* Endpoint Descriptor (ED) related functions */
1847c478bdstevel@tonic-gatestatic uint_t	ohci_unpack_endpoint(ohci_state_t	*ohcip,
1857c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph);
1867c478bdstevel@tonic-gatestatic void	ohci_insert_ed(ohci_state_t		*ohcip,
1877c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph);
1887c478bdstevel@tonic-gatestatic void	ohci_insert_ctrl_ed(
1897c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
1907c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp);
1917c478bdstevel@tonic-gatestatic void	ohci_insert_bulk_ed(
1927c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
1937c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp);
1947c478bdstevel@tonic-gatestatic void	ohci_insert_intr_ed(
1957c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
1967c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp);
1977c478bdstevel@tonic-gatestatic void	ohci_insert_isoc_ed(
1987c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
1997c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp);
2007c478bdstevel@tonic-gatestatic void	ohci_modify_sKip_bit(ohci_state_t	*ohcip,
2017c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
2027c478bdstevel@tonic-gate				skip_bit_t		action,
2037c478bdstevel@tonic-gate				usb_flags_t		flag);
2047c478bdstevel@tonic-gatestatic void	ohci_remove_ed(ohci_state_t		*ohcip,
2057c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp);
2067c478bdstevel@tonic-gatestatic void	ohci_remove_ctrl_ed(
2077c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
2087c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp);
2097c478bdstevel@tonic-gatestatic void	ohci_remove_bulk_ed(
2107c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
2117c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp);
2127c478bdstevel@tonic-gatestatic void	ohci_remove_periodic_ed(
2137c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
2147c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp);
2157c478bdstevel@tonic-gatestatic void	ohci_insert_ed_on_reclaim_list(
2167c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
2177c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp);
2187c478bdstevel@tonic-gatestatic void	ohci_detach_ed_from_list(
2197c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
2207c478bdstevel@tonic-gate				ohci_ed_t		*ept,
2217c478bdstevel@tonic-gate				uint_t			ept_type);
2227c478bdstevel@tonic-gatestatic ohci_ed_t *ohci_ed_iommu_to_cpu(
2237c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
2247c478bdstevel@tonic-gate				uintptr_t		addr);
2257c478bdstevel@tonic-gate
2267c478bdstevel@tonic-gate/* Transfer Descriptor (TD) related functions */
2277c478bdstevel@tonic-gatestatic int	ohci_initialize_dummy(ohci_state_t	*ohcip,
2287c478bdstevel@tonic-gate				ohci_ed_t		*ept);
2297c478bdstevel@tonic-gatestatic ohci_trans_wrapper_t *ohci_allocate_ctrl_resources(
2307c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
2317c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
2327c478bdstevel@tonic-gate				usb_ctrl_req_t		*ctrl_reqp,
2337c478bdstevel@tonic-gate				usb_flags_t		usb_flags);
2347c478bdstevel@tonic-gatestatic void	ohci_insert_ctrl_req(
2357c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
2367c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
2377c478bdstevel@tonic-gate				usb_ctrl_req_t		*ctrl_reqp,
2387c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
2397c478bdstevel@tonic-gate				usb_flags_t		usb_flags);
2407c478bdstevel@tonic-gatestatic ohci_trans_wrapper_t *ohci_allocate_bulk_resources(
2417c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
2427c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
2437c478bdstevel@tonic-gate				usb_bulk_req_t		*bulk_reqp,
2447c478bdstevel@tonic-gate				usb_flags_t		usb_flags);
2457c478bdstevel@tonic-gatestatic void	ohci_insert_bulk_req(ohci_state_t	*ohcip,
2467c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
2477c478bdstevel@tonic-gate				usb_bulk_req_t		*bulk_reqp,
2487c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
2497c478bdstevel@tonic-gate				usb_flags_t		flags);
2507c478bdstevel@tonic-gatestatic int	ohci_start_pipe_polling(ohci_state_t	*ohcip,
2517c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
2527c478bdstevel@tonic-gate				usb_flags_t		flags);
2537c478bdstevel@tonic-gatestatic void	ohci_set_periodic_pipe_polling(
2547c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
2557c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph);
2567c478bdstevel@tonic-gatestatic ohci_trans_wrapper_t *ohci_allocate_intr_resources(
2577c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
2587c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
2597c478bdstevel@tonic-gate				usb_intr_req_t		*intr_reqp,
2607c478bdstevel@tonic-gate				usb_flags_t		usb_flags);
2617c478bdstevel@tonic-gatestatic void	ohci_insert_intr_req(ohci_state_t	*ohcip,
2627c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
2637c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
2647c478bdstevel@tonic-gate				usb_flags_t		flags);
2657c478bdstevel@tonic-gatestatic int	ohci_stop_periodic_pipe_polling(
2667c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
2677c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
2687c478bdstevel@tonic-gate				usb_flags_t		flags);
2697c478bdstevel@tonic-gatestatic ohci_trans_wrapper_t *ohci_allocate_isoc_resources(
2707c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
2717c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
2727c478bdstevel@tonic-gate				usb_isoc_req_t		*isoc_reqp,
2737c478bdstevel@tonic-gate				usb_flags_t		usb_flags);
2747c478bdstevel@tonic-gatestatic int	ohci_insert_isoc_req(ohci_state_t	*ohcip,
2757c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
2767c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
2777c478bdstevel@tonic-gate				uint_t			flags);
27802acac7slstatic int	ohci_insert_hc_td(ohci_state_t		*ohcip,
2797c478bdstevel@tonic-gate				uint_t			hctd_ctrl,
28002acac7sl				uint32_t		hctd_dma_offs,
2817c478bdstevel@tonic-gate				size_t			hctd_length,
2827c478bdstevel@tonic-gate				uint32_t		hctd_ctrl_phase,
2837c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
2847c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw);
2857c478bdstevel@tonic-gatestatic ohci_td_t *ohci_allocate_td_from_pool(
2867c478bdstevel@tonic-gate				ohci_state_t		*ohcip);
2877c478bdstevel@tonic-gatestatic void	ohci_fill_in_td(ohci_state_t		*ohcip,
2887c478bdstevel@tonic-gate				ohci_td_t		*td,
2897c478bdstevel@tonic-gate				ohci_td_t		*new_dummy,
2907c478bdstevel@tonic-gate				uint_t			hctd_ctrl,
29102acac7sl				uint32_t		hctd_dma_offs,
2927c478bdstevel@tonic-gate				size_t			hctd_length,
2937c478bdstevel@tonic-gate				uint32_t		hctd_ctrl_phase,
2947c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
2957c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw);
2967c478bdstevel@tonic-gatestatic void	ohci_init_itd(
2977c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
2987c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
2997c478bdstevel@tonic-gate				uint_t			hctd_ctrl,
30002acac7sl				uint32_t		index,
3017c478bdstevel@tonic-gate				ohci_td_t		*td);
3027c478bdstevel@tonic-gatestatic int	ohci_insert_td_with_frame_number(
3037c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
3047c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
3057c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
3067c478bdstevel@tonic-gate				ohci_td_t		*current_td,
3077c478bdstevel@tonic-gate				ohci_td_t		*dummy_td);
3087c478bdstevel@tonic-gatestatic void	ohci_insert_td_on_tw(ohci_state_t	*ohcip,
3097c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
3107c478bdstevel@tonic-gate				ohci_td_t		*td);
3113e1e1e6Toomas Soomestatic void	ohci_done_list_tds(ohci_state_t		*ohcip,
3127c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph);
3137c478bdstevel@tonic-gate
3147c478bdstevel@tonic-gate/* Transfer Wrapper (TW) functions */
3157c478bdstevel@tonic-gatestatic ohci_trans_wrapper_t  *ohci_create_transfer_wrapper(
3167c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
3177c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
3187c478bdstevel@tonic-gate				size_t			length,
3197c478bdstevel@tonic-gate				uint_t			usb_flags);
32002acac7slstatic ohci_trans_wrapper_t  *ohci_create_isoc_transfer_wrapper(
32102acac7sl				ohci_state_t		*ohcip,
32202acac7sl				ohci_pipe_private_t	*pp,
32302acac7sl				size_t			length,
32402acac7sl				usb_isoc_pkt_descr_t	*descr,
32502acac7sl				ushort_t		pkt_count,
32629aca3elc				size_t			td_count,
32702acac7sl				uint_t			usb_flags);
3289b58c2azhigang lu - Sun Microsystems - Beijing Chinaint	ohci_allocate_tds_for_tw(
3297c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
3307c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
3317c478bdstevel@tonic-gate				size_t			td_count);
3327c478bdstevel@tonic-gatestatic ohci_trans_wrapper_t  *ohci_allocate_tw_resources(
3337c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
3347c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
3357c478bdstevel@tonic-gate				size_t			length,
3367c478bdstevel@tonic-gate				usb_flags_t		usb_flags,
3377c478bdstevel@tonic-gate				size_t			td_count);
3387c478bdstevel@tonic-gatestatic void	ohci_free_tw_tds_resources(
3397c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
3407c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw);
3417c478bdstevel@tonic-gatestatic void	ohci_start_xfer_timer(
3427c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
3437c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
3447c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw);
3457c478bdstevel@tonic-gatestatic void	ohci_stop_xfer_timer(
3467c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
3477c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
3487c478bdstevel@tonic-gate				uint_t			flag);
3497c478bdstevel@tonic-gatestatic void	ohci_xfer_timeout_handler(void		*arg);
3507c478bdstevel@tonic-gatestatic void	ohci_remove_tw_from_timeout_list(
3517c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
3527c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw);
3537c478bdstevel@tonic-gatestatic void	ohci_start_timer(ohci_state_t		*ohcip);
3547c478bdstevel@tonic-gatestatic void	ohci_free_dma_resources(ohci_state_t	*ohcip,
3557c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph);
3567c478bdstevel@tonic-gatestatic void	ohci_free_tw(ohci_state_t		*ohcip,
3577c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw);
35802acac7slstatic int	ohci_tw_rebind_cookie(
35902acac7sl				ohci_state_t		*ohcip,
36002acac7sl				ohci_pipe_private_t	*pp,
36102acac7sl				ohci_trans_wrapper_t	*tw);
3627c478bdstevel@tonic-gate
3637c478bdstevel@tonic-gate/* Interrupt Handling functions */
3649c75c6bgovindastatic uint_t	ohci_intr(caddr_t			arg1,
3659c75c6bgovinda				caddr_t			arg2);
3667c478bdstevel@tonic-gatestatic void	ohci_handle_missed_intr(
3677c478bdstevel@tonic-gate				ohci_state_t		*ohcip);
3687c478bdstevel@tonic-gatestatic void	ohci_handle_ue(ohci_state_t		*ohcip);
3697c478bdstevel@tonic-gatestatic void	ohci_handle_endpoint_reclaimation(
3707c478bdstevel@tonic-gate				ohci_state_t		*ohcip);
3717c478bdstevel@tonic-gatestatic void	ohci_traverse_done_list(
3727c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
3737c478bdstevel@tonic-gate				ohci_td_t		*head_done_list);
3747c478bdstevel@tonic-gatestatic ohci_td_t *ohci_reverse_done_list(
3757c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
3767c478bdstevel@tonic-gate				ohci_td_t		*head_done_list);
3777c478bdstevel@tonic-gatestatic usb_cr_t	ohci_parse_error(ohci_state_t		*ohcip,
3787c478bdstevel@tonic-gate				ohci_td_t		*td);
3797c478bdstevel@tonic-gatestatic void	ohci_parse_isoc_error(
3807c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
3817c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
3827c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
3837c478bdstevel@tonic-gate				ohci_td_t		*td);
3847c478bdstevel@tonic-gatestatic usb_cr_t ohci_check_for_error(
3857c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
3867c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
3877c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
3887c478bdstevel@tonic-gate				ohci_td_t		*td,
3897c478bdstevel@tonic-gate				uint_t			ctrl);
3907c478bdstevel@tonic-gatestatic void	ohci_handle_error(
3917c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
3927c478bdstevel@tonic-gate				ohci_td_t		*td,
3937c478bdstevel@tonic-gate				usb_cr_t		error);
3947c478bdstevel@tonic-gatestatic int	ohci_cleanup_data_underrun(
3957c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
3967c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
3977c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
3987c478bdstevel@tonic-gate				ohci_td_t		*td);
3997c478bdstevel@tonic-gatestatic void	ohci_handle_normal_td(
4007c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
4017c478bdstevel@tonic-gate				ohci_td_t		*td,
4027c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw);
4037c478bdstevel@tonic-gatestatic void	ohci_handle_ctrl_td(ohci_state_t	*ohcip,
4047c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
4057c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
4067c478bdstevel@tonic-gate				ohci_td_t		*td,
4077c478bdstevel@tonic-gate				void			*);
4087c478bdstevel@tonic-gatestatic void	ohci_handle_bulk_td(ohci_state_t	*ohcip,
4097c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
4107c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
4117c478bdstevel@tonic-gate				ohci_td_t		*td,
4127c478bdstevel@tonic-gate				void			*);
4137c478bdstevel@tonic-gatestatic void	ohci_handle_intr_td(ohci_state_t	*ohcip,
4147c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
4157c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
4167c478bdstevel@tonic-gate				ohci_td_t		*td,
4177c478bdstevel@tonic-gate				void			*);
4187c478bdstevel@tonic-gatestatic void	ohci_handle_one_xfer_completion(
4197c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
4207c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw);
4217c478bdstevel@tonic-gatestatic void	ohci_handle_isoc_td(ohci_state_t	*ohcip,
4227c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
4237c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
4247c478bdstevel@tonic-gate				ohci_td_t		*td,
4257c478bdstevel@tonic-gate				void			*);
4267c478bdstevel@tonic-gatestatic void	ohci_sendup_td_message(
4277c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
4287c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
4297c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
4307c478bdstevel@tonic-gate				ohci_td_t		*td,
4317c478bdstevel@tonic-gate				usb_cr_t		error);
432688b07cgcstatic int	ohci_check_done_head(
433688b07cgc				ohci_state_t *ohcip,
434688b07cgc				ohci_td_t		*done_head);
4357c478bdstevel@tonic-gate
4367c478bdstevel@tonic-gate/* Miscillaneous functions */
4377c478bdstevel@tonic-gatestatic void	ohci_cpr_cleanup(
4387c478bdstevel@tonic-gate				ohci_state_t		*ohcip);
4397c478bdstevel@tonic-gatestatic usb_req_attrs_t ohci_get_xfer_attrs(ohci_state_t *ohcip,
4407c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
4417c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw);
4427c478bdstevel@tonic-gatestatic int	ohci_allocate_periodic_in_resource(
4437c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
4447c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
4457c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
4467c478bdstevel@tonic-gate				usb_flags_t		flags);
4477c478bdstevel@tonic-gatestatic int	ohci_wait_for_sof(
4487c478bdstevel@tonic-gate				ohci_state_t		*ohcip);
4497c478bdstevel@tonic-gatestatic void	ohci_pipe_cleanup(
4507c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
4517c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph);
4527c478bdstevel@tonic-gatestatic void	ohci_wait_for_transfers_completion(
4537c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
4547c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp);
4557c478bdstevel@tonic-gatestatic void	ohci_check_for_transfers_completion(
4567c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
4577c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp);
4587c478bdstevel@tonic-gatestatic void	ohci_save_data_toggle(ohci_state_t	*ohcip,
4597c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph);
4607c478bdstevel@tonic-gatestatic void	ohci_restore_data_toggle(ohci_state_t	*ohcip,
4617c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph);
4627c478bdstevel@tonic-gatestatic void	ohci_deallocate_periodic_in_resource(
4637c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
4647c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
4657c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw);
4667c478bdstevel@tonic-gatestatic void	ohci_do_client_periodic_in_req_callback(
4677c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
4687c478bdstevel@tonic-gate				ohci_pipe_private_t	*pp,
4697c478bdstevel@tonic-gate				usb_cr_t		completion_reason);
4707c478bdstevel@tonic-gatestatic void	ohci_hcdi_callback(
4717c478bdstevel@tonic-gate				usba_pipe_handle_data_t	*ph,
4727c478bdstevel@tonic-gate				ohci_trans_wrapper_t	*tw,
4737c478bdstevel@tonic-gate				usb_cr_t		completion_reason);
4747c478bdstevel@tonic-gate
4757c478bdstevel@tonic-gate/* Kstat Support */
4767c478bdstevel@tonic-gatestatic void	ohci_create_stats(ohci_state_t		*ohcip);
4773e1e1e6Toomas Soomestatic void	ohci_destroy_stats(ohci_state_t		*ohcip);
4787c478bdstevel@tonic-gatestatic void	ohci_do_byte_stats(
4797c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
4807c478bdstevel@tonic-gate				size_t			len,
4813e1e1e6Toomas Soome				uint8_t			attr,
4823e1e1e6Toomas Soome				uint8_t			addr);
4837c478bdstevel@tonic-gatestatic void	ohci_do_intrs_stats(
4847c478bdstevel@tonic-gate				ohci_state_t		*ohcip,
4857c478bdstevel@tonic-gate				int			val);
4863e1e1e6Toomas Soomestatic void	ohci_print_op_regs(ohci_state_t		*ohcip);
4877c478bdstevel@tonic-gatestatic void	ohci_print_ed(ohci_state_t		*ohcip,
4887c478bdstevel@tonic-gate				ohci_ed_t		*ed);
4897c478bdstevel@tonic-gatestatic void	ohci_print_td(ohci_state_t		*ohcip,
4907c478bdstevel@tonic-gate				ohci_td_t		*td);
4917c478bdstevel@tonic-gate
4927c478bdstevel@tonic-gate/* extern */
4937c478bdstevel@tonic-gateint usba_hubdi_root_hub_power(dev_info_t *dip, int comp, int level);
4947c478bdstevel@tonic-gate
4957c478bdstevel@tonic-gate/*
4967c478bdstevel@tonic-gate * Device operations (dev_ops) entries function prototypes.
4977c478bdstevel@tonic-gate *
4987c478bdstevel@tonic-gate * We use the hub cbops since all nexus ioctl operations defined so far will
4997c478bdstevel@tonic-gate * be executed by the root hub. The following are the Host Controller Driver
5007c478bdstevel@tonic-gate * (HCD) entry points.
5017c478bdstevel@tonic-gate *
5027c478bdstevel@tonic-gate * the open/close/ioctl functions call the corresponding usba_hubdi_*
5037c478bdstevel@tonic-gate * calls after looking up the dip thru the dev_t.
5047c478bdstevel@tonic-gate */
5057c478bdstevel@tonic-gatestatic int	ohci_open(dev_t	*devp, int flags, int otyp, cred_t *credp);
5067c478bdstevel@tonic-gatestatic int	ohci_close(dev_t dev, int flag, int otyp, cred_t *credp);
5077c478bdstevel@tonic-gatestatic int	ohci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
5087c478bdstevel@tonic-gate				cred_t *credp, int *rvalp);
5097c478bdstevel@tonic-gate
5107c478bdstevel@tonic-gatestatic int	ohci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
5117c478bdstevel@tonic-gatestatic int	ohci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
5121939740Sherry Moorestatic int	ohci_quiesce(dev_info_t *dip);
5131939740Sherry Moore
5147c478bdstevel@tonic-gatestatic int	ohci_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
5157c478bdstevel@tonic-gate				void *arg, void **result);
5167c478bdstevel@tonic-gate
5177c478bdstevel@tonic-gatestatic struct cb_ops ohci_cb_ops = {
5187c478bdstevel@tonic-gate	ohci_open,			/* Open */
5197c478bdstevel@tonic-gate	ohci_close,			/* Close */
5207c478bdstevel@tonic-gate	nodev,				/* Strategy */
5217c478bdstevel@tonic-gate	nodev,				/* Print */
5227c478bdstevel@tonic-gate	nodev,				/* Dump */
5237c478bdstevel@tonic-gate	nodev,				/* Read */
5247c478bdstevel@tonic-gate	nodev,				/* Write */
5257c478bdstevel@tonic-gate	ohci_ioctl,			/* Ioctl */
5267c478bdstevel@tonic-gate	nodev,				/* Devmap */
5277c478bdstevel@tonic-gate	nodev,				/* Mmap */
5287c478bdstevel@tonic-gate	nodev,				/* Segmap */
5297c478bdstevel@tonic-gate	nochpoll,			/* Poll */
5307c478bdstevel@tonic-gate	ddi_prop_op,			/* cb_prop_op */
5317c478bdstevel@tonic-gate	NULL,				/* Streamtab */
5327c478bdstevel@tonic-gate	D_MP				/* Driver compatibility flag */
5337c478bdstevel@tonic-gate};
5347c478bdstevel@tonic-gate
5357c478bdstevel@tonic-gatestatic struct dev_ops ohci_ops = {
5367c478bdstevel@tonic-gate	DEVO_REV,			/* Devo_rev */
5377c478bdstevel@tonic-gate	0,				/* Refcnt */
5387c478bdstevel@tonic-gate	ohci_info,			/* Info */
5397c478bdstevel@tonic-gate	nulldev,			/* Identify */
5407c478bdstevel@tonic-gate	nulldev,			/* Probe */
5417c478bdstevel@tonic-gate	ohci_attach,			/* Attach */
5427c478bdstevel@tonic-gate	ohci_detach,			/* Detach */
5437c478bdstevel@tonic-gate	nodev,				/* Reset */
5447c478bdstevel@tonic-gate	&ohci_cb_ops,			/* Driver operations */
5457c478bdstevel@tonic-gate	&usba_hubdi_busops,		/* Bus operations */
5461939740Sherry Moore	usba_hubdi_root_hub_power,	/* Power */
5471939740Sherry Moore	ohci_quiesce,			/* Quiesce */
5487c478bdstevel@tonic-gate};
5497c478bdstevel@tonic-gate
5507c478bdstevel@tonic-gate/*
5517c478bdstevel@tonic-gate * The USBA library must be loaded for this driver.
5527c478bdstevel@tonic-gate */
5537c478bdstevel@tonic-gatestatic struct modldrv modldrv = {
5543e1e1e6Toomas Soome	&mod_driverops,		/* Type of module. This one is a driver */
5553e1e1e6Toomas Soome	"USB OpenHCI Driver",	/* Name of the module. */
5567c478bdstevel@tonic-gate	&ohci_ops,		/* Driver ops */
5577c478bdstevel@tonic-gate};
5587c478bdstevel@tonic-gate
5597c478bdstevel@tonic-gatestatic struct modlinkage modlinkage = {
5607c478bdstevel@tonic-gate	MODREV_1, (void *)&modldrv, NULL
5617c478bdstevel@tonic-gate};
5627c478bdstevel@tonic-gate
5637c478bdstevel@tonic-gate
5647c478bdstevel@tonic-gateint
5657c478bdstevel@tonic-gate_init(void)
5667c478bdstevel@tonic-gate{
5677c478bdstevel@tonic-gate	int error;
5687c478bdstevel@tonic-gate
5697c478bdstevel@tonic-gate	/* Initialize the soft state structures */
5707c478bdstevel@tonic-gate	if ((error = ddi_soft_state_init(&ohci_statep, sizeof (ohci_state_t),
5717c478bdstevel@tonic-gate	    OHCI_INSTS)) != 0) {
5727c478bdstevel@tonic-gate		return (error);
5737c478bdstevel@tonic-gate	}
5747c478bdstevel@tonic-gate
5757c478bdstevel@tonic-gate	/* Install the loadable module */
5767c478bdstevel@tonic-gate	if ((error = mod_install(&modlinkage)) != 0) {
5777c478bdstevel@tonic-gate		ddi_soft_state_fini(&ohci_statep);
5787c478bdstevel@tonic-gate	}
5797c478bdstevel@tonic-gate
5807c478bdstevel@tonic-gate	return (error);
5817c478bdstevel@tonic-gate}
5827c478bdstevel@tonic-gate
5837c478bdstevel@tonic-gate
5847c478bdstevel@tonic-gateint
5857c478bdstevel@tonic-gate_info(struct modinfo *modinfop)
5867c478bdstevel@tonic-gate{
5877c478bdstevel@tonic-gate	return (mod_info(&modlinkage, modinfop));
5887c478bdstevel@tonic-gate}
5897c478bdstevel@tonic-gate
5907c478bdstevel@tonic-gate
5917c478bdstevel@tonic-gateint
5927c478bdstevel@tonic-gate_fini(void)
5937c478bdstevel@tonic-gate{
5947c478bdstevel@tonic-gate	int error;
5957c478bdstevel@tonic-gate
5967c478bdstevel@tonic-gate	if ((error = mod_remove(&modlinkage)) == 0) {
5977c478bdstevel@tonic-gate		/* Release per module resources */
5987c478bdstevel@tonic-gate		ddi_soft_state_fini(&ohci_statep);
5997c478bdstevel@tonic-gate	}
6007c478bdstevel@tonic-gate
6017c478bdstevel@tonic-gate	return (error);
6027c478bdstevel@tonic-gate}
6037c478bdstevel@tonic-gate
6047c478bdstevel@tonic-gate
6057c478bdstevel@tonic-gate/*
6067c478bdstevel@tonic-gate * Host Controller Driver (HCD) entry points
6077c478bdstevel@tonic-gate */
6087c478bdstevel@tonic-gate
6097c478bdstevel@tonic-gate/*
6107c478bdstevel@tonic-gate * ohci_attach:
6117c478bdstevel@tonic-gate */
6127c478bdstevel@tonic-gatestatic int
6133e1e1e6Toomas Soomeohci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
6147c478bdstevel@tonic-gate{
6157c478bdstevel@tonic-gate	int			instance;
6167c478bdstevel@tonic-gate	ohci_state_t		*ohcip = NULL;
6177c478bdstevel@tonic-gate	usba_hcdi_register_args_t hcdi_args;
6187c478bdstevel@tonic-gate
6197c478bdstevel@tonic-gate	switch (cmd) {
6207c478bdstevel@tonic-gate	case DDI_ATTACH:
6217c478bdstevel@tonic-gate		break;
6227c478bdstevel@tonic-gate	case DDI_RESUME:
6237c478bdstevel@tonic-gate		ohcip = ohci_obtain_state(dip);
6247c478bdstevel@tonic-gate
6257c478bdstevel@tonic-gate		return (ohci_cpr_resume(ohcip));
6267c478bdstevel@tonic-gate	default:
6277c478bdstevel@tonic-gate		return (DDI_FAILURE);
6287c478bdstevel@tonic-gate	}
6297c478bdstevel@tonic-gate
6307c478bdstevel@tonic-gate	/* Get the instance and create soft state */
6317c478bdstevel@tonic-gate	instance = ddi_get_instance(dip);
6327c478bdstevel@tonic-gate
6337c478bdstevel@tonic-gate	if (ddi_soft_state_zalloc(ohci_statep, instance) != 0) {
6347c478bdstevel@tonic-gate
6357c478bdstevel@tonic-gate		return (DDI_FAILURE);
6367c478bdstevel@tonic-gate	}
6377c478bdstevel@tonic-gate
6387c478bdstevel@tonic-gate	ohcip = ddi_get_soft_state(ohci_statep, instance);
6397c478bdstevel@tonic-gate	if (ohcip == NULL) {
6407c478bdstevel@tonic-gate
6417c478bdstevel@tonic-gate		return (DDI_FAILURE);
6427c478bdstevel@tonic-gate	}
6437c478bdstevel@tonic-gate
6447c478bdstevel@tonic-gate	ohcip->ohci_flags = OHCI_ATTACH;
6457c478bdstevel@tonic-gate
6467c478bdstevel@tonic-gate	ohcip->ohci_log_hdl = usb_alloc_log_hdl(dip, "ohci", &ohci_errlevel,
6477c478bdstevel@tonic-gate	    &ohci_errmask, &ohci_instance_debug, 0);
6487c478bdstevel@tonic-gate
6497c478bdstevel@tonic-gate	ohcip->ohci_flags |= OHCI_ZALLOC;
6507c478bdstevel@tonic-gate
6517c478bdstevel@tonic-gate	/* Set host controller soft state to initilization */
6527c478bdstevel@tonic-gate	ohcip->ohci_hc_soft_state = OHCI_CTLR_INIT_STATE;
6537c478bdstevel@tonic-gate
6547c478bdstevel@tonic-gate	USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
6557c478bdstevel@tonic-gate	    "ohcip = 0x%p", (void *)ohcip);
6567c478bdstevel@tonic-gate
6577c478bdstevel@tonic-gate	/* Initialize the DMA attributes */
6587c478bdstevel@tonic-gate	ohci_set_dma_attributes(ohcip);
6597c478bdstevel@tonic-gate
6607c478bdstevel@tonic-gate	/* Save the dip and instance */
6617c478bdstevel@tonic-gate	ohcip->ohci_dip = dip;
6627c478bdstevel@tonic-gate	ohcip->ohci_instance = instance;
6637c478bdstevel@tonic-gate
6647c478bdstevel@tonic-gate	/* Initialize the kstat structures */
6657c478bdstevel@tonic-gate	ohci_create_stats(ohcip);
6667c478bdstevel@tonic-gate
6677c478bdstevel@tonic-gate	/* Create the td and ed pools */
6687c478bdstevel@tonic-gate	if (ohci_allocate_pools(ohcip) != DDI_SUCCESS) {
6697c478bdstevel@tonic-gate		(void) ohci_cleanup(ohcip);
6707c478bdstevel@tonic-gate
6717c478bdstevel@tonic-gate		return (DDI_FAILURE);
6727c478bdstevel@tonic-gate	}
6737c478bdstevel@tonic-gate
6747c478bdstevel@tonic-gate	/* Map the registers */
6757c478bdstevel@tonic-gate	if (ohci_map_regs(ohcip) != DDI_SUCCESS) {
6767c478bdstevel@tonic-gate		(void) ohci_cleanup(ohcip);
6777c478bdstevel@tonic-gate
6787c478bdstevel@tonic-gate		return (DDI_FAILURE);
6797c478bdstevel@tonic-gate	}
6807c478bdstevel@tonic-gate
681af95cb8zhigang lu - Sun Microsystems - Beijing China	/* Get the ohci chip vendor and device id */
682af95cb8zhigang lu - Sun Microsystems - Beijing China	ohcip->ohci_vendor_id = pci_config_get16(
683af95cb8zhigang lu - Sun Microsystems - Beijing China	    ohcip->ohci_config_handle, PCI_CONF_VENID);
684af95cb8zhigang lu - Sun Microsystems - Beijing China	ohcip->ohci_device_id = pci_config_get16(
685af95cb8zhigang lu - Sun Microsystems - Beijing China	    ohcip->ohci_config_handle, PCI_CONF_DEVID);
686af95cb8zhigang lu - Sun Microsystems - Beijing China	ohcip->ohci_rev_id = pci_config_get8(
687af95cb8zhigang lu - Sun Microsystems - Beijing China	    ohcip->ohci_config_handle, PCI_CONF_REVID);
688af95cb8zhigang lu - Sun Microsystems - Beijing China
6897c478bdstevel@tonic-gate	/* Register interrupts */
6907c478bdstevel@tonic-gate	if (ohci_register_intrs_and_init_mutex(ohcip) != DDI_SUCCESS) {
6917c478bdstevel@tonic-gate		(void) ohci_cleanup(ohcip);
6927c478bdstevel@tonic-gate
6937c478bdstevel@tonic-gate		return (DDI_FAILURE);
6947c478bdstevel@tonic-gate	}
6957c478bdstevel@tonic-gate
6967c478bdstevel@tonic-gate	mutex_enter(&ohcip->ohci_int_mutex);
6977c478bdstevel@tonic-gate
6987c478bdstevel@tonic-gate	/* Initialize the controller */
6997c478bdstevel@tonic-gate	if (ohci_init_ctlr(ohcip) != DDI_SUCCESS) {
7007c478bdstevel@tonic-gate		mutex_exit(&ohcip->ohci_int_mutex);
7017c478bdstevel@tonic-gate		(void) ohci_cleanup(ohcip);
7027c478bdstevel@tonic-gate
7037c478bdstevel@tonic-gate		return (DDI_FAILURE);
7047c478bdstevel@tonic-gate	}
7057c478bdstevel@tonic-gate
7067c478bdstevel@tonic-gate	/*
7077c478bdstevel@tonic-gate	 * At this point, the hardware wiil be okay.
7087c478bdstevel@tonic-gate	 * Initialize the usba_hcdi structure
7097c478bdstevel@tonic-gate	 */
7107c478bdstevel@tonic-gate	ohcip->ohci_hcdi_ops = ohci_alloc_hcdi_ops(ohcip);
7117c478bdstevel@tonic-gate
7127c478bdstevel@tonic-gate	mutex_exit(&ohcip->ohci_int_mutex);
7137c478bdstevel@tonic-gate
7147c478bdstevel@tonic-gate	/*
7157c478bdstevel@tonic-gate	 * Make this HCD instance known to USBA
7167c478bdstevel@tonic-gate	 * (dma_attr must be passed for USBA busctl's)
7177c478bdstevel@tonic-gate	 */
7187c478bdstevel@tonic-gate	hcdi_args.usba_hcdi_register_version = HCDI_REGISTER_VERSION;
7197c478bdstevel@tonic-gate	hcdi_args.usba_hcdi_register_dip = dip;
7207c478bdstevel@tonic-gate	hcdi_args.usba_hcdi_register_ops = ohcip->ohci_hcdi_ops;
7217c478bdstevel@tonic-gate	hcdi_args.usba_hcdi_register_dma_attr = &ohcip->ohci_dma_attr;
7227c478bdstevel@tonic-gate
7237c478bdstevel@tonic-gate	/*
7247c478bdstevel@tonic-gate	 * Priority and iblock_cookie are one and the same
7257c478bdstevel@tonic-gate	 * (However, retaining hcdi_soft_iblock_cookie for now
7267c478bdstevel@tonic-gate	 * assigning it w/ priority. In future all iblock_cookie
7277c478bdstevel@tonic-gate	 * could just go)
7287c478bdstevel@tonic-gate	 */
7297c478bdstevel@tonic-gate	hcdi_args.usba_hcdi_register_iblock_cookie =
730abdbd06agiri	    (ddi_iblock_cookie_t)(uintptr_t)ohcip->ohci_intr_pri;
7317c478bdstevel@tonic-gate
7327c478bdstevel@tonic-gate	if (usba_hcdi_register(&hcdi_args, 0) != DDI_SUCCESS) {
7337c478bdstevel@tonic-gate		(void) ohci_cleanup(ohcip);
7347c478bdstevel@tonic-gate
7357c478bdstevel@tonic-gate		return (DDI_FAILURE);
7367c478bdstevel@tonic-gate	}
7377c478bdstevel@tonic-gate	ohcip->ohci_flags |= OHCI_USBAREG;
7387c478bdstevel@tonic-gate
7397c478bdstevel@tonic-gate	mutex_enter(&ohcip->ohci_int_mutex);
7407c478bdstevel@tonic-gate
7417c478bdstevel@tonic-gate	if ((ohci_init_root_hub(ohcip)) != USB_SUCCESS) {
7427c478bdstevel@tonic-gate		mutex_exit(&ohcip->ohci_int_mutex);
7437c478bdstevel@tonic-gate		(void) ohci_cleanup(ohcip);
7447c478bdstevel@tonic-gate
7457c478bdstevel@tonic-gate		return (DDI_FAILURE);
7467c478bdstevel@tonic-gate	}
7477c478bdstevel@tonic-gate
7487c478bdstevel@tonic-gate	mutex_exit(&ohcip->ohci_int_mutex);
7497c478bdstevel@tonic-gate
7507c478bdstevel@tonic-gate	/* Finally load the root hub driver */
7517c478bdstevel@tonic-gate	if (ohci_load_root_hub_driver(ohcip) != USB_SUCCESS) {
7527c478bdstevel@tonic-gate		(void) ohci_cleanup(ohcip);
7537c478bdstevel@tonic-gate
7547c478bdstevel@tonic-gate		return (DDI_FAILURE);
7557c478bdstevel@tonic-gate	}
7567c478bdstevel@tonic-gate	ohcip->ohci_flags |= OHCI_RHREG;
7577c478bdstevel@tonic-gate
7587c478bdstevel@tonic-gate	/* Display information in the banner */
7597c478bdstevel@tonic-gate	ddi_report_dev(dip);
7607c478bdstevel@tonic-gate
7617c478bdstevel@tonic-gate	mutex_enter(&ohcip->ohci_int_mutex);
7627c478bdstevel@tonic-gate
7637c478bdstevel@tonic-gate	/* Reset the ohci initilization flag */
7647c478bdstevel@tonic-gate	ohcip->ohci_flags &= ~OHCI_ATTACH;
7657c478bdstevel@tonic-gate
7667c478bdstevel@tonic-gate	/* Print the Host Control's Operational registers */
7677c478bdstevel@tonic-gate	ohci_print_op_regs(ohcip);
7687c478bdstevel@tonic-gate
7697c478bdstevel@tonic-gate	/* For RIO we need to call pci_report_pmcap */
7707c478bdstevel@tonic-gate	if (OHCI_IS_RIO(ohcip)) {
7717c478bdstevel@tonic-gate
7727c478bdstevel@tonic-gate		(void) pci_report_pmcap(dip, PCI_PM_IDLESPEED, (void *)4000);
7737c478bdstevel@tonic-gate	}
7747c478bdstevel@tonic-gate
7757c478bdstevel@tonic-gate	mutex_exit(&ohcip->ohci_int_mutex);
7767c478bdstevel@tonic-gate
7777c478bdstevel@tonic-gate	USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
7787c478bdstevel@tonic-gate	    "ohci_attach: dip = 0x%p done", (void *)dip);
7797c478bdstevel@tonic-gate
7807c478bdstevel@tonic-gate	return (DDI_SUCCESS);
7817c478bdstevel@tonic-gate}
7827c478bdstevel@tonic-gate
7837c478bdstevel@tonic-gate
7847c478bdstevel@tonic-gate/*
7857c478bdstevel@tonic-gate * ohci_detach:
7867c478bdstevel@tonic-gate */
7877c478bdstevel@tonic-gateint
7883e1e1e6Toomas Soomeohci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
7897c478bdstevel@tonic-gate{
7907c478bdstevel@tonic-gate	ohci_state_t		*ohcip = ohci_obtain_state(dip);
7917c478bdstevel@tonic-gate
7927c478bdstevel@tonic-gate	USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_detach:");
7937c478bdstevel@tonic-gate
7947c478bdstevel@tonic-gate	switch (cmd) {
7957c478bdstevel@tonic-gate	case DDI_DETACH:
7967c478bdstevel@tonic-gate
7977c478bdstevel@tonic-gate		return (ohci_cleanup(ohcip));
7987c478bdstevel@tonic-gate
7997c478bdstevel@tonic-gate	case DDI_SUSPEND:
8007c478bdstevel@tonic-gate
8017c478bdstevel@tonic-gate		return (ohci_cpr_suspend(ohcip));
8027c478bdstevel@tonic-gate	default:
8037c478bdstevel@tonic-gate
8047c478bdstevel@tonic-gate		return (DDI_FAILURE);
8057c478bdstevel@tonic-gate	}
8067c478bdstevel@tonic-gate}
8077c478bdstevel@tonic-gate
8087c478bdstevel@tonic-gate
8097c478bdstevel@tonic-gate/*
8107c478bdstevel@tonic-gate * ohci_info:
8117c478bdstevel@tonic-gate */
8127c478bdstevel@tonic-gate/* ARGSUSED */
8137c478bdstevel@tonic-gatestatic int
8143e1e1e6Toomas Soomeohci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
8157c478bdstevel@tonic-gate{
8167c478bdstevel@tonic-gate	dev_t			dev;
8177c478bdstevel@tonic-gate	ohci_state_t		*ohcip;
8187c478bdstevel@tonic-gate	int			instance;
8197c478bdstevel@tonic-gate	int			error = DDI_FAILURE;
8207c478bdstevel@tonic-gate
8217c478bdstevel@tonic-gate	switch (infocmd) {
8227c478bdstevel@tonic-gate	case DDI_INFO_DEVT2DEVINFO:
8237c478bdstevel@tonic-gate		dev = (dev_t)arg;
8247c478bdstevel@tonic-gate		instance = OHCI_UNIT(dev);
8257c478bdstevel@tonic-gate		ohcip = ddi_get_soft_state(ohci_statep, instance);
8267c478bdstevel@tonic-gate		if (ohcip != NULL) {
8277c478bdstevel@tonic-gate			*result = (void *)ohcip->ohci_dip;
8287c478bdstevel@tonic-gate			if (*result != NULL) {
8297c478bdstevel@tonic-gate				error = DDI_SUCCESS;
8307c478bdstevel@tonic-gate			}
8317c478bdstevel@tonic-gate		} else {
8327c478bdstevel@tonic-gate			*result = NULL;
8337c478bdstevel@tonic-gate		}
8347c478bdstevel@tonic-gate
8357c478bdstevel@tonic-gate		break;
8367c478bdstevel@tonic-gate	case DDI_INFO_DEVT2INSTANCE:
8377c478bdstevel@tonic-gate		dev = (dev_t)arg;
8387c478bdstevel@tonic-gate		instance = OHCI_UNIT(dev);
8397c478bdstevel@tonic-gate		*result = (void *)(uintptr_t)instance;
8407c478bdstevel@tonic-gate		error = DDI_SUCCESS;
8417c478bdstevel@tonic-gate		break;
8427c478bdstevel@tonic-gate	default:
8437c478bdstevel@tonic-gate		break;
8447c478bdstevel@tonic-gate	}
8457c478bdstevel@tonic-gate
8467c478bdstevel@tonic-gate	return (error);
8477c478bdstevel@tonic-gate}
8487c478bdstevel@tonic-gate
8497c478bdstevel@tonic-gate
8507c478bdstevel@tonic-gate/*
8517c478bdstevel@tonic-gate * cb_ops entry points
8527c478bdstevel@tonic-gate */
8537c478bdstevel@tonic-gatestatic dev_info_t *
8543e1e1e6Toomas Soomeohci_get_dip(dev_t dev)
8557c478bdstevel@tonic-gate{
8567c478bdstevel@tonic-gate	int		instance = OHCI_UNIT(dev);
8577c478bdstevel@tonic-gate	ohci_state_t	*ohcip = ddi_get_soft_state(ohci_statep, instance);
8587c478bdstevel@tonic-gate
8597c478bdstevel@tonic-gate	if (ohcip) {
8607c478bdstevel@tonic-gate
8617c478bdstevel@tonic-gate		return (ohcip->ohci_dip);
8627c478bdstevel@tonic-gate	} else {
8637c478bdstevel@tonic-gate
8647c478bdstevel@tonic-gate		return (NULL);
8657c478bdstevel@tonic-gate	}
8667c478bdstevel@tonic-gate}
8677c478bdstevel@tonic-gate
8687c478bdstevel@tonic-gate
8697c478bdstevel@tonic-gatestatic int
8703e1e1e6Toomas Soomeohci_open(dev_t *devp, int flags, int otyp, cred_t *credp)
8717c478bdstevel@tonic-gate{
8727c478bdstevel@tonic-gate	dev_info_t	*dip = ohci_get_dip(*devp);
8737c478bdstevel@tonic-gate
8747c478bdstevel@tonic-gate	return (usba_hubdi_open(dip, devp, flags, otyp, credp));
8757c478bdstevel@tonic-gate}
8767c478bdstevel@tonic-gate
8777c478bdstevel@tonic-gate
8787c478bdstevel@tonic-gatestatic int
8793e1e1e6Toomas Soomeohci_close(dev_t dev, int flag, int otyp, cred_t *credp)
8807c478bdstevel@tonic-gate{
8817c478bdstevel@tonic-gate	dev_info_t	*dip = ohci_get_dip(dev);
8827c478bdstevel@tonic-gate
8837c478bdstevel@tonic-gate	return (usba_hubdi_close(dip, dev, flag, otyp, credp));
8847c478bdstevel@tonic-gate}
8857c478bdstevel@tonic-gate
8867c478bdstevel@tonic-gate
8877c478bdstevel@tonic-gatestatic int
8883e1e1e6Toomas Soomeohci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
8893e1e1e6Toomas Soome    int *rvalp)
8907c478bdstevel@tonic-gate{
8917c478bdstevel@tonic-gate	dev_info_t	*dip = ohci_get_dip(dev);
8927c478bdstevel@tonic-gate
8937c478bdstevel@tonic-gate	return (usba_hubdi_ioctl(dip,
8947c478bdstevel@tonic-gate	    dev, cmd, arg, mode, credp, rvalp));
8957c478bdstevel@tonic-gate}
8967c478bdstevel@tonic-gate
8977c478bdstevel@tonic-gate
8987c478bdstevel@tonic-gate/*
8997c478bdstevel@tonic-gate * Host Controller Driver (HCD) initialization functions
9007c478bdstevel@tonic-gate */
9017c478bdstevel@tonic-gate
9027c478bdstevel@tonic-gate/*
9037c478bdstevel@tonic-gate * ohci_set_dma_attributes:
9047c478bdstevel@tonic-gate *
9057c478bdstevel@tonic-gate * Set the limits in the DMA attributes structure. Most of the values used
9067c478bdstevel@tonic-gate * in the  DMA limit structres are the default values as specified by  the
9077c478bdstevel@tonic-gate * Writing PCI device drivers document.
9087c478bdstevel@tonic-gate */
9097c478bdstevel@tonic-gatestatic void
9107c478bdstevel@tonic-gateohci_set_dma_attributes(ohci_state_t	*ohcip)
9117c478bdstevel@tonic-gate{
9127c478bdstevel@tonic-gate	USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
9137c478bdstevel@tonic-gate	    "ohci_set_dma_attributes:");
9147c478bdstevel@tonic-gate
9157c478bdstevel@tonic-gate	/* Initialize the DMA attributes */
9167c478bdstevel@tonic-gate	ohcip->ohci_dma_attr.dma_attr_version = DMA_ATTR_V0;
9177c478bdstevel@tonic-gate	ohcip->ohci_dma_attr.dma_attr_addr_lo = 0x00000000ull;
9187c478bdstevel@tonic-gate	ohcip->ohci_dma_attr.dma_attr_addr_hi = 0xfffffffeull;
9197c478bdstevel@tonic-gate
9207c478bdstevel@tonic-gate	/* 32 bit addressing */
9217c478bdstevel@tonic-gate	ohcip->ohci_dma_attr.dma_attr_count_max = OHCI_DMA_ATTR_COUNT_MAX;
9227c478bdstevel@tonic-gate
9237c478bdstevel@tonic-gate	/* Byte alignment */
9247c478bdstevel@tonic-gate	ohcip->ohci_dma_attr.dma_attr_align = OHCI_DMA_ATTR_ALIGNMENT;
9257c478bdstevel@tonic-gate
9267c478bdstevel@tonic-gate	/*
9277c478bdstevel@tonic-gate	 * Since PCI  specification is byte alignment, the
9287c478bdstevel@tonic-gate	 * burstsize field should be set to 1 for PCI devices.
9297c478bdstevel@tonic-gate	 */
9307c478bdstevel@tonic-gate	ohcip->ohci_dma_attr.dma_attr_burstsizes = 0x1;
9317c478bdstevel@tonic-gate
9327c478bdstevel@tonic-gate	ohcip->ohci_dma_attr.dma_attr_minxfer = 0x1;
9337c478bdstevel@tonic-gate	ohcip->ohci_dma_attr.dma_attr_maxxfer = OHCI_DMA_ATTR_MAX_XFER;
9347c478bdstevel@tonic-gate	ohcip->ohci_dma_attr.dma_attr_seg = 0xffffffffull;
9357c478bdstevel@tonic-gate	ohcip->ohci_dma_attr.dma_attr_sgllen = 1;
9367c478bdstevel@tonic-gate	ohcip->ohci_dma_attr.dma_attr_granular = OHCI_DMA_ATTR_GRANULAR;
9377c478bdstevel@tonic-gate	ohcip->ohci_dma_attr.dma_attr_flags = 0;
9387c478bdstevel@tonic-gate}
9397c478bdstevel@tonic-gate
9407c478bdstevel@tonic-gate
9417c478bdstevel@tonic-gate/*
9427c478bdstevel@tonic-gate * ohci_allocate_pools:
9437c478bdstevel@tonic-gate *
9447c478bdstevel@tonic-gate * Allocate the system memory for the Endpoint Descriptor (ED) and for the
9457c478bdstevel@tonic-gate * Transfer Descriptor (TD) pools. Both ED and TD structures must be aligned
9467c478bdstevel@tonic-gate * to a 16 byte boundary.
9477c478bdstevel@tonic-gate */
9487c478bdstevel@tonic-gatestatic int
9497c478bdstevel@tonic-gateohci_allocate_pools(ohci_state_t	*ohcip)
9507c478bdstevel@tonic-gate{
9517c478bdstevel@tonic-gate	ddi_device_acc_attr_t		dev_attr;
9527c478bdstevel@tonic-gate	size_t				real_length;
9537c478bdstevel@tonic-gate	int				result;
9547c478bdstevel@tonic-gate	uint_t				ccount;
9557c478bdstevel@tonic-gate	int				i;
9567c478bdstevel@tonic-gate
9577c478bdstevel@tonic-gate	USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
9587c478bdstevel@tonic-gate	    "ohci_allocate_pools:");
9597c478bdstevel@tonic-gate
9607c478bdstevel@tonic-gate	/* The host controller will be little endian */
9617c478bdstevel@tonic-gate	dev_attr.devacc_attr_version	= DDI_DEVICE_ATTR_V0;
9627c478bdstevel@tonic-gate	dev_attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
9637c478bdstevel@tonic-gate	dev_attr.devacc_attr_dataorder	= DDI_STRICTORDER_ACC;
9647c478bdstevel@tonic-gate
9657c478bdstevel@tonic-gate	/* Byte alignment to TD alignment */
9667c478bdstevel@tonic-gate	ohcip->ohci_dma_attr.dma_attr_align = OHCI_DMA_ATTR_TD_ALIGNMENT;
9677c478bdstevel@tonic-gate
9687c478bdstevel@tonic-gate	/* Allocate the TD pool DMA handle */
9697c478bdstevel@tonic-gate	if (ddi_dma_alloc_handle(ohcip->ohci_dip, &ohcip->ohci_dma_attr,
97029aca3elc	    DDI_DMA_SLEEP, 0,
97129aca3elc	    &ohcip->ohci_td_pool_dma_handle) != DDI_SUCCESS) {
9727c478bdstevel@tonic-gate
9737c478bdstevel@tonic-gate		return (DDI_FAILURE);
9747c478bdstevel@tonic-gate	}
9757c478bdstevel@tonic-gate
9767c478bdstevel@tonic-gate	/* Allocate the memory for the TD pool */
9777c478bdstevel@tonic-gate	if (ddi_dma_mem_alloc(ohcip->ohci_td_pool_dma_handle,
97829aca3elc	    ohci_td_pool_size * sizeof (ohci_td_t),
97929aca3elc	    &dev_attr,
98029aca3elc	    DDI_DMA_CONSISTENT,
98129aca3elc	    DDI_DMA_SLEEP,
98229aca3elc	    0,
98329aca3elc	    (caddr_t *)&ohcip->ohci_td_pool_addr,
98429aca3elc	    &real_length,
98529aca3elc	    &ohcip->ohci_td_pool_mem_handle)) {
9867c478bdstevel@tonic-gate
9877c478bdstevel@tonic-gate		return (DDI_FAILURE);
9887c478bdstevel@tonic-gate	}
9897c478bdstevel@tonic-gate
9907c478bdstevel@tonic-gate	/* Map the TD pool into the I/O address space */
9917c478bdstevel@tonic-gate	result = ddi_dma_addr_bind_handle(
99229aca3elc	    ohcip->ohci_td_pool_dma_handle,
99329aca3elc	    NULL,
99429aca3elc	    (caddr_t)ohcip->ohci_td_pool_addr,
99529aca3elc	    real_length,
99629aca3elc	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
99729aca3elc	    DDI_DMA_SLEEP,
99829aca3elc	    NULL,
99929aca3elc	    &ohcip->ohci_td_pool_cookie,
100029aca3elc	    &ccount);
10017c478bdstevel@tonic-gate
10027c478bdstevel@tonic-gate	bzero((void *)ohcip->ohci_td_pool_addr,
100329aca3elc	    ohci_td_pool_size * sizeof (ohci_td_t));
10047c478bdstevel@tonic-gate
10057c478bdstevel@tonic-gate	/* Process the result */
10067c478bdstevel@tonic-gate	if (result == DDI_DMA_MAPPED) {
10077c478bdstevel@tonic-gate		/* The cookie count should be 1 */
10087c478bdstevel@tonic-gate		if (ccount != 1) {
10097c478bdstevel@tonic-gate			USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
10107c478bdstevel@tonic-gate			    "ohci_allocate_pools: More than 1 cookie");
10117c478bdstevel@tonic-gate
10127c478bdstevel@tonic-gate			return (DDI_FAILURE);
10137c478bdstevel@tonic-gate		}
10147c478bdstevel@tonic-gate	} else {
10157c478bdstevel@tonic-gate		USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
10167c478bdstevel@tonic-gate		    "ohci_allocate_pools: Result = %d", result);
10177c478bdstevel@tonic-gate
10187c478bdstevel@tonic-gate		ohci_decode_ddi_dma_addr_bind_handle_result(ohcip, result);
10197c478bdstevel@tonic-gate
10207c478bdstevel@tonic-gate		return (DDI_FAILURE);
10217c478bdstevel@tonic-gate	}
10227c478bdstevel@tonic-gate
10237c478bdstevel@tonic-gate	/*
10247c478bdstevel@tonic-gate	 * DMA addresses for TD pools are bound
10257c478bdstevel@tonic-gate	 */
10267c478bdstevel@tonic-gate	ohcip->ohci_dma_addr_bind_flag |= OHCI_TD_POOL_BOUND;
10277c478bdstevel@tonic-gate
10287c478bdstevel@tonic-gate	/* Initialize the TD pool */
10297c478bdstevel@tonic-gate	for (i = 0; i < ohci_td_pool_size; i ++) {
10307c478bdstevel@tonic-gate		Set_TD(ohcip->ohci_td_pool_addr[i].hctd_state, HC_TD_FREE);
10317c478bdstevel@tonic-gate	}
10327c478bdstevel@tonic-gate
10337c478bdstevel@tonic-gate	/* Byte alignment to ED alignment */
10347c478bdstevel@tonic-gate	ohcip->ohci_dma_attr.dma_attr_align = OHCI_DMA_ATTR_ED_ALIGNMENT;
10357c478bdstevel@tonic-gate
10367c478bdstevel@tonic-gate	/* Allocate the ED pool DMA handle */
10377c478bdstevel@tonic-gate	if (ddi_dma_alloc_handle(ohcip->ohci_dip,
103829aca3elc	    &ohcip->ohci_dma_attr,
103929aca3elc	    DDI_DMA_SLEEP,
104029aca3elc	    0,
104129aca3elc	    &ohcip->ohci_ed_pool_dma_handle) != DDI_SUCCESS) {
10427c478bdstevel@tonic-gate
10437c478bdstevel@tonic-gate		return (DDI_FAILURE);
10447c478bdstevel@tonic-gate	}
10457c478bdstevel@tonic-gate
10467c478bdstevel@tonic-gate	/* Allocate the memory for the ED pool */
10477c478bdstevel@tonic-gate	if (ddi_dma_mem_alloc(ohcip->ohci_ed_pool_dma_handle,
104829aca3elc	    ohci_ed_pool_size * sizeof (ohci_ed_t),
104929aca3elc	    &dev_attr,
105029aca3elc	    DDI_DMA_CONSISTENT,
105129aca3elc	    DDI_DMA_SLEEP,
105229aca3elc	    0,
105329aca3elc	    (caddr_t *)&ohcip->ohci_ed_pool_addr,
105429aca3elc	    &real_length,
105529aca3elc	    &ohcip->ohci_ed_pool_mem_handle) != DDI_SUCCESS) {
10567c478bdstevel@tonic-gate
10577c478bdstevel@tonic-gate		return (DDI_FAILURE);
10587c478bdstevel@tonic-gate	}
10597c478bdstevel@tonic-gate
10607c478bdstevel@tonic-gate	result = ddi_dma_addr_bind_handle(ohcip->ohci_ed_pool_dma_handle,
106129aca3elc	    NULL,
106229aca3elc	    (caddr_t)ohcip->ohci_ed_pool_addr,
106329aca3elc	    real_length,
106429aca3elc	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
106529aca3elc	    DDI_DMA_SLEEP,
106629aca3elc	    NULL,
106729aca3elc	    &ohcip->ohci_ed_pool_cookie,
106829aca3elc	    &ccount);
10697c478bdstevel@tonic-gate
10707c478bdstevel@tonic-gate	bzero((void *)ohcip->ohci_ed_pool_addr,
107129aca3elc	    ohci_ed_pool_size * sizeof (ohci_ed_t));
10727c478bdstevel@tonic-gate
10737c478bdstevel@tonic-gate	/* Process the result */
10747c478bdstevel@tonic-gate	if (result == DDI_DMA_MAPPED) {
10757c478bdstevel@tonic-gate		/* The cookie count should be 1 */
10767c478bdstevel@tonic-gate		if (ccount != 1) {
10777c478bdstevel@tonic-gate			USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
10787c478bdstevel@tonic-gate			    "ohci_allocate_pools: More than 1 cookie");
10797c478bdstevel@tonic-gate
10807c478bdstevel@tonic-gate			return (DDI_FAILURE);
10817c478bdstevel@tonic-gate		}
10827c478bdstevel@tonic-gate	} else {
10837c478bdstevel@tonic-gate		ohci_decode_ddi_dma_addr_bind_handle_result(ohcip, result);
10847c478bdstevel@tonic-gate
10857c478bdstevel@tonic-gate		return (DDI_FAILURE);
10867c478bdstevel@tonic-gate	}
10877c478bdstevel@tonic-gate
10887c478bdstevel@tonic-gate	/*
10897c478bdstevel@tonic-gate	 * DMA addresses for ED pools are bound
10907c478bdstevel@tonic-gate	 */
10917c478bdstevel@tonic-gate	ohcip->ohci_dma_addr_bind_flag |= OHCI_ED_POOL_BOUND;
10927c478bdstevel@tonic-gate
10937c478bdstevel@tonic-gate	/* Initialize the ED pool */
10947c478bdstevel@tonic-gate	for (i = 0; i < ohci_ed_pool_size; i ++) {
10957c478bdstevel@tonic-gate		Set_ED(ohcip->ohci_ed_pool_addr[i].hced_state, HC_EPT_FREE);
10967c478bdstevel@tonic-gate	}
10977c478bdstevel@tonic-gate
10987c478bdstevel@tonic-gate	return (DDI_SUCCESS);
10997c478bdstevel@tonic-gate}
11007c478bdstevel@tonic-gate
11017c478bdstevel@tonic-gate
11027c478bdstevel@tonic-gate/*
11037c478bdstevel@tonic-gate * ohci_decode_ddi_dma_addr_bind_handle_result:
11047c478bdstevel@tonic-gate *
11057c478bdstevel@tonic-gate * Process the return values of ddi_dma_addr_bind_handle()
11067c478bdstevel@tonic-gate */
11077c478bdstevel@tonic-gatestatic void
11087c478bdstevel@tonic-gateohci_decode_ddi_dma_addr_bind_handle_result(
11097c478bdstevel@tonic-gate	ohci_state_t	*ohcip,
11107c478bdstevel@tonic-gate	int		result)
11117c478bdstevel@tonic-gate{
11127c478bdstevel@tonic-gate	USB_DPRINTF_L2(PRINT_MASK_ALLOC, ohcip->ohci_log_hdl,
11137c478bdstevel@tonic-gate	    "ohci_decode_ddi_dma_addr_bind_handle_result:");
11147c478bdstevel@tonic-gate
11157c478bdstevel@tonic-gate	switch (result) {
11167c478bdstevel@tonic-gate	case DDI_DMA_PARTIAL_MAP:
11177c478bdstevel@tonic-gate		USB_DPRINTF_L2(PRINT_MASK_ALL, ohcip->ohci_log_hdl,
11187c478bdstevel@tonic-gate		    "Partial transfers not allowed");
11197c478bdstevel@tonic-gate		break;
11207c478bdstevel@tonic-gate	case DDI_DMA_INUSE:
11217c478bdstevel@tonic-gate		USB_DPRINTF_L2(PRINT_MASK_ALL,	ohcip->ohci_log_hdl,
11227c478bdstevel@tonic-gate		    "Handle is in use");
11237c478bdstevel@tonic-gate		break;
11247c478bdstevel@tonic-gate	case DDI_DMA_NORESOURCES:
11257c478bdstevel@tonic-gate		USB_DPRINTF_L2(PRINT_MASK_ALL,	ohcip->ohci_log_hdl,
11267c478bdstevel@tonic-gate		    "No resources");
11277c478bdstevel@tonic-gate		break;
11287c478bdstevel@tonic-gate	case DDI_DMA_NOMAPPING:
11297c478bdstevel@tonic-gate		USB_DPRINTF_L2(PRINT_MASK_ALL,	ohcip->ohci_log_hdl,
11307c478bdstevel@tonic-gate		    "No mapping");
11317c478bdstevel@tonic-gate		break;
11327c478bdstevel@tonic-gate	case DDI_DMA_TOOBIG:
11337c478bdstevel@tonic-gate		USB_DPRINTF_L2(PRINT_MASK_ALL,	ohcip->ohci_log_hdl,
11347c478bdstevel@tonic-gate		    "Object is too big");
11357c478bdstevel@tonic-gate		break;
11367c478bdstevel@tonic-gate	default:
11377c478bdstevel@tonic-gate		USB_DPRINTF_L2(PRINT_MASK_ALL,	ohcip->ohci_log_hdl,
11387c478bdstevel@tonic-gate		    "Unknown dma error");
11397c478bdstevel@tonic-gate	}
11407c478bdstevel@tonic-gate}
11417c478bdstevel@tonic-gate
11427c478bdstevel@tonic-gate
11437c478bdstevel@tonic-gate/*
11447c478bdstevel@tonic-gate * ohci_map_regs:
11457c478bdstevel@tonic-gate *
11467c478bdstevel@tonic-gate * The Host Controller (HC) contains a set of on-chip operational registers
11477c478bdstevel@tonic-gate * and which should be mapped into a non-cacheable portion of the  system
11487c478bdstevel@tonic-gate * addressable space.
11497c478bdstevel@tonic-gate */
11507c478bdstevel@tonic-gatestatic int
11517c478bdstevel@tonic-gateohci_map_regs(ohci_state_t	*ohcip)
11527c478bdstevel@tonic-gate{
11537c478bdstevel@tonic-gate	ddi_device_acc_attr_t	attr;
11547c478bdstevel@tonic-gate	uint16_t		cmd_reg;
11557c478bdstevel@tonic-gate
11567c478bdstevel@tonic-gate	USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_map_regs:");
11577c478bdstevel@tonic-gate
11587c478bdstevel@tonic-gate	/* The host controller will be little endian */
11597c478bdstevel@tonic-gate	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
11607c478bdstevel@tonic-gate	attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
11617c478bdstevel@tonic-gate	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
11627c478bdstevel@tonic-gate
11637c478bdstevel@tonic-gate	/* Map in operational registers */
11647c478bdstevel@tonic-gate	if (ddi_regs_map_setup(ohcip->ohci_dip, 1,
11657c478bdstevel@tonic-gate	    (caddr_t *)&ohcip->ohci_regsp, 0,
11667c478bdstevel@tonic-gate	    sizeof (ohci_regs_t), &attr,
11677c478bdstevel@tonic-gate	    &ohcip->ohci_regs_handle) != DDI_SUCCESS) {
11687c478bdstevel@tonic-gate
11697c478bdstevel@tonic-gate		USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
11707c478bdstevel@tonic-gate		    "ohci_map_regs: Map setup error");
11717c478bdstevel@tonic-gate
11727c478bdstevel@tonic-gate		return (DDI_FAILURE);
11737c478bdstevel@tonic-gate	}
11747c478bdstevel@tonic-gate
11757c478bdstevel@tonic-gate	if (pci_config_setup(ohcip->ohci_dip,
11767c478bdstevel@tonic-gate	    &ohcip->ohci_config_handle) != DDI_SUCCESS) {
11777c478bdstevel@tonic-gate
11787c478bdstevel@tonic-gate		USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
11797c478bdstevel@tonic-gate		    "ohci_map_regs: Config error");
11807c478bdstevel@tonic-gate
11817c478bdstevel@tonic-gate		return (DDI_FAILURE);
11827c478bdstevel@tonic-gate	}
11837c478bdstevel@tonic-gate
11847c478bdstevel@tonic-gate	/* Make sure Memory Access Enable and Master Enable are set */
11857c478bdstevel@tonic-gate	cmd_reg = pci_config_get16(ohcip->ohci_config_handle, PCI_CONF_COMM);
11867c478bdstevel@tonic-gate
11877c478bdstevel@tonic-gate	if (!(cmd_reg & PCI_COMM_MAE)) {
11887c478bdstevel@tonic-gate
11897c478bdstevel@tonic-gate		USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
11907c478bdstevel@tonic-gate		    "ohci_map_regs: Memory base address access disabled");
11917c478bdstevel@tonic-gate
11927c478bdstevel@tonic-gate		return (DDI_FAILURE);
11937c478bdstevel@tonic-gate	}
11947c478bdstevel@tonic-gate
11957c478bdstevel@tonic-gate	cmd_reg |= (PCI_COMM_MAE | PCI_COMM_ME);
11967c478bdstevel@tonic-gate
11977c478bdstevel@tonic-gate	pci_config_put16(ohcip->ohci_config_handle, PCI_CONF_COMM, cmd_reg);
11987c478bdstevel@tonic-gate
11997c478bdstevel@tonic-gate	return (DDI_SUCCESS);
12007c478bdstevel@tonic-gate}
12017c478bdstevel@tonic-gate
120228cdc3dszhou/*
120328cdc3dszhou * The following simulated polling is for debugging purposes only.
120428cdc3dszhou * It is activated on x86 by setting usb-polling=true in GRUB or ohci.conf.
120528cdc3dszhou */
120628cdc3dszhoustatic int
120728cdc3dszhouohci_is_polled(dev_info_t *dip)
120828cdc3dszhou{
120928cdc3dszhou	int ret;
121028cdc3dszhou	char *propval;
121128cdc3dszhou
121228cdc3dszhou	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
121328cdc3dszhou	    "usb-polling", &propval) != DDI_SUCCESS)
121428cdc3dszhou
121528cdc3dszhou		return (0);
121628cdc3dszhou
121728cdc3dszhou	ret = (strcmp(propval, "true") == 0);
121828cdc3dszhou	ddi_prop_free(propval);
121928cdc3dszhou
122028cdc3dszhou	return (ret);
122128cdc3dszhou}
122228cdc3dszhou
122328cdc3dszhoustatic void
122428cdc3dszhouohci_poll_intr(void *arg)
122528cdc3dszhou{
122628cdc3dszhou	/* poll every millisecond */
122728cdc3dszhou	for (;;) {
122828cdc3dszhou		(void) ohci_intr(arg, NULL);
122928cdc3dszhou		delay(drv_usectohz(1000));
123028cdc3dszhou	}
123128cdc3dszhou}
12327c478bdstevel@tonic-gate
12337c478bdstevel@tonic-gate/*
12347c478bdstevel@tonic-gate * ohci_register_intrs_and_init_mutex:
12357c478bdstevel@tonic-gate *
12367c478bdstevel@tonic-gate * Register interrupts and initialize each mutex and condition variables
12377c478bdstevel@tonic-gate */
12387c478bdstevel@tonic-gatestatic int
12397c478bdstevel@tonic-gateohci_register_intrs_and_init_mutex(ohci_state_t	*ohcip)
12407c478bdstevel@tonic-gate{
12419c75c6bgovinda	int	intr_types;
12427c478bdstevel@tonic-gate
12437c478bdstevel@tonic-gate	USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
12447c478bdstevel@tonic-gate	    "ohci_register_intrs_and_init_mutex:");
12457c478bdstevel@tonic-gate
1246af95cb8zhigang lu - Sun Microsystems - Beijing China	/*
1247af95cb8zhigang lu - Sun Microsystems - Beijing China	 * Sometimes the OHCI controller of ULI1575 southbridge
1248af95cb8zhigang lu - Sun Microsystems - Beijing China	 * could not receive SOF intrs when enable MSI. Hence
1249af95cb8zhigang lu - Sun Microsystems - Beijing China	 * MSI is disabled for this chip.
1250af95cb8zhigang lu - Sun Microsystems - Beijing China	 */
1251af95cb8zhigang lu - Sun Microsystems - Beijing China	if ((ohcip->ohci_vendor_id == PCI_ULI1575_VENID) &&
1252af95cb8zhigang lu - Sun Microsystems - Beijing China	    (ohcip->ohci_device_id == PCI_ULI1575_DEVID)) {
1253af95cb8zhigang lu - Sun Microsystems - Beijing China		ohcip->ohci_msi_enabled = B_FALSE;
1254af95cb8zhigang lu - Sun Microsystems - Beijing China	} else {
1255af95cb8zhigang lu - Sun Microsystems - Beijing China		ohcip->ohci_msi_enabled = ohci_enable_msi;
1256af95cb8zhigang lu - Sun Microsystems - Beijing China	}
1257af95cb8zhigang lu - Sun Microsystems - Beijing China
125828cdc3dszhou	if (ohci_is_polled(ohcip->ohci_dip)) {
125928cdc3dszhou		extern pri_t maxclsyspri;
126028cdc3dszhou
12618668df4lg		USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
126228cdc3dszhou		    "ohci_register_intrs_and_init_mutex: "
126328cdc3dszhou		    "running in simulated polled mode");
126428cdc3dszhou
126528cdc3dszhou		(void) thread_create(NULL, 0, ohci_poll_intr, ohcip, 0, &p0,
126628cdc3dszhou		    TS_RUN, maxclsyspri);
126728cdc3dszhou
126828cdc3dszhou		goto skip_intr;
126928cdc3dszhou	}
127028cdc3dszhou
12719c75c6bgovinda	/* Get supported interrupt types */
12729c75c6bgovinda	if (ddi_intr_get_supported_types(ohcip->ohci_dip,
12739c75c6bgovinda	    &intr_types) != DDI_SUCCESS) {
12747c478bdstevel@tonic-gate		USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
12757c478bdstevel@tonic-gate		    "ohci_register_intrs_and_init_mutex: "
12769c75c6bgovinda		    "ddi_intr_get_supported_types failed");
12777c478bdstevel@tonic-gate
12787c478bdstevel@tonic-gate		return (DDI_FAILURE);
12797c478bdstevel@tonic-gate	}
12807c478bdstevel@tonic-gate
12819c75c6bgovinda	USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
12829c75c6bgovinda	    "ohci_register_intrs_and_init_mutex: "
12839c75c6bgovinda	    "supported interrupt types 0x%x", intr_types);
12849c75c6bgovinda
1285af95cb8zhigang lu - Sun Microsystems - Beijing China	if ((intr_types & DDI_INTR_TYPE_MSI) && ohcip->ohci_msi_enabled) {
12869c75c6bgovinda		if (ohci_add_intrs(ohcip, DDI_INTR_TYPE_MSI)
12879c75c6bgovinda		    != DDI_SUCCESS) {
12889c75c6bgovinda			USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
12899c75c6bgovinda			    "ohci_register_intrs_and_init_mutex: MSI "
12909c75c6bgovinda			    "registration failed, trying FIXED interrupt \n");
12919c75c6bgovinda		} else {
12929c75c6bgovinda			USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
12939c75c6bgovinda			    "ohci_register_intrs_and_init_mutex: "
12949c75c6bgovinda			    "Using MSI interrupt type\n");
12957c478bdstevel@tonic-gate
12969c75c6bgovinda			ohcip->ohci_intr_type = DDI_INTR_TYPE_MSI;
12979c75c6bgovinda			ohcip->ohci_flags |= OHCI_INTR;
12989c75c6bgovinda		}
12999c75c6bgovinda	}
13009c75c6bgovinda
13019c75c6bgovinda	if ((!(ohcip->ohci_flags & OHCI_INTR)) &&
13029c75c6bgovinda	    (intr_types & DDI_INTR_TYPE_FIXED)) {
13039c75c6bgovinda		if (ohci_add_intrs(ohcip, DDI_INTR_TYPE_FIXED)
13049c75c6bgovinda		    != DDI_SUCCESS) {
13059c75c6bgovinda			USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13069c75c6bgovinda			    "ohci_register_intrs_and_init_mutex: "
13079c75c6bgovinda			    "FIXED interrupt registration failed\n");
13089c75c6bgovinda
13099c75c6bgovinda			return (DDI_FAILURE);
13109c75c6bgovinda		}
13119c75c6bgovinda
13129c75c6bgovinda		USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13137c478bdstevel@tonic-gate		    "ohci_register_intrs_and_init_mutex: "
13149c75c6bgovinda		    "Using FIXED interrupt type\n");
13159c75c6bgovinda
13169c75c6bgovinda		ohcip->ohci_intr_type = DDI_INTR_TYPE_FIXED;
13179c75c6bgovinda		ohcip->ohci_flags |= OHCI_INTR;
13189c75c6bgovinda	}
13199c75c6bgovinda
132028cdc3dszhouskip_intr:
13219c75c6bgovinda	/* Create prototype for SOF condition variable */
13229c75c6bgovinda	cv_init(&ohcip->ohci_SOF_cv, NULL, CV_DRIVER, NULL);
13239c75c6bgovinda
13249c75c6bgovinda	/* Semaphore to serialize opens and closes */
13259c75c6bgovinda	sema_init(&ohcip->ohci_ocsem, 1, NULL, SEMA_DRIVER, NULL);
13269c75c6bgovinda
13279c75c6bgovinda	return (DDI_SUCCESS);
13289c75c6bgovinda}
13299c75c6bgovinda
13309c75c6bgovinda
13319c75c6bgovinda/*
13329c75c6bgovinda * ohci_add_intrs:
13339c75c6bgovinda *
13349c75c6bgovinda * Register FIXED or MSI interrupts.
13359c75c6bgovinda */
13369c75c6bgovindastatic int
13373e1e1e6Toomas Soomeohci_add_intrs(ohci_state_t *ohcip, int intr_type)
13389c75c6bgovinda{
13399c75c6bgovinda	int	actual, avail, intr_size, count = 0;
134029aca3elc	int	i, flag, ret;
13419c75c6bgovinda
13429c75c6bgovinda	USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13439c75c6bgovinda	    "ohci_add_intrs: interrupt type 0x%x", intr_type);
13449c75c6bgovinda
13459c75c6bgovinda	/* Get number of interrupts */
13469c75c6bgovinda	ret = ddi_intr_get_nintrs(ohcip->ohci_dip, intr_type, &count);
13479c75c6bgovinda	if ((ret != DDI_SUCCESS) || (count == 0)) {
13489c75c6bgovinda		USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13499c75c6bgovinda		    "ohci_add_intrs: ddi_intr_get_nintrs() failure, "
13509c75c6bgovinda		    "ret: %d, count: %d", ret, count);
13519c75c6bgovinda
13529c75c6bgovinda		return (DDI_FAILURE);
13539c75c6bgovinda	}
13549c75c6bgovinda
13559c75c6bgovinda	/* Get number of available interrupts */
13569c75c6bgovinda	ret = ddi_intr_get_navail(ohcip->ohci_dip, intr_type, &avail);
13579c75c6bgovinda	if ((ret != DDI_SUCCESS) || (avail == 0)) {
13589c75c6bgovinda		USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13599c75c6bgovinda		    "ohci_add_intrs: ddi_intr_get_navail() failure, "
13609c75c6bgovinda		    "ret: %d, count: %d", ret, count);
13617c478bdstevel@tonic-gate
13627c478bdstevel@tonic-gate		return (DDI_FAILURE);
13637c478bdstevel@tonic-gate	}
13647c478bdstevel@tonic-gate
13659c75c6bgovinda	if (avail < count) {
13669c75c6bgovinda		USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13679c75c6bgovinda		    "ohci_add_intrs: ohci_add_intrs: nintrs () "
13689c75c6bgovinda		    "returned %d, navail returned %d\n", count, avail);
13699c75c6bgovinda	}
13709c75c6bgovinda
13719c75c6bgovinda	/* Allocate an array of interrupt handles */
13729c75c6bgovinda	intr_size = count * sizeof (ddi_intr_handle_t);
13739c75c6bgovinda	ohcip->ohci_htable = kmem_zalloc(intr_size, KM_SLEEP);
13749c75c6bgovinda
13759c75c6bgovinda	flag = (intr_type == DDI_INTR_TYPE_MSI) ?
13769c75c6bgovinda	    DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL;
13779c75c6bgovinda
13789c75c6bgovinda	/* call ddi_intr_alloc() */
13797c478bdstevel@tonic-gate	ret = ddi_intr_alloc(ohcip->ohci_dip, ohcip->ohci_htable,
13809c75c6bgovinda	    intr_type, 0, count, &actual, flag);
13817c478bdstevel@tonic-gate
13829c75c6bgovinda	if ((ret != DDI_SUCCESS) || (actual == 0)) {
13837c478bdstevel@tonic-gate		USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13849c75c6bgovinda		    "ohci_add_intrs: ddi_intr_alloc() failed %d", ret);
13857c478bdstevel@tonic-gate
13869c75c6bgovinda		kmem_free(ohcip->ohci_htable, intr_size);
13877c478bdstevel@tonic-gate
13887c478bdstevel@tonic-gate		return (DDI_FAILURE);
13897c478bdstevel@tonic-gate	}
13907c478bdstevel@tonic-gate
13919c75c6bgovinda	if (actual < count) {
13929c75c6bgovinda		USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
13939c75c6bgovinda		    "ohci_add_intrs: Requested: %d, Received: %d\n",
13949c75c6bgovinda		    count, actual);
13957c478bdstevel@tonic-gate
13969c75c6bgovinda		for (i = 0; i < actual; i++)
13979c75c6bgovinda			(void) ddi_intr_free(ohcip->ohci_htable[i]);
13989c75c6bgovinda
13999c75c6bgovinda		kmem_free(ohcip->ohci_htable, intr_size);
14009c75c6bgovinda
14019c75c6bgovinda		return (DDI_FAILURE);
14029c75c6bgovinda	}
14039c75c6bgovinda
14049c75c6bgovinda	ohcip->ohci_intr_cnt = actual;
14059c75c6bgovinda
14069c75c6bgovinda	if ((ret = ddi_intr_get_pri(ohcip->ohci_htable[0],
14079c75c6bgovinda	    &ohcip->ohci_intr_pri)) != DDI_SUCCESS) {
14087c478bdstevel@tonic-gate		USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
14099c75c6bgovinda		    "ohci_add_intrs: ddi_intr_get_pri() failed %d", ret);
14107c478bdstevel@tonic-gate
14119c75c6bgovinda		for (i = 0; i < actual; i++)
14129c75c6bgovinda			(void) ddi_intr_free(ohcip->ohci_htable[i]);
14139c75c6bgovinda
14149c75c6bgovinda		kmem_free(ohcip->ohci_htable, intr_size);
14157c478bdstevel@tonic-gate
14167c478bdstevel@tonic-gate		return (DDI_FAILURE);
14177c478bdstevel@tonic-gate	}
14187c478bdstevel@tonic-gate
14199c75c6bgovinda	USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
14209c75c6bgovinda	    "ohci_add_intrs: Supported Interrupt priority 0x%x",
14219c75c6bgovinda	    ohcip->ohci_intr_pri);
14227c478bdstevel@tonic-gate
14237c478bdstevel@tonic-gate	/* Test for high level mutex */
14247c478bdstevel@tonic-gate	if (ohcip->ohci_intr_pri >= ddi_intr_get_hilevel_pri()) {
14257c478bdstevel@tonic-gate		USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
14269c75c6bgovinda		    "ohci_add_intrs: Hi level interrupt not supported");
14279c75c6bgovinda
14289c75c6bgovinda		for (i = 0; i < actual; i++)
14299c75c6bgovinda			(void) ddi_intr_free(ohcip->ohci_htable[i]);
14307c478bdstevel@tonic-gate
14319c75c6bgovinda		kmem_free(ohcip->ohci_htable, intr_size);
14327c478bdstevel@tonic-gate
14337c478bdstevel@tonic-gate		return (DDI_FAILURE);
14347c478bdstevel@tonic-gate	}
14357c478bdstevel@tonic-gate
14367c478bdstevel@tonic-gate	/* Initialize the mutex */
14377c478bdstevel@tonic-gate	mutex_init(&ohcip->ohci_int_mutex, NULL, MUTEX_DRIVER,
1438a195726govinda	    DDI_INTR_PRI(ohcip->ohci_intr_pri));
14397c478bdstevel@tonic-gate
14409c75c6bgovinda	/* Call ddi_intr_add_handler() */
14419c75c6bgovinda	for (i = 0; i < actual; i++) {
14429c75c6bgovinda		if ((ret = ddi_intr_add_handler(ohcip->ohci_htable[i],
14439c75c6bgovinda		    ohci_intr, (caddr_t)ohcip,
14449c75c6bgovinda		    (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
14459c75c6bgovinda			USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
14469c75c6bgovinda			    "ohci_add_intrs: ddi_intr_add_handler() "
14479c75c6bgovinda			    "failed %d", ret);
14487c478bdstevel@tonic-gate
14499c75c6bgovinda			for (i = 0; i < actual; i++)
14509c75c6bgovinda				(void) ddi_intr_free(ohcip->ohci_htable[i]);
14517c478bdstevel@tonic-gate
14529c75c6bgovinda			mutex_destroy(&ohcip->ohci_int_mutex);
14539c75c6bgovinda			kmem_free(ohcip->ohci_htable, intr_size);
14549c75c6bgovinda
14559c75c6bgovinda			return (DDI_FAILURE);
14569c75c6bgovinda		}
14577c478bdstevel@tonic-gate	}
14587c478bdstevel@tonic-gate
14599c75c6bgovinda	if ((ret = ddi_intr_get_cap(ohcip->ohci_htable[0],
14609c75c6bgovinda	    &ohcip->ohci_intr_cap)) != DDI_SUCCESS) {
14617c478bdstevel@tonic-gate		USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
14629c75c6bgovinda		    "ohci_add_intrs: ddi_intr_get_cap() failed %d", ret);
14639c75c6bgovinda
14649c75c6bgovinda		for (i = 0; i < actual; i++) {
14659c75c6bgovinda			(void) ddi_intr_remove_handler(ohcip->ohci_htable[i]);
14669c75c6bgovinda			(void) ddi_intr_free(ohcip->ohci_htable[i]);
14679c75c6bgovinda		}
14687c478bdstevel@tonic-gate
14697c478bdstevel@tonic-gate		mutex_destroy(&ohcip->ohci_int_mutex);
14709c75c6bgovinda		kmem_free(ohcip->ohci_htable, intr_size);
14717c478bdstevel@tonic-gate
14727c478bdstevel@tonic-gate		return (DDI_FAILURE);
14737c478bdstevel@tonic-gate	}
14747c478bdstevel@tonic-gate
14759c75c6bgovinda	/* Enable all interrupts */
14769c75c6bgovinda	if (ohcip->ohci_intr_cap & DDI_INTR_FLAG_BLOCK) {
14779c75c6bgovinda		/* Call ddi_intr_block_enable() for MSI interrupts */
14789c75c6bgovinda		(void) ddi_intr_block_enable(ohcip->ohci_htable,
14799c75c6bgovinda		    ohcip->ohci_intr_cnt);
14809c75c6bgovinda	} else {
14819c75c6bgovinda		/* Call ddi_intr_enable for MSI or FIXED interrupts */
14829c75c6bgovinda		for (i = 0; i < ohcip->ohci_intr_cnt; i++)
14839c75c6bgovinda			(void) ddi_intr_enable(ohcip->ohci_htable[i]);
14849c75c6bgovinda	}
14857c478bdstevel@tonic-gate
14867c478bdstevel@tonic-gate	return (DDI_SUCCESS);
14877c478bdstevel@tonic-gate}
14887c478bdstevel@tonic-gate
14897c478bdstevel@tonic-gate
14907c478bdstevel@tonic-gate/*
14917c478bdstevel@tonic-gate * ohci_init_ctlr:
14927c478bdstevel@tonic-gate *
14937c478bdstevel@tonic-gate * Initialize the Host Controller (HC).
14947c478bdstevel@tonic-gate */
14957c478bdstevel@tonic-gatestatic int
14967c478bdstevel@tonic-gateohci_init_ctlr(ohci_state_t	*ohcip)
14977c478bdstevel@tonic-gate{
14987c478bdstevel@tonic-gate	int			revision, curr_control, max_packet = 0;
14997c478bdstevel@tonic-gate	clock_t			sof_time_wait;
1500cbab2b2lg	int			retry = 0;
1501cbab2b2lg	int			ohci_frame_interval;
15027c478bdstevel@tonic-gate
15037c478bdstevel@tonic-gate	USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl, "ohci_init_ctlr:");
15047c478bdstevel@tonic-gate
15057c478bdstevel@tonic-gate	if (ohci_take_control(ohcip) != DDI_SUCCESS) {
15067c478bdstevel@tonic-gate		USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
15077c478bdstevel@tonic-gate		    "ohci_init_ctlr: ohci_take_control failed\n");
15087c478bdstevel@tonic-gate
15097c478bdstevel@tonic-gate		return (DDI_FAILURE);
15107c478bdstevel@tonic-gate	}
15117c478bdstevel@tonic-gate
15127c478bdstevel@tonic-gate	/*
15137c478bdstevel@tonic-gate	 * Soft reset the host controller.
15147c478bdstevel@tonic-gate	 *
15157c478bdstevel@tonic-gate	 * On soft reset, the ohci host controller moves to the
15167c478bdstevel@tonic-gate	 * USB Suspend state in which most of the ohci operational
15177c478bdstevel@tonic-gate	 * registers are reset except stated ones. The soft reset
15187c478bdstevel@tonic-gate	 * doesn't cause a reset to the ohci root hub and even no
15197c478bdstevel@tonic-gate	 * subsequent reset signaling should be asserterd to its
15207c478bdstevel@tonic-gate	 * down stream.
15217c478bdstevel@tonic-gate	 */
15227c478bdstevel@tonic-gate	Set_OpReg(hcr_cmd_status, HCR_STATUS_RESET);
15237c478bdstevel@tonic-gate
152429aca3elc	mutex_exit(&ohcip->ohci_int_mutex);
15257c478bdstevel@tonic-gate	/* Wait 10ms for reset to complete */
152629aca3elc	delay(drv_usectohz(OHCI_RESET_TIMEWAIT));
152729aca3elc	mutex_enter(&ohcip->ohci_int_mutex);
15287c478bdstevel@tonic-gate
15297c478bdstevel@tonic-gate	/*
15307c478bdstevel@tonic-gate	 * Do hard reset the host controller.
15317c478bdstevel@tonic-gate	 *
15327c478bdstevel@tonic-gate	 * Now perform USB reset in order to reset the ohci root
15337c478bdstevel@tonic-gate	 * hub.
15347c478bdstevel@tonic-gate	 */
15357c478bdstevel@tonic-gate	Set_OpReg(hcr_control, HCR_CONTROL_RESET);
15367c478bdstevel@tonic-gate
15377c478bdstevel@tonic-gate	/*
15387c478bdstevel@tonic-gate	 * According to Section 5.1.2.3 of the specification, the
15397c478bdstevel@tonic-gate	 * host controller will go into suspend state immediately
15407c478bdstevel@tonic-gate	 * after the reset.
15417c478bdstevel@tonic-gate	 */
15427c478bdstevel@tonic-gate
15437c478bdstevel@tonic-gate	/* Verify the version number */
15447c478bdstevel@tonic-gate	revision = Get_OpReg(hcr_revision);
15457c478bdstevel@tonic-gate
15467c478bdstevel@tonic-gate	if ((revision & HCR_REVISION_MASK) != HCR_REVISION_1_0) {
15477c478bdstevel@tonic-gate
15487c478bdstevel@tonic-gate		return (DDI_FAILURE);
15497c478bdstevel@tonic-gate	}
15507c478bdstevel@tonic-gate
15517c478bdstevel@tonic-gate	USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
15527c478bdstevel@tonic-gate	    "ohci_init_ctlr: Revision verified");
1553