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