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