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