xref: /illumos-gate/usr/src/uts/common/io/usb/hcd/ehci/ehci_isoch.c (revision 2b24ab6b3865caeede9eeb9db6b83e1d89dcd1ea)
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 #include <sys/usb/hcd/ehci/ehci_isoch.h>
41 #include <sys/usb/hcd/ehci/ehci_isoch_util.h>
42 #include <sys/strsun.h>
43 
44 /*
45  * Isochronous initialization functions
46  */
47 int ehci_isoc_init(
48 	ehci_state_t		*ehcip);
49 void ehci_isoc_cleanup(
50 	ehci_state_t		*ehcip);
51 void ehci_isoc_pipe_cleanup(
52 	ehci_state_t		*ehcip,
53 	usba_pipe_handle_data_t *ph);
54 static void ehci_wait_for_isoc_completion(
55 	ehci_state_t		*ehcip,
56 	ehci_pipe_private_t	*pp);
57 
58 /*
59  * Isochronous request functions
60  */
61 ehci_isoc_xwrapper_t *ehci_allocate_isoc_resources(
62 	ehci_state_t		*ehcip,
63 	usba_pipe_handle_data_t *ph,
64 	usb_isoc_req_t		*isoc_reqp,
65 	usb_flags_t		usb_flags);
66 int ehci_insert_isoc_req(
67 	ehci_state_t		*ehcip,
68 	ehci_pipe_private_t	*pp,
69 	ehci_isoc_xwrapper_t	*itw,
70 	usb_flags_t		usb_flags);
71 static int ehci_insert_itd_req(
72 	ehci_state_t		*ehcip,
73 	ehci_pipe_private_t	*pp,
74 	ehci_isoc_xwrapper_t	*itw,
75 	usb_flags_t		usb_flags);
76 static int ehci_insert_sitd_req(
77 	ehci_state_t		*ehcip,
78 	ehci_pipe_private_t	*pp,
79 	ehci_isoc_xwrapper_t	*itw,
80 	usb_flags_t		usb_flags);
81 static void ehci_remove_isoc_itds(
82 	ehci_state_t		*ehcip,
83 	ehci_pipe_private_t	*pp);
84 static void ehci_mark_reclaim_isoc(
85 	ehci_state_t		*ehcip,
86 	ehci_pipe_private_t	*pp);
87 static void ehci_reclaim_isoc(
88 	ehci_state_t		*ehcip,
89 	ehci_isoc_xwrapper_t	*itw,
90 	ehci_itd_t		*itd,
91 	ehci_pipe_private_t	*pp);
92 int	ehci_start_isoc_polling(
93 	ehci_state_t		*ehcip,
94 	usba_pipe_handle_data_t	*ph,
95 	usb_flags_t		flags);
96 
97 /*
98  * Isochronronous handling functions.
99  */
100 void ehci_traverse_active_isoc_list(
101 	ehci_state_t		*ehcip);
102 static void ehci_handle_isoc(
103 	ehci_state_t		*ehcip,
104 	ehci_isoc_xwrapper_t	*itw,
105 	ehci_itd_t		*itd);
106 static void ehci_handle_itd(
107 	ehci_state_t		*ehcip,
108 	ehci_pipe_private_t	*pp,
109 	ehci_isoc_xwrapper_t	*itw,
110 	ehci_itd_t		*itd,
111 	void			*tw_handle_callback_value);
112 static void ehci_sendup_itd_message(
113 	ehci_state_t		*ehcip,
114 	ehci_pipe_private_t	*pp,
115 	ehci_isoc_xwrapper_t	*itw,
116 	ehci_itd_t		*td,
117 	usb_cr_t		error);
118 void ehci_hcdi_isoc_callback(
119 	usba_pipe_handle_data_t	*ph,
120 	ehci_isoc_xwrapper_t	*itw,
121 	usb_cr_t		completion_reason);
122 
123 
124 /*
125  * Isochronous initialization functions
126  */
127 /*
128  * Initialize all the needed resources needed by isochronous pipes.
129  */
130 int
131 ehci_isoc_init(
132 	ehci_state_t		*ehcip)
133 {
134 	return (ehci_allocate_isoc_pools(ehcip));
135 }
136 
137 
138 /*
139  * Cleanup isochronous resources.
140  */
141 void
142 ehci_isoc_cleanup(
143 	ehci_state_t		*ehcip)
144 {
145 	ehci_isoc_xwrapper_t	*itw;
146 	ehci_pipe_private_t	*pp;
147 	ehci_itd_t		*itd;
148 	int			i, ctrl, rval;
149 
150 	/* Free all the buffers */
151 	if (ehcip->ehci_itd_pool_addr && ehcip->ehci_itd_pool_mem_handle) {
152 		for (i = 0; i < ehci_get_itd_pool_size(); i ++) {
153 			itd = &ehcip->ehci_itd_pool_addr[i];
154 			ctrl = Get_ITD(ehcip->
155 			    ehci_itd_pool_addr[i].itd_state);
156 
157 			if ((ctrl != EHCI_ITD_FREE) &&
158 			    (ctrl != EHCI_ITD_DUMMY) &&
159 			    (itd->itd_trans_wrapper)) {
160 
161 				mutex_enter(&ehcip->ehci_int_mutex);
162 
163 				itw = (ehci_isoc_xwrapper_t *)
164 				    EHCI_LOOKUP_ID((uint32_t)
165 				    Get_ITD(itd->itd_trans_wrapper));
166 
167 				/* Obtain the pipe private structure */
168 				pp = itw->itw_pipe_private;
169 
170 				ehci_deallocate_itd(ehcip, itw, itd);
171 				ehci_deallocate_itw(ehcip, pp, itw);
172 
173 				mutex_exit(&ehcip->ehci_int_mutex);
174 			}
175 		}
176 
177 		/*
178 		 * If EHCI_ITD_POOL_BOUND flag is set, then unbind
179 		 * the handle for ITD pools.
180 		 */
181 		if ((ehcip->ehci_dma_addr_bind_flag &
182 		    EHCI_ITD_POOL_BOUND) == EHCI_ITD_POOL_BOUND) {
183 
184 			rval = ddi_dma_unbind_handle(
185 			    ehcip->ehci_itd_pool_dma_handle);
186 
187 			ASSERT(rval == DDI_SUCCESS);
188 		}
189 		ddi_dma_mem_free(&ehcip->ehci_itd_pool_mem_handle);
190 	}
191 
192 	/* Free the ITD pool */
193 	if (ehcip->ehci_itd_pool_dma_handle) {
194 		ddi_dma_free_handle(&ehcip->ehci_itd_pool_dma_handle);
195 	}
196 }
197 
198 
199 /*
200  * ehci_isoc_pipe_cleanup
201  *
202  * Cleanup ehci isoc pipes.
203  */
204 void ehci_isoc_pipe_cleanup(
205 	ehci_state_t		*ehcip,
206 	usba_pipe_handle_data_t *ph) {
207 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
208 	uint_t			pipe_state = pp->pp_state;
209 	usb_cr_t		completion_reason;
210 
211 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
212 	    "ehci_isoc_pipe_cleanup: ph = 0x%p", (void *)ph);
213 
214 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
215 
216 	/* Stop all further processing */
217 	ehci_mark_reclaim_isoc(ehcip, pp);
218 
219 	/*
220 	 * Wait for processing all completed transfers
221 	 * and send result upstream/
222 	 */
223 	ehci_wait_for_isoc_completion(ehcip, pp);
224 
225 	/* Go ahead and remove all remaining itds if there are any */
226 	ehci_remove_isoc_itds(ehcip, pp);
227 
228 	switch (pipe_state) {
229 	case EHCI_PIPE_STATE_CLOSE:
230 		completion_reason = USB_CR_PIPE_CLOSING;
231 		break;
232 	case EHCI_PIPE_STATE_RESET:
233 	case EHCI_PIPE_STATE_STOP_POLLING:
234 		/* Set completion reason */
235 		completion_reason = (pipe_state ==
236 		    EHCI_PIPE_STATE_RESET) ?
237 		    USB_CR_PIPE_RESET: USB_CR_STOPPED_POLLING;
238 
239 		/* Set pipe state to idle */
240 		pp->pp_state = EHCI_PIPE_STATE_IDLE;
241 
242 		break;
243 	}
244 
245 	/*
246 	 * Do the callback for the original client
247 	 * periodic IN request.
248 	 */
249 	if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) ==
250 	    USB_EP_DIR_IN) {
251 
252 		ehci_do_client_periodic_in_req_callback(
253 		    ehcip, pp, completion_reason);
254 	}
255 }
256 
257 
258 /*
259  * ehci_wait_for_transfers_completion:
260  *
261  * Wait for processing all completed transfers and to send results
262  * to upstream.
263  */
264 static void
265 ehci_wait_for_isoc_completion(
266 	ehci_state_t		*ehcip,
267 	ehci_pipe_private_t	*pp)
268 {
269 	clock_t			xfer_cmpl_time_wait;
270 
271 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
272 
273 	if (pp->pp_itw_head == NULL) {
274 
275 		return;
276 	}
277 
278 	/* Get the number of clock ticks to wait */
279 	xfer_cmpl_time_wait = drv_usectohz(EHCI_XFER_CMPL_TIMEWAIT * 1000000);
280 
281 	(void) cv_timedwait(&pp->pp_xfer_cmpl_cv,
282 	    &ehcip->ehci_int_mutex,
283 	    ddi_get_lbolt() + xfer_cmpl_time_wait);
284 
285 	if (pp->pp_itw_head) {
286 		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
287 		    "ehci_wait_for_isoc_completion: "
288 		    "No transfers completion confirmation received");
289 	}
290 }
291 
292 
293 /*
294  *  Isochronous request functions
295  */
296 /*
297  * ehci_allocate_isoc_resources:
298  *
299  * Calculates the number of tds necessary for a isoch transfer, and
300  * allocates all the necessary resources.
301  *
302  * Returns NULL if there is insufficient resources otherwise ITW.
303  */
304 ehci_isoc_xwrapper_t *
305 ehci_allocate_isoc_resources(
306 	ehci_state_t		*ehcip,
307 	usba_pipe_handle_data_t *ph,
308 	usb_isoc_req_t		*isoc_reqp,
309 	usb_flags_t		usb_flags)
310 {
311 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
312 	int			pipe_dir, i;
313 	uint_t			max_ep_pkt_size, max_isoc_xfer_size;
314 	usb_isoc_pkt_descr_t	*isoc_pkt_descr;
315 	size_t			isoc_pkt_count, isoc_pkts_length;
316 	size_t			itw_xfer_size = 0;
317 	ehci_isoc_xwrapper_t	*itw;
318 
319 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
320 	    "ehci_allocate_isoc_resources: flags = 0x%x", usb_flags);
321 
322 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
323 
324 	/*
325 	 * Check whether pipe is in halted state.
326 	 */
327 	if (pp->pp_state == EHCI_PIPE_STATE_ERROR) {
328 		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
329 		    "ehci_allocate_isoc_resources:"
330 		    "Pipe is in error state, need pipe reset to continue");
331 
332 		return (NULL);
333 	}
334 
335 	/* Calculate the maximum isochronous transfer size we allow */
336 	max_ep_pkt_size = (ph->p_ep.wMaxPacketSize &
337 	    EHCI_ITD_CTRL_MAX_PACKET_MASK) *
338 	    CalculateITDMultiField(ph->p_ep.wMaxPacketSize);
339 
340 	max_isoc_xfer_size = EHCI_MAX_ISOC_PKTS_PER_XFER * max_ep_pkt_size;
341 
342 	/* Get the packet descriptor and number of packets to send */
343 	if (isoc_reqp) {
344 		isoc_pkt_descr = isoc_reqp->isoc_pkt_descr;
345 		isoc_pkt_count = isoc_reqp->isoc_pkts_count;
346 		isoc_pkts_length = isoc_reqp->isoc_pkts_length;
347 	} else {
348 		isoc_pkt_descr = ((usb_isoc_req_t *)
349 		    pp->pp_client_periodic_in_reqp)->isoc_pkt_descr;
350 
351 		isoc_pkt_count = ((usb_isoc_req_t *)
352 		    pp->pp_client_periodic_in_reqp)->isoc_pkts_count;
353 
354 		isoc_pkts_length = ((usb_isoc_req_t *)
355 		    pp->pp_client_periodic_in_reqp)->isoc_pkts_length;
356 	}
357 
358 	/* Calculate the size of the transfer. */
359 	pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
360 	if (pipe_dir == USB_EP_DIR_IN) {
361 		for (i = 0; i < isoc_pkt_count; i++) {
362 			/*
363 			 * isoc_pkt_length is used as Transaction Length and
364 			 * according to EHCI spec Table 3-3, the maximum value
365 			 * allowed is 3072
366 			 */
367 			if (isoc_pkt_descr->isoc_pkt_length > 3072) {
368 
369 				return (NULL);
370 			}
371 
372 			itw_xfer_size += isoc_pkt_descr->isoc_pkt_length;
373 
374 			isoc_pkt_descr++;
375 		}
376 
377 		if ((isoc_pkts_length) &&
378 		    (isoc_pkts_length != itw_xfer_size)) {
379 
380 			USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
381 			    "ehci_allocate_isoc_resources: "
382 			    "isoc_pkts_length 0x%lx is not equal to the sum of "
383 			    "all pkt lengths 0x%lx in an isoc request",
384 			    isoc_pkts_length, itw_xfer_size);
385 
386 			return (NULL);
387 		}
388 
389 	} else {
390 		ASSERT(isoc_reqp != NULL);
391 		itw_xfer_size = MBLKL(isoc_reqp->isoc_data);
392 	}
393 
394 	/* Check the size of isochronous request */
395 	if (itw_xfer_size > max_isoc_xfer_size) {
396 
397 		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
398 		    "ehci_allocate_isoc_resources: Maximum isoc request "
399 		    "size 0x%x Given isoc request size 0x%lx",
400 		    max_isoc_xfer_size, itw_xfer_size);
401 
402 		return (NULL);
403 	}
404 
405 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
406 	    "ehci_allocate_isoc_resources: length = 0x%lx", itw_xfer_size);
407 
408 	/* Allocate the itw for this request */
409 	if ((itw = ehci_allocate_itw_resources(ehcip, pp, itw_xfer_size,
410 	    usb_flags, isoc_pkt_count)) == NULL) {
411 
412 		return (NULL);
413 	}
414 
415 	itw->itw_handle_callback_value = NULL;
416 
417 	if (pipe_dir == USB_EP_DIR_IN) {
418 		if (ehci_allocate_isoc_in_resource(ehcip, pp, itw, usb_flags) !=
419 		    USB_SUCCESS) {
420 
421 			ehci_deallocate_itw(ehcip, pp, itw);
422 
423 			return (NULL);
424 		}
425 	} else {
426 		if (itw->itw_length) {
427 			ASSERT(isoc_reqp->isoc_data != NULL);
428 
429 			/* Copy the data into the buffer */
430 			bcopy(isoc_reqp->isoc_data->b_rptr,
431 			    itw->itw_buf, itw->itw_length);
432 
433 			Sync_IO_Buffer_for_device(itw->itw_dmahandle,
434 			    itw->itw_length);
435 		}
436 		itw->itw_curr_xfer_reqp = isoc_reqp;
437 	}
438 
439 	return (itw);
440 }
441 
442 
443 /*
444  * ehci_insert_isoc_req:
445  *
446  * Insert an isochronous request into the Host Controller's
447  * isochronous list.
448  */
449 int
450 ehci_insert_isoc_req(
451 	ehci_state_t			*ehcip,
452 	ehci_pipe_private_t		*pp,
453 	ehci_isoc_xwrapper_t		*itw,
454 	usb_flags_t			usb_flags)
455 {
456 	int			error;
457 	ehci_itd_t		*new_itd, *temp_itd;
458 
459 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
460 	    "ehci_insert_isoc_req: flags = 0x%x port status = 0x%x",
461 	    usb_flags, itw->itw_port_status);
462 
463 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
464 
465 	ASSERT(itw->itw_curr_xfer_reqp != NULL);
466 	ASSERT(itw->itw_curr_xfer_reqp->isoc_pkt_descr != NULL);
467 
468 	/*
469 	 * Save address of first usb isochronous packet descriptor.
470 	 */
471 	itw->itw_curr_isoc_pktp = itw->itw_curr_xfer_reqp->isoc_pkt_descr;
472 
473 	if (itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
474 		error = ehci_insert_itd_req(ehcip, pp, itw, usb_flags);
475 	} else {
476 		error = ehci_insert_sitd_req(ehcip, pp, itw, usb_flags);
477 	}
478 
479 	/* Either all the isocs will be added or none of them will */
480 	error = ehci_insert_isoc_to_pfl(ehcip, pp, itw);
481 
482 	if (error != USB_SUCCESS) {
483 		/*
484 		 * Deallocate all the ITDs, otherwise they will be
485 		 * lost forever.
486 		 */
487 		new_itd = itw->itw_itd_head;
488 		while (new_itd) {
489 			temp_itd = ehci_itd_iommu_to_cpu(ehcip,
490 			    Get_ITD(new_itd->itd_itw_next_itd));
491 			ehci_deallocate_itd(ehcip, itw, new_itd);
492 			new_itd = temp_itd;
493 		}
494 		if ((itw->itw_direction == USB_EP_DIR_IN)) {
495 			ehci_deallocate_isoc_in_resource(ehcip, pp, itw);
496 
497 			if (pp->pp_cur_periodic_req_cnt) {
498 				/*
499 				 * Set pipe state to stop polling and
500 				 * error to no resource. Don't insert
501 				 * any more isoch polling requests.
502 				 */
503 				pp->pp_state =
504 				    EHCI_PIPE_STATE_STOP_POLLING;
505 				pp->pp_error = error;
506 			} else {
507 				/* Set periodic in pipe state to idle */
508 				pp->pp_state = EHCI_PIPE_STATE_IDLE;
509 			}
510 
511 			return (error);
512 		}
513 
514 		/* Save how many packets and data actually went */
515 		itw->itw_num_itds = 0;
516 		itw->itw_length  = 0;
517 	}
518 
519 	/*
520 	 * Reset back to the address of first usb isochronous
521 	 * packet descriptor.
522 	 */
523 	itw->itw_curr_isoc_pktp = itw->itw_curr_xfer_reqp->isoc_pkt_descr;
524 
525 	/* Reset the CONTINUE flag */
526 	pp->pp_flag &= ~EHCI_ISOC_XFER_CONTINUE;
527 
528 	return (error);
529 }
530 
531 
532 /*
533  * ehci_insert_itd_req:
534  *
535  * Insert an ITD request into the Host Controller's isochronous list.
536  */
537 /* ARGSUSED */
538 static int
539 ehci_insert_itd_req(
540 	ehci_state_t		*ehcip,
541 	ehci_pipe_private_t	*pp,
542 	ehci_isoc_xwrapper_t	*itw,
543 	usb_flags_t		usb_flags)
544 {
545 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
546 	usb_isoc_req_t		*curr_isoc_reqp;
547 	usb_isoc_pkt_descr_t	*curr_isoc_pkt_descr;
548 	size_t			curr_isoc_xfer_offset;
549 	size_t			isoc_pkt_length;
550 	uint_t			count, xactcount;
551 	uint32_t		xact_status;
552 	uint32_t		page, pageselected;
553 	uint32_t		buf[EHCI_ITD_BUFFER_LIST_SIZE];
554 	uint16_t		index = 0;
555 	uint16_t		multi = 0;
556 	ehci_itd_t		*new_itd;
557 
558 	/*
559 	 * Get the current isochronous request and packet
560 	 * descriptor pointers.
561 	 */
562 	curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
563 
564 	page = itw->itw_cookie.dmac_address;
565 	ASSERT((page % EHCI_4K_ALIGN) == 0);
566 
567 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
568 	    "ehci_insert_itd_req: itw_curr_xfer_reqp = 0x%p page = 0x%x,"
569 	    " pagesize = 0x%lx", (void *)itw->itw_curr_xfer_reqp, page,
570 	    itw->itw_cookie.dmac_size);
571 
572 	/* Insert all the isochronous TDs */
573 	count = 0;
574 	curr_isoc_xfer_offset = 0;
575 
576 	while (count < curr_isoc_reqp->isoc_pkts_count) {
577 
578 		/* Grab a new itd */
579 		new_itd = itw->itw_itd_free_list;
580 
581 		ASSERT(new_itd != NULL);
582 
583 		itw->itw_itd_free_list = ehci_itd_iommu_to_cpu(ehcip,
584 		    Get_ITD(new_itd->itd_link_ptr));
585 		Set_ITD(new_itd->itd_link_ptr, NULL);
586 
587 		bzero(buf, EHCI_ITD_BUFFER_LIST_SIZE * sizeof (uint32_t));
588 
589 		multi = CalculateITDMultiField(ph->p_ep.wMaxPacketSize);
590 
591 		if (multi > EHCI_ITD_CTRL_MULTI_MASK) {
592 			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
593 			    "ehci_insert_itd_req: Wrong multi value.");
594 
595 			return (USB_FAILURE);
596 		}
597 
598 		/* Fill 8 transaction for every iTD */
599 		for (xactcount = 0, pageselected = 0;
600 		    xactcount < EHCI_ITD_CTRL_LIST_SIZE; xactcount++) {
601 
602 			curr_isoc_pkt_descr = itw->itw_curr_isoc_pktp;
603 
604 			isoc_pkt_length =
605 			    curr_isoc_pkt_descr->isoc_pkt_length;
606 
607 			curr_isoc_pkt_descr->isoc_pkt_actual_length
608 			    = (ushort_t)isoc_pkt_length;
609 
610 			xact_status = 0;
611 
612 			if (pageselected < EHCI_ITD_BUFFER_LIST_SIZE) {
613 
614 				buf[pageselected] |= page;
615 			} else {
616 				USB_DPRINTF_L2(PRINT_MASK_INTR,
617 				    ehcip->ehci_log_hdl,
618 				    "ehci_insert_itd_req: "
619 				    "Error in buffer pointer.");
620 
621 				return (USB_FAILURE);
622 			}
623 
624 			xact_status = (uint32_t)curr_isoc_xfer_offset;
625 			xact_status |= (pageselected << 12);
626 			xact_status |= isoc_pkt_length << 16;
627 			xact_status |= EHCI_ITD_XFER_ACTIVE;
628 
629 			/* Set IOC on the last TD. */
630 			if (count == (curr_isoc_reqp->isoc_pkts_count - 1)) {
631 				xact_status |= EHCI_ITD_XFER_IOC_ON;
632 			}
633 
634 			USB_DPRINTF_L3(PRINT_MASK_INTR,
635 			    ehcip->ehci_log_hdl,
636 			    "ehci_insert_itd_req: count = 0x%x multi = %d"
637 			    "status = 0x%x page = 0x%x index = %d "
638 			    "pageselected = %d isoc_pkt_length = 0x%lx",
639 			    xactcount, multi, xact_status, page,
640 			    index, pageselected, isoc_pkt_length);
641 
642 			/* Fill in the new itd */
643 			Set_ITD_BODY(new_itd, xactcount, xact_status);
644 
645 			itw->itw_curr_isoc_pktp++;
646 			Set_ITD_INDEX(new_itd, xactcount, index++);
647 
648 			curr_isoc_xfer_offset += isoc_pkt_length;
649 
650 			if (curr_isoc_xfer_offset >= EHCI_4K_ALIGN) {
651 				pageselected ++;
652 				page += EHCI_4K_ALIGN;
653 				curr_isoc_xfer_offset -= EHCI_4K_ALIGN;
654 			}
655 
656 			count ++;
657 			if (count >= curr_isoc_reqp->isoc_pkts_count) {
658 
659 				break;
660 			}
661 		}
662 
663 		buf[0] |= (itw->itw_endpoint_num << 8);
664 		buf[0] |= itw->itw_device_addr;
665 		buf[1] |= ph->p_ep.wMaxPacketSize &
666 		    EHCI_ITD_CTRL_MAX_PACKET_MASK;
667 
668 		if (itw->itw_direction == USB_EP_DIR_IN) {
669 			buf[1] |= EHCI_ITD_CTRL_DIR_IN;
670 		}
671 		buf[2] |= multi;
672 
673 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER0, buf[0]);
674 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER1, buf[1]);
675 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER2, buf[2]);
676 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER3, buf[3]);
677 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER4, buf[4]);
678 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER5, buf[5]);
679 		Set_ITD_BODY(new_itd, EHCI_ITD_BUFFER6, buf[6]);
680 
681 		Set_ITD(new_itd->itd_state, EHCI_ITD_ACTIVE);
682 		ehci_print_itd(ehcip, new_itd);
683 
684 		/*
685 		 * Add this itd to the itw before we add it in the PFL
686 		 * If adding it to the PFL fails, we will have to cleanup.
687 		 */
688 		ehci_insert_itd_on_itw(ehcip, itw, new_itd);
689 
690 	}
691 
692 	return (USB_SUCCESS);
693 }
694 
695 
696 /*
697  * ehci_insert_sitd_req:
698  *
699  * Insert an SITD request into the Host Controller's isochronous list.
700  */
701 /* ARGSUSED */
702 static int
703 ehci_insert_sitd_req(
704 	ehci_state_t		*ehcip,
705 	ehci_pipe_private_t	*pp,
706 	ehci_isoc_xwrapper_t	*itw,
707 	usb_flags_t		usb_flags)
708 {
709 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
710 	usb_isoc_req_t		*curr_isoc_reqp;
711 	usb_isoc_pkt_descr_t	*curr_isoc_pkt_descr;
712 	size_t			curr_isoc_xfer_offset;
713 	size_t			isoc_pkt_length;
714 	uint_t			count;
715 	uint32_t		ctrl, uframe_sched, xfer_state;
716 	uint32_t		page0, page1, prev_sitd;
717 	uint32_t		ssplit_count;
718 	ehci_itd_t		*new_sitd;
719 
720 	/*
721 	 * Get the current isochronous request and packet
722 	 * descriptor pointers.
723 	 */
724 	curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
725 
726 	/* Set the ctrl field */
727 	ctrl = 0;
728 	if (itw->itw_direction == USB_EP_DIR_IN) {
729 		ctrl |= EHCI_SITD_CTRL_DIR_IN;
730 	} else {
731 		ctrl |= EHCI_SITD_CTRL_DIR_OUT;
732 	}
733 
734 	ctrl |= (itw->itw_hub_port << EHCI_SITD_CTRL_PORT_SHIFT) &
735 	    EHCI_SITD_CTRL_PORT_MASK;
736 	ctrl |= (itw->itw_hub_addr << EHCI_SITD_CTRL_HUB_SHIFT) &
737 	    EHCI_SITD_CTRL_HUB_MASK;
738 	ctrl |= (itw->itw_endpoint_num << EHCI_SITD_CTRL_END_PT_SHIFT) &
739 	    EHCI_SITD_CTRL_END_PT_MASK;
740 	ctrl |= (itw->itw_device_addr << EHCI_SITD_CTRL_DEVICE_SHIFT) &
741 	    EHCI_SITD_CTRL_DEVICE_MASK;
742 
743 	/* Set the micro frame schedule */
744 	uframe_sched = 0;
745 	uframe_sched |= (pp->pp_smask << EHCI_SITD_UFRAME_SMASK_SHIFT) &
746 	    EHCI_SITD_UFRAME_SMASK_MASK;
747 	uframe_sched |= (pp->pp_cmask << EHCI_SITD_UFRAME_CMASK_SHIFT) &
748 	    EHCI_SITD_UFRAME_CMASK_MASK;
749 
750 	/* Set the default page information */
751 	page0 = itw->itw_cookie.dmac_address;
752 	page1 = 0;
753 
754 	prev_sitd = EHCI_ITD_LINK_PTR_INVALID;
755 
756 	/*
757 	 * Save the number of isochronous TDs needs
758 	 * to be insert to complete current isochronous request.
759 	 */
760 	itw->itw_num_itds = curr_isoc_reqp->isoc_pkts_count;
761 
762 	/* Insert all the isochronous TDs */
763 	for (count = 0, curr_isoc_xfer_offset = 0;
764 	    count < itw->itw_num_itds; count++) {
765 
766 		curr_isoc_pkt_descr = itw->itw_curr_isoc_pktp;
767 
768 		isoc_pkt_length = curr_isoc_pkt_descr->isoc_pkt_length;
769 		curr_isoc_pkt_descr->isoc_pkt_actual_length =
770 		    (ushort_t)isoc_pkt_length;
771 
772 		/* Set the transfer state information */
773 		xfer_state = 0;
774 
775 		if (itw->itw_direction == USB_EP_DIR_IN) {
776 			/* Set the size to the max packet size */
777 			xfer_state |= (ph->p_ep.wMaxPacketSize <<
778 			    EHCI_SITD_XFER_TOTAL_SHIFT) &
779 			    EHCI_SITD_XFER_TOTAL_MASK;
780 		} else {
781 			/* Set the size to the packet length */
782 			xfer_state |= (isoc_pkt_length <<
783 			    EHCI_SITD_XFER_TOTAL_SHIFT) &
784 			    EHCI_SITD_XFER_TOTAL_MASK;
785 		}
786 		xfer_state |=  EHCI_SITD_XFER_ACTIVE;
787 
788 		/* Set IOC on the last TD. */
789 		if (count == (itw->itw_num_itds - 1)) {
790 			xfer_state |= EHCI_SITD_XFER_IOC_ON;
791 		}
792 
793 		ssplit_count = isoc_pkt_length / MAX_UFRAME_SITD_XFER;
794 		if (isoc_pkt_length % MAX_UFRAME_SITD_XFER) {
795 			ssplit_count++;
796 		}
797 
798 		page1 = (ssplit_count & EHCI_SITD_XFER_TCOUNT_MASK) <<
799 		    EHCI_SITD_XFER_TCOUNT_SHIFT;
800 		if (ssplit_count > 1) {
801 			page1 |= EHCI_SITD_XFER_TP_BEGIN;
802 		} else {
803 			page1 |= EHCI_SITD_XFER_TP_ALL;
804 		}
805 
806 		/* Grab a new sitd */
807 		new_sitd = itw->itw_itd_free_list;
808 
809 		ASSERT(new_sitd != NULL);
810 
811 		itw->itw_itd_free_list = ehci_itd_iommu_to_cpu(ehcip,
812 		    Get_ITD(new_sitd->itd_link_ptr));
813 		Set_ITD(new_sitd->itd_link_ptr, NULL);
814 
815 		/* Fill in the new sitd */
816 		Set_ITD_BODY(new_sitd, EHCI_SITD_CTRL, ctrl);
817 		Set_ITD_BODY(new_sitd, EHCI_SITD_UFRAME_SCHED, uframe_sched);
818 		Set_ITD_BODY(new_sitd, EHCI_SITD_XFER_STATE, xfer_state);
819 		Set_ITD_BODY(new_sitd, EHCI_SITD_BUFFER0,
820 		    page0 + curr_isoc_xfer_offset);
821 		Set_ITD_BODY(new_sitd, EHCI_SITD_BUFFER1, page1);
822 		Set_ITD_BODY(new_sitd, EHCI_SITD_PREV_SITD, prev_sitd);
823 
824 		Set_ITD(new_sitd->itd_state, EHCI_ITD_ACTIVE);
825 
826 		/*
827 		 * Add this itd to the itw before we add it in the PFL
828 		 * If adding it to the PFL fails, we will have to cleanup.
829 		 */
830 		ehci_insert_itd_on_itw(ehcip, itw, new_sitd);
831 
832 		itw->itw_curr_isoc_pktp++;
833 		curr_isoc_xfer_offset += isoc_pkt_length;
834 	}
835 
836 	return (USB_SUCCESS);
837 }
838 
839 
840 /*
841  * ehci_remove_isoc_itds:
842  *
843  * Remove all itds from the PFL.
844  */
845 static void
846 ehci_remove_isoc_itds(
847 	ehci_state_t		*ehcip,
848 	ehci_pipe_private_t	*pp)
849 {
850 	ehci_isoc_xwrapper_t	*curr_itw, *next_itw;
851 	ehci_itd_t		*curr_itd, *next_itd;
852 
853 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
854 	    "ehci_remove_isoc_itds: pp = 0x%p", (void *)pp);
855 
856 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
857 
858 	curr_itw = pp->pp_itw_head;
859 	while (curr_itw) {
860 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
861 		    "ehci_remove_isoc_itds: itw = 0x%p num itds = %d",
862 		    (void *)curr_itw, curr_itw->itw_num_itds);
863 
864 		next_itw = curr_itw->itw_next;
865 
866 		curr_itd = curr_itw->itw_itd_head;
867 		while (curr_itd) {
868 			next_itd = ehci_itd_iommu_to_cpu(ehcip,
869 			    Get_ITD(curr_itd->itd_itw_next_itd));
870 
871 			ehci_reclaim_isoc(ehcip, curr_itw, curr_itd, pp);
872 
873 			curr_itd = next_itd;
874 		}
875 
876 		ehci_deallocate_itw(ehcip, pp, curr_itw);
877 
878 		curr_itw = next_itw;
879 	}
880 }
881 
882 
883 /*
884  * ehci_mark_reclaim_isoc:
885  *
886  * Set active ITDs to RECLAIM.
887  * Return number of ITD that need to be processed.
888  */
889 static void
890 ehci_mark_reclaim_isoc(
891 	ehci_state_t		*ehcip,
892 	ehci_pipe_private_t	*pp)
893 {
894 	usb_frame_number_t	current_frame_number;
895 	ehci_isoc_xwrapper_t	*curr_itw, *next_itw;
896 	ehci_itd_t		*curr_itd, *next_itd;
897 	uint_t			ctrl;
898 	uint_t			isActive;
899 	int			i;
900 
901 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
902 	    "ehci_mark_reclaim_isoc: pp = 0x%p", (void *)pp);
903 
904 	if (pp->pp_itw_head == NULL) {
905 
906 		return;
907 	}
908 
909 	/* Get the current frame number. */
910 	current_frame_number = ehci_get_current_frame_number(ehcip);
911 
912 	/* Traverse the list of transfer descriptors */
913 	curr_itw = pp->pp_itw_head;
914 	while (curr_itw) {
915 		next_itw = curr_itw->itw_next;
916 
917 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
918 		    "ehci_mark_reclaim_isoc: itw = 0x%p num itds = %d",
919 		    (void *)curr_itw, curr_itw->itw_num_itds);
920 
921 		curr_itd = curr_itw->itw_itd_head;
922 		while (curr_itd) {
923 			next_itd = ehci_itd_iommu_to_cpu(ehcip,
924 			    Get_ITD(curr_itd->itd_itw_next_itd));
925 
926 			if (curr_itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
927 
928 				for (i = 0; i < EHCI_ITD_CTRL_LIST_SIZE; i++) {
929 					ctrl = Get_ITD_BODY(curr_itd,
930 					    EHCI_ITD_CTRL0 + i);
931 					isActive = ctrl & EHCI_ITD_XFER_ACTIVE;
932 					/* If still active, deactivate it */
933 					if (isActive) {
934 						ctrl &= ~EHCI_ITD_XFER_ACTIVE;
935 						Set_ITD_BODY(curr_itd,
936 						    EHCI_ITD_CTRL0 + i,
937 						    ctrl);
938 						break;
939 					}
940 				}
941 			} else {
942 				ctrl = Get_ITD_BODY(curr_itd,
943 				    EHCI_SITD_XFER_STATE);
944 				isActive = ctrl & EHCI_SITD_XFER_ACTIVE;
945 				/* If it is still active deactivate it */
946 				if (isActive) {
947 					ctrl &= ~EHCI_SITD_XFER_ACTIVE;
948 					Set_ITD_BODY(curr_itd,
949 					    EHCI_SITD_XFER_STATE,
950 					    ctrl);
951 				}
952 			}
953 
954 			/*
955 			 * If the itd was active put it on the reclaim status,
956 			 * so the interrupt handler will know not to process it.
957 			 * Otherwise leave it alone and let the interrupt
958 			 * handler process it normally.
959 			 */
960 			if (isActive) {
961 				Set_ITD(curr_itd->itd_state, EHCI_ITD_RECLAIM);
962 				Set_ITD_FRAME(curr_itd->itd_reclaim_number,
963 				    current_frame_number);
964 				ehci_remove_isoc_from_pfl(ehcip, curr_itd);
965 			}
966 			curr_itd = next_itd;
967 		}
968 		curr_itw = next_itw;
969 	}
970 }
971 
972 
973 /*
974  * ehci_reclaim_isoc:
975  *
976  * "Reclaim" itds that were marked as RECLAIM.
977  */
978 static void
979 ehci_reclaim_isoc(
980 	ehci_state_t		*ehcip,
981 	ehci_isoc_xwrapper_t	*itw,
982 	ehci_itd_t		*itd,
983 	ehci_pipe_private_t	*pp)
984 {
985 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
986 	    "ehci_reclaim_isoc: itd = 0x%p", (void *)itd);
987 
988 	/*
989 	 * These are itds that were marked "RECLAIM"
990 	 * by the pipe cleanup.
991 	 *
992 	 * Decrement the num_itds and the periodic in
993 	 * request count if necessary.
994 	 */
995 	if ((--itw->itw_num_itds == 0) && (itw->itw_curr_xfer_reqp)) {
996 		if (itw->itw_direction == USB_EP_DIR_IN) {
997 
998 			pp->pp_cur_periodic_req_cnt--;
999 
1000 			ehci_deallocate_isoc_in_resource(ehcip, pp, itw);
1001 		} else {
1002 			ehci_hcdi_isoc_callback(pp->pp_pipe_handle, itw,
1003 			    USB_CR_FLUSHED);
1004 		}
1005 	}
1006 
1007 	/* Deallocate this transfer descriptor */
1008 	ehci_deallocate_itd(ehcip, itw, itd);
1009 }
1010 
1011 
1012 /*
1013  * ehci_start_isoc_polling:
1014  *
1015  * Insert the number of periodic requests corresponding to polling
1016  * interval as calculated during pipe open.
1017  */
1018 int
1019 ehci_start_isoc_polling(
1020 	ehci_state_t		*ehcip,
1021 	usba_pipe_handle_data_t	*ph,
1022 	usb_flags_t		flags)
1023 {
1024 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
1025 	ehci_isoc_xwrapper_t	*itw_list, *itw;
1026 	int			i, total_itws;
1027 	int			error = USB_SUCCESS;
1028 
1029 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1030 	    "ehci_start_isoc_polling:");
1031 
1032 	/* Allocate all the necessary resources for the IN transfer */
1033 	itw_list = NULL;
1034 	total_itws = pp->pp_max_periodic_req_cnt - pp->pp_cur_periodic_req_cnt;
1035 	for (i = 0; i < total_itws; i += 1) {
1036 		itw = ehci_allocate_isoc_resources(ehcip, ph, NULL, flags);
1037 		if (itw == NULL) {
1038 			error = USB_NO_RESOURCES;
1039 			/* There are not enough resources deallocate the ITWs */
1040 			itw = itw_list;
1041 			while (itw != NULL) {
1042 				itw_list = itw->itw_next;
1043 				ehci_deallocate_isoc_in_resource(
1044 				    ehcip, pp, itw);
1045 				ehci_deallocate_itw(ehcip, pp, itw);
1046 				itw = itw_list;
1047 			}
1048 
1049 			return (error);
1050 		} else {
1051 			if (itw_list == NULL) {
1052 				itw_list = itw;
1053 			}
1054 		}
1055 	}
1056 
1057 	i = 0;
1058 	while (pp->pp_cur_periodic_req_cnt < pp->pp_max_periodic_req_cnt) {
1059 
1060 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1061 		    "ehci_start_isoc_polling: max = %d curr = %d itw = %p:",
1062 		    pp->pp_max_periodic_req_cnt, pp->pp_cur_periodic_req_cnt,
1063 		    (void *)itw_list);
1064 
1065 		itw = itw_list;
1066 		itw_list = itw->itw_next;
1067 
1068 		error = ehci_insert_isoc_req(ehcip, pp, itw, flags);
1069 
1070 		if (error == USB_SUCCESS) {
1071 			pp->pp_cur_periodic_req_cnt++;
1072 		} else {
1073 			/*
1074 			 * Deallocate the remaining tw
1075 			 * The current tw should have already been deallocated
1076 			 */
1077 			itw = itw_list;
1078 			while (itw != NULL) {
1079 				itw_list = itw->itw_next;
1080 				ehci_deallocate_isoc_in_resource(
1081 				    ehcip, pp, itw);
1082 				ehci_deallocate_itw(ehcip, pp, itw);
1083 				itw = itw_list;
1084 			}
1085 			/*
1086 			 * If this is the first req return an error.
1087 			 * Otherwise return success.
1088 			 */
1089 			if (i != 0) {
1090 				error = USB_SUCCESS;
1091 			}
1092 
1093 			break;
1094 		}
1095 		i++;
1096 	}
1097 
1098 	return (error);
1099 }
1100 
1101 
1102 /*
1103  * Isochronronous handling functions.
1104  */
1105 /*
1106  * ehci_traverse_active_isoc_list:
1107  */
1108 void
1109 ehci_traverse_active_isoc_list(
1110 	ehci_state_t		*ehcip)
1111 {
1112 	ehci_isoc_xwrapper_t	*curr_itw;
1113 	ehci_itd_t		*curr_itd, *next_itd;
1114 	uint_t			state;
1115 	ehci_pipe_private_t	*pp;
1116 
1117 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1118 	    "ehci_traverse_active_isoc_list:");
1119 
1120 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1121 
1122 	/* Sync ITD pool */
1123 	Sync_ITD_Pool(ehcip);
1124 
1125 	/* Traverse the list of done itds */
1126 	curr_itd = ehci_create_done_itd_list(ehcip);
1127 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1128 	    "ehci_traverse_active_isoc_list: current itd = 0x%p",
1129 	    (void *)curr_itd);
1130 
1131 	while (curr_itd) {
1132 		/* Save the next_itd */
1133 		next_itd = ehci_itd_iommu_to_cpu(ehcip,
1134 		    Get_ITD(curr_itd->itd_next_active_itd));
1135 
1136 		/* Get the transfer wrapper and the pp */
1137 		curr_itw = (ehci_isoc_xwrapper_t *)EHCI_LOOKUP_ID(
1138 		    (uint32_t)Get_ITD(curr_itd->itd_trans_wrapper));
1139 		pp = curr_itw->itw_pipe_private;
1140 
1141 		if (curr_itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
1142 			ehci_print_itd(ehcip, curr_itd);
1143 		} else {
1144 			ehci_print_sitd(ehcip, curr_itd);
1145 		}
1146 
1147 		/* Get the ITD state */
1148 		state = Get_ITD(curr_itd->itd_state);
1149 
1150 		/* Only process the ITDs marked as active. */
1151 		if (state == EHCI_ITD_ACTIVE) {
1152 			ehci_parse_isoc_error(ehcip, curr_itw, curr_itd);
1153 			ehci_handle_isoc(ehcip, curr_itw, curr_itd);
1154 		} else {
1155 			ASSERT(state == EHCI_ITD_RECLAIM);
1156 			ehci_reclaim_isoc(ehcip, curr_itw, curr_itd, pp);
1157 		}
1158 
1159 		/*
1160 		 * Deallocate the transfer wrapper if there are no more
1161 		 * ITD's for the transfer wrapper.  ehci_deallocate_itw()
1162 		 * will  not deallocate the tw for a periodic in endpoint
1163 		 * since it will always have a ITD attached to it.
1164 		 */
1165 		ehci_deallocate_itw(ehcip, pp, curr_itw);
1166 
1167 		/* Check any ISOC is waiting for transfers completion event */
1168 		if (pp->pp_itw_head == NULL) {
1169 			USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
1170 			    "ehci_traverse_active_isoc_list: "
1171 			    "Sent transfers completion event pp = 0x%p",
1172 			    (void *)pp);
1173 			cv_signal(&pp->pp_xfer_cmpl_cv);
1174 		}
1175 
1176 		curr_itd = next_itd;
1177 
1178 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1179 		    "ehci_traverse_active_isoc_list: state = 0x%x "
1180 		    "pp = 0x%p itw = 0x%p itd = 0x%p next_itd = 0x%p",
1181 		    state, (void *)pp, (void *)curr_itw, (void *)curr_itd,
1182 		    (void *)next_itd);
1183 	}
1184 }
1185 
1186 
1187 static void
1188 ehci_handle_isoc(
1189 	ehci_state_t		*ehcip,
1190 	ehci_isoc_xwrapper_t	*itw,
1191 	ehci_itd_t		*itd)
1192 {
1193 	ehci_pipe_private_t	*pp;	/* Pipe private field */
1194 
1195 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1196 
1197 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1198 	    "ehci_handle_isoc:");
1199 
1200 	/* Obtain the pipe private structure */
1201 	pp = itw->itw_pipe_private;
1202 
1203 	ehci_handle_itd(ehcip, pp, itw, itd, itw->itw_handle_callback_value);
1204 }
1205 
1206 
1207 /*
1208  * ehci_handle_itd:
1209  *
1210  * Handle an (split) isochronous transfer descriptor.
1211  * This function will deallocate the itd from the list as well.
1212  */
1213 /* ARGSUSED */
1214 static void
1215 ehci_handle_itd(
1216 	ehci_state_t		*ehcip,
1217 	ehci_pipe_private_t	*pp,
1218 	ehci_isoc_xwrapper_t	*itw,
1219 	ehci_itd_t		*itd,
1220 	void			*tw_handle_callback_value)
1221 {
1222 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
1223 	usb_isoc_req_t		*curr_isoc_reqp =
1224 	    (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
1225 	int			error = USB_SUCCESS;
1226 	int			i, index;
1227 
1228 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1229 	    "ehci_handle_itd: pp=0x%p itw=0x%p itd=0x%p "
1230 	    "isoc_reqp=0%p data=0x%p", (void *)pp, (void *)itw, (void *)itd,
1231 	    (void *)curr_isoc_reqp, (void *)curr_isoc_reqp->isoc_data);
1232 
1233 	if (itw->itw_port_status == USBA_HIGH_SPEED_DEV &&
1234 	    curr_isoc_reqp != NULL) {
1235 
1236 		for (i = 0; i < EHCI_ITD_CTRL_LIST_SIZE; i++) {
1237 
1238 			index = Get_ITD_INDEX(itd, i);
1239 			if (index == EHCI_ITD_UNUSED_INDEX) {
1240 
1241 				continue;
1242 			}
1243 			curr_isoc_reqp->
1244 			    isoc_pkt_descr[index].isoc_pkt_actual_length =
1245 			    (Get_ITD_BODY(itd, i) & EHCI_ITD_XFER_LENGTH) >> 16;
1246 		}
1247 	}
1248 
1249 	/*
1250 	 * Decrement the ITDs counter and check whether all the isoc
1251 	 * data has been send or received. If ITDs counter reaches
1252 	 * zero then inform client driver about completion current
1253 	 * isoc request. Otherwise wait for completion of other isoc
1254 	 * ITDs or transactions on this pipe.
1255 	 */
1256 	if (--itw->itw_num_itds != 0) {
1257 		/* Deallocate this transfer descriptor */
1258 		ehci_deallocate_itd(ehcip, itw, itd);
1259 
1260 		return;
1261 	}
1262 
1263 	/*
1264 	 * If this is a isoc in pipe, return the data to the client.
1265 	 * For a isoc out pipe, there is no need to do anything.
1266 	 */
1267 	if (itw->itw_direction == USB_EP_DIR_OUT) {
1268 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1269 		    "ehci_handle_itd: Isoc out pipe, isoc_reqp=0x%p, data=0x%p",
1270 		    (void *)curr_isoc_reqp, (void *)curr_isoc_reqp->isoc_data);
1271 
1272 		/* Do the callback */
1273 		ehci_hcdi_isoc_callback(ph, itw, USB_CR_OK);
1274 
1275 		/* Deallocate this transfer descriptor */
1276 		ehci_deallocate_itd(ehcip, itw, itd);
1277 
1278 		return;
1279 	}
1280 
1281 	/* Decrement number of IN isochronous request count */
1282 	pp->pp_cur_periodic_req_cnt--;
1283 
1284 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1285 	    "ehci_handle_itd: pp_cur_periodic_req_cnt = 0x%x ",
1286 	    pp->pp_cur_periodic_req_cnt);
1287 
1288 	/* Call ehci_sendup_itd_message to send message to upstream */
1289 	ehci_sendup_itd_message(ehcip, pp, itw, itd, USB_CR_OK);
1290 
1291 	/* Deallocate this transfer descriptor */
1292 	ehci_deallocate_itd(ehcip, itw, itd);
1293 
1294 	/*
1295 	 * If isochronous pipe state is still active, insert next isochronous
1296 	 * request into the Host Controller's isochronous list.
1297 	 */
1298 	if (pp->pp_state != EHCI_PIPE_STATE_ACTIVE) {
1299 
1300 		return;
1301 	}
1302 
1303 	if ((error = ehci_allocate_isoc_in_resource(ehcip, pp, itw, 0)) ==
1304 	    USB_SUCCESS) {
1305 		curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
1306 
1307 		ASSERT(curr_isoc_reqp != NULL);
1308 
1309 		itw->itw_num_itds = ehci_calc_num_itds(itw,
1310 		    curr_isoc_reqp->isoc_pkts_count);
1311 
1312 		if (ehci_allocate_itds_for_itw(ehcip, itw, itw->itw_num_itds) !=
1313 		    USB_SUCCESS) {
1314 			ehci_deallocate_isoc_in_resource(ehcip, pp, itw);
1315 			itw->itw_num_itds = 0;
1316 			error = USB_FAILURE;
1317 		}
1318 	}
1319 
1320 	if ((error != USB_SUCCESS) ||
1321 	    (ehci_insert_isoc_req(ehcip, pp, itw, 0) != USB_SUCCESS)) {
1322 		/*
1323 		 * Set pipe state to stop polling and error to no
1324 		 * resource. Don't insert any more isoch polling
1325 		 * requests.
1326 		 */
1327 		pp->pp_state = EHCI_PIPE_STATE_STOP_POLLING;
1328 		pp->pp_error = USB_CR_NO_RESOURCES;
1329 
1330 	} else {
1331 		/* Increment number of IN isochronous request count */
1332 		pp->pp_cur_periodic_req_cnt++;
1333 
1334 		ASSERT(pp->pp_cur_periodic_req_cnt ==
1335 		    pp->pp_max_periodic_req_cnt);
1336 	}
1337 }
1338 
1339 
1340 /*
1341  * ehci_sendup_qtd_message:
1342  *	copy data, if necessary and do callback
1343  */
1344 /* ARGSUSED */
1345 static void
1346 ehci_sendup_itd_message(
1347 	ehci_state_t		*ehcip,
1348 	ehci_pipe_private_t	*pp,
1349 	ehci_isoc_xwrapper_t	*itw,
1350 	ehci_itd_t		*td,
1351 	usb_cr_t		error)
1352 {
1353 	usb_isoc_req_t		*isoc_reqp = itw->itw_curr_xfer_reqp;
1354 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
1355 	size_t			length;
1356 	uchar_t			*buf;
1357 	mblk_t			*mp;
1358 
1359 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1360 
1361 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1362 	    "ehci_sendup_itd_message:");
1363 
1364 	ASSERT(itw != NULL);
1365 
1366 	length = itw->itw_length;
1367 
1368 	/* Copy the data into the mblk_t */
1369 	buf = (uchar_t *)itw->itw_buf;
1370 
1371 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1372 	    "ehci_sendup_itd_message: length %ld error %d", length, error);
1373 
1374 	/* Get the message block */
1375 	mp = isoc_reqp->isoc_data;
1376 
1377 	ASSERT(mp != NULL);
1378 
1379 	if (length) {
1380 		/* Sync IO buffer */
1381 		Sync_IO_Buffer(itw->itw_dmahandle, length);
1382 
1383 		/* Copy the data into the message */
1384 		ddi_rep_get8(itw->itw_accesshandle,
1385 		    mp->b_rptr, buf, length, DDI_DEV_AUTOINCR);
1386 
1387 		/* Increment the write pointer */
1388 		mp->b_wptr = mp->b_wptr + length;
1389 	} else {
1390 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1391 		    "ehci_sendup_itd_message: Zero length packet");
1392 	}
1393 
1394 	ehci_hcdi_isoc_callback(ph, itw, error);
1395 }
1396 
1397 
1398 /*
1399  * ehci_hcdi_isoc_callback:
1400  *
1401  * Convenience wrapper around usba_hcdi_cb() other than root hub.
1402  */
1403 void
1404 ehci_hcdi_isoc_callback(
1405 	usba_pipe_handle_data_t	*ph,
1406 	ehci_isoc_xwrapper_t	*itw,
1407 	usb_cr_t		completion_reason)
1408 {
1409 	ehci_state_t		*ehcip = ehci_obtain_state(
1410 	    ph->p_usba_device->usb_root_hub_dip);
1411 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
1412 	usb_opaque_t		curr_xfer_reqp;
1413 	uint_t			pipe_state = 0;
1414 
1415 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
1416 	    "ehci_hcdi_isoc_callback: ph = 0x%p, itw = 0x%p, cr = 0x%x",
1417 	    (void *)ph, (void *)itw, completion_reason);
1418 
1419 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1420 
1421 	/* Set the pipe state as per completion reason */
1422 	switch (completion_reason) {
1423 	case USB_CR_OK:
1424 		pipe_state = pp->pp_state;
1425 		break;
1426 	case USB_CR_NO_RESOURCES:
1427 	case USB_CR_NOT_SUPPORTED:
1428 	case USB_CR_PIPE_RESET:
1429 	case USB_CR_STOPPED_POLLING:
1430 		pipe_state = EHCI_PIPE_STATE_IDLE;
1431 		break;
1432 	case USB_CR_PIPE_CLOSING:
1433 		break;
1434 	}
1435 
1436 	pp->pp_state = pipe_state;
1437 
1438 	if (itw && itw->itw_curr_xfer_reqp) {
1439 		curr_xfer_reqp = (usb_opaque_t)itw->itw_curr_xfer_reqp;
1440 		itw->itw_curr_xfer_reqp = NULL;
1441 	} else {
1442 		ASSERT(pp->pp_client_periodic_in_reqp != NULL);
1443 
1444 		curr_xfer_reqp = pp->pp_client_periodic_in_reqp;
1445 		pp->pp_client_periodic_in_reqp = NULL;
1446 	}
1447 
1448 	ASSERT(curr_xfer_reqp != NULL);
1449 
1450 	mutex_exit(&ehcip->ehci_int_mutex);
1451 
1452 	usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason);
1453 
1454 	mutex_enter(&ehcip->ehci_int_mutex);
1455 }
1456