ehci_isoch_util.c revision 7492:2387323b838f
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27/*
28 * EHCI Host Controller Driver (EHCI)
29 *
30 * The EHCI driver is a software driver which interfaces to the Universal
31 * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
32 * the Host Controller is defined by the EHCI Host Controller Interface.
33 *
34 * This module contains the EHCI driver isochronous code, which handles all
35 * Checking of status of USB transfers, error recovery and callbacks.
36 */
37#include <sys/usb/hcd/ehci/ehcid.h>
38#include <sys/usb/hcd/ehci/ehci_xfer.h>
39#include <sys/usb/hcd/ehci/ehci_util.h>
40
41/* Adjustable variables for the size of isoc pools */
42int ehci_itd_pool_size = EHCI_ITD_POOL_SIZE;
43
44/*
45 * pool functions
46 */
47int ehci_allocate_isoc_pools(
48	ehci_state_t		*ehcip);
49int ehci_get_itd_pool_size();
50
51/*
52 * Isochronous Transfer Wrapper Functions
53 */
54ehci_isoc_xwrapper_t *ehci_allocate_itw_resources(
55	ehci_state_t		*ehcip,
56	ehci_pipe_private_t	*pp,
57	size_t			itw_length,
58	usb_flags_t		usb_flags,
59	size_t			pkt_count);
60static ehci_isoc_xwrapper_t *ehci_allocate_itw(
61	ehci_state_t		*ehcip,
62	ehci_pipe_private_t	*pp,
63	size_t			length,
64	usb_flags_t		usb_flags);
65void ehci_deallocate_itw(
66	ehci_state_t		*ehcip,
67	ehci_pipe_private_t	*pp,
68	ehci_isoc_xwrapper_t	*itw);
69static void ehci_free_itw_dma(
70	ehci_state_t		*ehcip,
71	ehci_pipe_private_t	*pp,
72	ehci_isoc_xwrapper_t	*itw);
73
74/*
75 * transfer descriptor functions
76 */
77static ehci_itd_t *ehci_allocate_itd(
78	ehci_state_t		*ehcip);
79void ehci_deallocate_itd(
80	ehci_state_t		*ehcip,
81	ehci_isoc_xwrapper_t	*itw,
82	ehci_itd_t		*old_itd);
83uint_t ehci_calc_num_itds(
84	ehci_isoc_xwrapper_t	*itw,
85	size_t			pkt_count);
86int ehci_allocate_itds_for_itw(
87	ehci_state_t		*ehcip,
88	ehci_isoc_xwrapper_t	*itw,
89	uint_t			itd_count);
90static void ehci_deallocate_itds_for_itw(
91	ehci_state_t		*ehcip,
92	ehci_isoc_xwrapper_t	*itw);
93void ehci_insert_itd_on_itw(
94	ehci_state_t		*ehcip,
95	ehci_isoc_xwrapper_t	*itw,
96	ehci_itd_t		*itd);
97void ehci_insert_itd_into_active_list(
98	ehci_state_t		*ehcip,
99	ehci_itd_t		*itd);
100void ehci_remove_itd_from_active_list(
101	ehci_state_t		*ehcip,
102	ehci_itd_t		*itd);
103ehci_itd_t *ehci_create_done_itd_list(
104	ehci_state_t		*ehcip);
105int ehci_insert_isoc_to_pfl(
106	ehci_state_t		*ehcip,
107	ehci_pipe_private_t	*pp,
108	ehci_isoc_xwrapper_t	*itw);
109void ehci_remove_isoc_from_pfl(
110	ehci_state_t		*ehcip,
111	ehci_itd_t		*curr_itd);
112
113
114/*
115 * Isochronous in resource functions
116 */
117int ehci_allocate_isoc_in_resource(
118	ehci_state_t		*ehcip,
119	ehci_pipe_private_t	*pp,
120	ehci_isoc_xwrapper_t	*tw,
121	usb_flags_t		flags);
122void ehci_deallocate_isoc_in_resource(
123	ehci_state_t		*ehcip,
124	ehci_pipe_private_t	*pp,
125	ehci_isoc_xwrapper_t	*itw);
126
127/*
128 * memory addr functions
129 */
130uint32_t ehci_itd_cpu_to_iommu(
131	ehci_state_t		*ehcip,
132	ehci_itd_t		*addr);
133ehci_itd_t *ehci_itd_iommu_to_cpu(
134	ehci_state_t		*ehcip,
135	uintptr_t		addr);
136
137/*
138 * Error parsing functions
139 */
140void ehci_parse_isoc_error(
141	ehci_state_t		*ehcip,
142	ehci_isoc_xwrapper_t	*itw,
143	ehci_itd_t		*itd);
144static usb_cr_t ehci_parse_itd_error(
145	ehci_state_t		*ehcip,
146	ehci_isoc_xwrapper_t	*itw,
147	ehci_itd_t		*itd);
148static usb_cr_t ehci_parse_sitd_error(
149	ehci_state_t		*ehcip,
150	ehci_isoc_xwrapper_t	*itw,
151	ehci_itd_t		*itd);
152
153/*
154 * print functions
155 */
156void ehci_print_itd(
157	ehci_state_t		*ehcip,
158	ehci_itd_t		*itd);
159void ehci_print_sitd(
160	ehci_state_t		*ehcip,
161	ehci_itd_t		*itd);
162
163
164/*
165 * ehci_allocate_isoc_pools:
166 *
167 * Allocate the system memory for itd which are for low/full/high speed
168 * Transfer Descriptors. Must be aligned to a 32 byte boundary.
169 */
170int
171ehci_allocate_isoc_pools(ehci_state_t	*ehcip)
172{
173	ddi_device_acc_attr_t		dev_attr;
174	size_t				real_length;
175	int				result;
176	uint_t				ccount;
177	int				i;
178
179	USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
180	    "ehci_allocate_isoc_pools:");
181
182	/* Byte alignment */
183	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_TD_QH_ALIGNMENT;
184
185	/* Allocate the itd pool DMA handle */
186	result = ddi_dma_alloc_handle(ehcip->ehci_dip,
187	    &ehcip->ehci_dma_attr,
188	    DDI_DMA_SLEEP,
189	    0,
190	    &ehcip->ehci_itd_pool_dma_handle);
191
192	if (result != DDI_SUCCESS) {
193		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
194		    "ehci_allocate_isoc_pools: Alloc handle failed");
195
196		return (DDI_FAILURE);
197	}
198
199	/* The host controller will be little endian */
200	dev_attr.devacc_attr_version		= DDI_DEVICE_ATTR_V0;
201	dev_attr.devacc_attr_endian_flags	= DDI_STRUCTURE_LE_ACC;
202	dev_attr.devacc_attr_dataorder		= DDI_STRICTORDER_ACC;
203
204	/* Allocate the memory */
205	result = ddi_dma_mem_alloc(ehcip->ehci_itd_pool_dma_handle,
206	    ehci_itd_pool_size * sizeof (ehci_itd_t),
207	    &dev_attr,
208	    DDI_DMA_CONSISTENT,
209	    DDI_DMA_SLEEP,
210	    0,
211	    (caddr_t *)&ehcip->ehci_itd_pool_addr,
212	    &real_length,
213	    &ehcip->ehci_itd_pool_mem_handle);
214
215	if (result != DDI_SUCCESS) {
216		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
217		    "ehci_allocate_isoc_pools: Alloc memory failed");
218
219		return (DDI_FAILURE);
220	}
221
222	/* Map the ITD pool into the I/O address space */
223	result = ddi_dma_addr_bind_handle(
224	    ehcip->ehci_itd_pool_dma_handle,
225	    NULL,
226	    (caddr_t)ehcip->ehci_itd_pool_addr,
227	    real_length,
228	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
229	    DDI_DMA_SLEEP,
230	    NULL,
231	    &ehcip->ehci_itd_pool_cookie,
232	    &ccount);
233
234	bzero((void *)ehcip->ehci_itd_pool_addr,
235	    ehci_itd_pool_size * sizeof (ehci_itd_t));
236
237	/* Process the result */
238	if (result == DDI_DMA_MAPPED) {
239		/* The cookie count should be 1 */
240		if (ccount != 1) {
241			USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
242			    "ehci_allocate_isoc_pools: More than 1 cookie");
243
244			return (DDI_FAILURE);
245		}
246	} else {
247		USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
248		    "ehci_allocate_isoc_pools: Result = %d", result);
249
250		ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
251
252		return (DDI_FAILURE);
253	}
254
255	/*
256	 * DMA addresses for ITD pools are bound
257	 */
258	ehcip->ehci_dma_addr_bind_flag |= EHCI_ITD_POOL_BOUND;
259
260	/* Initialize the ITD pool */
261	for (i = 0; i < ehci_itd_pool_size; i++) {
262		Set_ITD(ehcip->ehci_itd_pool_addr[i].itd_state,
263		    EHCI_ITD_FREE);
264	}
265
266	return (DDI_SUCCESS);
267}
268
269
270int
271ehci_get_itd_pool_size()
272{
273	return (ehci_itd_pool_size);
274}
275
276
277/*
278 * Isochronous Transfer Wrapper Functions
279 */
280/*
281 * ehci_allocate_itw_resources:
282 *
283 * Allocate an iTW and n iTD from the iTD buffer pool and places it into the
284 * ITW.  It does an all or nothing transaction.
285 *
286 * Calculates the number of iTD needed based on pipe speed.
287 * For LOW/FULL speed devices, 1 iTD is needed for each packet.
288 * For HIGH speed device, 1 iTD is needed for 8 to 24 packets, depending on
289 *     the multiplier for "HIGH BANDWIDTH" transfers look at 4.7 in EHCI spec.
290 *
291 * Returns NULL if there is insufficient resources otherwise ITW.
292 */
293ehci_isoc_xwrapper_t *
294ehci_allocate_itw_resources(
295	ehci_state_t		*ehcip,
296	ehci_pipe_private_t	*pp,
297	size_t			itw_length,
298	usb_flags_t		usb_flags,
299	size_t			pkt_count)
300{
301	uint_t			itd_count;
302	ehci_isoc_xwrapper_t	*itw;
303
304	itw = ehci_allocate_itw(ehcip, pp, itw_length, usb_flags);
305
306	if (itw == NULL) {
307		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
308		    "ehci_allocate_itw_resources: Unable to allocate ITW");
309	} else {
310		itd_count = ehci_calc_num_itds(itw, pkt_count);
311		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
312		    "ehci_allocate_itw_resources: itd_count = 0x%d", itd_count);
313
314		if (ehci_allocate_itds_for_itw(ehcip, itw, itd_count) ==
315		    USB_SUCCESS) {
316			itw->itw_num_itds = itd_count;
317		} else {
318			ehci_deallocate_itw(ehcip, pp, itw);
319			itw = NULL;
320		}
321	}
322
323	return (itw);
324}
325
326
327/*
328 * ehci_allocate_itw:
329 *
330 * Creates a Isochronous Transfer Wrapper (itw) and populate it with this
331 * endpoint's data.  This involves the allocation of DMA resources.
332 *
333 * ITW Fields not set by this function:
334 * - will be populated itds are allocated
335 *   num_ids
336 *   itd_head
337 *   itd_tail
338 *   curr_xfer_reqp
339 *   curr_isoc_pktp
340 *   itw_itd_free_list
341 * - Should be set by the calling function
342 *   itw_handle_callback_value
343 */
344static ehci_isoc_xwrapper_t *
345ehci_allocate_itw(
346	ehci_state_t		*ehcip,
347	ehci_pipe_private_t	*pp,
348	size_t			length,
349	usb_flags_t		usb_flags)
350{
351	ddi_device_acc_attr_t	dev_attr;
352	int			result;
353	size_t			real_length;
354	uint_t			ccount;	/* Cookie count */
355	usba_pipe_handle_data_t *ph = pp->pp_pipe_handle;
356	usba_device_t		*usba_device = ph->p_usba_device;
357	usb_ep_descr_t		*endpoint = &ph->p_ep;
358	ehci_isoc_xwrapper_t	*itw;
359
360	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
361	    "ehci_allocate_itw: length = 0x%lx flags = 0x%x",
362	    length, usb_flags);
363
364	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
365
366	/* Allocate space for the transfer wrapper */
367	itw = kmem_zalloc(sizeof (ehci_isoc_xwrapper_t), KM_NOSLEEP);
368
369	if (itw == NULL) {
370		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
371		    "ehci_allocate_itw: kmem_zalloc failed");
372
373		return (NULL);
374	}
375
376	ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
377
378	/* Allocate the DMA handle */
379	result = ddi_dma_alloc_handle(ehcip->ehci_dip,
380	    &ehcip->ehci_dma_attr,
381	    DDI_DMA_DONTWAIT,
382	    0,
383	    &itw->itw_dmahandle);
384
385	if (result != DDI_SUCCESS) {
386		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
387		    "ehci_create_transfer_wrapper: Alloc handle failed");
388
389		kmem_free(itw, sizeof (ehci_isoc_xwrapper_t));
390
391		return (NULL);
392	}
393
394	/* no need for swapping the raw data in the buffers */
395	dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
396	dev_attr.devacc_attr_endian_flags  = DDI_NEVERSWAP_ACC;
397	dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
398
399	/* Allocate the memory */
400	result = ddi_dma_mem_alloc(itw->itw_dmahandle,
401	    length,
402	    &dev_attr,
403	    DDI_DMA_CONSISTENT,
404	    DDI_DMA_DONTWAIT,
405	    NULL,
406	    (caddr_t *)&itw->itw_buf,
407	    &real_length,
408	    &itw->itw_accesshandle);
409
410	if (result != DDI_SUCCESS) {
411		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
412		    "ehci_create_transfer_wrapper: dma_mem_alloc fail");
413
414		ddi_dma_free_handle(&itw->itw_dmahandle);
415		kmem_free(itw, sizeof (ehci_isoc_xwrapper_t));
416
417		return (NULL);
418	}
419
420	ASSERT(real_length >= length);
421
422	/* Bind the handle */
423	result = ddi_dma_addr_bind_handle(itw->itw_dmahandle,
424	    NULL,
425	    (caddr_t)itw->itw_buf,
426	    real_length,
427	    DDI_DMA_RDWR|DDI_DMA_CONSISTENT,
428	    DDI_DMA_DONTWAIT,
429	    NULL,
430	    &itw->itw_cookie,
431	    &ccount);
432
433	if (result == DDI_DMA_MAPPED) {
434		/* The cookie count should be 1 */
435		if (ccount != 1) {
436			USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
437			    "ehci_create_transfer_wrapper: More than 1 cookie");
438
439			result = ddi_dma_unbind_handle(itw->itw_dmahandle);
440			ASSERT(result == DDI_SUCCESS);
441
442			ddi_dma_mem_free(&itw->itw_accesshandle);
443			ddi_dma_free_handle(&itw->itw_dmahandle);
444			kmem_free(itw, sizeof (ehci_isoc_xwrapper_t));
445
446			return (NULL);
447		}
448	} else {
449		ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
450
451		ddi_dma_mem_free(&itw->itw_accesshandle);
452		ddi_dma_free_handle(&itw->itw_dmahandle);
453		kmem_free(itw, sizeof (ehci_isoc_xwrapper_t));
454
455		return (NULL);
456	}
457
458	/* Store a back pointer to the pipe private structure */
459	itw->itw_pipe_private = pp;
460	if (pp->pp_itw_head == NULL) {
461		pp->pp_itw_head = itw;
462		pp->pp_itw_tail = itw;
463	} else {
464		pp->pp_itw_tail->itw_next = itw;
465		pp->pp_itw_tail = itw;
466	}
467
468	/*
469	 * Store transfer information
470	 * itw_buf has been allocated and will be set later
471	 */
472	itw->itw_length = length;
473	itw->itw_flags = usb_flags;
474	itw->itw_port_status = usba_device->usb_port_status;
475	itw->itw_direction = endpoint->bEndpointAddress & USB_EP_DIR_MASK;
476
477	/*
478	 * Store the endpoint information that will be used by the
479	 * transfer descriptors later.
480	 */
481	mutex_enter(&usba_device->usb_mutex);
482	itw->itw_hub_addr = usba_device->usb_hs_hub_addr;
483	itw->itw_hub_port = usba_device->usb_hs_hub_port;
484	itw->itw_endpoint_num = endpoint->bEndpointAddress & USB_EP_NUM_MASK;
485	itw->itw_device_addr = usba_device->usb_addr;
486	mutex_exit(&usba_device->usb_mutex);
487
488	/* Get and Store 32bit ID */
489	itw->itw_id = EHCI_GET_ID((void *)itw);
490	ASSERT(itw->itw_id != NULL);
491
492	USB_DPRINTF_L3(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
493	    "ehci_create_itw: itw = 0x%p real_length = 0x%lx",
494	    (void *)itw, real_length);
495
496	return (itw);
497}
498
499
500/*
501 * ehci_deallocate_itw:
502 *
503 * Deallocate of a Isochronous Transaction Wrapper (TW) and this involves the
504 * freeing of DMA resources.
505 */
506void
507ehci_deallocate_itw(
508	ehci_state_t		*ehcip,
509	ehci_pipe_private_t	*pp,
510	ehci_isoc_xwrapper_t	*itw)
511{
512	ehci_isoc_xwrapper_t	*prev, *next;
513
514	USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
515	    "ehci_deallocate_itw: itw = 0x%p", (void *)itw);
516
517	/*
518	 * If the transfer wrapper has no Host Controller (HC)
519	 * Transfer Descriptors (ITD) associated with it,  then
520	 * remove the transfer wrapper.
521	 */
522	if (itw->itw_itd_head) {
523		ASSERT(itw->itw_itd_tail != NULL);
524
525		return;
526	}
527
528	ASSERT(itw->itw_itd_tail == NULL);
529
530	/* Make sure we return all the unused itd's to the pool as well */
531	ehci_deallocate_itds_for_itw(ehcip, itw);
532
533	/*
534	 * If pp->pp_tw_head and pp->pp_tw_tail are pointing to
535	 * given TW then set the head and  tail  equal to NULL.
536	 * Otherwise search for this TW in the linked TW's list
537	 * and then remove this TW from the list.
538	 */
539	if (pp->pp_itw_head == itw) {
540		if (pp->pp_itw_tail == itw) {
541			pp->pp_itw_head = NULL;
542			pp->pp_itw_tail = NULL;
543		} else {
544			pp->pp_itw_head = itw->itw_next;
545		}
546	} else {
547		prev = pp->pp_itw_head;
548		next = prev->itw_next;
549
550		while (next && (next != itw)) {
551			prev = next;
552			next = next->itw_next;
553		}
554
555		if (next == itw) {
556			prev->itw_next = next->itw_next;
557
558			if (pp->pp_itw_tail == itw) {
559				pp->pp_itw_tail = prev;
560			}
561		}
562	}
563
564	/* Free this iTWs dma resources */
565	ehci_free_itw_dma(ehcip, pp, itw);
566}
567
568
569/*
570 * ehci_free_itw_dma:
571 *
572 * Free the Isochronous Transfer Wrapper dma resources.
573 */
574/*ARGSUSED*/
575static void
576ehci_free_itw_dma(
577	ehci_state_t		*ehcip,
578	ehci_pipe_private_t	*pp,
579	ehci_isoc_xwrapper_t	*itw)
580{
581	int	rval;
582
583	USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
584	    "ehci_free_itw_dma: itw = 0x%p", (void *)itw);
585
586	ASSERT(itw != NULL);
587	ASSERT(itw->itw_id != NULL);
588
589	/* Free 32bit ID */
590	EHCI_FREE_ID((uint32_t)itw->itw_id);
591
592	rval = ddi_dma_unbind_handle(itw->itw_dmahandle);
593	ASSERT(rval == DDI_SUCCESS);
594
595	ddi_dma_mem_free(&itw->itw_accesshandle);
596	ddi_dma_free_handle(&itw->itw_dmahandle);
597
598	/* Free transfer wrapper */
599	kmem_free(itw, sizeof (ehci_isoc_xwrapper_t));
600}
601
602
603/*
604 * transfer descriptor functions
605 */
606/*
607 * ehci_allocate_itd:
608 *
609 * Allocate a Transfer Descriptor (iTD) from the iTD buffer pool.
610 */
611static ehci_itd_t *
612ehci_allocate_itd(ehci_state_t	*ehcip)
613{
614	int		i, state;
615	ehci_itd_t	*itd;
616
617	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
618
619	/*
620	 * Search for a blank Transfer Descriptor (iTD)
621	 * in the iTD buffer pool.
622	 */
623	for (i = 0; i < ehci_itd_pool_size; i ++) {
624		state = Get_ITD(ehcip->ehci_itd_pool_addr[i].itd_state);
625		if (state == EHCI_ITD_FREE) {
626			break;
627		}
628	}
629
630	if (i >= ehci_itd_pool_size) {
631		USB_DPRINTF_L2(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
632		    "ehci_allocate_itd: ITD exhausted");
633
634		return (NULL);
635	}
636
637	USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
638	    "ehci_allocate_itd: Allocated %d", i);
639
640	/* Create a new dummy for the end of the ITD list */
641	itd = &ehcip->ehci_itd_pool_addr[i];
642
643	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
644	    "ehci_allocate_itd: itd 0x%p", (void *)itd);
645
646	/* Mark the newly allocated ITD as a empty */
647	Set_ITD(itd->itd_state, EHCI_ITD_DUMMY);
648
649	return (itd);
650}
651
652
653/*
654 * ehci_deallocate_itd:
655 *
656 * Deallocate a Host Controller's (HC) Transfer Descriptor (ITD).
657 *
658 */
659void
660ehci_deallocate_itd(
661	ehci_state_t		*ehcip,
662	ehci_isoc_xwrapper_t	*itw,
663	ehci_itd_t		*old_itd)
664{
665	ehci_itd_t	*itd, *next_itd;
666
667	USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
668	    "ehci_deallocate_itd: old_itd = 0x%p", (void *)old_itd);
669
670	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
671	ASSERT(Get_ITD(old_itd->itd_trans_wrapper) == itw->itw_id);
672
673	/* If it has been marked RECLAIM it has already been removed */
674	if (Get_ITD(old_itd->itd_state) != EHCI_ITD_RECLAIM) {
675		ehci_remove_isoc_from_pfl(ehcip, old_itd);
676	}
677
678	/* Make sure the ITD is not in the PFL */
679	ASSERT(Get_ITD_FRAME(old_itd->itd_frame_number) == 0);
680
681	/* Remove the itd from the itw */
682	itd = itw->itw_itd_head;
683	if (old_itd != itd) {
684		next_itd = ehci_itd_iommu_to_cpu(ehcip,
685		    Get_ITD(itd->itd_itw_next_itd));
686
687		while (next_itd != old_itd) {
688			itd = next_itd;
689			next_itd = ehci_itd_iommu_to_cpu(ehcip,
690			    Get_ITD(itd->itd_itw_next_itd));
691		}
692
693		Set_ITD(itd->itd_itw_next_itd, old_itd->itd_itw_next_itd);
694
695		if (itd->itd_itw_next_itd == NULL) {
696			itw->itw_itd_tail = itd;
697		}
698	} else {
699		itw->itw_itd_head = ehci_itd_iommu_to_cpu(
700		    ehcip, Get_ITD(old_itd->itd_itw_next_itd));
701
702		if (itw->itw_itd_head == NULL) {
703			itw->itw_itd_tail = NULL;
704		}
705	}
706
707	bzero((char *)old_itd, sizeof (ehci_itd_t));
708	Set_ITD(old_itd->itd_state, EHCI_ITD_FREE);
709
710	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
711	    "Dealloc_itd: itd 0x%p", (void *)old_itd);
712}
713
714
715/*
716 * ehci_calc_num_itds:
717 *
718 * Calculates how many ITDs are needed for this request.
719 * The calculation is based on weather it is an HIGH speed
720 * transaction of a FULL/LOW transaction.
721 *
722 * For FULL/LOW transaction more itds are necessary if it
723 * spans frames.
724 */
725uint_t
726ehci_calc_num_itds(
727	ehci_isoc_xwrapper_t	*itw,
728	size_t			pkt_count)
729{
730	uint_t			multiplier, itd_count;
731
732	/* Allocate the appropriate isoc resources */
733	if (itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
734		/* Multiplier needs to be passed in somehow */
735		multiplier = 1 * 8;
736		itd_count = pkt_count / multiplier;
737		if (pkt_count % multiplier) {
738			itd_count++;
739		}
740	} else {
741		itd_count = (uint_t)pkt_count;
742	}
743
744	return (itd_count);
745}
746
747/*
748 * ehci_allocate_itds_for_itw:
749 *
750 * Allocate n Transfer Descriptors (TD) from the TD buffer pool and places it
751 * into the TW.
752 *
753 * Returns USB_NO_RESOURCES if it was not able to allocate all the requested TD
754 * otherwise USB_SUCCESS.
755 */
756int
757ehci_allocate_itds_for_itw(
758	ehci_state_t		*ehcip,
759	ehci_isoc_xwrapper_t	*itw,
760	uint_t			itd_count)
761{
762	ehci_itd_t		*itd;
763	uint32_t		itd_addr;
764	int			i;
765	int			error = USB_SUCCESS;
766
767	for (i = 0; i < itd_count; i += 1) {
768		itd = ehci_allocate_itd(ehcip);
769		if (itd == NULL) {
770			error = USB_NO_RESOURCES;
771			USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
772			    "ehci_allocate_itds_for_itw: "
773			    "Unable to allocate %d ITDs",
774			    itd_count);
775			break;
776		}
777		if (i > 0) {
778			itd_addr = ehci_itd_cpu_to_iommu(ehcip,
779			    itw->itw_itd_free_list);
780			Set_ITD(itd->itd_link_ptr, itd_addr);
781		}
782		Set_ITD_INDEX(itd, 0, EHCI_ITD_UNUSED_INDEX);
783		Set_ITD_INDEX(itd, 1, EHCI_ITD_UNUSED_INDEX);
784		Set_ITD_INDEX(itd, 2, EHCI_ITD_UNUSED_INDEX);
785		Set_ITD_INDEX(itd, 3, EHCI_ITD_UNUSED_INDEX);
786		Set_ITD_INDEX(itd, 4, EHCI_ITD_UNUSED_INDEX);
787		Set_ITD_INDEX(itd, 5, EHCI_ITD_UNUSED_INDEX);
788		Set_ITD_INDEX(itd, 6, EHCI_ITD_UNUSED_INDEX);
789		Set_ITD_INDEX(itd, 7, EHCI_ITD_UNUSED_INDEX);
790		itw->itw_itd_free_list = itd;
791	}
792
793	return (error);
794}
795
796
797/*
798 * ehci_deallocate_itds_for_itw:
799 *
800 * Free all allocated resources for Transaction Wrapper (TW).
801 * Does not free the iTW itself.
802 */
803static void
804ehci_deallocate_itds_for_itw(
805	ehci_state_t		*ehcip,
806	ehci_isoc_xwrapper_t	*itw)
807{
808	ehci_itd_t		*itd = NULL;
809	ehci_itd_t		*temp_itd = NULL;
810
811	USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
812	    "ehci_free_itw_itd_resources: itw = 0x%p", (void *)itw);
813
814	itd = itw->itw_itd_free_list;
815	while (itd != NULL) {
816		/* Save the pointer to the next itd before destroying it */
817		temp_itd = ehci_itd_iommu_to_cpu(ehcip,
818		    Get_ITD(itd->itd_link_ptr));
819		ehci_deallocate_itd(ehcip, itw, itd);
820		itd = temp_itd;
821	}
822	itw->itw_itd_free_list = NULL;
823}
824
825
826/*
827 * ehci_insert_itd_on_itw:
828 *
829 * The transfer wrapper keeps a list of all Transfer Descriptors (iTD) that
830 * are allocated for this transfer. Insert a iTD onto this list.
831 */
832void ehci_insert_itd_on_itw(
833	ehci_state_t		*ehcip,
834	ehci_isoc_xwrapper_t	*itw,
835	ehci_itd_t		*itd)
836{
837	/*
838	 * Set the next pointer to NULL because
839	 * this is the last ITD on list.
840	 */
841	Set_ITD(itd->itd_itw_next_itd, NULL);
842
843	if (itw->itw_itd_head == NULL) {
844		ASSERT(itw->itw_itd_tail == NULL);
845		itw->itw_itd_head = itd;
846		itw->itw_itd_tail = itd;
847	} else {
848		ehci_itd_t *dummy = (ehci_itd_t *)itw->itw_itd_tail;
849
850		ASSERT(dummy != NULL);
851		ASSERT(Get_ITD(itd->itd_state) == EHCI_ITD_ACTIVE);
852
853		/* Add the itd to the end of the list */
854		Set_ITD(dummy->itd_itw_next_itd,
855		    ehci_itd_cpu_to_iommu(ehcip, itd));
856
857		itw->itw_itd_tail = itd;
858	}
859
860	Set_ITD(itd->itd_trans_wrapper, (uint32_t)itw->itw_id);
861}
862
863
864/*
865 * ehci_insert_itd_into_active_list:
866 *
867 * Add current ITD into the active ITD list in reverse order.
868 * When he done list is created, remove it in the reverse order.
869 */
870void
871ehci_insert_itd_into_active_list(
872	ehci_state_t		*ehcip,
873	ehci_itd_t		*itd)
874{
875	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
876	ASSERT(itd != NULL);
877
878	Set_ITD(itd->itd_next_active_itd,
879	    ehci_itd_cpu_to_iommu(ehcip, ehcip->ehci_active_itd_list));
880	ehcip->ehci_active_itd_list = itd;
881}
882
883
884/*
885 * ehci_remove_itd_from_active_list:
886 *
887 * Remove current ITD from the active ITD list.
888 */
889void
890ehci_remove_itd_from_active_list(
891	ehci_state_t		*ehcip,
892	ehci_itd_t		*itd)
893{
894	ehci_itd_t		*curr_itd, *next_itd;
895
896	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
897	ASSERT(itd != NULL);
898
899	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
900	    "ehci_remove_itd_from_active_list: "
901	    "ehci_active_itd_list = 0x%p itd = 0x%p",
902	    (void *)ehcip->ehci_active_itd_list, (void *)itd);
903
904	curr_itd = ehcip->ehci_active_itd_list;
905
906	if (curr_itd == itd) {
907		ehcip->ehci_active_itd_list =
908		    ehci_itd_iommu_to_cpu(ehcip, itd->itd_next_active_itd);
909		itd->itd_next_active_itd = NULL;
910
911		return;
912	}
913
914	next_itd = ehci_itd_iommu_to_cpu(ehcip, curr_itd->itd_next_active_itd);
915	while (next_itd != itd) {
916		curr_itd = next_itd;
917		if (curr_itd) {
918			next_itd = ehci_itd_iommu_to_cpu(ehcip,
919			    curr_itd->itd_next_active_itd);
920		} else {
921			break;
922		}
923	}
924
925	if ((curr_itd) && (next_itd == itd)) {
926		Set_ITD(curr_itd->itd_next_active_itd,
927		    Get_ITD(itd->itd_next_active_itd));
928		Set_ITD(itd->itd_next_active_itd, NULL);
929	} else {
930		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
931		    "ehci_remove_itd_from_active_list: "
932		    "Unable to find ITD in active_itd_list");
933	}
934}
935
936
937/*
938 * ehci_create_done_itd_list:
939 *
940 * Traverse the active list and create a done list and remove them
941 * from the active list.
942 */
943ehci_itd_t *
944ehci_create_done_itd_list(
945	ehci_state_t		*ehcip)
946{
947	usb_frame_number_t	current_frame_number;
948	usb_frame_number_t	itd_frame_number, itd_reclaim_number;
949	ehci_itd_t		*curr_itd = NULL, *next_itd = NULL;
950	ehci_itd_t		*done_itd_list = NULL;
951	uint_t			state;
952
953	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
954	    "ehci_create_done_itd_list:");
955
956	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
957
958	/*
959	 * Get the current frame number.
960	 * Only process itd that were inserted before the current
961	 * frame number.
962	 */
963	current_frame_number = ehci_get_current_frame_number(ehcip);
964
965	curr_itd = ehcip->ehci_active_itd_list;
966
967	while (curr_itd) {
968		/* Get next itd from the active itd list */
969		next_itd = ehci_itd_iommu_to_cpu(ehcip,
970		    Get_ITD(curr_itd->itd_next_active_itd));
971
972		/*
973		 * If haven't past the frame number that the ITD was
974		 * suppose to be executed, don't touch it.  Just in
975		 * case it is being processed by the HCD and cause
976		 * a race condition.
977		 */
978		itd_frame_number = Get_ITD_FRAME(curr_itd->itd_frame_number);
979		itd_reclaim_number =
980		    Get_ITD_FRAME(curr_itd->itd_reclaim_number);
981
982		/* Get the ITD state */
983		state = Get_ITD(curr_itd->itd_state);
984
985		if (((state == EHCI_ITD_ACTIVE) &&
986		    (itd_frame_number < current_frame_number)) ||
987		    ((state == EHCI_ITD_RECLAIM) &&
988		    (itd_reclaim_number < current_frame_number))) {
989
990			/* Remove this ITD from active ITD list */
991			ehci_remove_itd_from_active_list(ehcip, curr_itd);
992
993			/*
994			 * Create the done list in reverse order, since the
995			 * active list was also created in reverse order.
996			 */
997			Set_ITD(curr_itd->itd_next_active_itd,
998			    ehci_itd_cpu_to_iommu(ehcip, done_itd_list));
999			done_itd_list = curr_itd;
1000		}
1001
1002		curr_itd = next_itd;
1003	}
1004
1005	return (done_itd_list);
1006}
1007
1008
1009/*
1010 * ehci_insert_isoc_to_pfl:
1011 *
1012 * Insert a ITD request into the Host Controller's isochronous list.
1013 * All the ITDs in the ITW will be added the PFL at once.  Either all
1014 * of them will make it or none of them will.
1015 */
1016int
1017ehci_insert_isoc_to_pfl(
1018	ehci_state_t		*ehcip,
1019	ehci_pipe_private_t	*pp,
1020	ehci_isoc_xwrapper_t	*itw)
1021{
1022	usb_isoc_req_t		*isoc_reqp = itw->itw_curr_xfer_reqp;
1023	usb_frame_number_t	current_frame_number, start_frame_number;
1024	uint_t			ddic, pfl_number;
1025	ehci_periodic_frame_list_t *periodic_frame_list =
1026	    ehcip->ehci_periodic_frame_list_tablep;
1027	uint32_t		addr, port_status;
1028	ehci_itd_t		*itd;
1029
1030	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1031	    "ehci_insert_isoc_to_pfl: "
1032	    "isoc flags 0x%x itw = 0x%p",
1033	    isoc_reqp->isoc_attributes, (void *)itw);
1034
1035	/*
1036	 * Enter critical, while programming the usb frame number
1037	 * and inserting current isochronous TD into the ED's list.
1038	 */
1039	ddic = ddi_enter_critical();
1040
1041	/* Get the current frame number */
1042	current_frame_number = ehci_get_current_frame_number(ehcip);
1043
1044	/*
1045	 * Check the given isochronous flags and get the frame number
1046	 * to insert the itd into.
1047	 */
1048	switch (isoc_reqp->isoc_attributes &
1049	    (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) {
1050	case USB_ATTRS_ISOC_START_FRAME:
1051
1052		/* Starting frame number is specified */
1053		if (pp->pp_flag & EHCI_ISOC_XFER_CONTINUE) {
1054			/* Get the starting usb frame number */
1055			start_frame_number = pp->pp_next_frame_number;
1056		} else {
1057			/* Check for the Starting usb frame number */
1058			if ((isoc_reqp->isoc_frame_no == 0) ||
1059			    ((isoc_reqp->isoc_frame_no +
1060			    isoc_reqp->isoc_pkts_count) <
1061			    current_frame_number)) {
1062
1063				/* Exit the critical */
1064				ddi_exit_critical(ddic);
1065
1066				USB_DPRINTF_L2(PRINT_MASK_LISTS,
1067				    ehcip->ehci_log_hdl,
1068				    "ehci_insert_isoc_to_pfl:"
1069				    "Invalid starting frame number");
1070
1071				return (USB_INVALID_START_FRAME);
1072			}
1073
1074			/* Get the starting usb frame number */
1075			start_frame_number = isoc_reqp->isoc_frame_no;
1076
1077			pp->pp_next_frame_number = 0;
1078		}
1079		break;
1080	case USB_ATTRS_ISOC_XFER_ASAP:
1081		/* ehci has to specify starting frame number */
1082		if ((pp->pp_next_frame_number) &&
1083		    (pp->pp_next_frame_number > current_frame_number)) {
1084			/*
1085			 * Get the next usb frame number.
1086			 */
1087			start_frame_number = pp->pp_next_frame_number;
1088		} else {
1089			/*
1090			 * Add appropriate offset to the current usb
1091			 * frame number and use it as a starting frame
1092			 * number.
1093			 */
1094			start_frame_number =
1095			    current_frame_number + EHCI_FRAME_OFFSET;
1096		}
1097
1098		if (!(pp->pp_flag & EHCI_ISOC_XFER_CONTINUE)) {
1099			isoc_reqp->isoc_frame_no = start_frame_number;
1100		}
1101		break;
1102	default:
1103		/* Exit the critical */
1104		ddi_exit_critical(ddic);
1105
1106		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1107		    "ehci_insert_isoc_to_pfl: Either starting "
1108		    "frame number or ASAP flags are not set, attrs = 0x%x",
1109		    isoc_reqp->isoc_attributes);
1110
1111		return (USB_NO_FRAME_NUMBER);
1112	}
1113
1114	if (itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
1115		port_status = EHCI_ITD_LINK_REF_ITD;
1116	} else {
1117		port_status = EHCI_ITD_LINK_REF_SITD;
1118	}
1119
1120	itd = itw->itw_itd_head;
1121	while (itd) {
1122		/* Find the appropriate frame list to put the itd into */
1123		pfl_number = start_frame_number % EHCI_NUM_PERIODIC_FRAME_LISTS;
1124
1125		addr = Get_PFLT(periodic_frame_list->
1126		    ehci_periodic_frame_list_table[pfl_number]);
1127		Set_ITD(itd->itd_link_ptr, addr);
1128
1129		/* Set the link_ref correctly as ITD or SITD. */
1130		addr = ehci_itd_cpu_to_iommu(ehcip, itd) & EHCI_ITD_LINK_PTR;
1131		addr |= port_status;
1132
1133		Set_PFLT(periodic_frame_list->
1134		    ehci_periodic_frame_list_table[pfl_number], addr);
1135
1136		/* Save which frame the ITD was inserted into */
1137		Set_ITD_FRAME(itd->itd_frame_number, start_frame_number);
1138
1139		ehci_insert_itd_into_active_list(ehcip, itd);
1140
1141		/* Get the next ITD in the ITW */
1142		itd = ehci_itd_iommu_to_cpu(ehcip,
1143		    Get_ITD(itd->itd_itw_next_itd));
1144
1145		start_frame_number++;
1146	}
1147
1148	/* Exit the critical */
1149	ddi_exit_critical(ddic);
1150
1151	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1152	    "ehci_insert_isoc_to_pfl: "
1153	    "current frame number 0x%llx start frame number 0x%llx num itds %d",
1154	    (unsigned long long)current_frame_number,
1155	    (unsigned long long)start_frame_number, itw->itw_num_itds);
1156
1157	/*
1158	 * Increment this saved frame number by current number
1159	 * of data packets needs to be transfer.
1160	 */
1161	pp->pp_next_frame_number = start_frame_number;
1162
1163	/*
1164	 * Set EHCI_ISOC_XFER_CONTINUE flag in order to send other
1165	 * isochronous packets,  part of the current isoch request
1166	 * in the subsequent frames.
1167	 */
1168	pp->pp_flag |= EHCI_ISOC_XFER_CONTINUE;
1169
1170	return (USB_SUCCESS);
1171}
1172
1173
1174/*
1175 * ehci_remove_isoc_to_pfl:
1176 *
1177 * Remove an ITD request from the Host Controller's isochronous list.
1178 * If we can't find it, something has gone wrong.
1179 */
1180void
1181ehci_remove_isoc_from_pfl(
1182	ehci_state_t		*ehcip,
1183	ehci_itd_t		*curr_itd)
1184{
1185	ehci_periodic_frame_list_t *periodic_frame_list;
1186	uint_t		pfl_number;
1187	uint32_t	next_addr, curr_itd_addr;
1188	uint32_t	link_ref;
1189	ehci_itd_t	*prev_itd = NULL;
1190
1191	USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
1192	    "ehci_remove_isoc_from_pfl:");
1193
1194	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1195
1196	/* Get the address of the current itd */
1197	curr_itd_addr = ehci_itd_cpu_to_iommu(ehcip, curr_itd);
1198
1199	/*
1200	 * Remove this ITD from the PFL
1201	 * But first we need to find it in the PFL
1202	 */
1203	periodic_frame_list = ehcip->ehci_periodic_frame_list_tablep;
1204	pfl_number = Get_ITD_FRAME(curr_itd->itd_frame_number) %
1205	    EHCI_NUM_PERIODIC_FRAME_LISTS;
1206
1207	USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
1208	    "ehci_remove_isoc_from_pfl: itd = 0x%p pfl number 0x%x",
1209	    (void *)curr_itd, pfl_number);
1210
1211	next_addr = Get_PFLT(periodic_frame_list->
1212	    ehci_periodic_frame_list_table[pfl_number]);
1213	while ((next_addr & EHCI_ITD_LINK_PTR) !=
1214	    (curr_itd_addr & EHCI_ITD_LINK_PTR)) {
1215
1216		link_ref = next_addr & EHCI_ITD_LINK_REF;
1217
1218		if ((link_ref == EHCI_ITD_LINK_REF_ITD) ||
1219		    (link_ref == EHCI_ITD_LINK_REF_SITD)) {
1220
1221			prev_itd = ehci_itd_iommu_to_cpu(ehcip,
1222			    (next_addr & EHCI_ITD_LINK_PTR));
1223			next_addr = Get_ITD(prev_itd->itd_link_ptr);
1224		} else {
1225
1226			break;
1227		}
1228	}
1229
1230	/*
1231	 * If the next itd is the current itd, that means we found it.
1232	 * Set the previous's ITD link ptr to the Curr_ITD's link ptr.
1233	 * But do not touch the Curr_ITD's link ptr.
1234	 */
1235	if ((next_addr & EHCI_ITD_LINK_PTR) ==
1236	    (curr_itd_addr & EHCI_ITD_LINK_PTR)) {
1237
1238		next_addr = Get_ITD(curr_itd->itd_link_ptr);
1239
1240		if (prev_itd == NULL) {
1241			/* This means PFL points to this ITD */
1242			Set_PFLT(periodic_frame_list->
1243			    ehci_periodic_frame_list_table[pfl_number],
1244			    next_addr);
1245		} else {
1246			/* Set the previous ITD's itd_link_ptr */
1247			Set_ITD(prev_itd->itd_link_ptr, next_addr);
1248		}
1249
1250		Set_ITD_FRAME(curr_itd->itd_frame_number, 0);
1251	} else {
1252		ASSERT((next_addr & EHCI_ITD_LINK_PTR) ==
1253		    (curr_itd_addr & EHCI_ITD_LINK_PTR));
1254		USB_DPRINTF_L3(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
1255		    "ehci_remove_isoc_from_pfl: Unable to find ITD in PFL");
1256	}
1257}
1258
1259
1260/*
1261 * Isochronous in resource functions
1262 */
1263/*
1264 * ehci_allocate_periodic_in_resource
1265 *
1266 * Allocate interrupt request structure for the interrupt IN transfer.
1267 */
1268int
1269ehci_allocate_isoc_in_resource(
1270	ehci_state_t		*ehcip,
1271	ehci_pipe_private_t	*pp,
1272	ehci_isoc_xwrapper_t	*itw,
1273	usb_flags_t		flags)
1274{
1275	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
1276	usb_isoc_req_t		*orig_isoc_reqp, *clone_isoc_reqp;
1277
1278	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1279	    "ehci_allocate_isoc_in_resource:"
1280	    "pp = 0x%p itw = 0x%p flags = 0x%x", (void *)pp, (void *)itw,
1281	    flags);
1282
1283	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1284	ASSERT(itw->itw_curr_xfer_reqp == NULL);
1285
1286	/* Get the client periodic in request pointer */
1287	orig_isoc_reqp = (usb_isoc_req_t *)(pp->pp_client_periodic_in_reqp);
1288
1289	ASSERT(orig_isoc_reqp != NULL);
1290
1291	clone_isoc_reqp = usba_hcdi_dup_isoc_req(ph->p_dip,
1292	    orig_isoc_reqp, flags);
1293
1294	if (clone_isoc_reqp == NULL) {
1295		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1296		    "ehci_allocate_isoc_in_resource: Isochronous"
1297		    "request structure allocation failed");
1298
1299		return (USB_NO_RESOURCES);
1300	}
1301
1302	/*
1303	 * Save the client's isochronous request pointer and
1304	 * length of isochronous transfer in transfer wrapper.
1305	 * The dup'ed request is saved in pp_client_periodic_in_reqp
1306	 */
1307	itw->itw_curr_xfer_reqp = orig_isoc_reqp;
1308
1309	pp->pp_client_periodic_in_reqp = (usb_opaque_t)clone_isoc_reqp;
1310
1311	mutex_enter(&ph->p_mutex);
1312	ph->p_req_count++;
1313	mutex_exit(&ph->p_mutex);
1314
1315	pp->pp_state = EHCI_PIPE_STATE_ACTIVE;
1316
1317	return (USB_SUCCESS);
1318}
1319
1320
1321/*
1322 * ehci_deallocate_isoc_in_resource
1323 *
1324 * Deallocate interrupt request structure for the interrupt IN transfer.
1325 */
1326void
1327ehci_deallocate_isoc_in_resource(
1328	ehci_state_t		*ehcip,
1329	ehci_pipe_private_t	*pp,
1330	ehci_isoc_xwrapper_t	*itw)
1331{
1332	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
1333	uchar_t			ep_attr = ph->p_ep.bmAttributes;
1334	usb_isoc_req_t		*isoc_reqp;
1335
1336	USB_DPRINTF_L4(PRINT_MASK_LISTS,
1337	    ehcip->ehci_log_hdl,
1338	    "ehci_deallocate_isoc_in_resource: "
1339	    "pp = 0x%p itw = 0x%p", (void *)pp, (void *)itw);
1340
1341	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1342	ASSERT((ep_attr & USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH);
1343
1344	isoc_reqp = itw->itw_curr_xfer_reqp;
1345
1346	/* Check the current periodic in request pointer */
1347	if (isoc_reqp) {
1348		itw->itw_curr_xfer_reqp = NULL;
1349		itw->itw_curr_isoc_pktp = NULL;
1350
1351		mutex_enter(&ph->p_mutex);
1352		ph->p_req_count--;
1353		mutex_exit(&ph->p_mutex);
1354
1355		usb_free_isoc_req(isoc_reqp);
1356
1357		/* Set periodic in pipe state to idle */
1358		pp->pp_state = EHCI_PIPE_STATE_IDLE;
1359	}
1360}
1361
1362
1363/*
1364 * ehci_itd_cpu_to_iommu:
1365 *
1366 * This function converts for the given Transfer Descriptor (ITD) CPU address
1367 * to IO address.
1368 */
1369uint32_t
1370ehci_itd_cpu_to_iommu(
1371	ehci_state_t	*ehcip,
1372	ehci_itd_t	*addr)
1373{
1374	uint32_t	td;
1375
1376	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1377
1378	if (addr == NULL) {
1379
1380		return (NULL);
1381	}
1382
1383	td = (uint32_t)ehcip->ehci_itd_pool_cookie.dmac_address +
1384	    (uint32_t)((uintptr_t)addr -
1385	    (uintptr_t)(ehcip->ehci_itd_pool_addr));
1386
1387	ASSERT(((uint32_t) (sizeof (ehci_itd_t) *
1388	    (addr - ehcip->ehci_itd_pool_addr))) ==
1389	    ((uint32_t)((uintptr_t)addr - (uintptr_t)
1390	    (ehcip->ehci_itd_pool_addr))));
1391
1392	ASSERT(td >= ehcip->ehci_itd_pool_cookie.dmac_address);
1393	ASSERT(td <= ehcip->ehci_itd_pool_cookie.dmac_address +
1394	    sizeof (ehci_itd_t) * ehci_itd_pool_size);
1395
1396	return (td);
1397}
1398
1399
1400/*
1401 * ehci_itd_iommu_to_cpu:
1402 *
1403 * This function converts for the given Transfer Descriptor (ITD) IO address
1404 * to CPU address.
1405 */
1406ehci_itd_t *
1407ehci_itd_iommu_to_cpu(
1408	ehci_state_t	*ehcip,
1409	uintptr_t	addr)
1410{
1411	ehci_itd_t	*itd;
1412
1413	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1414
1415	if (addr == NULL) {
1416
1417		return (NULL);
1418	}
1419
1420	itd = (ehci_itd_t *)((uintptr_t)
1421	    (addr - ehcip->ehci_itd_pool_cookie.dmac_address) +
1422	    (uintptr_t)ehcip->ehci_itd_pool_addr);
1423
1424	ASSERT(itd >= ehcip->ehci_itd_pool_addr);
1425	ASSERT((uintptr_t)itd <= (uintptr_t)ehcip->ehci_itd_pool_addr +
1426	    (uintptr_t)(sizeof (ehci_itd_t) * ehci_itd_pool_size));
1427
1428	return (itd);
1429}
1430
1431
1432/*
1433 * Error parsing functions
1434 */
1435void ehci_parse_isoc_error(
1436	ehci_state_t		*ehcip,
1437	ehci_isoc_xwrapper_t	*itw,
1438	ehci_itd_t		*itd)
1439{
1440	usb_isoc_req_t		*isoc_reqp;
1441	usb_cr_t		error;
1442
1443	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1444
1445	isoc_reqp = itw->itw_curr_xfer_reqp;
1446
1447	if (itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
1448		error = ehci_parse_itd_error(ehcip, itw, itd);
1449	} else {
1450		error = ehci_parse_sitd_error(ehcip, itw, itd);
1451
1452		if (error != USB_CR_OK) {
1453			isoc_reqp->isoc_error_count++;
1454
1455			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1456			    "ehci_parse_sitd_error: Error %d Device Address %d"
1457			    " Endpoint number %d", error, itw->itw_device_addr,
1458			    itw->itw_endpoint_num);
1459		}
1460
1461	}
1462}
1463
1464
1465/* ARGSUSED */
1466static usb_cr_t ehci_parse_itd_error(
1467	ehci_state_t		*ehcip,
1468	ehci_isoc_xwrapper_t	*itw,
1469	ehci_itd_t		*itd)
1470{
1471	uint32_t		status, index;
1472	usb_cr_t		error = USB_CR_OK;
1473	uint32_t		i;
1474	usb_isoc_req_t		*isoc_reqp;
1475
1476	isoc_reqp = itw->itw_curr_xfer_reqp;
1477
1478	for (i = 0; i < EHCI_ITD_CTRL_LIST_SIZE; i++) {
1479		index = Get_ITD_INDEX(itd, i);
1480		if (index == 0xffffffff) {
1481
1482			continue;
1483		}
1484
1485		error = USB_CR_OK;
1486
1487		status = Get_ITD_BODY(itd, EHCI_ITD_CTRL0 + i) &
1488		    EHCI_ITD_XFER_STATUS_MASK;
1489
1490		if (status & EHCI_ITD_XFER_DATA_BUFFER_ERR) {
1491			if (itw->itw_direction == USB_EP_DIR_OUT) {
1492				USB_DPRINTF_L3(PRINT_MASK_INTR,
1493				    ehcip->ehci_log_hdl,
1494				    "ehci_parse_itd_error: BUFFER Underrun");
1495
1496				error = USB_CR_BUFFER_UNDERRUN;
1497			} else {
1498				USB_DPRINTF_L3(PRINT_MASK_INTR,
1499				    ehcip->ehci_log_hdl,
1500				    "ehci_parse_itd_error: BUFFER Overrun");
1501
1502				error = USB_CR_BUFFER_OVERRUN;
1503			}
1504		}
1505
1506		if (status & EHCI_ITD_XFER_BABBLE) {
1507			USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1508			    "ehci_parse_itd_error: BABBLE DETECTED");
1509
1510			error = USB_CR_DATA_OVERRUN;
1511		}
1512
1513		if (status & EHCI_ITD_XFER_ERROR) {
1514			USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1515			    "ehci_parse_itd_error: XACT ERROR");
1516
1517			error = USB_CR_DEV_NOT_RESP;
1518		}
1519
1520		if (status & EHCI_ITD_XFER_ACTIVE) {
1521			USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1522			    "ehci_parse_itd_error: NOT ACCESSED");
1523
1524			error = USB_CR_NOT_ACCESSED;
1525		}
1526
1527		itw->itw_curr_isoc_pktp->isoc_pkt_actual_length = 0;
1528
1529		/* Write the status of isoc data packet */
1530		itw->itw_curr_isoc_pktp->isoc_pkt_status = error;
1531
1532		/* counts total number of error packets in this req */
1533		if (error != USB_CR_OK) {
1534			isoc_reqp->isoc_error_count++;
1535			USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1536			    "ehci_parse_itd_error: Error %d Device Address %d "
1537			    "Endpoint number %d", error, itw->itw_device_addr,
1538			    itw->itw_endpoint_num);
1539		}
1540
1541		itw->itw_curr_isoc_pktp++;
1542	}
1543
1544	return (error);
1545}
1546
1547static usb_cr_t ehci_parse_sitd_error(
1548	ehci_state_t		*ehcip,
1549	ehci_isoc_xwrapper_t	*itw,
1550	ehci_itd_t		*itd)
1551{
1552	uint32_t		status;
1553	usb_cr_t		error;
1554	usb_isoc_pkt_descr_t	*isoc_pkt_descr;
1555	uint32_t		residue;
1556
1557	isoc_pkt_descr = itw->itw_curr_isoc_pktp;
1558
1559	status = Get_ITD_BODY(itd, EHCI_SITD_XFER_STATE) &
1560	    EHCI_SITD_XFER_STATUS_MASK;
1561
1562	switch (status) {
1563	case EHCI_SITD_XFER_ACTIVE:
1564		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1565		    "ehci_check_for_sitd_error: NOT ACCESSED");
1566		error = USB_CR_NOT_ACCESSED;
1567
1568		break;
1569	case EHCI_SITD_XFER_ERROR:
1570		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1571		    "ehci_check_for_sitd_error: TT ERROR");
1572
1573		error = USB_CR_UNSPECIFIED_ERR;
1574
1575		break;
1576	case EHCI_SITD_XFER_DATA_BUFFER_ERR:
1577		if (itw->itw_direction == USB_EP_DIR_OUT) {
1578			USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1579			    "ehci_check_for_sitd_error: BUFFER Underrun");
1580			error = USB_CR_BUFFER_UNDERRUN;
1581		} else {
1582			USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1583			    "ehci_check_for_sitd_error: BUFFER Overrun");
1584			error = USB_CR_BUFFER_OVERRUN;
1585		}
1586
1587		break;
1588	case EHCI_SITD_XFER_BABBLE:
1589		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1590		    "ehci_check_for_sitd_error: BABBLE");
1591		error = USB_CR_DATA_OVERRUN;
1592
1593		break;
1594	case EHCI_SITD_XFER_XACT_ERROR:
1595		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1596		    "ehci_check_for_sitd_error: XACT ERROR");
1597
1598		error = USB_CR_DEV_NOT_RESP;
1599		break;
1600	case EHCI_SITD_XFER_MISSED_UFRAME:
1601		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1602		    "ehci_check_for_sitd_error: MISSED UFRAME");
1603
1604		error = USB_CR_NOT_ACCESSED;
1605		break;
1606	default:
1607		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1608		    "ehci_check_for_sitd_error: NO ERROR");
1609		error = USB_CR_OK;
1610
1611		break;
1612	}
1613
1614	/* This is HCD specific and may not have this information */
1615	residue =
1616	    (Get_ITD_BODY(itd, EHCI_SITD_XFER_STATE) &
1617	    EHCI_SITD_XFER_TOTAL_MASK) >>
1618	    EHCI_SITD_XFER_TOTAL_SHIFT;
1619
1620	/*
1621	 * Subtract the residue from the isoc_pkt_descr that
1622	 * was set when this ITD was inserted.
1623	 */
1624	isoc_pkt_descr->isoc_pkt_actual_length -= residue;
1625
1626	/* Write the status of isoc data packet */
1627	isoc_pkt_descr->isoc_pkt_status = error;
1628
1629	itw->itw_curr_isoc_pktp++;
1630
1631	return (error);
1632}
1633
1634
1635/*
1636 * debug print functions
1637 */
1638void
1639ehci_print_itd(
1640	ehci_state_t	*ehcip,
1641	ehci_itd_t	*itd)
1642{
1643	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1644	    "ehci_print_itd: itd = 0x%p", (void *)itd);
1645
1646	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1647	    "\titd_link_ptr: 0x%x ", Get_ITD(itd->itd_link_ptr));
1648
1649	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1650	    "\titd_ctrl0: 0x%x ",
1651	    Get_ITD(itd->itd_body[EHCI_ITD_CTRL0]));
1652	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1653	    "\titd_ctrl1: 0x%x ",
1654	    Get_ITD(itd->itd_body[EHCI_ITD_CTRL1]));
1655	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1656	    "\titd_ctrl2: 0x%x ",
1657	    Get_ITD(itd->itd_body[EHCI_ITD_CTRL2]));
1658	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1659	    "\titd_ctrl3: 0x%x ",
1660	    Get_ITD(itd->itd_body[EHCI_ITD_CTRL3]));
1661	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1662	    "\titd_ctrl4: 0x%x ",
1663	    Get_ITD(itd->itd_body[EHCI_ITD_CTRL4]));
1664	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1665	    "\titd_ctrl5: 0x%x ",
1666	    Get_ITD(itd->itd_body[EHCI_ITD_CTRL5]));
1667	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1668	    "\titd_ctrl6: 0x%x ",
1669	    Get_ITD(itd->itd_body[EHCI_ITD_CTRL6]));
1670	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1671	    "\titd_ctrl7: 0x%x ",
1672	    Get_ITD(itd->itd_body[EHCI_ITD_CTRL7]));
1673	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1674	    "\titd_buffer0: 0x%x ",
1675	    Get_ITD(itd->itd_body[EHCI_ITD_BUFFER0]));
1676	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1677	    "\titd_buffer1: 0x%x ",
1678	    Get_ITD(itd->itd_body[EHCI_ITD_BUFFER1]));
1679	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1680	    "\titd_buffer2: 0x%x ",
1681	    Get_ITD(itd->itd_body[EHCI_ITD_BUFFER2]));
1682	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1683	    "\titd_buffer3: 0x%x ",
1684	    Get_ITD(itd->itd_body[EHCI_ITD_BUFFER3]));
1685	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1686	    "\titd_buffer4: 0x%x ",
1687	    Get_ITD(itd->itd_body[EHCI_ITD_BUFFER4]));
1688	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1689	    "\titd_buffer5: 0x%x ",
1690	    Get_ITD(itd->itd_body[EHCI_ITD_BUFFER5]));
1691	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1692	    "\titd_buffer6: 0x%x ",
1693	    Get_ITD(itd->itd_body[EHCI_ITD_BUFFER6]));
1694
1695	/* HCD private fields */
1696	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1697	    "\titd_trans_wrapper: 0x%x ",
1698	    Get_ITD(itd->itd_trans_wrapper));
1699	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1700	    "\titd_itw_next_itd: 0x%x ",
1701	    Get_ITD(itd->itd_itw_next_itd));
1702	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1703	    "\titd_state: 0x%x ",
1704	    Get_ITD(itd->itd_state));
1705	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1706	    "\titd_index: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ",
1707	    Get_ITD_INDEX(itd, 0), Get_ITD_INDEX(itd, 1),
1708	    Get_ITD_INDEX(itd, 2), Get_ITD_INDEX(itd, 3),
1709	    Get_ITD_INDEX(itd, 4), Get_ITD_INDEX(itd, 5),
1710	    Get_ITD_INDEX(itd, 6), Get_ITD_INDEX(itd, 7));
1711	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1712	    "\titd_frame_number: 0x%x ",
1713	    Get_ITD(itd->itd_frame_number));
1714	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1715	    "\titd_reclaim_number: 0x%x ",
1716	    Get_ITD(itd->itd_reclaim_number));
1717	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1718	    "\titd_next_active_itd: 0x%x ",
1719	    Get_ITD(itd->itd_next_active_itd));
1720}
1721
1722
1723void
1724ehci_print_sitd(
1725	ehci_state_t	*ehcip,
1726	ehci_itd_t	*itd)
1727{
1728	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1729	    "ehci_print_itd: itd = 0x%p", (void *)itd);
1730
1731	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1732	    "\titd_link_ptr: 0x%x ", Get_ITD(itd->itd_link_ptr));
1733
1734	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1735	    "\tsitd_ctrl: 0x%x ",
1736	    Get_ITD(itd->itd_body[EHCI_SITD_CTRL]));
1737	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1738	    "\tsitd_uframe_sched: 0x%x ",
1739	    Get_ITD(itd->itd_body[EHCI_SITD_UFRAME_SCHED]));
1740	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1741	    "\tsitd_xfer_state: 0x%x ",
1742	    Get_ITD(itd->itd_body[EHCI_SITD_XFER_STATE]));
1743	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1744	    "\tsitd_buffer0: 0x%x ",
1745	    Get_ITD(itd->itd_body[EHCI_SITD_BUFFER0]));
1746	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1747	    "\tsitd_buffer1: 0x%x ",
1748	    Get_ITD(itd->itd_body[EHCI_SITD_BUFFER1]));
1749	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1750	    "\tsitd_prev_sitd: 0x%x ",
1751	    Get_ITD(itd->itd_body[EHCI_SITD_PREV_SITD]));
1752
1753	/* HCD private fields */
1754	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1755	    "\titd_trans_wrapper: 0x%x ",
1756	    Get_ITD(itd->itd_trans_wrapper));
1757	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1758	    "\titd_itw_next_itd: 0x%x ",
1759	    Get_ITD(itd->itd_itw_next_itd));
1760	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1761	    "\titd_state: 0x%x ",
1762	    Get_ITD(itd->itd_state));
1763	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1764	    "\titd_frame_number: 0x%x ",
1765	    Get_ITD(itd->itd_frame_number));
1766	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1767	    "\titd_reclaim_number: 0x%x ",
1768	    Get_ITD(itd->itd_reclaim_number));
1769	USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1770	    "\titd_next_active_itd: 0x%x ",
1771	    Get_ITD(itd->itd_next_active_itd));
1772}
1773