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