xref: /onnv-gate/usr/src/uts/common/io/usb/hcd/ehci/ehci_polled.c (revision 9095:ef4ae1685182)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51500Ssl147100  * Common Development and Distribution License (the "License").
61500Ssl147100  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*9095SZhigang.Lu@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * EHCI Host Controller Driver (EHCI)
280Sstevel@tonic-gate  *
290Sstevel@tonic-gate  * The EHCI driver is a software driver which interfaces to the Universal
300Sstevel@tonic-gate  * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
310Sstevel@tonic-gate  * the Host Controller is defined by the EHCI Host Controller Interface.
320Sstevel@tonic-gate  *
330Sstevel@tonic-gate  * This module contains the specific EHCI code used in POLLED mode. This
340Sstevel@tonic-gate  * code is in a separate file since it will never become part of the EHCI
350Sstevel@tonic-gate  * driver.
360Sstevel@tonic-gate  */
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h>
390Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h>
400Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h>
410Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_intr.h>
420Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_util.h>
430Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_polled.h>
440Sstevel@tonic-gate 
45*9095SZhigang.Lu@Sun.COM #ifndef __sparc
46*9095SZhigang.Lu@Sun.COM extern void invalidate_cache();
47*9095SZhigang.Lu@Sun.COM #endif
48*9095SZhigang.Lu@Sun.COM 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * Internal Function Prototypes
510Sstevel@tonic-gate  */
520Sstevel@tonic-gate 
530Sstevel@tonic-gate /* Polled initialization routines */
540Sstevel@tonic-gate static int	ehci_polled_init(
550Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph,
560Sstevel@tonic-gate 				ehci_state_t		*ehcip,
570Sstevel@tonic-gate 				usb_console_info_impl_t	*console_input_info);
580Sstevel@tonic-gate 
590Sstevel@tonic-gate /* Polled deinitialization routines */
600Sstevel@tonic-gate static int	ehci_polled_fini(ehci_polled_t		*ehci_polledp);
610Sstevel@tonic-gate 
620Sstevel@tonic-gate /* Polled save state routines */
630Sstevel@tonic-gate static void	ehci_polled_save_state(ehci_polled_t	*ehci_polledp);
640Sstevel@tonic-gate 
650Sstevel@tonic-gate /* Polled restore state routines */
660Sstevel@tonic-gate static void	ehci_polled_restore_state(ehci_polled_t	*ehci_polledp);
670Sstevel@tonic-gate static void	ehci_polled_stop_processing(
680Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp);
690Sstevel@tonic-gate static void	ehci_polled_start_processing(
700Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp);
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /* Polled read routines */
730Sstevel@tonic-gate static int	ehci_polled_process_active_intr_qtd_list(
740Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp);
750Sstevel@tonic-gate static int	ehci_polled_handle_normal_qtd(
760Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp,
770Sstevel@tonic-gate 				ehci_qtd_t		*qtd);
78*9095SZhigang.Lu@Sun.COM static void	ehci_polled_insert_intr_qtd(
790Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp,
800Sstevel@tonic-gate 				ehci_qtd_t		*qtd);
81*9095SZhigang.Lu@Sun.COM static void	ehci_polled_insert_bulk_qtd(
82*9095SZhigang.Lu@Sun.COM 				ehci_polled_t		*ehci_polledp);
830Sstevel@tonic-gate static void	ehci_polled_fill_in_qtd(
840Sstevel@tonic-gate 				ehci_state_t		*ehcip,
850Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
860Sstevel@tonic-gate 				uint_t			qtd_ctrl,
871500Ssl147100 				size_t			qtd_dma_offs,
880Sstevel@tonic-gate 				size_t			qtd_length,
890Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw);
900Sstevel@tonic-gate static void	ehci_polled_insert_qtd_on_tw(
910Sstevel@tonic-gate 				ehci_state_t		*ehcip,
920Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
930Sstevel@tonic-gate 				ehci_qtd_t		*qtd);
940Sstevel@tonic-gate static ehci_qtd_t *ehci_polled_create_done_qtd_list(
950Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp);
960Sstevel@tonic-gate static void	ehci_polled_insert_qtd_into_active_intr_qtd_list(
970Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp,
980Sstevel@tonic-gate 				ehci_qtd_t		*curr_qtd);
990Sstevel@tonic-gate static void	ehci_polled_remove_qtd_from_active_intr_qtd_list(
1000Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp,
1010Sstevel@tonic-gate 				ehci_qtd_t		*curr_qtd);
1020Sstevel@tonic-gate static void	ehci_polled_traverse_qtds(
1030Sstevel@tonic-gate 				ehci_polled_t		*ehci_polledp,
1040Sstevel@tonic-gate 				usba_pipe_handle_data_t	*ph);
1050Sstevel@tonic-gate static void	ehci_polled_finish_interrupt(
1060Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1070Sstevel@tonic-gate 				uint_t			intr);
108*9095SZhigang.Lu@Sun.COM static int	ehci_polled_create_tw(
109*9095SZhigang.Lu@Sun.COM 				ehci_polled_t		*ehci_polledp,
110*9095SZhigang.Lu@Sun.COM 				usba_pipe_handle_data_t	*ph,
111*9095SZhigang.Lu@Sun.COM 				usb_flags_t		usb_flags);
112*9095SZhigang.Lu@Sun.COM static void	ehci_polled_insert_async_qh(
113*9095SZhigang.Lu@Sun.COM 				ehci_state_t		*ehcip,
114*9095SZhigang.Lu@Sun.COM 				ehci_pipe_private_t	*pp);
115*9095SZhigang.Lu@Sun.COM static void	ehci_polled_remove_async_qh(
116*9095SZhigang.Lu@Sun.COM 				ehci_state_t		*ehcip,
117*9095SZhigang.Lu@Sun.COM 				ehci_pipe_private_t	*pp);
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate /*
1200Sstevel@tonic-gate  * POLLED entry points
1210Sstevel@tonic-gate  *
1220Sstevel@tonic-gate  * These functions are entry points into the POLLED code.
1230Sstevel@tonic-gate  */
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate /*
1260Sstevel@tonic-gate  * ehci_hcdi_polled_input_init:
1270Sstevel@tonic-gate  *
128*9095SZhigang.Lu@Sun.COM  * This is the initialization routine for handling the USB input device
1290Sstevel@tonic-gate  * in POLLED mode.  This routine is not called from POLLED mode, so
1300Sstevel@tonic-gate  * it is OK to acquire mutexes.
1310Sstevel@tonic-gate  */
1320Sstevel@tonic-gate int
ehci_hcdi_polled_input_init(usba_pipe_handle_data_t * ph,uchar_t ** polled_buf,usb_console_info_impl_t * console_input_info)1330Sstevel@tonic-gate ehci_hcdi_polled_input_init(
1340Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
1350Sstevel@tonic-gate 	uchar_t			**polled_buf,
1360Sstevel@tonic-gate 	usb_console_info_impl_t	*console_input_info)
1370Sstevel@tonic-gate {
1380Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp;
1390Sstevel@tonic-gate 	ehci_state_t		*ehcip;
1400Sstevel@tonic-gate 	int			ret;
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	ehcip = ehci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	/*
1450Sstevel@tonic-gate 	 * Grab the ehci_int_mutex so that things don't change on us
1460Sstevel@tonic-gate 	 * if an interrupt comes in.
1470Sstevel@tonic-gate 	 */
1480Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	ret = ehci_polled_init(ph, ehcip, console_input_info);
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	if (ret != USB_SUCCESS) {
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 		/* Allow interrupts to continue */
1550Sstevel@tonic-gate 		mutex_exit(&ehcip->ehci_int_mutex);
1560Sstevel@tonic-gate 		return (ret);
1570Sstevel@tonic-gate 	}
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	ehci_polledp = (ehci_polled_t *)console_input_info->uci_private;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	/*
1620Sstevel@tonic-gate 	 * Mark the structure so that if we are using it, we don't free
1630Sstevel@tonic-gate 	 * the structures if one of them is unplugged.
1640Sstevel@tonic-gate 	 */
1650Sstevel@tonic-gate 	ehci_polledp->ehci_polled_flags |= POLLED_INPUT_MODE;
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	/* increase the counter for keyboard connected */
1680Sstevel@tonic-gate 	ehcip->ehci_polled_kbd_count ++;
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	/*
1710Sstevel@tonic-gate 	 * This is the buffer we will copy characters into. It will be
1720Sstevel@tonic-gate 	 * copied into at this layer, so we need to keep track of it.
1730Sstevel@tonic-gate 	 */
1740Sstevel@tonic-gate 	ehci_polledp->ehci_polled_buf =
1750Sstevel@tonic-gate 	    (uchar_t *)kmem_zalloc(POLLED_RAW_BUF_SIZE, KM_SLEEP);
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	*polled_buf = ehci_polledp->ehci_polled_buf;
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	/*
1800Sstevel@tonic-gate 	 * This is a software workaround to fix schizo hardware bug.
1810Sstevel@tonic-gate 	 * Existence of "no-prom-cdma-sync"  property means consistent
1820Sstevel@tonic-gate 	 * dma sync should not be done while in prom or polled mode.
1830Sstevel@tonic-gate 	 */
1840Sstevel@tonic-gate 	if (ddi_prop_exists(DDI_DEV_T_ANY, ehcip->ehci_dip,
1850Sstevel@tonic-gate 	    DDI_PROP_NOTPROM, "no-prom-cdma-sync")) {
1860Sstevel@tonic-gate 		ehci_polledp->ehci_polled_no_sync_flag = B_TRUE;
1870Sstevel@tonic-gate 	}
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	/* Allow interrupts to continue */
1900Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	return (USB_SUCCESS);
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate /*
1970Sstevel@tonic-gate  * ehci_hcdi_polled_input_fini:
1980Sstevel@tonic-gate  */
1990Sstevel@tonic-gate int
ehci_hcdi_polled_input_fini(usb_console_info_impl_t * info)2000Sstevel@tonic-gate ehci_hcdi_polled_input_fini(usb_console_info_impl_t *info)
2010Sstevel@tonic-gate {
2020Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp;
2030Sstevel@tonic-gate 	ehci_state_t		*ehcip;
2040Sstevel@tonic-gate 	int			ret;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	ehci_polledp = (ehci_polled_t *)info->uci_private;
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	ehcip = ehci_polledp->ehci_polled_ehcip;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	mutex_enter(&ehcip->ehci_int_mutex);
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	/*
2130Sstevel@tonic-gate 	 * Reset the POLLED_INPUT_MODE flag so that we can tell if
2140Sstevel@tonic-gate 	 * this structure is in use in the ehci_polled_fini routine.
2150Sstevel@tonic-gate 	 */
2160Sstevel@tonic-gate 	ehci_polledp->ehci_polled_flags &= ~POLLED_INPUT_MODE;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	/* decrease the counter for keyboard disconnected */
2190Sstevel@tonic-gate 	ehcip->ehci_polled_kbd_count --;
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	/* Free the buffer that we copied data into */
2220Sstevel@tonic-gate 	kmem_free(ehci_polledp->ehci_polled_buf, POLLED_RAW_BUF_SIZE);
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	ret = ehci_polled_fini(ehci_polledp);
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	mutex_exit(&ehcip->ehci_int_mutex);
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	return (ret);
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate /*
2330Sstevel@tonic-gate  * ehci_hcdi_polled_input_enter:
2340Sstevel@tonic-gate  *
2350Sstevel@tonic-gate  * This is where we enter into POLLED mode.  This routine sets up
2360Sstevel@tonic-gate  * everything so that calls to	ehci_hcdi_polled_read will return
2370Sstevel@tonic-gate  * characters.
2380Sstevel@tonic-gate  */
2390Sstevel@tonic-gate int
ehci_hcdi_polled_input_enter(usb_console_info_impl_t * info)2400Sstevel@tonic-gate ehci_hcdi_polled_input_enter(usb_console_info_impl_t *info)
2410Sstevel@tonic-gate {
2420Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp;
243*9095SZhigang.Lu@Sun.COM 	ehci_state_t		*ehcip;
244*9095SZhigang.Lu@Sun.COM 	usba_pipe_handle_data_t	*ph;
245*9095SZhigang.Lu@Sun.COM 	ehci_pipe_private_t	*pp;
246*9095SZhigang.Lu@Sun.COM 	int			pipe_attr;
2470Sstevel@tonic-gate 
248*9095SZhigang.Lu@Sun.COM #ifndef lint
249*9095SZhigang.Lu@Sun.COM 	_NOTE(NO_COMPETING_THREADS_NOW);
250*9095SZhigang.Lu@Sun.COM #endif
2510Sstevel@tonic-gate 	ehci_polledp = (ehci_polled_t *)info->uci_private;
252*9095SZhigang.Lu@Sun.COM 	ehcip = ehci_polledp->ehci_polled_ehcip;
253*9095SZhigang.Lu@Sun.COM 	ph = ehci_polledp->ehci_polled_input_pipe_handle;
254*9095SZhigang.Lu@Sun.COM 	pp = (ehci_pipe_private_t *)ph->p_hcd_private;
255*9095SZhigang.Lu@Sun.COM 
256*9095SZhigang.Lu@Sun.COM 	pipe_attr = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK;
257*9095SZhigang.Lu@Sun.COM #ifndef lint
258*9095SZhigang.Lu@Sun.COM 	_NOTE(COMPETING_THREADS_NOW);
259*9095SZhigang.Lu@Sun.COM #endif
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	ehci_polledp->ehci_polled_entry++;
2620Sstevel@tonic-gate 	/*
2630Sstevel@tonic-gate 	 * If the controller is already switched over, just return
2640Sstevel@tonic-gate 	 */
2650Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_entry > 1) {
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 		return (USB_SUCCESS);
2680Sstevel@tonic-gate 	}
2690Sstevel@tonic-gate 
270*9095SZhigang.Lu@Sun.COM 	switch (pipe_attr) {
271*9095SZhigang.Lu@Sun.COM 	case USB_EP_ATTR_INTR:
272*9095SZhigang.Lu@Sun.COM 		ehci_polled_save_state(ehci_polledp);
273*9095SZhigang.Lu@Sun.COM 		break;
274*9095SZhigang.Lu@Sun.COM 	case USB_EP_ATTR_BULK:
275*9095SZhigang.Lu@Sun.COM #ifndef lint
276*9095SZhigang.Lu@Sun.COM 	_NOTE(NO_COMPETING_THREADS_NOW);
277*9095SZhigang.Lu@Sun.COM #endif
278*9095SZhigang.Lu@Sun.COM 		Set_OpReg(ehci_command, (Get_OpReg(ehci_command) &
279*9095SZhigang.Lu@Sun.COM 		    ~(EHCI_CMD_PERIODIC_SCHED_ENABLE |
280*9095SZhigang.Lu@Sun.COM 		    EHCI_CMD_ASYNC_SCHED_ENABLE)));
281*9095SZhigang.Lu@Sun.COM 		/* Wait for few milliseconds */
282*9095SZhigang.Lu@Sun.COM 		drv_usecwait(EHCI_POLLED_TIMEWAIT);
283*9095SZhigang.Lu@Sun.COM 
284*9095SZhigang.Lu@Sun.COM 		ehci_polled_insert_async_qh(ehcip, pp);
285*9095SZhigang.Lu@Sun.COM 
286*9095SZhigang.Lu@Sun.COM 		Set_OpReg(ehci_command,
287*9095SZhigang.Lu@Sun.COM 		    (Get_OpReg(ehci_command) | EHCI_CMD_ASYNC_SCHED_ENABLE));
288*9095SZhigang.Lu@Sun.COM #ifndef lint
289*9095SZhigang.Lu@Sun.COM 	_NOTE(COMPETING_THREADS_NOW);
290*9095SZhigang.Lu@Sun.COM #endif
291*9095SZhigang.Lu@Sun.COM 		/* Wait for few milliseconds */
292*9095SZhigang.Lu@Sun.COM 		drv_usecwait(EHCI_POLLED_TIMEWAIT);
293*9095SZhigang.Lu@Sun.COM 		break;
294*9095SZhigang.Lu@Sun.COM 	default:
295*9095SZhigang.Lu@Sun.COM 		return (USB_FAILURE);
296*9095SZhigang.Lu@Sun.COM 	}
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	ehci_polledp->ehci_polled_flags |= POLLED_INPUT_MODE_INUSE;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	return (USB_SUCCESS);
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate /*
3050Sstevel@tonic-gate  * ehci_hcdi_polled_input_exit:
3060Sstevel@tonic-gate  *
3070Sstevel@tonic-gate  * This is where we exit POLLED mode. This routine restores
3080Sstevel@tonic-gate  * everything that is needed to continue operation.
3090Sstevel@tonic-gate  */
3100Sstevel@tonic-gate int
ehci_hcdi_polled_input_exit(usb_console_info_impl_t * info)3110Sstevel@tonic-gate ehci_hcdi_polled_input_exit(usb_console_info_impl_t *info)
3120Sstevel@tonic-gate {
3130Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp;
314*9095SZhigang.Lu@Sun.COM 	ehci_state_t		*ehcip;
315*9095SZhigang.Lu@Sun.COM 	ehci_pipe_private_t	*pp;
316*9095SZhigang.Lu@Sun.COM 	int			pipe_attr;
3170Sstevel@tonic-gate 
318*9095SZhigang.Lu@Sun.COM #ifndef lint
319*9095SZhigang.Lu@Sun.COM 	_NOTE(NO_COMPETING_THREADS_NOW);
320*9095SZhigang.Lu@Sun.COM #endif
3210Sstevel@tonic-gate 	ehci_polledp = (ehci_polled_t *)info->uci_private;
322*9095SZhigang.Lu@Sun.COM 	ehcip = ehci_polledp->ehci_polled_ehcip;
323*9095SZhigang.Lu@Sun.COM 	pp = (ehci_pipe_private_t *)ehci_polledp->
324*9095SZhigang.Lu@Sun.COM 	    ehci_polled_input_pipe_handle->p_hcd_private;
325*9095SZhigang.Lu@Sun.COM 
326*9095SZhigang.Lu@Sun.COM 	pipe_attr = ehci_polledp->ehci_polled_input_pipe_handle->
327*9095SZhigang.Lu@Sun.COM 	    p_ep.bmAttributes & USB_EP_ATTR_MASK;
328*9095SZhigang.Lu@Sun.COM #ifndef lint
329*9095SZhigang.Lu@Sun.COM 	_NOTE(COMPETING_THREADS_NOW);
330*9095SZhigang.Lu@Sun.COM #endif
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	ehci_polledp->ehci_polled_entry--;
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	/*
3350Sstevel@tonic-gate 	 * If there are still outstanding "enters", just return
3360Sstevel@tonic-gate 	 */
3370Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_entry > 0) {
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 		return (USB_SUCCESS);
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	ehci_polledp->ehci_polled_flags &= ~POLLED_INPUT_MODE_INUSE;
3430Sstevel@tonic-gate 
344*9095SZhigang.Lu@Sun.COM 	switch (pipe_attr & USB_EP_ATTR_MASK) {
345*9095SZhigang.Lu@Sun.COM 	case USB_EP_ATTR_INTR:
346*9095SZhigang.Lu@Sun.COM 		ehci_polled_restore_state(ehci_polledp);
347*9095SZhigang.Lu@Sun.COM 		break;
348*9095SZhigang.Lu@Sun.COM 	case USB_EP_ATTR_BULK:
349*9095SZhigang.Lu@Sun.COM #ifndef lint
350*9095SZhigang.Lu@Sun.COM 	_NOTE(NO_COMPETING_THREADS_NOW);
351*9095SZhigang.Lu@Sun.COM #endif
352*9095SZhigang.Lu@Sun.COM 		Set_OpReg(ehci_command, (Get_OpReg(ehci_command) &
353*9095SZhigang.Lu@Sun.COM 		    ~(EHCI_CMD_PERIODIC_SCHED_ENABLE |
354*9095SZhigang.Lu@Sun.COM 		    EHCI_CMD_ASYNC_SCHED_ENABLE)));
355*9095SZhigang.Lu@Sun.COM 		/* Wait for few milliseconds */
356*9095SZhigang.Lu@Sun.COM 		drv_usecwait(EHCI_POLLED_TIMEWAIT);
357*9095SZhigang.Lu@Sun.COM 
358*9095SZhigang.Lu@Sun.COM 		ehci_polled_remove_async_qh(ehcip, pp);
359*9095SZhigang.Lu@Sun.COM 
360*9095SZhigang.Lu@Sun.COM 		Set_OpReg(ehci_command,
361*9095SZhigang.Lu@Sun.COM 		    (Get_OpReg(ehci_command) | EHCI_CMD_ASYNC_SCHED_ENABLE |
362*9095SZhigang.Lu@Sun.COM 		    EHCI_CMD_ASYNC_SCHED_ENABLE));
363*9095SZhigang.Lu@Sun.COM #ifndef lint
364*9095SZhigang.Lu@Sun.COM 	_NOTE(COMPETING_THREADS_NOW);
365*9095SZhigang.Lu@Sun.COM #endif
366*9095SZhigang.Lu@Sun.COM 		/* Wait for few milliseconds */
367*9095SZhigang.Lu@Sun.COM 		drv_usecwait(EHCI_POLLED_TIMEWAIT);
368*9095SZhigang.Lu@Sun.COM 		break;
369*9095SZhigang.Lu@Sun.COM 	default:
370*9095SZhigang.Lu@Sun.COM 		return (USB_FAILURE);
371*9095SZhigang.Lu@Sun.COM 
372*9095SZhigang.Lu@Sun.COM 	}
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	return (USB_SUCCESS);
3750Sstevel@tonic-gate }
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate /*
3790Sstevel@tonic-gate  * ehci_hcdi_polled_read:
3800Sstevel@tonic-gate  *
3810Sstevel@tonic-gate  * Get a key character
3820Sstevel@tonic-gate  */
3830Sstevel@tonic-gate int
ehci_hcdi_polled_read(usb_console_info_impl_t * info,uint_t * num_characters)3840Sstevel@tonic-gate ehci_hcdi_polled_read(
3850Sstevel@tonic-gate 	usb_console_info_impl_t	*info,
3860Sstevel@tonic-gate 	uint_t			*num_characters)
3870Sstevel@tonic-gate {
3880Sstevel@tonic-gate 	ehci_state_t		*ehcip;
3890Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp;
3900Sstevel@tonic-gate 	uint_t			intr;
391*9095SZhigang.Lu@Sun.COM 	int			pipe_attr;
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	ehci_polledp = (ehci_polled_t *)info->uci_private;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	ehcip = ehci_polledp->ehci_polled_ehcip;
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate #ifndef lint
3980Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
3990Sstevel@tonic-gate #endif
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	*num_characters = 0;
4020Sstevel@tonic-gate 
403*9095SZhigang.Lu@Sun.COM 	pipe_attr = ehci_polledp->ehci_polled_input_pipe_handle->
404*9095SZhigang.Lu@Sun.COM 	    p_ep.bmAttributes & USB_EP_ATTR_MASK;
405*9095SZhigang.Lu@Sun.COM 
406*9095SZhigang.Lu@Sun.COM 	if (pipe_attr == USB_EP_ATTR_BULK) {
407*9095SZhigang.Lu@Sun.COM 		ehci_polled_insert_bulk_qtd(ehci_polledp);
408*9095SZhigang.Lu@Sun.COM 	}
409*9095SZhigang.Lu@Sun.COM 
4100Sstevel@tonic-gate 	intr = ((Get_OpReg(ehci_status) & Get_OpReg(ehci_interrupt)) &
4110Sstevel@tonic-gate 	    (EHCI_INTR_FRAME_LIST_ROLLOVER |
4120Sstevel@tonic-gate 	    EHCI_INTR_USB | EHCI_INTR_USB_ERROR));
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	/*
4150Sstevel@tonic-gate 	 * Check whether any frame list rollover interrupt is pending
4160Sstevel@tonic-gate 	 * and if it is pending, process this interrupt.
4170Sstevel@tonic-gate 	 */
4180Sstevel@tonic-gate 	if (intr & EHCI_INTR_FRAME_LIST_ROLLOVER) {
4190Sstevel@tonic-gate 		/* Check any frame list rollover interrupt is pending */
4200Sstevel@tonic-gate 		ehci_handle_frame_list_rollover(ehcip);
4210Sstevel@tonic-gate 		ehci_polled_finish_interrupt(ehcip,
4220Sstevel@tonic-gate 		    EHCI_INTR_FRAME_LIST_ROLLOVER);
4230Sstevel@tonic-gate 	}
4240Sstevel@tonic-gate 
425*9095SZhigang.Lu@Sun.COM 	/* Process any QTD's on the active interrupt qtd list */
426*9095SZhigang.Lu@Sun.COM 	*num_characters =
427*9095SZhigang.Lu@Sun.COM 	    ehci_polled_process_active_intr_qtd_list(ehci_polledp);
428*9095SZhigang.Lu@Sun.COM 
429*9095SZhigang.Lu@Sun.COM #ifndef lint
430*9095SZhigang.Lu@Sun.COM 	_NOTE(COMPETING_THREADS_NOW);
431*9095SZhigang.Lu@Sun.COM #endif
432*9095SZhigang.Lu@Sun.COM 
433*9095SZhigang.Lu@Sun.COM 	return (USB_SUCCESS);
434*9095SZhigang.Lu@Sun.COM }
435*9095SZhigang.Lu@Sun.COM 
436*9095SZhigang.Lu@Sun.COM 
437*9095SZhigang.Lu@Sun.COM /*
438*9095SZhigang.Lu@Sun.COM  * ehci_hcdi_polled_output_init:
439*9095SZhigang.Lu@Sun.COM  *
440*9095SZhigang.Lu@Sun.COM  * This is the initialization routine for handling the USB serial output
441*9095SZhigang.Lu@Sun.COM  * in POLLED mode.  This routine is not called from POLLED mode, so
442*9095SZhigang.Lu@Sun.COM  * it is OK to acquire mutexes.
443*9095SZhigang.Lu@Sun.COM  */
444*9095SZhigang.Lu@Sun.COM int
ehci_hcdi_polled_output_init(usba_pipe_handle_data_t * ph,usb_console_info_impl_t * console_output_info)445*9095SZhigang.Lu@Sun.COM ehci_hcdi_polled_output_init(
446*9095SZhigang.Lu@Sun.COM 	usba_pipe_handle_data_t	*ph,
447*9095SZhigang.Lu@Sun.COM 	usb_console_info_impl_t	*console_output_info)
448*9095SZhigang.Lu@Sun.COM {
449*9095SZhigang.Lu@Sun.COM 	ehci_polled_t		*ehci_polledp;
450*9095SZhigang.Lu@Sun.COM 	ehci_state_t		*ehcip;
451*9095SZhigang.Lu@Sun.COM 	ehci_pipe_private_t	*pp;
452*9095SZhigang.Lu@Sun.COM 	int			ret;
453*9095SZhigang.Lu@Sun.COM 
454*9095SZhigang.Lu@Sun.COM 	ehcip = ehci_obtain_state(ph->p_usba_device->usb_root_hub_dip);
455*9095SZhigang.Lu@Sun.COM 
456*9095SZhigang.Lu@Sun.COM 	/*
457*9095SZhigang.Lu@Sun.COM 	 * Grab the ehci_int_mutex so that things don't change on us
458*9095SZhigang.Lu@Sun.COM 	 * if an interrupt comes in.
459*9095SZhigang.Lu@Sun.COM 	 */
460*9095SZhigang.Lu@Sun.COM 	mutex_enter(&ehcip->ehci_int_mutex);
461*9095SZhigang.Lu@Sun.COM 
462*9095SZhigang.Lu@Sun.COM 	ret = ehci_polled_init(ph, ehcip, console_output_info);
463*9095SZhigang.Lu@Sun.COM 
464*9095SZhigang.Lu@Sun.COM 	if (ret != USB_SUCCESS) {
465*9095SZhigang.Lu@Sun.COM 
466*9095SZhigang.Lu@Sun.COM 		/* Allow interrupts to continue */
467*9095SZhigang.Lu@Sun.COM 		mutex_exit(&ehcip->ehci_int_mutex);
468*9095SZhigang.Lu@Sun.COM 
469*9095SZhigang.Lu@Sun.COM 		return (ret);
470*9095SZhigang.Lu@Sun.COM 	}
471*9095SZhigang.Lu@Sun.COM 
472*9095SZhigang.Lu@Sun.COM 	ehci_polledp = (ehci_polled_t *)console_output_info->uci_private;
473*9095SZhigang.Lu@Sun.COM 	/*
474*9095SZhigang.Lu@Sun.COM 	 * Mark the structure so that if we are using it, we don't free
475*9095SZhigang.Lu@Sun.COM 	 * the structures if one of them is unplugged.
476*9095SZhigang.Lu@Sun.COM 	 */
477*9095SZhigang.Lu@Sun.COM 	ehci_polledp->ehci_polled_flags |= POLLED_OUTPUT_MODE;
478*9095SZhigang.Lu@Sun.COM 
479*9095SZhigang.Lu@Sun.COM 	/*
480*9095SZhigang.Lu@Sun.COM 	 * Insert the Endpoint Descriptor to appropriate endpoint list.
481*9095SZhigang.Lu@Sun.COM 	 */
482*9095SZhigang.Lu@Sun.COM 	pp = (ehci_pipe_private_t *)ehci_polledp->
483*9095SZhigang.Lu@Sun.COM 	    ehci_polled_input_pipe_handle->p_hcd_private;
484*9095SZhigang.Lu@Sun.COM 	ehci_polled_insert_async_qh(ehcip, pp);
485*9095SZhigang.Lu@Sun.COM 
486*9095SZhigang.Lu@Sun.COM 	/*
487*9095SZhigang.Lu@Sun.COM 	 * This is a software workaround to fix schizo hardware bug.
488*9095SZhigang.Lu@Sun.COM 	 * Existence of "no-prom-cdma-sync"  property means consistent
489*9095SZhigang.Lu@Sun.COM 	 * dma sync should not be done while in prom or polled mode.
490*9095SZhigang.Lu@Sun.COM 	 */
491*9095SZhigang.Lu@Sun.COM 	if (ddi_prop_exists(DDI_DEV_T_ANY, ehcip->ehci_dip,
492*9095SZhigang.Lu@Sun.COM 	    DDI_PROP_NOTPROM, "no-prom-cdma-sync")) {
493*9095SZhigang.Lu@Sun.COM 		ehci_polledp->ehci_polled_no_sync_flag = B_TRUE;
494*9095SZhigang.Lu@Sun.COM 	}
495*9095SZhigang.Lu@Sun.COM 
496*9095SZhigang.Lu@Sun.COM 	/* Allow interrupts to continue */
497*9095SZhigang.Lu@Sun.COM 	mutex_exit(&ehcip->ehci_int_mutex);
498*9095SZhigang.Lu@Sun.COM 
499*9095SZhigang.Lu@Sun.COM 	return (USB_SUCCESS);
500*9095SZhigang.Lu@Sun.COM }
501*9095SZhigang.Lu@Sun.COM 
502*9095SZhigang.Lu@Sun.COM 
503*9095SZhigang.Lu@Sun.COM /*
504*9095SZhigang.Lu@Sun.COM  * ehci_hcdi_polled_output_fini:
505*9095SZhigang.Lu@Sun.COM  */
506*9095SZhigang.Lu@Sun.COM int
ehci_hcdi_polled_output_fini(usb_console_info_impl_t * info)507*9095SZhigang.Lu@Sun.COM ehci_hcdi_polled_output_fini(usb_console_info_impl_t *info)
508*9095SZhigang.Lu@Sun.COM {
509*9095SZhigang.Lu@Sun.COM 	ehci_polled_t		*ehci_polledp;
510*9095SZhigang.Lu@Sun.COM 	ehci_state_t		*ehcip;
511*9095SZhigang.Lu@Sun.COM 	ehci_pipe_private_t	*pp;
512*9095SZhigang.Lu@Sun.COM 	int			ret;
513*9095SZhigang.Lu@Sun.COM 
514*9095SZhigang.Lu@Sun.COM 	ehci_polledp = (ehci_polled_t *)info->uci_private;
515*9095SZhigang.Lu@Sun.COM 
516*9095SZhigang.Lu@Sun.COM 	ehcip = ehci_polledp->ehci_polled_ehcip;
517*9095SZhigang.Lu@Sun.COM 
518*9095SZhigang.Lu@Sun.COM 	mutex_enter(&ehcip->ehci_int_mutex);
519*9095SZhigang.Lu@Sun.COM 
520*9095SZhigang.Lu@Sun.COM 	/* Remove the Endpoint Descriptor. */
521*9095SZhigang.Lu@Sun.COM 	pp = (ehci_pipe_private_t *)ehci_polledp->
522*9095SZhigang.Lu@Sun.COM 	    ehci_polled_input_pipe_handle->p_hcd_private;
523*9095SZhigang.Lu@Sun.COM 	ehci_polled_remove_async_qh(ehcip, pp);
524*9095SZhigang.Lu@Sun.COM 
525*9095SZhigang.Lu@Sun.COM 	/*
526*9095SZhigang.Lu@Sun.COM 	 * Reset the POLLED_INPUT_MODE flag so that we can tell if
527*9095SZhigang.Lu@Sun.COM 	 * this structure is in use in the ehci_polled_fini routine.
528*9095SZhigang.Lu@Sun.COM 	 */
529*9095SZhigang.Lu@Sun.COM 	ehci_polledp->ehci_polled_flags &= ~POLLED_OUTPUT_MODE;
530*9095SZhigang.Lu@Sun.COM 
531*9095SZhigang.Lu@Sun.COM 	ret = ehci_polled_fini(ehci_polledp);
532*9095SZhigang.Lu@Sun.COM 
533*9095SZhigang.Lu@Sun.COM 	info->uci_private = NULL;
534*9095SZhigang.Lu@Sun.COM 
535*9095SZhigang.Lu@Sun.COM 	mutex_exit(&ehcip->ehci_int_mutex);
536*9095SZhigang.Lu@Sun.COM 
537*9095SZhigang.Lu@Sun.COM 	return (ret);
538*9095SZhigang.Lu@Sun.COM }
539*9095SZhigang.Lu@Sun.COM 
540*9095SZhigang.Lu@Sun.COM 
541*9095SZhigang.Lu@Sun.COM /*
542*9095SZhigang.Lu@Sun.COM  * ehci_hcdi_polled_output_enter:
543*9095SZhigang.Lu@Sun.COM  *
544*9095SZhigang.Lu@Sun.COM  * everything is done in input enter
545*9095SZhigang.Lu@Sun.COM  */
546*9095SZhigang.Lu@Sun.COM /*ARGSUSED*/
547*9095SZhigang.Lu@Sun.COM int
ehci_hcdi_polled_output_enter(usb_console_info_impl_t * info)548*9095SZhigang.Lu@Sun.COM ehci_hcdi_polled_output_enter(usb_console_info_impl_t *info)
549*9095SZhigang.Lu@Sun.COM {
550*9095SZhigang.Lu@Sun.COM 	return (USB_SUCCESS);
551*9095SZhigang.Lu@Sun.COM }
552*9095SZhigang.Lu@Sun.COM 
553*9095SZhigang.Lu@Sun.COM 
554*9095SZhigang.Lu@Sun.COM /*
555*9095SZhigang.Lu@Sun.COM  * ehci_hcdi_polled_output_exit:
556*9095SZhigang.Lu@Sun.COM  *
557*9095SZhigang.Lu@Sun.COM  * everything is done in input exit
558*9095SZhigang.Lu@Sun.COM  */
559*9095SZhigang.Lu@Sun.COM /*ARGSUSED*/
560*9095SZhigang.Lu@Sun.COM int
ehci_hcdi_polled_output_exit(usb_console_info_impl_t * info)561*9095SZhigang.Lu@Sun.COM ehci_hcdi_polled_output_exit(usb_console_info_impl_t *info)
562*9095SZhigang.Lu@Sun.COM {
563*9095SZhigang.Lu@Sun.COM 	return (USB_SUCCESS);
564*9095SZhigang.Lu@Sun.COM }
565*9095SZhigang.Lu@Sun.COM 
566*9095SZhigang.Lu@Sun.COM 
567*9095SZhigang.Lu@Sun.COM /*
568*9095SZhigang.Lu@Sun.COM  * ehci_hcdi_polled_write:
569*9095SZhigang.Lu@Sun.COM  *	Put a key character.
570*9095SZhigang.Lu@Sun.COM  */
571*9095SZhigang.Lu@Sun.COM int
ehci_hcdi_polled_write(usb_console_info_impl_t * info,uchar_t * buf,uint_t num_characters,uint_t * num_characters_written)572*9095SZhigang.Lu@Sun.COM ehci_hcdi_polled_write(usb_console_info_impl_t *info, uchar_t *buf,
573*9095SZhigang.Lu@Sun.COM     uint_t num_characters, uint_t *num_characters_written)
574*9095SZhigang.Lu@Sun.COM {
575*9095SZhigang.Lu@Sun.COM 	ehci_state_t		*ehcip;
576*9095SZhigang.Lu@Sun.COM 	ehci_polled_t		*ehci_polledp;
577*9095SZhigang.Lu@Sun.COM 	ehci_trans_wrapper_t	*tw;
578*9095SZhigang.Lu@Sun.COM 	ehci_pipe_private_t	*pp;
579*9095SZhigang.Lu@Sun.COM 	usba_pipe_handle_data_t	*ph;
580*9095SZhigang.Lu@Sun.COM 	int			intr;
581*9095SZhigang.Lu@Sun.COM 
582*9095SZhigang.Lu@Sun.COM #ifndef lint
583*9095SZhigang.Lu@Sun.COM 	_NOTE(NO_COMPETING_THREADS_NOW);
584*9095SZhigang.Lu@Sun.COM #endif
585*9095SZhigang.Lu@Sun.COM 	ehci_polledp = (ehci_polled_t *)info->uci_private;
586*9095SZhigang.Lu@Sun.COM 	ehcip = ehci_polledp->ehci_polled_ehcip;
587*9095SZhigang.Lu@Sun.COM 	ph = ehci_polledp->ehci_polled_input_pipe_handle;
588*9095SZhigang.Lu@Sun.COM 	pp = (ehci_pipe_private_t *)ph->p_hcd_private;
589*9095SZhigang.Lu@Sun.COM 
590*9095SZhigang.Lu@Sun.COM 	/* Disable all list processing */
591*9095SZhigang.Lu@Sun.COM 	Set_OpReg(ehci_command, Get_OpReg(ehci_command) &
592*9095SZhigang.Lu@Sun.COM 	    ~(EHCI_CMD_ASYNC_SCHED_ENABLE |
593*9095SZhigang.Lu@Sun.COM 	    EHCI_CMD_PERIODIC_SCHED_ENABLE));
594*9095SZhigang.Lu@Sun.COM 
595*9095SZhigang.Lu@Sun.COM 	/* Wait for few milliseconds */
596*9095SZhigang.Lu@Sun.COM 	drv_usecwait(EHCI_POLLED_TIMEWAIT);
597*9095SZhigang.Lu@Sun.COM 
598*9095SZhigang.Lu@Sun.COM 	tw = pp->pp_tw_head;
599*9095SZhigang.Lu@Sun.COM 	ASSERT(tw != NULL);
600*9095SZhigang.Lu@Sun.COM 
601*9095SZhigang.Lu@Sun.COM 	/* copy transmit buffer */
602*9095SZhigang.Lu@Sun.COM 	if (num_characters > POLLED_RAW_BUF_SIZE) {
603*9095SZhigang.Lu@Sun.COM 		cmn_err(CE_NOTE, "polled write size %d bigger than %d",
604*9095SZhigang.Lu@Sun.COM 		    num_characters, POLLED_RAW_BUF_SIZE);
605*9095SZhigang.Lu@Sun.COM 		num_characters = POLLED_RAW_BUF_SIZE;
606*9095SZhigang.Lu@Sun.COM 	}
607*9095SZhigang.Lu@Sun.COM 	tw->tw_length = num_characters;
608*9095SZhigang.Lu@Sun.COM 	ddi_rep_put8(tw->tw_accesshandle,
609*9095SZhigang.Lu@Sun.COM 	    buf, (uint8_t *)tw->tw_buf,
610*9095SZhigang.Lu@Sun.COM 	    tw->tw_length, DDI_DEV_AUTOINCR);
611*9095SZhigang.Lu@Sun.COM 	Sync_IO_Buffer_for_device(tw->tw_dmahandle, tw->tw_length);
612*9095SZhigang.Lu@Sun.COM 
613*9095SZhigang.Lu@Sun.COM 	ehci_polled_insert_bulk_qtd(ehci_polledp);
614*9095SZhigang.Lu@Sun.COM 
615*9095SZhigang.Lu@Sun.COM 	/* Enable async list processing */
616*9095SZhigang.Lu@Sun.COM 	Set_OpReg(ehci_command, (Get_OpReg(ehci_command) |
617*9095SZhigang.Lu@Sun.COM 	    EHCI_CMD_ASYNC_SCHED_ENABLE));
618*9095SZhigang.Lu@Sun.COM 
619*9095SZhigang.Lu@Sun.COM 	/* Wait for few milliseconds */
620*9095SZhigang.Lu@Sun.COM 	drv_usecwait(EHCI_POLLED_TIMEWAIT);
621*9095SZhigang.Lu@Sun.COM 
622*9095SZhigang.Lu@Sun.COM 	while (!((Get_OpReg(ehci_status)) & (EHCI_INTR_USB
623*9095SZhigang.Lu@Sun.COM 	    |EHCI_INTR_FRAME_LIST_ROLLOVER | EHCI_INTR_USB_ERROR))) {
624*9095SZhigang.Lu@Sun.COM #ifndef __sparc
625*9095SZhigang.Lu@Sun.COM 		invalidate_cache();
626*9095SZhigang.Lu@Sun.COM #else
627*9095SZhigang.Lu@Sun.COM 		;
628*9095SZhigang.Lu@Sun.COM #endif
629*9095SZhigang.Lu@Sun.COM 	}
630*9095SZhigang.Lu@Sun.COM 
631*9095SZhigang.Lu@Sun.COM 	intr = (Get_OpReg(ehci_status)) &
632*9095SZhigang.Lu@Sun.COM 	    (EHCI_INTR_FRAME_LIST_ROLLOVER |
633*9095SZhigang.Lu@Sun.COM 	    EHCI_INTR_USB | EHCI_INTR_USB_ERROR);
634*9095SZhigang.Lu@Sun.COM 
635*9095SZhigang.Lu@Sun.COM 	/*
636*9095SZhigang.Lu@Sun.COM 	 * Check whether any frame list rollover interrupt is pending
637*9095SZhigang.Lu@Sun.COM 	 * and if it is pending, process this interrupt.
638*9095SZhigang.Lu@Sun.COM 	 */
639*9095SZhigang.Lu@Sun.COM 	if (intr & EHCI_INTR_FRAME_LIST_ROLLOVER) {
640*9095SZhigang.Lu@Sun.COM 
641*9095SZhigang.Lu@Sun.COM 		ehci_handle_frame_list_rollover(ehcip);
642*9095SZhigang.Lu@Sun.COM 		ehci_polled_finish_interrupt(ehcip,
643*9095SZhigang.Lu@Sun.COM 		    EHCI_INTR_FRAME_LIST_ROLLOVER);
644*9095SZhigang.Lu@Sun.COM 	}
645*9095SZhigang.Lu@Sun.COM 
6460Sstevel@tonic-gate 	/* Check for any USB transaction completion notification */
6470Sstevel@tonic-gate 	if (intr & (EHCI_INTR_USB | EHCI_INTR_USB_ERROR)) {
648*9095SZhigang.Lu@Sun.COM 
649*9095SZhigang.Lu@Sun.COM 		(void) ehci_polled_process_active_intr_qtd_list(ehci_polledp);
6500Sstevel@tonic-gate 
651*9095SZhigang.Lu@Sun.COM 		/* Acknowledge the USB and USB error interrupt */
652*9095SZhigang.Lu@Sun.COM 		ehci_polled_finish_interrupt(ehcip,
653*9095SZhigang.Lu@Sun.COM 		    intr & (EHCI_INTR_USB | EHCI_INTR_USB_ERROR));
654*9095SZhigang.Lu@Sun.COM 
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate 
657*9095SZhigang.Lu@Sun.COM 	*num_characters_written = num_characters;
658*9095SZhigang.Lu@Sun.COM 
6590Sstevel@tonic-gate #ifndef lint
6600Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
6610Sstevel@tonic-gate #endif
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	return (USB_SUCCESS);
6640Sstevel@tonic-gate }
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate /*
6680Sstevel@tonic-gate  * Internal Functions
6690Sstevel@tonic-gate  */
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate /*
6720Sstevel@tonic-gate  * Polled initialization routines
6730Sstevel@tonic-gate  */
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate /*
6770Sstevel@tonic-gate  * ehci_polled_init:
6780Sstevel@tonic-gate  *
6790Sstevel@tonic-gate  * Initialize generic information Uthat is needed to provide USB/POLLED
6800Sstevel@tonic-gate  * support.
6810Sstevel@tonic-gate  */
6820Sstevel@tonic-gate static int
ehci_polled_init(usba_pipe_handle_data_t * ph,ehci_state_t * ehcip,usb_console_info_impl_t * console_info)6830Sstevel@tonic-gate ehci_polled_init(
6840Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
6850Sstevel@tonic-gate 	ehci_state_t		*ehcip,
6860Sstevel@tonic-gate 	usb_console_info_impl_t	*console_info)
6870Sstevel@tonic-gate {
6880Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp;
6890Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
6900Sstevel@tonic-gate 	ehci_qtd_t		*qtd;
691*9095SZhigang.Lu@Sun.COM 	int			pipe_attr;
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	/*
6960Sstevel@tonic-gate 	 * We have already initialized this structure. If the structure
6970Sstevel@tonic-gate 	 * has already been initialized, then we don't need to redo it.
6980Sstevel@tonic-gate 	 */
6990Sstevel@tonic-gate 	if (console_info->uci_private) {
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 		return (USB_SUCCESS);
7020Sstevel@tonic-gate 	}
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	/* Allocate and intitialize a state structure */
7050Sstevel@tonic-gate 	ehci_polledp = (ehci_polled_t *)
7060Sstevel@tonic-gate 	    kmem_zalloc(sizeof (ehci_polled_t), KM_SLEEP);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	console_info->uci_private = (usb_console_info_private_t)ehci_polledp;
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	/*
7110Sstevel@tonic-gate 	 * Store away the ehcip so that we can get to it when we are in
7120Sstevel@tonic-gate 	 * POLLED mode. We don't want to have to call ehci_obtain_state
7130Sstevel@tonic-gate 	 * every time we want to access this structure.
7140Sstevel@tonic-gate 	 */
7150Sstevel@tonic-gate 	ehci_polledp->ehci_polled_ehcip = ehcip;
7160Sstevel@tonic-gate 	/*
7170Sstevel@tonic-gate 	 * Save usb device and endpoint number information from the usb
7180Sstevel@tonic-gate 	 * pipe handle.
7190Sstevel@tonic-gate 	 */
7200Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
7210Sstevel@tonic-gate 	ehci_polledp->ehci_polled_usb_dev = ph->p_usba_device;
7220Sstevel@tonic-gate 	ehci_polledp->ehci_polled_ep_addr = ph->p_ep.bEndpointAddress;
7230Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	/*
7260Sstevel@tonic-gate 	 * Allocate memory to make duplicate of original usb pipe handle.
7270Sstevel@tonic-gate 	 */
7280Sstevel@tonic-gate 	ehci_polledp->ehci_polled_input_pipe_handle =
7290Sstevel@tonic-gate 	    kmem_zalloc(sizeof (usba_pipe_handle_data_t), KM_SLEEP);
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	/*
7320Sstevel@tonic-gate 	 * Copy the USB handle into the new pipe handle. Also
7330Sstevel@tonic-gate 	 * create new lock for the new pipe handle.
7340Sstevel@tonic-gate 	 */
7350Sstevel@tonic-gate 	bcopy((void *)ph,
7360Sstevel@tonic-gate 	    (void *)ehci_polledp->ehci_polled_input_pipe_handle,
7370Sstevel@tonic-gate 	    sizeof (usba_pipe_handle_data_t));
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	/*
7400Sstevel@tonic-gate 	 * uint64_t typecast to make sure amd64 can compile
7410Sstevel@tonic-gate 	 */
7420Sstevel@tonic-gate 	mutex_init(&ehci_polledp->ehci_polled_input_pipe_handle->p_mutex,
743693Sgovinda 	    NULL, MUTEX_DRIVER, DDI_INTR_PRI(ehcip->ehci_intr_pri));
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	/*
7460Sstevel@tonic-gate 	 * Create a new ehci pipe private structure
7470Sstevel@tonic-gate 	 */
7480Sstevel@tonic-gate 	pp = (ehci_pipe_private_t *)
7490Sstevel@tonic-gate 	    kmem_zalloc(sizeof (ehci_pipe_private_t), KM_SLEEP);
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	/*
7520Sstevel@tonic-gate 	 * Store the pointer in the pipe handle. This structure was also
7530Sstevel@tonic-gate 	 * just allocated.
7540Sstevel@tonic-gate 	 */
7550Sstevel@tonic-gate 	mutex_enter(&ehci_polledp->ehci_polled_input_pipe_handle->p_mutex);
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	ehci_polledp->ehci_polled_input_pipe_handle->
7580Sstevel@tonic-gate 	    p_hcd_private = (usb_opaque_t)pp;
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	mutex_exit(&ehci_polledp->ehci_polled_input_pipe_handle->p_mutex);
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	/*
7630Sstevel@tonic-gate 	 * Store a pointer to the pipe handle. This structure was  just
7640Sstevel@tonic-gate 	 * allocated and it is not in use yet.	The locking is there to
7650Sstevel@tonic-gate 	 * satisfy warlock.
7660Sstevel@tonic-gate 	 */
7670Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 	bcopy(&ph->p_policy, &pp->pp_policy, sizeof (usb_pipe_policy_t));
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 	pp->pp_pipe_handle = ehci_polledp->ehci_polled_input_pipe_handle;
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	/*
7760Sstevel@tonic-gate 	 * Allocate a dummy for the interrupt table. This dummy will be
7770Sstevel@tonic-gate 	 * put into the action when we	switch interrupt  tables during
7780Sstevel@tonic-gate 	 * ehci_hcdi_polled_enter. Dummy is placed on the unused lattice
7790Sstevel@tonic-gate 	 * entries. When the QH is allocated we will replace dummy QH by
7800Sstevel@tonic-gate 	 * valid interrupt QH in one or more locations in the interrupt
7810Sstevel@tonic-gate 	 * lattice depending on the requested polling interval. Also we
7820Sstevel@tonic-gate 	 * will hang a dummy QTD to the QH & dummy QTD is used to indicate
7830Sstevel@tonic-gate 	 * the end of the QTD chain.
7840Sstevel@tonic-gate 	 */
7850Sstevel@tonic-gate 	ehci_polledp->ehci_polled_dummy_qh =
7860Sstevel@tonic-gate 	    ehci_alloc_qh(ehcip, NULL, EHCI_POLLED_MODE_FLAG);
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_dummy_qh == NULL) {
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
7910Sstevel@tonic-gate 	}
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	/*
794*9095SZhigang.Lu@Sun.COM 	 * Allocate the endpoint. This QH will be inserted in
795*9095SZhigang.Lu@Sun.COM 	 * to the lattice chain for the device. This endpoint
7960Sstevel@tonic-gate 	 * will have the QTDs hanging off of it for the processing.
7970Sstevel@tonic-gate 	 */
7980Sstevel@tonic-gate 	ehci_polledp->ehci_polled_qh = ehci_alloc_qh(
7990Sstevel@tonic-gate 	    ehcip, ph, EHCI_POLLED_MODE_FLAG);
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_qh == NULL) {
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
8040Sstevel@tonic-gate 	}
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	/* Set the state of pipe as idle */
8070Sstevel@tonic-gate 	pp->pp_state = EHCI_PIPE_STATE_IDLE;
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	/* Set polled mode flag */
8100Sstevel@tonic-gate 	pp->pp_flag = EHCI_POLLED_MODE_FLAG;
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	/* Insert the endpoint onto the pipe handle */
8130Sstevel@tonic-gate 	pp->pp_qh = ehci_polledp->ehci_polled_qh;
8140Sstevel@tonic-gate 
815*9095SZhigang.Lu@Sun.COM 	pipe_attr = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK;
816*9095SZhigang.Lu@Sun.COM 
817*9095SZhigang.Lu@Sun.COM 	switch (pipe_attr) {
818*9095SZhigang.Lu@Sun.COM 	case USB_EP_ATTR_INTR:
819*9095SZhigang.Lu@Sun.COM 		/*
820*9095SZhigang.Lu@Sun.COM 		 * Set soft interrupt handler flag in the normal mode usb
821*9095SZhigang.Lu@Sun.COM 		 * pipe handle.
822*9095SZhigang.Lu@Sun.COM 		 */
823*9095SZhigang.Lu@Sun.COM 		mutex_enter(&ph->p_mutex);
824*9095SZhigang.Lu@Sun.COM 		ph->p_spec_flag |= USBA_PH_FLAG_USE_SOFT_INTR;
825*9095SZhigang.Lu@Sun.COM 		mutex_exit(&ph->p_mutex);
8260Sstevel@tonic-gate 
827*9095SZhigang.Lu@Sun.COM 		/*
828*9095SZhigang.Lu@Sun.COM 		 * Insert a Interrupt polling request onto the endpoint.
829*9095SZhigang.Lu@Sun.COM 		 *
830*9095SZhigang.Lu@Sun.COM 		 * There will now be two QTDs on the QH, one is the dummy QTD
831*9095SZhigang.Lu@Sun.COM 		 * that was allocated above in the  ehci_alloc_qh and this
832*9095SZhigang.Lu@Sun.COM 		 * new one.
833*9095SZhigang.Lu@Sun.COM 		 */
834*9095SZhigang.Lu@Sun.COM 		if ((ehci_start_periodic_pipe_polling(ehcip,
835*9095SZhigang.Lu@Sun.COM 		    ehci_polledp->ehci_polled_input_pipe_handle,
836*9095SZhigang.Lu@Sun.COM 		    NULL, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
8370Sstevel@tonic-gate 
838*9095SZhigang.Lu@Sun.COM 			return (USB_NO_RESOURCES);
839*9095SZhigang.Lu@Sun.COM 		}
840*9095SZhigang.Lu@Sun.COM 		/* Get the given new interrupt qtd */
841*9095SZhigang.Lu@Sun.COM 		qtd = (ehci_qtd_t *)(ehci_qtd_iommu_to_cpu(ehcip,
842*9095SZhigang.Lu@Sun.COM 		    (Get_QH(pp->pp_qh->qh_next_qtd) & EHCI_QH_NEXT_QTD_PTR)));
8430Sstevel@tonic-gate 
844*9095SZhigang.Lu@Sun.COM 		/* Insert this qtd into active interrupt QTD list */
845*9095SZhigang.Lu@Sun.COM 		ehci_polled_insert_qtd_into_active_intr_qtd_list(ehci_polledp,
846*9095SZhigang.Lu@Sun.COM 		    qtd);
847*9095SZhigang.Lu@Sun.COM 		break;
848*9095SZhigang.Lu@Sun.COM 	case USB_EP_ATTR_BULK:
849*9095SZhigang.Lu@Sun.COM 		if ((ehci_polled_create_tw(ehci_polledp,
850*9095SZhigang.Lu@Sun.COM 		    ehci_polledp->ehci_polled_input_pipe_handle,
851*9095SZhigang.Lu@Sun.COM 		    USB_FLAGS_SLEEP)) != USB_SUCCESS) {
8520Sstevel@tonic-gate 
853*9095SZhigang.Lu@Sun.COM 			return (USB_NO_RESOURCES);
854*9095SZhigang.Lu@Sun.COM 		}
855*9095SZhigang.Lu@Sun.COM 		break;
856*9095SZhigang.Lu@Sun.COM 	default:
857*9095SZhigang.Lu@Sun.COM 		return (USB_FAILURE);
858*9095SZhigang.Lu@Sun.COM 	}
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	return (USB_SUCCESS);
8610Sstevel@tonic-gate }
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate /*
8650Sstevel@tonic-gate  * Polled deinitialization routines
8660Sstevel@tonic-gate  */
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate /*
8700Sstevel@tonic-gate  * ehci_polled_fini:
8710Sstevel@tonic-gate  */
8720Sstevel@tonic-gate static int
ehci_polled_fini(ehci_polled_t * ehci_polledp)8730Sstevel@tonic-gate ehci_polled_fini(ehci_polled_t	*ehci_polledp)
8740Sstevel@tonic-gate {
8750Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
8760Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	/* If the structure is already in use, then don't free it */
8810Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_flags & POLLED_INPUT_MODE) {
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 		return (USB_SUCCESS);
8840Sstevel@tonic-gate 	}
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 	pp = (ehci_pipe_private_t *)
8870Sstevel@tonic-gate 	    ehci_polledp->ehci_polled_input_pipe_handle->p_hcd_private;
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	/* Deallocate all the pre-allocated interrupt requests */
8900Sstevel@tonic-gate 	ehci_handle_outstanding_requests(ehcip, pp);
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	/*
8930Sstevel@tonic-gate 	 * Traverse the list of QTD's on this endpoint and these QTD's
8940Sstevel@tonic-gate 	 * have outstanding transfer requests. Since list processing
8950Sstevel@tonic-gate 	 * is stopped, these QTDs can be deallocated.
8960Sstevel@tonic-gate 	 */
8970Sstevel@tonic-gate 	ehci_polled_traverse_qtds(ehci_polledp, pp->pp_pipe_handle);
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	/* Free DMA resources */
9000Sstevel@tonic-gate 	ehci_free_dma_resources(ehcip, pp->pp_pipe_handle);
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	/*
9030Sstevel@tonic-gate 	 * Deallocate the endpoint descriptors that we allocated
9040Sstevel@tonic-gate 	 * with ehci_alloc_qh.
9050Sstevel@tonic-gate 	 */
9060Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_dummy_qh) {
9070Sstevel@tonic-gate 		ehci_deallocate_qh(ehcip, ehci_polledp->ehci_polled_dummy_qh);
9080Sstevel@tonic-gate 	}
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_qh) {
9110Sstevel@tonic-gate 		ehci_deallocate_qh(ehcip, ehci_polledp->ehci_polled_qh);
9120Sstevel@tonic-gate 	}
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	mutex_destroy(&ehci_polledp->ehci_polled_input_pipe_handle->p_mutex);
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 	/*
9170Sstevel@tonic-gate 	 * Destroy everything about the pipe that we allocated in
9180Sstevel@tonic-gate 	 * ehci_polled_duplicate_pipe_handle
9190Sstevel@tonic-gate 	 */
9200Sstevel@tonic-gate 	kmem_free(pp, sizeof (ehci_pipe_private_t));
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	kmem_free(ehci_polledp->ehci_polled_input_pipe_handle,
9230Sstevel@tonic-gate 	    sizeof (usba_pipe_handle_data_t));
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	/*
9260Sstevel@tonic-gate 	 * We use this field to determine if a QTD is for input or not,
9270Sstevel@tonic-gate 	 * so NULL the pointer so we don't check deallocated data.
9280Sstevel@tonic-gate 	 */
9290Sstevel@tonic-gate 	ehci_polledp->ehci_polled_input_pipe_handle = NULL;
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	/*
9320Sstevel@tonic-gate 	 * Finally, free off the structure that we use to keep track
9330Sstevel@tonic-gate 	 * of all this.
9340Sstevel@tonic-gate 	 */
9350Sstevel@tonic-gate 	kmem_free(ehci_polledp, sizeof (ehci_polled_t));
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	return (USB_SUCCESS);
9380Sstevel@tonic-gate }
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate /*
9420Sstevel@tonic-gate  * Polled save state routines
9430Sstevel@tonic-gate  */
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate /*
9470Sstevel@tonic-gate  * ehci_polled_save_state:
9480Sstevel@tonic-gate  */
9490Sstevel@tonic-gate static void
ehci_polled_save_state(ehci_polled_t * ehci_polledp)9500Sstevel@tonic-gate ehci_polled_save_state(ehci_polled_t	*ehci_polledp)
9510Sstevel@tonic-gate {
9520Sstevel@tonic-gate 	int				i;
9530Sstevel@tonic-gate 	ehci_state_t			*ehcip;
9540Sstevel@tonic-gate 	uint_t				polled_toggle;
9550Sstevel@tonic-gate 	uint_t				real_toggle;
9560Sstevel@tonic-gate 	ehci_pipe_private_t		*pp = NULL; /* Normal mode Pipe */
9570Sstevel@tonic-gate 	ehci_pipe_private_t		*polled_pp; /* Polled mode Pipe */
9580Sstevel@tonic-gate 	usba_pipe_handle_data_t		*ph;
9590Sstevel@tonic-gate 	uint8_t				ep_addr;
9600Sstevel@tonic-gate 	ehci_regs_t			*ehci_polled_regsp;
9610Sstevel@tonic-gate 	ehci_qh_t			*qh;
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate #ifndef lint
9640Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
9650Sstevel@tonic-gate #endif
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	/*
9680Sstevel@tonic-gate 	 * If either of these two flags are set, then we have already
9690Sstevel@tonic-gate 	 * saved off the state information and setup the controller.
9700Sstevel@tonic-gate 	 */
9710Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_flags & POLLED_INPUT_MODE_INUSE) {
9720Sstevel@tonic-gate #ifndef lint
9730Sstevel@tonic-gate 		_NOTE(COMPETING_THREADS_NOW);
9740Sstevel@tonic-gate #endif
9750Sstevel@tonic-gate 		return;
9760Sstevel@tonic-gate 	}
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	ehcip = ehci_polledp->ehci_polled_ehcip;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	/*
9810Sstevel@tonic-gate 	 * Check if the number of keyboard reach the max number we can
9820Sstevel@tonic-gate 	 * support in polled mode
9830Sstevel@tonic-gate 	 */
9840Sstevel@tonic-gate 	if (++ ehcip->ehci_polled_enter_count > MAX_NUM_FOR_KEYBOARD) {
9850Sstevel@tonic-gate #ifndef lint
9860Sstevel@tonic-gate 		_NOTE(COMPETING_THREADS_NOW);
9870Sstevel@tonic-gate #endif
9880Sstevel@tonic-gate 		return;
9890Sstevel@tonic-gate 	}
9900Sstevel@tonic-gate 	ehci_polled_regsp = &ehcip->ehci_polled_save_regs;
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	/* Get the endpoint addr. */
9930Sstevel@tonic-gate 	ep_addr = ehci_polledp->ehci_polled_ep_addr;
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	/* Get the normal mode usb pipe handle */
9960Sstevel@tonic-gate 	ph = usba_hcdi_get_ph_data(ehci_polledp->ehci_polled_usb_dev, ep_addr);
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	/*
9990Sstevel@tonic-gate 	 * The first enter keyboard entry should save info of the normal mode,
10000Sstevel@tonic-gate 	 * disable all list processing and interrupt, initialize the
10010Sstevel@tonic-gate 	 * frame list table with dummy QHs.
10020Sstevel@tonic-gate 	 */
10030Sstevel@tonic-gate 	if (ehcip->ehci_polled_enter_count == 1) {
10040Sstevel@tonic-gate 		/*
10050Sstevel@tonic-gate 		 * Save the current normal mode ehci registers	and later this
10060Sstevel@tonic-gate 		 * saved register copy is used to replace some of required ehci
10070Sstevel@tonic-gate 		 * registers before switching from polled mode to normal mode.
10080Sstevel@tonic-gate 		 */
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 		bzero((void *)ehci_polled_regsp, sizeof (ehci_regs_t));
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 		/* Save current ehci registers */
10130Sstevel@tonic-gate 		ehci_polled_regsp->ehci_command = Get_OpReg(ehci_command);
10140Sstevel@tonic-gate 		ehci_polled_regsp->ehci_interrupt = Get_OpReg(ehci_interrupt);
10150Sstevel@tonic-gate 		ehci_polled_regsp->ehci_ctrl_segment =
10160Sstevel@tonic-gate 		    Get_OpReg(ehci_ctrl_segment);
10170Sstevel@tonic-gate 		ehci_polled_regsp->
10180Sstevel@tonic-gate 		    ehci_async_list_addr = Get_OpReg(ehci_async_list_addr);
10190Sstevel@tonic-gate 		ehci_polled_regsp->ehci_config_flag =
10200Sstevel@tonic-gate 		    Get_OpReg(ehci_config_flag);
10210Sstevel@tonic-gate 		ehci_polled_regsp->ehci_periodic_list_base =
10220Sstevel@tonic-gate 		    Get_OpReg(ehci_periodic_list_base);
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 		/* Disable all list processing and interrupts */
10250Sstevel@tonic-gate 		Set_OpReg(ehci_command, Get_OpReg(ehci_command) &
10260Sstevel@tonic-gate 		    ~(EHCI_CMD_ASYNC_SCHED_ENABLE |
10270Sstevel@tonic-gate 		    EHCI_CMD_PERIODIC_SCHED_ENABLE));
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 		/* Wait for few milliseconds */
10300Sstevel@tonic-gate 		drv_usecwait(EHCI_POLLED_TIMEWAIT);
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 		/* Save any unprocessed normal mode ehci interrupts */
10330Sstevel@tonic-gate 		ehcip->ehci_missed_intr_sts = EHCI_INTR_USB;
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 		/*
10360Sstevel@tonic-gate 		 * Save the current interrupt lattice and  replace this lattice
10370Sstevel@tonic-gate 		 * with an lattice used in POLLED mode. We will restore lattice
10380Sstevel@tonic-gate 		 * back when we exit from the POLLED mode.
10390Sstevel@tonic-gate 		 */
10400Sstevel@tonic-gate 		for (i = 0; i < EHCI_NUM_PERIODIC_FRAME_LISTS; i++) {
10410Sstevel@tonic-gate 			ehcip->ehci_polled_frame_list_table[i] =
10420Sstevel@tonic-gate 			    (ehci_qh_t *)(uintptr_t)Get_PFLT(ehcip->
10430Sstevel@tonic-gate 			    ehci_periodic_frame_list_tablep->
10440Sstevel@tonic-gate 			    ehci_periodic_frame_list_table[i]);
10450Sstevel@tonic-gate 		}
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 		/*
10480Sstevel@tonic-gate 		 * Fill in the lattice with dummy QHs. These QHs are used so the
10490Sstevel@tonic-gate 		 * controller can tell that it is at the end of the QH list.
10500Sstevel@tonic-gate 		 */
10510Sstevel@tonic-gate 		for (i = 0; i < EHCI_NUM_PERIODIC_FRAME_LISTS; i++) {
10520Sstevel@tonic-gate 			Set_PFLT(ehcip->ehci_periodic_frame_list_tablep->
10530Sstevel@tonic-gate 			    ehci_periodic_frame_list_table[i],
10540Sstevel@tonic-gate 			    ehci_qh_cpu_to_iommu(ehcip,
10550Sstevel@tonic-gate 			    ehci_polledp->ehci_polled_dummy_qh) |
10560Sstevel@tonic-gate 			    (EHCI_QH_LINK_REF_QH | EHCI_QH_LINK_PTR_VALID));
10570Sstevel@tonic-gate 		}
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 	}
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	/* Get the polled mode ehci pipe private structure */
10620Sstevel@tonic-gate 	polled_pp = (ehci_pipe_private_t *)
10630Sstevel@tonic-gate 	    ehci_polledp->ehci_polled_input_pipe_handle->p_hcd_private;
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	/*
10660Sstevel@tonic-gate 	 * Before replacing the lattice, adjust the data togggle on the
10670Sstevel@tonic-gate 	 * on the ehci's interrupt ed
10680Sstevel@tonic-gate 	 */
10690Sstevel@tonic-gate 	polled_toggle = (Get_QH(polled_pp->pp_qh->qh_status) &
10700Sstevel@tonic-gate 	    EHCI_QH_STS_DATA_TOGGLE) ? DATA1:DATA0;
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	/*
10730Sstevel@tonic-gate 	 * If normal mode interrupt pipe endpoint is active, get the data
10740Sstevel@tonic-gate 	 * toggle from the this interrupt endpoint through the corresponding
10750Sstevel@tonic-gate 	 * interrupt pipe handle. Else get the data toggle information from
10760Sstevel@tonic-gate 	 * the usb device structure and this information is saved during the
10770Sstevel@tonic-gate 	 * normal mode interrupt pipe close. Use this data toggle information
10780Sstevel@tonic-gate 	 * to fix the data toggle of polled mode interrupt endpoint.
10790Sstevel@tonic-gate 	 */
10800Sstevel@tonic-gate 	if (ph) {
10810Sstevel@tonic-gate 		/* Get the normal mode ehci pipe private structure */
10820Sstevel@tonic-gate 		pp = (ehci_pipe_private_t *)ph->p_hcd_private;
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 		real_toggle = (Get_QH(pp->pp_qh->qh_status) &
10850Sstevel@tonic-gate 		    EHCI_QH_STS_DATA_TOGGLE) ? DATA1:DATA0;
10860Sstevel@tonic-gate 	} else {
10870Sstevel@tonic-gate 		real_toggle = usba_hcdi_get_data_toggle(
10880Sstevel@tonic-gate 		    ehci_polledp->ehci_polled_usb_dev, ep_addr);
10890Sstevel@tonic-gate 	}
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 	if (polled_toggle != real_toggle) {
10920Sstevel@tonic-gate 		if (real_toggle == DATA0) {
10930Sstevel@tonic-gate 			Set_QH(polled_pp->pp_qh->qh_status,
10940Sstevel@tonic-gate 			    Get_QH(polled_pp->pp_qh->qh_status) &
10950Sstevel@tonic-gate 			    ~EHCI_QH_STS_DATA_TOGGLE);
10960Sstevel@tonic-gate 		} else {
10970Sstevel@tonic-gate 			Set_QH(polled_pp->pp_qh->qh_status,
10980Sstevel@tonic-gate 			    Get_QH(polled_pp->pp_qh->qh_status) |
10990Sstevel@tonic-gate 			    EHCI_QH_STS_DATA_TOGGLE);
11000Sstevel@tonic-gate 		}
11010Sstevel@tonic-gate 	}
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	/*
11040Sstevel@tonic-gate 	 * Check whether Halt bit is set in the QH and if so  clear the
11050Sstevel@tonic-gate 	 * halt bit.
11060Sstevel@tonic-gate 	 */
11070Sstevel@tonic-gate 	if (polled_pp->pp_qh->qh_status & EHCI_QH_STS_HALTED) {
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 		/* Clear the halt bit */
11100Sstevel@tonic-gate 		Set_QH(polled_pp->pp_qh->qh_status,
11110Sstevel@tonic-gate 		    (Get_QH(polled_pp->pp_qh->qh_status) &
11120Sstevel@tonic-gate 		    ~EHCI_QH_STS_HALTED));
11130Sstevel@tonic-gate 	}
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate 	/*
11160Sstevel@tonic-gate 	 * Initialize the qh overlay area
11170Sstevel@tonic-gate 	 */
11180Sstevel@tonic-gate 	qh = ehci_polledp->ehci_polled_qh;
11190Sstevel@tonic-gate 	for (i = 0; i < 5; i++) {
11200Sstevel@tonic-gate 		Set_QH(qh->qh_buf[i], NULL);
11210Sstevel@tonic-gate 		Set_QH(qh->qh_buf_high[i], NULL);
11220Sstevel@tonic-gate 	}
11230Sstevel@tonic-gate 	Set_QH(qh->qh_next_qtd, ehci_qtd_cpu_to_iommu(ehcip,
11240Sstevel@tonic-gate 	    ehci_polledp->ehci_polled_active_intr_qtd_list));
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	/*
11270Sstevel@tonic-gate 	 * Now, add the endpoint to the lattice that we will  hang  our
11280Sstevel@tonic-gate 	 * QTD's off of.  We need to poll this device at  every 8 ms and
11290Sstevel@tonic-gate 	 * hence add this QH needs 4 entries in interrupt lattice.
11300Sstevel@tonic-gate 	 */
11310Sstevel@tonic-gate 	for (i = ehcip->ehci_polled_enter_count - 1;
11320Sstevel@tonic-gate 	    i < EHCI_NUM_PERIODIC_FRAME_LISTS;
11330Sstevel@tonic-gate 	    i = i + LS_MIN_POLL_INTERVAL) {
11340Sstevel@tonic-gate 		Set_PFLT(ehcip->ehci_periodic_frame_list_tablep->
11350Sstevel@tonic-gate 		    ehci_periodic_frame_list_table[i],
11360Sstevel@tonic-gate 		    ehci_qh_cpu_to_iommu(ehcip,
11370Sstevel@tonic-gate 		    ehci_polledp->ehci_polled_qh) | EHCI_QH_LINK_REF_QH);
11380Sstevel@tonic-gate 	}
11390Sstevel@tonic-gate 	/* The first enter keyboard entry enable interrupts and periodic list */
11400Sstevel@tonic-gate 	if (ehcip->ehci_polled_enter_count == 1) {
11410Sstevel@tonic-gate 		/* Enable USB and Frame list rollover interrupts */
11420Sstevel@tonic-gate 		Set_OpReg(ehci_interrupt, (EHCI_INTR_USB |
11430Sstevel@tonic-gate 		    EHCI_INTR_USB_ERROR | EHCI_INTR_FRAME_LIST_ROLLOVER));
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 		/* Enable the periodic list */
11460Sstevel@tonic-gate 		Set_OpReg(ehci_command,
11470Sstevel@tonic-gate 		    (Get_OpReg(ehci_command) | EHCI_CMD_PERIODIC_SCHED_ENABLE));
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 		/* Wait for few milliseconds */
11500Sstevel@tonic-gate 		drv_usecwait(EHCI_POLLED_TIMEWAIT);
11510Sstevel@tonic-gate 	}
11520Sstevel@tonic-gate #ifndef lint
11530Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
11540Sstevel@tonic-gate #endif
11550Sstevel@tonic-gate }
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate /*
11590Sstevel@tonic-gate  * Polled restore state routines
11600Sstevel@tonic-gate  */
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate /*
11640Sstevel@tonic-gate  * ehci_polled_restore_state:
11650Sstevel@tonic-gate  */
11660Sstevel@tonic-gate static void
ehci_polled_restore_state(ehci_polled_t * ehci_polledp)11670Sstevel@tonic-gate ehci_polled_restore_state(ehci_polled_t	*ehci_polledp)
11680Sstevel@tonic-gate {
11690Sstevel@tonic-gate 	ehci_state_t			*ehcip;
11700Sstevel@tonic-gate 	int				i;
11710Sstevel@tonic-gate 	uint_t				polled_toggle;
11720Sstevel@tonic-gate 	uint_t				real_toggle;
11730Sstevel@tonic-gate 	ehci_pipe_private_t		*pp = NULL; /* Normal mode Pipe */
11740Sstevel@tonic-gate 	ehci_pipe_private_t		*polled_pp; /* Polled mode Pipe */
11750Sstevel@tonic-gate 	usba_pipe_handle_data_t		*ph;
11760Sstevel@tonic-gate 	uint8_t				ep_addr;
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate #ifndef lint
11790Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
11800Sstevel@tonic-gate #endif
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	/*
11830Sstevel@tonic-gate 	 * If this flag is set, then we are still using this structure,
11840Sstevel@tonic-gate 	 * so don't restore any controller state information yet.
11850Sstevel@tonic-gate 	 */
11860Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_flags & POLLED_INPUT_MODE_INUSE) {
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate #ifndef lint
11890Sstevel@tonic-gate 		_NOTE(COMPETING_THREADS_NOW);
11900Sstevel@tonic-gate #endif
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 		return;
11930Sstevel@tonic-gate 	}
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 	ehcip = ehci_polledp->ehci_polled_ehcip;
11960Sstevel@tonic-gate 	ehcip->ehci_polled_enter_count --;
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	/* Get the endpoint addr */
11990Sstevel@tonic-gate 	ep_addr = ehci_polledp->ehci_polled_ep_addr;
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 	/* Get the normal mode usb pipe handle */
12020Sstevel@tonic-gate 	ph = usba_hcdi_get_ph_data(ehci_polledp->ehci_polled_usb_dev, ep_addr);
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 	/* Disable list processing and other things */
12050Sstevel@tonic-gate 	ehci_polled_stop_processing(ehci_polledp);
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	/* Get the polled mode ehci pipe private structure */
12080Sstevel@tonic-gate 	polled_pp = (ehci_pipe_private_t *)
12090Sstevel@tonic-gate 	    ehci_polledp->ehci_polled_input_pipe_handle->p_hcd_private;
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate 	/*
12120Sstevel@tonic-gate 	 * Before replacing the lattice, adjust the data togggle
12130Sstevel@tonic-gate 	 * on the on the ehci's interrupt ed
12140Sstevel@tonic-gate 	 */
12150Sstevel@tonic-gate 	polled_toggle = (Get_QH(polled_pp->pp_qh->qh_status) &
12160Sstevel@tonic-gate 	    EHCI_QH_STS_DATA_TOGGLE) ? DATA1:DATA0;
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	/*
12190Sstevel@tonic-gate 	 * If normal mode interrupt pipe endpoint is active, fix the
12200Sstevel@tonic-gate 	 * data toggle for this interrupt endpoint by getting the data
12210Sstevel@tonic-gate 	 * toggle information from the polled interrupt endpoint. Else
12220Sstevel@tonic-gate 	 * save the data toggle information in usb device structure.
12230Sstevel@tonic-gate 	 */
12240Sstevel@tonic-gate 	if (ph) {
12250Sstevel@tonic-gate 		/* Get the normal mode ehci pipe private structure */
12260Sstevel@tonic-gate 		pp = (ehci_pipe_private_t *)ph->p_hcd_private;
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 		real_toggle = (Get_QH(pp->pp_qh->qh_status) &
12290Sstevel@tonic-gate 		    EHCI_QH_STS_DATA_TOGGLE) ? DATA1:DATA0;
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 		if (polled_toggle != real_toggle) {
12320Sstevel@tonic-gate 			if (polled_toggle == DATA0) {
12330Sstevel@tonic-gate 				Set_QH(pp->pp_qh->qh_status,
12340Sstevel@tonic-gate 				    Get_QH(pp->pp_qh->qh_status) &
12350Sstevel@tonic-gate 				    ~EHCI_QH_STS_DATA_TOGGLE);
12360Sstevel@tonic-gate 			} else {
12370Sstevel@tonic-gate 				Set_QH(pp->pp_qh->qh_status,
12380Sstevel@tonic-gate 				    Get_QH(pp->pp_qh->qh_status) |
12390Sstevel@tonic-gate 				    EHCI_QH_STS_DATA_TOGGLE);
12400Sstevel@tonic-gate 			}
12410Sstevel@tonic-gate 		}
12420Sstevel@tonic-gate 	} else {
12430Sstevel@tonic-gate 		usba_hcdi_set_data_toggle(ehci_polledp->ehci_polled_usb_dev,
12440Sstevel@tonic-gate 		    ep_addr, polled_toggle);
12450Sstevel@tonic-gate 	}
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	/*
12480Sstevel@tonic-gate 	 * Only the last leave keyboard entry restore the save frame
12490Sstevel@tonic-gate 	 * list table and start processing.
12500Sstevel@tonic-gate 	 */
12510Sstevel@tonic-gate 	if (ehcip->ehci_polled_enter_count == 0) {
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 		/* Replace the lattice */
12540Sstevel@tonic-gate 		for (i = 0; i < EHCI_NUM_PERIODIC_FRAME_LISTS; i++) {
12550Sstevel@tonic-gate 			Set_PFLT(ehcip->ehci_periodic_frame_list_tablep->
12560Sstevel@tonic-gate 			    ehci_periodic_frame_list_table[i],
12570Sstevel@tonic-gate 			    ehcip->ehci_polled_frame_list_table[i]);
12580Sstevel@tonic-gate 		}
12590Sstevel@tonic-gate 		ehci_polled_start_processing(ehci_polledp);
12600Sstevel@tonic-gate 	}
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate #ifndef lint
12630Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
12640Sstevel@tonic-gate #endif
12650Sstevel@tonic-gate }
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate /*
12690Sstevel@tonic-gate  * ehci_polled_stop_processing:
12700Sstevel@tonic-gate  */
12710Sstevel@tonic-gate static void
ehci_polled_stop_processing(ehci_polled_t * ehci_polledp)12720Sstevel@tonic-gate ehci_polled_stop_processing(ehci_polled_t	*ehci_polledp)
12730Sstevel@tonic-gate {
12740Sstevel@tonic-gate 	ehci_state_t		*ehcip;
12750Sstevel@tonic-gate 	ehci_qh_t		*qh = ehci_polledp->ehci_polled_qh;
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate 	ehcip = ehci_polledp->ehci_polled_ehcip;
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 	/* First inactive this QH */
12800Sstevel@tonic-gate 	Set_QH(qh->qh_ctrl,
12810Sstevel@tonic-gate 	    Get_QH(qh->qh_ctrl) | EHCI_QH_CTRL_ED_INACTIVATE);
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate 	/* Only first leave keyboard entry turn off periodic list processing */
12840Sstevel@tonic-gate 	if (Get_OpReg(ehci_command) & EHCI_CMD_PERIODIC_SCHED_ENABLE) {
12850Sstevel@tonic-gate 		Set_OpReg(ehci_command, (Get_OpReg(ehci_command) &
12867425SGongtian.Zhao@Sun.COM 		    ~EHCI_CMD_PERIODIC_SCHED_ENABLE));
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 		/* Wait for few milliseconds */
12890Sstevel@tonic-gate 		drv_usecwait(EHCI_POLLED_TIMEWAIT);
12900Sstevel@tonic-gate 	}
12910Sstevel@tonic-gate 	/*
12920Sstevel@tonic-gate 	 * Now clear all required fields of QH
12930Sstevel@tonic-gate 	 * including inactive bit.
12940Sstevel@tonic-gate 	 */
12950Sstevel@tonic-gate 	Set_QH(qh->qh_ctrl,
12960Sstevel@tonic-gate 	    Get_QH(qh->qh_ctrl) & ~(EHCI_QH_CTRL_ED_INACTIVATE));
12970Sstevel@tonic-gate 	Set_QH(qh->qh_status,
12980Sstevel@tonic-gate 	    Get_QH(qh->qh_status) & ~(EHCI_QH_STS_XACT_STATUS));
12990Sstevel@tonic-gate 	Set_QH(qh->qh_curr_qtd, NULL);
13000Sstevel@tonic-gate 	Set_QH(qh->qh_alt_next_qtd, EHCI_QH_ALT_NEXT_QTD_PTR_VALID);
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	/*
13030Sstevel@tonic-gate 	 * Now look up at the QTD's that are in the active qtd list &
13040Sstevel@tonic-gate 	 * re-insert them back into the QH's QTD list.
13050Sstevel@tonic-gate 	 */
13060Sstevel@tonic-gate 	(void) ehci_polled_process_active_intr_qtd_list(ehci_polledp);
13070Sstevel@tonic-gate }
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate /*
13110Sstevel@tonic-gate  * ehci_polled_start_processing:
13120Sstevel@tonic-gate  */
13130Sstevel@tonic-gate static void
ehci_polled_start_processing(ehci_polled_t * ehci_polledp)13140Sstevel@tonic-gate ehci_polled_start_processing(ehci_polled_t	*ehci_polledp)
13150Sstevel@tonic-gate {
13160Sstevel@tonic-gate 	ehci_state_t		*ehcip;
13170Sstevel@tonic-gate 	uint32_t		mask;
13180Sstevel@tonic-gate 	ehci_regs_t		*ehci_polled_regsp;
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 	ehcip = ehci_polledp->ehci_polled_ehcip;
13210Sstevel@tonic-gate 	ehci_polled_regsp = &ehcip->ehci_polled_save_regs;
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 	mask = ((uint32_t)ehci_polled_regsp->ehci_interrupt &
13240Sstevel@tonic-gate 	    (EHCI_INTR_HOST_SYSTEM_ERROR | EHCI_INTR_FRAME_LIST_ROLLOVER |
13250Sstevel@tonic-gate 	    EHCI_INTR_USB_ERROR | EHCI_INTR_USB | EHCI_INTR_ASYNC_ADVANCE));
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 	/* Enable all required EHCI interrupts */
13280Sstevel@tonic-gate 	Set_OpReg(ehci_interrupt, mask);
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	mask = ((uint32_t)ehci_polled_regsp->ehci_command &
13310Sstevel@tonic-gate 	    (EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE));
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 	/* Enable all reuired list processing */
13340Sstevel@tonic-gate 	Set_OpReg(ehci_command, (Get_OpReg(ehci_command) | mask));
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate 	/* Wait for few milliseconds */
13370Sstevel@tonic-gate 	drv_usecwait(EHCI_POLLED_TIMEWAIT);
13380Sstevel@tonic-gate }
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 
13410Sstevel@tonic-gate /*
13420Sstevel@tonic-gate  * Polled read routines
13430Sstevel@tonic-gate  */
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate /*
13470Sstevel@tonic-gate  * ehci_polled_process_active_intr_qtd_list:
13480Sstevel@tonic-gate  *
13490Sstevel@tonic-gate  * This routine takes the QTD's off of the input done head and processes
13500Sstevel@tonic-gate  * them.  It returns the number of characters that have been copied for
13510Sstevel@tonic-gate  * input.
13520Sstevel@tonic-gate  */
13530Sstevel@tonic-gate static int
ehci_polled_process_active_intr_qtd_list(ehci_polled_t * ehci_polledp)13540Sstevel@tonic-gate ehci_polled_process_active_intr_qtd_list(ehci_polled_t	*ehci_polledp)
13550Sstevel@tonic-gate {
13560Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
13570Sstevel@tonic-gate 	ehci_qtd_t		*qtd, *next_qtd;
13580Sstevel@tonic-gate 	uint_t			num_characters = 0;
13590Sstevel@tonic-gate 	uint_t			ctrl;
13600Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
13610Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
13627425SGongtian.Zhao@Sun.COM 	usb_cr_t		error;
1363*9095SZhigang.Lu@Sun.COM 	int			pipe_attr, pipe_dir;
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 	/* Sync QH and QTD pool */
13660Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_no_sync_flag == B_FALSE) {
13670Sstevel@tonic-gate 		Sync_QH_QTD_Pool(ehcip);
13680Sstevel@tonic-gate 	}
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate 	/* Create done qtd list */
13710Sstevel@tonic-gate 	qtd = ehci_polled_create_done_qtd_list(ehci_polledp);
13720Sstevel@tonic-gate 
1373*9095SZhigang.Lu@Sun.COM 	pipe_attr = ehci_polledp->ehci_polled_input_pipe_handle->
1374*9095SZhigang.Lu@Sun.COM 	    p_ep.bmAttributes & USB_EP_ATTR_MASK;
1375*9095SZhigang.Lu@Sun.COM 	pipe_dir = ehci_polledp->ehci_polled_input_pipe_handle->
1376*9095SZhigang.Lu@Sun.COM 	    p_ep.bEndpointAddress & USB_EP_DIR_MASK;
13770Sstevel@tonic-gate 	/*
13780Sstevel@tonic-gate 	 * Traverse the list of transfer descriptors.  We can't destroy
13790Sstevel@tonic-gate 	 * the qtd_next pointers of these QTDs because we are using it
13800Sstevel@tonic-gate 	 * to traverse the done list.  Therefore, we can not put these
13810Sstevel@tonic-gate 	 * QTD's back on the QH until we are done processing all of them.
13820Sstevel@tonic-gate 	 */
13830Sstevel@tonic-gate 	while (qtd) {
13840Sstevel@tonic-gate 		/* Get next active QTD from the active QTD list */
13850Sstevel@tonic-gate 		next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
13860Sstevel@tonic-gate 		    Get_QTD(qtd->qtd_active_qtd_next));
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 		/* Obtain the transfer wrapper from the QTD */
13890Sstevel@tonic-gate 		tw = (ehci_trans_wrapper_t *)EHCI_LOOKUP_ID(
13900Sstevel@tonic-gate 		    (uint32_t)Get_QTD(qtd->qtd_trans_wrapper));
13910Sstevel@tonic-gate 
1392*9095SZhigang.Lu@Sun.COM 		/* Get ehci pipe from transfer wrapper */
13930Sstevel@tonic-gate 		pp = tw->tw_pipe_private;
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 		/* Look at the status */
13960Sstevel@tonic-gate 		ctrl = (uint_t)Get_QTD(qtd->qtd_ctrl) &
13970Sstevel@tonic-gate 		    (uint32_t)EHCI_QTD_CTRL_XACT_STATUS;
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 		error = ehci_check_for_error(ehcip, pp, tw, qtd, ctrl);
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate 		/*
14020Sstevel@tonic-gate 		 * Check to see if there is an error. If there is error
14030Sstevel@tonic-gate 		 * clear the halt condition in the Endpoint  Descriptor
14040Sstevel@tonic-gate 		 * (QH) associated with this Transfer  Descriptor (QTD).
14050Sstevel@tonic-gate 		 */
1406*9095SZhigang.Lu@Sun.COM 		if (error != USB_CR_OK) {
14070Sstevel@tonic-gate 			/* Clear the halt bit */
14080Sstevel@tonic-gate 			Set_QH(pp->pp_qh->qh_status,
14090Sstevel@tonic-gate 			    Get_QH(pp->pp_qh->qh_status) &
14100Sstevel@tonic-gate 			    ~(EHCI_QH_STS_XACT_STATUS));
1411*9095SZhigang.Lu@Sun.COM 		} else if (pipe_dir == USB_EP_DIR_IN) {
1412*9095SZhigang.Lu@Sun.COM 
1413*9095SZhigang.Lu@Sun.COM 			num_characters +=
1414*9095SZhigang.Lu@Sun.COM 			    ehci_polled_handle_normal_qtd(ehci_polledp,
1415*9095SZhigang.Lu@Sun.COM 			    qtd);
14160Sstevel@tonic-gate 		}
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate 		/* Insert this qtd back into QH's qtd list */
1419*9095SZhigang.Lu@Sun.COM 		switch (pipe_attr) {
1420*9095SZhigang.Lu@Sun.COM 		case USB_EP_ATTR_INTR:
1421*9095SZhigang.Lu@Sun.COM 			ehci_polled_insert_intr_qtd(ehci_polledp, qtd);
1422*9095SZhigang.Lu@Sun.COM 			break;
1423*9095SZhigang.Lu@Sun.COM 		case USB_EP_ATTR_BULK:
1424*9095SZhigang.Lu@Sun.COM 			if (tw->tw_qtd_free_list != NULL) {
1425*9095SZhigang.Lu@Sun.COM 				uint32_t	td_addr;
1426*9095SZhigang.Lu@Sun.COM 				td_addr = ehci_qtd_cpu_to_iommu(ehcip,
1427*9095SZhigang.Lu@Sun.COM 				    tw->tw_qtd_free_list);
1428*9095SZhigang.Lu@Sun.COM 				Set_QTD(qtd->qtd_tw_next_qtd, td_addr);
1429*9095SZhigang.Lu@Sun.COM 				Set_QTD(qtd->qtd_state, EHCI_QTD_DUMMY);
1430*9095SZhigang.Lu@Sun.COM 				tw->tw_qtd_free_list = qtd;
1431*9095SZhigang.Lu@Sun.COM 			} else {
1432*9095SZhigang.Lu@Sun.COM 				tw->tw_qtd_free_list = qtd;
1433*9095SZhigang.Lu@Sun.COM 				Set_QTD(qtd->qtd_tw_next_qtd, NULL);
1434*9095SZhigang.Lu@Sun.COM 				Set_QTD(qtd->qtd_state, EHCI_QTD_DUMMY);
1435*9095SZhigang.Lu@Sun.COM 			}
1436*9095SZhigang.Lu@Sun.COM 			break;
1437*9095SZhigang.Lu@Sun.COM 		}
14380Sstevel@tonic-gate 		qtd = next_qtd;
14390Sstevel@tonic-gate 	}
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 	return (num_characters);
14420Sstevel@tonic-gate }
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate /*
14460Sstevel@tonic-gate  * ehci_polled_handle_normal_qtd:
14470Sstevel@tonic-gate  */
14480Sstevel@tonic-gate static int
ehci_polled_handle_normal_qtd(ehci_polled_t * ehci_polledp,ehci_qtd_t * qtd)14490Sstevel@tonic-gate ehci_polled_handle_normal_qtd(
14500Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp,
14510Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
14520Sstevel@tonic-gate {
14530Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
14540Sstevel@tonic-gate 	uchar_t			*buf;
14550Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
14560Sstevel@tonic-gate 	size_t			length;
14570Sstevel@tonic-gate 	uint32_t		residue;
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 	/* Obtain the transfer wrapper from the QTD */
14600Sstevel@tonic-gate 	tw = (ehci_trans_wrapper_t *)EHCI_LOOKUP_ID((uint32_t)
14617425SGongtian.Zhao@Sun.COM 	    Get_QTD(qtd->qtd_trans_wrapper));
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate 	ASSERT(tw != NULL);
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 	buf = (uchar_t *)tw->tw_buf;
14660Sstevel@tonic-gate 
14670Sstevel@tonic-gate 	length = tw->tw_length;
14680Sstevel@tonic-gate 
14690Sstevel@tonic-gate 	/*
14700Sstevel@tonic-gate 	 * If "Total bytes of xfer" in control field of qtd is not equal to 0,
14710Sstevel@tonic-gate 	 * then we received less data from the usb device than requested by us.
14720Sstevel@tonic-gate 	 * In that case, get the actual received data size.
14730Sstevel@tonic-gate 	 */
14740Sstevel@tonic-gate 	residue = ((Get_QTD(qtd->qtd_ctrl) &
14750Sstevel@tonic-gate 	    EHCI_QTD_CTRL_BYTES_TO_XFER) >> EHCI_QTD_CTRL_BYTES_TO_XFER_SHIFT);
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate 	if (residue) {
14780Sstevel@tonic-gate 
14791500Ssl147100 		length = Get_QTD(qtd->qtd_xfer_offs) +
14801500Ssl147100 		    Get_QTD(qtd->qtd_xfer_len) - residue;
14810Sstevel@tonic-gate 	}
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	/* Sync IO buffer */
14840Sstevel@tonic-gate 	if (ehci_polledp->ehci_polled_no_sync_flag == B_FALSE) {
14850Sstevel@tonic-gate 		Sync_IO_Buffer(tw->tw_dmahandle, length);
14860Sstevel@tonic-gate 	}
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 	/* Copy the data into the message */
14890Sstevel@tonic-gate 	bcopy(buf, ehci_polledp->ehci_polled_buf, length);
14900Sstevel@tonic-gate 
14917492SZhigang.Lu@Sun.COM 	return ((int)length);
14920Sstevel@tonic-gate }
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 
14950Sstevel@tonic-gate /*
1496*9095SZhigang.Lu@Sun.COM  * ehci_polled_insert_intr_qtd:
14970Sstevel@tonic-gate  *
14980Sstevel@tonic-gate  * Insert a Transfer Descriptor (QTD) on an Endpoint Descriptor (QH).
14990Sstevel@tonic-gate  */
15000Sstevel@tonic-gate static void
ehci_polled_insert_intr_qtd(ehci_polled_t * ehci_polledp,ehci_qtd_t * qtd)1501*9095SZhigang.Lu@Sun.COM ehci_polled_insert_intr_qtd(
15020Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp,
15030Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
15040Sstevel@tonic-gate {
15050Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
15060Sstevel@tonic-gate 	ehci_qtd_t		*curr_dummy_qtd, *next_dummy_qtd;
15070Sstevel@tonic-gate 	ehci_qtd_t		*new_dummy_qtd;
15080Sstevel@tonic-gate 	uint_t			qtd_control;
15090Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
15100Sstevel@tonic-gate 	ehci_qh_t		*qh;
15110Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	/* Obtain the transfer wrapper from the QTD */
15140Sstevel@tonic-gate 	tw = (ehci_trans_wrapper_t *)EHCI_LOOKUP_ID(
15150Sstevel@tonic-gate 	    (uint32_t)Get_QTD(qtd->qtd_trans_wrapper));
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 	pp = tw->tw_pipe_private;
15180Sstevel@tonic-gate 
15190Sstevel@tonic-gate 	/* Obtain the endpoint and interrupt request */
15200Sstevel@tonic-gate 	qh = pp->pp_qh;
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 	/*
15230Sstevel@tonic-gate 	 * Take this QTD off the transfer wrapper's list since
15240Sstevel@tonic-gate 	 * the pipe is FIFO, this must be the first QTD on the
15250Sstevel@tonic-gate 	 * list.
15260Sstevel@tonic-gate 	 */
15270Sstevel@tonic-gate 	ASSERT((ehci_qtd_t *)tw->tw_qtd_head == qtd);
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 	tw->tw_qtd_head = (ehci_qtd_t *)
15300Sstevel@tonic-gate 	    ehci_qtd_iommu_to_cpu(ehcip, Get_QTD(qtd->qtd_tw_next_qtd));
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate 	/*
15330Sstevel@tonic-gate 	 * If the head becomes NULL, then there are no more
15340Sstevel@tonic-gate 	 * active QTD's for this transfer wrapper. Also	set
15350Sstevel@tonic-gate 	 * the tail to NULL.
15360Sstevel@tonic-gate 	 */
15370Sstevel@tonic-gate 	if (tw->tw_qtd_head == NULL) {
15380Sstevel@tonic-gate 		tw->tw_qtd_tail = NULL;
15390Sstevel@tonic-gate 	}
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate 	/* Convert current valid QTD as new dummy QTD */
15420Sstevel@tonic-gate 	bzero((char *)qtd, sizeof (ehci_qtd_t));
15430Sstevel@tonic-gate 	Set_QTD(qtd->qtd_state, EHCI_QTD_DUMMY);
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	/* Rename qtd as new_dummy_qtd */
15460Sstevel@tonic-gate 	new_dummy_qtd = qtd;
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate 	/* Get the current and next dummy QTDs */
15490Sstevel@tonic-gate 	curr_dummy_qtd = ehci_qtd_iommu_to_cpu(ehcip,
15500Sstevel@tonic-gate 	    Get_QH(qh->qh_dummy_qtd));
15510Sstevel@tonic-gate 	next_dummy_qtd = ehci_qtd_iommu_to_cpu(ehcip,
15520Sstevel@tonic-gate 	    Get_QTD(curr_dummy_qtd->qtd_next_qtd));
15530Sstevel@tonic-gate 
15540Sstevel@tonic-gate 	/* Update QH's dummy qtd field */
15550Sstevel@tonic-gate 	Set_QH(qh->qh_dummy_qtd, ehci_qtd_cpu_to_iommu(ehcip, next_dummy_qtd));
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 	/* Update next dummy's next qtd pointer */
15580Sstevel@tonic-gate 	Set_QTD(next_dummy_qtd->qtd_next_qtd,
15590Sstevel@tonic-gate 	    ehci_qtd_cpu_to_iommu(ehcip, new_dummy_qtd));
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 	qtd_control = (tw->tw_direction | EHCI_QTD_CTRL_INTR_ON_COMPLETE);
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate 	/*
15640Sstevel@tonic-gate 	 * Fill in the current dummy qtd and
15650Sstevel@tonic-gate 	 * add the new dummy to the end.
15660Sstevel@tonic-gate 	 */
15670Sstevel@tonic-gate 	ehci_polled_fill_in_qtd(ehcip, curr_dummy_qtd, qtd_control,
15681500Ssl147100 	    0, tw->tw_length, tw);
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 	/* Insert this qtd onto the tw */
15710Sstevel@tonic-gate 	ehci_polled_insert_qtd_on_tw(ehcip, tw, curr_dummy_qtd);
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 	/* Insert this qtd into active interrupt QTD list */
15740Sstevel@tonic-gate 	ehci_polled_insert_qtd_into_active_intr_qtd_list(
15750Sstevel@tonic-gate 	    ehci_polledp, curr_dummy_qtd);
15760Sstevel@tonic-gate }
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 
1579*9095SZhigang.Lu@Sun.COM static void
ehci_polled_insert_bulk_qtd(ehci_polled_t * ehci_polledp)1580*9095SZhigang.Lu@Sun.COM ehci_polled_insert_bulk_qtd(
1581*9095SZhigang.Lu@Sun.COM 	ehci_polled_t	*ehci_polledp)
1582*9095SZhigang.Lu@Sun.COM {
1583*9095SZhigang.Lu@Sun.COM 	ehci_state_t		*ehcip;
1584*9095SZhigang.Lu@Sun.COM 	ehci_pipe_private_t	*pp;
1585*9095SZhigang.Lu@Sun.COM 	ehci_trans_wrapper_t	*tw;
1586*9095SZhigang.Lu@Sun.COM 	ehci_qh_t		*qh;
1587*9095SZhigang.Lu@Sun.COM 	ehci_qtd_t		*new_dummy_qtd;
1588*9095SZhigang.Lu@Sun.COM 	ehci_qtd_t		*curr_dummy_qtd, *next_dummy_qtd;
1589*9095SZhigang.Lu@Sun.COM 	uint_t			qtd_control;
1590*9095SZhigang.Lu@Sun.COM 
1591*9095SZhigang.Lu@Sun.COM 	ehcip = ehci_polledp->ehci_polled_ehcip;
1592*9095SZhigang.Lu@Sun.COM 	pp = (ehci_pipe_private_t *)ehci_polledp->
1593*9095SZhigang.Lu@Sun.COM 	    ehci_polled_input_pipe_handle->p_hcd_private;
1594*9095SZhigang.Lu@Sun.COM 	tw = pp->pp_tw_head;
1595*9095SZhigang.Lu@Sun.COM 	qh = ehci_polledp->ehci_polled_qh;
1596*9095SZhigang.Lu@Sun.COM 	new_dummy_qtd = tw->tw_qtd_free_list;
1597*9095SZhigang.Lu@Sun.COM 
1598*9095SZhigang.Lu@Sun.COM 	if (new_dummy_qtd == NULL) {
1599*9095SZhigang.Lu@Sun.COM 		return;
1600*9095SZhigang.Lu@Sun.COM 	}
1601*9095SZhigang.Lu@Sun.COM 
1602*9095SZhigang.Lu@Sun.COM 	tw->tw_qtd_free_list = ehci_qtd_iommu_to_cpu(ehcip,
1603*9095SZhigang.Lu@Sun.COM 	    Get_QTD(new_dummy_qtd->qtd_tw_next_qtd));
1604*9095SZhigang.Lu@Sun.COM 	Set_QTD(new_dummy_qtd->qtd_tw_next_qtd, NULL);
1605*9095SZhigang.Lu@Sun.COM 
1606*9095SZhigang.Lu@Sun.COM 	/* Get the current and next dummy QTDs */
1607*9095SZhigang.Lu@Sun.COM 	curr_dummy_qtd = ehci_qtd_iommu_to_cpu(ehcip,
1608*9095SZhigang.Lu@Sun.COM 	    Get_QH(qh->qh_dummy_qtd));
1609*9095SZhigang.Lu@Sun.COM 	next_dummy_qtd = ehci_qtd_iommu_to_cpu(ehcip,
1610*9095SZhigang.Lu@Sun.COM 	    Get_QTD(curr_dummy_qtd->qtd_next_qtd));
1611*9095SZhigang.Lu@Sun.COM 
1612*9095SZhigang.Lu@Sun.COM 	/* Update QH's dummy qtd field */
1613*9095SZhigang.Lu@Sun.COM 	Set_QH(qh->qh_dummy_qtd, ehci_qtd_cpu_to_iommu(ehcip, next_dummy_qtd));
1614*9095SZhigang.Lu@Sun.COM 
1615*9095SZhigang.Lu@Sun.COM 	/* Update next dummy's next qtd pointer */
1616*9095SZhigang.Lu@Sun.COM 	Set_QTD(next_dummy_qtd->qtd_next_qtd,
1617*9095SZhigang.Lu@Sun.COM 	    ehci_qtd_cpu_to_iommu(ehcip, new_dummy_qtd));
1618*9095SZhigang.Lu@Sun.COM 
1619*9095SZhigang.Lu@Sun.COM 	qtd_control = (tw->tw_direction | EHCI_QTD_CTRL_INTR_ON_COMPLETE);
1620*9095SZhigang.Lu@Sun.COM 
1621*9095SZhigang.Lu@Sun.COM 	/*
1622*9095SZhigang.Lu@Sun.COM 	 * Fill in the current dummy qtd and
1623*9095SZhigang.Lu@Sun.COM 	 * add the new dummy to the end.
1624*9095SZhigang.Lu@Sun.COM 	 */
1625*9095SZhigang.Lu@Sun.COM 	ehci_polled_fill_in_qtd(ehcip, curr_dummy_qtd, qtd_control,
1626*9095SZhigang.Lu@Sun.COM 	    0, tw->tw_length, tw);
1627*9095SZhigang.Lu@Sun.COM 
1628*9095SZhigang.Lu@Sun.COM 	/* Insert this qtd into active interrupt QTD list */
1629*9095SZhigang.Lu@Sun.COM 	ehci_polled_insert_qtd_into_active_intr_qtd_list(
1630*9095SZhigang.Lu@Sun.COM 	    ehci_polledp, curr_dummy_qtd);
1631*9095SZhigang.Lu@Sun.COM }
1632*9095SZhigang.Lu@Sun.COM 
1633*9095SZhigang.Lu@Sun.COM 
16340Sstevel@tonic-gate /*
16350Sstevel@tonic-gate  * ehci_polled_fill_in_qtd:
16360Sstevel@tonic-gate  *
16370Sstevel@tonic-gate  * Fill in the fields of a Transfer Descriptor (QTD).
16381500Ssl147100  * The "Buffer Pointer" fields of a QTD are retrieved from the TW
16391500Ssl147100  * it is associated with.
16400Sstevel@tonic-gate  *
16410Sstevel@tonic-gate  * Unlike the it's ehci_fill_in_qtd counterpart, we do not
16420Sstevel@tonic-gate  * set the alternative ptr in polled mode.  There is not need
16430Sstevel@tonic-gate  * for it in polled mode, because it doesn't need to cleanup
16440Sstevel@tonic-gate  * short xfer conditions.
16451500Ssl147100  *
16461500Ssl147100  * Note:
16471500Ssl147100  * qtd_dma_offs - the starting offset into the TW buffer, where the QTD
16487425SGongtian.Zhao@Sun.COM  *		  should transfer from. It should be 4K aligned. And when
16497425SGongtian.Zhao@Sun.COM  *		  a TW has more than one QTDs, the QTDs must be filled in
16507425SGongtian.Zhao@Sun.COM  *		  increasing order.
16511500Ssl147100  * qtd_length - the total bytes to transfer.
16520Sstevel@tonic-gate  */
16530Sstevel@tonic-gate static void
ehci_polled_fill_in_qtd(ehci_state_t * ehcip,ehci_qtd_t * qtd,uint_t qtd_ctrl,size_t qtd_dma_offs,size_t qtd_length,ehci_trans_wrapper_t * tw)16540Sstevel@tonic-gate ehci_polled_fill_in_qtd(
16550Sstevel@tonic-gate 	ehci_state_t		*ehcip,
16560Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
16570Sstevel@tonic-gate 	uint_t			qtd_ctrl,
16581500Ssl147100 	size_t			qtd_dma_offs,
16590Sstevel@tonic-gate 	size_t			qtd_length,
16600Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw)
16610Sstevel@tonic-gate {
16621500Ssl147100 	uint32_t		buf_addr;
16630Sstevel@tonic-gate 	size_t			buf_len = qtd_length;
16640Sstevel@tonic-gate 	uint32_t		ctrl = qtd_ctrl;
16650Sstevel@tonic-gate 	uint_t			i = 0;
16661500Ssl147100 	int			rem_len;
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate 	/* Assert that the qtd to be filled in is a dummy */
16690Sstevel@tonic-gate 	ASSERT(Get_QTD(qtd->qtd_state) == EHCI_QTD_DUMMY);
16700Sstevel@tonic-gate 
16710Sstevel@tonic-gate 	/* Change QTD's state Active */
16720Sstevel@tonic-gate 	Set_QTD(qtd->qtd_state, EHCI_QTD_ACTIVE);
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 	/* Set the total length data tarnsfer */
16750Sstevel@tonic-gate 	ctrl |= (((qtd_length << EHCI_QTD_CTRL_BYTES_TO_XFER_SHIFT)
16760Sstevel@tonic-gate 	    & EHCI_QTD_CTRL_BYTES_TO_XFER) | EHCI_QTD_CTRL_MAX_ERR_COUNTS);
16770Sstevel@tonic-gate 
16780Sstevel@tonic-gate 	/*
16791500Ssl147100 	 * QTDs must be filled in increasing DMA offset order.
16801500Ssl147100 	 * tw_dma_offs is initialized to be 0 at TW creation and
16811500Ssl147100 	 * is only increased in this function.
16821500Ssl147100 	 */
16831500Ssl147100 	ASSERT(buf_len == 0 || qtd_dma_offs >= tw->tw_dma_offs);
16841500Ssl147100 
16851500Ssl147100 	/*
16861500Ssl147100 	 * Save the starting dma buffer offset used and
16870Sstevel@tonic-gate 	 * length of data that will be transfered in
16880Sstevel@tonic-gate 	 * the current QTD.
16890Sstevel@tonic-gate 	 */
16901500Ssl147100 	Set_QTD(qtd->qtd_xfer_offs, qtd_dma_offs);
16910Sstevel@tonic-gate 	Set_QTD(qtd->qtd_xfer_len, buf_len);
16920Sstevel@tonic-gate 
16930Sstevel@tonic-gate 	while (buf_len) {
16941500Ssl147100 		/*
16951500Ssl147100 		 * Advance to the next DMA cookie until finding the cookie
16961500Ssl147100 		 * that qtd_dma_offs falls in.
16971500Ssl147100 		 * It is very likely this loop will never repeat more than
16981500Ssl147100 		 * once. It is here just to accommodate the case qtd_dma_offs
16991500Ssl147100 		 * is increased by multiple cookies during two consecutive
17001500Ssl147100 		 * calls into this function. In that case, the interim DMA
17011500Ssl147100 		 * buffer is allowed to be skipped.
17021500Ssl147100 		 */
17031500Ssl147100 		while ((tw->tw_dma_offs + tw->tw_cookie.dmac_size) <=
17041500Ssl147100 		    qtd_dma_offs) {
17051500Ssl147100 			/*
17061500Ssl147100 			 * tw_dma_offs always points to the starting offset
17071500Ssl147100 			 * of a cookie
17081500Ssl147100 			 */
17091500Ssl147100 			tw->tw_dma_offs += tw->tw_cookie.dmac_size;
17101500Ssl147100 			ddi_dma_nextcookie(tw->tw_dmahandle, &tw->tw_cookie);
17111500Ssl147100 			tw->tw_cookie_idx++;
17121500Ssl147100 			ASSERT(tw->tw_cookie_idx < tw->tw_ncookies);
17131500Ssl147100 		}
17141500Ssl147100 
17151500Ssl147100 		/*
17161500Ssl147100 		 * Counting the remained buffer length to be filled in
17171500Ssl147100 		 * the QTD for current DMA cookie
17181500Ssl147100 		 */
17191500Ssl147100 		rem_len = (tw->tw_dma_offs + tw->tw_cookie.dmac_size) -
17201500Ssl147100 		    qtd_dma_offs;
17211500Ssl147100 
17220Sstevel@tonic-gate 		/* Update the beginning of the buffer */
17231500Ssl147100 		buf_addr = (qtd_dma_offs - tw->tw_dma_offs) +
17241500Ssl147100 		    tw->tw_cookie.dmac_address;
17251500Ssl147100 		ASSERT((buf_addr % EHCI_4K_ALIGN) == 0);
17260Sstevel@tonic-gate 		Set_QTD(qtd->qtd_buf[i], buf_addr);
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 		if (buf_len <= EHCI_MAX_QTD_BUF_SIZE) {
17291500Ssl147100 			ASSERT(buf_len <= rem_len);
17300Sstevel@tonic-gate 			break;
17310Sstevel@tonic-gate 		} else {
17321500Ssl147100 			ASSERT(rem_len >= EHCI_MAX_QTD_BUF_SIZE);
17330Sstevel@tonic-gate 			buf_len -= EHCI_MAX_QTD_BUF_SIZE;
17341500Ssl147100 			qtd_dma_offs += EHCI_MAX_QTD_BUF_SIZE;
17350Sstevel@tonic-gate 		}
17360Sstevel@tonic-gate 
17370Sstevel@tonic-gate 		i++;
17380Sstevel@tonic-gate 	}
17390Sstevel@tonic-gate 
17400Sstevel@tonic-gate 	/*
17410Sstevel@tonic-gate 	 * For control, bulk and interrupt QTD, now
17420Sstevel@tonic-gate 	 * enable current QTD by setting active bit.
17430Sstevel@tonic-gate 	 */
17440Sstevel@tonic-gate 	Set_QTD(qtd->qtd_ctrl, (ctrl | EHCI_QTD_CTRL_ACTIVE_XACT));
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate 	Set_QTD(qtd->qtd_trans_wrapper, (uint32_t)tw->tw_id);
17470Sstevel@tonic-gate }
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 
17500Sstevel@tonic-gate /*
17510Sstevel@tonic-gate  * ehci_polled_insert_qtd_on_tw:
17520Sstevel@tonic-gate  *
17530Sstevel@tonic-gate  * The transfer wrapper keeps a list of all Transfer Descriptors (QTD) that
17540Sstevel@tonic-gate  * are allocated for this transfer. Insert a QTD  onto this list. The  list
17550Sstevel@tonic-gate  * of QTD's does not include the dummy QTD that is at the end of the list of
17560Sstevel@tonic-gate  * QTD's for the endpoint.
17570Sstevel@tonic-gate  */
17580Sstevel@tonic-gate static void
ehci_polled_insert_qtd_on_tw(ehci_state_t * ehcip,ehci_trans_wrapper_t * tw,ehci_qtd_t * qtd)17590Sstevel@tonic-gate ehci_polled_insert_qtd_on_tw(
17600Sstevel@tonic-gate 	ehci_state_t		*ehcip,
17610Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
17620Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
17630Sstevel@tonic-gate {
17640Sstevel@tonic-gate 	/*
17650Sstevel@tonic-gate 	 * Set the next pointer to NULL because
17660Sstevel@tonic-gate 	 * this is the last QTD on list.
17670Sstevel@tonic-gate 	 */
17680Sstevel@tonic-gate 	Set_QTD(qtd->qtd_tw_next_qtd, NULL);
17690Sstevel@tonic-gate 
17700Sstevel@tonic-gate 	if (tw->tw_qtd_head == NULL) {
17710Sstevel@tonic-gate 		ASSERT(tw->tw_qtd_tail == NULL);
17720Sstevel@tonic-gate 		tw->tw_qtd_head = qtd;
17730Sstevel@tonic-gate 		tw->tw_qtd_tail = qtd;
17740Sstevel@tonic-gate 	} else {
17750Sstevel@tonic-gate 		ehci_qtd_t *dummy = (ehci_qtd_t *)tw->tw_qtd_tail;
17760Sstevel@tonic-gate 
17770Sstevel@tonic-gate 		ASSERT(dummy != NULL);
17780Sstevel@tonic-gate 		ASSERT(dummy != qtd);
17790Sstevel@tonic-gate 		ASSERT(Get_QTD(qtd->qtd_state) != EHCI_QTD_DUMMY);
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate 		/* Add the qtd to the end of the list */
17820Sstevel@tonic-gate 		Set_QTD(dummy->qtd_tw_next_qtd,
17830Sstevel@tonic-gate 		    ehci_qtd_cpu_to_iommu(ehcip, qtd));
17840Sstevel@tonic-gate 
17850Sstevel@tonic-gate 		tw->tw_qtd_tail = qtd;
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate 		ASSERT(Get_QTD(qtd->qtd_tw_next_qtd) == NULL);
17880Sstevel@tonic-gate 	}
17890Sstevel@tonic-gate }
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 
17920Sstevel@tonic-gate /*
17930Sstevel@tonic-gate  * ehci_polled_create_done_qtd_list:
17940Sstevel@tonic-gate  *
17950Sstevel@tonic-gate  * Create done qtd list from active qtd list.
17960Sstevel@tonic-gate  */
17970Sstevel@tonic-gate static ehci_qtd_t *
ehci_polled_create_done_qtd_list(ehci_polled_t * ehci_polledp)17980Sstevel@tonic-gate ehci_polled_create_done_qtd_list(
17990Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp)
18000Sstevel@tonic-gate {
18010Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
18020Sstevel@tonic-gate 	ehci_qtd_t		*curr_qtd = NULL, *next_qtd = NULL;
18030Sstevel@tonic-gate 	ehci_qtd_t		*done_qtd_list = NULL, *last_done_qtd = NULL;
18040Sstevel@tonic-gate 
18050Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
18060Sstevel@tonic-gate 	    "ehci_polled_create_done_qtd_list:");
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 	curr_qtd = ehci_polledp->ehci_polled_active_intr_qtd_list;
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate 	while (curr_qtd) {
18110Sstevel@tonic-gate 
18120Sstevel@tonic-gate 		/* Get next qtd from the active qtd list */
18130Sstevel@tonic-gate 		next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
18140Sstevel@tonic-gate 		    Get_QTD(curr_qtd->qtd_active_qtd_next));
18150Sstevel@tonic-gate 
18160Sstevel@tonic-gate 		/* Check this QTD has been processed by Host Controller */
18170Sstevel@tonic-gate 		if (!(Get_QTD(curr_qtd->qtd_ctrl) &
18180Sstevel@tonic-gate 		    EHCI_QTD_CTRL_ACTIVE_XACT)) {
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate 			/* Remove this QTD from active QTD list */
18210Sstevel@tonic-gate 			ehci_polled_remove_qtd_from_active_intr_qtd_list(
18220Sstevel@tonic-gate 			    ehci_polledp, curr_qtd);
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 			Set_QTD(curr_qtd->qtd_active_qtd_next, NULL);
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate 			if (done_qtd_list) {
18270Sstevel@tonic-gate 				Set_QTD(last_done_qtd->qtd_active_qtd_next,
18280Sstevel@tonic-gate 				    ehci_qtd_cpu_to_iommu(ehcip, curr_qtd));
18290Sstevel@tonic-gate 
18300Sstevel@tonic-gate 				last_done_qtd = curr_qtd;
18310Sstevel@tonic-gate 			} else {
18320Sstevel@tonic-gate 				done_qtd_list = curr_qtd;
18330Sstevel@tonic-gate 				last_done_qtd = curr_qtd;
18340Sstevel@tonic-gate 			}
18350Sstevel@tonic-gate 		}
18360Sstevel@tonic-gate 
18370Sstevel@tonic-gate 		curr_qtd = next_qtd;
18380Sstevel@tonic-gate 	}
18390Sstevel@tonic-gate 
18400Sstevel@tonic-gate 	return (done_qtd_list);
18410Sstevel@tonic-gate }
18420Sstevel@tonic-gate 
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate /*
18450Sstevel@tonic-gate  * ehci_polled_insert_qtd_into_active_intr_qtd_list:
18460Sstevel@tonic-gate  *
18470Sstevel@tonic-gate  * Insert current QTD into active interrupt QTD list.
18480Sstevel@tonic-gate  */
18490Sstevel@tonic-gate static void
ehci_polled_insert_qtd_into_active_intr_qtd_list(ehci_polled_t * ehci_polledp,ehci_qtd_t * qtd)18500Sstevel@tonic-gate ehci_polled_insert_qtd_into_active_intr_qtd_list(
18510Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp,
18520Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
18530Sstevel@tonic-gate {
18540Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
18550Sstevel@tonic-gate 	ehci_qtd_t		*curr_qtd, *next_qtd;
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate 	curr_qtd = ehci_polledp->ehci_polled_active_intr_qtd_list;
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 	/* Insert this qtd into active intr qtd list */
18600Sstevel@tonic-gate 	if (curr_qtd) {
18610Sstevel@tonic-gate 		next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
18620Sstevel@tonic-gate 		    Get_QTD(curr_qtd->qtd_active_qtd_next));
18630Sstevel@tonic-gate 
18640Sstevel@tonic-gate 		while (next_qtd) {
18650Sstevel@tonic-gate 			curr_qtd = next_qtd;
18660Sstevel@tonic-gate 			next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
18670Sstevel@tonic-gate 			    Get_QTD(curr_qtd->qtd_active_qtd_next));
18680Sstevel@tonic-gate 		}
18690Sstevel@tonic-gate 
18700Sstevel@tonic-gate 		Set_QTD(qtd->qtd_active_qtd_prev,
18710Sstevel@tonic-gate 		    ehci_qtd_cpu_to_iommu(ehcip, curr_qtd));
18720Sstevel@tonic-gate 
18730Sstevel@tonic-gate 		Set_QTD(curr_qtd->qtd_active_qtd_next,
18740Sstevel@tonic-gate 		    ehci_qtd_cpu_to_iommu(ehcip, qtd));
18750Sstevel@tonic-gate 	} else {
18760Sstevel@tonic-gate 		ehci_polledp->ehci_polled_active_intr_qtd_list = qtd;
18770Sstevel@tonic-gate 		Set_QTD(qtd->qtd_active_qtd_next, NULL);
18780Sstevel@tonic-gate 		Set_QTD(qtd->qtd_active_qtd_prev, NULL);
18790Sstevel@tonic-gate 	}
18800Sstevel@tonic-gate }
18810Sstevel@tonic-gate 
18820Sstevel@tonic-gate 
18830Sstevel@tonic-gate /*
18840Sstevel@tonic-gate  * ehci_polled_remove_qtd_from_active_intr_qtd_list:
18850Sstevel@tonic-gate  *
18860Sstevel@tonic-gate  * Remove current QTD from the active QTD list.
18870Sstevel@tonic-gate  */
18880Sstevel@tonic-gate void
ehci_polled_remove_qtd_from_active_intr_qtd_list(ehci_polled_t * ehci_polledp,ehci_qtd_t * qtd)18890Sstevel@tonic-gate ehci_polled_remove_qtd_from_active_intr_qtd_list(
18900Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp,
18910Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
18920Sstevel@tonic-gate {
18930Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
18940Sstevel@tonic-gate 	ehci_qtd_t		*curr_qtd, *prev_qtd, *next_qtd;
18950Sstevel@tonic-gate 
18960Sstevel@tonic-gate 	ASSERT(qtd != NULL);
18970Sstevel@tonic-gate 
18980Sstevel@tonic-gate 	curr_qtd = ehci_polledp->ehci_polled_active_intr_qtd_list;
18990Sstevel@tonic-gate 
19000Sstevel@tonic-gate 	while ((curr_qtd) && (curr_qtd != qtd)) {
19010Sstevel@tonic-gate 		curr_qtd = ehci_qtd_iommu_to_cpu(ehcip,
19020Sstevel@tonic-gate 		    Get_QTD(curr_qtd->qtd_active_qtd_next));
19030Sstevel@tonic-gate 	}
19040Sstevel@tonic-gate 
19050Sstevel@tonic-gate 	if ((curr_qtd) && (curr_qtd == qtd)) {
19060Sstevel@tonic-gate 		prev_qtd = ehci_qtd_iommu_to_cpu(ehcip,
19070Sstevel@tonic-gate 		    Get_QTD(curr_qtd->qtd_active_qtd_prev));
19080Sstevel@tonic-gate 		next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
19090Sstevel@tonic-gate 		    Get_QTD(curr_qtd->qtd_active_qtd_next));
19100Sstevel@tonic-gate 
19110Sstevel@tonic-gate 		if (prev_qtd) {
19120Sstevel@tonic-gate 			Set_QTD(prev_qtd->qtd_active_qtd_next,
19130Sstevel@tonic-gate 			    Get_QTD(curr_qtd->qtd_active_qtd_next));
19140Sstevel@tonic-gate 		} else {
19150Sstevel@tonic-gate 			ehci_polledp->
19160Sstevel@tonic-gate 			    ehci_polled_active_intr_qtd_list = next_qtd;
19170Sstevel@tonic-gate 		}
19180Sstevel@tonic-gate 
19190Sstevel@tonic-gate 		if (next_qtd) {
19200Sstevel@tonic-gate 			Set_QTD(next_qtd->qtd_active_qtd_prev,
19210Sstevel@tonic-gate 			    Get_QTD(curr_qtd->qtd_active_qtd_prev));
19220Sstevel@tonic-gate 		}
19230Sstevel@tonic-gate 	}
19240Sstevel@tonic-gate }
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate 
19270Sstevel@tonic-gate /*
19280Sstevel@tonic-gate  * ehci_polled_traverse_qtds:
19290Sstevel@tonic-gate  *
19300Sstevel@tonic-gate  * Traverse the list of QTDs for given pipe using transfer wrapper.  Since
19310Sstevel@tonic-gate  * the endpoint is marked as Halted, the Host Controller (HC) is no longer
19320Sstevel@tonic-gate  * accessing these QTDs. Remove all the QTDs that are attached to endpoint.
19330Sstevel@tonic-gate  */
19340Sstevel@tonic-gate static void
ehci_polled_traverse_qtds(ehci_polled_t * ehci_polledp,usba_pipe_handle_data_t * ph)19350Sstevel@tonic-gate ehci_polled_traverse_qtds(
19360Sstevel@tonic-gate 	ehci_polled_t		*ehci_polledp,
19370Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph)
19380Sstevel@tonic-gate {
19390Sstevel@tonic-gate 	ehci_state_t		*ehcip = ehci_polledp->ehci_polled_ehcip;
19400Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
19410Sstevel@tonic-gate 	ehci_trans_wrapper_t	*next_tw;
19420Sstevel@tonic-gate 	ehci_qtd_t		*qtd;
19430Sstevel@tonic-gate 	ehci_qtd_t		*next_qtd;
19440Sstevel@tonic-gate 
19450Sstevel@tonic-gate 	/* Process the transfer wrappers for this pipe */
19460Sstevel@tonic-gate 	next_tw = pp->pp_tw_head;
19470Sstevel@tonic-gate 
19480Sstevel@tonic-gate 	while (next_tw) {
19490Sstevel@tonic-gate 		qtd = (ehci_qtd_t *)next_tw->tw_qtd_head;
19500Sstevel@tonic-gate 
19510Sstevel@tonic-gate 		/* Walk through each QTD for this transfer wrapper */
19520Sstevel@tonic-gate 		while (qtd) {
19530Sstevel@tonic-gate 			/* Remove this QTD from active QTD list */
19540Sstevel@tonic-gate 			ehci_polled_remove_qtd_from_active_intr_qtd_list(
19550Sstevel@tonic-gate 			    ehci_polledp, qtd);
19560Sstevel@tonic-gate 
19570Sstevel@tonic-gate 			next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
19580Sstevel@tonic-gate 			    Get_QTD(qtd->qtd_tw_next_qtd));
19590Sstevel@tonic-gate 
19600Sstevel@tonic-gate 			/* Deallocate this QTD */
19610Sstevel@tonic-gate 			ehci_deallocate_qtd(ehcip, qtd);
19620Sstevel@tonic-gate 
19630Sstevel@tonic-gate 			qtd = next_qtd;
19640Sstevel@tonic-gate 		}
19650Sstevel@tonic-gate 
19660Sstevel@tonic-gate 		next_tw = next_tw->tw_next;
19670Sstevel@tonic-gate 	}
19680Sstevel@tonic-gate 
19690Sstevel@tonic-gate 	/* Clear current qtd pointer */
19700Sstevel@tonic-gate 	Set_QH(pp->pp_qh->qh_curr_qtd, (uint32_t)0x00000000);
19710Sstevel@tonic-gate 
19720Sstevel@tonic-gate 	/* Update the next qtd pointer in the QH */
19730Sstevel@tonic-gate 	Set_QH(pp->pp_qh->qh_next_qtd, Get_QH(pp->pp_qh->qh_dummy_qtd));
19740Sstevel@tonic-gate }
19750Sstevel@tonic-gate 
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate /*
19780Sstevel@tonic-gate  * ehci_polled_finish_interrupt:
19790Sstevel@tonic-gate  */
19800Sstevel@tonic-gate static void
ehci_polled_finish_interrupt(ehci_state_t * ehcip,uint_t intr)19810Sstevel@tonic-gate ehci_polled_finish_interrupt(
19820Sstevel@tonic-gate 	ehci_state_t	*ehcip,
19830Sstevel@tonic-gate 	uint_t		intr)
19840Sstevel@tonic-gate {
19850Sstevel@tonic-gate 	/* Acknowledge the interrupt */
19860Sstevel@tonic-gate 	Set_OpReg(ehci_status, intr);
19870Sstevel@tonic-gate 
19880Sstevel@tonic-gate 	/*
19890Sstevel@tonic-gate 	 * Read interrupt status register to make sure that any PIO
19900Sstevel@tonic-gate 	 * store to clear the ISR has made it on the PCI bus before
19910Sstevel@tonic-gate 	 * returning from its interrupt handler.
19920Sstevel@tonic-gate 	 */
19930Sstevel@tonic-gate 	(void) Get_OpReg(ehci_status);
19940Sstevel@tonic-gate }
1995*9095SZhigang.Lu@Sun.COM 
1996*9095SZhigang.Lu@Sun.COM 
1997*9095SZhigang.Lu@Sun.COM static int
ehci_polled_create_tw(ehci_polled_t * ehci_polledp,usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)1998*9095SZhigang.Lu@Sun.COM ehci_polled_create_tw(
1999*9095SZhigang.Lu@Sun.COM 	ehci_polled_t	*ehci_polledp,
2000*9095SZhigang.Lu@Sun.COM 	usba_pipe_handle_data_t	*ph,
2001*9095SZhigang.Lu@Sun.COM 	usb_flags_t	usb_flags)
2002*9095SZhigang.Lu@Sun.COM {
2003*9095SZhigang.Lu@Sun.COM 	uint_t			ccount;
2004*9095SZhigang.Lu@Sun.COM 	size_t			real_length;
2005*9095SZhigang.Lu@Sun.COM 	ehci_trans_wrapper_t	*tw;
2006*9095SZhigang.Lu@Sun.COM 	ddi_device_acc_attr_t	dev_attr;
2007*9095SZhigang.Lu@Sun.COM 	int			result, pipe_dir, qtd_count;
2008*9095SZhigang.Lu@Sun.COM 	ehci_state_t		*ehcip;
2009*9095SZhigang.Lu@Sun.COM 	ehci_pipe_private_t	*pp;
2010*9095SZhigang.Lu@Sun.COM 	ddi_dma_attr_t		dma_attr;
2011*9095SZhigang.Lu@Sun.COM 
2012*9095SZhigang.Lu@Sun.COM 	ehcip = ehci_polledp->ehci_polled_ehcip;
2013*9095SZhigang.Lu@Sun.COM 	pp = (ehci_pipe_private_t *)ph->p_hcd_private;
2014*9095SZhigang.Lu@Sun.COM 
2015*9095SZhigang.Lu@Sun.COM 	/* Get the required qtd counts */
2016*9095SZhigang.Lu@Sun.COM 	qtd_count = (POLLED_RAW_BUF_SIZE - 1) / EHCI_MAX_QTD_XFER_SIZE + 1;
2017*9095SZhigang.Lu@Sun.COM 
2018*9095SZhigang.Lu@Sun.COM 	if ((tw = kmem_zalloc(sizeof (ehci_trans_wrapper_t),
2019*9095SZhigang.Lu@Sun.COM 	    KM_NOSLEEP)) == NULL) {
2020*9095SZhigang.Lu@Sun.COM 		return (USB_FAILURE);
2021*9095SZhigang.Lu@Sun.COM 	}
2022*9095SZhigang.Lu@Sun.COM 
2023*9095SZhigang.Lu@Sun.COM 	/* allow sg lists for transfer wrapper dma memory */
2024*9095SZhigang.Lu@Sun.COM 	bcopy(&ehcip->ehci_dma_attr, &dma_attr, sizeof (ddi_dma_attr_t));
2025*9095SZhigang.Lu@Sun.COM 	dma_attr.dma_attr_sgllen = EHCI_DMA_ATTR_TW_SGLLEN;
2026*9095SZhigang.Lu@Sun.COM 	dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
2027*9095SZhigang.Lu@Sun.COM 
2028*9095SZhigang.Lu@Sun.COM 	/* Allocate the DMA handle */
2029*9095SZhigang.Lu@Sun.COM 	if ((result = ddi_dma_alloc_handle(ehcip->ehci_dip,
2030*9095SZhigang.Lu@Sun.COM 	    &dma_attr, DDI_DMA_DONTWAIT, 0, &tw->tw_dmahandle)) !=
2031*9095SZhigang.Lu@Sun.COM 	    DDI_SUCCESS) {
2032*9095SZhigang.Lu@Sun.COM 		kmem_free(tw, sizeof (ehci_trans_wrapper_t));
2033*9095SZhigang.Lu@Sun.COM 
2034*9095SZhigang.Lu@Sun.COM 		return (USB_FAILURE);
2035*9095SZhigang.Lu@Sun.COM 	}
2036*9095SZhigang.Lu@Sun.COM 
2037*9095SZhigang.Lu@Sun.COM 	dev_attr.devacc_attr_version		= DDI_DEVICE_ATTR_V0;
2038*9095SZhigang.Lu@Sun.COM 	dev_attr.devacc_attr_endian_flags	= DDI_STRUCTURE_LE_ACC;
2039*9095SZhigang.Lu@Sun.COM 	dev_attr.devacc_attr_dataorder		= DDI_STRICTORDER_ACC;
2040*9095SZhigang.Lu@Sun.COM 
2041*9095SZhigang.Lu@Sun.COM 	/* Allocate the memory */
2042*9095SZhigang.Lu@Sun.COM 	if ((result = ddi_dma_mem_alloc(tw->tw_dmahandle, POLLED_RAW_BUF_SIZE,
2043*9095SZhigang.Lu@Sun.COM 	    &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
2044*9095SZhigang.Lu@Sun.COM 	    &tw->tw_buf, &real_length, &tw->tw_accesshandle)) !=
2045*9095SZhigang.Lu@Sun.COM 	    DDI_SUCCESS) {
2046*9095SZhigang.Lu@Sun.COM 		ddi_dma_free_handle(&tw->tw_dmahandle);
2047*9095SZhigang.Lu@Sun.COM 		kmem_free(tw, sizeof (ehci_trans_wrapper_t));
2048*9095SZhigang.Lu@Sun.COM 
2049*9095SZhigang.Lu@Sun.COM 		return (USB_FAILURE);
2050*9095SZhigang.Lu@Sun.COM 	}
2051*9095SZhigang.Lu@Sun.COM 
2052*9095SZhigang.Lu@Sun.COM 	/* Bind the handle */
2053*9095SZhigang.Lu@Sun.COM 	if ((result = ddi_dma_addr_bind_handle(tw->tw_dmahandle, NULL,
2054*9095SZhigang.Lu@Sun.COM 	    tw->tw_buf, real_length, DDI_DMA_RDWR|DDI_DMA_CONSISTENT,
2055*9095SZhigang.Lu@Sun.COM 	    DDI_DMA_DONTWAIT, NULL, &tw->tw_cookie, &ccount)) !=
2056*9095SZhigang.Lu@Sun.COM 	    DDI_DMA_MAPPED) {
2057*9095SZhigang.Lu@Sun.COM 		ddi_dma_mem_free(&tw->tw_accesshandle);
2058*9095SZhigang.Lu@Sun.COM 		ddi_dma_free_handle(&tw->tw_dmahandle);
2059*9095SZhigang.Lu@Sun.COM 		kmem_free(tw, sizeof (ehci_trans_wrapper_t));
2060*9095SZhigang.Lu@Sun.COM 
2061*9095SZhigang.Lu@Sun.COM 		return (USB_FAILURE);
2062*9095SZhigang.Lu@Sun.COM 	}
2063*9095SZhigang.Lu@Sun.COM 
2064*9095SZhigang.Lu@Sun.COM 	/* The cookie count should be 1 */
2065*9095SZhigang.Lu@Sun.COM 	if (ccount != 1) {
2066*9095SZhigang.Lu@Sun.COM 		result = ddi_dma_unbind_handle(tw->tw_dmahandle);
2067*9095SZhigang.Lu@Sun.COM 		ASSERT(result == DDI_SUCCESS);
2068*9095SZhigang.Lu@Sun.COM 
2069*9095SZhigang.Lu@Sun.COM 		ddi_dma_mem_free(&tw->tw_accesshandle);
2070*9095SZhigang.Lu@Sun.COM 		ddi_dma_free_handle(&tw->tw_dmahandle);
2071*9095SZhigang.Lu@Sun.COM 		kmem_free(tw, sizeof (ehci_trans_wrapper_t));
2072*9095SZhigang.Lu@Sun.COM 
2073*9095SZhigang.Lu@Sun.COM 		return (USB_FAILURE);
2074*9095SZhigang.Lu@Sun.COM 	}
2075*9095SZhigang.Lu@Sun.COM 
2076*9095SZhigang.Lu@Sun.COM 	if (ehci_allocate_tds_for_tw(ehcip, pp, tw, qtd_count) == USB_SUCCESS) {
2077*9095SZhigang.Lu@Sun.COM 		tw->tw_num_qtds = qtd_count;
2078*9095SZhigang.Lu@Sun.COM 	} else {
2079*9095SZhigang.Lu@Sun.COM 		ehci_deallocate_tw(ehcip, pp, tw);
2080*9095SZhigang.Lu@Sun.COM 		return (USB_FAILURE);
2081*9095SZhigang.Lu@Sun.COM 	}
2082*9095SZhigang.Lu@Sun.COM 	tw->tw_cookie_idx = 0;
2083*9095SZhigang.Lu@Sun.COM 	tw->tw_dma_offs = 0;
2084*9095SZhigang.Lu@Sun.COM 
2085*9095SZhigang.Lu@Sun.COM 	/*
2086*9095SZhigang.Lu@Sun.COM 	 * Only allow one wrapper to be added at a time. Insert the
2087*9095SZhigang.Lu@Sun.COM 	 * new transaction wrapper into the list for this pipe.
2088*9095SZhigang.Lu@Sun.COM 	 */
2089*9095SZhigang.Lu@Sun.COM 	if (pp->pp_tw_head == NULL) {
2090*9095SZhigang.Lu@Sun.COM 		pp->pp_tw_head = tw;
2091*9095SZhigang.Lu@Sun.COM 		pp->pp_tw_tail = tw;
2092*9095SZhigang.Lu@Sun.COM 	} else {
2093*9095SZhigang.Lu@Sun.COM 		pp->pp_tw_tail->tw_next = tw;
2094*9095SZhigang.Lu@Sun.COM 		pp->pp_tw_tail = tw;
2095*9095SZhigang.Lu@Sun.COM 	}
2096*9095SZhigang.Lu@Sun.COM 
2097*9095SZhigang.Lu@Sun.COM 	/* Store the transfer length */
2098*9095SZhigang.Lu@Sun.COM 	tw->tw_length = POLLED_RAW_BUF_SIZE;
2099*9095SZhigang.Lu@Sun.COM 
2100*9095SZhigang.Lu@Sun.COM 	/* Store a back pointer to the pipe private structure */
2101*9095SZhigang.Lu@Sun.COM 	tw->tw_pipe_private = pp;
2102*9095SZhigang.Lu@Sun.COM 
2103*9095SZhigang.Lu@Sun.COM 	/* Store the transfer type - synchronous or asynchronous */
2104*9095SZhigang.Lu@Sun.COM 	tw->tw_flags = usb_flags;
2105*9095SZhigang.Lu@Sun.COM 
2106*9095SZhigang.Lu@Sun.COM 	/* Get and Store 32bit ID */
2107*9095SZhigang.Lu@Sun.COM 	tw->tw_id = EHCI_GET_ID((void *)tw);
2108*9095SZhigang.Lu@Sun.COM 
2109*9095SZhigang.Lu@Sun.COM 	pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
2110*9095SZhigang.Lu@Sun.COM 	tw->tw_direction = (pipe_dir == USB_EP_DIR_OUT)?
2111*9095SZhigang.Lu@Sun.COM 	    EHCI_QTD_CTRL_OUT_PID : EHCI_QTD_CTRL_IN_PID;
2112*9095SZhigang.Lu@Sun.COM 
2113*9095SZhigang.Lu@Sun.COM 	USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
2114*9095SZhigang.Lu@Sun.COM 	    "ehci_create_transfer_wrapper: tw = 0x%p, ncookies = %u",
2115*9095SZhigang.Lu@Sun.COM 	    (void *)tw, tw->tw_ncookies);
2116*9095SZhigang.Lu@Sun.COM 
2117*9095SZhigang.Lu@Sun.COM 	return (USB_SUCCESS);
2118*9095SZhigang.Lu@Sun.COM }
2119*9095SZhigang.Lu@Sun.COM 
2120*9095SZhigang.Lu@Sun.COM 
2121*9095SZhigang.Lu@Sun.COM /*
2122*9095SZhigang.Lu@Sun.COM  * ehci_polled_insert_async_qh:
2123*9095SZhigang.Lu@Sun.COM  *
2124*9095SZhigang.Lu@Sun.COM  * Insert a bulk endpoint into the Host Controller's (HC)
2125*9095SZhigang.Lu@Sun.COM  * Asynchronous schedule endpoint list.
2126*9095SZhigang.Lu@Sun.COM  */
2127*9095SZhigang.Lu@Sun.COM static void
ehci_polled_insert_async_qh(ehci_state_t * ehcip,ehci_pipe_private_t * pp)2128*9095SZhigang.Lu@Sun.COM ehci_polled_insert_async_qh(
2129*9095SZhigang.Lu@Sun.COM 	ehci_state_t		*ehcip,
2130*9095SZhigang.Lu@Sun.COM 	ehci_pipe_private_t	*pp)
2131*9095SZhigang.Lu@Sun.COM {
2132*9095SZhigang.Lu@Sun.COM 	ehci_qh_t		*qh = pp->pp_qh;
2133*9095SZhigang.Lu@Sun.COM 	ehci_qh_t		*async_head_qh;
2134*9095SZhigang.Lu@Sun.COM 	ehci_qh_t		*next_qh;
2135*9095SZhigang.Lu@Sun.COM 	uintptr_t		qh_addr;
2136*9095SZhigang.Lu@Sun.COM 
2137*9095SZhigang.Lu@Sun.COM 	/* Make sure this QH is not already in the list */
2138*9095SZhigang.Lu@Sun.COM 	ASSERT((Get_QH(qh->qh_prev) & EHCI_QH_LINK_PTR) == NULL);
2139*9095SZhigang.Lu@Sun.COM 
2140*9095SZhigang.Lu@Sun.COM 	qh_addr = ehci_qh_cpu_to_iommu(ehcip, qh);
2141*9095SZhigang.Lu@Sun.COM 
2142*9095SZhigang.Lu@Sun.COM 	/* Obtain a ptr to the head of the Async schedule list */
2143*9095SZhigang.Lu@Sun.COM 	async_head_qh = ehcip->ehci_head_of_async_sched_list;
2144*9095SZhigang.Lu@Sun.COM 
2145*9095SZhigang.Lu@Sun.COM 	if (async_head_qh == NULL) {
2146*9095SZhigang.Lu@Sun.COM 		/* Set this QH to be the "head" of the circular list */
2147*9095SZhigang.Lu@Sun.COM 		Set_QH(qh->qh_ctrl,
2148*9095SZhigang.Lu@Sun.COM 		    (Get_QH(qh->qh_ctrl) | EHCI_QH_CTRL_RECLAIM_HEAD));
2149*9095SZhigang.Lu@Sun.COM 
2150*9095SZhigang.Lu@Sun.COM 		/* Set new QH's link and previous pointer to itself */
2151*9095SZhigang.Lu@Sun.COM 		Set_QH(qh->qh_link_ptr, qh_addr | EHCI_QH_LINK_REF_QH);
2152*9095SZhigang.Lu@Sun.COM 		Set_QH(qh->qh_prev, qh_addr);
2153*9095SZhigang.Lu@Sun.COM 
2154*9095SZhigang.Lu@Sun.COM 		ehcip->ehci_head_of_async_sched_list = qh;
2155*9095SZhigang.Lu@Sun.COM 
2156*9095SZhigang.Lu@Sun.COM 		/* Set the head ptr to the new endpoint */
2157*9095SZhigang.Lu@Sun.COM 		Set_OpReg(ehci_async_list_addr, qh_addr);
2158*9095SZhigang.Lu@Sun.COM 
2159*9095SZhigang.Lu@Sun.COM 		/*
2160*9095SZhigang.Lu@Sun.COM 		 * For some reason this register might get nulled out by
2161*9095SZhigang.Lu@Sun.COM 		 * the Uli M1575 South Bridge. To workaround the hardware
2162*9095SZhigang.Lu@Sun.COM 		 * problem, check the value after write and retry if the
2163*9095SZhigang.Lu@Sun.COM 		 * last write fails.
2164*9095SZhigang.Lu@Sun.COM 		 *
2165*9095SZhigang.Lu@Sun.COM 		 * If the ASYNCLISTADDR remains "stuck" after
2166*9095SZhigang.Lu@Sun.COM 		 * EHCI_MAX_RETRY retries, then the M1575 is broken
2167*9095SZhigang.Lu@Sun.COM 		 * and is stuck in an inconsistent state and is about
2168*9095SZhigang.Lu@Sun.COM 		 * to crash the machine with a trn_oor panic when it
2169*9095SZhigang.Lu@Sun.COM 		 * does a DMA read from 0x0.  It is better to panic
2170*9095SZhigang.Lu@Sun.COM 		 * now rather than wait for the trn_oor crash; this
2171*9095SZhigang.Lu@Sun.COM 		 * way Customer Service will have a clean signature
2172*9095SZhigang.Lu@Sun.COM 		 * that indicts the M1575 chip rather than a
2173*9095SZhigang.Lu@Sun.COM 		 * mysterious and hard-to-diagnose trn_oor panic.
2174*9095SZhigang.Lu@Sun.COM 		 */
2175*9095SZhigang.Lu@Sun.COM 		if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
2176*9095SZhigang.Lu@Sun.COM 		    (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) &&
2177*9095SZhigang.Lu@Sun.COM 		    (qh_addr != Get_OpReg(ehci_async_list_addr))) {
2178*9095SZhigang.Lu@Sun.COM 			int retry = 0;
2179*9095SZhigang.Lu@Sun.COM 
2180*9095SZhigang.Lu@Sun.COM 			Set_OpRegRetry(ehci_async_list_addr, qh_addr, retry);
2181*9095SZhigang.Lu@Sun.COM 			if (retry >= EHCI_MAX_RETRY)
2182*9095SZhigang.Lu@Sun.COM 				cmn_err(CE_PANIC, "ehci_insert_async_qh:"
2183*9095SZhigang.Lu@Sun.COM 				    " ASYNCLISTADDR write failed.");
2184*9095SZhigang.Lu@Sun.COM 
2185*9095SZhigang.Lu@Sun.COM 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
2186*9095SZhigang.Lu@Sun.COM 			    "ehci_insert_async_qh: ASYNCLISTADDR "
2187*9095SZhigang.Lu@Sun.COM 			    "write failed, retry=%d", retry);
2188*9095SZhigang.Lu@Sun.COM 		}
2189*9095SZhigang.Lu@Sun.COM 	} else {
2190*9095SZhigang.Lu@Sun.COM 		ASSERT(Get_QH(async_head_qh->qh_ctrl) &
2191*9095SZhigang.Lu@Sun.COM 		    EHCI_QH_CTRL_RECLAIM_HEAD);
2192*9095SZhigang.Lu@Sun.COM 
2193*9095SZhigang.Lu@Sun.COM 		/* Ensure this QH's "H" bit is not set */
2194*9095SZhigang.Lu@Sun.COM 		Set_QH(qh->qh_ctrl,
2195*9095SZhigang.Lu@Sun.COM 		    (Get_QH(qh->qh_ctrl) & ~EHCI_QH_CTRL_RECLAIM_HEAD));
2196*9095SZhigang.Lu@Sun.COM 
2197*9095SZhigang.Lu@Sun.COM 		next_qh = ehci_qh_iommu_to_cpu(ehcip,
2198*9095SZhigang.Lu@Sun.COM 		    Get_QH(async_head_qh->qh_link_ptr) & EHCI_QH_LINK_PTR);
2199*9095SZhigang.Lu@Sun.COM 
2200*9095SZhigang.Lu@Sun.COM 		/* Set new QH's link and previous pointers */
2201*9095SZhigang.Lu@Sun.COM 		Set_QH(qh->qh_link_ptr,
2202*9095SZhigang.Lu@Sun.COM 		    Get_QH(async_head_qh->qh_link_ptr) | EHCI_QH_LINK_REF_QH);
2203*9095SZhigang.Lu@Sun.COM 		Set_QH(qh->qh_prev, ehci_qh_cpu_to_iommu(ehcip, async_head_qh));
2204*9095SZhigang.Lu@Sun.COM 
2205*9095SZhigang.Lu@Sun.COM 		/* Set next QH's prev pointer */
2206*9095SZhigang.Lu@Sun.COM 		Set_QH(next_qh->qh_prev, ehci_qh_cpu_to_iommu(ehcip, qh));
2207*9095SZhigang.Lu@Sun.COM 
2208*9095SZhigang.Lu@Sun.COM 		/* Set QH Head's link pointer points to new QH */
2209*9095SZhigang.Lu@Sun.COM 		Set_QH(async_head_qh->qh_link_ptr,
2210*9095SZhigang.Lu@Sun.COM 		    qh_addr | EHCI_QH_LINK_REF_QH);
2211*9095SZhigang.Lu@Sun.COM 	}
2212*9095SZhigang.Lu@Sun.COM }
2213*9095SZhigang.Lu@Sun.COM 
2214*9095SZhigang.Lu@Sun.COM 
2215*9095SZhigang.Lu@Sun.COM /*
2216*9095SZhigang.Lu@Sun.COM  * ehci_remove_async_qh:
2217*9095SZhigang.Lu@Sun.COM  *
2218*9095SZhigang.Lu@Sun.COM  * Remove a control/bulk endpoint into the Host Controller's (HC)
2219*9095SZhigang.Lu@Sun.COM  * Asynchronous schedule endpoint list.
2220*9095SZhigang.Lu@Sun.COM  */
2221*9095SZhigang.Lu@Sun.COM static void
ehci_polled_remove_async_qh(ehci_state_t * ehcip,ehci_pipe_private_t * pp)2222*9095SZhigang.Lu@Sun.COM ehci_polled_remove_async_qh(
2223*9095SZhigang.Lu@Sun.COM 	ehci_state_t		*ehcip,
2224*9095SZhigang.Lu@Sun.COM 	ehci_pipe_private_t	*pp)
2225*9095SZhigang.Lu@Sun.COM {
2226*9095SZhigang.Lu@Sun.COM 	ehci_qh_t		*qh = pp->pp_qh; /* qh to be removed */
2227*9095SZhigang.Lu@Sun.COM 	ehci_qh_t		*prev_qh, *next_qh;
2228*9095SZhigang.Lu@Sun.COM 
2229*9095SZhigang.Lu@Sun.COM 	prev_qh = ehci_qh_iommu_to_cpu(ehcip,
2230*9095SZhigang.Lu@Sun.COM 	    Get_QH(qh->qh_prev) & EHCI_QH_LINK_PTR);
2231*9095SZhigang.Lu@Sun.COM 	next_qh = ehci_qh_iommu_to_cpu(ehcip,
2232*9095SZhigang.Lu@Sun.COM 	    Get_QH(qh->qh_link_ptr) & EHCI_QH_LINK_PTR);
2233*9095SZhigang.Lu@Sun.COM 
2234*9095SZhigang.Lu@Sun.COM 	/* Make sure this QH is in the list */
2235*9095SZhigang.Lu@Sun.COM 	ASSERT(prev_qh != NULL);
2236*9095SZhigang.Lu@Sun.COM 
2237*9095SZhigang.Lu@Sun.COM 	/*
2238*9095SZhigang.Lu@Sun.COM 	 * If next QH and current QH are the same, then this is the last
2239*9095SZhigang.Lu@Sun.COM 	 * QH on the Asynchronous Schedule list.
2240*9095SZhigang.Lu@Sun.COM 	 */
2241*9095SZhigang.Lu@Sun.COM 	if (qh == next_qh) {
2242*9095SZhigang.Lu@Sun.COM 		ASSERT(Get_QH(qh->qh_ctrl) & EHCI_QH_CTRL_RECLAIM_HEAD);
2243*9095SZhigang.Lu@Sun.COM 		/*
2244*9095SZhigang.Lu@Sun.COM 		 * Null our pointer to the async sched list, but do not
2245*9095SZhigang.Lu@Sun.COM 		 * touch the host controller's list_addr.
2246*9095SZhigang.Lu@Sun.COM 		 */
2247*9095SZhigang.Lu@Sun.COM 		ehcip->ehci_head_of_async_sched_list = NULL;
2248*9095SZhigang.Lu@Sun.COM 	} else {
2249*9095SZhigang.Lu@Sun.COM 		/* If this QH is the HEAD then find another one to replace it */
2250*9095SZhigang.Lu@Sun.COM 		if (ehcip->ehci_head_of_async_sched_list == qh) {
2251*9095SZhigang.Lu@Sun.COM 
2252*9095SZhigang.Lu@Sun.COM 			ASSERT(Get_QH(qh->qh_ctrl) & EHCI_QH_CTRL_RECLAIM_HEAD);
2253*9095SZhigang.Lu@Sun.COM 			ehcip->ehci_head_of_async_sched_list = next_qh;
2254*9095SZhigang.Lu@Sun.COM 			Set_QH(next_qh->qh_ctrl,
2255*9095SZhigang.Lu@Sun.COM 			    Get_QH(next_qh->qh_ctrl) |
2256*9095SZhigang.Lu@Sun.COM 			    EHCI_QH_CTRL_RECLAIM_HEAD);
2257*9095SZhigang.Lu@Sun.COM 		}
2258*9095SZhigang.Lu@Sun.COM 		Set_QH(prev_qh->qh_link_ptr, Get_QH(qh->qh_link_ptr));
2259*9095SZhigang.Lu@Sun.COM 		Set_QH(next_qh->qh_prev, Get_QH(qh->qh_prev));
2260*9095SZhigang.Lu@Sun.COM 	}
2261*9095SZhigang.Lu@Sun.COM 
2262*9095SZhigang.Lu@Sun.COM 	/* qh_prev to indicate it is no longer in the circular list */
2263*9095SZhigang.Lu@Sun.COM 	Set_QH(qh->qh_prev, NULL);
2264*9095SZhigang.Lu@Sun.COM 
2265*9095SZhigang.Lu@Sun.COM }
2266