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 2001-2002 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * hci1394_isoch.c 29 * HCI HAL isochronous interface routines. Contains routines used 30 * internally within the HAL to manage isochronous contexts, and 31 * also routines called from the Services Layer to manage an isochronous 32 * DMA resource. 33 */ 34 35 #include <sys/types.h> 36 #include <sys/kmem.h> 37 #include <sys/conf.h> 38 #include <sys/ddi.h> 39 #include <sys/sunddi.h> 40 41 #include <sys/1394/h1394.h> 42 #include <sys/1394/adapters/hci1394.h> 43 44 /* 45 * Patchable variable used to indicate the number of microseconds to wait 46 * for an isoch ctxt to stop ("active" goes low) after clearing the "run" 47 * bit 48 */ 49 uint_t hci1394_iso_ctxt_stop_delay_uS = 1000; 50 51 /* 52 * Number of microseconds to wait in hci1394_do_stop() for an isoch ctxt 53 * interrupt handler to complete. Experiments showed that in some cases 54 * the timeout needed was as long as 2 seconds. This is probably due to 55 * significant interrupt processing overhead for certain IXL chains. 56 */ 57 uint_t hci1394_iso_ctxt_stop_intr_timeout_uS = 5 * 1000000; 58 59 /* 60 * hci1394_isoch_init() 61 * Initialize the isochronous dma soft state. 62 */ 63 void 64 hci1394_isoch_init(hci1394_drvinfo_t *drvinfo, hci1394_ohci_handle_t ohci, 65 hci1394_isoch_handle_t *isoch_hdl) 66 { 67 hci1394_isoch_t *isochp; 68 int i; 69 70 ASSERT(drvinfo != NULL); 71 ASSERT(isoch_hdl != NULL); 72 73 isochp = kmem_alloc(sizeof (hci1394_isoch_t), KM_SLEEP); 74 75 /* initialize contexts */ 76 for (i = 0; i < HCI1394_MAX_ISOCH_CONTEXTS; i++) { 77 isochp->ctxt_xmit[i].ctxt_index = i; 78 79 /* init context flags to 0 */ 80 isochp->ctxt_xmit[i].ctxt_flags = 0; 81 82 mutex_init(&isochp->ctxt_xmit[i].intrprocmutex, NULL, 83 MUTEX_DRIVER, drvinfo->di_iblock_cookie); 84 cv_init(&isochp->ctxt_xmit[i].intr_cv, NULL, 85 CV_DRIVER, NULL); 86 87 isochp->ctxt_recv[i].ctxt_index = i; 88 isochp->ctxt_recv[i].ctxt_flags = HCI1394_ISO_CTXT_RECV; 89 mutex_init(&isochp->ctxt_recv[i].intrprocmutex, NULL, 90 MUTEX_DRIVER, drvinfo->di_iblock_cookie); 91 cv_init(&isochp->ctxt_recv[i].intr_cv, NULL, 92 CV_DRIVER, NULL); 93 } 94 95 /* initialize the count for allocated isoch dma */ 96 isochp->isoch_dma_alloc_cnt = 0; 97 98 /* initialize the cycle_lost_thresh struct */ 99 isochp->cycle_lost_thresh.last_intr_time = 0; 100 isochp->cycle_lost_thresh.delta_t_counter = 0; 101 isochp->cycle_lost_thresh.delta_t_thresh = HCI1394_CYC_LOST_DELTA; 102 isochp->cycle_lost_thresh.counter_thresh = HCI1394_CYC_LOST_COUNT; 103 104 /* initialize the cycle_incon_thresh struct */ 105 isochp->cycle_incon_thresh.last_intr_time = 0; 106 isochp->cycle_incon_thresh.delta_t_counter = 0; 107 isochp->cycle_incon_thresh.delta_t_thresh = HCI1394_CYC_INCON_DELTA; 108 isochp->cycle_incon_thresh.counter_thresh = HCI1394_CYC_INCON_COUNT; 109 110 /* determine number of contexts supported */ 111 isochp->ctxt_xmit_count = hci1394_ohci_it_ctxt_count_get(ohci); 112 isochp->ctxt_recv_count = hci1394_ohci_ir_ctxt_count_get(ohci); 113 114 /* the isochronous context mutex is used during some error interrupts */ 115 mutex_init(&isochp->ctxt_list_mutex, NULL, MUTEX_DRIVER, 116 drvinfo->di_iblock_cookie); 117 118 *isoch_hdl = isochp; 119 } 120 121 /* 122 * hci1394_isoch_fini() 123 * Cleanup after hci1394_isoch_init. This should be called during detach. 124 */ 125 void 126 hci1394_isoch_fini(hci1394_isoch_handle_t *isoch_hdl) 127 { 128 hci1394_isoch_t *isochp; 129 int i; 130 131 ASSERT(isoch_hdl != NULL); 132 133 isochp = *isoch_hdl; 134 135 for (i = 0; i < HCI1394_MAX_ISOCH_CONTEXTS; i++) { 136 mutex_destroy(&isochp->ctxt_xmit[i].intrprocmutex); 137 mutex_destroy(&isochp->ctxt_recv[i].intrprocmutex); 138 cv_destroy(&isochp->ctxt_xmit[i].intr_cv); 139 cv_destroy(&isochp->ctxt_recv[i].intr_cv); 140 } 141 142 mutex_destroy(&isochp->ctxt_list_mutex); 143 kmem_free(isochp, sizeof (hci1394_isoch_t)); 144 *isoch_hdl = NULL; 145 } 146 147 148 /* 149 * hci1394_isoch_resume() 150 * There is currently nothing to do for resume. This is a placeholder. 151 */ 152 /* ARGSUSED */ 153 int 154 hci1394_isoch_resume(hci1394_state_t *soft_state) 155 { 156 return (DDI_SUCCESS); 157 } 158 159 /* 160 * hci1394_alloc_isoch_dma () 161 * Called by the Services Layer. Used to allocate a local Isoch DMA context. 162 * Goes through appropriate context list (either transmit or receive) 163 * looking for an unused context. Fails if none found. 164 * Then compiles the provided IXL program. 165 */ 166 int 167 hci1394_alloc_isoch_dma(void *hal_private, id1394_isoch_dmainfo_t *idi, 168 void **hal_idma_handlep, int *resultp) 169 { 170 int i; 171 int err; 172 hci1394_state_t *soft_statep = (hci1394_state_t *)hal_private; 173 hci1394_isoch_t *isochp; 174 hci1394_iso_ctxt_t *ctxtp; 175 176 177 ASSERT(soft_statep != NULL); 178 ASSERT(hal_idma_handlep != NULL); 179 180 isochp = soft_statep->isoch; 181 *hal_idma_handlep = NULL; 182 183 /* 184 * find context to use based on whether talking(send) or listening(recv) 185 */ 186 mutex_enter(&isochp->ctxt_list_mutex); 187 if ((idi->idma_options & ID1394_TALK) != 0) { 188 /* TRANSMIT */ 189 190 /* 191 * search through list of hardware supported contexts for 192 * one that's not inuse 193 */ 194 for (i = 0; i < isochp->ctxt_xmit_count; i++) { 195 if ((isochp->ctxt_xmit[i].ctxt_flags & 196 HCI1394_ISO_CTXT_INUSE) == 0) { 197 break; 198 } 199 } 200 201 /* if there aren't any left, return an error */ 202 if (i >= isochp->ctxt_xmit_count) { 203 mutex_exit(&isochp->ctxt_list_mutex); 204 *resultp = IXL1394_ENO_DMA_RESRCS; 205 return (DDI_FAILURE); 206 } 207 208 /* mark inuse and set up handle to context */ 209 isochp->ctxt_xmit[i].ctxt_flags |= HCI1394_ISO_CTXT_INUSE; 210 ctxtp = &isochp->ctxt_xmit[i]; 211 isochp->ctxt_xmit[i].ctxt_regsp = 212 &soft_statep->ohci->ohci_regs->it[i]; 213 } else { 214 /* RECEIVE */ 215 216 /* search thru implemented contexts for one that's available */ 217 for (i = 0; i < isochp->ctxt_recv_count; i++) { 218 if ((isochp->ctxt_recv[i].ctxt_flags & 219 HCI1394_ISO_CTXT_INUSE) == 0) { 220 break; 221 } 222 } 223 224 /* if there aren't any left, return an error */ 225 /* XXX support for multi-chan could go here */ 226 if (i >= isochp->ctxt_recv_count) { 227 mutex_exit(&isochp->ctxt_list_mutex); 228 *resultp = IXL1394_ENO_DMA_RESRCS; 229 return (DDI_FAILURE); 230 } 231 232 /* set up receive mode flags */ 233 if ((idi->idma_options & ID1394_LISTEN_BUF_MODE) != 0) { 234 isochp->ctxt_recv[i].ctxt_flags |= 235 HCI1394_ISO_CTXT_BFFILL; 236 } 237 if ((idi->idma_options & ID1394_RECV_HEADERS) != 0) { 238 isochp->ctxt_recv[i].ctxt_flags |= 239 HCI1394_ISO_CTXT_RHDRS; 240 } 241 242 /* mark inuse and set up handle to context */ 243 isochp->ctxt_recv[i].ctxt_flags |= HCI1394_ISO_CTXT_INUSE; 244 ctxtp = &isochp->ctxt_recv[i]; 245 246 isochp->ctxt_recv[i].ctxt_regsp = (hci1394_ctxt_regs_t *) 247 &soft_statep->ohci->ohci_regs->ir[i]; 248 } 249 mutex_exit(&isochp->ctxt_list_mutex); 250 251 /* before compiling, set up some default context values */ 252 ctxtp->isochan = idi->channel_num; 253 ctxtp->default_tag = idi->default_tag; 254 ctxtp->default_sync = idi->default_sync; 255 ctxtp->global_callback_arg = idi->global_callback_arg; 256 ctxtp->isoch_dma_stopped = idi->isoch_dma_stopped; 257 ctxtp->idma_evt_arg = idi->idma_evt_arg; 258 ctxtp->isospd = idi->it_speed; 259 ctxtp->default_skipmode = idi->it_default_skip; 260 ctxtp->default_skiplabelp = idi->it_default_skiplabel; 261 262 err = hci1394_compile_ixl(soft_statep, ctxtp, idi->ixlp, resultp); 263 264 265 /* 266 * if the compile failed, clear the appropriate flags. 267 * Note that the context mutex is needed to eliminate race condition 268 * with cycle_inconsistent and other error intrs. 269 */ 270 if (err != DDI_SUCCESS) { 271 272 mutex_enter(&isochp->ctxt_list_mutex); 273 if ((ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RECV) != 0) { 274 /* undo the set up of receive mode flags */ 275 isochp->ctxt_recv[i].ctxt_flags &= 276 ~HCI1394_ISO_CTXT_BFFILL; 277 isochp->ctxt_recv[i].ctxt_flags &= 278 ~HCI1394_ISO_CTXT_RHDRS; 279 } 280 ctxtp->ctxt_flags &= ~HCI1394_ISO_CTXT_INUSE; 281 mutex_exit(&isochp->ctxt_list_mutex); 282 283 return (DDI_FAILURE); 284 } 285 286 /* 287 * Update count of allocated isoch dma (and enable interrupts 288 * if necessary) 289 */ 290 mutex_enter(&isochp->ctxt_list_mutex); 291 if (isochp->isoch_dma_alloc_cnt == 0) { 292 hci1394_ohci_intr_clear(soft_statep->ohci, 293 OHCI_INTR_CYC_LOST | OHCI_INTR_CYC_INCONSISTENT); 294 hci1394_ohci_intr_enable(soft_statep->ohci, 295 OHCI_INTR_CYC_LOST | OHCI_INTR_CYC_INCONSISTENT); 296 } 297 isochp->isoch_dma_alloc_cnt++; 298 mutex_exit(&isochp->ctxt_list_mutex); 299 300 /* No errors, so all set to go. initialize interrupt/execution flags */ 301 ctxtp->intr_flags = 0; 302 303 *hal_idma_handlep = ctxtp; 304 return (DDI_SUCCESS); 305 } 306 307 308 /* 309 * hci1394_start_isoch_dma() 310 * Used to start an allocated isochronous dma resource. 311 * Sets the context's command ptr to start at the first IXL, 312 * sets up IR match register (if IR), and enables the context_control 313 * register RUN bit. 314 */ 315 /* ARGSUSED */ 316 int 317 hci1394_start_isoch_dma(void *hal_private, void *hal_isoch_dma_handle, 318 id1394_isoch_dma_ctrlinfo_t *idma_ctrlinfop, uint_t flags, int *result) 319 { 320 hci1394_state_t *soft_statep = (hci1394_state_t *)hal_private; 321 hci1394_iso_ctxt_t *ctxtp; 322 int tag0, tag1, tag2, tag3; 323 324 /* pick up the context pointer from the private idma data */ 325 ctxtp = (hci1394_iso_ctxt_t *)hal_isoch_dma_handle; 326 327 ASSERT(hal_private != NULL); 328 ASSERT(ctxtp != NULL); 329 ASSERT(idma_ctrlinfop != NULL); 330 331 /* if the context is already running, just exit. else set running */ 332 mutex_enter(&soft_statep->isoch->ctxt_list_mutex); 333 if ((ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RUNNING) != 0) { 334 335 mutex_exit(&soft_statep->isoch->ctxt_list_mutex); 336 337 return (DDI_SUCCESS); 338 } 339 ctxtp->ctxt_flags |= HCI1394_ISO_CTXT_RUNNING; 340 mutex_exit(&soft_statep->isoch->ctxt_list_mutex); 341 342 ctxtp->intr_flags &= ~HCI1394_ISO_CTXT_STOP; 343 344 /* initialize context values */ 345 ctxtp->ixl_execp = ctxtp->ixl_firstp; /* start of ixl chain */ 346 ctxtp->ixl_exec_depth = 0; 347 ctxtp->dma_last_time = 0; 348 ctxtp->rem_noadv_intrs = ctxtp->max_noadv_intrs; 349 350 /* 351 * clear out hci DMA descriptor status to start with clean slate. 352 * note that statuses could be set if context was previously started 353 * then stopped. 354 */ 355 hci1394_ixl_reset_status(ctxtp); 356 357 /* set up registers, and start isoch */ 358 if (ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RECV) { 359 360 /* set context's command ptr to the first descriptor */ 361 hci1394_ohci_ir_cmd_ptr_set(soft_statep->ohci, 362 ctxtp->ctxt_index, ctxtp->dma_mem_execp); 363 364 /* 365 * determine correct tag values. map target's requested 2-bit 366 * tag into one of the 4 openHCI tag bits. 367 * XXX for now the t1394 api only supports a single tag setting, 368 * whereas openhci supports a set of (non-mutually exclusive) 369 * valid tags. if the api changes to support multiple 370 * simultaneous tags, then this code must be changed. 371 */ 372 tag0 = 0; 373 tag1 = 1; 374 tag2 = 2; 375 tag3 = 3; 376 if (ctxtp->default_tag == 0x0) 377 tag0 = 1; 378 else if (ctxtp->default_tag == 0x1) 379 tag1 = 1; 380 else if (ctxtp->default_tag == 0x2) 381 tag2 = 1; 382 else if (ctxtp->default_tag == 0x3) 383 tag3 = 1; 384 385 /* set match register as desired */ 386 HCI1394_IRCTXT_MATCH_WRITE(soft_statep, ctxtp->ctxt_index, tag3, 387 tag2, tag1, tag0, 388 idma_ctrlinfop->start_cycle /* cycleMatch */, 389 ctxtp->default_sync /* sync */, 0 /* tag1sync */, 390 ctxtp->isochan /* chan */); 391 392 /* clear all bits in context ctrl reg to init to known state */ 393 HCI1394_IRCTXT_CTRL_CLR(soft_statep, ctxtp->ctxt_index, 394 (uint32_t)1, 1, 1, 1, 1); 395 396 /* set desired values in context control register */ 397 HCI1394_IRCTXT_CTRL_SET(soft_statep, ctxtp->ctxt_index, 398 (ctxtp->ctxt_flags & HCI1394_ISO_CTXT_BFFILL) != 0 /* bf */, 399 (ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RHDRS) != 0 /* hdr */, 400 (flags & ID1394_START_ON_CYCLE) != 0 /* match enbl */, 401 0 /* multi-chan mode */, 1 /* run */, 0 /* wake */); 402 403 /* 404 * before enabling interrupts, make sure any vestige interrupt 405 * event (from a previous use) is cleared. 406 */ 407 hci1394_ohci_ir_intr_clear(soft_statep->ohci, 408 (uint32_t)(0x1 << ctxtp->ctxt_index)); 409 410 /* enable interrupts for this IR context */ 411 hci1394_ohci_ir_intr_enable(soft_statep->ohci, 412 (uint32_t)(0x1 << ctxtp->ctxt_index)); 413 414 } else { 415 /* TRANSMIT */ 416 417 /* set context's command ptr to the first descriptor */ 418 hci1394_ohci_it_cmd_ptr_set(soft_statep->ohci, 419 ctxtp->ctxt_index, ctxtp->dma_mem_execp); 420 421 /* set desired values in context control register */ 422 HCI1394_ITCTXT_CTRL_SET(soft_statep, ctxtp->ctxt_index, 423 ((flags & ID1394_START_ON_CYCLE) != 0) /* match enable */, 424 idma_ctrlinfop->start_cycle /* cycle Match */, 425 1 /* run */, 0 /* wake */); 426 427 /* 428 * before enabling interrupts, make sure any vestige interrupt 429 * event (from a previous use) is cleared. 430 */ 431 hci1394_ohci_it_intr_clear(soft_statep->ohci, 432 (uint32_t)(0x1 << ctxtp->ctxt_index)); 433 434 /* enable interrupts for this IT context */ 435 hci1394_ohci_it_intr_enable(soft_statep->ohci, 436 (uint32_t)(0x1 << ctxtp->ctxt_index)); 437 } 438 439 return (DDI_SUCCESS); 440 } 441 442 /* 443 * hci1394_update_isoch_dma() 444 * 445 * Returns DDI_SUCCESS, or DDI_FAILURE. If DDI_FAILURE, then resultp 446 * contains the error code. 447 */ 448 /* ARGSUSED */ 449 int 450 hci1394_update_isoch_dma(void *hal_private, void *hal_isoch_dma_handle, 451 id1394_isoch_dma_updateinfo_t *idma_updateinfop, uint_t flags, int *resultp) 452 { 453 hci1394_state_t *soft_statep = (hci1394_state_t *)hal_private; 454 hci1394_iso_ctxt_t *ctxtp; 455 ixl1394_command_t *cur_new_ixlp; 456 ixl1394_command_t *cur_orig_ixlp; 457 int ii; 458 int err = DDI_SUCCESS; 459 460 /* pick up the context pointer from the private idma data */ 461 ctxtp = (hci1394_iso_ctxt_t *)hal_isoch_dma_handle; 462 463 ASSERT(hal_private != NULL); 464 ASSERT(ctxtp != NULL); 465 ASSERT(idma_updateinfop != NULL); 466 467 /* 468 * regardless of the type of context (IR or IT), loop through each 469 * command pair (one from new, one from orig), updating the relevant 470 * fields of orig with those from new. 471 */ 472 cur_new_ixlp = idma_updateinfop->temp_ixlp; 473 cur_orig_ixlp = idma_updateinfop->orig_ixlp; 474 475 ASSERT(cur_new_ixlp != NULL); 476 ASSERT(cur_orig_ixlp != NULL); 477 478 for (ii = 0; (ii < idma_updateinfop->ixl_count) && (err == DDI_SUCCESS); 479 ii++) { 480 481 /* error if hit a null ixl command too soon */ 482 if ((cur_new_ixlp == NULL) || (cur_orig_ixlp == NULL)) { 483 *resultp = IXL1394_ECOUNT_MISMATCH; 484 err = DDI_FAILURE; 485 486 break; 487 } 488 489 /* proceed with the update */ 490 err = hci1394_ixl_update(soft_statep, ctxtp, cur_new_ixlp, 491 cur_orig_ixlp, 0, resultp); 492 493 /* advance new and orig chains */ 494 cur_new_ixlp = cur_new_ixlp->next_ixlp; 495 cur_orig_ixlp = cur_orig_ixlp->next_ixlp; 496 } 497 498 return (err); 499 } 500 501 502 /* 503 * hci1394_stop_isoch_dma() 504 * Used to stop a "running" isochronous dma resource. 505 * This is a wrapper which calls the hci1394_do_stop to do the actual work, 506 * but NOT to invoke the target's isoch_dma_stopped(). 507 */ 508 /* ARGSUSED */ 509 void 510 hci1394_stop_isoch_dma(void *hal_private, void *hal_isoch_dma_handle, 511 int *result) 512 { 513 hci1394_state_t *soft_statep = (hci1394_state_t *)hal_private; 514 hci1394_iso_ctxt_t *ctxtp; 515 516 /* pick up the context pointer from the private idma data */ 517 ctxtp = (hci1394_iso_ctxt_t *)hal_isoch_dma_handle; 518 519 ASSERT(hal_private != NULL); 520 ASSERT(ctxtp != NULL); 521 522 /* stop the context, do not invoke target's stop callback */ 523 hci1394_do_stop(soft_statep, ctxtp, B_FALSE, 0); 524 525 /* 526 * call interrupt processing functions to bring callbacks and 527 * store_timestamps upto date. Don't care about errors. 528 */ 529 hci1394_ixl_interrupt(soft_statep, ctxtp, B_TRUE); 530 } 531 532 /* 533 * hci1394_do_stop() 534 * Used to stop a "running" isochronous dma resource. 535 * Disables interrupts for the context, clears the context_control register's 536 * RUN bit, and makes sure the ixl is up-to-date with where the hardware is 537 * in the DMA chain. 538 * If do_callback is B_TRUE, the target's isoch_dma_stopped() callback is 539 * invoked. Caller must not hold mutex(es) if calling with 540 * do_callback==B_TRUE, otherwise mutex(es) will be held during callback. 541 * If do_callback is B_FALSE, the isoch_dma_stopped() callback is NOT 542 * invoked and stop_args is ignored. 543 */ 544 void 545 hci1394_do_stop(hci1394_state_t *soft_statep, hci1394_iso_ctxt_t *ctxtp, 546 boolean_t do_callback, id1394_isoch_dma_stopped_t stop_args) 547 { 548 int count; 549 clock_t upto; 550 551 /* already stopped? if yes, done, else set state to not-running */ 552 mutex_enter(&soft_statep->isoch->ctxt_list_mutex); 553 if ((ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RUNNING) == 0) { 554 mutex_exit(&soft_statep->isoch->ctxt_list_mutex); 555 return; 556 } 557 ctxtp->ctxt_flags &= ~HCI1394_ISO_CTXT_RUNNING; 558 mutex_exit(&soft_statep->isoch->ctxt_list_mutex); 559 560 /* turn off context control register's run bit */ 561 if (ctxtp->ctxt_flags & HCI1394_ISO_CTXT_RECV) { 562 /* RECEIVE */ 563 564 /* disable interrupts for this IR context */ 565 hci1394_ohci_ir_intr_disable(soft_statep->ohci, 566 (uint32_t)(0x1 << ctxtp->ctxt_index)); 567 568 /* turn off run bit */ 569 HCI1394_IRCTXT_CTRL_CLR(soft_statep, ctxtp->ctxt_index, 570 0 /* bffill */, 0 /* iso hdrs */, 0 /* match enbl */, 571 0 /* multi-chan mode (not implemented) */, 1 /* run */); 572 } else { 573 /* TRANSMIT */ 574 575 /* disable interrupts for this IT context */ 576 hci1394_ohci_it_intr_disable(soft_statep->ohci, 577 (uint32_t)(0x1 << ctxtp->ctxt_index)); 578 579 /* turn of run bit */ 580 HCI1394_ITCTXT_CTRL_CLR(soft_statep, ctxtp->ctxt_index, 581 0 /* match enbl */, 0 /* match */, 1 /* run */); 582 } 583 584 /* 585 * If interrupt is already in progress, wait until it's over. 586 * Otherwise, set flag to prevent the new interrupt. 587 */ 588 mutex_enter(&ctxtp->intrprocmutex); 589 ctxtp->intr_flags |= HCI1394_ISO_CTXT_STOP; 590 if (ctxtp->intr_flags & HCI1394_ISO_CTXT_ININTR) { 591 upto = ddi_get_lbolt() + 592 drv_usectohz(hci1394_iso_ctxt_stop_intr_timeout_uS); 593 while (ctxtp->intr_flags & HCI1394_ISO_CTXT_ININTR) { 594 if (cv_timedwait(&ctxtp->intr_cv, &ctxtp->intrprocmutex, 595 upto) <= 0) { 596 break; 597 } 598 } 599 } 600 mutex_exit(&ctxtp->intrprocmutex); 601 602 /* Wait until "active" bit is cleared before continuing */ 603 count = 0; 604 while (count < hci1394_iso_ctxt_stop_delay_uS) { 605 /* Has the "active" bit gone low yet? */ 606 if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) == 0) 607 break; 608 609 /* 610 * The context did not stop yet. Wait 1us, increment the 611 * count and try again. 612 */ 613 drv_usecwait(1); 614 count++; 615 } 616 617 /* Check to see if we timed out or not */ 618 if (count >= hci1394_iso_ctxt_stop_delay_uS) { 619 h1394_error_detected(soft_statep->drvinfo.di_sl_private, 620 H1394_SELF_INITIATED_SHUTDOWN, NULL); 621 cmn_err(CE_WARN, "hci1394(%d): driver shutdown: " 622 "unable to stop isoch context", 623 soft_statep->drvinfo.di_instance); 624 hci1394_shutdown(soft_statep->drvinfo.di_dip); 625 626 return; 627 } 628 629 /* 630 * invoke callback as directed. Note that the CTXT_INCALL flag is NOT 631 * needed here. That flag is only used when we have to drop a mutex 632 * that we want to grab back again. We're not doing that here. 633 */ 634 if (do_callback == B_TRUE) { 635 if (ctxtp->isoch_dma_stopped != NULL) { 636 ctxtp->isoch_dma_stopped( 637 (struct isoch_dma_handle *)ctxtp, 638 ctxtp->idma_evt_arg, stop_args); 639 } 640 } 641 } 642 643 /* 644 * hci1394_free_isoch_dma() 645 * Used to free up usage of an isochronous context and any other 646 * system resources acquired during IXL compilation. 647 * This does NOT free up the IXL and it's data buffers which is 648 * the target driver's responsibility. 649 */ 650 void 651 hci1394_free_isoch_dma(void *hal_private, void *hal_isoch_dma_handle) 652 { 653 hci1394_state_t *soft_statep = (hci1394_state_t *)hal_private; 654 hci1394_iso_ctxt_t *ctxtp; 655 hci1394_isoch_t *isochp; 656 657 /* pick up the context pointer from the private idma data */ 658 ctxtp = (hci1394_iso_ctxt_t *)hal_isoch_dma_handle; 659 660 ASSERT(soft_statep); 661 ASSERT(ctxtp); 662 663 isochp = soft_statep->isoch; 664 665 mutex_enter(&soft_statep->isoch->ctxt_list_mutex); 666 667 /* delete xfer_ctl structs and pages of allocated hci_desc memory */ 668 hci1394_ixl_cleanup(soft_statep, ctxtp); 669 670 /* 671 * free context. no need to determine if xmit or recv. clearing of recv 672 * flags is harmless for xmit. 673 */ 674 ctxtp->ctxt_flags &= ~(HCI1394_ISO_CTXT_INUSE | 675 HCI1394_ISO_CTXT_BFFILL | HCI1394_ISO_CTXT_RHDRS); 676 677 /* 678 * Update count of allocated isoch dma (and disable interrupts 679 * if necessary) 680 */ 681 ASSERT(isochp->isoch_dma_alloc_cnt > 0); 682 isochp->isoch_dma_alloc_cnt--; 683 if (isochp->isoch_dma_alloc_cnt == 0) { 684 hci1394_ohci_intr_disable(soft_statep->ohci, 685 OHCI_INTR_CYC_LOST | OHCI_INTR_CYC_INCONSISTENT); 686 } 687 688 mutex_exit(&soft_statep->isoch->ctxt_list_mutex); 689 } 690 691 /* 692 * hci1394_isoch_recv_count_get() 693 * returns the number of supported isoch receive contexts. 694 */ 695 int 696 hci1394_isoch_recv_count_get(hci1394_isoch_handle_t isoch_hdl) 697 { 698 ASSERT(isoch_hdl != NULL); 699 return (isoch_hdl->ctxt_recv_count); 700 } 701 702 /* 703 * hci1394_isoch_recv_ctxt_get() 704 * given a context index, returns its isoch receive context struct 705 */ 706 hci1394_iso_ctxt_t * 707 hci1394_isoch_recv_ctxt_get(hci1394_isoch_handle_t isoch_hdl, int num) 708 { 709 ASSERT(isoch_hdl != NULL); 710 return (&isoch_hdl->ctxt_recv[num]); 711 } 712 713 /* 714 * hci1394_isoch_xmit_count_get() 715 * returns the number of supported isoch transmit contexts. 716 */ 717 int 718 hci1394_isoch_xmit_count_get(hci1394_isoch_handle_t isoch_hdl) 719 { 720 ASSERT(isoch_hdl != NULL); 721 return (isoch_hdl->ctxt_xmit_count); 722 } 723 724 /* 725 * hci1394_isoch_xmit_ctxt_get() 726 * given a context index, returns its isoch transmit context struct 727 */ 728 hci1394_iso_ctxt_t * 729 hci1394_isoch_xmit_ctxt_get(hci1394_isoch_handle_t isoch_hdl, int num) 730 { 731 ASSERT(isoch_hdl != NULL); 732 return (&isoch_hdl->ctxt_xmit[num]); 733 } 734 735 /* 736 * hci1394_isoch_error_ints_enable() 737 * after bus reset, reenable CYCLE_LOST and CYCLE_INCONSISTENT 738 * interrupts (if necessary). 739 */ 740 void 741 hci1394_isoch_error_ints_enable(hci1394_state_t *soft_statep) 742 { 743 ASSERT(soft_statep); 744 745 mutex_enter(&soft_statep->isoch->ctxt_list_mutex); 746 747 if (soft_statep->isoch->isoch_dma_alloc_cnt != 0) { 748 soft_statep->isoch->cycle_lost_thresh.delta_t_counter = 0; 749 soft_statep->isoch->cycle_incon_thresh.delta_t_counter = 0; 750 hci1394_ohci_intr_clear(soft_statep->ohci, 751 OHCI_INTR_CYC_LOST | OHCI_INTR_CYC_INCONSISTENT); 752 hci1394_ohci_intr_enable(soft_statep->ohci, 753 OHCI_INTR_CYC_LOST | OHCI_INTR_CYC_INCONSISTENT); 754 } 755 mutex_exit(&soft_statep->isoch->ctxt_list_mutex); 756 } 757