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
 131 ehci_isoc_init(
 132         ehci_state_t            *ehcip)
 133 {
 134         return (ehci_allocate_isoc_pools(ehcip));
 135 }
 136 
 137 
 138 /*
 139  * Cleanup isochronous resources.
 140  */
 141 void
 142 ehci_isoc_cleanup(
 143         ehci_state_t            *ehcip)
 144 {
 145         ehci_isoc_xwrapper_t    *itw;
 146         ehci_pipe_private_t     *pp;
 147         ehci_itd_t              *itd;
 148         int                     i, ctrl, rval;
 149 
 150         /* Free all the buffers */
 151         if (ehcip->ehci_itd_pool_addr && ehcip->ehci_itd_pool_mem_handle) {
 152                 for (i = 0; i < ehci_get_itd_pool_size(); i ++) {
 153                         itd = &ehcip->ehci_itd_pool_addr[i];
 154                         ctrl = Get_ITD(ehcip->
 155                             ehci_itd_pool_addr[i].itd_state);
 156 
 157                         if ((ctrl != EHCI_ITD_FREE) &&
 158                             (ctrl != EHCI_ITD_DUMMY) &&
 159                             (itd->itd_trans_wrapper)) {
 160 
 161                                 mutex_enter(&ehcip->ehci_int_mutex);
 162 
 163                                 itw = (ehci_isoc_xwrapper_t *)
 164                                     EHCI_LOOKUP_ID((uint32_t)
 165                                     Get_ITD(itd->itd_trans_wrapper));
 166 
 167                                 /* Obtain the pipe private structure */
 168                                 pp = itw->itw_pipe_private;
 169 
 170                                 ehci_deallocate_itd(ehcip, itw, itd);
 171                                 ehci_deallocate_itw(ehcip, pp, itw);
 172 
 173                                 mutex_exit(&ehcip->ehci_int_mutex);
 174                         }
 175                 }
 176 
 177                 /*
 178                  * If EHCI_ITD_POOL_BOUND flag is set, then unbind
 179                  * the handle for ITD pools.
 180                  */
 181                 if ((ehcip->ehci_dma_addr_bind_flag &
 182                     EHCI_ITD_POOL_BOUND) == EHCI_ITD_POOL_BOUND) {
 183 
 184                         rval = ddi_dma_unbind_handle(
 185                             ehcip->ehci_itd_pool_dma_handle);
 186 
 187                         ASSERT(rval == DDI_SUCCESS);
 188                 }
 189                 ddi_dma_mem_free(&ehcip->ehci_itd_pool_mem_handle);
 190         }
 191 
 192         /* Free the ITD pool */
 193         if (ehcip->ehci_itd_pool_dma_handle) {
 194                 ddi_dma_free_handle(&ehcip->ehci_itd_pool_dma_handle);
 195         }
 196 }
 197 
 198 
 199 /*
 200  * ehci_isoc_pipe_cleanup
 201  *
 202  * Cleanup ehci isoc pipes.
 203  */
 204 void ehci_isoc_pipe_cleanup(
 205         ehci_state_t            *ehcip,
 206         usba_pipe_handle_data_t *ph) {
 207         ehci_pipe_private_t     *pp = (ehci_pipe_private_t *)ph->p_hcd_private;
 208         uint_t                  pipe_state = pp->pp_state;
 209         usb_cr_t                completion_reason;
 210 
 211         USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
 212             "ehci_isoc_pipe_cleanup: ph = 0x%p", (void *)ph);
 213 
 214         ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
 215 
 216         /* Stop all further processing */
 217         ehci_mark_reclaim_isoc(ehcip, pp);
 218 
 219         /*
 220          * Wait for processing all completed transfers
 221          * and send result upstream/
 222          */
 223         ehci_wait_for_isoc_completion(ehcip, pp);
 224 
 225         /* Go ahead and remove all remaining itds if there are any */
 226         ehci_remove_isoc_itds(ehcip, pp);
 227 
 228         switch (pipe_state) {
 229         case EHCI_PIPE_STATE_CLOSE:
 230                 completion_reason = USB_CR_PIPE_CLOSING;
 231                 break;
 232         case EHCI_PIPE_STATE_RESET:
 233         case EHCI_PIPE_STATE_STOP_POLLING:
 234                 /* Set completion reason */
 235                 completion_reason = (pipe_state ==
 236                     EHCI_PIPE_STATE_RESET) ?
 237                     USB_CR_PIPE_RESET: USB_CR_STOPPED_POLLING;
 238 
 239                 /* Set pipe state to idle */
 240                 pp->pp_state = EHCI_PIPE_STATE_IDLE;
 241 
 242                 break;
 243         }
 244 
 245         /*
 246          * Do the callback for the original client
 247          * periodic IN request.
 248          */
 249         if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) ==
 250             USB_EP_DIR_IN) {
 251 
 252                 ehci_do_client_periodic_in_req_callback(
 253                     ehcip, pp, completion_reason);
 254         }
 255 }
 256 
 257 
 258 /*
 259  * ehci_wait_for_transfers_completion:
 260  *
 261  * Wait for processing all completed transfers and to send results
 262  * to upstream.
 263  */
 264 static void
 265 ehci_wait_for_isoc_completion(
 266         ehci_state_t            *ehcip,
 267         ehci_pipe_private_t     *pp)
 268 {
 269         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_sectohz(EHCI_XFER_CMPL_TIMEWAIT), 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 *
 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
 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
 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
 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
 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
 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
 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
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
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
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
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
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
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 }