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