xref: /onnv-gate/usr/src/uts/common/io/usb/hcd/uhci/uhciutil.c (revision 11066:cebb50cbe4f9)
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
52125Ssl147100  * Common Development and Distribution License (the "License").
62125Ssl147100  * 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 /*
228945SGuoqing.Zhu@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 /*
280Sstevel@tonic-gate  * Universal Host Controller Driver (UHCI)
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * The UHCI driver is a driver which interfaces to the Universal
310Sstevel@tonic-gate  * Serial Bus Driver (USBA) and the Host Controller (HC). The interface to
320Sstevel@tonic-gate  * the Host Controller is defined by the UHCI.
330Sstevel@tonic-gate  * This file contains misc functions.
340Sstevel@tonic-gate  */
350Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcid.h>
360Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhciutil.h>
370Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcipolled.h>
380Sstevel@tonic-gate 
392125Ssl147100 #include <sys/disp.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate /* Globals */
420Sstevel@tonic-gate extern uint_t	uhci_td_pool_size;			/* Num TDs */
430Sstevel@tonic-gate extern uint_t	uhci_qh_pool_size;			/* Num QHs */
440Sstevel@tonic-gate extern ushort_t	uhci_tree_bottom_nodes[];
450Sstevel@tonic-gate extern void	*uhci_statep;
460Sstevel@tonic-gate 
470Sstevel@tonic-gate /* function prototypes */
480Sstevel@tonic-gate static void	uhci_build_interrupt_lattice(uhci_state_t *uhcip);
490Sstevel@tonic-gate static int	uhci_init_frame_lst_table(dev_info_t *dip, uhci_state_t *uhcip);
500Sstevel@tonic-gate 
510Sstevel@tonic-gate static uint_t	uhci_lattice_height(uint_t bandwidth);
520Sstevel@tonic-gate static uint_t	uhci_lattice_parent(uint_t node);
530Sstevel@tonic-gate static uint_t	uhci_leftmost_leaf(uint_t node, uint_t height);
540Sstevel@tonic-gate static uint_t	uhci_compute_total_bandwidth(usb_ep_descr_t *endpoint,
550Sstevel@tonic-gate 		    usb_port_status_t port_status);
560Sstevel@tonic-gate 
570Sstevel@tonic-gate static int	uhci_bandwidth_adjust(uhci_state_t *uhcip,
580Sstevel@tonic-gate 		    usb_ep_descr_t *endpoint, usb_port_status_t port_status);
590Sstevel@tonic-gate 
600Sstevel@tonic-gate static uhci_td_t *uhci_allocate_td_from_pool(uhci_state_t *uhcip);
610Sstevel@tonic-gate static void	uhci_fill_in_td(uhci_state_t *uhcip,
620Sstevel@tonic-gate 		    uhci_td_t *td, uhci_td_t *current_dummy,
632125Ssl147100 		    uint32_t buffer_offset, size_t length,
640Sstevel@tonic-gate 		    uhci_pipe_private_t	*pp, uchar_t PID,
652125Ssl147100 		    usb_req_attrs_t attrs, uhci_trans_wrapper_t *tw);
662125Ssl147100 static uint32_t	uhci_get_tw_paddr_by_offs(uhci_state_t *uhcip,
672125Ssl147100 		    uint32_t buffer_offset, size_t length,
682125Ssl147100 		    uhci_trans_wrapper_t *tw);
690Sstevel@tonic-gate static uhci_trans_wrapper_t *uhci_create_transfer_wrapper(
700Sstevel@tonic-gate 		    uhci_state_t *uhcip, uhci_pipe_private_t *pp,
710Sstevel@tonic-gate 		    size_t length, usb_flags_t usb_flags);
722125Ssl147100 static uhci_trans_wrapper_t *uhci_create_isoc_transfer_wrapper(
732125Ssl147100 		    uhci_state_t *uhcip, uhci_pipe_private_t *pp,
742125Ssl147100 		    usb_isoc_req_t *req, size_t length,
752125Ssl147100 		    usb_flags_t usb_flags);
760Sstevel@tonic-gate 
770Sstevel@tonic-gate static int	uhci_create_setup_pkt(uhci_state_t *uhcip,
780Sstevel@tonic-gate 		    uhci_pipe_private_t	*pp, uhci_trans_wrapper_t *tw);
790Sstevel@tonic-gate static void	uhci_insert_ctrl_qh(uhci_state_t *uhcip,
800Sstevel@tonic-gate 		    uhci_pipe_private_t *pp);
810Sstevel@tonic-gate static void	uhci_remove_ctrl_qh(uhci_state_t *uhcip,
820Sstevel@tonic-gate 		    uhci_pipe_private_t *pp);
830Sstevel@tonic-gate static void	uhci_insert_intr_qh(uhci_state_t *uhcip,
840Sstevel@tonic-gate 		    uhci_pipe_private_t *pp);
850Sstevel@tonic-gate static void	uhci_remove_intr_qh(uhci_state_t *uhcip,
860Sstevel@tonic-gate 		    uhci_pipe_private_t *pp);
870Sstevel@tonic-gate static void	uhci_remove_bulk_qh(uhci_state_t *uhcip,
880Sstevel@tonic-gate 		    uhci_pipe_private_t *pp);
890Sstevel@tonic-gate static void	uhci_insert_bulk_qh(uhci_state_t *uhcip,
900Sstevel@tonic-gate 		    uhci_pipe_private_t *pp);
910Sstevel@tonic-gate static void	uhci_handle_bulk_td_errors(uhci_state_t *uhcip, uhci_td_t *td);
920Sstevel@tonic-gate static int	uhci_alloc_memory_for_tds(uhci_state_t *uhcip, uint_t num_tds,
930Sstevel@tonic-gate 		    uhci_bulk_isoc_xfer_t *info);
942125Ssl147100 static int	uhci_alloc_bulk_isoc_tds(uhci_state_t *uhcip, uint_t num_tds,
952125Ssl147100 		    uhci_bulk_isoc_xfer_t *info);
962125Ssl147100 static void	uhci_get_isoc_td_by_index(uhci_state_t *uhcip,
972125Ssl147100 		    uhci_bulk_isoc_xfer_t *info, uint_t index,
982125Ssl147100 		    uhci_td_t **tdpp, uhci_bulk_isoc_td_pool_t **td_pool_pp);
992125Ssl147100 static void	uhci_get_bulk_td_by_paddr(uhci_state_t *uhcip,
1002125Ssl147100 		    uhci_bulk_isoc_xfer_t *info, uint32_t paddr,
1012125Ssl147100 		    uhci_bulk_isoc_td_pool_t **td_pool_pp);
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate static	int	uhci_handle_isoc_receive(uhci_state_t *uhcip,
1040Sstevel@tonic-gate 		uhci_pipe_private_t *pp, uhci_trans_wrapper_t *tw);
1050Sstevel@tonic-gate static void	uhci_delete_isoc_td(uhci_state_t *uhcip,
1060Sstevel@tonic-gate 		    uhci_td_t *td);
1070Sstevel@tonic-gate #ifdef DEBUG
1080Sstevel@tonic-gate static void	uhci_print_td(uhci_state_t *uhcip, uhci_td_t *td);
1090Sstevel@tonic-gate static void	uhci_print_qh(uhci_state_t *uhcip, queue_head_t *qh);
1100Sstevel@tonic-gate #endif
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate  * uhci_build_interrupt_lattice:
1150Sstevel@tonic-gate  *
1160Sstevel@tonic-gate  * Construct the interrupt lattice tree using static Queue Head pointers.
1170Sstevel@tonic-gate  * This interrupt lattice tree will have total of 63 queue heads and the
1180Sstevel@tonic-gate  * Host Controller (HC) processes queue heads every frame.
1190Sstevel@tonic-gate  */
1200Sstevel@tonic-gate static void
uhci_build_interrupt_lattice(uhci_state_t * uhcip)1210Sstevel@tonic-gate uhci_build_interrupt_lattice(uhci_state_t *uhcip)
1220Sstevel@tonic-gate {
1230Sstevel@tonic-gate 	int			half_list = NUM_INTR_QH_LISTS / 2;
1240Sstevel@tonic-gate 	uint16_t		i, j, k;
1250Sstevel@tonic-gate 	uhci_td_t		*sof_td, *isoc_td;
1260Sstevel@tonic-gate 	uintptr_t		addr;
1270Sstevel@tonic-gate 	queue_head_t		*list_array = uhcip->uhci_qh_pool_addr;
1280Sstevel@tonic-gate 	queue_head_t		*tmp_qh;
1290Sstevel@tonic-gate 	frame_lst_table_t	*frame_lst_tablep =
1305773Sqz150045 	    uhcip->uhci_frame_lst_tablep;
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
1330Sstevel@tonic-gate 	    "uhci_build_interrupt_lattice:");
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	/*
1360Sstevel@tonic-gate 	 * Reserve the first 63 queue head structures in the pool as static
1370Sstevel@tonic-gate 	 * queue heads & these are required for constructing interrupt
1380Sstevel@tonic-gate 	 * lattice tree.
1390Sstevel@tonic-gate 	 */
1400Sstevel@tonic-gate 	for (i = 0; i < NUM_INTR_QH_LISTS; i++) {
1410Sstevel@tonic-gate 		SetQH32(uhcip, list_array[i].link_ptr, HC_END_OF_LIST);
1420Sstevel@tonic-gate 		SetQH32(uhcip, list_array[i].element_ptr, HC_END_OF_LIST);
1430Sstevel@tonic-gate 		list_array[i].qh_flag		= QUEUE_HEAD_FLAG_STATIC;
1440Sstevel@tonic-gate 		list_array[i].node		= i;
1450Sstevel@tonic-gate 	}
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	/* Build the interrupt lattice tree */
1480Sstevel@tonic-gate 	for (i = 0; i < half_list - 1; i++) {
1490Sstevel@tonic-gate 		/*
1500Sstevel@tonic-gate 		 * The next  pointer in the host controller  queue head
1510Sstevel@tonic-gate 		 * descriptor must contain an iommu address. Calculate
1520Sstevel@tonic-gate 		 * the offset into the cpu address and add this to the
1530Sstevel@tonic-gate 		 * starting iommu address.
1540Sstevel@tonic-gate 		 */
1550Sstevel@tonic-gate 		addr = QH_PADDR(&list_array[i]) | HC_QUEUE_HEAD;
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 		SetQH32(uhcip, list_array[2*i + 1].link_ptr, addr);
1580Sstevel@tonic-gate 		SetQH32(uhcip, list_array[2*i + 2].link_ptr, addr);
1590Sstevel@tonic-gate 	}
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	/*
1620Sstevel@tonic-gate 	 * Initialize the interrupt list in the Frame list Table
1630Sstevel@tonic-gate 	 * so that it points to the bottom of the tree.
1640Sstevel@tonic-gate 	 */
1650Sstevel@tonic-gate 	for (i = 0, j = 0; i < pow_2(TREE_HEIGHT); i++) {
1660Sstevel@tonic-gate 		addr = QH_PADDR(&list_array[half_list + i - 1]);
1670Sstevel@tonic-gate 		for (k = 0; k <  pow_2(VIRTUAL_TREE_HEIGHT); k++) {
1680Sstevel@tonic-gate 			SetFL32(uhcip,
1690Sstevel@tonic-gate 			    frame_lst_tablep[uhci_tree_bottom_nodes[j++]],
1700Sstevel@tonic-gate 			    addr | HC_QUEUE_HEAD);
1710Sstevel@tonic-gate 		}
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	/*
1750Sstevel@tonic-gate 	 *  Create a controller and bulk Queue heads
1760Sstevel@tonic-gate 	 */
1770Sstevel@tonic-gate 	uhcip->uhci_ctrl_xfers_q_head = uhci_alloc_queue_head(uhcip);
1780Sstevel@tonic-gate 	tmp_qh = uhcip->uhci_ctrl_xfers_q_tail = uhcip->uhci_ctrl_xfers_q_head;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	SetQH32(uhcip, list_array[0].link_ptr,
1815773Sqz150045 	    (QH_PADDR(tmp_qh) | HC_QUEUE_HEAD));
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	uhcip->uhci_bulk_xfers_q_head = uhci_alloc_queue_head(uhcip);
1840Sstevel@tonic-gate 	uhcip->uhci_bulk_xfers_q_tail = uhcip->uhci_bulk_xfers_q_head;
1850Sstevel@tonic-gate 	SetQH32(uhcip, tmp_qh->link_ptr,
1860Sstevel@tonic-gate 	    (QH_PADDR(uhcip->uhci_bulk_xfers_q_head)|HC_QUEUE_HEAD));
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	SetQH32(uhcip, uhcip->uhci_bulk_xfers_q_head->link_ptr, HC_END_OF_LIST);
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	/*
1910Sstevel@tonic-gate 	 * Add a dummy TD to the static queue head 0. THis is used
1920Sstevel@tonic-gate 	 * to generate an at the end of frame.
1930Sstevel@tonic-gate 	 */
1940Sstevel@tonic-gate 	sof_td = uhci_allocate_td_from_pool(uhcip);
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	SetQH32(uhcip, list_array[0].element_ptr,
1970Sstevel@tonic-gate 	    TD_PADDR(sof_td) | HC_TD_HEAD);
1980Sstevel@tonic-gate 	SetTD32(uhcip, sof_td->link_ptr, HC_END_OF_LIST);
1990Sstevel@tonic-gate 	uhcip->uhci_sof_td = sof_td;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	/*
2020Sstevel@tonic-gate 	 * Add a dummy td that is used to generate an interrupt for
2030Sstevel@tonic-gate 	 * every 1024 frames.
2040Sstevel@tonic-gate 	 */
2050Sstevel@tonic-gate 	isoc_td = uhci_allocate_td_from_pool(uhcip);
2060Sstevel@tonic-gate 	SetTD32(uhcip, isoc_td->link_ptr, HC_END_OF_LIST);
2070Sstevel@tonic-gate 	uhcip->uhci_isoc_td = isoc_td;
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	uhcip->uhci_isoc_qh = uhci_alloc_queue_head(uhcip);
2100Sstevel@tonic-gate 	SetQH32(uhcip, uhcip->uhci_isoc_qh->link_ptr,
2110Sstevel@tonic-gate 	    GetFL32(uhcip, uhcip->uhci_frame_lst_tablep[MAX_FRAME_NUM]));
2120Sstevel@tonic-gate 	SetQH32(uhcip, uhcip->uhci_isoc_qh->element_ptr, TD_PADDR(isoc_td));
2130Sstevel@tonic-gate 	SetFL32(uhcip, uhcip->uhci_frame_lst_tablep[MAX_FRAME_NUM],
2145773Sqz150045 	    QH_PADDR(uhcip->uhci_isoc_qh) | HC_QUEUE_HEAD);
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate /*
2190Sstevel@tonic-gate  * uhci_allocate_pools:
2200Sstevel@tonic-gate  *	Allocate the system memory for the Queue Heads Descriptor and
2210Sstevel@tonic-gate  *	for the Transfer Descriptor (TD) pools. Both QH and TD structures
2220Sstevel@tonic-gate  *	must be aligned to a 16 byte boundary.
2230Sstevel@tonic-gate  */
2240Sstevel@tonic-gate int
uhci_allocate_pools(uhci_state_t * uhcip)2250Sstevel@tonic-gate uhci_allocate_pools(uhci_state_t *uhcip)
2260Sstevel@tonic-gate {
2270Sstevel@tonic-gate 	dev_info_t		*dip = uhcip->uhci_dip;
2280Sstevel@tonic-gate 	size_t			real_length;
2290Sstevel@tonic-gate 	int			i, result;
2300Sstevel@tonic-gate 	uint_t			ccount;
2310Sstevel@tonic-gate 	ddi_device_acc_attr_t	dev_attr;
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
2340Sstevel@tonic-gate 	    "uhci_allocate_pools:");
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	/* The host controller will be little endian */
2370Sstevel@tonic-gate 	dev_attr.devacc_attr_version		= DDI_DEVICE_ATTR_V0;
2380Sstevel@tonic-gate 	dev_attr.devacc_attr_endian_flags	= DDI_STRUCTURE_LE_ACC;
2390Sstevel@tonic-gate 	dev_attr.devacc_attr_dataorder		= DDI_STRICTORDER_ACC;
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	/* Allocate the TD pool DMA handle */
2420Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(dip, &uhcip->uhci_dma_attr, DDI_DMA_SLEEP, 0,
2430Sstevel@tonic-gate 	    &uhcip->uhci_td_pool_dma_handle) != DDI_SUCCESS) {
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 		return (USB_FAILURE);
2460Sstevel@tonic-gate 	}
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	/* Allocate the memory for the TD pool */
2490Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(uhcip->uhci_td_pool_dma_handle,
2500Sstevel@tonic-gate 	    uhci_td_pool_size * sizeof (uhci_td_t),
2510Sstevel@tonic-gate 	    &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
2520Sstevel@tonic-gate 	    (caddr_t *)&uhcip->uhci_td_pool_addr, &real_length,
2530Sstevel@tonic-gate 	    &uhcip->uhci_td_pool_mem_handle)) {
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 		return (USB_FAILURE);
2560Sstevel@tonic-gate 	}
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	/* Map the TD pool into the I/O address space */
2590Sstevel@tonic-gate 	result = ddi_dma_addr_bind_handle(uhcip->uhci_td_pool_dma_handle,
2600Sstevel@tonic-gate 	    NULL, (caddr_t)uhcip->uhci_td_pool_addr, real_length,
2610Sstevel@tonic-gate 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
2620Sstevel@tonic-gate 	    NULL, &uhcip->uhci_td_pool_cookie, &ccount);
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	bzero((void *)uhcip->uhci_td_pool_addr,
2650Sstevel@tonic-gate 	    uhci_td_pool_size * sizeof (uhci_td_t));
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	/* Process the result */
2680Sstevel@tonic-gate 	if (result == DDI_DMA_MAPPED) {
2690Sstevel@tonic-gate 		/* The cookie count should be 1 */
2700Sstevel@tonic-gate 		if (ccount != 1) {
2710Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
2720Sstevel@tonic-gate 			    "uhci_allocate_pools: More than 1 cookie");
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 			return (USB_FAILURE);
2750Sstevel@tonic-gate 		}
2760Sstevel@tonic-gate 	} else {
2770Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
2780Sstevel@tonic-gate 		    "uhci_allocate_pools: Result = %d", result);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 		uhci_decode_ddi_dma_addr_bind_handle_result(uhcip, result);
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 		return (USB_FAILURE);
2830Sstevel@tonic-gate 	}
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	uhcip->uhci_dma_addr_bind_flag |= UHCI_TD_POOL_BOUND;
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	/* Initialize the TD pool */
2880Sstevel@tonic-gate 	for (i = 0; i < uhci_td_pool_size; i++) {
2890Sstevel@tonic-gate 		uhcip->uhci_td_pool_addr[i].flag = TD_FLAG_FREE;
2900Sstevel@tonic-gate 	}
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	/* Allocate the TD pool DMA handle */
2930Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(dip, &uhcip->uhci_dma_attr, DDI_DMA_SLEEP,
2940Sstevel@tonic-gate 	    0, &uhcip->uhci_qh_pool_dma_handle) != DDI_SUCCESS) {
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 		return (USB_FAILURE);
2970Sstevel@tonic-gate 	}
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	/* Allocate the memory for the QH pool */
3000Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(uhcip->uhci_qh_pool_dma_handle,
3010Sstevel@tonic-gate 	    uhci_qh_pool_size * sizeof (queue_head_t),
3020Sstevel@tonic-gate 	    &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
3030Sstevel@tonic-gate 	    (caddr_t *)&uhcip->uhci_qh_pool_addr, &real_length,
3040Sstevel@tonic-gate 	    &uhcip->uhci_qh_pool_mem_handle) != DDI_SUCCESS) {
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 		return (USB_FAILURE);
3070Sstevel@tonic-gate 	}
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	result = ddi_dma_addr_bind_handle(uhcip->uhci_qh_pool_dma_handle,
3100Sstevel@tonic-gate 	    NULL, (caddr_t)uhcip->uhci_qh_pool_addr, real_length,
3110Sstevel@tonic-gate 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
3120Sstevel@tonic-gate 	    &uhcip->uhci_qh_pool_cookie, &ccount);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	/* Process the result */
3150Sstevel@tonic-gate 	if (result == DDI_DMA_MAPPED) {
3160Sstevel@tonic-gate 		/* The cookie count should be 1 */
3170Sstevel@tonic-gate 		if (ccount != 1) {
3180Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
3190Sstevel@tonic-gate 			    "uhci_allocate_pools: More than 1 cookie");
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 			return (USB_FAILURE);
3220Sstevel@tonic-gate 		}
3230Sstevel@tonic-gate 	} else {
3240Sstevel@tonic-gate 		uhci_decode_ddi_dma_addr_bind_handle_result(uhcip, result);
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 		return (USB_FAILURE);
3270Sstevel@tonic-gate 	}
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	uhcip->uhci_dma_addr_bind_flag |= UHCI_QH_POOL_BOUND;
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	bzero((void *)uhcip->uhci_qh_pool_addr,
3320Sstevel@tonic-gate 	    uhci_qh_pool_size * sizeof (queue_head_t));
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	/* Initialize the QH pool */
3350Sstevel@tonic-gate 	for (i = 0; i < uhci_qh_pool_size; i ++) {
3360Sstevel@tonic-gate 		uhcip->uhci_qh_pool_addr[i].qh_flag = QUEUE_HEAD_FLAG_FREE;
3370Sstevel@tonic-gate 	}
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
3400Sstevel@tonic-gate 	    "uhci_allocate_pools: Completed");
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	return (USB_SUCCESS);
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate /*
3470Sstevel@tonic-gate  * uhci_free_pools:
3480Sstevel@tonic-gate  *	Cleanup on attach failure or detach
3490Sstevel@tonic-gate  */
3500Sstevel@tonic-gate void
uhci_free_pools(uhci_state_t * uhcip)3510Sstevel@tonic-gate uhci_free_pools(uhci_state_t *uhcip)
3520Sstevel@tonic-gate {
3530Sstevel@tonic-gate 	int			i, flag, rval;
3540Sstevel@tonic-gate 	uhci_td_t		*td;
3550Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw;
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
3585773Sqz150045 	    "uhci_free_pools:");
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	if (uhcip->uhci_td_pool_addr && uhcip->uhci_td_pool_mem_handle) {
3610Sstevel@tonic-gate 		for (i = 0; i < uhci_td_pool_size; i ++) {
3620Sstevel@tonic-gate 			td = &uhcip->uhci_td_pool_addr[i];
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 			flag = uhcip->uhci_td_pool_addr[i].flag;
3650Sstevel@tonic-gate 			if ((flag != TD_FLAG_FREE) &&
3660Sstevel@tonic-gate 			    (flag != TD_FLAG_DUMMY) && (td->tw != NULL)) {
3670Sstevel@tonic-gate 				tw = td->tw;
3680Sstevel@tonic-gate 				uhci_free_tw(uhcip, tw);
3690Sstevel@tonic-gate 			}
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 		}
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 		if (uhcip->uhci_dma_addr_bind_flag & UHCI_TD_POOL_BOUND) {
3740Sstevel@tonic-gate 			rval = ddi_dma_unbind_handle(
3755773Sqz150045 			    uhcip->uhci_td_pool_dma_handle);
3760Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
3770Sstevel@tonic-gate 		}
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 		ddi_dma_mem_free(&uhcip->uhci_td_pool_mem_handle);
3800Sstevel@tonic-gate 	}
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	/* Free the TD pool */
3830Sstevel@tonic-gate 	if (uhcip->uhci_td_pool_dma_handle) {
3840Sstevel@tonic-gate 		ddi_dma_free_handle(&uhcip->uhci_td_pool_dma_handle);
3850Sstevel@tonic-gate 	}
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	if (uhcip->uhci_qh_pool_addr && uhcip->uhci_qh_pool_mem_handle) {
3880Sstevel@tonic-gate 		if (uhcip->uhci_dma_addr_bind_flag & UHCI_QH_POOL_BOUND) {
3890Sstevel@tonic-gate 			rval = ddi_dma_unbind_handle(
3905773Sqz150045 			    uhcip->uhci_qh_pool_dma_handle);
3910Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
3920Sstevel@tonic-gate 		}
3930Sstevel@tonic-gate 		ddi_dma_mem_free(&uhcip->uhci_qh_pool_mem_handle);
3940Sstevel@tonic-gate 	}
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	/* Free the QH pool */
3970Sstevel@tonic-gate 	if (uhcip->uhci_qh_pool_dma_handle) {
3980Sstevel@tonic-gate 		ddi_dma_free_handle(&uhcip->uhci_qh_pool_dma_handle);
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	/* Free the Frame list Table area */
4020Sstevel@tonic-gate 	if (uhcip->uhci_frame_lst_tablep && uhcip->uhci_flt_mem_handle) {
4030Sstevel@tonic-gate 		if (uhcip->uhci_dma_addr_bind_flag & UHCI_FLA_POOL_BOUND) {
4040Sstevel@tonic-gate 			rval = ddi_dma_unbind_handle(
4055773Sqz150045 			    uhcip->uhci_flt_dma_handle);
4060Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
4070Sstevel@tonic-gate 		}
4080Sstevel@tonic-gate 		ddi_dma_mem_free(&uhcip->uhci_flt_mem_handle);
4090Sstevel@tonic-gate 	}
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	if (uhcip->uhci_flt_dma_handle) {
4120Sstevel@tonic-gate 		ddi_dma_free_handle(&uhcip->uhci_flt_dma_handle);
4130Sstevel@tonic-gate 	}
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate /*
4180Sstevel@tonic-gate  * uhci_decode_ddi_dma_addr_bind_handle_result:
4190Sstevel@tonic-gate  *	Process the return values of ddi_dma_addr_bind_handle()
4200Sstevel@tonic-gate  */
4210Sstevel@tonic-gate void
uhci_decode_ddi_dma_addr_bind_handle_result(uhci_state_t * uhcip,int result)4220Sstevel@tonic-gate uhci_decode_ddi_dma_addr_bind_handle_result(uhci_state_t *uhcip, int result)
4230Sstevel@tonic-gate {
4240Sstevel@tonic-gate 	char *msg;
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl,
4270Sstevel@tonic-gate 	    "uhci_decode_ddi_dma_addr_bind_handle_result:");
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	switch (result) {
4300Sstevel@tonic-gate 	case DDI_DMA_PARTIAL_MAP:
4310Sstevel@tonic-gate 		msg = "Partial transfers not allowed";
4320Sstevel@tonic-gate 		break;
4330Sstevel@tonic-gate 	case DDI_DMA_INUSE:
4340Sstevel@tonic-gate 		msg = "Handle is in use";
4350Sstevel@tonic-gate 		break;
4360Sstevel@tonic-gate 	case DDI_DMA_NORESOURCES:
4370Sstevel@tonic-gate 		msg = "No resources";
4380Sstevel@tonic-gate 		break;
4390Sstevel@tonic-gate 	case DDI_DMA_NOMAPPING:
4400Sstevel@tonic-gate 		msg = "No mapping";
4410Sstevel@tonic-gate 		break;
4420Sstevel@tonic-gate 	case DDI_DMA_TOOBIG:
4430Sstevel@tonic-gate 		msg = "Object is too big";
4440Sstevel@tonic-gate 		break;
4450Sstevel@tonic-gate 	default:
4460Sstevel@tonic-gate 		msg = "Unknown dma error";
4470Sstevel@tonic-gate 	}
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, uhcip->uhci_log_hdl, "%s", msg);
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate /*
4540Sstevel@tonic-gate  * uhci_init_ctlr:
4550Sstevel@tonic-gate  *	Initialize the Host Controller (HC).
4560Sstevel@tonic-gate  */
4570Sstevel@tonic-gate int
uhci_init_ctlr(uhci_state_t * uhcip)4580Sstevel@tonic-gate uhci_init_ctlr(uhci_state_t *uhcip)
4590Sstevel@tonic-gate {
4600Sstevel@tonic-gate 	dev_info_t *dip = uhcip->uhci_dip;
4610Sstevel@tonic-gate 	uint_t	cmd_reg;
4620Sstevel@tonic-gate 	uint_t	frame_base_addr;
4630Sstevel@tonic-gate 
4646427Ssl147100 	mutex_enter(&uhcip->uhci_int_mutex);
4656427Ssl147100 
4660Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, "uhci_init_ctlr:");
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	/*
4690Sstevel@tonic-gate 	 * When USB legacy mode is enabled, the BIOS manages the USB keyboard
4700Sstevel@tonic-gate 	 * attached to the UHCI controller. It has been observed that some
4710Sstevel@tonic-gate 	 * times the BIOS does not clear the interrupts in the legacy mode
4720Sstevel@tonic-gate 	 * register in the PCI configuration space. So, disable the SMI intrs
4730Sstevel@tonic-gate 	 * and route the intrs to PIRQD here.
4740Sstevel@tonic-gate 	 */
4750Sstevel@tonic-gate 	pci_config_put16(uhcip->uhci_config_handle,
4760Sstevel@tonic-gate 	    LEGACYMODE_REG_OFFSET, LEGACYMODE_REG_INIT_VALUE);
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	/*
4790Sstevel@tonic-gate 	 * Disable all the interrupts.
4800Sstevel@tonic-gate 	 */
4810Sstevel@tonic-gate 	Set_OpReg16(USBINTR, DISABLE_ALL_INTRS);
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	cmd_reg = Get_OpReg16(USBCMD);
4840Sstevel@tonic-gate 	cmd_reg &= (~USBCMD_REG_HC_RUN);
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	/* Stop the controller */
4870Sstevel@tonic-gate 	Set_OpReg16(USBCMD, cmd_reg);
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 	/* Reset the host controller */
4900Sstevel@tonic-gate 	Set_OpReg16(USBCMD, USBCMD_REG_GBL_RESET);
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	/* Wait 10ms for reset to complete */
4930Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
4940Sstevel@tonic-gate 	delay(drv_usectohz(UHCI_RESET_DELAY));
4950Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	Set_OpReg16(USBCMD, 0);
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	/* Set the frame number to zero */
5000Sstevel@tonic-gate 	Set_OpReg16(FRNUM, 0);
5010Sstevel@tonic-gate 
5025773Sqz150045 	if (uhcip->uhci_hc_soft_state == UHCI_CTLR_INIT_STATE) {
5035773Sqz150045 		/* Initialize the Frame list base address area */
5045773Sqz150045 		if (uhci_init_frame_lst_table(dip, uhcip) != USB_SUCCESS) {
5055773Sqz150045 			mutex_exit(&uhcip->uhci_int_mutex);
5065773Sqz150045 
5075773Sqz150045 			return (USB_FAILURE);
5085773Sqz150045 		}
5090Sstevel@tonic-gate 	}
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	/* Save the contents of the Frame Interval Registers */
5120Sstevel@tonic-gate 	uhcip->uhci_frame_interval = Get_OpReg8(SOFMOD);
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	frame_base_addr = uhcip->uhci_flt_cookie.dmac_address;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	/* Set the Frame list base address */
5170Sstevel@tonic-gate 	Set_OpReg32(FRBASEADD, frame_base_addr);
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	/*
5200Sstevel@tonic-gate 	 * Begin sending SOFs
5210Sstevel@tonic-gate 	 * Set the Host Controller Functional State to Operational
5220Sstevel@tonic-gate 	 */
5230Sstevel@tonic-gate 	cmd_reg = Get_OpReg16(USBCMD);
5240Sstevel@tonic-gate 	cmd_reg |= (USBCMD_REG_HC_RUN | USBCMD_REG_MAXPKT_64 |
5255773Sqz150045 	    USBCMD_REG_CONFIG_FLAG);
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	Set_OpReg16(USBCMD, cmd_reg);
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	/*
5300Sstevel@tonic-gate 	 * Verify the Command and interrupt enable registers,
5310Sstevel@tonic-gate 	 * a sanity check whether actually initialized or not
5320Sstevel@tonic-gate 	 */
5330Sstevel@tonic-gate 	cmd_reg = Get_OpReg16(USBCMD);
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	if (!(cmd_reg & (USBCMD_REG_HC_RUN | USBCMD_REG_MAXPKT_64 |
5360Sstevel@tonic-gate 	    USBCMD_REG_CONFIG_FLAG))) {
537978Sfrits 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
5380Sstevel@tonic-gate 		    "uhci_init_ctlr: Controller initialization failed");
5395773Sqz150045 		mutex_exit(&uhcip->uhci_int_mutex);
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 		return (USB_FAILURE);
5420Sstevel@tonic-gate 	}
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	/*
5450Sstevel@tonic-gate 	 * Set the ioc bit of the isoc intr td. This enables
5460Sstevel@tonic-gate 	 * the generation of an interrupt for every 1024 frames.
5470Sstevel@tonic-gate 	 */
5480Sstevel@tonic-gate 	SetTD_ioc(uhcip, uhcip->uhci_isoc_td, 1);
5490Sstevel@tonic-gate 
5505773Sqz150045 	/* Set host controller soft state to operational */
5515773Sqz150045 	uhcip->uhci_hc_soft_state = UHCI_CTLR_OPERATIONAL_STATE;
5525773Sqz150045 	mutex_exit(&uhcip->uhci_int_mutex);
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
5550Sstevel@tonic-gate 	    "uhci_init_ctlr: Completed");
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	return (USB_SUCCESS);
5580Sstevel@tonic-gate }
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate /*
5620Sstevel@tonic-gate  * uhci_uninit_ctlr:
5630Sstevel@tonic-gate  *	uninitialize the Host Controller (HC).
5640Sstevel@tonic-gate  */
5650Sstevel@tonic-gate void
uhci_uninit_ctlr(uhci_state_t * uhcip)5660Sstevel@tonic-gate uhci_uninit_ctlr(uhci_state_t *uhcip)
5670Sstevel@tonic-gate {
5680Sstevel@tonic-gate 	if (uhcip->uhci_regs_handle) {
5690Sstevel@tonic-gate 		/* Disable all the interrupts. */
5700Sstevel@tonic-gate 		Set_OpReg16(USBINTR, DISABLE_ALL_INTRS);
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 		/* Complete the current transaction and then halt. */
5730Sstevel@tonic-gate 		Set_OpReg16(USBCMD, 0);
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 		/* Wait for sometime */
5760Sstevel@tonic-gate 		mutex_exit(&uhcip->uhci_int_mutex);
5770Sstevel@tonic-gate 		delay(drv_usectohz(UHCI_TIMEWAIT));
5780Sstevel@tonic-gate 		mutex_enter(&uhcip->uhci_int_mutex);
5790Sstevel@tonic-gate 	}
5800Sstevel@tonic-gate }
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate /*
5840Sstevel@tonic-gate  * uhci_map_regs:
5850Sstevel@tonic-gate  *	The Host Controller (HC) contains a set of on-chip operational
5860Sstevel@tonic-gate  *	registers and which should be mapped into a non-cacheable
5870Sstevel@tonic-gate  *	portion of the system addressable space.
5880Sstevel@tonic-gate  */
5890Sstevel@tonic-gate int
uhci_map_regs(uhci_state_t * uhcip)5900Sstevel@tonic-gate uhci_map_regs(uhci_state_t *uhcip)
5910Sstevel@tonic-gate {
5920Sstevel@tonic-gate 	dev_info_t		*dip = uhcip->uhci_dip;
5930Sstevel@tonic-gate 	int			index;
5940Sstevel@tonic-gate 	uint32_t		regs_prop_len;
5950Sstevel@tonic-gate 	int32_t			*regs_list;
5960Sstevel@tonic-gate 	uint16_t		command_reg;
5970Sstevel@tonic-gate 	ddi_device_acc_attr_t	attr;
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, "uhci_map_regs:");
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	/* The host controller will be little endian */
6020Sstevel@tonic-gate 	attr.devacc_attr_version	= DDI_DEVICE_ATTR_V0;
6030Sstevel@tonic-gate 	attr.devacc_attr_endian_flags	= DDI_STRUCTURE_LE_ACC;
6040Sstevel@tonic-gate 	attr.devacc_attr_dataorder	= DDI_STRICTORDER_ACC;
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, uhcip->uhci_dip,
6070Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "reg", &regs_list, &regs_prop_len) !=
6080Sstevel@tonic-gate 	    DDI_PROP_SUCCESS) {
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 		return (USB_FAILURE);
6110Sstevel@tonic-gate 	}
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	for (index = 0; index * 5 < regs_prop_len; index++) {
6140Sstevel@tonic-gate 		if (regs_list[index * 5] & UHCI_PROP_MASK) {
6150Sstevel@tonic-gate 			break;
6160Sstevel@tonic-gate 		}
6170Sstevel@tonic-gate 	}
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	/*
6200Sstevel@tonic-gate 	 * Deallocate the memory allocated by the ddi_prop_lookup_int_array
6210Sstevel@tonic-gate 	 */
6220Sstevel@tonic-gate 	ddi_prop_free(regs_list);
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	if (index * 5 >= regs_prop_len) {
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 		return (USB_FAILURE);
6270Sstevel@tonic-gate 	}
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	/* Map in operational registers */
6300Sstevel@tonic-gate 	if (ddi_regs_map_setup(dip, index, (caddr_t *)&uhcip->uhci_regsp,
6310Sstevel@tonic-gate 	    0, sizeof (hc_regs_t), &attr, &uhcip->uhci_regs_handle) !=
6320Sstevel@tonic-gate 	    DDI_SUCCESS) {
633978Sfrits 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
6340Sstevel@tonic-gate 		    "ddi_regs_map_setup: failed");
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 		return (USB_FAILURE);
6370Sstevel@tonic-gate 	}
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	if (pci_config_setup(dip, &uhcip->uhci_config_handle) != DDI_SUCCESS) {
6400Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
6410Sstevel@tonic-gate 		    "uhci_map_regs: Config error");
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 		return (USB_FAILURE);
6440Sstevel@tonic-gate 	}
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	/* Make sure Memory Access Enable and Master Enable are set */
6470Sstevel@tonic-gate 	command_reg = pci_config_get16(uhcip->uhci_config_handle,
6480Sstevel@tonic-gate 	    PCI_CONF_COMM);
6490Sstevel@tonic-gate 	if (!(command_reg & (PCI_COMM_MAE | PCI_COMM_ME))) {
6500Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
6510Sstevel@tonic-gate 		    "uhci_map_regs: No MAE/ME");
6520Sstevel@tonic-gate 	}
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	command_reg |= PCI_COMM_MAE | PCI_COMM_ME;
6550Sstevel@tonic-gate 	pci_config_put16(uhcip->uhci_config_handle, PCI_CONF_COMM, command_reg);
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	/*
6580Sstevel@tonic-gate 	 * Check whether I/O base address is configured and enabled.
6590Sstevel@tonic-gate 	 */
6600Sstevel@tonic-gate 	if (!(command_reg & PCI_COMM_IO)) {
6610Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
6620Sstevel@tonic-gate 		    "I/O Base address access disabled");
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 		return (USB_FAILURE);
6650Sstevel@tonic-gate 	}
6660Sstevel@tonic-gate 	/*
6670Sstevel@tonic-gate 	 * Get the IO base address of the controller
6680Sstevel@tonic-gate 	 */
6690Sstevel@tonic-gate 	uhcip->uhci_iobase = (pci_config_get16(uhcip->uhci_config_handle,
6700Sstevel@tonic-gate 	    PCI_CONF_IOBASE) & PCI_CONF_IOBASE_MASK);
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
6730Sstevel@tonic-gate 	    "uhci_map_regs: Completed");
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	return (USB_SUCCESS);
6760Sstevel@tonic-gate }
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate void
uhci_unmap_regs(uhci_state_t * uhcip)6800Sstevel@tonic-gate uhci_unmap_regs(uhci_state_t *uhcip)
6810Sstevel@tonic-gate {
6820Sstevel@tonic-gate 	/* Unmap the UHCI registers */
6830Sstevel@tonic-gate 	if (uhcip->uhci_regs_handle) {
6840Sstevel@tonic-gate 		/* Reset the host controller */
6850Sstevel@tonic-gate 		Set_OpReg16(USBCMD, USBCMD_REG_GBL_RESET);
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 		ddi_regs_map_free(&uhcip->uhci_regs_handle);
6880Sstevel@tonic-gate 	}
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	if (uhcip->uhci_config_handle) {
6910Sstevel@tonic-gate 		pci_config_teardown(&uhcip->uhci_config_handle);
6920Sstevel@tonic-gate 	}
6930Sstevel@tonic-gate }
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate /*
6970Sstevel@tonic-gate  * uhci_set_dma_attributes:
6980Sstevel@tonic-gate  *	Set the limits in the DMA attributes structure. Most of the values used
6990Sstevel@tonic-gate  *	in the	DMA limit structres are the default values as specified by  the
7000Sstevel@tonic-gate  *	Writing PCI device drivers document.
7010Sstevel@tonic-gate  */
7020Sstevel@tonic-gate void
uhci_set_dma_attributes(uhci_state_t * uhcip)7030Sstevel@tonic-gate uhci_set_dma_attributes(uhci_state_t *uhcip)
7040Sstevel@tonic-gate {
7050Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
7060Sstevel@tonic-gate 	    "uhci_set_dma_attributes:");
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	/* Initialize the DMA attributes */
7090Sstevel@tonic-gate 	uhcip->uhci_dma_attr.dma_attr_version = DMA_ATTR_V0;
7100Sstevel@tonic-gate 	uhcip->uhci_dma_attr.dma_attr_addr_lo = 0x00000000ull;
7110Sstevel@tonic-gate 	uhcip->uhci_dma_attr.dma_attr_addr_hi = 0xfffffff0ull;
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	/* 32 bit addressing */
7140Sstevel@tonic-gate 	uhcip->uhci_dma_attr.dma_attr_count_max = 0xffffffull;
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	/*
7170Sstevel@tonic-gate 	 * Setting the dam_att_align to 512, some times fails the
7180Sstevel@tonic-gate 	 * binding handle. I dont know why ? But setting to 16 will
7190Sstevel@tonic-gate 	 * be right for our case (16 byte alignment required per
7200Sstevel@tonic-gate 	 * UHCI spec for TD descriptors).
7210Sstevel@tonic-gate 	 */
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	/* 16 byte alignment */
7240Sstevel@tonic-gate 	uhcip->uhci_dma_attr.dma_attr_align = 0x10;
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	/*
7270Sstevel@tonic-gate 	 * Since PCI  specification is byte alignment, the
7280Sstevel@tonic-gate 	 * burstsize field should be set to 1 for PCI devices.
7290Sstevel@tonic-gate 	 */
7300Sstevel@tonic-gate 	uhcip->uhci_dma_attr.dma_attr_burstsizes = 0x1;
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	uhcip->uhci_dma_attr.dma_attr_minxfer	= 0x1;
7330Sstevel@tonic-gate 	uhcip->uhci_dma_attr.dma_attr_maxxfer	= 0xffffffull;
7340Sstevel@tonic-gate 	uhcip->uhci_dma_attr.dma_attr_seg	= 0xffffffffull;
7350Sstevel@tonic-gate 	uhcip->uhci_dma_attr.dma_attr_sgllen	= 1;
7360Sstevel@tonic-gate 	uhcip->uhci_dma_attr.dma_attr_granular	= 1;
7370Sstevel@tonic-gate 	uhcip->uhci_dma_attr.dma_attr_flags	= 0;
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate uint_t
pow_2(uint_t x)7420Sstevel@tonic-gate pow_2(uint_t x)
7430Sstevel@tonic-gate {
7440Sstevel@tonic-gate 	return ((x == 0) ? 1 : (1 << x));
7450Sstevel@tonic-gate }
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate uint_t
log_2(uint_t x)7490Sstevel@tonic-gate log_2(uint_t x)
7500Sstevel@tonic-gate {
7510Sstevel@tonic-gate 	int ret_val = 0;
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 	while (x != 1) {
7540Sstevel@tonic-gate 		ret_val++;
7550Sstevel@tonic-gate 		x = x >> 1;
7560Sstevel@tonic-gate 	}
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	return (ret_val);
7590Sstevel@tonic-gate }
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate /*
7630Sstevel@tonic-gate  * uhci_obtain_state:
7640Sstevel@tonic-gate  */
7650Sstevel@tonic-gate uhci_state_t *
uhci_obtain_state(dev_info_t * dip)7660Sstevel@tonic-gate uhci_obtain_state(dev_info_t *dip)
7670Sstevel@tonic-gate {
7680Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
7690Sstevel@tonic-gate 	uhci_state_t *state = ddi_get_soft_state(uhci_statep, instance);
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	ASSERT(state != NULL);
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 	return (state);
7740Sstevel@tonic-gate }
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate /*
7780Sstevel@tonic-gate  * uhci_alloc_hcdi_ops:
7790Sstevel@tonic-gate  *	The HCDI interfaces or entry points are the software interfaces used by
7800Sstevel@tonic-gate  *	the Universal Serial Bus Driver  (USBA) to  access the services of the
7810Sstevel@tonic-gate  *	Host Controller Driver (HCD).  During HCD initialization, inform  USBA
7820Sstevel@tonic-gate  *	about all available HCDI interfaces or entry points.
7830Sstevel@tonic-gate  */
7840Sstevel@tonic-gate usba_hcdi_ops_t *
uhci_alloc_hcdi_ops(uhci_state_t * uhcip)7850Sstevel@tonic-gate uhci_alloc_hcdi_ops(uhci_state_t *uhcip)
7860Sstevel@tonic-gate {
7870Sstevel@tonic-gate 	usba_hcdi_ops_t	*hcdi_ops;
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
7900Sstevel@tonic-gate 	    "uhci_alloc_hcdi_ops:");
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	hcdi_ops = usba_alloc_hcdi_ops();
7930Sstevel@tonic-gate 
7942191Sszhou 	hcdi_ops->usba_hcdi_ops_version = HCDI_OPS_VERSION_1;
7952191Sszhou 
7960Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_pipe_open = uhci_hcdi_pipe_open;
7970Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_pipe_close	= uhci_hcdi_pipe_close;
7980Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_pipe_reset = uhci_hcdi_pipe_reset;
7998945SGuoqing.Zhu@Sun.COM 	hcdi_ops->usba_hcdi_pipe_reset_data_toggle =
8008945SGuoqing.Zhu@Sun.COM 	    uhci_hcdi_pipe_reset_data_toggle;
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_pipe_ctrl_xfer = uhci_hcdi_pipe_ctrl_xfer;
8030Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_pipe_bulk_xfer = uhci_hcdi_pipe_bulk_xfer;
8040Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_pipe_intr_xfer = uhci_hcdi_pipe_intr_xfer;
8050Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_pipe_isoc_xfer = uhci_hcdi_pipe_isoc_xfer;
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_bulk_transfer_size = uhci_hcdi_bulk_transfer_size;
8080Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_pipe_stop_intr_polling =
8095773Sqz150045 	    uhci_hcdi_pipe_stop_intr_polling;
8100Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_pipe_stop_isoc_polling =
8115773Sqz150045 	    uhci_hcdi_pipe_stop_isoc_polling;
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_get_current_frame_number =
8145773Sqz150045 	    uhci_hcdi_get_current_frame_number;
8150Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_get_max_isoc_pkts = uhci_hcdi_get_max_isoc_pkts;
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_console_input_init = uhci_hcdi_polled_input_init;
8180Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_console_input_enter = uhci_hcdi_polled_input_enter;
8190Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_console_read = uhci_hcdi_polled_read;
8200Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_console_input_exit = uhci_hcdi_polled_input_exit;
8210Sstevel@tonic-gate 	hcdi_ops->usba_hcdi_console_input_fini = uhci_hcdi_polled_input_fini;
8220Sstevel@tonic-gate 
8232191Sszhou 	hcdi_ops->usba_hcdi_console_output_init = uhci_hcdi_polled_output_init;
8242191Sszhou 	hcdi_ops->usba_hcdi_console_output_enter =
8252191Sszhou 	    uhci_hcdi_polled_output_enter;
8262191Sszhou 	hcdi_ops->usba_hcdi_console_write = uhci_hcdi_polled_write;
8272191Sszhou 	hcdi_ops->usba_hcdi_console_output_exit = uhci_hcdi_polled_output_exit;
8282191Sszhou 	hcdi_ops->usba_hcdi_console_output_fini = uhci_hcdi_polled_output_fini;
8292191Sszhou 
8300Sstevel@tonic-gate 	return (hcdi_ops);
8310Sstevel@tonic-gate }
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate /*
8350Sstevel@tonic-gate  * uhci_init_frame_lst_table :
8360Sstevel@tonic-gate  *	Allocate the system memory and initialize Host Controller
8370Sstevel@tonic-gate  *	Frame list table area The starting of the Frame list Table
8380Sstevel@tonic-gate  *	area must be 4096 byte aligned.
8390Sstevel@tonic-gate  */
8400Sstevel@tonic-gate static int
uhci_init_frame_lst_table(dev_info_t * dip,uhci_state_t * uhcip)8410Sstevel@tonic-gate uhci_init_frame_lst_table(dev_info_t *dip, uhci_state_t *uhcip)
8420Sstevel@tonic-gate {
8430Sstevel@tonic-gate 	int			result;
8440Sstevel@tonic-gate 	uint_t			ccount;
8450Sstevel@tonic-gate 	size_t			real_length;
8460Sstevel@tonic-gate 	ddi_device_acc_attr_t	dev_attr;
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
8510Sstevel@tonic-gate 	    "uhci_init_frame_lst_table:");
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 	/* The host controller will be little endian */
8540Sstevel@tonic-gate 	dev_attr.devacc_attr_version		= DDI_DEVICE_ATTR_V0;
8550Sstevel@tonic-gate 	dev_attr.devacc_attr_endian_flags	= DDI_STRUCTURE_LE_ACC;
8560Sstevel@tonic-gate 	dev_attr.devacc_attr_dataorder		= DDI_STRICTORDER_ACC;
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	/* 4K alignment required */
8590Sstevel@tonic-gate 	uhcip->uhci_dma_attr.dma_attr_align = 0x1000;
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	/* Create space for the HCCA block */
8620Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(dip, &uhcip->uhci_dma_attr, DDI_DMA_SLEEP,
8630Sstevel@tonic-gate 	    0, &uhcip->uhci_flt_dma_handle) != DDI_SUCCESS) {
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 		return (USB_FAILURE);
8660Sstevel@tonic-gate 	}
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	/* Reset to default 16 bytes */
8690Sstevel@tonic-gate 	uhcip->uhci_dma_attr.dma_attr_align = 0x10;
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(uhcip->uhci_flt_dma_handle,
8720Sstevel@tonic-gate 	    SIZE_OF_FRAME_LST_TABLE, &dev_attr, DDI_DMA_CONSISTENT,
8730Sstevel@tonic-gate 	    DDI_DMA_SLEEP, 0, (caddr_t *)&uhcip->uhci_frame_lst_tablep,
8740Sstevel@tonic-gate 	    &real_length, &uhcip->uhci_flt_mem_handle)) {
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 		return (USB_FAILURE);
8770Sstevel@tonic-gate 	}
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	/* Map the whole Frame list base area into the I/O address space */
8800Sstevel@tonic-gate 	result = ddi_dma_addr_bind_handle(uhcip->uhci_flt_dma_handle,
8810Sstevel@tonic-gate 	    NULL, (caddr_t)uhcip->uhci_frame_lst_tablep, real_length,
8820Sstevel@tonic-gate 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
8830Sstevel@tonic-gate 	    &uhcip->uhci_flt_cookie, &ccount);
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	if (result == DDI_DMA_MAPPED) {
8860Sstevel@tonic-gate 		/* The cookie count should be 1 */
8870Sstevel@tonic-gate 		if (ccount != 1) {
8880Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
8890Sstevel@tonic-gate 			    "uhci_init_frame_list_table: More than 1 cookie");
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 			return (USB_FAILURE);
8920Sstevel@tonic-gate 		}
8930Sstevel@tonic-gate 	} else {
8940Sstevel@tonic-gate 		uhci_decode_ddi_dma_addr_bind_handle_result(uhcip, result);
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 		return (USB_FAILURE);
8970Sstevel@tonic-gate 	}
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	uhcip->uhci_dma_addr_bind_flag |= UHCI_FLA_POOL_BOUND;
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	bzero((void *)uhcip->uhci_frame_lst_tablep, real_length);
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	/* Initialize the interrupt lists */
9040Sstevel@tonic-gate 	uhci_build_interrupt_lattice(uhcip);
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	return (USB_SUCCESS);
9070Sstevel@tonic-gate }
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate /*
9110Sstevel@tonic-gate  * uhci_alloc_queue_head:
9120Sstevel@tonic-gate  *	Allocate a queue head
9130Sstevel@tonic-gate  */
9140Sstevel@tonic-gate queue_head_t *
uhci_alloc_queue_head(uhci_state_t * uhcip)9150Sstevel@tonic-gate uhci_alloc_queue_head(uhci_state_t *uhcip)
9160Sstevel@tonic-gate {
9170Sstevel@tonic-gate 	int		index;
9180Sstevel@tonic-gate 	uhci_td_t	*dummy_td;
9190Sstevel@tonic-gate 	queue_head_t	*queue_head;
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl,
9220Sstevel@tonic-gate 	    "uhci_alloc_queue_head");
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 	/* Allocate a dummy td first. */
9270Sstevel@tonic-gate 	if ((dummy_td = uhci_allocate_td_from_pool(uhcip)) == NULL) {
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALLOC,  uhcip->uhci_log_hdl,
9305773Sqz150045 		    "uhci_alloc_queue_head: allocate td from pool failed");
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 		return (NULL);
9330Sstevel@tonic-gate 	}
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	/*
9360Sstevel@tonic-gate 	 * The first 63 queue heads in the Queue Head (QH)
9370Sstevel@tonic-gate 	 * buffer pool are reserved for building interrupt lattice
9380Sstevel@tonic-gate 	 * tree. Search for a blank Queue head in the QH buffer pool.
9390Sstevel@tonic-gate 	 */
9400Sstevel@tonic-gate 	for (index = NUM_STATIC_NODES; index < uhci_qh_pool_size; index++) {
9410Sstevel@tonic-gate 		if (uhcip->uhci_qh_pool_addr[index].qh_flag ==
9420Sstevel@tonic-gate 		    QUEUE_HEAD_FLAG_FREE) {
9430Sstevel@tonic-gate 			break;
9440Sstevel@tonic-gate 		}
9450Sstevel@tonic-gate 	}
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl,
9480Sstevel@tonic-gate 	    "uhci_alloc_queue_head: Allocated %d", index);
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	if (index == uhci_qh_pool_size) {
951978Sfrits 		USB_DPRINTF_L2(PRINT_MASK_ALLOC,  uhcip->uhci_log_hdl,
9520Sstevel@tonic-gate 		    "uhci_alloc_queue_head: All QH exhausted");
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 		/* Free the dummy td allocated for this qh. */
9550Sstevel@tonic-gate 		dummy_td->flag = TD_FLAG_FREE;
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 		return (NULL);
9580Sstevel@tonic-gate 	}
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 	queue_head = &uhcip->uhci_qh_pool_addr[index];
9610Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl,
9626898Sfb209375 	    "uhci_alloc_queue_head: Allocated address 0x%p",
9636898Sfb209375 	    (void *)queue_head);
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	bzero((void *)queue_head, sizeof (queue_head_t));
9660Sstevel@tonic-gate 	SetQH32(uhcip, queue_head->link_ptr, HC_END_OF_LIST);
9670Sstevel@tonic-gate 	SetQH32(uhcip, queue_head->element_ptr, HC_END_OF_LIST);
9680Sstevel@tonic-gate 	queue_head->prev_qh	= NULL;
9690Sstevel@tonic-gate 	queue_head->qh_flag	= QUEUE_HEAD_FLAG_BUSY;
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	bzero((char *)dummy_td, sizeof (uhci_td_t));
9720Sstevel@tonic-gate 	queue_head->td_tailp	= dummy_td;
9730Sstevel@tonic-gate 	SetQH32(uhcip, queue_head->element_ptr, TD_PADDR(dummy_td));
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	return (queue_head);
9760Sstevel@tonic-gate }
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate /*
9800Sstevel@tonic-gate  * uhci_allocate_bandwidth:
9810Sstevel@tonic-gate  *	Figure out whether or not this interval may be supported. Return
9820Sstevel@tonic-gate  *	the index into the  lattice if it can be supported.  Return
9830Sstevel@tonic-gate  *	allocation failure if it can not be supported.
9840Sstevel@tonic-gate  */
9850Sstevel@tonic-gate int
uhci_allocate_bandwidth(uhci_state_t * uhcip,usba_pipe_handle_data_t * pipe_handle,uint_t * node)9860Sstevel@tonic-gate uhci_allocate_bandwidth(
9870Sstevel@tonic-gate 	uhci_state_t		*uhcip,
9880Sstevel@tonic-gate 	usba_pipe_handle_data_t	*pipe_handle,
9890Sstevel@tonic-gate 	uint_t			*node)
9900Sstevel@tonic-gate {
9910Sstevel@tonic-gate 	int		bandwidth;	/* Requested bandwidth */
9920Sstevel@tonic-gate 	uint_t		min, min_index;
9930Sstevel@tonic-gate 	uint_t		i;
9940Sstevel@tonic-gate 	uint_t		height;		/* Bandwidth's height in the tree */
9950Sstevel@tonic-gate 	uint_t		leftmost;
9960Sstevel@tonic-gate 	uint_t		length;
9970Sstevel@tonic-gate 	uint32_t	paddr;
9980Sstevel@tonic-gate 	queue_head_t	*tmp_qh;
9990Sstevel@tonic-gate 	usb_ep_descr_t	*endpoint = &pipe_handle->p_ep;
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	/*
10040Sstevel@tonic-gate 	 * Calculate the length in bytes of a transaction on this
10050Sstevel@tonic-gate 	 * periodic endpoint.
10060Sstevel@tonic-gate 	 */
10070Sstevel@tonic-gate 	mutex_enter(&pipe_handle->p_usba_device->usb_mutex);
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 	length = uhci_compute_total_bandwidth(endpoint,
10105773Sqz150045 	    pipe_handle->p_usba_device->usb_port_status);
10110Sstevel@tonic-gate 	mutex_exit(&pipe_handle->p_usba_device->usb_mutex);
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	/*
10140Sstevel@tonic-gate 	 * If the length in bytes plus the allocated bandwidth exceeds
10150Sstevel@tonic-gate 	 * the maximum, return bandwidth allocation failure.
10160Sstevel@tonic-gate 	 */
10170Sstevel@tonic-gate 	if ((length + uhcip->uhci_bandwidth_intr_min +
10185773Sqz150045 	    uhcip->uhci_bandwidth_isoch_sum) > (MAX_PERIODIC_BANDWIDTH)) {
10190Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
10200Sstevel@tonic-gate 		    "uhci_allocate_bandwidth: "
10210Sstevel@tonic-gate 		    "Reached maximum bandwidth value and cannot allocate "
10220Sstevel@tonic-gate 		    "bandwidth for a given Interrupt/Isoch endpoint");
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 		return (USB_NO_BANDWIDTH);
10250Sstevel@tonic-gate 	}
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	/*
10280Sstevel@tonic-gate 	 * ISOC xfers are not supported at this point type
10290Sstevel@tonic-gate 	 */
10300Sstevel@tonic-gate 	if (UHCI_XFER_TYPE(endpoint) == USB_EP_ATTR_ISOCH) {
10310Sstevel@tonic-gate 		uhcip->uhci_bandwidth_isoch_sum += length;
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 		return (USB_SUCCESS);
10340Sstevel@tonic-gate 	}
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 	/*
10370Sstevel@tonic-gate 	 * This is an interrupt endpoint.
10380Sstevel@tonic-gate 	 * Adjust bandwidth to be a power of 2
10390Sstevel@tonic-gate 	 */
10400Sstevel@tonic-gate 	mutex_enter(&pipe_handle->p_usba_device->usb_mutex);
10410Sstevel@tonic-gate 	bandwidth = uhci_bandwidth_adjust(uhcip, endpoint,
10425773Sqz150045 	    pipe_handle->p_usba_device->usb_port_status);
10430Sstevel@tonic-gate 	mutex_exit(&pipe_handle->p_usba_device->usb_mutex);
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	/*
10460Sstevel@tonic-gate 	 * If this bandwidth can't be supported,
10470Sstevel@tonic-gate 	 * return allocation failure.
10480Sstevel@tonic-gate 	 */
10490Sstevel@tonic-gate 	if (bandwidth == USB_FAILURE) {
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 		return (USB_FAILURE);
10520Sstevel@tonic-gate 	}
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_BW, uhcip->uhci_log_hdl,
10550Sstevel@tonic-gate 	    "The new bandwidth is %d", bandwidth);
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	/* Find the leaf with the smallest allocated bandwidth */
10580Sstevel@tonic-gate 	min_index = 0;
10590Sstevel@tonic-gate 	min = uhcip->uhci_bandwidth[0];
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	for (i = 1; i < NUM_FRAME_LST_ENTRIES; i++) {
10620Sstevel@tonic-gate 		if (uhcip->uhci_bandwidth[i] < min) {
10630Sstevel@tonic-gate 			min_index = i;
10640Sstevel@tonic-gate 			min = uhcip->uhci_bandwidth[i];
10650Sstevel@tonic-gate 		}
10660Sstevel@tonic-gate 	}
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_BW, uhcip->uhci_log_hdl,
10690Sstevel@tonic-gate 	    "The leaf with minimal bandwidth %d, "
10700Sstevel@tonic-gate 	    "The smallest bandwidth %d", min_index, min);
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	/*
10730Sstevel@tonic-gate 	 * Find the index into the lattice given the
10740Sstevel@tonic-gate 	 * leaf with the smallest allocated bandwidth.
10750Sstevel@tonic-gate 	 */
10760Sstevel@tonic-gate 	height = uhci_lattice_height(bandwidth);
10770Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_BW, uhcip->uhci_log_hdl,
10780Sstevel@tonic-gate 	    "The height is %d", height);
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 	*node = uhci_tree_bottom_nodes[min_index];
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	/* check if there are isocs TDs scheduled for this frame */
10830Sstevel@tonic-gate 	if (uhcip->uhci_isoc_q_tailp[*node]) {
10840Sstevel@tonic-gate 		paddr = (uhcip->uhci_isoc_q_tailp[*node]->link_ptr &
10855773Sqz150045 		    FRAME_LST_PTR_MASK);
10860Sstevel@tonic-gate 	} else {
10870Sstevel@tonic-gate 		paddr = (uhcip->uhci_frame_lst_tablep[*node] &
10885773Sqz150045 		    FRAME_LST_PTR_MASK);
10890Sstevel@tonic-gate 	}
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 	tmp_qh = QH_VADDR(paddr);
10920Sstevel@tonic-gate 	*node = tmp_qh->node;
10930Sstevel@tonic-gate 	for (i = 0; i < height; i++) {
10940Sstevel@tonic-gate 		*node = uhci_lattice_parent(*node);
10950Sstevel@tonic-gate 	}
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_BW, uhcip->uhci_log_hdl,
10980Sstevel@tonic-gate 	    "The real node is %d", *node);
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	/*
11010Sstevel@tonic-gate 	 * Find the leftmost leaf in the subtree specified by the node.
11020Sstevel@tonic-gate 	 */
11030Sstevel@tonic-gate 	leftmost = uhci_leftmost_leaf(*node, height);
11040Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_BW, uhcip->uhci_log_hdl,
11050Sstevel@tonic-gate 	    "Leftmost %d", leftmost);
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	for (i = leftmost; i < leftmost +
11080Sstevel@tonic-gate 	    (NUM_FRAME_LST_ENTRIES/bandwidth); i ++) {
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 		if ((length + uhcip->uhci_bandwidth_isoch_sum +
11115773Sqz150045 		    uhcip->uhci_bandwidth[i]) > MAX_PERIODIC_BANDWIDTH) {
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
11140Sstevel@tonic-gate 			    "uhci_allocate_bandwidth: "
11150Sstevel@tonic-gate 			    "Reached maximum bandwidth value and cannot "
11160Sstevel@tonic-gate 			    "allocate bandwidth for Interrupt endpoint");
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 			return (USB_NO_BANDWIDTH);
11190Sstevel@tonic-gate 		}
11200Sstevel@tonic-gate 	}
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 	/*
11230Sstevel@tonic-gate 	 * All the leaves for this node must be updated with the bandwidth.
11240Sstevel@tonic-gate 	 */
11250Sstevel@tonic-gate 	for (i = leftmost; i < leftmost +
11260Sstevel@tonic-gate 	    (NUM_FRAME_LST_ENTRIES/bandwidth); i ++) {
11270Sstevel@tonic-gate 		uhcip->uhci_bandwidth[i] += length;
11280Sstevel@tonic-gate 	}
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 	/* Find the leaf with the smallest allocated bandwidth */
11310Sstevel@tonic-gate 	min_index = 0;
11320Sstevel@tonic-gate 	min = uhcip->uhci_bandwidth[0];
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	for (i = 1; i < NUM_FRAME_LST_ENTRIES; i++) {
11350Sstevel@tonic-gate 		if (uhcip->uhci_bandwidth[i] < min) {
11360Sstevel@tonic-gate 			min_index = i;
11370Sstevel@tonic-gate 			min = uhcip->uhci_bandwidth[i];
11380Sstevel@tonic-gate 		}
11390Sstevel@tonic-gate 	}
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	/* Save the minimum for later use */
11420Sstevel@tonic-gate 	uhcip->uhci_bandwidth_intr_min = min;
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 	return (USB_SUCCESS);
11450Sstevel@tonic-gate }
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate /*
11490Sstevel@tonic-gate  * uhci_deallocate_bandwidth:
11500Sstevel@tonic-gate  *	Deallocate bandwidth for the given node in the lattice
11510Sstevel@tonic-gate  *	and the length of transfer.
11520Sstevel@tonic-gate  */
11530Sstevel@tonic-gate void
uhci_deallocate_bandwidth(uhci_state_t * uhcip,usba_pipe_handle_data_t * pipe_handle)11540Sstevel@tonic-gate uhci_deallocate_bandwidth(uhci_state_t *uhcip,
11550Sstevel@tonic-gate     usba_pipe_handle_data_t *pipe_handle)
11560Sstevel@tonic-gate {
11570Sstevel@tonic-gate 	uint_t		bandwidth;
11580Sstevel@tonic-gate 	uint_t		height;
11590Sstevel@tonic-gate 	uint_t		leftmost;
11600Sstevel@tonic-gate 	uint_t		i;
11610Sstevel@tonic-gate 	uint_t		min;
11620Sstevel@tonic-gate 	usb_ep_descr_t	*endpoint = &pipe_handle->p_ep;
11630Sstevel@tonic-gate 	uint_t		node, length;
11640Sstevel@tonic-gate 	uhci_pipe_private_t *pp =
11655773Sqz150045 	    (uhci_pipe_private_t *)pipe_handle->p_hcd_private;
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 	/* This routine is protected by the uhci_int_mutex */
11680Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	/* Obtain the length */
11710Sstevel@tonic-gate 	mutex_enter(&pipe_handle->p_usba_device->usb_mutex);
11720Sstevel@tonic-gate 	length = uhci_compute_total_bandwidth(endpoint,
11735773Sqz150045 	    pipe_handle->p_usba_device->usb_port_status);
11740Sstevel@tonic-gate 	mutex_exit(&pipe_handle->p_usba_device->usb_mutex);
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 	/*
11770Sstevel@tonic-gate 	 * If this is an isochronous endpoint, just delete endpoint's
11780Sstevel@tonic-gate 	 * bandwidth from the total allocated isochronous bandwidth.
11790Sstevel@tonic-gate 	 */
11800Sstevel@tonic-gate 	if (UHCI_XFER_TYPE(endpoint) == USB_EP_ATTR_ISOCH) {
11810Sstevel@tonic-gate 		uhcip->uhci_bandwidth_isoch_sum -= length;
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 		return;
11840Sstevel@tonic-gate 	}
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	/* Obtain the node */
11870Sstevel@tonic-gate 	node = pp->pp_node;
11880Sstevel@tonic-gate 
11890Sstevel@tonic-gate 	/* Adjust bandwidth to be a power of 2 */
11900Sstevel@tonic-gate 	mutex_enter(&pipe_handle->p_usba_device->usb_mutex);
11910Sstevel@tonic-gate 	bandwidth = uhci_bandwidth_adjust(uhcip, endpoint,
11925773Sqz150045 	    pipe_handle->p_usba_device->usb_port_status);
11930Sstevel@tonic-gate 	mutex_exit(&pipe_handle->p_usba_device->usb_mutex);
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 	/* Find the height in the tree */
11960Sstevel@tonic-gate 	height = uhci_lattice_height(bandwidth);
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	/*
11990Sstevel@tonic-gate 	 * Find the leftmost leaf in the subtree specified by the node
12000Sstevel@tonic-gate 	 */
12010Sstevel@tonic-gate 	leftmost = uhci_leftmost_leaf(node, height);
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 	/* Delete the bandwith from the appropriate lists */
12040Sstevel@tonic-gate 	for (i = leftmost; i < leftmost + (NUM_FRAME_LST_ENTRIES/bandwidth);
12050Sstevel@tonic-gate 	    i ++) {
12060Sstevel@tonic-gate 		uhcip->uhci_bandwidth[i] -= length;
12070Sstevel@tonic-gate 	}
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 	min = uhcip->uhci_bandwidth[0];
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate 	/* Recompute the minimum */
12120Sstevel@tonic-gate 	for (i = 1; i < NUM_FRAME_LST_ENTRIES; i++) {
12130Sstevel@tonic-gate 		if (uhcip->uhci_bandwidth[i] < min) {
12140Sstevel@tonic-gate 			min = uhcip->uhci_bandwidth[i];
12150Sstevel@tonic-gate 		}
12160Sstevel@tonic-gate 	}
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	/* Save the minimum for later use */
12190Sstevel@tonic-gate 	uhcip->uhci_bandwidth_intr_min = min;
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate /*
12240Sstevel@tonic-gate  * uhci_compute_total_bandwidth:
12250Sstevel@tonic-gate  *
12260Sstevel@tonic-gate  * Given a periodic endpoint (interrupt or isochronous) determine the total
12270Sstevel@tonic-gate  * bandwidth for one transaction. The UHCI host controller traverses the
12280Sstevel@tonic-gate  * endpoint descriptor lists on a first-come-first-serve basis. When the HC
12290Sstevel@tonic-gate  * services an endpoint, only a single transaction attempt is made. The  HC
12300Sstevel@tonic-gate  * moves to the next Endpoint Descriptor after the first transaction attempt
12310Sstevel@tonic-gate  * rather than finishing the entire Transfer Descriptor. Therefore, when  a
12320Sstevel@tonic-gate  * Transfer Descriptor is inserted into the lattice, we will only count the
12330Sstevel@tonic-gate  * number of bytes for one transaction.
12340Sstevel@tonic-gate  *
12350Sstevel@tonic-gate  * The following are the formulas used for calculating bandwidth in terms
12360Sstevel@tonic-gate  * bytes and it is for the single USB full speed and low speed	transaction
12370Sstevel@tonic-gate  * respectively. The protocol overheads will be different for each of  type
12380Sstevel@tonic-gate  * of USB transfer and all these formulas & protocol overheads are  derived
12390Sstevel@tonic-gate  * from the 5.9.3 section of USB Specification & with the help of Bandwidth
12400Sstevel@tonic-gate  * Analysis white paper which is posted on the USB  developer forum.
12410Sstevel@tonic-gate  *
12420Sstevel@tonic-gate  * Full-Speed:
12430Sstevel@tonic-gate  *	  Protocol overhead  + ((MaxPacketSize * 7)/6 )  + Host_Delay
12440Sstevel@tonic-gate  *
12450Sstevel@tonic-gate  * Low-Speed:
12460Sstevel@tonic-gate  *		Protocol overhead  + Hub LS overhead +
12470Sstevel@tonic-gate  *		  (Low-Speed clock * ((MaxPacketSize * 7)/6 )) + Host_Delay
12480Sstevel@tonic-gate  */
12490Sstevel@tonic-gate static uint_t
uhci_compute_total_bandwidth(usb_ep_descr_t * endpoint,usb_port_status_t port_status)12500Sstevel@tonic-gate uhci_compute_total_bandwidth(usb_ep_descr_t *endpoint,
12510Sstevel@tonic-gate 		usb_port_status_t port_status)
12520Sstevel@tonic-gate {
12530Sstevel@tonic-gate 	uint_t		bandwidth;
12540Sstevel@tonic-gate 	ushort_t	MaxPacketSize = endpoint->wMaxPacketSize;
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 	/* Add Host Controller specific delay to required bandwidth */
12570Sstevel@tonic-gate 	bandwidth = HOST_CONTROLLER_DELAY;
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	/* Add bit-stuffing overhead */
12600Sstevel@tonic-gate 	MaxPacketSize = (ushort_t)((MaxPacketSize * 7) / 6);
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate 	/* Low Speed interrupt transaction */
12630Sstevel@tonic-gate 	if (port_status == USBA_LOW_SPEED_DEV) {
12640Sstevel@tonic-gate 		/* Low Speed interrupt transaction */
12650Sstevel@tonic-gate 		bandwidth += (LOW_SPEED_PROTO_OVERHEAD +
12665773Sqz150045 		    HUB_LOW_SPEED_PROTO_OVERHEAD +
12675773Sqz150045 		    (LOW_SPEED_CLOCK * MaxPacketSize));
12680Sstevel@tonic-gate 	} else {
12690Sstevel@tonic-gate 		/* Full Speed transaction */
12700Sstevel@tonic-gate 		bandwidth += MaxPacketSize;
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 		if (UHCI_XFER_TYPE(endpoint) == USB_EP_ATTR_INTR) {
12730Sstevel@tonic-gate 			/* Full Speed interrupt transaction */
12740Sstevel@tonic-gate 			bandwidth += FS_NON_ISOC_PROTO_OVERHEAD;
12750Sstevel@tonic-gate 		} else {
12760Sstevel@tonic-gate 			/* Isochronus and input transaction */
12770Sstevel@tonic-gate 			if (UHCI_XFER_DIR(endpoint) == USB_EP_DIR_IN) {
12780Sstevel@tonic-gate 				bandwidth += FS_ISOC_INPUT_PROTO_OVERHEAD;
12790Sstevel@tonic-gate 			} else {
12800Sstevel@tonic-gate 				/* Isochronus and output transaction */
12810Sstevel@tonic-gate 				bandwidth += FS_ISOC_OUTPUT_PROTO_OVERHEAD;
12820Sstevel@tonic-gate 			}
12830Sstevel@tonic-gate 		}
12840Sstevel@tonic-gate 	}
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 	return (bandwidth);
12870Sstevel@tonic-gate }
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate /*
12910Sstevel@tonic-gate  * uhci_bandwidth_adjust:
12920Sstevel@tonic-gate  */
12930Sstevel@tonic-gate static int
uhci_bandwidth_adjust(uhci_state_t * uhcip,usb_ep_descr_t * endpoint,usb_port_status_t port_status)12940Sstevel@tonic-gate uhci_bandwidth_adjust(
12950Sstevel@tonic-gate 	uhci_state_t		*uhcip,
12960Sstevel@tonic-gate 	usb_ep_descr_t		*endpoint,
12970Sstevel@tonic-gate 	usb_port_status_t	port_status)
12980Sstevel@tonic-gate {
12990Sstevel@tonic-gate 	int	i = 0;
13000Sstevel@tonic-gate 	uint_t	interval;
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	/*
13030Sstevel@tonic-gate 	 * Get the polling interval from the endpoint descriptor
13040Sstevel@tonic-gate 	 */
13050Sstevel@tonic-gate 	interval = endpoint->bInterval;
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	/*
13080Sstevel@tonic-gate 	 * The bInterval value in the endpoint descriptor can range
13090Sstevel@tonic-gate 	 * from 1 to 255ms. The interrupt lattice has 32 leaf nodes,
13100Sstevel@tonic-gate 	 * and the host controller cycles through these nodes every
13110Sstevel@tonic-gate 	 * 32ms. The longest polling  interval that the  controller
13120Sstevel@tonic-gate 	 * supports is 32ms.
13130Sstevel@tonic-gate 	 */
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 	/*
13160Sstevel@tonic-gate 	 * Return an error if the polling interval is less than 1ms
13170Sstevel@tonic-gate 	 * and greater than 255ms
13180Sstevel@tonic-gate 	 */
13190Sstevel@tonic-gate 	if ((interval < MIN_POLL_INTERVAL) || (interval > MAX_POLL_INTERVAL)) {
13200Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
13210Sstevel@tonic-gate 		    "uhci_bandwidth_adjust: Endpoint's poll interval must be "
13220Sstevel@tonic-gate 		    "between %d and %d ms", MIN_POLL_INTERVAL,
13230Sstevel@tonic-gate 		    MAX_POLL_INTERVAL);
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate 		return (USB_FAILURE);
13260Sstevel@tonic-gate 	}
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 	/*
13290Sstevel@tonic-gate 	 * According USB Specifications, a  full-speed endpoint can
13300Sstevel@tonic-gate 	 * specify a desired polling interval 1ms to 255ms and a low
13310Sstevel@tonic-gate 	 * speed  endpoints are limited to  specifying only 10ms to
13320Sstevel@tonic-gate 	 * 255ms. But some old keyboards & mice uses polling interval
13330Sstevel@tonic-gate 	 * of 8ms. For compatibility  purpose, we are using polling
13340Sstevel@tonic-gate 	 * interval between 8ms & 255ms for low speed endpoints.
13350Sstevel@tonic-gate 	 */
13360Sstevel@tonic-gate 	if ((port_status == USBA_LOW_SPEED_DEV) &&
13370Sstevel@tonic-gate 	    (interval < MIN_LOW_SPEED_POLL_INTERVAL)) {
1338978Sfrits 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
13390Sstevel@tonic-gate 		    "uhci_bandwidth_adjust: Low speed endpoint's poll interval "
13400Sstevel@tonic-gate 		    "must be >= %d ms, adjusted",
13410Sstevel@tonic-gate 		    MIN_LOW_SPEED_POLL_INTERVAL);
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 		interval = MIN_LOW_SPEED_POLL_INTERVAL;
13440Sstevel@tonic-gate 	}
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate 	/*
13470Sstevel@tonic-gate 	 * If polling interval is greater than 32ms,
13480Sstevel@tonic-gate 	 * adjust polling interval equal to 32ms.
13490Sstevel@tonic-gate 	 */
13500Sstevel@tonic-gate 	if (interval > 32) {
13510Sstevel@tonic-gate 		interval = 32;
13520Sstevel@tonic-gate 	}
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate 	/*
13550Sstevel@tonic-gate 	 * Find the nearest power of 2 that's less
13560Sstevel@tonic-gate 	 * than interval.
13570Sstevel@tonic-gate 	 */
13580Sstevel@tonic-gate 	while ((pow_2(i)) <= interval) {
13590Sstevel@tonic-gate 		i++;
13600Sstevel@tonic-gate 	}
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	return (pow_2((i - 1)));
13630Sstevel@tonic-gate }
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate /*
13670Sstevel@tonic-gate  * uhci_lattice_height:
13680Sstevel@tonic-gate  *	Given the requested bandwidth, find the height in the tree at
13690Sstevel@tonic-gate  *	which the nodes for this bandwidth fall.  The height is measured
13700Sstevel@tonic-gate  *	as the number of nodes from the leaf to the level specified by
13710Sstevel@tonic-gate  *	bandwidth The root of the tree is at height TREE_HEIGHT.
13720Sstevel@tonic-gate  */
13730Sstevel@tonic-gate static uint_t
uhci_lattice_height(uint_t bandwidth)13740Sstevel@tonic-gate uhci_lattice_height(uint_t bandwidth)
13750Sstevel@tonic-gate {
13760Sstevel@tonic-gate 	return (TREE_HEIGHT - (log_2(bandwidth)));
13770Sstevel@tonic-gate }
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate static uint_t
uhci_lattice_parent(uint_t node)13810Sstevel@tonic-gate uhci_lattice_parent(uint_t node)
13820Sstevel@tonic-gate {
13830Sstevel@tonic-gate 	return (((node % 2) == 0) ? ((node/2) - 1) : (node/2));
13840Sstevel@tonic-gate }
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate /*
13880Sstevel@tonic-gate  * uhci_leftmost_leaf:
13890Sstevel@tonic-gate  *	Find the leftmost leaf in the subtree specified by the node.
13900Sstevel@tonic-gate  *	Height refers to number of nodes from the bottom of the tree
13910Sstevel@tonic-gate  *	to the node,  including the node.
13920Sstevel@tonic-gate  */
13930Sstevel@tonic-gate static uint_t
uhci_leftmost_leaf(uint_t node,uint_t height)13940Sstevel@tonic-gate uhci_leftmost_leaf(uint_t node, uint_t height)
13950Sstevel@tonic-gate {
13960Sstevel@tonic-gate 	node = pow_2(height + VIRTUAL_TREE_HEIGHT) * (node+1) -
13975773Sqz150045 	    NUM_FRAME_LST_ENTRIES;
13980Sstevel@tonic-gate 	return (node);
13990Sstevel@tonic-gate }
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate 
14020Sstevel@tonic-gate /*
14030Sstevel@tonic-gate  * uhci_insert_qh:
14040Sstevel@tonic-gate  *	Add the Queue Head (QH) into the Host Controller's (HC)
14050Sstevel@tonic-gate  *	appropriate queue head list.
14060Sstevel@tonic-gate  */
14070Sstevel@tonic-gate void
uhci_insert_qh(uhci_state_t * uhcip,usba_pipe_handle_data_t * ph)14080Sstevel@tonic-gate uhci_insert_qh(uhci_state_t *uhcip, usba_pipe_handle_data_t *ph)
14090Sstevel@tonic-gate {
14100Sstevel@tonic-gate 	uhci_pipe_private_t *pp = (uhci_pipe_private_t *)ph->p_hcd_private;
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
14130Sstevel@tonic-gate 	    "uhci_insert_qh:");
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 	switch (UHCI_XFER_TYPE(&ph->p_ep)) {
14180Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
14190Sstevel@tonic-gate 		uhci_insert_ctrl_qh(uhcip, pp);
14200Sstevel@tonic-gate 		break;
14210Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
14220Sstevel@tonic-gate 		uhci_insert_bulk_qh(uhcip, pp);
14230Sstevel@tonic-gate 		break;
14240Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
14250Sstevel@tonic-gate 		uhci_insert_intr_qh(uhcip, pp);
14260Sstevel@tonic-gate 		break;
14270Sstevel@tonic-gate 	case USB_EP_ATTR_ISOCH:
14280Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
14295773Sqz150045 			    "uhci_insert_qh: Illegal request");
14300Sstevel@tonic-gate 		break;
14310Sstevel@tonic-gate 	}
14320Sstevel@tonic-gate }
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate /*
14360Sstevel@tonic-gate  * uhci_insert_ctrl_qh:
14370Sstevel@tonic-gate  *	Insert a control QH into the Host Controller's (HC) control QH list.
14380Sstevel@tonic-gate  */
14390Sstevel@tonic-gate static void
uhci_insert_ctrl_qh(uhci_state_t * uhcip,uhci_pipe_private_t * pp)14400Sstevel@tonic-gate uhci_insert_ctrl_qh(uhci_state_t *uhcip, uhci_pipe_private_t *pp)
14410Sstevel@tonic-gate {
14420Sstevel@tonic-gate 	queue_head_t *qh = pp->pp_qh;
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
14450Sstevel@tonic-gate 	    "uhci_insert_ctrl_qh:");
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate 	if (uhcip->uhci_ctrl_xfers_q_head == uhcip->uhci_ctrl_xfers_q_tail) {
14500Sstevel@tonic-gate 		uhcip->uhci_ctrl_xfers_q_head->prev_qh	= UHCI_INVALID_PTR;
14510Sstevel@tonic-gate 	}
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 	SetQH32(uhcip, qh->link_ptr,
14540Sstevel@tonic-gate 	    GetQH32(uhcip, uhcip->uhci_ctrl_xfers_q_tail->link_ptr));
14550Sstevel@tonic-gate 	qh->prev_qh = uhcip->uhci_ctrl_xfers_q_tail;
14560Sstevel@tonic-gate 	SetQH32(uhcip, uhcip->uhci_ctrl_xfers_q_tail->link_ptr,
14575773Sqz150045 	    QH_PADDR(qh) | HC_QUEUE_HEAD);
14580Sstevel@tonic-gate 	uhcip->uhci_ctrl_xfers_q_tail = qh;
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate }
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate /*
14640Sstevel@tonic-gate  * uhci_insert_bulk_qh:
14650Sstevel@tonic-gate  *	Insert a bulk QH into the Host Controller's (HC) bulk QH list.
14660Sstevel@tonic-gate  */
14670Sstevel@tonic-gate static void
uhci_insert_bulk_qh(uhci_state_t * uhcip,uhci_pipe_private_t * pp)14680Sstevel@tonic-gate uhci_insert_bulk_qh(uhci_state_t *uhcip, uhci_pipe_private_t *pp)
14690Sstevel@tonic-gate {
14700Sstevel@tonic-gate 	queue_head_t *qh = pp->pp_qh;
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
14730Sstevel@tonic-gate 	    "uhci_insert_bulk_qh:");
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate 	if (uhcip->uhci_bulk_xfers_q_head == uhcip->uhci_bulk_xfers_q_tail) {
14780Sstevel@tonic-gate 		uhcip->uhci_bulk_xfers_q_head->prev_qh = UHCI_INVALID_PTR;
14790Sstevel@tonic-gate 	} else if (uhcip->uhci_bulk_xfers_q_head->link_ptr ==
14805773Sqz150045 	    uhcip->uhci_bulk_xfers_q_tail->link_ptr) {
14810Sstevel@tonic-gate 
14820Sstevel@tonic-gate 		/* If there is already a loop, we should keep the loop. */
14830Sstevel@tonic-gate 		qh->link_ptr = uhcip->uhci_bulk_xfers_q_tail->link_ptr;
14840Sstevel@tonic-gate 	}
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	qh->prev_qh = uhcip->uhci_bulk_xfers_q_tail;
14870Sstevel@tonic-gate 	SetQH32(uhcip, uhcip->uhci_bulk_xfers_q_tail->link_ptr,
14885773Sqz150045 	    QH_PADDR(qh) | HC_QUEUE_HEAD);
14890Sstevel@tonic-gate 	uhcip->uhci_bulk_xfers_q_tail = qh;
14900Sstevel@tonic-gate }
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate /*
14940Sstevel@tonic-gate  * uhci_insert_intr_qh:
14950Sstevel@tonic-gate  *	Insert a periodic Queue head i.e Interrupt queue head into the
14960Sstevel@tonic-gate  *	Host Controller's (HC) interrupt lattice tree.
14970Sstevel@tonic-gate  */
14980Sstevel@tonic-gate static void
uhci_insert_intr_qh(uhci_state_t * uhcip,uhci_pipe_private_t * pp)14990Sstevel@tonic-gate uhci_insert_intr_qh(uhci_state_t *uhcip, uhci_pipe_private_t *pp)
15000Sstevel@tonic-gate {
15010Sstevel@tonic-gate 	uint_t		node = pp->pp_node;	/* The appropriate node was */
15020Sstevel@tonic-gate 						/* found during the opening */
15030Sstevel@tonic-gate 						/* of the pipe.  */
15040Sstevel@tonic-gate 	queue_head_t	*qh = pp->pp_qh;
15050Sstevel@tonic-gate 	queue_head_t	*next_lattice_qh, *lattice_qh;
15060Sstevel@tonic-gate 
15070Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
15080Sstevel@tonic-gate 	    "uhci_insert_intr_qh:");
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate 	/* Find the lattice queue head */
15130Sstevel@tonic-gate 	lattice_qh = &uhcip->uhci_qh_pool_addr[node];
15140Sstevel@tonic-gate 	next_lattice_qh =
15150Sstevel@tonic-gate 	    QH_VADDR(GetQH32(uhcip, lattice_qh->link_ptr) & QH_LINK_PTR_MASK);
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 	next_lattice_qh->prev_qh = qh;
15180Sstevel@tonic-gate 	qh->link_ptr	= lattice_qh->link_ptr;
15190Sstevel@tonic-gate 	qh->prev_qh	= lattice_qh;
15200Sstevel@tonic-gate 	SetQH32(uhcip, lattice_qh->link_ptr, QH_PADDR(qh) | HC_QUEUE_HEAD);
15210Sstevel@tonic-gate 	pp->pp_data_toggle = 0;
15220Sstevel@tonic-gate }
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 
15250Sstevel@tonic-gate /*
15260Sstevel@tonic-gate  * uhci_insert_intr_td:
15270Sstevel@tonic-gate  *	Create a TD and a data buffer for an interrupt endpoint.
15280Sstevel@tonic-gate  */
15290Sstevel@tonic-gate int
uhci_insert_intr_td(uhci_state_t * uhcip,usba_pipe_handle_data_t * ph,usb_intr_req_t * req,usb_flags_t flags)15300Sstevel@tonic-gate uhci_insert_intr_td(
15310Sstevel@tonic-gate 	uhci_state_t		*uhcip,
15320Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
15330Sstevel@tonic-gate 	usb_intr_req_t		*req,
15340Sstevel@tonic-gate 	usb_flags_t		flags)
15350Sstevel@tonic-gate {
15360Sstevel@tonic-gate 	int			error, pipe_dir;
15370Sstevel@tonic-gate 	uint_t			length, mps;
15382125Ssl147100 	uint32_t		buf_offs;
15390Sstevel@tonic-gate 	uhci_td_t		*tmp_td;
15400Sstevel@tonic-gate 	usb_intr_req_t		*intr_reqp;
15410Sstevel@tonic-gate 	uhci_pipe_private_t	*pp = (uhci_pipe_private_t *)ph->p_hcd_private;
15420Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw;
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
15456898Sfb209375 	    "uhci_insert_intr_td: req: 0x%p", (void *)req);
15460Sstevel@tonic-gate 
15470Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
15480Sstevel@tonic-gate 
15490Sstevel@tonic-gate 	/* Get the interrupt pipe direction */
15500Sstevel@tonic-gate 	pipe_dir = UHCI_XFER_DIR(&ph->p_ep);
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate 	/* Get the current interrupt request pointer */
15530Sstevel@tonic-gate 	if (req) {
15540Sstevel@tonic-gate 		length = req->intr_len;
15550Sstevel@tonic-gate 	} else {
15560Sstevel@tonic-gate 		ASSERT(pipe_dir == USB_EP_DIR_IN);
1557918Sqz150045 		length = (pp->pp_client_periodic_in_reqp) ?
1558918Sqz150045 		    (((usb_intr_req_t *)pp->
1559918Sqz150045 		    pp_client_periodic_in_reqp)->intr_len) :
1560918Sqz150045 		    ph->p_ep.wMaxPacketSize;
15610Sstevel@tonic-gate 	}
15620Sstevel@tonic-gate 
1563918Sqz150045 	/* Check the size of interrupt request */
1564918Sqz150045 	if (length > UHCI_MAX_TD_XFER_SIZE) {
1565918Sqz150045 
1566918Sqz150045 		/* the length shouldn't exceed 8K */
15670Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
15686898Sfb209375 		    "uhci_insert_intr_td: Intr request size 0x%x is "
15690Sstevel@tonic-gate 		    "more than 0x%x", length, UHCI_MAX_TD_XFER_SIZE);
15700Sstevel@tonic-gate 
15715773Sqz150045 		return (USB_INVALID_REQUEST);
15720Sstevel@tonic-gate 	}
15730Sstevel@tonic-gate 
15740Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
15756898Sfb209375 	    "uhci_insert_intr_td: length: 0x%x", length);
15760Sstevel@tonic-gate 
15770Sstevel@tonic-gate 	/* Allocate a transaction wrapper */
15780Sstevel@tonic-gate 	if ((tw = uhci_create_transfer_wrapper(uhcip, pp, length, flags)) ==
15790Sstevel@tonic-gate 	    NULL) {
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
15820Sstevel@tonic-gate 		    "uhci_insert_intr_td: TW allocation failed");
15830Sstevel@tonic-gate 
15840Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
15850Sstevel@tonic-gate 	}
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate 	/*
15880Sstevel@tonic-gate 	 * Initialize the callback and any callback
15890Sstevel@tonic-gate 	 * data for when the td completes.
15900Sstevel@tonic-gate 	 */
15910Sstevel@tonic-gate 	tw->tw_handle_td = uhci_handle_intr_td;
15920Sstevel@tonic-gate 	tw->tw_handle_callback_value = NULL;
15930Sstevel@tonic-gate 	tw->tw_direction = (pipe_dir == USB_EP_DIR_OUT) ?
15945773Sqz150045 	    PID_OUT : PID_IN;
15950Sstevel@tonic-gate 	tw->tw_curr_xfer_reqp = (usb_opaque_t)req;
15960Sstevel@tonic-gate 
15970Sstevel@tonic-gate 	/*
15980Sstevel@tonic-gate 	 * If it is an Interrupt IN request and interrupt request is NULL,
15990Sstevel@tonic-gate 	 * allocate the usb interrupt request structure for the current
16000Sstevel@tonic-gate 	 * interrupt polling request.
16010Sstevel@tonic-gate 	 */
16020Sstevel@tonic-gate 	if (tw->tw_direction == PID_IN) {
16030Sstevel@tonic-gate 		if ((error = uhci_allocate_periodic_in_resource(uhcip,
16040Sstevel@tonic-gate 		    pp, tw, flags)) != USB_SUCCESS) {
16050Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
16060Sstevel@tonic-gate 			    "uhci_insert_intr_td: Interrupt request structure "
16070Sstevel@tonic-gate 			    "allocation failed");
16080Sstevel@tonic-gate 
16092125Ssl147100 			/* free the transfer wrapper */
16102125Ssl147100 			uhci_deallocate_tw(uhcip, pp, tw);
16112125Ssl147100 
16120Sstevel@tonic-gate 			return (error);
16130Sstevel@tonic-gate 		}
16140Sstevel@tonic-gate 	}
16150Sstevel@tonic-gate 
16160Sstevel@tonic-gate 	intr_reqp = (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
16170Sstevel@tonic-gate 	ASSERT(tw->tw_curr_xfer_reqp != NULL);
16180Sstevel@tonic-gate 
16190Sstevel@tonic-gate 	tw->tw_timeout_cnt = (intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER) ?
16200Sstevel@tonic-gate 	    intr_reqp->intr_timeout : 0;
16210Sstevel@tonic-gate 
16220Sstevel@tonic-gate 	/* DATA IN */
16230Sstevel@tonic-gate 	if (tw->tw_direction == PID_IN) {
16240Sstevel@tonic-gate 		/* Insert the td onto the queue head */
16252125Ssl147100 		error = uhci_insert_hc_td(uhcip, 0,
16265773Sqz150045 		    length, pp, tw, PID_IN, intr_reqp->intr_attributes);
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate 		if (error != USB_SUCCESS) {
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 			uhci_deallocate_periodic_in_resource(uhcip, pp, tw);
16310Sstevel@tonic-gate 			/* free the transfer wrapper */
16320Sstevel@tonic-gate 			uhci_deallocate_tw(uhcip, pp, tw);
16330Sstevel@tonic-gate 
16340Sstevel@tonic-gate 			return (USB_NO_RESOURCES);
16350Sstevel@tonic-gate 		}
16360Sstevel@tonic-gate 		tw->tw_bytes_xfered = 0;
16370Sstevel@tonic-gate 
16380Sstevel@tonic-gate 		return (USB_SUCCESS);
16390Sstevel@tonic-gate 	}
16400Sstevel@tonic-gate 
16412495Sgc161489 	if (req->intr_len) {
16422495Sgc161489 		/* DATA OUT */
16432495Sgc161489 		ASSERT(req->intr_data != NULL);
16442495Sgc161489 
16452495Sgc161489 		/* Copy the data into the message */
16462495Sgc161489 		ddi_rep_put8(tw->tw_accesshandle, req->intr_data->b_rptr,
16475773Sqz150045 		    (uint8_t *)tw->tw_buf, req->intr_len, DDI_DEV_AUTOINCR);
16482495Sgc161489 	}
16490Sstevel@tonic-gate 
16500Sstevel@tonic-gate 	/* set tw->tw_claim flag, so that nobody else works on this tw. */
16510Sstevel@tonic-gate 	tw->tw_claim = UHCI_INTR_HDLR_CLAIMED;
16520Sstevel@tonic-gate 
16530Sstevel@tonic-gate 	mps = ph->p_ep.wMaxPacketSize;
16542125Ssl147100 	buf_offs = 0;
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 	/* Insert tds onto the queue head */
16570Sstevel@tonic-gate 	while (length > 0) {
16580Sstevel@tonic-gate 
16592125Ssl147100 		error = uhci_insert_hc_td(uhcip, buf_offs,
16605773Sqz150045 		    (length > mps) ? mps : length,
16615773Sqz150045 		    pp, tw, PID_OUT,
16625773Sqz150045 		    intr_reqp->intr_attributes);
16630Sstevel@tonic-gate 
16640Sstevel@tonic-gate 		if (error != USB_SUCCESS) {
16650Sstevel@tonic-gate 			/* no resource. */
16660Sstevel@tonic-gate 			break;
16670Sstevel@tonic-gate 		}
16680Sstevel@tonic-gate 
16690Sstevel@tonic-gate 		if (length <= mps) {
16700Sstevel@tonic-gate 			/* inserted all data. */
16710Sstevel@tonic-gate 			length = 0;
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate 		} else {
16740Sstevel@tonic-gate 
16752125Ssl147100 			buf_offs += mps;
16760Sstevel@tonic-gate 			length -= mps;
16770Sstevel@tonic-gate 		}
16780Sstevel@tonic-gate 	}
16790Sstevel@tonic-gate 
16800Sstevel@tonic-gate 	if (error != USB_SUCCESS) {
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl,
16830Sstevel@tonic-gate 		    "uhci_insert_intr_td: allocate td failed, free resource");
16840Sstevel@tonic-gate 
16850Sstevel@tonic-gate 		/* remove all the tds */
16860Sstevel@tonic-gate 		while (tw->tw_hctd_head != NULL) {
16870Sstevel@tonic-gate 			uhci_delete_td(uhcip, tw->tw_hctd_head);
16880Sstevel@tonic-gate 		}
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate 		tw->tw_claim = UHCI_NOT_CLAIMED;
16910Sstevel@tonic-gate 		uhci_deallocate_tw(uhcip, pp, tw);
16920Sstevel@tonic-gate 
16930Sstevel@tonic-gate 		return (error);
16940Sstevel@tonic-gate 	}
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 	/* allow HC to xfer the tds of this tw */
16970Sstevel@tonic-gate 	tmp_td = tw->tw_hctd_head;
16980Sstevel@tonic-gate 	while (tmp_td != NULL) {
16990Sstevel@tonic-gate 
17000Sstevel@tonic-gate 		SetTD_status(uhcip, tmp_td, UHCI_TD_ACTIVE);
17010Sstevel@tonic-gate 		tmp_td = tmp_td->tw_td_next;
17020Sstevel@tonic-gate 	}
17030Sstevel@tonic-gate 
17040Sstevel@tonic-gate 	tw->tw_bytes_xfered = 0;
17050Sstevel@tonic-gate 	tw->tw_claim = UHCI_NOT_CLAIMED;
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate 	return (error);
17080Sstevel@tonic-gate }
17090Sstevel@tonic-gate 
17100Sstevel@tonic-gate 
17110Sstevel@tonic-gate /*
17120Sstevel@tonic-gate  * uhci_create_transfer_wrapper:
17132125Ssl147100  *	Create a Transaction Wrapper (TW) for non-isoc transfer types.
17140Sstevel@tonic-gate  *	This involves the allocating of DMA resources.
17152125Ssl147100  *
17162125Ssl147100  *	For non-isoc transfers, one DMA handle and one DMA buffer are
17172125Ssl147100  *	allocated per transfer. The DMA buffer may contain multiple
17182125Ssl147100  *	DMA cookies and the cookies should meet certain alignment
17192125Ssl147100  *	requirement to be able to fit in the multiple TDs. The alignment
17202125Ssl147100  *	needs to ensure:
17212125Ssl147100  *	1. the size of a cookie be larger than max TD length (0x500)
17222125Ssl147100  *	2. the size of a cookie be a multiple of wMaxPacketSize of the
17232125Ssl147100  *	ctrl/bulk pipes
17242125Ssl147100  *
17252125Ssl147100  *	wMaxPacketSize for ctrl and bulk pipes may be 8, 16, 32 or 64 bytes.
17262125Ssl147100  *	So the alignment should be a multiple of 64. wMaxPacketSize for intr
17272125Ssl147100  *	pipes is a little different since it only specifies the max to be
17282125Ssl147100  *	64 bytes, but as long as an intr transfer is limited to max TD length,
17292125Ssl147100  *	any alignment can work if the cookie size is larger than max TD length.
17302125Ssl147100  *
17312125Ssl147100  *	Considering the above conditions, 2K alignment is used. 4K alignment
17322125Ssl147100  *	should also be fine.
17330Sstevel@tonic-gate  */
17340Sstevel@tonic-gate static uhci_trans_wrapper_t *
uhci_create_transfer_wrapper(uhci_state_t * uhcip,uhci_pipe_private_t * pp,size_t length,usb_flags_t usb_flags)17350Sstevel@tonic-gate uhci_create_transfer_wrapper(
17360Sstevel@tonic-gate 	uhci_state_t		*uhcip,
17370Sstevel@tonic-gate 	uhci_pipe_private_t	*pp,
17380Sstevel@tonic-gate 	size_t			length,
17390Sstevel@tonic-gate 	usb_flags_t		usb_flags)
17400Sstevel@tonic-gate {
17410Sstevel@tonic-gate 	size_t			real_length;
17420Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw;
17430Sstevel@tonic-gate 	ddi_device_acc_attr_t	dev_attr;
17442125Ssl147100 	ddi_dma_attr_t		dma_attr;
17452125Ssl147100 	int			kmem_flag;
17462125Ssl147100 	int			(*dmamem_wait)(caddr_t);
17472125Ssl147100 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
17500Sstevel@tonic-gate 	    "uhci_create_transfer_wrapper: length = 0x%lx flags = 0x%x",
17510Sstevel@tonic-gate 	    length, usb_flags);
17520Sstevel@tonic-gate 
17530Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
17540Sstevel@tonic-gate 
17552125Ssl147100 	/* isochronous pipe should not call into this function */
17562125Ssl147100 	if (UHCI_XFER_TYPE(&ph->p_ep) == USB_EP_ATTR_ISOCH) {
17572125Ssl147100 
17582125Ssl147100 		return (NULL);
17592125Ssl147100 	}
17602125Ssl147100 
17619072SZhigang.Lu@Sun.COM 	/* SLEEP flag should not be used while holding mutex */
17629072SZhigang.Lu@Sun.COM 	kmem_flag = KM_NOSLEEP;
17639072SZhigang.Lu@Sun.COM 	dmamem_wait = DDI_DMA_DONTWAIT;
17642125Ssl147100 
17650Sstevel@tonic-gate 	/* Allocate space for the transfer wrapper */
17662125Ssl147100 	if ((tw = kmem_zalloc(sizeof (uhci_trans_wrapper_t), kmem_flag)) ==
17670Sstevel@tonic-gate 	    NULL) {
17680Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS,  uhcip->uhci_log_hdl,
17690Sstevel@tonic-gate 		    "uhci_create_transfer_wrapper: kmem_alloc failed");
17700Sstevel@tonic-gate 
17710Sstevel@tonic-gate 		return (NULL);
17720Sstevel@tonic-gate 	}
17730Sstevel@tonic-gate 
17742495Sgc161489 	/* zero-length packet doesn't need to allocate dma memory */
17752495Sgc161489 	if (length == 0) {
17762495Sgc161489 
17772495Sgc161489 		goto dmadone;
17782495Sgc161489 	}
17792495Sgc161489 
17802125Ssl147100 	/* allow sg lists for transfer wrapper dma memory */
17812125Ssl147100 	bcopy(&uhcip->uhci_dma_attr, &dma_attr, sizeof (ddi_dma_attr_t));
17822125Ssl147100 	dma_attr.dma_attr_sgllen = UHCI_DMA_ATTR_SGLLEN;
17832125Ssl147100 	dma_attr.dma_attr_align = UHCI_DMA_ATTR_ALIGN;
17842125Ssl147100 
17850Sstevel@tonic-gate 	/* Store the transfer length */
17860Sstevel@tonic-gate 	tw->tw_length = length;
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 	/* Allocate the DMA handle */
17892125Ssl147100 	if (ddi_dma_alloc_handle(uhcip->uhci_dip, &dma_attr, dmamem_wait,
17902125Ssl147100 	    0, &tw->tw_dmahandle) != DDI_SUCCESS) {
17910Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
17920Sstevel@tonic-gate 		    "uhci_create_transfer_wrapper: Alloc handle failed");
17930Sstevel@tonic-gate 		kmem_free(tw, sizeof (uhci_trans_wrapper_t));
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 		return (NULL);
17960Sstevel@tonic-gate 	}
17970Sstevel@tonic-gate 
17980Sstevel@tonic-gate 	dev_attr.devacc_attr_version		= DDI_DEVICE_ATTR_V0;
17990Sstevel@tonic-gate 	dev_attr.devacc_attr_endian_flags	= DDI_STRUCTURE_LE_ACC;
18000Sstevel@tonic-gate 	dev_attr.devacc_attr_dataorder		= DDI_STRICTORDER_ACC;
18010Sstevel@tonic-gate 
18020Sstevel@tonic-gate 	/* Allocate the memory */
18032125Ssl147100 	if (ddi_dma_mem_alloc(tw->tw_dmahandle, tw->tw_length, &dev_attr,
18042125Ssl147100 	    DDI_DMA_CONSISTENT, dmamem_wait, NULL, (caddr_t *)&tw->tw_buf,
18052125Ssl147100 	    &real_length, &tw->tw_accesshandle) != DDI_SUCCESS) {
18060Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
18070Sstevel@tonic-gate 		    "uhci_create_transfer_wrapper: dma_mem_alloc fail");
18080Sstevel@tonic-gate 		ddi_dma_free_handle(&tw->tw_dmahandle);
18090Sstevel@tonic-gate 		kmem_free(tw, sizeof (uhci_trans_wrapper_t));
18100Sstevel@tonic-gate 
18110Sstevel@tonic-gate 		return (NULL);
18120Sstevel@tonic-gate 	}
18130Sstevel@tonic-gate 
18140Sstevel@tonic-gate 	ASSERT(real_length >= length);
18150Sstevel@tonic-gate 
18160Sstevel@tonic-gate 	/* Bind the handle */
18172125Ssl147100 	if (ddi_dma_addr_bind_handle(tw->tw_dmahandle, NULL,
18180Sstevel@tonic-gate 	    (caddr_t)tw->tw_buf, real_length, DDI_DMA_RDWR|DDI_DMA_CONSISTENT,
18192125Ssl147100 	    dmamem_wait, NULL, &tw->tw_cookie, &tw->tw_ncookies) !=
18200Sstevel@tonic-gate 	    DDI_DMA_MAPPED) {
18210Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
18220Sstevel@tonic-gate 		    "uhci_create_transfer_wrapper: Bind handle failed");
18230Sstevel@tonic-gate 		ddi_dma_mem_free(&tw->tw_accesshandle);
18240Sstevel@tonic-gate 		ddi_dma_free_handle(&tw->tw_dmahandle);
18250Sstevel@tonic-gate 		kmem_free(tw, sizeof (uhci_trans_wrapper_t));
18260Sstevel@tonic-gate 
18270Sstevel@tonic-gate 		return (NULL);
18280Sstevel@tonic-gate 	}
18290Sstevel@tonic-gate 
18302125Ssl147100 	tw->tw_cookie_idx = 0;
18312125Ssl147100 	tw->tw_dma_offs = 0;
18320Sstevel@tonic-gate 
18332495Sgc161489 dmadone:
18340Sstevel@tonic-gate 	/*
18350Sstevel@tonic-gate 	 * Only allow one wrapper to be added at a time. Insert the
18360Sstevel@tonic-gate 	 * new transaction wrapper into the list for this pipe.
18370Sstevel@tonic-gate 	 */
18380Sstevel@tonic-gate 	if (pp->pp_tw_head == NULL) {
18390Sstevel@tonic-gate 		pp->pp_tw_head = tw;
18400Sstevel@tonic-gate 		pp->pp_tw_tail = tw;
18410Sstevel@tonic-gate 	} else {
18420Sstevel@tonic-gate 		pp->pp_tw_tail->tw_next = tw;
18430Sstevel@tonic-gate 		pp->pp_tw_tail = tw;
18440Sstevel@tonic-gate 		ASSERT(tw->tw_next == NULL);
18450Sstevel@tonic-gate 	}
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate 	/* Store a back pointer to the pipe private structure */
18480Sstevel@tonic-gate 	tw->tw_pipe_private = pp;
18490Sstevel@tonic-gate 
18500Sstevel@tonic-gate 	/* Store the transfer type - synchronous or asynchronous */
18510Sstevel@tonic-gate 	tw->tw_flags = usb_flags;
18520Sstevel@tonic-gate 
18532125Ssl147100 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
18542125Ssl147100 	    "uhci_create_transfer_wrapper: tw = 0x%p, ncookies = %u",
18556898Sfb209375 	    (void *)tw, tw->tw_ncookies);
18562125Ssl147100 
18570Sstevel@tonic-gate 	return (tw);
18580Sstevel@tonic-gate }
18590Sstevel@tonic-gate 
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate /*
18620Sstevel@tonic-gate  * uhci_insert_hc_td:
18630Sstevel@tonic-gate  *	Insert a Transfer Descriptor (TD) on an QH.
18640Sstevel@tonic-gate  */
18650Sstevel@tonic-gate int
uhci_insert_hc_td(uhci_state_t * uhcip,uint32_t buffer_offset,size_t hcgtd_length,uhci_pipe_private_t * pp,uhci_trans_wrapper_t * tw,uchar_t PID,usb_req_attrs_t attrs)18660Sstevel@tonic-gate uhci_insert_hc_td(
18670Sstevel@tonic-gate 	uhci_state_t		*uhcip,
18682125Ssl147100 	uint32_t		buffer_offset,
18690Sstevel@tonic-gate 	size_t			hcgtd_length,
18700Sstevel@tonic-gate 	uhci_pipe_private_t	*pp,
18710Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw,
18720Sstevel@tonic-gate 	uchar_t			PID,
18730Sstevel@tonic-gate 	usb_req_attrs_t		attrs)
18740Sstevel@tonic-gate {
18750Sstevel@tonic-gate 	uhci_td_t	*td, *current_dummy;
18760Sstevel@tonic-gate 	queue_head_t	*qh = pp->pp_qh;
18770Sstevel@tonic-gate 
18780Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
18790Sstevel@tonic-gate 
18800Sstevel@tonic-gate 	if ((td = uhci_allocate_td_from_pool(uhcip)) == NULL) {
18810Sstevel@tonic-gate 
18820Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
18830Sstevel@tonic-gate 	}
18840Sstevel@tonic-gate 
18850Sstevel@tonic-gate 	current_dummy = qh->td_tailp;
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl,
18886898Sfb209375 	    "uhci_insert_hc_td: td %p, attrs = 0x%x", (void *)td, attrs);
18890Sstevel@tonic-gate 
18900Sstevel@tonic-gate 	/*
18910Sstevel@tonic-gate 	 * Fill in the current dummy td and
18920Sstevel@tonic-gate 	 * add the new dummy to the end.
18930Sstevel@tonic-gate 	 */
18942125Ssl147100 	uhci_fill_in_td(uhcip, td, current_dummy, buffer_offset,
18952125Ssl147100 	    hcgtd_length, pp, PID, attrs, tw);
18960Sstevel@tonic-gate 
18970Sstevel@tonic-gate 	/*
18980Sstevel@tonic-gate 	 * Allow HC hardware xfer the td, except interrupt out td.
18990Sstevel@tonic-gate 	 */
19000Sstevel@tonic-gate 	if ((tw->tw_handle_td != uhci_handle_intr_td) || (PID != PID_OUT)) {
19010Sstevel@tonic-gate 
19020Sstevel@tonic-gate 		SetTD_status(uhcip, current_dummy, UHCI_TD_ACTIVE);
19030Sstevel@tonic-gate 	}
19040Sstevel@tonic-gate 
19050Sstevel@tonic-gate 	/* Insert this td onto the tw */
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate 	if (tw->tw_hctd_head == NULL) {
19080Sstevel@tonic-gate 		ASSERT(tw->tw_hctd_tail == NULL);
19090Sstevel@tonic-gate 		tw->tw_hctd_head = current_dummy;
19100Sstevel@tonic-gate 		tw->tw_hctd_tail = current_dummy;
19110Sstevel@tonic-gate 	} else {
19120Sstevel@tonic-gate 		/* Add the td to the end of the list */
19130Sstevel@tonic-gate 		tw->tw_hctd_tail->tw_td_next = current_dummy;
19140Sstevel@tonic-gate 		tw->tw_hctd_tail = current_dummy;
19150Sstevel@tonic-gate 	}
19160Sstevel@tonic-gate 
19170Sstevel@tonic-gate 	/*
19180Sstevel@tonic-gate 	 * Insert the TD on to the QH. When this occurs,
19190Sstevel@tonic-gate 	 * the Host Controller will see the newly filled in TD
19200Sstevel@tonic-gate 	 */
19210Sstevel@tonic-gate 	current_dummy->outst_td_next	 = NULL;
19220Sstevel@tonic-gate 	current_dummy->outst_td_prev	 = uhcip->uhci_outst_tds_tail;
19230Sstevel@tonic-gate 	if (uhcip->uhci_outst_tds_head == NULL) {
19240Sstevel@tonic-gate 		uhcip->uhci_outst_tds_head = current_dummy;
19250Sstevel@tonic-gate 	} else {
19260Sstevel@tonic-gate 		uhcip->uhci_outst_tds_tail->outst_td_next = current_dummy;
19270Sstevel@tonic-gate 	}
19280Sstevel@tonic-gate 	uhcip->uhci_outst_tds_tail = current_dummy;
19290Sstevel@tonic-gate 	current_dummy->tw = tw;
19300Sstevel@tonic-gate 
19310Sstevel@tonic-gate 	return (USB_SUCCESS);
19320Sstevel@tonic-gate }
19330Sstevel@tonic-gate 
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate /*
19360Sstevel@tonic-gate  * uhci_fill_in_td:
19370Sstevel@tonic-gate  *	Fill in the fields of a Transfer Descriptor (TD).
19380Sstevel@tonic-gate  */
19390Sstevel@tonic-gate static void
uhci_fill_in_td(uhci_state_t * uhcip,uhci_td_t * td,uhci_td_t * current_dummy,uint32_t buffer_offset,size_t length,uhci_pipe_private_t * pp,uchar_t PID,usb_req_attrs_t attrs,uhci_trans_wrapper_t * tw)19400Sstevel@tonic-gate uhci_fill_in_td(
19410Sstevel@tonic-gate 	uhci_state_t		*uhcip,
19420Sstevel@tonic-gate 	uhci_td_t		*td,
19430Sstevel@tonic-gate 	uhci_td_t		*current_dummy,
19442125Ssl147100 	uint32_t		buffer_offset,
19450Sstevel@tonic-gate 	size_t			length,
19460Sstevel@tonic-gate 	uhci_pipe_private_t	*pp,
19470Sstevel@tonic-gate 	uchar_t			PID,
19482125Ssl147100 	usb_req_attrs_t		attrs,
19492125Ssl147100 	uhci_trans_wrapper_t	*tw)
19500Sstevel@tonic-gate {
19510Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
19522125Ssl147100 	uint32_t		buf_addr;
19530Sstevel@tonic-gate 
19540Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl,
19552125Ssl147100 	    "uhci_fill_in_td: td 0x%p buf_offs 0x%x len 0x%lx "
19566898Sfb209375 	    "attrs 0x%x", (void *)td, buffer_offset, length, attrs);
19570Sstevel@tonic-gate 
19580Sstevel@tonic-gate 	/*
19590Sstevel@tonic-gate 	 * If this is an isochronous TD, just return
19600Sstevel@tonic-gate 	 */
19610Sstevel@tonic-gate 	if (UHCI_XFER_TYPE(&ph->p_ep) == USB_EP_ATTR_ISOCH) {
19620Sstevel@tonic-gate 
19630Sstevel@tonic-gate 		return;
19640Sstevel@tonic-gate 	}
19650Sstevel@tonic-gate 
19662125Ssl147100 	/* The maximum transfer length of UHCI cannot exceed 0x500 bytes */
19672125Ssl147100 	ASSERT(length <= UHCI_MAX_TD_XFER_SIZE);
19682125Ssl147100 
19690Sstevel@tonic-gate 	bzero((char *)td, sizeof (uhci_td_t));	/* Clear the TD */
19700Sstevel@tonic-gate 	SetTD32(uhcip, current_dummy->link_ptr, TD_PADDR(td));
19710Sstevel@tonic-gate 
19720Sstevel@tonic-gate 	if (attrs & USB_ATTRS_SHORT_XFER_OK) {
19730Sstevel@tonic-gate 		SetTD_spd(uhcip, current_dummy, 1);
19740Sstevel@tonic-gate 	}
19750Sstevel@tonic-gate 
19760Sstevel@tonic-gate 	mutex_enter(&ph->p_usba_device->usb_mutex);
19770Sstevel@tonic-gate 	if (ph->p_usba_device->usb_port_status == USBA_LOW_SPEED_DEV) {
19780Sstevel@tonic-gate 		SetTD_ls(uhcip, current_dummy, LOW_SPEED_DEVICE);
19790Sstevel@tonic-gate 	}
19800Sstevel@tonic-gate 
19810Sstevel@tonic-gate 	SetTD_c_err(uhcip, current_dummy, UHCI_MAX_ERR_COUNT);
19822495Sgc161489 	SetTD_mlen(uhcip, current_dummy,
19835773Sqz150045 	    (length == 0) ? ZERO_LENGTH : (length - 1));
19840Sstevel@tonic-gate 	SetTD_dtogg(uhcip, current_dummy, pp->pp_data_toggle);
19850Sstevel@tonic-gate 
19860Sstevel@tonic-gate 	/* Adjust the data toggle bit */
19870Sstevel@tonic-gate 	ADJ_DATA_TOGGLE(pp);
19880Sstevel@tonic-gate 
19890Sstevel@tonic-gate 	SetTD_devaddr(uhcip, current_dummy,  ph->p_usba_device->usb_addr);
19900Sstevel@tonic-gate 	SetTD_endpt(uhcip, current_dummy,
19915773Sqz150045 	    ph->p_ep.bEndpointAddress & END_POINT_ADDRESS_MASK);
19920Sstevel@tonic-gate 	SetTD_PID(uhcip, current_dummy, PID);
19930Sstevel@tonic-gate 	SetTD_ioc(uhcip, current_dummy, INTERRUPT_ON_COMPLETION);
19940Sstevel@tonic-gate 
19952125Ssl147100 	buf_addr = uhci_get_tw_paddr_by_offs(uhcip, buffer_offset, length, tw);
19962125Ssl147100 	SetTD32(uhcip, current_dummy->buffer_address, buf_addr);
19972125Ssl147100 
19980Sstevel@tonic-gate 	td->qh_td_prev			= current_dummy;
19990Sstevel@tonic-gate 	current_dummy->qh_td_prev	= NULL;
20000Sstevel@tonic-gate 	pp->pp_qh->td_tailp		= td;
20010Sstevel@tonic-gate 	mutex_exit(&ph->p_usba_device->usb_mutex);
20020Sstevel@tonic-gate }
20030Sstevel@tonic-gate 
20042125Ssl147100 /*
20052125Ssl147100  * uhci_get_tw_paddr_by_offs:
20062125Ssl147100  *	Walk through the DMA cookies of a TW buffer to retrieve
20072125Ssl147100  *	the device address used for a TD.
20082125Ssl147100  *
20092125Ssl147100  * buffer_offset - the starting offset into the TW buffer, where the
20105773Sqz150045  *		   TD should transfer from. When a TW has more than
20115773Sqz150045  *		   one TD, the TDs must be filled in increasing order.
20122125Ssl147100  */
20132125Ssl147100 static uint32_t
uhci_get_tw_paddr_by_offs(uhci_state_t * uhcip,uint32_t buffer_offset,size_t length,uhci_trans_wrapper_t * tw)20142125Ssl147100 uhci_get_tw_paddr_by_offs(
20152125Ssl147100 	uhci_state_t		*uhcip,
20162125Ssl147100 	uint32_t		buffer_offset,
20172125Ssl147100 	size_t			length,
20182125Ssl147100 	uhci_trans_wrapper_t	*tw)
20192125Ssl147100 {
20202125Ssl147100 	uint32_t		buf_addr;
20212125Ssl147100 	int			rem_len;
20222125Ssl147100 
20232125Ssl147100 	USB_DPRINTF_L4(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl,
20242125Ssl147100 	    "uhci_get_tw_paddr_by_offs: buf_offs 0x%x len 0x%lx",
20252125Ssl147100 	    buffer_offset, length);
20262125Ssl147100 
20272125Ssl147100 	/*
20282125Ssl147100 	 * TDs must be filled in increasing DMA offset order.
20292125Ssl147100 	 * tw_dma_offs is initialized to be 0 at TW creation and
20302125Ssl147100 	 * is only increased in this function.
20312125Ssl147100 	 */
20322125Ssl147100 	ASSERT(length == 0 || buffer_offset >= tw->tw_dma_offs);
20332125Ssl147100 
20342125Ssl147100 	if (length == 0) {
20352125Ssl147100 		buf_addr = 0;
20362125Ssl147100 
20372125Ssl147100 		return (buf_addr);
20382125Ssl147100 	}
20392125Ssl147100 
20402125Ssl147100 	/*
20412125Ssl147100 	 * Advance to the next DMA cookie until finding the cookie
20422125Ssl147100 	 * that buffer_offset falls in.
20432125Ssl147100 	 * It is very likely this loop will never repeat more than
20442125Ssl147100 	 * once. It is here just to accommodate the case buffer_offset
20452125Ssl147100 	 * is increased by multiple cookies during two consecutive
20462125Ssl147100 	 * calls into this function. In that case, the interim DMA
20472125Ssl147100 	 * buffer is allowed to be skipped.
20482125Ssl147100 	 */
20492125Ssl147100 	while ((tw->tw_dma_offs + tw->tw_cookie.dmac_size) <=
20502125Ssl147100 	    buffer_offset) {
20512125Ssl147100 		/*
20522125Ssl147100 		 * tw_dma_offs always points to the starting offset
20532125Ssl147100 		 * of a cookie
20542125Ssl147100 		 */
20552125Ssl147100 		tw->tw_dma_offs += tw->tw_cookie.dmac_size;
20562125Ssl147100 		ddi_dma_nextcookie(tw->tw_dmahandle, &tw->tw_cookie);
20572125Ssl147100 		tw->tw_cookie_idx++;
20582125Ssl147100 		ASSERT(tw->tw_cookie_idx < tw->tw_ncookies);
20592125Ssl147100 	}
20602125Ssl147100 
20612125Ssl147100 	/*
20622125Ssl147100 	 * Counting the remained buffer length to be filled in
20632125Ssl147100 	 * the TDs for current DMA cookie
20642125Ssl147100 	 */
20652125Ssl147100 	rem_len = (tw->tw_dma_offs + tw->tw_cookie.dmac_size) -
20662125Ssl147100 	    buffer_offset;
20672125Ssl147100 
20682125Ssl147100 	/* Calculate the beginning address of the buffer */
20692125Ssl147100 	ASSERT(length <= rem_len);
20702125Ssl147100 	buf_addr = (buffer_offset - tw->tw_dma_offs) +
20712125Ssl147100 	    tw->tw_cookie.dmac_address;
20722125Ssl147100 
20732125Ssl147100 	USB_DPRINTF_L3(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl,
20746898Sfb209375 	    "uhci_get_tw_paddr_by_offs: dmac_addr 0x%x dmac_size "
20752125Ssl147100 	    "0x%lx idx %d", buf_addr, tw->tw_cookie.dmac_size,
20762125Ssl147100 	    tw->tw_cookie_idx);
20772125Ssl147100 
20782125Ssl147100 	return (buf_addr);
20792125Ssl147100 }
20802125Ssl147100 
20810Sstevel@tonic-gate 
20820Sstevel@tonic-gate /*
20830Sstevel@tonic-gate  * uhci_modify_td_active_bits:
20840Sstevel@tonic-gate  *	Sets active bit in all the tds of QH to INACTIVE so that
20850Sstevel@tonic-gate  *	the HC stops processing the TD's related to the QH.
20860Sstevel@tonic-gate  */
20870Sstevel@tonic-gate void
uhci_modify_td_active_bits(uhci_state_t * uhcip,uhci_pipe_private_t * pp)20880Sstevel@tonic-gate uhci_modify_td_active_bits(
20890Sstevel@tonic-gate 	uhci_state_t		*uhcip,
20900Sstevel@tonic-gate 	uhci_pipe_private_t	*pp)
20910Sstevel@tonic-gate {
20920Sstevel@tonic-gate 	uhci_td_t		*td_head;
20930Sstevel@tonic-gate 	usb_ep_descr_t		*ept = &pp->pp_pipe_handle->p_ep;
20940Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw_head = pp->pp_tw_head;
20950Sstevel@tonic-gate 
20960Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl,
20970Sstevel@tonic-gate 	    "uhci_modify_td_active_bits: tw head %p", (void *)tw_head);
20980Sstevel@tonic-gate 
20990Sstevel@tonic-gate 	while (tw_head != NULL) {
21000Sstevel@tonic-gate 		tw_head->tw_claim = UHCI_MODIFY_TD_BITS_CLAIMED;
21010Sstevel@tonic-gate 		td_head = tw_head->tw_hctd_head;
21020Sstevel@tonic-gate 
21030Sstevel@tonic-gate 		while (td_head) {
21040Sstevel@tonic-gate 			if (UHCI_XFER_TYPE(ept) == USB_EP_ATTR_ISOCH) {
21050Sstevel@tonic-gate 				SetTD_status(uhcip, td_head,
21060Sstevel@tonic-gate 				    GetTD_status(uhcip, td_head) & TD_INACTIVE);
21070Sstevel@tonic-gate 			} else {
21080Sstevel@tonic-gate 				SetTD32(uhcip, td_head->link_ptr,
21090Sstevel@tonic-gate 				    GetTD32(uhcip, td_head->link_ptr) |
21100Sstevel@tonic-gate 				    HC_END_OF_LIST);
21110Sstevel@tonic-gate 			}
21120Sstevel@tonic-gate 
21130Sstevel@tonic-gate 			td_head = td_head->tw_td_next;
21140Sstevel@tonic-gate 		}
21150Sstevel@tonic-gate 		tw_head = tw_head->tw_next;
21160Sstevel@tonic-gate 	}
21170Sstevel@tonic-gate }
21180Sstevel@tonic-gate 
21190Sstevel@tonic-gate 
21200Sstevel@tonic-gate /*
21210Sstevel@tonic-gate  * uhci_insert_ctrl_td:
21220Sstevel@tonic-gate  *	Create a TD and a data buffer for a control Queue Head.
21230Sstevel@tonic-gate  */
21240Sstevel@tonic-gate int
uhci_insert_ctrl_td(uhci_state_t * uhcip,usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp,usb_flags_t flags)21250Sstevel@tonic-gate uhci_insert_ctrl_td(
21260Sstevel@tonic-gate 	uhci_state_t		*uhcip,
21270Sstevel@tonic-gate 	usba_pipe_handle_data_t  *ph,
21280Sstevel@tonic-gate 	usb_ctrl_req_t		*ctrl_reqp,
21290Sstevel@tonic-gate 	usb_flags_t		flags)
21300Sstevel@tonic-gate {
21310Sstevel@tonic-gate 	uhci_pipe_private_t  *pp = (uhci_pipe_private_t *)ph->p_hcd_private;
21320Sstevel@tonic-gate 	uhci_trans_wrapper_t *tw;
21332125Ssl147100 	size_t	ctrl_buf_size;
21340Sstevel@tonic-gate 
21350Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
21360Sstevel@tonic-gate 	    "uhci_insert_ctrl_td: timeout: 0x%x", ctrl_reqp->ctrl_timeout);
21370Sstevel@tonic-gate 
21380Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
21390Sstevel@tonic-gate 
21402125Ssl147100 	/*
21412125Ssl147100 	 * If we have a control data phase, make the data buffer start
21422125Ssl147100 	 * on the next 64-byte boundary so as to ensure the DMA cookie
21432125Ssl147100 	 * can fit in the multiple TDs. The buffer in the range of
21442125Ssl147100 	 * [SETUP_SIZE, UHCI_CTRL_EPT_MAX_SIZE) is just for padding
21452125Ssl147100 	 * and not to be transferred.
21462125Ssl147100 	 */
21472125Ssl147100 	if (ctrl_reqp->ctrl_wLength) {
21482125Ssl147100 		ctrl_buf_size = UHCI_CTRL_EPT_MAX_SIZE +
21492125Ssl147100 		    ctrl_reqp->ctrl_wLength;
21502125Ssl147100 	} else {
21512125Ssl147100 		ctrl_buf_size = SETUP_SIZE;
21522125Ssl147100 	}
21532125Ssl147100 
21540Sstevel@tonic-gate 	/* Allocate a transaction wrapper */
21550Sstevel@tonic-gate 	if ((tw = uhci_create_transfer_wrapper(uhcip, pp,
21562125Ssl147100 	    ctrl_buf_size, flags)) == NULL) {
21570Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
21580Sstevel@tonic-gate 		    "uhci_insert_ctrl_td: TW allocation failed");
21590Sstevel@tonic-gate 
21600Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
21610Sstevel@tonic-gate 	}
21620Sstevel@tonic-gate 
21630Sstevel@tonic-gate 	pp->pp_data_toggle = 0;
21640Sstevel@tonic-gate 
21650Sstevel@tonic-gate 	tw->tw_curr_xfer_reqp = (usb_opaque_t)ctrl_reqp;
21660Sstevel@tonic-gate 	tw->tw_bytes_xfered = 0;
21670Sstevel@tonic-gate 	tw->tw_bytes_pending = ctrl_reqp->ctrl_wLength;
21680Sstevel@tonic-gate 	tw->tw_timeout_cnt = max(UHCI_CTRL_TIMEOUT, ctrl_reqp->ctrl_timeout);
21690Sstevel@tonic-gate 
21700Sstevel@tonic-gate 	/*
21710Sstevel@tonic-gate 	 * Initialize the callback and any callback
21720Sstevel@tonic-gate 	 * data for when the td completes.
21730Sstevel@tonic-gate 	 */
21740Sstevel@tonic-gate 	tw->tw_handle_td = uhci_handle_ctrl_td;
21750Sstevel@tonic-gate 	tw->tw_handle_callback_value = NULL;
21760Sstevel@tonic-gate 
21770Sstevel@tonic-gate 	if ((uhci_create_setup_pkt(uhcip, pp, tw)) != USB_SUCCESS) {
21780Sstevel@tonic-gate 		tw->tw_ctrl_state = 0;
21790Sstevel@tonic-gate 
21800Sstevel@tonic-gate 		/* free the transfer wrapper */
21810Sstevel@tonic-gate 		uhci_deallocate_tw(uhcip, pp, tw);
21820Sstevel@tonic-gate 
21830Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
21840Sstevel@tonic-gate 	}
21850Sstevel@tonic-gate 
21860Sstevel@tonic-gate 	tw->tw_ctrl_state = SETUP;
21870Sstevel@tonic-gate 
21880Sstevel@tonic-gate 	return (USB_SUCCESS);
21890Sstevel@tonic-gate }
21900Sstevel@tonic-gate 
21910Sstevel@tonic-gate 
21920Sstevel@tonic-gate /*
21930Sstevel@tonic-gate  * uhci_create_setup_pkt:
21940Sstevel@tonic-gate  *	create a setup packet to initiate a control transfer.
21950Sstevel@tonic-gate  *
21960Sstevel@tonic-gate  *	OHCI driver has seen the case where devices fail if there is
21970Sstevel@tonic-gate  *	more than one control transfer to the device within a frame.
21980Sstevel@tonic-gate  *	So, the UHCI ensures that only one TD will be put on the control
21990Sstevel@tonic-gate  *	pipe to one device (to be consistent with OHCI driver).
22000Sstevel@tonic-gate  */
22010Sstevel@tonic-gate static int
uhci_create_setup_pkt(uhci_state_t * uhcip,uhci_pipe_private_t * pp,uhci_trans_wrapper_t * tw)22020Sstevel@tonic-gate uhci_create_setup_pkt(
22030Sstevel@tonic-gate 	uhci_state_t		*uhcip,
22040Sstevel@tonic-gate 	uhci_pipe_private_t	*pp,
22050Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw)
22060Sstevel@tonic-gate {
22070Sstevel@tonic-gate 	int		sdata;
22080Sstevel@tonic-gate 	usb_ctrl_req_t	*req = (usb_ctrl_req_t *)tw->tw_curr_xfer_reqp;
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl,
22110Sstevel@tonic-gate 	    "uhci_create_setup_pkt: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%p",
22120Sstevel@tonic-gate 	    req->ctrl_bmRequestType, req->ctrl_bRequest, req->ctrl_wValue,
22130Sstevel@tonic-gate 	    req->ctrl_wIndex, req->ctrl_wLength, (void *)req->ctrl_data);
22140Sstevel@tonic-gate 
22150Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
22160Sstevel@tonic-gate 	ASSERT(tw != NULL);
22170Sstevel@tonic-gate 
22180Sstevel@tonic-gate 	/* Create the first four bytes of the setup packet */
22190Sstevel@tonic-gate 	sdata = (req->ctrl_bmRequestType | (req->ctrl_bRequest << 8) |
22205773Sqz150045 	    (req->ctrl_wValue << 16));
22210Sstevel@tonic-gate 	ddi_put32(tw->tw_accesshandle, (uint_t *)tw->tw_buf, sdata);
22220Sstevel@tonic-gate 
22230Sstevel@tonic-gate 	/* Create the second four bytes */
22240Sstevel@tonic-gate 	sdata = (uint32_t)(req->ctrl_wIndex | (req->ctrl_wLength << 16));
22250Sstevel@tonic-gate 	ddi_put32(tw->tw_accesshandle,
22260Sstevel@tonic-gate 	    (uint_t *)(tw->tw_buf + sizeof (uint_t)), sdata);
22270Sstevel@tonic-gate 
22280Sstevel@tonic-gate 	/*
22290Sstevel@tonic-gate 	 * The TD's are placed on the QH one at a time.
22300Sstevel@tonic-gate 	 * Once this TD is placed on the done list, the
22310Sstevel@tonic-gate 	 * data or status phase TD will be enqueued.
22320Sstevel@tonic-gate 	 */
22332125Ssl147100 	if ((uhci_insert_hc_td(uhcip, 0, SETUP_SIZE,
22340Sstevel@tonic-gate 	    pp, tw, PID_SETUP, req->ctrl_attributes)) != USB_SUCCESS) {
22350Sstevel@tonic-gate 
22360Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
22370Sstevel@tonic-gate 	}
22380Sstevel@tonic-gate 
22390Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl,
22406898Sfb209375 	    "Create_setup: pp = 0x%p, attrs = 0x%x", (void *)pp,
22416898Sfb209375 	    req->ctrl_attributes);
22420Sstevel@tonic-gate 
22430Sstevel@tonic-gate 	/*
22440Sstevel@tonic-gate 	 * If this control transfer has a data phase, record the
22450Sstevel@tonic-gate 	 * direction. If the data phase is an OUT transaction ,
22460Sstevel@tonic-gate 	 * copy the data into the buffer of the transfer wrapper.
22470Sstevel@tonic-gate 	 */
22480Sstevel@tonic-gate 	if (req->ctrl_wLength != 0) {
22490Sstevel@tonic-gate 		/* There is a data stage.  Find the direction */
22500Sstevel@tonic-gate 		if (req->ctrl_bmRequestType & USB_DEV_REQ_DEV_TO_HOST) {
22510Sstevel@tonic-gate 			tw->tw_direction = PID_IN;
22520Sstevel@tonic-gate 		} else {
22530Sstevel@tonic-gate 			tw->tw_direction = PID_OUT;
22540Sstevel@tonic-gate 
22550Sstevel@tonic-gate 			/* Copy the data into the buffer */
22560Sstevel@tonic-gate 			ddi_rep_put8(tw->tw_accesshandle,
22570Sstevel@tonic-gate 			    req->ctrl_data->b_rptr,
22582125Ssl147100 			    (uint8_t *)(tw->tw_buf + UHCI_CTRL_EPT_MAX_SIZE),
22590Sstevel@tonic-gate 			    req->ctrl_wLength,
22600Sstevel@tonic-gate 			    DDI_DEV_AUTOINCR);
22610Sstevel@tonic-gate 		}
22620Sstevel@tonic-gate 	}
22630Sstevel@tonic-gate 
22640Sstevel@tonic-gate 	return (USB_SUCCESS);
22650Sstevel@tonic-gate }
22660Sstevel@tonic-gate 
22670Sstevel@tonic-gate 
22680Sstevel@tonic-gate /*
22690Sstevel@tonic-gate  * uhci_create_stats:
22700Sstevel@tonic-gate  *	Allocate and initialize the uhci kstat structures
22710Sstevel@tonic-gate  */
22720Sstevel@tonic-gate void
uhci_create_stats(uhci_state_t * uhcip)22730Sstevel@tonic-gate uhci_create_stats(uhci_state_t *uhcip)
22740Sstevel@tonic-gate {
22750Sstevel@tonic-gate 	int			i;
22760Sstevel@tonic-gate 	char			kstatname[KSTAT_STRLEN];
22770Sstevel@tonic-gate 	char			*usbtypes[USB_N_COUNT_KSTATS] =
22785773Sqz150045 	    {"ctrl", "isoch", "bulk", "intr"};
22790Sstevel@tonic-gate 	uint_t			instance = uhcip->uhci_instance;
22800Sstevel@tonic-gate 	const char		*dname = ddi_driver_name(uhcip->uhci_dip);
22810Sstevel@tonic-gate 	uhci_intrs_stats_t	*isp;
22820Sstevel@tonic-gate 
22830Sstevel@tonic-gate 	if (UHCI_INTRS_STATS(uhcip) == NULL) {
22840Sstevel@tonic-gate 		(void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,intrs",
22850Sstevel@tonic-gate 		    dname, instance);
22860Sstevel@tonic-gate 		UHCI_INTRS_STATS(uhcip) = kstat_create("usba", instance,
22870Sstevel@tonic-gate 		    kstatname, "usb_interrupts", KSTAT_TYPE_NAMED,
22880Sstevel@tonic-gate 		    sizeof (uhci_intrs_stats_t) / sizeof (kstat_named_t),
22890Sstevel@tonic-gate 		    KSTAT_FLAG_PERSISTENT);
22900Sstevel@tonic-gate 
22910Sstevel@tonic-gate 		if (UHCI_INTRS_STATS(uhcip) != NULL) {
22920Sstevel@tonic-gate 			isp = UHCI_INTRS_STATS_DATA(uhcip);
22930Sstevel@tonic-gate 			kstat_named_init(&isp->uhci_intrs_hc_halted,
22940Sstevel@tonic-gate 			    "HC Halted", KSTAT_DATA_UINT64);
22950Sstevel@tonic-gate 			kstat_named_init(&isp->uhci_intrs_hc_process_err,
22960Sstevel@tonic-gate 			    "HC Process Errors", KSTAT_DATA_UINT64);
22970Sstevel@tonic-gate 			kstat_named_init(&isp->uhci_intrs_host_sys_err,
22980Sstevel@tonic-gate 			    "Host Sys Errors", KSTAT_DATA_UINT64);
22990Sstevel@tonic-gate 			kstat_named_init(&isp->uhci_intrs_resume_detected,
23000Sstevel@tonic-gate 			    "Resume Detected", KSTAT_DATA_UINT64);
23010Sstevel@tonic-gate 			kstat_named_init(&isp->uhci_intrs_usb_err_intr,
23020Sstevel@tonic-gate 			    "USB Error", KSTAT_DATA_UINT64);
23030Sstevel@tonic-gate 			kstat_named_init(&isp->uhci_intrs_usb_intr,
23040Sstevel@tonic-gate 			    "USB Interrupts", KSTAT_DATA_UINT64);
23050Sstevel@tonic-gate 			kstat_named_init(&isp->uhci_intrs_total,
23060Sstevel@tonic-gate 			    "Total Interrupts", KSTAT_DATA_UINT64);
23070Sstevel@tonic-gate 			kstat_named_init(&isp->uhci_intrs_not_claimed,
23080Sstevel@tonic-gate 			    "Not Claimed", KSTAT_DATA_UINT64);
23090Sstevel@tonic-gate 
23100Sstevel@tonic-gate 			UHCI_INTRS_STATS(uhcip)->ks_private = uhcip;
23110Sstevel@tonic-gate 			UHCI_INTRS_STATS(uhcip)->ks_update = nulldev;
23120Sstevel@tonic-gate 			kstat_install(UHCI_INTRS_STATS(uhcip));
23130Sstevel@tonic-gate 		}
23140Sstevel@tonic-gate 	}
23150Sstevel@tonic-gate 
23160Sstevel@tonic-gate 	if (UHCI_TOTAL_STATS(uhcip) == NULL) {
23170Sstevel@tonic-gate 		(void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,total",
23180Sstevel@tonic-gate 		    dname, instance);
23190Sstevel@tonic-gate 		UHCI_TOTAL_STATS(uhcip) = kstat_create("usba", instance,
23200Sstevel@tonic-gate 		    kstatname, "usb_byte_count", KSTAT_TYPE_IO, 1,
23210Sstevel@tonic-gate 		    KSTAT_FLAG_PERSISTENT);
23220Sstevel@tonic-gate 
23230Sstevel@tonic-gate 		if (UHCI_TOTAL_STATS(uhcip) != NULL) {
23240Sstevel@tonic-gate 			kstat_install(UHCI_TOTAL_STATS(uhcip));
23250Sstevel@tonic-gate 		}
23260Sstevel@tonic-gate 	}
23270Sstevel@tonic-gate 
23280Sstevel@tonic-gate 	for (i = 0; i < USB_N_COUNT_KSTATS; i++) {
23290Sstevel@tonic-gate 		if (uhcip->uhci_count_stats[i] == NULL) {
23300Sstevel@tonic-gate 			(void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,%s",
23310Sstevel@tonic-gate 			    dname, instance, usbtypes[i]);
23320Sstevel@tonic-gate 			uhcip->uhci_count_stats[i] = kstat_create("usba",
23330Sstevel@tonic-gate 			    instance, kstatname, "usb_byte_count",
23340Sstevel@tonic-gate 			    KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
23350Sstevel@tonic-gate 
23360Sstevel@tonic-gate 			if (uhcip->uhci_count_stats[i] != NULL) {
23370Sstevel@tonic-gate 				kstat_install(uhcip->uhci_count_stats[i]);
23380Sstevel@tonic-gate 			}
23390Sstevel@tonic-gate 		}
23400Sstevel@tonic-gate 	}
23410Sstevel@tonic-gate }
23420Sstevel@tonic-gate 
23430Sstevel@tonic-gate 
23440Sstevel@tonic-gate /*
23450Sstevel@tonic-gate  * uhci_destroy_stats:
23460Sstevel@tonic-gate  *	Clean up uhci kstat structures
23470Sstevel@tonic-gate  */
23480Sstevel@tonic-gate void
uhci_destroy_stats(uhci_state_t * uhcip)23490Sstevel@tonic-gate uhci_destroy_stats(uhci_state_t *uhcip)
23500Sstevel@tonic-gate {
23510Sstevel@tonic-gate 	int i;
23520Sstevel@tonic-gate 
23530Sstevel@tonic-gate 	if (UHCI_INTRS_STATS(uhcip)) {
23540Sstevel@tonic-gate 		kstat_delete(UHCI_INTRS_STATS(uhcip));
23550Sstevel@tonic-gate 		UHCI_INTRS_STATS(uhcip) = NULL;
23560Sstevel@tonic-gate 	}
23570Sstevel@tonic-gate 
23580Sstevel@tonic-gate 	if (UHCI_TOTAL_STATS(uhcip)) {
23590Sstevel@tonic-gate 		kstat_delete(UHCI_TOTAL_STATS(uhcip));
23600Sstevel@tonic-gate 		UHCI_TOTAL_STATS(uhcip) = NULL;
23610Sstevel@tonic-gate 	}
23620Sstevel@tonic-gate 
23630Sstevel@tonic-gate 	for (i = 0; i < USB_N_COUNT_KSTATS; i++) {
23640Sstevel@tonic-gate 		if (uhcip->uhci_count_stats[i]) {
23650Sstevel@tonic-gate 			kstat_delete(uhcip->uhci_count_stats[i]);
23660Sstevel@tonic-gate 			uhcip->uhci_count_stats[i] = NULL;
23670Sstevel@tonic-gate 		}
23680Sstevel@tonic-gate 	}
23690Sstevel@tonic-gate }
23700Sstevel@tonic-gate 
23710Sstevel@tonic-gate 
23720Sstevel@tonic-gate void
uhci_do_intrs_stats(uhci_state_t * uhcip,int val)23730Sstevel@tonic-gate uhci_do_intrs_stats(uhci_state_t *uhcip, int val)
23740Sstevel@tonic-gate {
23750Sstevel@tonic-gate 	if (UHCI_INTRS_STATS(uhcip) == NULL) {
23760Sstevel@tonic-gate 
23770Sstevel@tonic-gate 		return;
23780Sstevel@tonic-gate 	}
23790Sstevel@tonic-gate 
23800Sstevel@tonic-gate 	UHCI_INTRS_STATS_DATA(uhcip)->uhci_intrs_total.value.ui64++;
23810Sstevel@tonic-gate 	switch (val) {
23820Sstevel@tonic-gate 	case USBSTS_REG_HC_HALTED:
23830Sstevel@tonic-gate 		UHCI_INTRS_STATS_DATA(uhcip)->uhci_intrs_hc_halted.value.ui64++;
23840Sstevel@tonic-gate 		break;
23850Sstevel@tonic-gate 	case USBSTS_REG_HC_PROCESS_ERR:
23860Sstevel@tonic-gate 		UHCI_INTRS_STATS_DATA(uhcip)->
23875773Sqz150045 		    uhci_intrs_hc_process_err.value.ui64++;
23880Sstevel@tonic-gate 		break;
23890Sstevel@tonic-gate 	case USBSTS_REG_HOST_SYS_ERR:
23900Sstevel@tonic-gate 		UHCI_INTRS_STATS_DATA(uhcip)->
23915773Sqz150045 		    uhci_intrs_host_sys_err.value.ui64++;
23920Sstevel@tonic-gate 		break;
23930Sstevel@tonic-gate 	case USBSTS_REG_RESUME_DETECT:
23940Sstevel@tonic-gate 		UHCI_INTRS_STATS_DATA(uhcip)->
23955773Sqz150045 		    uhci_intrs_resume_detected.value.ui64++;
23960Sstevel@tonic-gate 		break;
23970Sstevel@tonic-gate 	case USBSTS_REG_USB_ERR_INTR:
23980Sstevel@tonic-gate 		UHCI_INTRS_STATS_DATA(uhcip)->
23995773Sqz150045 		    uhci_intrs_usb_err_intr.value.ui64++;
24000Sstevel@tonic-gate 		break;
24010Sstevel@tonic-gate 	case USBSTS_REG_USB_INTR:
24020Sstevel@tonic-gate 		UHCI_INTRS_STATS_DATA(uhcip)->uhci_intrs_usb_intr.value.ui64++;
24030Sstevel@tonic-gate 		break;
24040Sstevel@tonic-gate 	default:
24050Sstevel@tonic-gate 		UHCI_INTRS_STATS_DATA(uhcip)->
24065773Sqz150045 		    uhci_intrs_not_claimed.value.ui64++;
24070Sstevel@tonic-gate 		break;
24080Sstevel@tonic-gate 	}
24090Sstevel@tonic-gate }
24100Sstevel@tonic-gate 
24110Sstevel@tonic-gate 
24120Sstevel@tonic-gate void
uhci_do_byte_stats(uhci_state_t * uhcip,size_t len,uint8_t attr,uint8_t addr)24130Sstevel@tonic-gate uhci_do_byte_stats(uhci_state_t *uhcip, size_t len, uint8_t attr, uint8_t addr)
24140Sstevel@tonic-gate {
24150Sstevel@tonic-gate 	uint8_t type = attr & USB_EP_ATTR_MASK;
24160Sstevel@tonic-gate 	uint8_t dir = addr & USB_EP_DIR_MASK;
24170Sstevel@tonic-gate 
24180Sstevel@tonic-gate 	switch (dir) {
24190Sstevel@tonic-gate 	case USB_EP_DIR_IN:
24200Sstevel@tonic-gate 		UHCI_TOTAL_STATS_DATA(uhcip)->reads++;
24210Sstevel@tonic-gate 		UHCI_TOTAL_STATS_DATA(uhcip)->nread += len;
24220Sstevel@tonic-gate 		switch (type) {
24230Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
24240Sstevel@tonic-gate 			UHCI_CTRL_STATS(uhcip)->reads++;
24250Sstevel@tonic-gate 			UHCI_CTRL_STATS(uhcip)->nread += len;
24260Sstevel@tonic-gate 			break;
24270Sstevel@tonic-gate 		case USB_EP_ATTR_BULK:
24280Sstevel@tonic-gate 			UHCI_BULK_STATS(uhcip)->reads++;
24290Sstevel@tonic-gate 			UHCI_BULK_STATS(uhcip)->nread += len;
24300Sstevel@tonic-gate 			break;
24310Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
24320Sstevel@tonic-gate 			UHCI_INTR_STATS(uhcip)->reads++;
24330Sstevel@tonic-gate 			UHCI_INTR_STATS(uhcip)->nread += len;
24340Sstevel@tonic-gate 			break;
24350Sstevel@tonic-gate 		case USB_EP_ATTR_ISOCH:
24360Sstevel@tonic-gate 			UHCI_ISOC_STATS(uhcip)->reads++;
24370Sstevel@tonic-gate 			UHCI_ISOC_STATS(uhcip)->nread += len;
24380Sstevel@tonic-gate 			break;
24390Sstevel@tonic-gate 		}
24400Sstevel@tonic-gate 		break;
24410Sstevel@tonic-gate 	case USB_EP_DIR_OUT:
24420Sstevel@tonic-gate 		UHCI_TOTAL_STATS_DATA(uhcip)->writes++;
24430Sstevel@tonic-gate 		UHCI_TOTAL_STATS_DATA(uhcip)->nwritten += len;
24440Sstevel@tonic-gate 		switch (type) {
24450Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
24460Sstevel@tonic-gate 			UHCI_CTRL_STATS(uhcip)->writes++;
24470Sstevel@tonic-gate 			UHCI_CTRL_STATS(uhcip)->nwritten += len;
24480Sstevel@tonic-gate 			break;
24490Sstevel@tonic-gate 		case USB_EP_ATTR_BULK:
24500Sstevel@tonic-gate 			UHCI_BULK_STATS(uhcip)->writes++;
24510Sstevel@tonic-gate 			UHCI_BULK_STATS(uhcip)->nwritten += len;
24520Sstevel@tonic-gate 			break;
24530Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
24540Sstevel@tonic-gate 			UHCI_INTR_STATS(uhcip)->writes++;
24550Sstevel@tonic-gate 			UHCI_INTR_STATS(uhcip)->nwritten += len;
24560Sstevel@tonic-gate 			break;
24570Sstevel@tonic-gate 		case USB_EP_ATTR_ISOCH:
24580Sstevel@tonic-gate 			UHCI_ISOC_STATS(uhcip)->writes++;
24590Sstevel@tonic-gate 			UHCI_ISOC_STATS(uhcip)->nwritten += len;
24600Sstevel@tonic-gate 			break;
24610Sstevel@tonic-gate 		}
24620Sstevel@tonic-gate 		break;
24630Sstevel@tonic-gate 	}
24640Sstevel@tonic-gate }
24650Sstevel@tonic-gate 
24660Sstevel@tonic-gate 
24670Sstevel@tonic-gate /*
24680Sstevel@tonic-gate  * uhci_free_tw:
24690Sstevel@tonic-gate  *	Free the Transfer Wrapper (TW).
24700Sstevel@tonic-gate  */
24710Sstevel@tonic-gate void
uhci_free_tw(uhci_state_t * uhcip,uhci_trans_wrapper_t * tw)24720Sstevel@tonic-gate uhci_free_tw(uhci_state_t *uhcip, uhci_trans_wrapper_t *tw)
24730Sstevel@tonic-gate {
24742125Ssl147100 	int rval, i;
24750Sstevel@tonic-gate 
24760Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl, "uhci_free_tw:");
24770Sstevel@tonic-gate 
24780Sstevel@tonic-gate 	ASSERT(tw != NULL);
24790Sstevel@tonic-gate 
24802125Ssl147100 	if (tw->tw_isoc_strtlen > 0) {
24812125Ssl147100 		ASSERT(tw->tw_isoc_bufs != NULL);
24822125Ssl147100 		for (i = 0; i < tw->tw_ncookies; i++) {
24832125Ssl147100 			rval = ddi_dma_unbind_handle(
24842125Ssl147100 			    tw->tw_isoc_bufs[i].dma_handle);
24852125Ssl147100 			ASSERT(rval == USB_SUCCESS);
24862125Ssl147100 			ddi_dma_mem_free(&tw->tw_isoc_bufs[i].mem_handle);
24872125Ssl147100 			ddi_dma_free_handle(&tw->tw_isoc_bufs[i].dma_handle);
24882125Ssl147100 		}
24892125Ssl147100 		kmem_free(tw->tw_isoc_bufs, tw->tw_isoc_strtlen);
24902125Ssl147100 	} else if (tw->tw_dmahandle != NULL) {
24912125Ssl147100 		rval = ddi_dma_unbind_handle(tw->tw_dmahandle);
24922125Ssl147100 		ASSERT(rval == DDI_SUCCESS);
24932125Ssl147100 
24942125Ssl147100 		ddi_dma_mem_free(&tw->tw_accesshandle);
24952125Ssl147100 		ddi_dma_free_handle(&tw->tw_dmahandle);
24962125Ssl147100 	}
24972125Ssl147100 
24980Sstevel@tonic-gate 	kmem_free(tw, sizeof (uhci_trans_wrapper_t));
24990Sstevel@tonic-gate }
25000Sstevel@tonic-gate 
25010Sstevel@tonic-gate 
25020Sstevel@tonic-gate /*
25030Sstevel@tonic-gate  * uhci_deallocate_tw:
25040Sstevel@tonic-gate  *	Deallocate of a Transaction Wrapper (TW) and this involves
25050Sstevel@tonic-gate  *	the freeing of DMA resources.
25060Sstevel@tonic-gate  */
25070Sstevel@tonic-gate void
uhci_deallocate_tw(uhci_state_t * uhcip,uhci_pipe_private_t * pp,uhci_trans_wrapper_t * tw)25080Sstevel@tonic-gate uhci_deallocate_tw(uhci_state_t *uhcip,
25090Sstevel@tonic-gate     uhci_pipe_private_t *pp, uhci_trans_wrapper_t *tw)
25100Sstevel@tonic-gate {
25110Sstevel@tonic-gate 	uhci_trans_wrapper_t	*head;
25120Sstevel@tonic-gate 
25130Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl,
25140Sstevel@tonic-gate 	    "uhci_deallocate_tw:");
25150Sstevel@tonic-gate 
25160Sstevel@tonic-gate 	/*
25170Sstevel@tonic-gate 	 * If the transfer wrapper has no Host Controller (HC)
25180Sstevel@tonic-gate 	 * Transfer Descriptors (TD) associated with it,  then
25190Sstevel@tonic-gate 	 * remove the transfer wrapper. The transfers are done
25200Sstevel@tonic-gate 	 * in FIFO order, so this should be the first transfer
25210Sstevel@tonic-gate 	 * wrapper on the list.
25220Sstevel@tonic-gate 	 */
25230Sstevel@tonic-gate 	if (tw->tw_hctd_head != NULL) {
25240Sstevel@tonic-gate 		ASSERT(tw->tw_hctd_tail != NULL);
25250Sstevel@tonic-gate 
25260Sstevel@tonic-gate 		return;
25270Sstevel@tonic-gate 	}
25280Sstevel@tonic-gate 
25290Sstevel@tonic-gate 	ASSERT(tw->tw_hctd_tail == NULL);
25300Sstevel@tonic-gate 	ASSERT(pp->pp_tw_head != NULL);
25310Sstevel@tonic-gate 
25320Sstevel@tonic-gate 	/*
25330Sstevel@tonic-gate 	 * If pp->pp_tw_head is NULL, set the tail also to NULL.
25340Sstevel@tonic-gate 	 */
25350Sstevel@tonic-gate 	head = pp->pp_tw_head;
25360Sstevel@tonic-gate 
25370Sstevel@tonic-gate 	if (head == tw) {
25380Sstevel@tonic-gate 		pp->pp_tw_head = head->tw_next;
25390Sstevel@tonic-gate 		if (pp->pp_tw_head == NULL) {
25400Sstevel@tonic-gate 			pp->pp_tw_tail = NULL;
25410Sstevel@tonic-gate 		}
25420Sstevel@tonic-gate 	} else {
25430Sstevel@tonic-gate 		while (head->tw_next != tw)
25440Sstevel@tonic-gate 			head = head->tw_next;
25450Sstevel@tonic-gate 		head->tw_next = tw->tw_next;
25460Sstevel@tonic-gate 		if (tw->tw_next == NULL) {
25470Sstevel@tonic-gate 			pp->pp_tw_tail = head;
25480Sstevel@tonic-gate 		}
25490Sstevel@tonic-gate 	}
25500Sstevel@tonic-gate 	uhci_free_tw(uhcip, tw);
25510Sstevel@tonic-gate }
25520Sstevel@tonic-gate 
25530Sstevel@tonic-gate 
25540Sstevel@tonic-gate void
uhci_delete_td(uhci_state_t * uhcip,uhci_td_t * td)25550Sstevel@tonic-gate uhci_delete_td(uhci_state_t *uhcip, uhci_td_t *td)
25560Sstevel@tonic-gate {
25570Sstevel@tonic-gate 	uhci_td_t		*tmp_td;
25580Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw = td->tw;
25590Sstevel@tonic-gate 
25600Sstevel@tonic-gate 	if ((td->outst_td_next == NULL) && (td->outst_td_prev == NULL)) {
25610Sstevel@tonic-gate 		uhcip->uhci_outst_tds_head = NULL;
25620Sstevel@tonic-gate 		uhcip->uhci_outst_tds_tail = NULL;
25630Sstevel@tonic-gate 	} else if (td->outst_td_next == NULL) {
25640Sstevel@tonic-gate 		td->outst_td_prev->outst_td_next = NULL;
25650Sstevel@tonic-gate 		uhcip->uhci_outst_tds_tail = td->outst_td_prev;
25660Sstevel@tonic-gate 	} else if (td->outst_td_prev == NULL) {
25670Sstevel@tonic-gate 		td->outst_td_next->outst_td_prev = NULL;
25680Sstevel@tonic-gate 		uhcip->uhci_outst_tds_head = td->outst_td_next;
25690Sstevel@tonic-gate 	} else {
25700Sstevel@tonic-gate 		td->outst_td_prev->outst_td_next = td->outst_td_next;
25710Sstevel@tonic-gate 		td->outst_td_next->outst_td_prev = td->outst_td_prev;
25720Sstevel@tonic-gate 	}
25730Sstevel@tonic-gate 
25740Sstevel@tonic-gate 	tmp_td = tw->tw_hctd_head;
25750Sstevel@tonic-gate 
25760Sstevel@tonic-gate 	if (tmp_td != td) {
25770Sstevel@tonic-gate 		while (tmp_td->tw_td_next != td) {
25780Sstevel@tonic-gate 			tmp_td = tmp_td->tw_td_next;
25790Sstevel@tonic-gate 		}
25800Sstevel@tonic-gate 		ASSERT(tmp_td);
25810Sstevel@tonic-gate 		tmp_td->tw_td_next = td->tw_td_next;
25820Sstevel@tonic-gate 		if (td->tw_td_next == NULL) {
25830Sstevel@tonic-gate 			tw->tw_hctd_tail = tmp_td;
25840Sstevel@tonic-gate 		}
25850Sstevel@tonic-gate 	} else {
25860Sstevel@tonic-gate 		tw->tw_hctd_head = tw->tw_hctd_head->tw_td_next;
25870Sstevel@tonic-gate 		if (tw->tw_hctd_head == NULL) {
25880Sstevel@tonic-gate 			tw->tw_hctd_tail = NULL;
25890Sstevel@tonic-gate 		}
25900Sstevel@tonic-gate 	}
25910Sstevel@tonic-gate 
25920Sstevel@tonic-gate 	td->flag  = TD_FLAG_FREE;
25930Sstevel@tonic-gate }
25940Sstevel@tonic-gate 
25950Sstevel@tonic-gate 
25960Sstevel@tonic-gate void
uhci_remove_tds_tws(uhci_state_t * uhcip,usba_pipe_handle_data_t * ph)25970Sstevel@tonic-gate uhci_remove_tds_tws(
25980Sstevel@tonic-gate 	uhci_state_t		*uhcip,
25990Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph)
26000Sstevel@tonic-gate {
26010Sstevel@tonic-gate 	usb_opaque_t		curr_reqp;
26020Sstevel@tonic-gate 	uhci_pipe_private_t	*pp = (uhci_pipe_private_t *)ph->p_hcd_private;
26030Sstevel@tonic-gate 	usb_ep_descr_t		*ept = &pp->pp_pipe_handle->p_ep;
26040Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw_tmp;
26050Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw_head = pp->pp_tw_head;
26060Sstevel@tonic-gate 
26070Sstevel@tonic-gate 	while (tw_head != NULL) {
26080Sstevel@tonic-gate 		tw_tmp = tw_head;
26090Sstevel@tonic-gate 		tw_head = tw_head->tw_next;
26100Sstevel@tonic-gate 
26110Sstevel@tonic-gate 		curr_reqp = tw_tmp->tw_curr_xfer_reqp;
26120Sstevel@tonic-gate 		if (curr_reqp) {
26130Sstevel@tonic-gate 			/* do this for control/bulk/intr */
26140Sstevel@tonic-gate 			if ((tw_tmp->tw_direction == PID_IN) &&
26150Sstevel@tonic-gate 			    (UHCI_XFER_TYPE(ept) == USB_EP_ATTR_INTR)) {
26160Sstevel@tonic-gate 				uhci_deallocate_periodic_in_resource(uhcip,
26170Sstevel@tonic-gate 				    pp, tw_tmp);
26180Sstevel@tonic-gate 			} else {
26190Sstevel@tonic-gate 				uhci_hcdi_callback(uhcip, pp,
26200Sstevel@tonic-gate 				    pp->pp_pipe_handle, tw_tmp, USB_CR_FLUSHED);
26210Sstevel@tonic-gate 			}
26220Sstevel@tonic-gate 		} /* end of curr_reqp */
26230Sstevel@tonic-gate 
26240Sstevel@tonic-gate 		if (tw_tmp->tw_claim != UHCI_MODIFY_TD_BITS_CLAIMED) {
26250Sstevel@tonic-gate 			continue;
26260Sstevel@tonic-gate 		}
26270Sstevel@tonic-gate 
26280Sstevel@tonic-gate 		while (tw_tmp->tw_hctd_head != NULL) {
26290Sstevel@tonic-gate 			uhci_delete_td(uhcip, tw_tmp->tw_hctd_head);
26300Sstevel@tonic-gate 		}
26310Sstevel@tonic-gate 
26320Sstevel@tonic-gate 		uhci_deallocate_tw(uhcip, pp, tw_tmp);
26330Sstevel@tonic-gate 	}
26340Sstevel@tonic-gate }
26350Sstevel@tonic-gate 
26360Sstevel@tonic-gate 
26370Sstevel@tonic-gate /*
26380Sstevel@tonic-gate  * uhci_remove_qh:
26390Sstevel@tonic-gate  *	Remove the Queue Head from the Host Controller's
26400Sstevel@tonic-gate  *	appropriate QH list.
26410Sstevel@tonic-gate  */
26420Sstevel@tonic-gate void
uhci_remove_qh(uhci_state_t * uhcip,uhci_pipe_private_t * pp)26430Sstevel@tonic-gate uhci_remove_qh(uhci_state_t *uhcip, uhci_pipe_private_t *pp)
26440Sstevel@tonic-gate {
26450Sstevel@tonic-gate 	uhci_td_t	*dummy_td;
26460Sstevel@tonic-gate 
26470Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
26480Sstevel@tonic-gate 
26490Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
26500Sstevel@tonic-gate 	    "uhci_remove_qh:");
26510Sstevel@tonic-gate 
26520Sstevel@tonic-gate 	dummy_td = pp->pp_qh->td_tailp;
26530Sstevel@tonic-gate 	dummy_td->flag = TD_FLAG_FREE;
26540Sstevel@tonic-gate 
26550Sstevel@tonic-gate 	switch (UHCI_XFER_TYPE(&pp->pp_pipe_handle->p_ep)) {
26560Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
26570Sstevel@tonic-gate 		uhci_remove_ctrl_qh(uhcip, pp);
26580Sstevel@tonic-gate 		break;
26590Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
26600Sstevel@tonic-gate 		uhci_remove_bulk_qh(uhcip, pp);
26610Sstevel@tonic-gate 		break;
26620Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
26630Sstevel@tonic-gate 		uhci_remove_intr_qh(uhcip, pp);
26640Sstevel@tonic-gate 		break;
26650Sstevel@tonic-gate 	}
26660Sstevel@tonic-gate }
26670Sstevel@tonic-gate 
26680Sstevel@tonic-gate 
26690Sstevel@tonic-gate static void
uhci_remove_intr_qh(uhci_state_t * uhcip,uhci_pipe_private_t * pp)26700Sstevel@tonic-gate uhci_remove_intr_qh(uhci_state_t *uhcip, uhci_pipe_private_t *pp)
26710Sstevel@tonic-gate {
26720Sstevel@tonic-gate 	queue_head_t   *qh = pp->pp_qh;
26730Sstevel@tonic-gate 	queue_head_t   *next_lattice_qh =
26745773Sqz150045 	    QH_VADDR(GetQH32(uhcip, qh->link_ptr) & QH_LINK_PTR_MASK);
26750Sstevel@tonic-gate 
26760Sstevel@tonic-gate 	qh->prev_qh->link_ptr	 = qh->link_ptr;
26770Sstevel@tonic-gate 	next_lattice_qh->prev_qh = qh->prev_qh;
26780Sstevel@tonic-gate 	qh->qh_flag = QUEUE_HEAD_FLAG_FREE;
26790Sstevel@tonic-gate 
26800Sstevel@tonic-gate }
26810Sstevel@tonic-gate 
26820Sstevel@tonic-gate /*
26830Sstevel@tonic-gate  * uhci_remove_bulk_qh:
26840Sstevel@tonic-gate  *	Remove a bulk QH from the Host Controller's QH list. There may be a
26850Sstevel@tonic-gate  *	loop for bulk QHs, we must care about this while removing a bulk QH.
26860Sstevel@tonic-gate  */
26870Sstevel@tonic-gate static void
uhci_remove_bulk_qh(uhci_state_t * uhcip,uhci_pipe_private_t * pp)26880Sstevel@tonic-gate uhci_remove_bulk_qh(uhci_state_t *uhcip, uhci_pipe_private_t *pp)
26890Sstevel@tonic-gate {
26900Sstevel@tonic-gate 	queue_head_t   *qh = pp->pp_qh;
26910Sstevel@tonic-gate 	queue_head_t   *next_lattice_qh;
26920Sstevel@tonic-gate 	uint32_t	paddr;
26930Sstevel@tonic-gate 
26940Sstevel@tonic-gate 	paddr = (GetQH32(uhcip, qh->link_ptr) & QH_LINK_PTR_MASK);
26950Sstevel@tonic-gate 	next_lattice_qh = (qh == uhcip->uhci_bulk_xfers_q_tail) ?
26960Sstevel@tonic-gate 	    0 : QH_VADDR(paddr);
26970Sstevel@tonic-gate 
26980Sstevel@tonic-gate 	if ((qh == uhcip->uhci_bulk_xfers_q_tail) &&
26990Sstevel@tonic-gate 	    (qh->prev_qh == uhcip->uhci_bulk_xfers_q_head)) {
27000Sstevel@tonic-gate 		SetQH32(uhcip, qh->prev_qh->link_ptr, HC_END_OF_LIST);
27010Sstevel@tonic-gate 	} else {
27020Sstevel@tonic-gate 		qh->prev_qh->link_ptr = qh->link_ptr;
27030Sstevel@tonic-gate 	}
27040Sstevel@tonic-gate 
27050Sstevel@tonic-gate 	if (next_lattice_qh == NULL) {
27060Sstevel@tonic-gate 		uhcip->uhci_bulk_xfers_q_tail = qh->prev_qh;
27070Sstevel@tonic-gate 	} else {
27080Sstevel@tonic-gate 		next_lattice_qh->prev_qh = qh->prev_qh;
27090Sstevel@tonic-gate 	}
27100Sstevel@tonic-gate 
27110Sstevel@tonic-gate 	qh->qh_flag = QUEUE_HEAD_FLAG_FREE;
27120Sstevel@tonic-gate 
27130Sstevel@tonic-gate }
27140Sstevel@tonic-gate 
27150Sstevel@tonic-gate 
27160Sstevel@tonic-gate static void
uhci_remove_ctrl_qh(uhci_state_t * uhcip,uhci_pipe_private_t * pp)27170Sstevel@tonic-gate uhci_remove_ctrl_qh(uhci_state_t *uhcip, uhci_pipe_private_t *pp)
27180Sstevel@tonic-gate {
27190Sstevel@tonic-gate 	queue_head_t   *qh = pp->pp_qh;
27200Sstevel@tonic-gate 	queue_head_t   *next_lattice_qh =
27210Sstevel@tonic-gate 	    QH_VADDR(GetQH32(uhcip, qh->link_ptr) & QH_LINK_PTR_MASK);
27220Sstevel@tonic-gate 
27230Sstevel@tonic-gate 	qh->prev_qh->link_ptr = qh->link_ptr;
27240Sstevel@tonic-gate 	if (next_lattice_qh->prev_qh != NULL) {
27250Sstevel@tonic-gate 		next_lattice_qh->prev_qh = qh->prev_qh;
27260Sstevel@tonic-gate 	} else {
27270Sstevel@tonic-gate 		uhcip->uhci_ctrl_xfers_q_tail = qh->prev_qh;
27280Sstevel@tonic-gate 	}
27290Sstevel@tonic-gate 
27300Sstevel@tonic-gate 	qh->qh_flag = QUEUE_HEAD_FLAG_FREE;
27310Sstevel@tonic-gate }
27320Sstevel@tonic-gate 
27330Sstevel@tonic-gate 
27340Sstevel@tonic-gate /*
27350Sstevel@tonic-gate  * uhci_allocate_td_from_pool:
27360Sstevel@tonic-gate  *	Allocate a Transfer Descriptor (TD) from the TD buffer pool.
27370Sstevel@tonic-gate  */
27380Sstevel@tonic-gate static uhci_td_t *
uhci_allocate_td_from_pool(uhci_state_t * uhcip)27390Sstevel@tonic-gate uhci_allocate_td_from_pool(uhci_state_t *uhcip)
27400Sstevel@tonic-gate {
27410Sstevel@tonic-gate 	int		index;
27420Sstevel@tonic-gate 	uhci_td_t	*td;
27430Sstevel@tonic-gate 
27440Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
27450Sstevel@tonic-gate 
27460Sstevel@tonic-gate 	/*
27470Sstevel@tonic-gate 	 * Search for a blank Transfer Descriptor (TD)
27480Sstevel@tonic-gate 	 * in the TD buffer pool.
27490Sstevel@tonic-gate 	 */
27500Sstevel@tonic-gate 	for (index = 0; index < uhci_td_pool_size; index ++) {
27510Sstevel@tonic-gate 		if (uhcip->uhci_td_pool_addr[index].flag == TD_FLAG_FREE) {
27520Sstevel@tonic-gate 			break;
27530Sstevel@tonic-gate 		}
27540Sstevel@tonic-gate 	}
27550Sstevel@tonic-gate 
27560Sstevel@tonic-gate 	if (index == uhci_td_pool_size) {
27570Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl,
27580Sstevel@tonic-gate 		    "uhci_allocate_td_from_pool: TD exhausted");
27590Sstevel@tonic-gate 
27600Sstevel@tonic-gate 		return (NULL);
27610Sstevel@tonic-gate 	}
27620Sstevel@tonic-gate 
27630Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALLOC, uhcip->uhci_log_hdl,
27640Sstevel@tonic-gate 	    "uhci_allocate_td_from_pool: Allocated %d", index);
27650Sstevel@tonic-gate 
27660Sstevel@tonic-gate 	/* Create a new dummy for the end of the TD list */
27670Sstevel@tonic-gate 	td = &uhcip->uhci_td_pool_addr[index];
27680Sstevel@tonic-gate 
27690Sstevel@tonic-gate 	/* Mark the newly allocated TD as a dummy */
27700Sstevel@tonic-gate 	td->flag =  TD_FLAG_DUMMY;
27710Sstevel@tonic-gate 	td->qh_td_prev	=  NULL;
27720Sstevel@tonic-gate 
27730Sstevel@tonic-gate 	return (td);
27740Sstevel@tonic-gate }
27750Sstevel@tonic-gate 
27760Sstevel@tonic-gate 
27770Sstevel@tonic-gate /*
27780Sstevel@tonic-gate  * uhci_insert_bulk_td:
27790Sstevel@tonic-gate  */
27800Sstevel@tonic-gate int
uhci_insert_bulk_td(uhci_state_t * uhcip,usba_pipe_handle_data_t * ph,usb_bulk_req_t * req,usb_flags_t flags)27810Sstevel@tonic-gate uhci_insert_bulk_td(
27820Sstevel@tonic-gate 	uhci_state_t		*uhcip,
27830Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
27840Sstevel@tonic-gate 	usb_bulk_req_t		*req,
27850Sstevel@tonic-gate 	usb_flags_t		flags)
27860Sstevel@tonic-gate {
27870Sstevel@tonic-gate 	size_t			length;
27880Sstevel@tonic-gate 	uint_t			mps;	/* MaxPacketSize */
27892125Ssl147100 	uint_t			num_bulk_tds, i, j;
27902125Ssl147100 	uint32_t		buf_offs;
27910Sstevel@tonic-gate 	uhci_td_t		*bulk_td_ptr;
27922125Ssl147100 	uhci_td_t		*current_dummy, *tmp_td;
27930Sstevel@tonic-gate 	uhci_pipe_private_t	*pp = (uhci_pipe_private_t *)ph->p_hcd_private;
27940Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw;
27950Sstevel@tonic-gate 	uhci_bulk_isoc_xfer_t	*bulk_xfer_info;
27962125Ssl147100 	uhci_bulk_isoc_td_pool_t *td_pool_ptr;
27970Sstevel@tonic-gate 
27980Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
27996898Sfb209375 	    "uhci_insert_bulk_td: req: 0x%p, flags = 0x%x", (void *)req, flags);
28000Sstevel@tonic-gate 
28010Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
28020Sstevel@tonic-gate 
28030Sstevel@tonic-gate 	/*
28040Sstevel@tonic-gate 	 * Create transfer wrapper
28050Sstevel@tonic-gate 	 */
28060Sstevel@tonic-gate 	if ((tw = uhci_create_transfer_wrapper(uhcip, pp, req->bulk_len,
28070Sstevel@tonic-gate 	    flags)) == NULL) {
28080Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
28090Sstevel@tonic-gate 		    "uhci_insert_bulk_td: TW allocation failed");
28100Sstevel@tonic-gate 
28110Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
28120Sstevel@tonic-gate 	}
28130Sstevel@tonic-gate 
28140Sstevel@tonic-gate 	tw->tw_bytes_xfered		= 0;
28150Sstevel@tonic-gate 	tw->tw_bytes_pending		= req->bulk_len;
28160Sstevel@tonic-gate 	tw->tw_handle_td		= uhci_handle_bulk_td;
28170Sstevel@tonic-gate 	tw->tw_handle_callback_value	= (usb_opaque_t)req->bulk_data;
28180Sstevel@tonic-gate 	tw->tw_timeout_cnt		= req->bulk_timeout;
28190Sstevel@tonic-gate 	tw->tw_data			= req->bulk_data;
28200Sstevel@tonic-gate 	tw->tw_curr_xfer_reqp		= (usb_opaque_t)req;
28210Sstevel@tonic-gate 
28220Sstevel@tonic-gate 	/* Get the bulk pipe direction */
28230Sstevel@tonic-gate 	tw->tw_direction = (UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_OUT) ?
28245773Sqz150045 	    PID_OUT : PID_IN;
28250Sstevel@tonic-gate 
28260Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
28270Sstevel@tonic-gate 	    "uhci_insert_bulk_td: direction: 0x%x", tw->tw_direction);
28280Sstevel@tonic-gate 
28290Sstevel@tonic-gate 	/* If the DATA OUT, copy the data into transfer buffer. */
28300Sstevel@tonic-gate 	if (tw->tw_direction == PID_OUT) {
28312495Sgc161489 		if (req->bulk_len) {
28322495Sgc161489 			ASSERT(req->bulk_data != NULL);
28332495Sgc161489 
28342495Sgc161489 			/* Copy the data into the message */
28352495Sgc161489 			ddi_rep_put8(tw->tw_accesshandle,
28365773Sqz150045 			    req->bulk_data->b_rptr,
28375773Sqz150045 			    (uint8_t *)tw->tw_buf,
28385773Sqz150045 			    req->bulk_len, DDI_DEV_AUTOINCR);
28392495Sgc161489 		}
28400Sstevel@tonic-gate 	}
28410Sstevel@tonic-gate 
28420Sstevel@tonic-gate 	/* Get the max packet size.  */
28430Sstevel@tonic-gate 	length = mps = pp->pp_pipe_handle->p_ep.wMaxPacketSize;
28440Sstevel@tonic-gate 
28450Sstevel@tonic-gate 	/*
28460Sstevel@tonic-gate 	 * Calculate number of TD's to insert in the current frame interval.
28470Sstevel@tonic-gate 	 * Max number TD's allowed (driver implementation) is 128
28480Sstevel@tonic-gate 	 * in one frame interval. Once all the TD's are completed
28490Sstevel@tonic-gate 	 * then the remaining TD's will be inserted into the lattice
28500Sstevel@tonic-gate 	 * in the uhci_handle_bulk_td().
28510Sstevel@tonic-gate 	 */
28520Sstevel@tonic-gate 	if ((tw->tw_bytes_pending / mps) >= MAX_NUM_BULK_TDS_PER_XFER) {
28530Sstevel@tonic-gate 		num_bulk_tds = MAX_NUM_BULK_TDS_PER_XFER;
28540Sstevel@tonic-gate 	} else {
28550Sstevel@tonic-gate 		num_bulk_tds = (tw->tw_bytes_pending / mps);
28560Sstevel@tonic-gate 
28572495Sgc161489 		if (tw->tw_bytes_pending % mps || tw->tw_bytes_pending == 0) {
28580Sstevel@tonic-gate 			num_bulk_tds++;
28590Sstevel@tonic-gate 			length = (tw->tw_bytes_pending % mps);
28600Sstevel@tonic-gate 		}
28610Sstevel@tonic-gate 	}
28620Sstevel@tonic-gate 
28630Sstevel@tonic-gate 	/*
28640Sstevel@tonic-gate 	 * Allocate memory for the bulk xfer information structure
28650Sstevel@tonic-gate 	 */
28660Sstevel@tonic-gate 	if ((bulk_xfer_info = kmem_zalloc(
28670Sstevel@tonic-gate 	    sizeof (uhci_bulk_isoc_xfer_t), KM_NOSLEEP)) == NULL) {
28680Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
28690Sstevel@tonic-gate 		    "uhci_insert_bulk_td: kmem_zalloc failed");
28700Sstevel@tonic-gate 
28710Sstevel@tonic-gate 		/* Free the transfer wrapper */
28720Sstevel@tonic-gate 		uhci_deallocate_tw(uhcip, pp, tw);
28730Sstevel@tonic-gate 
28740Sstevel@tonic-gate 		return (USB_FAILURE);
28750Sstevel@tonic-gate 	}
28760Sstevel@tonic-gate 
28770Sstevel@tonic-gate 	/* Allocate memory for the bulk TD's */
28782125Ssl147100 	if (uhci_alloc_bulk_isoc_tds(uhcip, num_bulk_tds, bulk_xfer_info) !=
28790Sstevel@tonic-gate 	    USB_SUCCESS) {
28800Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
28812125Ssl147100 		    "uhci_insert_bulk_td: alloc_bulk_isoc_tds failed");
28820Sstevel@tonic-gate 
28830Sstevel@tonic-gate 		kmem_free(bulk_xfer_info, sizeof (uhci_bulk_isoc_xfer_t));
28840Sstevel@tonic-gate 
28850Sstevel@tonic-gate 		/* Free the transfer wrapper */
28860Sstevel@tonic-gate 		uhci_deallocate_tw(uhcip, pp, tw);
28870Sstevel@tonic-gate 
28880Sstevel@tonic-gate 		return (USB_FAILURE);
28890Sstevel@tonic-gate 	}
28900Sstevel@tonic-gate 
28912125Ssl147100 	td_pool_ptr = &bulk_xfer_info->td_pools[0];
28922125Ssl147100 	bulk_td_ptr = (uhci_td_t *)td_pool_ptr->pool_addr;
28930Sstevel@tonic-gate 	bulk_td_ptr[0].qh_td_prev = NULL;
28940Sstevel@tonic-gate 	current_dummy = pp->pp_qh->td_tailp;
28952125Ssl147100 	buf_offs = 0;
28960Sstevel@tonic-gate 	pp->pp_qh->bulk_xfer_info = bulk_xfer_info;
28970Sstevel@tonic-gate 
28980Sstevel@tonic-gate 	/* Fill up all the bulk TD's */
28992125Ssl147100 	for (i = 0; i < bulk_xfer_info->num_pools; i++) {
29002125Ssl147100 		for (j = 0; j < (td_pool_ptr->num_tds - 1); j++) {
29012125Ssl147100 			uhci_fill_in_bulk_isoc_td(uhcip, &bulk_td_ptr[j],
29022125Ssl147100 			    &bulk_td_ptr[j+1], BULKTD_PADDR(td_pool_ptr,
29032125Ssl147100 			    &bulk_td_ptr[j+1]), ph, buf_offs, mps, tw);
29042125Ssl147100 			buf_offs += mps;
29052125Ssl147100 		}
29062125Ssl147100 
29072125Ssl147100 		/* fill in the last TD */
29082125Ssl147100 		if (i == (bulk_xfer_info->num_pools - 1)) {
29092125Ssl147100 			uhci_fill_in_bulk_isoc_td(uhcip, &bulk_td_ptr[j],
29102125Ssl147100 			    current_dummy, TD_PADDR(current_dummy),
29112125Ssl147100 			    ph, buf_offs, length, tw);
29122125Ssl147100 		} else {
29132125Ssl147100 			/* fill in the TD at the tail of a pool */
29142125Ssl147100 			tmp_td = &bulk_td_ptr[j];
29152125Ssl147100 			td_pool_ptr = &bulk_xfer_info->td_pools[i + 1];
29162125Ssl147100 			bulk_td_ptr = (uhci_td_t *)td_pool_ptr->pool_addr;
29172125Ssl147100 			uhci_fill_in_bulk_isoc_td(uhcip, tmp_td,
29182125Ssl147100 			    &bulk_td_ptr[0], BULKTD_PADDR(td_pool_ptr,
29192125Ssl147100 			    &bulk_td_ptr[0]), ph, buf_offs, mps, tw);
29202125Ssl147100 			buf_offs += mps;
29212125Ssl147100 		}
29220Sstevel@tonic-gate 	}
29230Sstevel@tonic-gate 
29247492SZhigang.Lu@Sun.COM 	bulk_xfer_info->num_tds	= (ushort_t)num_bulk_tds;
29250Sstevel@tonic-gate 
29260Sstevel@tonic-gate 	/*
29270Sstevel@tonic-gate 	 * Point the end of the lattice tree to the start of the bulk xfers
29280Sstevel@tonic-gate 	 * queue head. This allows the HC to execute the same Queue Head/TD
29290Sstevel@tonic-gate 	 * in the same frame. There are some bulk devices, which NAKs after
29300Sstevel@tonic-gate 	 * completing each TD. As a result, the performance on such devices
29310Sstevel@tonic-gate 	 * is very bad.  This loop will  provide a chance to execute NAk'ed
29320Sstevel@tonic-gate 	 * bulk TDs again in the same frame.
29330Sstevel@tonic-gate 	 */
29340Sstevel@tonic-gate 	if (uhcip->uhci_pending_bulk_cmds++ == 0) {
29350Sstevel@tonic-gate 		uhcip->uhci_bulk_xfers_q_tail->link_ptr =
29365773Sqz150045 		    uhcip->uhci_bulk_xfers_q_head->link_ptr;
29370Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
29380Sstevel@tonic-gate 		    "uhci_insert_bulk_td: count = %d no tds  %d",
29390Sstevel@tonic-gate 		    uhcip->uhci_pending_bulk_cmds, num_bulk_tds);
29400Sstevel@tonic-gate 	}
29410Sstevel@tonic-gate 
29420Sstevel@tonic-gate 	/* Insert on the bulk queue head for the execution by HC */
29430Sstevel@tonic-gate 	SetQH32(uhcip, pp->pp_qh->element_ptr,
29442125Ssl147100 	    bulk_xfer_info->td_pools[0].cookie.dmac_address);
29450Sstevel@tonic-gate 
29460Sstevel@tonic-gate 	return (USB_SUCCESS);
29470Sstevel@tonic-gate }
29480Sstevel@tonic-gate 
29490Sstevel@tonic-gate 
29500Sstevel@tonic-gate /*
29510Sstevel@tonic-gate  * uhci_fill_in_bulk_isoc_td
29522125Ssl147100  *     Fills the bulk/isoc TD
29532125Ssl147100  *
29542125Ssl147100  * offset - different meanings for bulk and isoc TDs:
29555773Sqz150045  *	    starting offset into the TW buffer for a bulk TD
29565773Sqz150045  *	    and the index into the isoc packet list for an isoc TD
29570Sstevel@tonic-gate  */
29580Sstevel@tonic-gate void
uhci_fill_in_bulk_isoc_td(uhci_state_t * uhcip,uhci_td_t * current_td,uhci_td_t * next_td,uint32_t next_td_paddr,usba_pipe_handle_data_t * ph,uint_t offset,uint_t length,uhci_trans_wrapper_t * tw)29590Sstevel@tonic-gate uhci_fill_in_bulk_isoc_td(uhci_state_t *uhcip, uhci_td_t *current_td,
29600Sstevel@tonic-gate 	uhci_td_t		*next_td,
29610Sstevel@tonic-gate 	uint32_t		next_td_paddr,
29620Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
29632125Ssl147100 	uint_t			offset,
29640Sstevel@tonic-gate 	uint_t			length,
29650Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw)
29660Sstevel@tonic-gate {
29670Sstevel@tonic-gate 	uhci_pipe_private_t	*pp = (uhci_pipe_private_t *)ph->p_hcd_private;
29680Sstevel@tonic-gate 	usb_ep_descr_t		*ept = &pp->pp_pipe_handle->p_ep;
29692125Ssl147100 	uint32_t		buf_addr;
29700Sstevel@tonic-gate 
29710Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
29722125Ssl147100 	    "uhci_fill_in_bulk_isoc_td: tw 0x%p offs 0x%x length 0x%x",
29736898Sfb209375 	    (void *)tw, offset, length);
29740Sstevel@tonic-gate 
29750Sstevel@tonic-gate 	bzero((char *)current_td, sizeof (uhci_td_t));
29760Sstevel@tonic-gate 	SetTD32(uhcip, current_td->link_ptr, next_td_paddr | HC_DEPTH_FIRST);
29770Sstevel@tonic-gate 
29780Sstevel@tonic-gate 	switch (UHCI_XFER_TYPE(ept)) {
29790Sstevel@tonic-gate 	case USB_EP_ATTR_ISOCH:
29800Sstevel@tonic-gate 		if (((usb_isoc_req_t *)tw->tw_curr_xfer_reqp)->isoc_attributes
29810Sstevel@tonic-gate 		    & USB_ATTRS_SHORT_XFER_OK) {
29820Sstevel@tonic-gate 			SetTD_spd(uhcip, current_td, 1);
29830Sstevel@tonic-gate 		}
29840Sstevel@tonic-gate 		break;
29850Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
29860Sstevel@tonic-gate 		if (((usb_bulk_req_t *)tw->tw_curr_xfer_reqp)->bulk_attributes
29870Sstevel@tonic-gate 		    & USB_ATTRS_SHORT_XFER_OK) {
29880Sstevel@tonic-gate 			SetTD_spd(uhcip, current_td, 1);
29890Sstevel@tonic-gate 		}
29900Sstevel@tonic-gate 		break;
29910Sstevel@tonic-gate 	}
29920Sstevel@tonic-gate 
29930Sstevel@tonic-gate 	mutex_enter(&ph->p_usba_device->usb_mutex);
29940Sstevel@tonic-gate 
29950Sstevel@tonic-gate 	SetTD_c_err(uhcip, current_td, UHCI_MAX_ERR_COUNT);
29960Sstevel@tonic-gate 	SetTD_status(uhcip, current_td, UHCI_TD_ACTIVE);
29970Sstevel@tonic-gate 	SetTD_ioc(uhcip, current_td, INTERRUPT_ON_COMPLETION);
29982495Sgc161489 	SetTD_mlen(uhcip, current_td,
29995773Sqz150045 	    (length == 0) ? ZERO_LENGTH : (length - 1));
30000Sstevel@tonic-gate 	SetTD_dtogg(uhcip, current_td, pp->pp_data_toggle);
30010Sstevel@tonic-gate 	SetTD_devaddr(uhcip, current_td, ph->p_usba_device->usb_addr);
30020Sstevel@tonic-gate 	SetTD_endpt(uhcip, current_td, ph->p_ep.bEndpointAddress &
30035773Sqz150045 	    END_POINT_ADDRESS_MASK);
30040Sstevel@tonic-gate 	SetTD_PID(uhcip, current_td, tw->tw_direction);
30052125Ssl147100 
30062125Ssl147100 	/* Get the right buffer address for the current TD */
30072125Ssl147100 	switch (UHCI_XFER_TYPE(ept)) {
30082125Ssl147100 	case USB_EP_ATTR_ISOCH:
30092125Ssl147100 		buf_addr = tw->tw_isoc_bufs[offset].cookie.dmac_address;
30102125Ssl147100 		break;
30112125Ssl147100 	case USB_EP_ATTR_BULK:
30122125Ssl147100 		buf_addr = uhci_get_tw_paddr_by_offs(uhcip, offset,
30132125Ssl147100 		    length, tw);
30142125Ssl147100 		break;
30152125Ssl147100 	}
30162125Ssl147100 	SetTD32(uhcip, current_td->buffer_address, buf_addr);
30170Sstevel@tonic-gate 
30180Sstevel@tonic-gate 	/*
30190Sstevel@tonic-gate 	 * Adjust the data toggle.
30200Sstevel@tonic-gate 	 * The data toggle bit must always be 0 for isoc transfers.
30210Sstevel@tonic-gate 	 * And set the "iso" bit in the TD for isoc transfers.
30220Sstevel@tonic-gate 	 */
30230Sstevel@tonic-gate 	if (UHCI_XFER_TYPE(ept) == USB_EP_ATTR_ISOCH) {
30240Sstevel@tonic-gate 		pp->pp_data_toggle = 0;
30250Sstevel@tonic-gate 		SetTD_iso(uhcip, current_td, 1);
30260Sstevel@tonic-gate 	} else {
30270Sstevel@tonic-gate 		ADJ_DATA_TOGGLE(pp);
30280Sstevel@tonic-gate 		next_td->qh_td_prev = current_td;
30290Sstevel@tonic-gate 		pp->pp_qh->td_tailp = next_td;
30300Sstevel@tonic-gate 	}
30310Sstevel@tonic-gate 
30320Sstevel@tonic-gate 	current_td->outst_td_next = NULL;
30330Sstevel@tonic-gate 	current_td->outst_td_prev = uhcip->uhci_outst_tds_tail;
30340Sstevel@tonic-gate 	if (uhcip->uhci_outst_tds_head == NULL) {
30350Sstevel@tonic-gate 		uhcip->uhci_outst_tds_head = current_td;
30360Sstevel@tonic-gate 	} else {
30370Sstevel@tonic-gate 		uhcip->uhci_outst_tds_tail->outst_td_next = current_td;
30380Sstevel@tonic-gate 	}
30390Sstevel@tonic-gate 	uhcip->uhci_outst_tds_tail = current_td;
30400Sstevel@tonic-gate 	current_td->tw = tw;
30410Sstevel@tonic-gate 
30420Sstevel@tonic-gate 	if (tw->tw_hctd_head == NULL) {
30430Sstevel@tonic-gate 		ASSERT(tw->tw_hctd_tail == NULL);
30440Sstevel@tonic-gate 		tw->tw_hctd_head = current_td;
30450Sstevel@tonic-gate 		tw->tw_hctd_tail = current_td;
30460Sstevel@tonic-gate 	} else {
30470Sstevel@tonic-gate 		/* Add the td to the end of the list */
30480Sstevel@tonic-gate 		tw->tw_hctd_tail->tw_td_next = current_td;
30490Sstevel@tonic-gate 		tw->tw_hctd_tail = current_td;
30500Sstevel@tonic-gate 	}
30510Sstevel@tonic-gate 
30520Sstevel@tonic-gate 	mutex_exit(&ph->p_usba_device->usb_mutex);
30530Sstevel@tonic-gate }
30540Sstevel@tonic-gate 
30550Sstevel@tonic-gate 
30560Sstevel@tonic-gate /*
30572125Ssl147100  * uhci_alloc_bulk_isoc_tds:
30582125Ssl147100  *	- Allocates the isoc/bulk TD pools. It will allocate one whole
30592125Ssl147100  *	  pool to store all the TDs if the system allows. Only when the
30602125Ssl147100  *	  first allocation fails, it tries to allocate several small
30612125Ssl147100  *	  pools with each pool limited in physical page size.
30622125Ssl147100  */
30632125Ssl147100 static int
uhci_alloc_bulk_isoc_tds(uhci_state_t * uhcip,uint_t num_tds,uhci_bulk_isoc_xfer_t * info)30642125Ssl147100 uhci_alloc_bulk_isoc_tds(
30652125Ssl147100 	uhci_state_t		*uhcip,
30662125Ssl147100 	uint_t			num_tds,
30672125Ssl147100 	uhci_bulk_isoc_xfer_t	*info)
30682125Ssl147100 {
30692125Ssl147100 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
30702125Ssl147100 	    "uhci_alloc_bulk_isoc_tds: num_tds: 0x%x info: 0x%p",
30716898Sfb209375 	    num_tds, (void *)info);
30722125Ssl147100 
30732125Ssl147100 	info->num_pools = 1;
30742125Ssl147100 	/* allocate as a whole pool at the first time */
30752125Ssl147100 	if (uhci_alloc_memory_for_tds(uhcip, num_tds, info) !=
30762125Ssl147100 	    USB_SUCCESS) {
30772125Ssl147100 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
30782125Ssl147100 		    "alloc_memory_for_tds failed: num_tds %d num_pools %d",
30792125Ssl147100 		    num_tds, info->num_pools);
30802125Ssl147100 
30812125Ssl147100 		/* reduce the td number per pool and alloc again */
30822125Ssl147100 		info->num_pools = num_tds / UHCI_MAX_TD_NUM_PER_POOL;
30832125Ssl147100 		if (num_tds % UHCI_MAX_TD_NUM_PER_POOL) {
30842125Ssl147100 			info->num_pools++;
30852125Ssl147100 		}
30862125Ssl147100 
30872125Ssl147100 		if (uhci_alloc_memory_for_tds(uhcip, num_tds, info) !=
30882125Ssl147100 		    USB_SUCCESS) {
30892125Ssl147100 			USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
30902125Ssl147100 			    "alloc_memory_for_tds failed: num_tds %d "
30912125Ssl147100 			    "num_pools %d", num_tds, info->num_pools);
30922125Ssl147100 
30932125Ssl147100 			return (USB_NO_RESOURCES);
30942125Ssl147100 		}
30952125Ssl147100 	}
30962125Ssl147100 
30972125Ssl147100 	return (USB_SUCCESS);
30982125Ssl147100 }
30992125Ssl147100 
31002125Ssl147100 
31012125Ssl147100 /*
31020Sstevel@tonic-gate  * uhci_alloc_memory_for_tds:
31030Sstevel@tonic-gate  *	- Allocates memory for the isoc/bulk td pools.
31040Sstevel@tonic-gate  */
31050Sstevel@tonic-gate static int
uhci_alloc_memory_for_tds(uhci_state_t * uhcip,uint_t num_tds,uhci_bulk_isoc_xfer_t * info)31060Sstevel@tonic-gate uhci_alloc_memory_for_tds(
31070Sstevel@tonic-gate 	uhci_state_t		*uhcip,
31080Sstevel@tonic-gate 	uint_t			num_tds,
31090Sstevel@tonic-gate 	uhci_bulk_isoc_xfer_t	*info)
31100Sstevel@tonic-gate {
31112125Ssl147100 	int			result, i, j, err;
31120Sstevel@tonic-gate 	size_t			real_length;
31132125Ssl147100 	uint_t			ccount, num;
31140Sstevel@tonic-gate 	ddi_device_acc_attr_t	dev_attr;
31152125Ssl147100 	uhci_bulk_isoc_td_pool_t *td_pool_ptr1, *td_pool_ptr2;
31160Sstevel@tonic-gate 
31170Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
31182125Ssl147100 	    "uhci_alloc_memory_for_tds: num_tds: 0x%x info: 0x%p "
31196898Sfb209375 	    "num_pools: %u", num_tds, (void *)info, info->num_pools);
31200Sstevel@tonic-gate 
31210Sstevel@tonic-gate 	/* The host controller will be little endian */
31220Sstevel@tonic-gate 	dev_attr.devacc_attr_version		= DDI_DEVICE_ATTR_V0;
31230Sstevel@tonic-gate 	dev_attr.devacc_attr_endian_flags	= DDI_STRUCTURE_LE_ACC;
31240Sstevel@tonic-gate 	dev_attr.devacc_attr_dataorder		= DDI_STRICTORDER_ACC;
31250Sstevel@tonic-gate 
31262125Ssl147100 	/* Allocate the TD pool structures */
31272125Ssl147100 	if ((info->td_pools = kmem_zalloc(
31282125Ssl147100 	    (sizeof (uhci_bulk_isoc_td_pool_t) * info->num_pools),
31292125Ssl147100 	    KM_SLEEP)) == NULL) {
31302125Ssl147100 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
31312125Ssl147100 		    "uhci_alloc_memory_for_tds: alloc td_pools failed");
31320Sstevel@tonic-gate 
31330Sstevel@tonic-gate 		return (USB_FAILURE);
31340Sstevel@tonic-gate 	}
31350Sstevel@tonic-gate 
31362125Ssl147100 	for (i = 0; i < info->num_pools; i++) {
31372125Ssl147100 		if (info->num_pools == 1) {
31382125Ssl147100 			num = num_tds;
31392125Ssl147100 		} else if (i < (info->num_pools - 1)) {
31402125Ssl147100 			num = UHCI_MAX_TD_NUM_PER_POOL;
31412125Ssl147100 		} else {
31422125Ssl147100 			num = (num_tds % UHCI_MAX_TD_NUM_PER_POOL);
31432125Ssl147100 		}
31442125Ssl147100 
31452125Ssl147100 		td_pool_ptr1 = &info->td_pools[i];
31462125Ssl147100 
31472125Ssl147100 		/* Allocate the bulk TD pool DMA handle */
31482125Ssl147100 		if (ddi_dma_alloc_handle(uhcip->uhci_dip,
31492125Ssl147100 		    &uhcip->uhci_dma_attr, DDI_DMA_SLEEP, 0,
31502125Ssl147100 		    &td_pool_ptr1->dma_handle) != DDI_SUCCESS) {
31512125Ssl147100 
31522125Ssl147100 			for (j = 0; j < i; j++) {
31532125Ssl147100 				td_pool_ptr2 = &info->td_pools[j];
31542125Ssl147100 				result = ddi_dma_unbind_handle(
31552125Ssl147100 				    td_pool_ptr2->dma_handle);
31562125Ssl147100 				ASSERT(result == DDI_SUCCESS);
31572125Ssl147100 				ddi_dma_mem_free(&td_pool_ptr2->mem_handle);
31582125Ssl147100 				ddi_dma_free_handle(&td_pool_ptr2->dma_handle);
31592125Ssl147100 			}
31602125Ssl147100 
31612125Ssl147100 			kmem_free(info->td_pools,
31622125Ssl147100 			    (sizeof (uhci_bulk_isoc_td_pool_t) *
31632125Ssl147100 			    info->num_pools));
31642125Ssl147100 
31652125Ssl147100 			return (USB_FAILURE);
31662125Ssl147100 		}
31672125Ssl147100 
31682125Ssl147100 		/* Allocate the memory for the bulk TD pool */
31692125Ssl147100 		if (ddi_dma_mem_alloc(td_pool_ptr1->dma_handle,
31702125Ssl147100 		    num * sizeof (uhci_td_t), &dev_attr,
31712125Ssl147100 		    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
31722125Ssl147100 		    &td_pool_ptr1->pool_addr, &real_length,
31732125Ssl147100 		    &td_pool_ptr1->mem_handle) != DDI_SUCCESS) {
31742125Ssl147100 
31752125Ssl147100 			ddi_dma_free_handle(&td_pool_ptr1->dma_handle);
31762125Ssl147100 
31772125Ssl147100 			for (j = 0; j < i; j++) {
31782125Ssl147100 				td_pool_ptr2 = &info->td_pools[j];
31792125Ssl147100 				result = ddi_dma_unbind_handle(
31802125Ssl147100 				    td_pool_ptr2->dma_handle);
31812125Ssl147100 				ASSERT(result == DDI_SUCCESS);
31822125Ssl147100 				ddi_dma_mem_free(&td_pool_ptr2->mem_handle);
31832125Ssl147100 				ddi_dma_free_handle(&td_pool_ptr2->dma_handle);
31842125Ssl147100 			}
31852125Ssl147100 
31862125Ssl147100 			kmem_free(info->td_pools,
31872125Ssl147100 			    (sizeof (uhci_bulk_isoc_td_pool_t) *
31882125Ssl147100 			    info->num_pools));
31890Sstevel@tonic-gate 
31900Sstevel@tonic-gate 			return (USB_FAILURE);
31910Sstevel@tonic-gate 		}
31922125Ssl147100 
31932125Ssl147100 		/* Map the bulk TD pool into the I/O address space */
31942125Ssl147100 		result = ddi_dma_addr_bind_handle(td_pool_ptr1->dma_handle,
31952125Ssl147100 		    NULL, (caddr_t)td_pool_ptr1->pool_addr, real_length,
31962125Ssl147100 		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
31972125Ssl147100 		    &td_pool_ptr1->cookie, &ccount);
31982125Ssl147100 
31992125Ssl147100 		/* Process the result */
32002125Ssl147100 		err = USB_SUCCESS;
32012125Ssl147100 
32022125Ssl147100 		if (result != DDI_DMA_MAPPED) {
32032125Ssl147100 			USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
32042125Ssl147100 			    "uhci_allocate_memory_for_tds: Result = %d",
32052125Ssl147100 			    result);
32062125Ssl147100 			uhci_decode_ddi_dma_addr_bind_handle_result(uhcip,
32072125Ssl147100 			    result);
32082125Ssl147100 
32092125Ssl147100 			err = USB_FAILURE;
32102125Ssl147100 		}
32112125Ssl147100 
32122125Ssl147100 		if ((result == DDI_DMA_MAPPED) && (ccount != 1)) {
32132125Ssl147100 			/* The cookie count should be 1 */
32142125Ssl147100 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
32152125Ssl147100 			    uhcip->uhci_log_hdl,
32162125Ssl147100 			    "uhci_allocate_memory_for_tds: "
32172125Ssl147100 			    "More than 1 cookie");
32182125Ssl147100 
32192125Ssl147100 			result = ddi_dma_unbind_handle(
32202125Ssl147100 			    td_pool_ptr1->dma_handle);
32212125Ssl147100 			ASSERT(result == DDI_SUCCESS);
32222125Ssl147100 
32232125Ssl147100 			err = USB_FAILURE;
32242125Ssl147100 		}
32252125Ssl147100 
32262125Ssl147100 		if (err == USB_FAILURE) {
32272125Ssl147100 
32282125Ssl147100 			ddi_dma_mem_free(&td_pool_ptr1->mem_handle);
32292125Ssl147100 			ddi_dma_free_handle(&td_pool_ptr1->dma_handle);
32302125Ssl147100 
32312125Ssl147100 			for (j = 0; j < i; j++) {
32322125Ssl147100 				td_pool_ptr2 = &info->td_pools[j];
32332125Ssl147100 				result = ddi_dma_unbind_handle(
32342125Ssl147100 				    td_pool_ptr2->dma_handle);
32352125Ssl147100 				ASSERT(result == DDI_SUCCESS);
32362125Ssl147100 				ddi_dma_mem_free(&td_pool_ptr2->mem_handle);
32372125Ssl147100 				ddi_dma_free_handle(&td_pool_ptr2->dma_handle);
32382125Ssl147100 			}
32392125Ssl147100 
32402125Ssl147100 			kmem_free(info->td_pools,
32412125Ssl147100 			    (sizeof (uhci_bulk_isoc_td_pool_t) *
32422125Ssl147100 			    info->num_pools));
32432125Ssl147100 
32442125Ssl147100 			return (USB_FAILURE);
32452125Ssl147100 		}
32462125Ssl147100 
32472125Ssl147100 		bzero((void *)td_pool_ptr1->pool_addr,
32482125Ssl147100 		    num * sizeof (uhci_td_t));
32497492SZhigang.Lu@Sun.COM 		td_pool_ptr1->num_tds = (ushort_t)num;
32500Sstevel@tonic-gate 	}
32510Sstevel@tonic-gate 
32520Sstevel@tonic-gate 	return (USB_SUCCESS);
32530Sstevel@tonic-gate }
32540Sstevel@tonic-gate 
32550Sstevel@tonic-gate 
32560Sstevel@tonic-gate /*
32570Sstevel@tonic-gate  * uhci_handle_bulk_td:
32580Sstevel@tonic-gate  *
32590Sstevel@tonic-gate  *	Handles the completed bulk transfer descriptors
32600Sstevel@tonic-gate  */
32610Sstevel@tonic-gate void
uhci_handle_bulk_td(uhci_state_t * uhcip,uhci_td_t * td)32620Sstevel@tonic-gate uhci_handle_bulk_td(uhci_state_t *uhcip, uhci_td_t *td)
32630Sstevel@tonic-gate {
32642125Ssl147100 	uint_t			num_bulk_tds, index, td_count, j;
32650Sstevel@tonic-gate 	usb_cr_t		error;
32660Sstevel@tonic-gate 	uint_t			length, bytes_xfered;
32670Sstevel@tonic-gate 	ushort_t		MaxPacketSize;
32682125Ssl147100 	uint32_t		buf_offs, paddr;
32690Sstevel@tonic-gate 	uhci_td_t		*bulk_td_ptr, *current_dummy, *td_head;
32702125Ssl147100 	uhci_td_t		*tmp_td;
32710Sstevel@tonic-gate 	queue_head_t		*qh, *next_qh;
32720Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw = td->tw;
32730Sstevel@tonic-gate 	uhci_pipe_private_t	*pp = tw->tw_pipe_private;
32740Sstevel@tonic-gate 	uhci_bulk_isoc_xfer_t	*bulk_xfer_info;
32752125Ssl147100 	uhci_bulk_isoc_td_pool_t *td_pool_ptr;
32760Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph;
32770Sstevel@tonic-gate 
32780Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
32796898Sfb209375 	    "uhci_handle_bulk_td: td = 0x%p tw = 0x%p", (void *)td, (void *)tw);
32800Sstevel@tonic-gate 
32810Sstevel@tonic-gate 	/*
32820Sstevel@tonic-gate 	 * Update the tw_bytes_pending, and tw_bytes_xfered
32830Sstevel@tonic-gate 	 */
32840Sstevel@tonic-gate 	bytes_xfered = ZERO_LENGTH;
32850Sstevel@tonic-gate 
32860Sstevel@tonic-gate 	/*
32870Sstevel@tonic-gate 	 * Check whether there are any errors occurred in the xfer.
32880Sstevel@tonic-gate 	 * If so, update the data_toggle for the queue head and
32890Sstevel@tonic-gate 	 * return error to the upper layer.
32900Sstevel@tonic-gate 	 */
32910Sstevel@tonic-gate 	if (GetTD_status(uhcip, td) & TD_STATUS_MASK) {
32920Sstevel@tonic-gate 		uhci_handle_bulk_td_errors(uhcip, td);
32930Sstevel@tonic-gate 
32940Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
32950Sstevel@tonic-gate 		    "uhci_handle_bulk_td: error; data toggle: 0x%x",
32960Sstevel@tonic-gate 		    pp->pp_data_toggle);
32970Sstevel@tonic-gate 
32980Sstevel@tonic-gate 		return;
32990Sstevel@tonic-gate 	}
33000Sstevel@tonic-gate 
33010Sstevel@tonic-gate 	/*
33020Sstevel@tonic-gate 	 * Update the tw_bytes_pending, and tw_bytes_xfered
33030Sstevel@tonic-gate 	 */
33040Sstevel@tonic-gate 	bytes_xfered = GetTD_alen(uhcip, td);
33050Sstevel@tonic-gate 	if (bytes_xfered != ZERO_LENGTH) {
33060Sstevel@tonic-gate 		tw->tw_bytes_pending -= (bytes_xfered + 1);
33070Sstevel@tonic-gate 		tw->tw_bytes_xfered  += (bytes_xfered + 1);
33080Sstevel@tonic-gate 	}
33090Sstevel@tonic-gate 
33100Sstevel@tonic-gate 	/*
33110Sstevel@tonic-gate 	 * Get Bulk pipe information and pipe handle
33120Sstevel@tonic-gate 	 */
33130Sstevel@tonic-gate 	bulk_xfer_info	= pp->pp_qh->bulk_xfer_info;
33140Sstevel@tonic-gate 	ph = tw->tw_pipe_private->pp_pipe_handle;
33150Sstevel@tonic-gate 
33160Sstevel@tonic-gate 	/*
33170Sstevel@tonic-gate 	 * Check whether data underrun occurred.
33180Sstevel@tonic-gate 	 * If so, complete the transfer
33190Sstevel@tonic-gate 	 * Update the data toggle bit
33200Sstevel@tonic-gate 	 */
33210Sstevel@tonic-gate 	if (bytes_xfered != GetTD_mlen(uhcip, td)) {
33220Sstevel@tonic-gate 		bulk_xfer_info->num_tds = 1;
33230Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
33240Sstevel@tonic-gate 		    "uhci_handle_bulk_td: Data underrun occured");
33250Sstevel@tonic-gate 
33260Sstevel@tonic-gate 		pp->pp_data_toggle = GetTD_dtogg(uhcip, td) == 0 ? 1 : 0;
33270Sstevel@tonic-gate 	}
33280Sstevel@tonic-gate 
33290Sstevel@tonic-gate 	/*
33300Sstevel@tonic-gate 	 * If the TD's in the current frame are completed, then check
33310Sstevel@tonic-gate 	 * whether we have any more bytes to xfer. If so, insert TD's.
33320Sstevel@tonic-gate 	 * If no more bytes needs to be transferred, then do callback to the
33330Sstevel@tonic-gate 	 * upper layer.
33340Sstevel@tonic-gate 	 * If the TD's in the current frame are not completed, then
33350Sstevel@tonic-gate 	 * just delete the TD from the linked lists.
33360Sstevel@tonic-gate 	 */
33370Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
33380Sstevel@tonic-gate 	    "uhci_handle_bulk_td: completed TD data toggle: 0x%x",
33390Sstevel@tonic-gate 	    GetTD_dtogg(uhcip, td));
33400Sstevel@tonic-gate 
33410Sstevel@tonic-gate 	if (--bulk_xfer_info->num_tds == 0) {
33420Sstevel@tonic-gate 		uhci_delete_td(uhcip, td);
33430Sstevel@tonic-gate 
33440Sstevel@tonic-gate 		if ((tw->tw_bytes_pending) &&
33450Sstevel@tonic-gate 		    (GetTD_mlen(uhcip, td) - GetTD_alen(uhcip, td) == 0)) {
33460Sstevel@tonic-gate 
33470Sstevel@tonic-gate 			MaxPacketSize = pp->pp_pipe_handle->p_ep.wMaxPacketSize;
33480Sstevel@tonic-gate 			length = MaxPacketSize;
33490Sstevel@tonic-gate 
33500Sstevel@tonic-gate 			qh = pp->pp_qh;
33510Sstevel@tonic-gate 			paddr = GetQH32(uhcip, qh->link_ptr) & QH_LINK_PTR_MASK;
33520Sstevel@tonic-gate 			if (GetQH32(uhcip, qh->link_ptr) !=
33530Sstevel@tonic-gate 			    GetQH32(uhcip,
33545773Sqz150045 			    uhcip->uhci_bulk_xfers_q_head->link_ptr)) {
33550Sstevel@tonic-gate 				next_qh = QH_VADDR(paddr);
33560Sstevel@tonic-gate 				SetQH32(uhcip, qh->prev_qh->link_ptr,
33570Sstevel@tonic-gate 				    paddr|(0x2));
33580Sstevel@tonic-gate 				next_qh->prev_qh = qh->prev_qh;
33590Sstevel@tonic-gate 				SetQH32(uhcip, qh->link_ptr,
33600Sstevel@tonic-gate 				    GetQH32(uhcip,
33610Sstevel@tonic-gate 				    uhcip->uhci_bulk_xfers_q_head->link_ptr));
33620Sstevel@tonic-gate 				qh->prev_qh = uhcip->uhci_bulk_xfers_q_tail;
33630Sstevel@tonic-gate 				SetQH32(uhcip,
33640Sstevel@tonic-gate 				    uhcip->uhci_bulk_xfers_q_tail->link_ptr,
33650Sstevel@tonic-gate 				    QH_PADDR(qh) | 0x2);
33660Sstevel@tonic-gate 				uhcip->uhci_bulk_xfers_q_tail = qh;
33670Sstevel@tonic-gate 			}
33680Sstevel@tonic-gate 
33690Sstevel@tonic-gate 			if ((tw->tw_bytes_pending / MaxPacketSize) >=
33700Sstevel@tonic-gate 			    MAX_NUM_BULK_TDS_PER_XFER) {
33710Sstevel@tonic-gate 				num_bulk_tds = MAX_NUM_BULK_TDS_PER_XFER;
33720Sstevel@tonic-gate 			} else {
33730Sstevel@tonic-gate 				num_bulk_tds =
33745773Sqz150045 				    (tw->tw_bytes_pending / MaxPacketSize);
33750Sstevel@tonic-gate 				if (tw->tw_bytes_pending % MaxPacketSize) {
33760Sstevel@tonic-gate 					num_bulk_tds++;
33770Sstevel@tonic-gate 					length = (tw->tw_bytes_pending %
33785773Sqz150045 					    MaxPacketSize);
33790Sstevel@tonic-gate 				}
33800Sstevel@tonic-gate 			}
33810Sstevel@tonic-gate 
33820Sstevel@tonic-gate 			current_dummy = pp->pp_qh->td_tailp;
33832125Ssl147100 			td_pool_ptr = &bulk_xfer_info->td_pools[0];
33842125Ssl147100 			bulk_td_ptr = (uhci_td_t *)td_pool_ptr->pool_addr;
33852125Ssl147100 			buf_offs = tw->tw_bytes_xfered;
33862125Ssl147100 			td_count = num_bulk_tds;
33872125Ssl147100 			index = 0;
33882125Ssl147100 
33892125Ssl147100 			/* reuse the TDs to transfer more data */
33902125Ssl147100 			while (td_count > 0) {
33912125Ssl147100 				for (j = 0;
33922125Ssl147100 				    (j < (td_pool_ptr->num_tds - 1)) &&
33932125Ssl147100 				    (td_count > 1); j++, td_count--) {
33942125Ssl147100 					uhci_fill_in_bulk_isoc_td(uhcip,
33952125Ssl147100 					    &bulk_td_ptr[j], &bulk_td_ptr[j+1],
33962125Ssl147100 					    BULKTD_PADDR(td_pool_ptr,
33972125Ssl147100 					    &bulk_td_ptr[j+1]), ph, buf_offs,
33982125Ssl147100 					    MaxPacketSize, tw);
33992125Ssl147100 					buf_offs += MaxPacketSize;
34002125Ssl147100 				}
34012125Ssl147100 
34022125Ssl147100 				if (td_count == 1) {
34032125Ssl147100 					uhci_fill_in_bulk_isoc_td(uhcip,
34042125Ssl147100 					    &bulk_td_ptr[j], current_dummy,
34052125Ssl147100 					    TD_PADDR(current_dummy), ph,
34062125Ssl147100 					    buf_offs, length, tw);
34072125Ssl147100 
34082125Ssl147100 					break;
34092125Ssl147100 				} else {
34102125Ssl147100 					tmp_td = &bulk_td_ptr[j];
34112125Ssl147100 					ASSERT(index <
34122125Ssl147100 					    (bulk_xfer_info->num_pools - 1));
34132125Ssl147100 					td_pool_ptr = &bulk_xfer_info->
34142125Ssl147100 					    td_pools[index + 1];
34152125Ssl147100 					bulk_td_ptr = (uhci_td_t *)
34162125Ssl147100 					    td_pool_ptr->pool_addr;
34172125Ssl147100 					uhci_fill_in_bulk_isoc_td(uhcip,
34182125Ssl147100 					    tmp_td, &bulk_td_ptr[0],
34192125Ssl147100 					    BULKTD_PADDR(td_pool_ptr,
34202125Ssl147100 					    &bulk_td_ptr[0]), ph, buf_offs,
34212125Ssl147100 					    MaxPacketSize, tw);
34222125Ssl147100 					buf_offs += MaxPacketSize;
34232125Ssl147100 					td_count--;
34242125Ssl147100 					index++;
34252125Ssl147100 				}
34260Sstevel@tonic-gate 			}
34270Sstevel@tonic-gate 
34280Sstevel@tonic-gate 			pp->pp_qh->bulk_xfer_info = bulk_xfer_info;
34297492SZhigang.Lu@Sun.COM 			bulk_xfer_info->num_tds	= (ushort_t)num_bulk_tds;
34300Sstevel@tonic-gate 			SetQH32(uhcip, pp->pp_qh->element_ptr,
34312125Ssl147100 			    bulk_xfer_info->td_pools[0].cookie.dmac_address);
34320Sstevel@tonic-gate 		} else {
34330Sstevel@tonic-gate 			usba_pipe_handle_data_t *usb_pp = pp->pp_pipe_handle;
34340Sstevel@tonic-gate 
34350Sstevel@tonic-gate 			pp->pp_qh->bulk_xfer_info = NULL;
34360Sstevel@tonic-gate 
34370Sstevel@tonic-gate 			if (tw->tw_bytes_pending) {
34380Sstevel@tonic-gate 				/* Update the element pointer */
34390Sstevel@tonic-gate 				SetQH32(uhcip, pp->pp_qh->element_ptr,
34405773Sqz150045 				    TD_PADDR(pp->pp_qh->td_tailp));
34410Sstevel@tonic-gate 
34420Sstevel@tonic-gate 				/* Remove all the tds */
34430Sstevel@tonic-gate 				td_head = tw->tw_hctd_head;
34440Sstevel@tonic-gate 				while (td_head != NULL) {
34450Sstevel@tonic-gate 					uhci_delete_td(uhcip, td_head);
34460Sstevel@tonic-gate 					td_head = tw->tw_hctd_head;
34470Sstevel@tonic-gate 				}
34480Sstevel@tonic-gate 			}
34490Sstevel@tonic-gate 
34500Sstevel@tonic-gate 			if (tw->tw_direction == PID_IN) {
34510Sstevel@tonic-gate 				usb_req_attrs_t	attrs = ((usb_bulk_req_t *)
34525773Sqz150045 				    tw->tw_curr_xfer_reqp)->bulk_attributes;
34530Sstevel@tonic-gate 
34540Sstevel@tonic-gate 				error = USB_CR_OK;
34550Sstevel@tonic-gate 
34560Sstevel@tonic-gate 				/* Data run occurred */
34570Sstevel@tonic-gate 				if (tw->tw_bytes_pending &&
34580Sstevel@tonic-gate 				    (!(attrs & USB_ATTRS_SHORT_XFER_OK))) {
34590Sstevel@tonic-gate 					error = USB_CR_DATA_UNDERRUN;
34600Sstevel@tonic-gate 				}
34610Sstevel@tonic-gate 
34620Sstevel@tonic-gate 				uhci_sendup_td_message(uhcip, error, tw);
34630Sstevel@tonic-gate 			} else {
34640Sstevel@tonic-gate 				uhci_do_byte_stats(uhcip, tw->tw_length,
34650Sstevel@tonic-gate 				    usb_pp->p_ep.bmAttributes,
34660Sstevel@tonic-gate 				    usb_pp->p_ep.bEndpointAddress);
34670Sstevel@tonic-gate 
34680Sstevel@tonic-gate 				/* Data underrun occurred */
34690Sstevel@tonic-gate 				if (tw->tw_bytes_pending) {
34700Sstevel@tonic-gate 
34710Sstevel@tonic-gate 					tw->tw_data->b_rptr +=
34725773Sqz150045 					    tw->tw_bytes_xfered;
34730Sstevel@tonic-gate 
34740Sstevel@tonic-gate 					USB_DPRINTF_L2(PRINT_MASK_ATTA,
34750Sstevel@tonic-gate 					    uhcip->uhci_log_hdl,
34760Sstevel@tonic-gate 					    "uhci_handle_bulk_td: "
34770Sstevel@tonic-gate 					    "data underrun occurred");
34780Sstevel@tonic-gate 
34790Sstevel@tonic-gate 					uhci_hcdi_callback(uhcip, pp,
34800Sstevel@tonic-gate 					    tw->tw_pipe_private->pp_pipe_handle,
34810Sstevel@tonic-gate 					    tw, USB_CR_DATA_UNDERRUN);
34820Sstevel@tonic-gate 				} else {
34830Sstevel@tonic-gate 					uhci_hcdi_callback(uhcip, pp,
34840Sstevel@tonic-gate 					    tw->tw_pipe_private->pp_pipe_handle,
34850Sstevel@tonic-gate 					    tw, USB_CR_OK);
34860Sstevel@tonic-gate 				}
34870Sstevel@tonic-gate 			} /* direction */
34880Sstevel@tonic-gate 
34890Sstevel@tonic-gate 			/* Deallocate DMA memory */
34900Sstevel@tonic-gate 			uhci_deallocate_tw(uhcip, pp, tw);
34912125Ssl147100 			for (j = 0; j < bulk_xfer_info->num_pools; j++) {
34922125Ssl147100 				td_pool_ptr = &bulk_xfer_info->td_pools[j];
34932125Ssl147100 				(void) ddi_dma_unbind_handle(
34942125Ssl147100 				    td_pool_ptr->dma_handle);
34952125Ssl147100 				ddi_dma_mem_free(&td_pool_ptr->mem_handle);
34962125Ssl147100 				ddi_dma_free_handle(&td_pool_ptr->dma_handle);
34972125Ssl147100 			}
34982125Ssl147100 			kmem_free(bulk_xfer_info->td_pools,
34992125Ssl147100 			    (sizeof (uhci_bulk_isoc_td_pool_t) *
35002125Ssl147100 			    bulk_xfer_info->num_pools));
35010Sstevel@tonic-gate 			kmem_free(bulk_xfer_info,
35020Sstevel@tonic-gate 			    sizeof (uhci_bulk_isoc_xfer_t));
35030Sstevel@tonic-gate 
35040Sstevel@tonic-gate 			/*
35050Sstevel@tonic-gate 			 * When there are no pending bulk commands, point the
35060Sstevel@tonic-gate 			 * end of the lattice tree to NULL. This will make sure
35070Sstevel@tonic-gate 			 * that the HC control does not loop anymore and PCI
35080Sstevel@tonic-gate 			 * bus is not affected.
35090Sstevel@tonic-gate 			 */
35100Sstevel@tonic-gate 			if (--uhcip->uhci_pending_bulk_cmds == 0) {
35110Sstevel@tonic-gate 				uhcip->uhci_bulk_xfers_q_tail->link_ptr =
35120Sstevel@tonic-gate 				    HC_END_OF_LIST;
35130Sstevel@tonic-gate 				USB_DPRINTF_L3(PRINT_MASK_ATTA,
35140Sstevel@tonic-gate 				    uhcip->uhci_log_hdl,
35150Sstevel@tonic-gate 				    "uhci_handle_bulk_td: count = %d",
35160Sstevel@tonic-gate 				    uhcip->uhci_pending_bulk_cmds);
35170Sstevel@tonic-gate 			}
35180Sstevel@tonic-gate 		}
35190Sstevel@tonic-gate 	} else {
35200Sstevel@tonic-gate 		uhci_delete_td(uhcip, td);
35210Sstevel@tonic-gate 	}
35220Sstevel@tonic-gate }
35230Sstevel@tonic-gate 
35240Sstevel@tonic-gate 
35250Sstevel@tonic-gate void
uhci_handle_bulk_td_errors(uhci_state_t * uhcip,uhci_td_t * td)35260Sstevel@tonic-gate uhci_handle_bulk_td_errors(uhci_state_t *uhcip, uhci_td_t *td)
35270Sstevel@tonic-gate {
35280Sstevel@tonic-gate 	usb_cr_t		usb_err;
35292125Ssl147100 	uint32_t		paddr_tail, element_ptr, paddr;
35300Sstevel@tonic-gate 	uhci_td_t		*next_td;
35310Sstevel@tonic-gate 	uhci_pipe_private_t	*pp;
35320Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw = td->tw;
35330Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph;
35342125Ssl147100 	uhci_bulk_isoc_td_pool_t *td_pool_ptr = NULL;
35350Sstevel@tonic-gate 
35360Sstevel@tonic-gate 	USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
35370Sstevel@tonic-gate 	    "uhci_handle_bulk_td_errors: td = %p", (void *)td);
35380Sstevel@tonic-gate 
35390Sstevel@tonic-gate #ifdef	DEBUG
35400Sstevel@tonic-gate 	uhci_print_td(uhcip, td);
35410Sstevel@tonic-gate #endif
35420Sstevel@tonic-gate 
35430Sstevel@tonic-gate 	tw = td->tw;
35440Sstevel@tonic-gate 	ph = tw->tw_pipe_private->pp_pipe_handle;
35450Sstevel@tonic-gate 	pp = (uhci_pipe_private_t *)ph->p_hcd_private;
35460Sstevel@tonic-gate 
35470Sstevel@tonic-gate 	/*
35480Sstevel@tonic-gate 	 * Find the type of error occurred and return the error
35490Sstevel@tonic-gate 	 * to the upper layer. And adjust the data toggle.
35500Sstevel@tonic-gate 	 */
35510Sstevel@tonic-gate 	element_ptr = GetQH32(uhcip, pp->pp_qh->element_ptr) &
35520Sstevel@tonic-gate 	    QH_ELEMENT_PTR_MASK;
35530Sstevel@tonic-gate 	paddr_tail = TD_PADDR(pp->pp_qh->td_tailp);
35540Sstevel@tonic-gate 
35550Sstevel@tonic-gate 	/*
35560Sstevel@tonic-gate 	 * If a timeout occurs before a transfer has completed,
35570Sstevel@tonic-gate 	 * the timeout handler sets the CRC/Timeout bit and clears the Active
35580Sstevel@tonic-gate 	 * bit in the link_ptr for each td in the transfer.
35590Sstevel@tonic-gate 	 * It then waits (at least) 1 ms so that any tds the controller might
35600Sstevel@tonic-gate 	 * have been executing will have completed.
35610Sstevel@tonic-gate 	 * So at this point element_ptr will point to either:
35620Sstevel@tonic-gate 	 * 1) the next td for the transfer (which has not been executed,
35630Sstevel@tonic-gate 	 * and has the CRC/Timeout status bit set and Active bit cleared),
35640Sstevel@tonic-gate 	 * 2) the dummy td for this qh.
35650Sstevel@tonic-gate 	 * So if the element_ptr does not point to the dummy td, we know
35660Sstevel@tonic-gate 	 * it points to the next td that would have been executed.
35670Sstevel@tonic-gate 	 * That td has the data toggle we want to save.
35680Sstevel@tonic-gate 	 * All outstanding tds have been marked as CRC/Timeout,
35690Sstevel@tonic-gate 	 * so it doesn't matter which td we pass to uhci_parse_td_error
35700Sstevel@tonic-gate 	 * for the error status.
35710Sstevel@tonic-gate 	 */
35720Sstevel@tonic-gate 	if (element_ptr != paddr_tail) {
35732125Ssl147100 		paddr = (element_ptr & QH_ELEMENT_PTR_MASK);
35742125Ssl147100 		uhci_get_bulk_td_by_paddr(uhcip, pp->pp_qh->bulk_xfer_info,
35752125Ssl147100 		    paddr, &td_pool_ptr);
35762125Ssl147100 		next_td = BULKTD_VADDR(td_pool_ptr, paddr);
35770Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
35780Sstevel@tonic-gate 		    "uhci_handle_bulk_td_errors: next td = %p",
35790Sstevel@tonic-gate 		    (void *)next_td);
35800Sstevel@tonic-gate 
35810Sstevel@tonic-gate 		usb_err = uhci_parse_td_error(uhcip, pp, next_td);
35820Sstevel@tonic-gate 	} else {
35830Sstevel@tonic-gate 		usb_err = uhci_parse_td_error(uhcip, pp, td);
35840Sstevel@tonic-gate 	}
35850Sstevel@tonic-gate 
35860Sstevel@tonic-gate 	/*
35870Sstevel@tonic-gate 	 * Update the link pointer.
35880Sstevel@tonic-gate 	 */
35890Sstevel@tonic-gate 	SetQH32(uhcip, pp->pp_qh->element_ptr, TD_PADDR(pp->pp_qh->td_tailp));
35900Sstevel@tonic-gate 
35910Sstevel@tonic-gate 	/*
35920Sstevel@tonic-gate 	 * Send up number of bytes transferred before the error condition.
35930Sstevel@tonic-gate 	 */
35940Sstevel@tonic-gate 	if ((tw->tw_direction == PID_OUT) && tw->tw_data) {
35950Sstevel@tonic-gate 		tw->tw_data->b_rptr += tw->tw_bytes_xfered;
35960Sstevel@tonic-gate 	}
35970Sstevel@tonic-gate 
35980Sstevel@tonic-gate 	uhci_remove_bulk_tds_tws(uhcip, tw->tw_pipe_private, UHCI_IN_ERROR);
35990Sstevel@tonic-gate 
36000Sstevel@tonic-gate 	/*
36010Sstevel@tonic-gate 	 * When there  are no pending bulk commands, point the end of the
36020Sstevel@tonic-gate 	 * lattice tree to NULL. This will make sure that the  HC control
36030Sstevel@tonic-gate 	 * does not loop anymore and PCI bus is not affected.
36040Sstevel@tonic-gate 	 */
36050Sstevel@tonic-gate 	if (--uhcip->uhci_pending_bulk_cmds == 0) {
36060Sstevel@tonic-gate 		uhcip->uhci_bulk_xfers_q_tail->link_ptr = HC_END_OF_LIST;
36070Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
36080Sstevel@tonic-gate 		    "uhci_handle_bulk_td_errors: count = %d",
36090Sstevel@tonic-gate 		    uhcip->uhci_pending_bulk_cmds);
36100Sstevel@tonic-gate 	}
36110Sstevel@tonic-gate 
36120Sstevel@tonic-gate 	uhci_hcdi_callback(uhcip, pp, ph, tw, usb_err);
36130Sstevel@tonic-gate 	uhci_deallocate_tw(uhcip, pp, tw);
36140Sstevel@tonic-gate }
36150Sstevel@tonic-gate 
36160Sstevel@tonic-gate 
36172125Ssl147100 /*
36182125Ssl147100  * uhci_get_bulk_td_by_paddr:
36192125Ssl147100  *	Obtain the address of the TD pool the physical address falls in.
36202125Ssl147100  *
36212125Ssl147100  * td_pool_pp - pointer to the address of the TD pool containing the paddr
36222125Ssl147100  */
36232125Ssl147100 /* ARGSUSED */
36242125Ssl147100 static void
uhci_get_bulk_td_by_paddr(uhci_state_t * uhcip,uhci_bulk_isoc_xfer_t * info,uint32_t paddr,uhci_bulk_isoc_td_pool_t ** td_pool_pp)36252125Ssl147100 uhci_get_bulk_td_by_paddr(
36262125Ssl147100 	uhci_state_t			*uhcip,
36272125Ssl147100 	uhci_bulk_isoc_xfer_t		*info,
36282125Ssl147100 	uint32_t			paddr,
36292125Ssl147100 	uhci_bulk_isoc_td_pool_t	**td_pool_pp)
36302125Ssl147100 {
36312125Ssl147100 	uint_t				i = 0;
36322125Ssl147100 
36332125Ssl147100 	while (i < info->num_pools) {
36342125Ssl147100 		*td_pool_pp = &info->td_pools[i];
36352125Ssl147100 		if (((*td_pool_pp)->cookie.dmac_address <= paddr) &&
36362125Ssl147100 		    (((*td_pool_pp)->cookie.dmac_address +
36372125Ssl147100 		    (*td_pool_pp)->cookie.dmac_size) > paddr)) {
36382125Ssl147100 
36392125Ssl147100 			break;
36402125Ssl147100 		}
36412125Ssl147100 		i++;
36422125Ssl147100 	}
36432125Ssl147100 
36442125Ssl147100 	ASSERT(i < info->num_pools);
36452125Ssl147100 }
36462125Ssl147100 
36472125Ssl147100 
36480Sstevel@tonic-gate void
uhci_remove_bulk_tds_tws(uhci_state_t * uhcip,uhci_pipe_private_t * pp,int what)36490Sstevel@tonic-gate uhci_remove_bulk_tds_tws(
36500Sstevel@tonic-gate 	uhci_state_t		*uhcip,
36510Sstevel@tonic-gate 	uhci_pipe_private_t	*pp,
36520Sstevel@tonic-gate 	int			what)
36530Sstevel@tonic-gate {
36542125Ssl147100 	uint_t			rval, i;
36550Sstevel@tonic-gate 	uhci_td_t		*head;
36560Sstevel@tonic-gate 	uhci_td_t		*head_next;
36570Sstevel@tonic-gate 	usb_opaque_t		curr_reqp;
36580Sstevel@tonic-gate 	uhci_bulk_isoc_xfer_t	*info;
36592125Ssl147100 	uhci_bulk_isoc_td_pool_t *td_pool_ptr;
36600Sstevel@tonic-gate 
36610Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
36620Sstevel@tonic-gate 
36630Sstevel@tonic-gate 	if ((info = pp->pp_qh->bulk_xfer_info) == NULL) {
36640Sstevel@tonic-gate 
36650Sstevel@tonic-gate 		return;
36660Sstevel@tonic-gate 	}
36670Sstevel@tonic-gate 
36680Sstevel@tonic-gate 	head = uhcip->uhci_outst_tds_head;
36690Sstevel@tonic-gate 
36700Sstevel@tonic-gate 	while (head) {
36710Sstevel@tonic-gate 		uhci_trans_wrapper_t *tw_tmp = head->tw;
36720Sstevel@tonic-gate 		head_next = head->outst_td_next;
36730Sstevel@tonic-gate 
36740Sstevel@tonic-gate 		if (pp->pp_qh == tw_tmp->tw_pipe_private->pp_qh) {
36750Sstevel@tonic-gate 			curr_reqp = tw_tmp->tw_curr_xfer_reqp;
36760Sstevel@tonic-gate 			if (curr_reqp &&
36770Sstevel@tonic-gate 			    ((what == UHCI_IN_CLOSE) ||
36780Sstevel@tonic-gate 			    (what == UHCI_IN_RESET))) {
36790Sstevel@tonic-gate 				uhci_hcdi_callback(uhcip, pp,
36800Sstevel@tonic-gate 				    pp->pp_pipe_handle,
36810Sstevel@tonic-gate 				    tw_tmp, USB_CR_FLUSHED);
36820Sstevel@tonic-gate 			} /* end of curr_reqp */
36830Sstevel@tonic-gate 
36840Sstevel@tonic-gate 			uhci_delete_td(uhcip, head);
36850Sstevel@tonic-gate 
36860Sstevel@tonic-gate 			if (what == UHCI_IN_CLOSE || what == UHCI_IN_RESET) {
36870Sstevel@tonic-gate 				ASSERT(info->num_tds > 0);
36880Sstevel@tonic-gate 				if (--info->num_tds == 0) {
36890Sstevel@tonic-gate 					uhci_deallocate_tw(uhcip, pp, tw_tmp);
36900Sstevel@tonic-gate 
36910Sstevel@tonic-gate 					/*
36920Sstevel@tonic-gate 					 * This will make sure that the HC
36930Sstevel@tonic-gate 					 * does not loop anymore when there
36940Sstevel@tonic-gate 					 * are no pending bulk commands.
36950Sstevel@tonic-gate 					 */
36960Sstevel@tonic-gate 					if (--uhcip->uhci_pending_bulk_cmds
36970Sstevel@tonic-gate 					    == 0) {
36980Sstevel@tonic-gate 						uhcip->uhci_bulk_xfers_q_tail->
36990Sstevel@tonic-gate 						    link_ptr = HC_END_OF_LIST;
37000Sstevel@tonic-gate 						USB_DPRINTF_L3(PRINT_MASK_ATTA,
37010Sstevel@tonic-gate 						    uhcip->uhci_log_hdl,
37020Sstevel@tonic-gate 						    "uhci_remove_bulk_tds_tws:"
37030Sstevel@tonic-gate 						    " count = %d",
37040Sstevel@tonic-gate 						    uhcip->
37050Sstevel@tonic-gate 						    uhci_pending_bulk_cmds);
37060Sstevel@tonic-gate 					}
37070Sstevel@tonic-gate 				}
37080Sstevel@tonic-gate 			}
37090Sstevel@tonic-gate 		}
37100Sstevel@tonic-gate 
37110Sstevel@tonic-gate 		head = head_next;
37120Sstevel@tonic-gate 	}
37130Sstevel@tonic-gate 
37140Sstevel@tonic-gate 	if (what == UHCI_IN_CLOSE || what == UHCI_IN_RESET) {
37150Sstevel@tonic-gate 		ASSERT(info->num_tds == 0);
37160Sstevel@tonic-gate 	}
37170Sstevel@tonic-gate 
37182125Ssl147100 	for (i = 0; i < info->num_pools; i++) {
37192125Ssl147100 		td_pool_ptr = &info->td_pools[i];
37202125Ssl147100 		rval = ddi_dma_unbind_handle(td_pool_ptr->dma_handle);
37212125Ssl147100 		ASSERT(rval == DDI_SUCCESS);
37222125Ssl147100 		ddi_dma_mem_free(&td_pool_ptr->mem_handle);
37232125Ssl147100 		ddi_dma_free_handle(&td_pool_ptr->dma_handle);
37242125Ssl147100 	}
37252125Ssl147100 	kmem_free(info->td_pools, (sizeof (uhci_bulk_isoc_td_pool_t) *
37262125Ssl147100 	    info->num_pools));
37270Sstevel@tonic-gate 	kmem_free(info, sizeof (uhci_bulk_isoc_xfer_t));
37280Sstevel@tonic-gate 	pp->pp_qh->bulk_xfer_info = NULL;
37290Sstevel@tonic-gate }
37300Sstevel@tonic-gate 
37310Sstevel@tonic-gate 
37320Sstevel@tonic-gate /*
37330Sstevel@tonic-gate  * uhci_save_data_toggle ()
37340Sstevel@tonic-gate  *	Save the data toggle in the usba_device structure
37350Sstevel@tonic-gate  */
37360Sstevel@tonic-gate void
uhci_save_data_toggle(uhci_pipe_private_t * pp)37370Sstevel@tonic-gate uhci_save_data_toggle(uhci_pipe_private_t *pp)
37380Sstevel@tonic-gate {
37390Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
37400Sstevel@tonic-gate 
37410Sstevel@tonic-gate 	/* Save the data toggle in the usb devices structure. */
37420Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
37430Sstevel@tonic-gate 	usba_hcdi_set_data_toggle(ph->p_usba_device, ph->p_ep.bEndpointAddress,
37440Sstevel@tonic-gate 	    pp->pp_data_toggle);
37450Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
37460Sstevel@tonic-gate }
37470Sstevel@tonic-gate 
37482125Ssl147100 /*
37492125Ssl147100  * uhci_create_isoc_transfer_wrapper:
37502125Ssl147100  *	Create a Transaction Wrapper (TW) for isoc transfer.
37512125Ssl147100  *	This involves the allocating of DMA resources.
37522125Ssl147100  *
37532125Ssl147100  *	For isoc transfers, one isoc transfer includes multiple packets
37542125Ssl147100  *	and each packet may have a different length. So each packet is
37552125Ssl147100  *	transfered by one TD. We only know the individual packet length
37562125Ssl147100  *	won't exceed 1023 bytes, but we don't know exactly the lengths.
37572125Ssl147100  *	It is hard to make one physically discontiguous DMA buffer which
37582125Ssl147100  *	can fit in all the TDs like what can be done to the ctrl/bulk/
37592125Ssl147100  *	intr transfers. It is also undesirable to make one physically
37602125Ssl147100  *	contiguous DMA buffer for all the packets, since this may easily
37612125Ssl147100  *	fail when the system is in low memory. So an individual DMA
37622125Ssl147100  *	buffer is allocated for an individual isoc packet and each DMA
37632125Ssl147100  *	buffer is physically contiguous. An extra structure is allocated
37642125Ssl147100  *	to save the multiple DMA handles.
37652125Ssl147100  */
37662125Ssl147100 static uhci_trans_wrapper_t *
uhci_create_isoc_transfer_wrapper(uhci_state_t * uhcip,uhci_pipe_private_t * pp,usb_isoc_req_t * req,size_t length,usb_flags_t usb_flags)37672125Ssl147100 uhci_create_isoc_transfer_wrapper(
37682125Ssl147100 	uhci_state_t		*uhcip,
37692125Ssl147100 	uhci_pipe_private_t	*pp,
37702125Ssl147100 	usb_isoc_req_t		*req,
37712125Ssl147100 	size_t			length,
37722125Ssl147100 	usb_flags_t		usb_flags)
37732125Ssl147100 {
37742125Ssl147100 	int			result;
37752125Ssl147100 	size_t			real_length, strtlen, xfer_size;
37762125Ssl147100 	uhci_trans_wrapper_t	*tw;
37772125Ssl147100 	ddi_device_acc_attr_t	dev_attr;
37782125Ssl147100 	ddi_dma_attr_t		dma_attr;
37792125Ssl147100 	int			kmem_flag;
37802125Ssl147100 	int			(*dmamem_wait)(caddr_t);
37812125Ssl147100 	uint_t			i, j, ccount;
37822125Ssl147100 	usb_isoc_req_t		*tmp_req = req;
37832125Ssl147100 
37842125Ssl147100 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
37852125Ssl147100 
37862125Ssl147100 	if (UHCI_XFER_TYPE(&pp->pp_pipe_handle->p_ep) != USB_EP_ATTR_ISOCH) {
37872125Ssl147100 
37882125Ssl147100 		return (NULL);
37892125Ssl147100 	}
37902125Ssl147100 
37912125Ssl147100 	if ((req == NULL) && (UHCI_XFER_DIR(&pp->pp_pipe_handle->p_ep) ==
37922125Ssl147100 	    USB_EP_DIR_IN)) {
37932125Ssl147100 		tmp_req = (usb_isoc_req_t *)pp->pp_client_periodic_in_reqp;
37942125Ssl147100 	}
37952125Ssl147100 
37962125Ssl147100 	if (tmp_req == NULL) {
37972125Ssl147100 
37982125Ssl147100 		return (NULL);
37992125Ssl147100 	}
38002125Ssl147100 
38012125Ssl147100 
38022125Ssl147100 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
38032125Ssl147100 	    "uhci_create_isoc_transfer_wrapper: length = 0x%lx flags = 0x%x",
38042125Ssl147100 	    length, usb_flags);
38052125Ssl147100 
38062125Ssl147100 	/* SLEEP flag should not be used in interrupt context */
38072125Ssl147100 	if (servicing_interrupt()) {
38082125Ssl147100 		kmem_flag = KM_NOSLEEP;
38092125Ssl147100 		dmamem_wait = DDI_DMA_DONTWAIT;
38102125Ssl147100 	} else {
38112125Ssl147100 		kmem_flag = KM_SLEEP;
38122125Ssl147100 		dmamem_wait = DDI_DMA_SLEEP;
38132125Ssl147100 	}
38142125Ssl147100 
38152125Ssl147100 	/* Allocate space for the transfer wrapper */
38162125Ssl147100 	if ((tw = kmem_zalloc(sizeof (uhci_trans_wrapper_t), kmem_flag)) ==
38172125Ssl147100 	    NULL) {
38182125Ssl147100 		USB_DPRINTF_L2(PRINT_MASK_LISTS,  uhcip->uhci_log_hdl,
38192125Ssl147100 		    "uhci_create_isoc_transfer_wrapper: kmem_alloc failed");
38202125Ssl147100 
38212125Ssl147100 		return (NULL);
38222125Ssl147100 	}
38232125Ssl147100 
38242125Ssl147100 	/* Allocate space for the isoc buffer handles */
38252125Ssl147100 	strtlen = sizeof (uhci_isoc_buf_t) * tmp_req->isoc_pkts_count;
38262125Ssl147100 	if ((tw->tw_isoc_bufs = kmem_zalloc(strtlen, kmem_flag)) == NULL) {
38272125Ssl147100 		USB_DPRINTF_L2(PRINT_MASK_LISTS,  uhcip->uhci_log_hdl,
38282125Ssl147100 		    "uhci_create_isoc_transfer_wrapper: kmem_alloc "
38292125Ssl147100 		    "isoc buffer failed");
38302125Ssl147100 		kmem_free(tw, sizeof (uhci_trans_wrapper_t));
38312125Ssl147100 
38322125Ssl147100 		return (NULL);
38332125Ssl147100 	}
38342125Ssl147100 
38352125Ssl147100 	bcopy(&uhcip->uhci_dma_attr, &dma_attr, sizeof (ddi_dma_attr_t));
38362125Ssl147100 	dma_attr.dma_attr_sgllen = 1;
38372125Ssl147100 
38382125Ssl147100 	dev_attr.devacc_attr_version		= DDI_DEVICE_ATTR_V0;
38392125Ssl147100 	dev_attr.devacc_attr_endian_flags	= DDI_STRUCTURE_LE_ACC;
38402125Ssl147100 	dev_attr.devacc_attr_dataorder		= DDI_STRICTORDER_ACC;
38412125Ssl147100 
38422125Ssl147100 	/* Store the transfer length */
38432125Ssl147100 	tw->tw_length = length;
38442125Ssl147100 
38452125Ssl147100 	for (i = 0; i < tmp_req->isoc_pkts_count; i++) {
38467492SZhigang.Lu@Sun.COM 		tw->tw_isoc_bufs[i].index = (ushort_t)i;
38472125Ssl147100 
38482125Ssl147100 		/* Allocate the DMA handle */
38492125Ssl147100 		if ((result = ddi_dma_alloc_handle(uhcip->uhci_dip, &dma_attr,
38502125Ssl147100 		    dmamem_wait, 0, &tw->tw_isoc_bufs[i].dma_handle)) !=
38512125Ssl147100 		    DDI_SUCCESS) {
38522125Ssl147100 			USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
38532125Ssl147100 			    "uhci_create_isoc_transfer_wrapper: "
38542125Ssl147100 			    "Alloc handle %d failed", i);
38552125Ssl147100 
38562125Ssl147100 			for (j = 0; j < i; j++) {
38572125Ssl147100 				result = ddi_dma_unbind_handle(
38582125Ssl147100 				    tw->tw_isoc_bufs[j].dma_handle);
38592125Ssl147100 				ASSERT(result == USB_SUCCESS);
38602125Ssl147100 				ddi_dma_mem_free(&tw->tw_isoc_bufs[j].
38612125Ssl147100 				    mem_handle);
38622125Ssl147100 				ddi_dma_free_handle(&tw->tw_isoc_bufs[j].
38632125Ssl147100 				    dma_handle);
38642125Ssl147100 			}
38652125Ssl147100 			kmem_free(tw->tw_isoc_bufs, strtlen);
38662125Ssl147100 			kmem_free(tw, sizeof (uhci_trans_wrapper_t));
38672125Ssl147100 
38682125Ssl147100 			return (NULL);
38692125Ssl147100 		}
38702125Ssl147100 
38712125Ssl147100 		/* Allocate the memory */
38722125Ssl147100 		xfer_size = tmp_req->isoc_pkt_descr[i].isoc_pkt_length;
38732125Ssl147100 		if ((result = ddi_dma_mem_alloc(tw->tw_isoc_bufs[i].dma_handle,
38742125Ssl147100 		    xfer_size, &dev_attr, DDI_DMA_CONSISTENT, dmamem_wait,
38752125Ssl147100 		    NULL, (caddr_t *)&tw->tw_isoc_bufs[i].buf_addr,
38762125Ssl147100 		    &real_length, &tw->tw_isoc_bufs[i].mem_handle)) !=
38772125Ssl147100 		    DDI_SUCCESS) {
38782125Ssl147100 			USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
38792125Ssl147100 			    "uhci_create_isoc_transfer_wrapper: "
38802125Ssl147100 			    "dma_mem_alloc %d fail", i);
38812125Ssl147100 			ddi_dma_free_handle(&tw->tw_isoc_bufs[i].dma_handle);
38822125Ssl147100 
38832125Ssl147100 			for (j = 0; j < i; j++) {
38842125Ssl147100 				result = ddi_dma_unbind_handle(
38852125Ssl147100 				    tw->tw_isoc_bufs[j].dma_handle);
38862125Ssl147100 				ASSERT(result == USB_SUCCESS);
38872125Ssl147100 				ddi_dma_mem_free(&tw->tw_isoc_bufs[j].
38882125Ssl147100 				    mem_handle);
38892125Ssl147100 				ddi_dma_free_handle(&tw->tw_isoc_bufs[j].
38902125Ssl147100 				    dma_handle);
38912125Ssl147100 			}
38922125Ssl147100 			kmem_free(tw->tw_isoc_bufs, strtlen);
38932125Ssl147100 			kmem_free(tw, sizeof (uhci_trans_wrapper_t));
38942125Ssl147100 
38952125Ssl147100 			return (NULL);
38962125Ssl147100 		}
38972125Ssl147100 
38982125Ssl147100 		ASSERT(real_length >= xfer_size);
38992125Ssl147100 
39002125Ssl147100 		/* Bind the handle */
39012125Ssl147100 		result = ddi_dma_addr_bind_handle(
39022125Ssl147100 		    tw->tw_isoc_bufs[i].dma_handle, NULL,
39032125Ssl147100 		    (caddr_t)tw->tw_isoc_bufs[i].buf_addr, real_length,
39042125Ssl147100 		    DDI_DMA_RDWR|DDI_DMA_CONSISTENT, dmamem_wait, NULL,
39052125Ssl147100 		    &tw->tw_isoc_bufs[i].cookie, &ccount);
39062125Ssl147100 
39072125Ssl147100 		if ((result == DDI_DMA_MAPPED) && (ccount == 1)) {
39082125Ssl147100 			tw->tw_isoc_bufs[i].length = xfer_size;
39092125Ssl147100 
39102125Ssl147100 			continue;
39112125Ssl147100 		} else {
39122125Ssl147100 			USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
39132125Ssl147100 			    "uhci_create_isoc_transfer_wrapper: "
39142125Ssl147100 			    "Bind handle %d failed", i);
39152125Ssl147100 			if (result == DDI_DMA_MAPPED) {
39162125Ssl147100 				result = ddi_dma_unbind_handle(
39172125Ssl147100 				    tw->tw_isoc_bufs[i].dma_handle);
39182125Ssl147100 				ASSERT(result == USB_SUCCESS);
39192125Ssl147100 			}
39202125Ssl147100 			ddi_dma_mem_free(&tw->tw_isoc_bufs[i].mem_handle);
39212125Ssl147100 			ddi_dma_free_handle(&tw->tw_isoc_bufs[i].dma_handle);
39222125Ssl147100 
39232125Ssl147100 			for (j = 0; j < i; j++) {
39242125Ssl147100 				result = ddi_dma_unbind_handle(
39252125Ssl147100 				    tw->tw_isoc_bufs[j].dma_handle);
39262125Ssl147100 				ASSERT(result == USB_SUCCESS);
39272125Ssl147100 				ddi_dma_mem_free(&tw->tw_isoc_bufs[j].
39282125Ssl147100 				    mem_handle);
39292125Ssl147100 				ddi_dma_free_handle(&tw->tw_isoc_bufs[j].
39302125Ssl147100 				    dma_handle);
39312125Ssl147100 			}
39322125Ssl147100 			kmem_free(tw->tw_isoc_bufs, strtlen);
39332125Ssl147100 			kmem_free(tw, sizeof (uhci_trans_wrapper_t));
39342125Ssl147100 
39352125Ssl147100 			return (NULL);
39362125Ssl147100 		}
39372125Ssl147100 	}
39382125Ssl147100 
39392125Ssl147100 	tw->tw_ncookies = tmp_req->isoc_pkts_count;
39402125Ssl147100 	tw->tw_isoc_strtlen = strtlen;
39412125Ssl147100 
39422125Ssl147100 	/*
39432125Ssl147100 	 * Only allow one wrapper to be added at a time. Insert the
39442125Ssl147100 	 * new transaction wrapper into the list for this pipe.
39452125Ssl147100 	 */
39462125Ssl147100 	if (pp->pp_tw_head == NULL) {
39472125Ssl147100 		pp->pp_tw_head = tw;
39482125Ssl147100 		pp->pp_tw_tail = tw;
39492125Ssl147100 	} else {
39502125Ssl147100 		pp->pp_tw_tail->tw_next = tw;
39512125Ssl147100 		pp->pp_tw_tail = tw;
39522125Ssl147100 		ASSERT(tw->tw_next == NULL);
39532125Ssl147100 	}
39542125Ssl147100 
39552125Ssl147100 	/* Store a back pointer to the pipe private structure */
39562125Ssl147100 	tw->tw_pipe_private = pp;
39572125Ssl147100 
39582125Ssl147100 	/* Store the transfer type - synchronous or asynchronous */
39592125Ssl147100 	tw->tw_flags = usb_flags;
39602125Ssl147100 
39612125Ssl147100 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
39622125Ssl147100 	    "uhci_create_isoc_transfer_wrapper: tw = 0x%p, ncookies = %u",
39636898Sfb209375 	    (void *)tw, tw->tw_ncookies);
39642125Ssl147100 
39652125Ssl147100 	return (tw);
39662125Ssl147100 }
39670Sstevel@tonic-gate 
39680Sstevel@tonic-gate /*
39690Sstevel@tonic-gate  * uhci_insert_isoc_td:
39700Sstevel@tonic-gate  *	- Create transfer wrapper
39710Sstevel@tonic-gate  *	- Allocate memory for the isoc td's
39720Sstevel@tonic-gate  *	- Fill up all the TD's and submit to the HC
39730Sstevel@tonic-gate  *	- Update all the linked lists
39740Sstevel@tonic-gate  */
39750Sstevel@tonic-gate int
uhci_insert_isoc_td(uhci_state_t * uhcip,usba_pipe_handle_data_t * ph,usb_isoc_req_t * isoc_req,size_t length,usb_flags_t flags)39760Sstevel@tonic-gate uhci_insert_isoc_td(
39770Sstevel@tonic-gate 	uhci_state_t		*uhcip,
39780Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
39790Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_req,
39800Sstevel@tonic-gate 	size_t			length,
39810Sstevel@tonic-gate 	usb_flags_t		flags)
39820Sstevel@tonic-gate {
39830Sstevel@tonic-gate 	int			rval = USB_SUCCESS;
39840Sstevel@tonic-gate 	int			error;
39850Sstevel@tonic-gate 	uint_t			ddic;
39862125Ssl147100 	uint32_t		i, j, index;
39870Sstevel@tonic-gate 	uint32_t		bytes_to_xfer;
39880Sstevel@tonic-gate 	uint32_t		expired_frames = 0;
39890Sstevel@tonic-gate 	usb_frame_number_t	start_frame, end_frame, current_frame;
39900Sstevel@tonic-gate 	uhci_td_t		*td_ptr;
39910Sstevel@tonic-gate 	uhci_pipe_private_t	*pp = (uhci_pipe_private_t *)ph->p_hcd_private;
39920Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw;
39930Sstevel@tonic-gate 	uhci_bulk_isoc_xfer_t	*isoc_xfer_info;
39942125Ssl147100 	uhci_bulk_isoc_td_pool_t *td_pool_ptr;
39950Sstevel@tonic-gate 
39960Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
39972125Ssl147100 	    "uhci_insert_isoc_td: ph = 0x%p isoc req = %p length = %lu",
39986898Sfb209375 	    (void *)ph, (void *)isoc_req, length);
39990Sstevel@tonic-gate 
40000Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
40010Sstevel@tonic-gate 
40020Sstevel@tonic-gate 	/* Allocate a transfer wrapper */
40032125Ssl147100 	if ((tw = uhci_create_isoc_transfer_wrapper(uhcip, pp, isoc_req,
40042125Ssl147100 	    length, flags)) == NULL) {
40050Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
40060Sstevel@tonic-gate 		    "uhci_insert_isoc_td: TW allocation failed");
40070Sstevel@tonic-gate 
40080Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
40090Sstevel@tonic-gate 	}
40100Sstevel@tonic-gate 
40110Sstevel@tonic-gate 	/* Save current isochronous request pointer */
40120Sstevel@tonic-gate 	tw->tw_curr_xfer_reqp = (usb_opaque_t)isoc_req;
40130Sstevel@tonic-gate 
40140Sstevel@tonic-gate 	/*
40150Sstevel@tonic-gate 	 * Initialize the transfer wrapper. These values are useful
40160Sstevel@tonic-gate 	 * for sending back the reply.
40170Sstevel@tonic-gate 	 */
40180Sstevel@tonic-gate 	tw->tw_handle_td		= uhci_handle_isoc_td;
40190Sstevel@tonic-gate 	tw->tw_handle_callback_value	= NULL;
40200Sstevel@tonic-gate 	tw->tw_direction = (UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_OUT) ?
40215773Sqz150045 	    PID_OUT : PID_IN;
40220Sstevel@tonic-gate 
40230Sstevel@tonic-gate 	/*
40240Sstevel@tonic-gate 	 * If the transfer isoc send, then copy the data from the request
40250Sstevel@tonic-gate 	 * to the transfer wrapper.
40260Sstevel@tonic-gate 	 */
40270Sstevel@tonic-gate 	if ((tw->tw_direction == PID_OUT) && length) {
40282125Ssl147100 		uchar_t *p;
40292125Ssl147100 
40300Sstevel@tonic-gate 		ASSERT(isoc_req->isoc_data != NULL);
40312125Ssl147100 		p = isoc_req->isoc_data->b_rptr;
40320Sstevel@tonic-gate 
40330Sstevel@tonic-gate 		/* Copy the data into the message */
40342125Ssl147100 		for (i = 0; i < isoc_req->isoc_pkts_count; i++) {
40352125Ssl147100 			ddi_rep_put8(tw->tw_isoc_bufs[i].mem_handle,
40362125Ssl147100 			    p, (uint8_t *)tw->tw_isoc_bufs[i].buf_addr,
40372125Ssl147100 			    isoc_req->isoc_pkt_descr[i].isoc_pkt_length,
40382125Ssl147100 			    DDI_DEV_AUTOINCR);
40392125Ssl147100 			p += isoc_req->isoc_pkt_descr[i].isoc_pkt_length;
40402125Ssl147100 		}
40410Sstevel@tonic-gate 	}
40420Sstevel@tonic-gate 
40430Sstevel@tonic-gate 	if (tw->tw_direction == PID_IN) {
40440Sstevel@tonic-gate 		if ((rval = uhci_allocate_periodic_in_resource(uhcip, pp, tw,
40450Sstevel@tonic-gate 		    flags)) != USB_SUCCESS) {
40460Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
40470Sstevel@tonic-gate 			    "uhci_insert_isoc_td: isoc_req_t alloc failed");
40482125Ssl147100 			uhci_deallocate_tw(uhcip, pp, tw);
40490Sstevel@tonic-gate 
40500Sstevel@tonic-gate 			return (rval);
40510Sstevel@tonic-gate 		}
40520Sstevel@tonic-gate 
40530Sstevel@tonic-gate 		isoc_req = (usb_isoc_req_t *)tw->tw_curr_xfer_reqp;
40540Sstevel@tonic-gate 	}
40550Sstevel@tonic-gate 
40560Sstevel@tonic-gate 	tw->tw_isoc_req	= (usb_isoc_req_t *)tw->tw_curr_xfer_reqp;
40570Sstevel@tonic-gate 
40580Sstevel@tonic-gate 	/* Get the pointer to the isoc_xfer_info structure */
40590Sstevel@tonic-gate 	isoc_xfer_info = (uhci_bulk_isoc_xfer_t *)&tw->tw_xfer_info;
40600Sstevel@tonic-gate 	isoc_xfer_info->num_tds = isoc_req->isoc_pkts_count;
40610Sstevel@tonic-gate 
40620Sstevel@tonic-gate 	/*
40630Sstevel@tonic-gate 	 * Allocate memory for isoc tds
40640Sstevel@tonic-gate 	 */
40652125Ssl147100 	if ((rval = uhci_alloc_bulk_isoc_tds(uhcip, isoc_req->isoc_pkts_count,
40660Sstevel@tonic-gate 	    isoc_xfer_info)) != USB_SUCCESS) {
40670Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
40682125Ssl147100 		    "uhci_alloc_bulk_isoc_td: Memory allocation failure");
40692125Ssl147100 
40702125Ssl147100 		if (tw->tw_direction == PID_IN) {
40712125Ssl147100 			uhci_deallocate_periodic_in_resource(uhcip, pp, tw);
40722125Ssl147100 		}
40730Sstevel@tonic-gate 		uhci_deallocate_tw(uhcip, pp, tw);
40740Sstevel@tonic-gate 
40750Sstevel@tonic-gate 		return (rval);
40760Sstevel@tonic-gate 	}
40770Sstevel@tonic-gate 
40780Sstevel@tonic-gate 	/*
40790Sstevel@tonic-gate 	 * Get the isoc td pool address, buffer address and
40800Sstevel@tonic-gate 	 * max packet size that the device supports.
40810Sstevel@tonic-gate 	 */
40822125Ssl147100 	td_pool_ptr = &isoc_xfer_info->td_pools[0];
40832125Ssl147100 	td_ptr = (uhci_td_t *)td_pool_ptr->pool_addr;
40842125Ssl147100 	index = 0;
40850Sstevel@tonic-gate 
40860Sstevel@tonic-gate 	/*
40870Sstevel@tonic-gate 	 * Fill up the isoc tds
40880Sstevel@tonic-gate 	 */
40890Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
40900Sstevel@tonic-gate 	    "uhci_insert_isoc_td : isoc pkts %d", isoc_req->isoc_pkts_count);
40910Sstevel@tonic-gate 
40922125Ssl147100 	for (i = 0; i < isoc_xfer_info->num_pools; i++) {
40932125Ssl147100 		for (j = 0; j < td_pool_ptr->num_tds; j++) {
40942125Ssl147100 			bytes_to_xfer =
40952125Ssl147100 			    isoc_req->isoc_pkt_descr[index].isoc_pkt_length;
40962125Ssl147100 
40972125Ssl147100 			uhci_fill_in_bulk_isoc_td(uhcip, &td_ptr[j],
40982125Ssl147100 			    (uhci_td_t *)NULL, HC_END_OF_LIST, ph, index,
40992125Ssl147100 			    bytes_to_xfer, tw);
41007492SZhigang.Lu@Sun.COM 			td_ptr[j].isoc_pkt_index = (ushort_t)index;
41012125Ssl147100 			index++;
41022125Ssl147100 		}
41032125Ssl147100 
41042125Ssl147100 		if (i < (isoc_xfer_info->num_pools - 1)) {
41052125Ssl147100 			td_pool_ptr = &isoc_xfer_info->td_pools[i + 1];
41062125Ssl147100 			td_ptr = (uhci_td_t *)td_pool_ptr->pool_addr;
41072125Ssl147100 		}
41080Sstevel@tonic-gate 	}
41090Sstevel@tonic-gate 
41100Sstevel@tonic-gate 	/*
41110Sstevel@tonic-gate 	 * Get the starting frame number.
41120Sstevel@tonic-gate 	 * The client drivers sets the flag USB_ATTRS_ISOC_XFER_ASAP to inform
41130Sstevel@tonic-gate 	 * the HCD to care of starting frame number.
41140Sstevel@tonic-gate 	 *
41150Sstevel@tonic-gate 	 * Following code is very time critical. So, perform atomic execution.
41160Sstevel@tonic-gate 	 */
41170Sstevel@tonic-gate 	ddic = ddi_enter_critical();
41180Sstevel@tonic-gate 	current_frame = uhci_get_sw_frame_number(uhcip);
41190Sstevel@tonic-gate 
41200Sstevel@tonic-gate 	if (isoc_req->isoc_attributes & USB_ATTRS_ISOC_START_FRAME) {
41210Sstevel@tonic-gate 		start_frame = isoc_req->isoc_frame_no;
41220Sstevel@tonic-gate 		end_frame = start_frame + isoc_req->isoc_pkts_count;
41230Sstevel@tonic-gate 
41240Sstevel@tonic-gate 		/* Check available frames */
41250Sstevel@tonic-gate 		if ((end_frame - current_frame) < UHCI_MAX_ISOC_FRAMES) {
41260Sstevel@tonic-gate 			if (current_frame > start_frame) {
41270Sstevel@tonic-gate 				if ((current_frame + FRNUM_OFFSET) <
41280Sstevel@tonic-gate 				    end_frame) {
41290Sstevel@tonic-gate 					expired_frames = current_frame +
41305773Sqz150045 					    FRNUM_OFFSET - start_frame;
41310Sstevel@tonic-gate 					start_frame = current_frame +
41325773Sqz150045 					    FRNUM_OFFSET;
41330Sstevel@tonic-gate 				} else {
41340Sstevel@tonic-gate 					rval = USB_INVALID_START_FRAME;
41350Sstevel@tonic-gate 				}
41360Sstevel@tonic-gate 			}
41370Sstevel@tonic-gate 		} else {
41380Sstevel@tonic-gate 			rval = USB_INVALID_START_FRAME;
41390Sstevel@tonic-gate 		}
41400Sstevel@tonic-gate 
41410Sstevel@tonic-gate 	} else if (isoc_req->isoc_attributes & USB_ATTRS_ISOC_XFER_ASAP) {
41420Sstevel@tonic-gate 		start_frame = pp->pp_frame_num;
41430Sstevel@tonic-gate 
41440Sstevel@tonic-gate 		if (start_frame == INVALID_FRNUM) {
41450Sstevel@tonic-gate 			start_frame = current_frame + FRNUM_OFFSET;
41460Sstevel@tonic-gate 		} else if (current_frame > start_frame) {
41470Sstevel@tonic-gate 			start_frame = current_frame + FRNUM_OFFSET;
41480Sstevel@tonic-gate 		}
41490Sstevel@tonic-gate 
41500Sstevel@tonic-gate 		end_frame = start_frame + isoc_req->isoc_pkts_count;
41510Sstevel@tonic-gate 		isoc_req->isoc_frame_no = start_frame;
41520Sstevel@tonic-gate 
41530Sstevel@tonic-gate 	}
41540Sstevel@tonic-gate 
41550Sstevel@tonic-gate 	if (rval != USB_SUCCESS) {
41560Sstevel@tonic-gate 
41570Sstevel@tonic-gate 		/* Exit the critical */
41580Sstevel@tonic-gate 		ddi_exit_critical(ddic);
41590Sstevel@tonic-gate 
41600Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
41610Sstevel@tonic-gate 		    "uhci_insert_isoc_td: Invalid starting frame number");
41620Sstevel@tonic-gate 
41632125Ssl147100 		if (tw->tw_direction == PID_IN) {
41642125Ssl147100 			uhci_deallocate_periodic_in_resource(uhcip, pp, tw);
41652125Ssl147100 		}
41662125Ssl147100 
41670Sstevel@tonic-gate 		while (tw->tw_hctd_head) {
41680Sstevel@tonic-gate 			uhci_delete_td(uhcip, tw->tw_hctd_head);
41690Sstevel@tonic-gate 		}
41700Sstevel@tonic-gate 
41712125Ssl147100 		for (i = 0; i < isoc_xfer_info->num_pools; i++) {
41722125Ssl147100 			td_pool_ptr = &isoc_xfer_info->td_pools[i];
41732125Ssl147100 			error = ddi_dma_unbind_handle(td_pool_ptr->dma_handle);
41742125Ssl147100 			ASSERT(error == DDI_SUCCESS);
41752125Ssl147100 			ddi_dma_mem_free(&td_pool_ptr->mem_handle);
41762125Ssl147100 			ddi_dma_free_handle(&td_pool_ptr->dma_handle);
41772125Ssl147100 		}
41782125Ssl147100 		kmem_free(isoc_xfer_info->td_pools,
41792125Ssl147100 		    (sizeof (uhci_bulk_isoc_td_pool_t) *
41802125Ssl147100 		    isoc_xfer_info->num_pools));
41810Sstevel@tonic-gate 
41820Sstevel@tonic-gate 		uhci_deallocate_tw(uhcip, pp, tw);
41830Sstevel@tonic-gate 
41840Sstevel@tonic-gate 		return (rval);
41850Sstevel@tonic-gate 	}
41860Sstevel@tonic-gate 
41870Sstevel@tonic-gate 	for (i = 0; i < expired_frames; i++) {
41880Sstevel@tonic-gate 		isoc_req->isoc_pkt_descr[i].isoc_pkt_status =
41895773Sqz150045 		    USB_CR_NOT_ACCESSED;
41900Sstevel@tonic-gate 		isoc_req->isoc_pkt_descr[i].isoc_pkt_actual_length =
41915773Sqz150045 		    isoc_req->isoc_pkt_descr[i].isoc_pkt_length;
41922125Ssl147100 		uhci_get_isoc_td_by_index(uhcip, isoc_xfer_info, i,
41932125Ssl147100 		    &td_ptr, &td_pool_ptr);
41942125Ssl147100 		uhci_delete_td(uhcip, td_ptr);
41950Sstevel@tonic-gate 		--isoc_xfer_info->num_tds;
41960Sstevel@tonic-gate 	}
41970Sstevel@tonic-gate 
41980Sstevel@tonic-gate 	/*
41990Sstevel@tonic-gate 	 * Add the TD's to the HC list
42000Sstevel@tonic-gate 	 */
42010Sstevel@tonic-gate 	start_frame = (start_frame & 0x3ff);
42020Sstevel@tonic-gate 	for (; i < isoc_req->isoc_pkts_count; i++) {
42032125Ssl147100 		uhci_get_isoc_td_by_index(uhcip, isoc_xfer_info, i,
42042125Ssl147100 		    &td_ptr, &td_pool_ptr);
42050Sstevel@tonic-gate 		if (uhcip->uhci_isoc_q_tailp[start_frame]) {
42062125Ssl147100 			td_ptr->isoc_prev =
42075773Sqz150045 			    uhcip->uhci_isoc_q_tailp[start_frame];
42082125Ssl147100 			td_ptr->isoc_next = NULL;
42092125Ssl147100 			td_ptr->link_ptr =
42100Sstevel@tonic-gate 			    uhcip->uhci_isoc_q_tailp[start_frame]->link_ptr;
42110Sstevel@tonic-gate 			uhcip->uhci_isoc_q_tailp[start_frame]->isoc_next =
42125773Sqz150045 			    td_ptr;
42130Sstevel@tonic-gate 			SetTD32(uhcip,
42140Sstevel@tonic-gate 			    uhcip->uhci_isoc_q_tailp[start_frame]->link_ptr,
42152125Ssl147100 			    ISOCTD_PADDR(td_pool_ptr, td_ptr));
42162125Ssl147100 			uhcip->uhci_isoc_q_tailp[start_frame] = td_ptr;
42170Sstevel@tonic-gate 		} else {
42182125Ssl147100 			uhcip->uhci_isoc_q_tailp[start_frame] = td_ptr;
42192125Ssl147100 			td_ptr->isoc_next = NULL;
42202125Ssl147100 			td_ptr->isoc_prev = NULL;
42212125Ssl147100 			SetTD32(uhcip, td_ptr->link_ptr,
42220Sstevel@tonic-gate 			    GetFL32(uhcip,
42235773Sqz150045 			    uhcip->uhci_frame_lst_tablep[start_frame]));
42240Sstevel@tonic-gate 			SetFL32(uhcip,
42250Sstevel@tonic-gate 			    uhcip->uhci_frame_lst_tablep[start_frame],
42262125Ssl147100 			    ISOCTD_PADDR(td_pool_ptr, td_ptr));
42270Sstevel@tonic-gate 		}
42287492SZhigang.Lu@Sun.COM 		td_ptr->starting_frame = (uint_t)start_frame;
42290Sstevel@tonic-gate 
42300Sstevel@tonic-gate 		if (++start_frame == NUM_FRAME_LST_ENTRIES)
42310Sstevel@tonic-gate 			start_frame = 0;
42320Sstevel@tonic-gate 	}
42330Sstevel@tonic-gate 
42340Sstevel@tonic-gate 	ddi_exit_critical(ddic);
42350Sstevel@tonic-gate 	pp->pp_frame_num = end_frame;
42360Sstevel@tonic-gate 
42370Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
42380Sstevel@tonic-gate 	    "uhci_insert_isoc_td: current frame number 0x%llx, pipe frame num"
42396898Sfb209375 	    " 0x%llx", (unsigned long long)current_frame,
42406898Sfb209375 	    (unsigned long long)(pp->pp_frame_num));
42410Sstevel@tonic-gate 
42420Sstevel@tonic-gate 	return (rval);
42430Sstevel@tonic-gate }
42440Sstevel@tonic-gate 
42450Sstevel@tonic-gate 
42460Sstevel@tonic-gate /*
42472125Ssl147100  * uhci_get_isoc_td_by_index:
42482125Ssl147100  *	Obtain the addresses of the TD pool and the TD at the index.
42492125Ssl147100  *
42502125Ssl147100  * tdpp - pointer to the address of the TD at the isoc packet index
42512125Ssl147100  * td_pool_pp - pointer to the address of the TD pool containing
42525773Sqz150045  *		the specified TD
42532125Ssl147100  */
42542125Ssl147100 /* ARGSUSED */
42552125Ssl147100 static void
uhci_get_isoc_td_by_index(uhci_state_t * uhcip,uhci_bulk_isoc_xfer_t * info,uint_t index,uhci_td_t ** tdpp,uhci_bulk_isoc_td_pool_t ** td_pool_pp)42562125Ssl147100 uhci_get_isoc_td_by_index(
42572125Ssl147100 	uhci_state_t			*uhcip,
42582125Ssl147100 	uhci_bulk_isoc_xfer_t		*info,
42592125Ssl147100 	uint_t				index,
42602125Ssl147100 	uhci_td_t			**tdpp,
42612125Ssl147100 	uhci_bulk_isoc_td_pool_t	**td_pool_pp)
42622125Ssl147100 {
42632125Ssl147100 	uint_t			i = 0, j = 0;
42642125Ssl147100 	uhci_td_t		*td_ptr;
42652125Ssl147100 
42662125Ssl147100 	while (j < info->num_pools) {
42672125Ssl147100 		if ((i + info->td_pools[j].num_tds) <= index) {
42682125Ssl147100 			i += info->td_pools[j].num_tds;
42692125Ssl147100 			j++;
42702125Ssl147100 		} else {
42712125Ssl147100 			i = index - i;
42722125Ssl147100 
42732125Ssl147100 			break;
42742125Ssl147100 		}
42752125Ssl147100 	}
42762125Ssl147100 
42772125Ssl147100 	ASSERT(j < info->num_pools);
42782125Ssl147100 	*td_pool_pp = &info->td_pools[j];
42792125Ssl147100 	td_ptr = (uhci_td_t *)((*td_pool_pp)->pool_addr);
42802125Ssl147100 	*tdpp = &td_ptr[i];
42812125Ssl147100 }
42822125Ssl147100 
42832125Ssl147100 
42842125Ssl147100 /*
42850Sstevel@tonic-gate  * uhci_handle_isoc_td:
42860Sstevel@tonic-gate  *	Handles the completed isoc tds
42870Sstevel@tonic-gate  */
42880Sstevel@tonic-gate void
uhci_handle_isoc_td(uhci_state_t * uhcip,uhci_td_t * td)42890Sstevel@tonic-gate uhci_handle_isoc_td(uhci_state_t *uhcip, uhci_td_t *td)
42900Sstevel@tonic-gate {
42912125Ssl147100 	uint_t			rval, i;
42920Sstevel@tonic-gate 	uint32_t		pkt_index = td->isoc_pkt_index;
42930Sstevel@tonic-gate 	usb_cr_t		cr;
42940Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw = td->tw;
42950Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_req = (usb_isoc_req_t *)tw->tw_isoc_req;
42960Sstevel@tonic-gate 	uhci_pipe_private_t	*pp = tw->tw_pipe_private;
42970Sstevel@tonic-gate 	uhci_bulk_isoc_xfer_t	*isoc_xfer_info = &tw->tw_xfer_info;
42980Sstevel@tonic-gate 	usba_pipe_handle_data_t	*usb_pp;
42992125Ssl147100 	uhci_bulk_isoc_td_pool_t *td_pool_ptr;
43000Sstevel@tonic-gate 
43010Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
43020Sstevel@tonic-gate 	    "uhci_handle_isoc_td: td = 0x%p, pp = 0x%p, tw = 0x%p, req = 0x%p, "
43036898Sfb209375 	    "index = %x", (void *)td, (void *)pp, (void *)tw, (void *)isoc_req,
43046898Sfb209375 	    pkt_index);
43050Sstevel@tonic-gate 
43060Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
43070Sstevel@tonic-gate 
43080Sstevel@tonic-gate 	usb_pp = pp->pp_pipe_handle;
43090Sstevel@tonic-gate 
43100Sstevel@tonic-gate 	/*
43110Sstevel@tonic-gate 	 * Check whether there are any errors occurred. If so, update error
43120Sstevel@tonic-gate 	 * count and return it to the upper.But never return a non zero
43130Sstevel@tonic-gate 	 * completion reason.
43140Sstevel@tonic-gate 	 */
43150Sstevel@tonic-gate 	cr = USB_CR_OK;
43160Sstevel@tonic-gate 	if (GetTD_status(uhcip, td) & TD_STATUS_MASK) {
43170Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
43180Sstevel@tonic-gate 		    "uhci_handle_isoc_td: Error Occurred: TD Status = %x",
43190Sstevel@tonic-gate 		    GetTD_status(uhcip, td));
43200Sstevel@tonic-gate 		isoc_req->isoc_error_count++;
43210Sstevel@tonic-gate 	}
43220Sstevel@tonic-gate 
43230Sstevel@tonic-gate 	if (isoc_req != NULL) {
43240Sstevel@tonic-gate 		isoc_req->isoc_pkt_descr[pkt_index].isoc_pkt_status = cr;
43250Sstevel@tonic-gate 		isoc_req->isoc_pkt_descr[pkt_index].isoc_pkt_actual_length =
43265773Sqz150045 		    (GetTD_alen(uhcip, td) == ZERO_LENGTH) ? 0 :
43275773Sqz150045 		    GetTD_alen(uhcip, td) + 1;
43280Sstevel@tonic-gate 	}
43290Sstevel@tonic-gate 
43300Sstevel@tonic-gate 	uhci_delete_isoc_td(uhcip, td);
43310Sstevel@tonic-gate 
43320Sstevel@tonic-gate 	if (--isoc_xfer_info->num_tds != 0) {
43330Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
43340Sstevel@tonic-gate 		    "uhci_handle_isoc_td: Number of TDs %d",
43350Sstevel@tonic-gate 		    isoc_xfer_info->num_tds);
43360Sstevel@tonic-gate 
43370Sstevel@tonic-gate 		return;
43380Sstevel@tonic-gate 	}
43390Sstevel@tonic-gate 
43400Sstevel@tonic-gate 	tw->tw_claim = UHCI_INTR_HDLR_CLAIMED;
43410Sstevel@tonic-gate 	if (tw->tw_direction == PID_IN) {
43420Sstevel@tonic-gate 		uhci_sendup_td_message(uhcip, cr, tw);
43430Sstevel@tonic-gate 
43440Sstevel@tonic-gate 		if ((uhci_handle_isoc_receive(uhcip, pp, tw)) != USB_SUCCESS) {
43450Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
43460Sstevel@tonic-gate 			    "uhci_handle_isoc_td: Drop message");
43470Sstevel@tonic-gate 		}
43480Sstevel@tonic-gate 
43490Sstevel@tonic-gate 	} else {
43500Sstevel@tonic-gate 		/* update kstats only for OUT. sendup_td_msg() does it for IN */
43510Sstevel@tonic-gate 		uhci_do_byte_stats(uhcip, tw->tw_length,
43520Sstevel@tonic-gate 		    usb_pp->p_ep.bmAttributes, usb_pp->p_ep.bEndpointAddress);
43530Sstevel@tonic-gate 
43540Sstevel@tonic-gate 		uhci_hcdi_callback(uhcip, pp, usb_pp, tw, USB_CR_OK);
43550Sstevel@tonic-gate 	}
43560Sstevel@tonic-gate 
43572125Ssl147100 	for (i = 0; i < isoc_xfer_info->num_pools; i++) {
43582125Ssl147100 		td_pool_ptr = &isoc_xfer_info->td_pools[i];
43592125Ssl147100 		rval = ddi_dma_unbind_handle(td_pool_ptr->dma_handle);
43602125Ssl147100 		ASSERT(rval == DDI_SUCCESS);
43612125Ssl147100 		ddi_dma_mem_free(&td_pool_ptr->mem_handle);
43622125Ssl147100 		ddi_dma_free_handle(&td_pool_ptr->dma_handle);
43632125Ssl147100 	}
43642125Ssl147100 	kmem_free(isoc_xfer_info->td_pools,
43652125Ssl147100 	    (sizeof (uhci_bulk_isoc_td_pool_t) *
43662125Ssl147100 	    isoc_xfer_info->num_pools));
43670Sstevel@tonic-gate 	uhci_deallocate_tw(uhcip, pp, tw);
43680Sstevel@tonic-gate }
43690Sstevel@tonic-gate 
43700Sstevel@tonic-gate 
43710Sstevel@tonic-gate /*
43720Sstevel@tonic-gate  * uhci_handle_isoc_receive:
43730Sstevel@tonic-gate  *	- Sends the isoc data to the client
43740Sstevel@tonic-gate  *	- Inserts another isoc receive request
43750Sstevel@tonic-gate  */
43760Sstevel@tonic-gate static int
uhci_handle_isoc_receive(uhci_state_t * uhcip,uhci_pipe_private_t * pp,uhci_trans_wrapper_t * tw)43770Sstevel@tonic-gate uhci_handle_isoc_receive(
43780Sstevel@tonic-gate 	uhci_state_t		*uhcip,
43790Sstevel@tonic-gate 	uhci_pipe_private_t	*pp,
43800Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw)
43810Sstevel@tonic-gate {
43820Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
43836898Sfb209375 	    "uhci_handle_isoc_receive: tw = 0x%p", (void *)tw);
43840Sstevel@tonic-gate 
43850Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
43860Sstevel@tonic-gate 
43870Sstevel@tonic-gate 	/*
43880Sstevel@tonic-gate 	 * -- check for pipe state being polling before
43890Sstevel@tonic-gate 	 * inserting a new request. Check when is TD
43900Sstevel@tonic-gate 	 * de-allocation being done? (so we can reuse the same TD)
43910Sstevel@tonic-gate 	 */
43920Sstevel@tonic-gate 	if (uhci_start_isoc_receive_polling(uhcip,
43930Sstevel@tonic-gate 	    pp->pp_pipe_handle, (usb_isoc_req_t *)tw->tw_curr_xfer_reqp,
43940Sstevel@tonic-gate 	    0) != USB_SUCCESS) {
43950Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
43960Sstevel@tonic-gate 		    "uhci_handle_isoc_receive: receive polling failed");
43970Sstevel@tonic-gate 
43980Sstevel@tonic-gate 		return (USB_FAILURE);
43990Sstevel@tonic-gate 	}
44000Sstevel@tonic-gate 
44010Sstevel@tonic-gate 	return (USB_SUCCESS);
44020Sstevel@tonic-gate }
44030Sstevel@tonic-gate 
44040Sstevel@tonic-gate 
44050Sstevel@tonic-gate /*
44060Sstevel@tonic-gate  * uhci_delete_isoc_td:
44070Sstevel@tonic-gate  *	- Delete from the outstanding command queue
44080Sstevel@tonic-gate  *	- Delete from the tw queue
44090Sstevel@tonic-gate  *	- Delete from the isoc queue
44100Sstevel@tonic-gate  *	- Delete from the HOST CONTROLLER list
44110Sstevel@tonic-gate  */
44120Sstevel@tonic-gate static void
uhci_delete_isoc_td(uhci_state_t * uhcip,uhci_td_t * td)44130Sstevel@tonic-gate uhci_delete_isoc_td(uhci_state_t *uhcip, uhci_td_t *td)
44140Sstevel@tonic-gate {
44150Sstevel@tonic-gate 	uint32_t	starting_frame = td->starting_frame;
44160Sstevel@tonic-gate 
44170Sstevel@tonic-gate 	if ((td->isoc_next == NULL) && (td->isoc_prev == NULL)) {
44180Sstevel@tonic-gate 		SetFL32(uhcip, uhcip->uhci_frame_lst_tablep[starting_frame],
44195773Sqz150045 		    GetTD32(uhcip, td->link_ptr));
44200Sstevel@tonic-gate 		uhcip->uhci_isoc_q_tailp[starting_frame] = 0;
44210Sstevel@tonic-gate 	} else if (td->isoc_next == NULL) {
44220Sstevel@tonic-gate 		td->isoc_prev->link_ptr = td->link_ptr;
44230Sstevel@tonic-gate 		td->isoc_prev->isoc_next = NULL;
44240Sstevel@tonic-gate 		uhcip->uhci_isoc_q_tailp[starting_frame] = td->isoc_prev;
44250Sstevel@tonic-gate 	} else if (td->isoc_prev == NULL) {
44260Sstevel@tonic-gate 		td->isoc_next->isoc_prev = NULL;
44270Sstevel@tonic-gate 		SetFL32(uhcip, uhcip->uhci_frame_lst_tablep[starting_frame],
44280Sstevel@tonic-gate 		    GetTD32(uhcip, td->link_ptr));
44290Sstevel@tonic-gate 	} else {
44300Sstevel@tonic-gate 		td->isoc_prev->isoc_next = td->isoc_next;
44310Sstevel@tonic-gate 		td->isoc_next->isoc_prev = td->isoc_prev;
44320Sstevel@tonic-gate 		td->isoc_prev->link_ptr = td->link_ptr;
44330Sstevel@tonic-gate 	}
44340Sstevel@tonic-gate 
44350Sstevel@tonic-gate 	uhci_delete_td(uhcip, td);
44360Sstevel@tonic-gate }
44370Sstevel@tonic-gate 
44380Sstevel@tonic-gate 
44390Sstevel@tonic-gate /*
44400Sstevel@tonic-gate  * uhci_send_isoc_receive
44410Sstevel@tonic-gate  *	- Allocates usb_isoc_request
44420Sstevel@tonic-gate  *	- Updates the isoc request
44430Sstevel@tonic-gate  *	- Inserts the isoc td's into the HC processing list.
44440Sstevel@tonic-gate  */
44450Sstevel@tonic-gate int
uhci_start_isoc_receive_polling(uhci_state_t * uhcip,usba_pipe_handle_data_t * ph,usb_isoc_req_t * isoc_req,usb_flags_t usb_flags)44460Sstevel@tonic-gate uhci_start_isoc_receive_polling(
44470Sstevel@tonic-gate 	uhci_state_t		*uhcip,
44480Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph,
44490Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_req,
44500Sstevel@tonic-gate 	usb_flags_t		usb_flags)
44510Sstevel@tonic-gate {
44520Sstevel@tonic-gate 	int			ii, error;
44533255Slg150142 	size_t			max_isoc_xfer_size, length, isoc_pkts_length;
44540Sstevel@tonic-gate 	ushort_t		isoc_pkt_count;
44550Sstevel@tonic-gate 	uhci_pipe_private_t	*pp = (uhci_pipe_private_t *)ph->p_hcd_private;
44560Sstevel@tonic-gate 	usb_isoc_pkt_descr_t	*isoc_pkt_descr;
44570Sstevel@tonic-gate 
44580Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
44590Sstevel@tonic-gate 	    "uhci_start_isoc_receive_polling: usb_flags = %x", usb_flags);
44600Sstevel@tonic-gate 
44610Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
44620Sstevel@tonic-gate 
44630Sstevel@tonic-gate 	max_isoc_xfer_size = ph->p_ep.wMaxPacketSize * UHCI_MAX_ISOC_PKTS;
44640Sstevel@tonic-gate 
44650Sstevel@tonic-gate 	if (isoc_req) {
44660Sstevel@tonic-gate 		isoc_pkt_descr = isoc_req->isoc_pkt_descr;
44670Sstevel@tonic-gate 		isoc_pkt_count = isoc_req->isoc_pkts_count;
44683255Slg150142 		isoc_pkts_length = isoc_req->isoc_pkts_length;
44690Sstevel@tonic-gate 	} else {
44700Sstevel@tonic-gate 		isoc_pkt_descr = ((usb_isoc_req_t *)
44715773Sqz150045 		    pp->pp_client_periodic_in_reqp)->isoc_pkt_descr;
44720Sstevel@tonic-gate 		isoc_pkt_count = ((usb_isoc_req_t *)
44735773Sqz150045 		    pp->pp_client_periodic_in_reqp)->isoc_pkts_count;
44743255Slg150142 		isoc_pkts_length = ((usb_isoc_req_t *)
44755773Sqz150045 		    pp->pp_client_periodic_in_reqp)->isoc_pkts_length;
44760Sstevel@tonic-gate 	}
44770Sstevel@tonic-gate 
44780Sstevel@tonic-gate 	for (ii = 0, length = 0; ii < isoc_pkt_count; ii++) {
44790Sstevel@tonic-gate 		length += isoc_pkt_descr->isoc_pkt_length;
44800Sstevel@tonic-gate 		isoc_pkt_descr++;
44810Sstevel@tonic-gate 	}
44820Sstevel@tonic-gate 
44833255Slg150142 	if ((isoc_pkts_length) && (isoc_pkts_length != length)) {
44843255Slg150142 
44853255Slg150142 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
44866898Sfb209375 		    "uhci_start_isoc_receive_polling: isoc_pkts_length 0x%lx "
44876898Sfb209375 		    "is not equal to the sum of all pkt lengths 0x%lx in "
44883255Slg150142 		    "an isoc request", isoc_pkts_length, length);
44893255Slg150142 
44903255Slg150142 		return (USB_FAILURE);
44913255Slg150142 	}
44923255Slg150142 
44930Sstevel@tonic-gate 	/* Check the size of isochronous request */
44940Sstevel@tonic-gate 	if (length > max_isoc_xfer_size) {
44950Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
44960Sstevel@tonic-gate 		    "uhci_start_isoc_receive_polling: "
44970Sstevel@tonic-gate 		    "Max isoc request size = %lx, Given isoc req size = %lx",
44980Sstevel@tonic-gate 		    max_isoc_xfer_size, length);
44990Sstevel@tonic-gate 
45000Sstevel@tonic-gate 		return (USB_FAILURE);
45010Sstevel@tonic-gate 	}
45020Sstevel@tonic-gate 
45030Sstevel@tonic-gate 	/* Add the TD into the Host Controller's isoc list */
45042125Ssl147100 	error = uhci_insert_isoc_td(uhcip, ph, isoc_req, length, usb_flags);
45050Sstevel@tonic-gate 
45060Sstevel@tonic-gate 	return (error);
45070Sstevel@tonic-gate }
45080Sstevel@tonic-gate 
45090Sstevel@tonic-gate 
45100Sstevel@tonic-gate /*
45110Sstevel@tonic-gate  * uhci_remove_isoc_tds_tws
45120Sstevel@tonic-gate  *	This routine scans the pipe and removes all the td's
45130Sstevel@tonic-gate  *	and transfer wrappers and deallocates the memory
45140Sstevel@tonic-gate  *	associated with those td's and tw's.
45150Sstevel@tonic-gate  */
45160Sstevel@tonic-gate void
uhci_remove_isoc_tds_tws(uhci_state_t * uhcip,uhci_pipe_private_t * pp)45170Sstevel@tonic-gate uhci_remove_isoc_tds_tws(uhci_state_t *uhcip, uhci_pipe_private_t *pp)
45180Sstevel@tonic-gate {
45192125Ssl147100 	uint_t			rval, i;
45200Sstevel@tonic-gate 	uhci_td_t		*tmp_td, *td_head;
45210Sstevel@tonic-gate 	usb_isoc_req_t		*isoc_req;
45220Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tmp_tw, *tw_head;
45232125Ssl147100 	uhci_bulk_isoc_xfer_t	*isoc_xfer_info;
45242125Ssl147100 	uhci_bulk_isoc_td_pool_t *td_pool_ptr;
45250Sstevel@tonic-gate 
45260Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ISOC, uhcip->uhci_log_hdl,
45270Sstevel@tonic-gate 	    "uhci_remove_isoc_tds_tws: pp = %p", (void *)pp);
45280Sstevel@tonic-gate 
45290Sstevel@tonic-gate 	tw_head = pp->pp_tw_head;
45300Sstevel@tonic-gate 	while (tw_head) {
45310Sstevel@tonic-gate 		tmp_tw = tw_head;
45320Sstevel@tonic-gate 		tw_head = tw_head->tw_next;
45330Sstevel@tonic-gate 		td_head = tmp_tw->tw_hctd_head;
45340Sstevel@tonic-gate 		if (tmp_tw->tw_direction == PID_IN) {
45350Sstevel@tonic-gate 			uhci_deallocate_periodic_in_resource(uhcip, pp,
45365773Sqz150045 			    tmp_tw);
45370Sstevel@tonic-gate 		} else if (tmp_tw->tw_direction == PID_OUT) {
45380Sstevel@tonic-gate 			uhci_hcdi_callback(uhcip, pp, pp->pp_pipe_handle,
45390Sstevel@tonic-gate 			    tmp_tw, USB_CR_FLUSHED);
45400Sstevel@tonic-gate 		}
45410Sstevel@tonic-gate 
45420Sstevel@tonic-gate 		while (td_head) {
45430Sstevel@tonic-gate 			tmp_td = td_head;
45440Sstevel@tonic-gate 			td_head = td_head->tw_td_next;
45450Sstevel@tonic-gate 			uhci_delete_isoc_td(uhcip, tmp_td);
45460Sstevel@tonic-gate 		}
45470Sstevel@tonic-gate 
45480Sstevel@tonic-gate 		isoc_req = (usb_isoc_req_t *)tmp_tw->tw_isoc_req;
45490Sstevel@tonic-gate 		if (isoc_req) {
45500Sstevel@tonic-gate 			usb_free_isoc_req(isoc_req);
45510Sstevel@tonic-gate 		}
45520Sstevel@tonic-gate 
45530Sstevel@tonic-gate 		ASSERT(tmp_tw->tw_hctd_head == NULL);
45540Sstevel@tonic-gate 
45552125Ssl147100 		if (tmp_tw->tw_xfer_info.td_pools) {
45562125Ssl147100 			isoc_xfer_info =
45572125Ssl147100 			    (uhci_bulk_isoc_xfer_t *)&tmp_tw->tw_xfer_info;
45582125Ssl147100 			for (i = 0; i < isoc_xfer_info->num_pools; i++) {
45592125Ssl147100 				td_pool_ptr = &isoc_xfer_info->td_pools[i];
45602125Ssl147100 				rval = ddi_dma_unbind_handle(
45612125Ssl147100 				    td_pool_ptr->dma_handle);
45622125Ssl147100 				ASSERT(rval == DDI_SUCCESS);
45632125Ssl147100 				ddi_dma_mem_free(&td_pool_ptr->mem_handle);
45642125Ssl147100 				ddi_dma_free_handle(&td_pool_ptr->dma_handle);
45652125Ssl147100 			}
45662125Ssl147100 			kmem_free(isoc_xfer_info->td_pools,
45672125Ssl147100 			    (sizeof (uhci_bulk_isoc_td_pool_t) *
45682125Ssl147100 			    isoc_xfer_info->num_pools));
45690Sstevel@tonic-gate 		}
45700Sstevel@tonic-gate 
45710Sstevel@tonic-gate 		uhci_deallocate_tw(uhcip, pp, tmp_tw);
45720Sstevel@tonic-gate 	}
45730Sstevel@tonic-gate }
45740Sstevel@tonic-gate 
45750Sstevel@tonic-gate 
45760Sstevel@tonic-gate /*
45770Sstevel@tonic-gate  * uhci_isoc_update_sw_frame_number()
45780Sstevel@tonic-gate  *	to avoid code duplication, call uhci_get_sw_frame_number()
45790Sstevel@tonic-gate  */
45800Sstevel@tonic-gate void
uhci_isoc_update_sw_frame_number(uhci_state_t * uhcip)45810Sstevel@tonic-gate uhci_isoc_update_sw_frame_number(uhci_state_t *uhcip)
45820Sstevel@tonic-gate {
45830Sstevel@tonic-gate 	(void) uhci_get_sw_frame_number(uhcip);
45840Sstevel@tonic-gate }
45850Sstevel@tonic-gate 
45860Sstevel@tonic-gate 
45870Sstevel@tonic-gate /*
45880Sstevel@tonic-gate  * uhci_get_sw_frame_number:
45890Sstevel@tonic-gate  *	Hold the uhci_int_mutex before calling this routine.
45900Sstevel@tonic-gate  */
45910Sstevel@tonic-gate uint64_t
uhci_get_sw_frame_number(uhci_state_t * uhcip)45920Sstevel@tonic-gate uhci_get_sw_frame_number(uhci_state_t *uhcip)
45930Sstevel@tonic-gate {
45940Sstevel@tonic-gate 	uint64_t sw_frnum, hw_frnum, current_frnum;
45950Sstevel@tonic-gate 
45960Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
45970Sstevel@tonic-gate 
45980Sstevel@tonic-gate 	sw_frnum = uhcip->uhci_sw_frnum;
45990Sstevel@tonic-gate 	hw_frnum = Get_OpReg16(FRNUM);
46000Sstevel@tonic-gate 
46010Sstevel@tonic-gate 	/*
46020Sstevel@tonic-gate 	 * Check bit 10 in the software counter and hardware frame counter.
46030Sstevel@tonic-gate 	 * If both are same, then don't increment the software frame counter
46040Sstevel@tonic-gate 	 * (Bit 10 of hw frame counter toggle for every 1024 frames)
46050Sstevel@tonic-gate 	 * The lower 11 bits of software counter contains the hardware frame
46060Sstevel@tonic-gate 	 * counter value. The MSB (bit 10) of software counter is incremented
46070Sstevel@tonic-gate 	 * for every 1024 frames either here or in get frame number routine.
46080Sstevel@tonic-gate 	 */
46090Sstevel@tonic-gate 	if ((sw_frnum & UHCI_BIT_10_MASK) == (hw_frnum & UHCI_BIT_10_MASK)) {
46100Sstevel@tonic-gate 		/* The MSB of hw counter did not toggle */
46110Sstevel@tonic-gate 		current_frnum = ((sw_frnum & (SW_FRNUM_MASK)) | hw_frnum);
46120Sstevel@tonic-gate 	} else {
46130Sstevel@tonic-gate 		/*
46140Sstevel@tonic-gate 		 * The hw counter wrapped around. And the interrupt handler
46150Sstevel@tonic-gate 		 * did not get a chance to update the sw frame counter.
46160Sstevel@tonic-gate 		 * So, update the sw frame counter and return correct frame no.
46170Sstevel@tonic-gate 		 */
46180Sstevel@tonic-gate 		sw_frnum >>= UHCI_SIZE_OF_HW_FRNUM - 1;
46190Sstevel@tonic-gate 		current_frnum =
46200Sstevel@tonic-gate 		    ((++sw_frnum << (UHCI_SIZE_OF_HW_FRNUM - 1)) | hw_frnum);
46210Sstevel@tonic-gate 	}
46220Sstevel@tonic-gate 	uhcip->uhci_sw_frnum = current_frnum;
46230Sstevel@tonic-gate 
46240Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
46256898Sfb209375 	    "uhci_get_sw_frame_number: sw=%lld hd=%lld",
46266898Sfb209375 	    (unsigned long long)(uhcip->uhci_sw_frnum),
46276898Sfb209375 	    (unsigned long long)hw_frnum);
46280Sstevel@tonic-gate 
46290Sstevel@tonic-gate 	return (current_frnum);
46300Sstevel@tonic-gate }
46310Sstevel@tonic-gate 
46320Sstevel@tonic-gate 
46330Sstevel@tonic-gate /*
46340Sstevel@tonic-gate  * uhci_cmd_timeout_hdlr:
46350Sstevel@tonic-gate  *	This routine will get called for every second. It checks for
46360Sstevel@tonic-gate  *	timed out control commands/bulk commands. Timeout any commands
46370Sstevel@tonic-gate  *	that exceeds the time out period specified by the pipe policy.
46380Sstevel@tonic-gate  */
46390Sstevel@tonic-gate void
uhci_cmd_timeout_hdlr(void * arg)46400Sstevel@tonic-gate uhci_cmd_timeout_hdlr(void *arg)
46410Sstevel@tonic-gate {
46420Sstevel@tonic-gate 	uint_t			flag = B_FALSE;
46430Sstevel@tonic-gate 	uhci_td_t		*head, *tmp_td;
46440Sstevel@tonic-gate 	uhci_state_t		*uhcip = (uhci_state_t *)arg;
46450Sstevel@tonic-gate 	uhci_pipe_private_t	*pp;
46460Sstevel@tonic-gate 
46470Sstevel@tonic-gate 	/*
46480Sstevel@tonic-gate 	 * Check whether any of the control xfers are timed out.
46490Sstevel@tonic-gate 	 * If so, complete those commands with time out as reason.
46500Sstevel@tonic-gate 	 */
46510Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
46520Sstevel@tonic-gate 	head = uhcip->uhci_outst_tds_head;
46530Sstevel@tonic-gate 
46540Sstevel@tonic-gate 	while (head) {
46550Sstevel@tonic-gate 		/*
46560Sstevel@tonic-gate 		 * If timeout out is zero, then dont timeout command.
46570Sstevel@tonic-gate 		 */
46580Sstevel@tonic-gate 		if (head->tw->tw_timeout_cnt == 0)  {
46590Sstevel@tonic-gate 			head = head->outst_td_next;
46600Sstevel@tonic-gate 			continue;
46610Sstevel@tonic-gate 		}
46620Sstevel@tonic-gate 
46630Sstevel@tonic-gate 		if (!(head->tw->tw_flags & TW_TIMEOUT_FLAG)) {
46640Sstevel@tonic-gate 			head->tw->tw_flags |= TW_TIMEOUT_FLAG;
46650Sstevel@tonic-gate 			--head->tw->tw_timeout_cnt;
46660Sstevel@tonic-gate 		}
46670Sstevel@tonic-gate 
46680Sstevel@tonic-gate 		/* only do it for bulk and control TDs */
46690Sstevel@tonic-gate 		if ((head->tw->tw_timeout_cnt == 0) &&
46700Sstevel@tonic-gate 		    (head->tw->tw_handle_td != uhci_handle_isoc_td)) {
46710Sstevel@tonic-gate 
46720Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
46730Sstevel@tonic-gate 			    "Command timed out: td = %p", (void *)head);
46740Sstevel@tonic-gate 
46750Sstevel@tonic-gate 			head->tw->tw_claim = UHCI_TIMEOUT_HDLR_CLAIMED;
46760Sstevel@tonic-gate 
46770Sstevel@tonic-gate 			/*
46780Sstevel@tonic-gate 			 * Check finally whether the command completed
46790Sstevel@tonic-gate 			 */
46800Sstevel@tonic-gate 			if (GetTD_status(uhcip, head) & UHCI_TD_ACTIVE) {
46810Sstevel@tonic-gate 				SetTD32(uhcip, head->link_ptr,
46820Sstevel@tonic-gate 				    GetTD32(uhcip, head->link_ptr) |
46830Sstevel@tonic-gate 				    HC_END_OF_LIST);
46840Sstevel@tonic-gate 				pp = head->tw->tw_pipe_private;
46850Sstevel@tonic-gate 				SetQH32(uhcip, pp->pp_qh->element_ptr,
46860Sstevel@tonic-gate 				    GetQH32(uhcip, pp->pp_qh->element_ptr) |
46870Sstevel@tonic-gate 				    HC_END_OF_LIST);
46880Sstevel@tonic-gate 			}
46890Sstevel@tonic-gate 
46900Sstevel@tonic-gate 			flag = B_TRUE;
46910Sstevel@tonic-gate 		}
46920Sstevel@tonic-gate 
46930Sstevel@tonic-gate 		head = head->outst_td_next;
46940Sstevel@tonic-gate 	}
46950Sstevel@tonic-gate 
46960Sstevel@tonic-gate 	if (flag) {
46970Sstevel@tonic-gate 		(void) uhci_wait_for_sof(uhcip);
46980Sstevel@tonic-gate 	}
46990Sstevel@tonic-gate 
47000Sstevel@tonic-gate 	head = uhcip->uhci_outst_tds_head;
47010Sstevel@tonic-gate 	while (head) {
47020Sstevel@tonic-gate 		if (head->tw->tw_flags & TW_TIMEOUT_FLAG) {
47030Sstevel@tonic-gate 			head->tw->tw_flags &= ~TW_TIMEOUT_FLAG;
47040Sstevel@tonic-gate 		}
47050Sstevel@tonic-gate 		if (head->tw->tw_claim == UHCI_TIMEOUT_HDLR_CLAIMED) {
47060Sstevel@tonic-gate 			head->tw->tw_claim = UHCI_NOT_CLAIMED;
47070Sstevel@tonic-gate 			tmp_td = head->tw->tw_hctd_head;
47080Sstevel@tonic-gate 			while (tmp_td) {
47090Sstevel@tonic-gate 				SetTD_status(uhcip, tmp_td,
47105773Sqz150045 				    UHCI_TD_CRC_TIMEOUT);
47110Sstevel@tonic-gate 				tmp_td = tmp_td->tw_td_next;
47120Sstevel@tonic-gate 			}
47130Sstevel@tonic-gate 		}
47140Sstevel@tonic-gate 		head = head->outst_td_next;
47150Sstevel@tonic-gate 	}
47160Sstevel@tonic-gate 
47170Sstevel@tonic-gate 	/*
47180Sstevel@tonic-gate 	 * Process the td which was completed before shifting from normal
47190Sstevel@tonic-gate 	 * mode to polled mode
47200Sstevel@tonic-gate 	 */
47210Sstevel@tonic-gate 	if (uhcip->uhci_polled_flag == UHCI_POLLED_FLAG_TRUE) {
47220Sstevel@tonic-gate 		uhci_process_submitted_td_queue(uhcip);
47230Sstevel@tonic-gate 		uhcip->uhci_polled_flag = UHCI_POLLED_FLAG_FALSE;
47240Sstevel@tonic-gate 	} else if (flag) {
47250Sstevel@tonic-gate 		/* Process the completed/timed out commands */
47260Sstevel@tonic-gate 		uhci_process_submitted_td_queue(uhcip);
47270Sstevel@tonic-gate 	}
47280Sstevel@tonic-gate 
47290Sstevel@tonic-gate 	/* Re-register the control/bulk/intr commands' timeout handler */
47300Sstevel@tonic-gate 	if (uhcip->uhci_cmd_timeout_id) {
47310Sstevel@tonic-gate 		uhcip->uhci_cmd_timeout_id = timeout(uhci_cmd_timeout_hdlr,
47320Sstevel@tonic-gate 		    (void *)uhcip, UHCI_ONE_SECOND);
47330Sstevel@tonic-gate 	}
47340Sstevel@tonic-gate 
47350Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
47360Sstevel@tonic-gate }
47370Sstevel@tonic-gate 
47380Sstevel@tonic-gate 
47390Sstevel@tonic-gate /*
47400Sstevel@tonic-gate  * uhci_wait_for_sof:
47410Sstevel@tonic-gate  *	Wait for the start of the next frame (implying any changes made in the
47420Sstevel@tonic-gate  *	lattice have now taken effect).
47430Sstevel@tonic-gate  *	To be sure this is the case, we wait for the completion of the current
47440Sstevel@tonic-gate  *	frame (which might have already been pending), then another complete
47450Sstevel@tonic-gate  *	frame to ensure everything has taken effect.
47460Sstevel@tonic-gate  */
47470Sstevel@tonic-gate int
uhci_wait_for_sof(uhci_state_t * uhcip)47480Sstevel@tonic-gate uhci_wait_for_sof(uhci_state_t *uhcip)
47490Sstevel@tonic-gate {
47505773Sqz150045 	int	n, error;
47510Sstevel@tonic-gate 	ushort_t    cmd_reg;
47520Sstevel@tonic-gate 	usb_frame_number_t	before_frame_number, after_frame_number;
4753*11066Srafael.vanoni@sun.com 	clock_t	rval;
47540Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
47556898Sfb209375 	    "uhci_wait_for_sof: uhcip = %p", (void *)uhcip);
47560Sstevel@tonic-gate 
47570Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
47585773Sqz150045 
47595773Sqz150045 	error = uhci_state_is_operational(uhcip);
47605773Sqz150045 
47615773Sqz150045 	if (error != USB_SUCCESS) {
47625773Sqz150045 
47635773Sqz150045 		return (error);
47645773Sqz150045 	}
47655773Sqz150045 
47660Sstevel@tonic-gate 	before_frame_number =  uhci_get_sw_frame_number(uhcip);
47670Sstevel@tonic-gate 	for (n = 0; n < MAX_SOF_WAIT_COUNT; n++) {
47680Sstevel@tonic-gate 		SetTD_ioc(uhcip, uhcip->uhci_sof_td, 1);
47690Sstevel@tonic-gate 		uhcip->uhci_cv_signal = B_TRUE;
47700Sstevel@tonic-gate 
4771*11066Srafael.vanoni@sun.com 		rval = cv_reltimedwait(&uhcip->uhci_cv_SOF,
4772*11066Srafael.vanoni@sun.com 		    &uhcip->uhci_int_mutex, UHCI_ONE_SECOND, TR_CLOCK_TICK);
47730Sstevel@tonic-gate 
47740Sstevel@tonic-gate 		after_frame_number = uhci_get_sw_frame_number(uhcip);
47750Sstevel@tonic-gate 		if ((rval == -1) &&
47760Sstevel@tonic-gate 		    (after_frame_number <= before_frame_number)) {
47770Sstevel@tonic-gate 			cmd_reg = Get_OpReg16(USBCMD);
47780Sstevel@tonic-gate 			Set_OpReg16(USBCMD, (cmd_reg | USBCMD_REG_HC_RUN));
47790Sstevel@tonic-gate 			Set_OpReg16(USBINTR, ENABLE_ALL_INTRS);
47800Sstevel@tonic-gate 			after_frame_number = uhci_get_sw_frame_number(uhcip);
47810Sstevel@tonic-gate 		}
47820Sstevel@tonic-gate 		before_frame_number = after_frame_number;
47830Sstevel@tonic-gate 	}
47840Sstevel@tonic-gate 
47850Sstevel@tonic-gate 	SetTD_ioc(uhcip, uhcip->uhci_sof_td, 0);
47860Sstevel@tonic-gate 
47870Sstevel@tonic-gate 	return (uhcip->uhci_cv_signal ? USB_FAILURE : USB_SUCCESS);
47880Sstevel@tonic-gate 
47890Sstevel@tonic-gate }
47900Sstevel@tonic-gate 
47910Sstevel@tonic-gate /*
47920Sstevel@tonic-gate  * uhci_allocate_periodic_in_resource:
47930Sstevel@tonic-gate  *	Allocate interrupt/isochronous request structure for the
47940Sstevel@tonic-gate  *	interrupt/isochronous IN transfer.
47950Sstevel@tonic-gate  */
47960Sstevel@tonic-gate int
uhci_allocate_periodic_in_resource(uhci_state_t * uhcip,uhci_pipe_private_t * pp,uhci_trans_wrapper_t * tw,usb_flags_t flags)47970Sstevel@tonic-gate uhci_allocate_periodic_in_resource(
47980Sstevel@tonic-gate 	uhci_state_t		*uhcip,
47990Sstevel@tonic-gate 	uhci_pipe_private_t	*pp,
48000Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw,
48010Sstevel@tonic-gate 	usb_flags_t		flags)
48020Sstevel@tonic-gate {
48030Sstevel@tonic-gate 	size_t			length = 0;
48040Sstevel@tonic-gate 	usb_opaque_t		client_periodic_in_reqp;
48050Sstevel@tonic-gate 	usb_intr_req_t		*cur_intr_req;
48060Sstevel@tonic-gate 	usb_isoc_req_t		*curr_isoc_reqp;
48070Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
48080Sstevel@tonic-gate 
48090Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
48100Sstevel@tonic-gate 	    "uhci_allocate_periodic_in_resource:\n\t"
48116898Sfb209375 	    "ph = 0x%p, pp = 0x%p, tw = 0x%p, flags = 0x%x",
48126898Sfb209375 	    (void *)ph, (void *)pp, (void *)tw, flags);
48130Sstevel@tonic-gate 
48140Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
48150Sstevel@tonic-gate 
48160Sstevel@tonic-gate 	/* Check the current periodic in request pointer */
48170Sstevel@tonic-gate 	if (tw->tw_curr_xfer_reqp) {
48180Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
48190Sstevel@tonic-gate 		    "uhci_allocate_periodic_in_resource: Interrupt "
48200Sstevel@tonic-gate 		    "request structure already exists: "
48210Sstevel@tonic-gate 		    "allocation failed");
48220Sstevel@tonic-gate 
48230Sstevel@tonic-gate 		return (USB_SUCCESS);
48240Sstevel@tonic-gate 	}
48250Sstevel@tonic-gate 
48260Sstevel@tonic-gate 	/* Get the client periodic in request pointer */
48270Sstevel@tonic-gate 	client_periodic_in_reqp = pp->pp_client_periodic_in_reqp;
48280Sstevel@tonic-gate 
48290Sstevel@tonic-gate 	/*
48300Sstevel@tonic-gate 	 * If it a periodic IN request and periodic request is NULL,
48310Sstevel@tonic-gate 	 * allocate corresponding usb periodic IN request for the
48320Sstevel@tonic-gate 	 * current periodic polling request and copy the information
48330Sstevel@tonic-gate 	 * from the saved periodic request structure.
48340Sstevel@tonic-gate 	 */
48350Sstevel@tonic-gate 	if (UHCI_XFER_TYPE(&ph->p_ep) == USB_EP_ATTR_INTR) {
48360Sstevel@tonic-gate 		/* Get the interrupt transfer length */
48370Sstevel@tonic-gate 		length = ((usb_intr_req_t *)client_periodic_in_reqp)->
48385773Sqz150045 		    intr_len;
48390Sstevel@tonic-gate 
48400Sstevel@tonic-gate 		cur_intr_req = usba_hcdi_dup_intr_req(ph->p_dip,
48410Sstevel@tonic-gate 		    (usb_intr_req_t *)client_periodic_in_reqp, length, flags);
48420Sstevel@tonic-gate 		if (cur_intr_req == NULL) {
48430Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
48440Sstevel@tonic-gate 			    "uhci_allocate_periodic_in_resource: Interrupt "
48450Sstevel@tonic-gate 			    "request structure allocation failed");
48460Sstevel@tonic-gate 
48470Sstevel@tonic-gate 			return (USB_NO_RESOURCES);
48480Sstevel@tonic-gate 		}
48490Sstevel@tonic-gate 
48500Sstevel@tonic-gate 		/* Check and save the timeout value */
48510Sstevel@tonic-gate 		tw->tw_timeout_cnt = (cur_intr_req->intr_attributes &
48520Sstevel@tonic-gate 		    USB_ATTRS_ONE_XFER) ? cur_intr_req->intr_timeout: 0;
48530Sstevel@tonic-gate 		tw->tw_curr_xfer_reqp = (usb_opaque_t)cur_intr_req;
48540Sstevel@tonic-gate 		tw->tw_length = cur_intr_req->intr_len;
48550Sstevel@tonic-gate 	} else {
48560Sstevel@tonic-gate 		ASSERT(client_periodic_in_reqp != NULL);
48570Sstevel@tonic-gate 
48580Sstevel@tonic-gate 		if ((curr_isoc_reqp = usba_hcdi_dup_isoc_req(ph->p_dip,
48590Sstevel@tonic-gate 		    (usb_isoc_req_t *)client_periodic_in_reqp, flags)) ==
48600Sstevel@tonic-gate 		    NULL) {
48610Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
48620Sstevel@tonic-gate 			    "uhci_allocate_periodic_in_resource: Isochronous "
48630Sstevel@tonic-gate 			    "request structure allocation failed");
48640Sstevel@tonic-gate 
48650Sstevel@tonic-gate 			return (USB_NO_RESOURCES);
48660Sstevel@tonic-gate 		}
48670Sstevel@tonic-gate 
48680Sstevel@tonic-gate 		/*
48690Sstevel@tonic-gate 		 * Save the client's isochronous request pointer and
48700Sstevel@tonic-gate 		 * length of isochronous transfer in transfer wrapper.
48710Sstevel@tonic-gate 		 * The dup'ed request is saved in pp_client_periodic_in_reqp
48720Sstevel@tonic-gate 		 */
48730Sstevel@tonic-gate 		tw->tw_curr_xfer_reqp =
48745773Sqz150045 		    (usb_opaque_t)pp->pp_client_periodic_in_reqp;
48750Sstevel@tonic-gate 		pp->pp_client_periodic_in_reqp = (usb_opaque_t)curr_isoc_reqp;
48760Sstevel@tonic-gate 	}
48770Sstevel@tonic-gate 
48780Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
48790Sstevel@tonic-gate 	ph->p_req_count++;
48800Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
48810Sstevel@tonic-gate 
48820Sstevel@tonic-gate 	return (USB_SUCCESS);
48830Sstevel@tonic-gate }
48840Sstevel@tonic-gate 
48850Sstevel@tonic-gate 
48860Sstevel@tonic-gate /*
48870Sstevel@tonic-gate  * uhci_deallocate_periodic_in_resource:
48880Sstevel@tonic-gate  *	Deallocate interrupt/isochronous request structure for the
48890Sstevel@tonic-gate  *	interrupt/isochronous IN transfer.
48900Sstevel@tonic-gate  */
48910Sstevel@tonic-gate void
uhci_deallocate_periodic_in_resource(uhci_state_t * uhcip,uhci_pipe_private_t * pp,uhci_trans_wrapper_t * tw)48920Sstevel@tonic-gate uhci_deallocate_periodic_in_resource(
48930Sstevel@tonic-gate 	uhci_state_t		*uhcip,
48940Sstevel@tonic-gate 	uhci_pipe_private_t	*pp,
48950Sstevel@tonic-gate 	uhci_trans_wrapper_t	*tw)
48960Sstevel@tonic-gate {
48970Sstevel@tonic-gate 	usb_opaque_t		curr_xfer_reqp;
48980Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
48990Sstevel@tonic-gate 
49000Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
49010Sstevel@tonic-gate 	    "uhci_deallocate_periodic_in_resource: "
49026898Sfb209375 	    "pp = 0x%p tw = 0x%p", (void *)pp, (void *)tw);
49030Sstevel@tonic-gate 
49040Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
49050Sstevel@tonic-gate 
49060Sstevel@tonic-gate 	curr_xfer_reqp = tw->tw_curr_xfer_reqp;
49070Sstevel@tonic-gate 	if (curr_xfer_reqp) {
49080Sstevel@tonic-gate 		/*
49090Sstevel@tonic-gate 		 * Reset periodic in request usb isoch
49100Sstevel@tonic-gate 		 * packet request pointers to null.
49110Sstevel@tonic-gate 		 */
49120Sstevel@tonic-gate 		tw->tw_curr_xfer_reqp = NULL;
49130Sstevel@tonic-gate 		tw->tw_isoc_req = NULL;
49140Sstevel@tonic-gate 
49150Sstevel@tonic-gate 		mutex_enter(&ph->p_mutex);
49160Sstevel@tonic-gate 		ph->p_req_count--;
49170Sstevel@tonic-gate 		mutex_exit(&ph->p_mutex);
49180Sstevel@tonic-gate 
49190Sstevel@tonic-gate 		/*
49200Sstevel@tonic-gate 		 * Free pre-allocated interrupt or isochronous requests.
49210Sstevel@tonic-gate 		 */
49220Sstevel@tonic-gate 		switch (UHCI_XFER_TYPE(&ph->p_ep)) {
49230Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
49240Sstevel@tonic-gate 			usb_free_intr_req((usb_intr_req_t *)curr_xfer_reqp);
49250Sstevel@tonic-gate 			break;
49260Sstevel@tonic-gate 		case USB_EP_ATTR_ISOCH:
49270Sstevel@tonic-gate 			usb_free_isoc_req((usb_isoc_req_t *)curr_xfer_reqp);
49280Sstevel@tonic-gate 			break;
49290Sstevel@tonic-gate 		}
49300Sstevel@tonic-gate 	}
49310Sstevel@tonic-gate }
49320Sstevel@tonic-gate 
49330Sstevel@tonic-gate 
49340Sstevel@tonic-gate /*
49350Sstevel@tonic-gate  * uhci_hcdi_callback()
49360Sstevel@tonic-gate  *	convenience wrapper around usba_hcdi_callback()
49370Sstevel@tonic-gate  */
49380Sstevel@tonic-gate void
uhci_hcdi_callback(uhci_state_t * uhcip,uhci_pipe_private_t * pp,usba_pipe_handle_data_t * ph,uhci_trans_wrapper_t * tw,usb_cr_t cr)49390Sstevel@tonic-gate uhci_hcdi_callback(uhci_state_t *uhcip, uhci_pipe_private_t *pp,
49400Sstevel@tonic-gate     usba_pipe_handle_data_t *ph, uhci_trans_wrapper_t *tw, usb_cr_t cr)
49410Sstevel@tonic-gate {
49420Sstevel@tonic-gate 	usb_opaque_t	curr_xfer_reqp;
49430Sstevel@tonic-gate 
49440Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
49456898Sfb209375 	    "uhci_hcdi_callback: ph = 0x%p, tw = 0x%p, cr = 0x%x",
49466898Sfb209375 	    (void *)ph, (void *)tw, cr);
49470Sstevel@tonic-gate 
49480Sstevel@tonic-gate 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
49490Sstevel@tonic-gate 
49500Sstevel@tonic-gate 	if (tw && tw->tw_curr_xfer_reqp) {
49510Sstevel@tonic-gate 		curr_xfer_reqp = tw->tw_curr_xfer_reqp;
49520Sstevel@tonic-gate 		tw->tw_curr_xfer_reqp = NULL;
49530Sstevel@tonic-gate 		tw->tw_isoc_req = NULL;
49540Sstevel@tonic-gate 	} else {
49550Sstevel@tonic-gate 		ASSERT(pp->pp_client_periodic_in_reqp != NULL);
49560Sstevel@tonic-gate 
49570Sstevel@tonic-gate 		curr_xfer_reqp = pp->pp_client_periodic_in_reqp;
49580Sstevel@tonic-gate 		pp->pp_client_periodic_in_reqp = NULL;
49590Sstevel@tonic-gate 	}
49600Sstevel@tonic-gate 
49610Sstevel@tonic-gate 	ASSERT(curr_xfer_reqp != NULL);
49620Sstevel@tonic-gate 
49630Sstevel@tonic-gate 	mutex_exit(&uhcip->uhci_int_mutex);
49640Sstevel@tonic-gate 	usba_hcdi_cb(ph, curr_xfer_reqp, cr);
49650Sstevel@tonic-gate 	mutex_enter(&uhcip->uhci_int_mutex);
49660Sstevel@tonic-gate }
49670Sstevel@tonic-gate 
49680Sstevel@tonic-gate 
49695773Sqz150045 /*
49705773Sqz150045  * uhci_state_is_operational:
49715773Sqz150045  *
49725773Sqz150045  * Check the Host controller state and return proper values.
49735773Sqz150045  */
49745773Sqz150045 int
uhci_state_is_operational(uhci_state_t * uhcip)49755773Sqz150045 uhci_state_is_operational(uhci_state_t	*uhcip)
49765773Sqz150045 {
49775773Sqz150045 	int	val;
49785773Sqz150045 
49795773Sqz150045 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
49805773Sqz150045 
49815773Sqz150045 	switch (uhcip->uhci_hc_soft_state) {
49825773Sqz150045 	case UHCI_CTLR_INIT_STATE:
49835773Sqz150045 	case UHCI_CTLR_SUSPEND_STATE:
49845773Sqz150045 		val = USB_FAILURE;
49855773Sqz150045 		break;
49865773Sqz150045 	case UHCI_CTLR_OPERATIONAL_STATE:
49875773Sqz150045 		val = USB_SUCCESS;
49885773Sqz150045 		break;
49895773Sqz150045 	case UHCI_CTLR_ERROR_STATE:
49905773Sqz150045 		val = USB_HC_HARDWARE_ERROR;
49915773Sqz150045 		break;
49925773Sqz150045 	default:
49935773Sqz150045 		val = USB_FAILURE;
49945773Sqz150045 		break;
49955773Sqz150045 	}
49965773Sqz150045 
49975773Sqz150045 	return (val);
49985773Sqz150045 }
49995773Sqz150045 
50005773Sqz150045 
50010Sstevel@tonic-gate #ifdef DEBUG
50020Sstevel@tonic-gate static void
uhci_print_td(uhci_state_t * uhcip,uhci_td_t * td)50030Sstevel@tonic-gate uhci_print_td(uhci_state_t *uhcip, uhci_td_t *td)
50040Sstevel@tonic-gate {
50050Sstevel@tonic-gate 	uint_t	*ptr = (uint_t *)td;
50060Sstevel@tonic-gate 
50070Sstevel@tonic-gate #ifndef lint
50080Sstevel@tonic-gate 	_NOTE(NO_COMPETING_THREADS_NOW);
50090Sstevel@tonic-gate #endif
50100Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_DUMPING, uhcip->uhci_log_hdl,
50110Sstevel@tonic-gate 	    "\tDWORD 1 0x%x\t DWORD 2 0x%x", ptr[0], ptr[1]);
50120Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_DUMPING, uhcip->uhci_log_hdl,
50130Sstevel@tonic-gate 	    "\tDWORD 3 0x%x\t DWORD 4 0x%x", ptr[2], ptr[3]);
50140Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_DUMPING, uhcip->uhci_log_hdl,
50150Sstevel@tonic-gate 	    "\tBytes xfered    = %d", td->tw->tw_bytes_xfered);
50160Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_DUMPING, uhcip->uhci_log_hdl,
50170Sstevel@tonic-gate 	    "\tBytes Pending   = %d", td->tw->tw_bytes_pending);
50180Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_DUMPING, uhcip->uhci_log_hdl,
50190Sstevel@tonic-gate 	    "Queue Head Details:");
50200Sstevel@tonic-gate 	uhci_print_qh(uhcip, td->tw->tw_pipe_private->pp_qh);
50210Sstevel@tonic-gate 
50220Sstevel@tonic-gate #ifndef lint
50230Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
50240Sstevel@tonic-gate #endif
50250Sstevel@tonic-gate }
50260Sstevel@tonic-gate 
50270Sstevel@tonic-gate 
50280Sstevel@tonic-gate static void
uhci_print_qh(uhci_state_t * uhcip,queue_head_t * qh)50290Sstevel@tonic-gate uhci_print_qh(uhci_state_t *uhcip, queue_head_t *qh)
50300Sstevel@tonic-gate {
50310Sstevel@tonic-gate 	uint_t	*ptr = (uint_t *)qh;
50320Sstevel@tonic-gate 
50330Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_DUMPING, uhcip->uhci_log_hdl,
50340Sstevel@tonic-gate 	    "\tLink Ptr = %x Element Ptr = %x", ptr[0], ptr[1]);
50350Sstevel@tonic-gate }
50360Sstevel@tonic-gate #endif
5037