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 1999-2002 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * hci1394_ixl_isr.c 29 * Isochronous IXL Interrupt Service Routines. 30 * The interrupt handler determines which OpenHCI DMA descriptors 31 * have been executed by the hardware, tracks the path in the 32 * corresponding IXL program, issues callbacks as needed, and resets 33 * the OpenHCI DMA descriptors. 34 */ 35 36 #include <sys/types.h> 37 #include <sys/conf.h> 38 #include <sys/1394/h1394.h> 39 #include <sys/1394/ixl1394.h> 40 #include <sys/1394/adapters/hci1394.h> 41 42 43 /* Return values for local hci1394_ixl_intr_check_done() */ 44 #define IXL_CHECK_LOST (-1) /* ixl cmd intr processing lost */ 45 #define IXL_CHECK_DONE 0 /* ixl cmd intr processing done */ 46 #define IXL_CHECK_SKIP 1 /* ixl cmd intr processing context skipped */ 47 #define IXL_CHECK_STOP 2 /* ixl cmd intr processing context stopped */ 48 49 static boolean_t hci1394_ixl_intr_check_xfer(hci1394_state_t *soft_statep, 50 hci1394_iso_ctxt_t *ctxtp, ixl1394_command_t *ixlp, 51 ixl1394_command_t **ixlnextpp, uint16_t *timestampp, int *donecodep); 52 static int hci1394_ixl_intr_check_done(hci1394_state_t *soft_statep, 53 hci1394_iso_ctxt_t *ctxtp); 54 55 /* 56 * hci1394_ixl_interrupt 57 * main entry point (front-end) into interrupt processing. 58 * acquires mutex, checks if update in progress, sets flags accordingly, 59 * and calls to do real interrupt processing. 60 */ 61 void 62 hci1394_ixl_interrupt(hci1394_state_t *soft_statep, 63 hci1394_iso_ctxt_t *ctxtp, boolean_t in_stop) 64 { 65 uint_t status; 66 int retcode; 67 68 status = 1; 69 70 /* acquire the interrupt processing context mutex */ 71 mutex_enter(&ctxtp->intrprocmutex); 72 73 /* set flag to indicate that interrupt processing is required */ 74 ctxtp->intr_flags |= HCI1394_ISO_CTXT_INTRSET; 75 76 /* if update proc already in progress, let it handle intr processing */ 77 if (ctxtp->intr_flags & HCI1394_ISO_CTXT_INUPDATE) { 78 retcode = HCI1394_IXL_INTR_INUPDATE; 79 status = 0; 80 } else if (ctxtp->intr_flags & HCI1394_ISO_CTXT_ININTR) { 81 /* else fatal error if inter processing already in progress */ 82 retcode = HCI1394_IXL_INTR_ININTR; 83 status = 0; 84 } else if (ctxtp->intr_flags & HCI1394_ISO_CTXT_INCALL) { 85 /* else fatal error if callback in progress flag is set */ 86 retcode = HCI1394_IXL_INTR_INCALL; 87 status = 0; 88 } else if (!in_stop && (ctxtp->intr_flags & HCI1394_ISO_CTXT_STOP)) { 89 /* context is being stopped */ 90 retcode = HCI1394_IXL_INTR_STOP; 91 status = 0; 92 } 93 94 /* 95 * if context is available, reserve it, do interrupt processing 96 * and free it 97 */ 98 if (status) { 99 ctxtp->intr_flags |= HCI1394_ISO_CTXT_ININTR; 100 ctxtp->intr_flags &= ~HCI1394_ISO_CTXT_INTRSET; 101 mutex_exit(&ctxtp->intrprocmutex); 102 103 retcode = hci1394_ixl_dma_sync(soft_statep, ctxtp); 104 105 mutex_enter(&ctxtp->intrprocmutex); 106 ctxtp->intr_flags &= ~HCI1394_ISO_CTXT_ININTR; 107 108 /* notify stop thread that the interrupt is finished */ 109 if ((ctxtp->intr_flags & HCI1394_ISO_CTXT_STOP) && !in_stop) { 110 cv_signal(&ctxtp->intr_cv); 111 } 112 }; 113 114 /* free the intr processing context mutex before error checks */ 115 mutex_exit(&ctxtp->intrprocmutex); 116 117 /* if context stopped, invoke callback */ 118 if (retcode == HCI1394_IXL_INTR_DMASTOP) { 119 hci1394_do_stop(soft_statep, ctxtp, B_TRUE, ID1394_DONE); 120 } 121 /* if error, stop and invoke callback */ 122 if (retcode == HCI1394_IXL_INTR_DMALOST) { 123 hci1394_do_stop(soft_statep, ctxtp, B_TRUE, ID1394_FAIL); 124 } 125 } 126 127 /* 128 * hci1394_ixl_dma_sync() 129 * the heart of interrupt processing, this routine correlates where the 130 * hardware is for the specified context with the IXL program. Invokes 131 * callbacks as needed. Also called by "update" to make sure ixl is 132 * sync'ed up with where the hardware is. 133 * Returns one of the ixl_intr defined return codes - HCI1394_IXL_INTR... 134 * {..._DMALOST, ..._DMASTOP, ..._NOADV,... _NOERROR} 135 */ 136 int 137 hci1394_ixl_dma_sync(hci1394_state_t *soft_statep, hci1394_iso_ctxt_t *ctxtp) 138 { 139 ixl1394_command_t *ixlp = NULL; /* current ixl command */ 140 ixl1394_command_t *ixlnextp; /* next ixl command */ 141 uint16_t ixlopcode; 142 uint16_t timestamp; 143 int donecode; 144 boolean_t isdone; 145 146 void (*callback)(opaque_t, struct ixl1394_callback *); 147 148 ASSERT(MUTEX_NOT_HELD(&ctxtp->intrprocmutex)); 149 150 /* xfer start ixl cmd where last left off */ 151 ixlnextp = ctxtp->ixl_execp; 152 153 /* last completed descriptor block's timestamp */ 154 timestamp = ctxtp->dma_last_time; 155 156 /* 157 * follow execution path in IXL, until find dma descriptor in IXL 158 * xfer command whose status isn't set or until run out of IXL cmds 159 */ 160 while (ixlnextp != NULL) { 161 ixlp = ixlnextp; 162 ixlnextp = ixlp->next_ixlp; 163 ixlopcode = ixlp->ixl_opcode & ~IXL1394_OPF_UPDATE; 164 165 /* 166 * process IXL commands: xfer start, callback, store timestamp 167 * and jump and ignore the others 168 */ 169 170 /* determine if this is an xfer start IXL command */ 171 if (((ixlopcode & IXL1394_OPF_ISXFER) != 0) && 172 ((ixlopcode & IXL1394_OPTY_MASK) != 0)) { 173 174 /* process xfer cmd to see if HW has been here */ 175 isdone = hci1394_ixl_intr_check_xfer(soft_statep, ctxtp, 176 ixlp, &ixlnextp, ×tamp, &donecode); 177 178 if (isdone == B_TRUE) { 179 return (donecode); 180 } 181 182 /* continue to process next IXL command */ 183 continue; 184 } 185 186 /* else check if IXL cmd - jump, callback or store timestamp */ 187 switch (ixlopcode) { 188 case IXL1394_OP_JUMP: 189 /* 190 * set next IXL cmd to label ptr in current IXL jump cmd 191 */ 192 ixlnextp = ((ixl1394_jump_t *)ixlp)->label; 193 break; 194 195 case IXL1394_OP_STORE_TIMESTAMP: 196 /* 197 * set last timestamp value recorded into current IXL 198 * cmd 199 */ 200 ((ixl1394_store_timestamp_t *)ixlp)->timestamp = 201 timestamp; 202 break; 203 204 case IXL1394_OP_CALLBACK: 205 /* 206 * if callback function is specified, call it with IXL 207 * cmd addr. Make sure to grab the lock before setting 208 * the "in callback" flag in intr_flags. 209 */ 210 mutex_enter(&ctxtp->intrprocmutex); 211 ctxtp->intr_flags |= HCI1394_ISO_CTXT_INCALL; 212 mutex_exit(&ctxtp->intrprocmutex); 213 214 callback = ((ixl1394_callback_t *)ixlp)->callback; 215 if (callback != NULL) { 216 callback(ctxtp->global_callback_arg, 217 (ixl1394_callback_t *)ixlp); 218 } 219 220 /* 221 * And grab the lock again before clearing 222 * the "in callback" flag. 223 */ 224 mutex_enter(&ctxtp->intrprocmutex); 225 ctxtp->intr_flags &= ~HCI1394_ISO_CTXT_INCALL; 226 mutex_exit(&ctxtp->intrprocmutex); 227 break; 228 } 229 } 230 231 /* 232 * If we jumped to NULL because of an updateable JUMP, set ixl_execp 233 * back to ixlp. The destination label might get updated to a 234 * non-NULL value. 235 */ 236 if ((ixlp != NULL) && (ixlp->ixl_opcode == IXL1394_OP_JUMP_U)) { 237 ctxtp->ixl_execp = ixlp; 238 return (HCI1394_IXL_INTR_NOERROR); 239 } 240 241 /* save null IXL cmd and depth and last timestamp */ 242 ctxtp->ixl_execp = NULL; 243 ctxtp->ixl_exec_depth = 0; 244 ctxtp->dma_last_time = timestamp; 245 246 ctxtp->rem_noadv_intrs = 0; 247 248 249 /* return stopped status if at end of IXL cmds & context stopped */ 250 if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) == 0) { 251 return (HCI1394_IXL_INTR_DMASTOP); 252 } 253 254 /* else interrupt processing is lost */ 255 return (HCI1394_IXL_INTR_DMALOST); 256 } 257 258 /* 259 * hci1394_ixl_intr_check_xfer() 260 * Process given IXL xfer cmd, checking status of each dma descriptor block 261 * for the command until find one whose status isn't set or until full depth 262 * reached at current IXL command or until find hardware skip has occurred. 263 * 264 * Returns B_TRUE if processing should terminate (either have stopped 265 * or encountered an error), and B_FALSE if it should continue looking. 266 * If B_TRUE, donecodep contains the reason: HCI1394_IXL_INTR_DMALOST, 267 * HCI1394_IXL_INTR_DMASTOP, HCI1394_IXL_INTR_NOADV, or 268 * HCI1394_IXL_INTR_NOERROR. NOERROR means that the current location 269 * has been determined and do not need to look further. 270 */ 271 static boolean_t 272 hci1394_ixl_intr_check_xfer(hci1394_state_t *soft_statep, 273 hci1394_iso_ctxt_t *ctxtp, ixl1394_command_t *ixlp, 274 ixl1394_command_t **ixlnextpp, uint16_t *timestampp, int *donecodep) 275 { 276 uint_t dma_advances; 277 int intrstatus; 278 uint_t skipped; 279 hci1394_xfer_ctl_t *xferctlp; 280 uint16_t ixldepth; 281 uint16_t ixlopcode; 282 283 *donecodep = 0; 284 dma_advances = 0; 285 ixldepth = ctxtp->ixl_exec_depth; 286 ixlopcode = ixlp->ixl_opcode & ~IXL1394_OPF_UPDATE; 287 288 /* get control struct for this xfer start IXL command */ 289 xferctlp = (hci1394_xfer_ctl_t *)ixlp->compiler_privatep; 290 291 skipped = 0; 292 while ((skipped == 0) && (ixldepth < xferctlp->cnt)) { 293 /* 294 * check if status is set in dma descriptor 295 * block at cur depth in cur xfer start IXL cmd 296 */ 297 if (hci1394_ixl_check_status(&xferctlp->dma[ixldepth], 298 ixlopcode, timestampp, B_TRUE) != 0) { 299 300 /* advance depth to next desc block in cur IXL cmd */ 301 ixldepth++; 302 303 /* 304 * count dma desc blks whose status was set 305 * (i.e. advanced to next dma desc) 306 */ 307 dma_advances++; 308 continue; 309 } 310 311 /* if get to here, status is not set */ 312 313 /* 314 * cur IXL cmd dma desc status not set. save IXL cur cmd 315 * and depth and last timestamp for next time. 316 */ 317 ctxtp->ixl_execp = ixlp; 318 ctxtp->ixl_exec_depth = ixldepth; 319 ctxtp->dma_last_time = *timestampp; 320 321 /* 322 * check if dma descriptor processing location is indeterminate 323 * (lost), context has either stopped, is done, or has skipped 324 */ 325 intrstatus = hci1394_ixl_intr_check_done(soft_statep, ctxtp); 326 if (intrstatus == IXL_CHECK_LOST) { 327 /* 328 * location indeterminate, try once more to determine 329 * current state. First, recheck if status has become 330 * set in cur dma descriptor block. (don't reset status 331 * here if is set) 332 */ 333 if (hci1394_ixl_check_status(&xferctlp->dma[ixldepth], 334 ixlopcode, timestampp, 1) != B_TRUE) { 335 /* resume from where we left off */ 336 skipped = 0; 337 continue; 338 } 339 340 /* 341 * status not set, check intr processing 342 * completion status again 343 */ 344 if ((intrstatus = hci1394_ixl_intr_check_done( 345 soft_statep, ctxtp)) == IXL_CHECK_LOST) { 346 /* 347 * location still indeterminate, 348 * processing is lost 349 */ 350 *donecodep = HCI1394_IXL_INTR_DMALOST; 351 return (B_TRUE); 352 } 353 } 354 355 /* 356 * if dma processing stopped. current location has been 357 * determined. 358 */ 359 if (intrstatus == IXL_CHECK_STOP) { 360 /* 361 * save timestamp, clear currently executing IXL 362 * command and depth. return stopped. 363 */ 364 ctxtp->ixl_execp = NULL; 365 ctxtp->ixl_exec_depth = 0; 366 ctxtp->dma_last_time = *timestampp; 367 ctxtp->rem_noadv_intrs = 0; 368 369 *donecodep = HCI1394_IXL_INTR_DMASTOP; 370 return (B_TRUE); 371 } 372 373 /* 374 * dma processing done for now. current location has 375 * has been determined 376 */ 377 if (intrstatus == IXL_CHECK_DONE) { 378 /* 379 * if in update processing call: 380 * clear update processing flag & return ok. 381 * if dma advances happened, reset to max allowed. 382 * however, if none have, don't reduce remaining 383 * amount - that's for real interrupt call to adjust. 384 */ 385 if (ctxtp->intr_flags & HCI1394_ISO_CTXT_INUPDATE) { 386 387 if (dma_advances > 0) { 388 ctxtp->rem_noadv_intrs = 389 ctxtp->max_noadv_intrs; 390 } 391 392 *donecodep = HCI1394_IXL_INTR_NOERROR; 393 return (B_TRUE); 394 } 395 396 /* 397 * else, not in update call processing, are in normal 398 * intr call. if no dma statuses were found set 399 * (i.e. no dma advances), reduce remaining count of 400 * interrupts allowed with no I/O completions 401 */ 402 if (dma_advances == 0) { 403 ctxtp->rem_noadv_intrs--; 404 } else { 405 /* 406 * else some dma statuses were found set. 407 * reinit remaining count of interrupts allowed 408 * with no I/O completions 409 */ 410 ctxtp->rem_noadv_intrs = ctxtp->max_noadv_intrs; 411 } 412 413 /* 414 * if no remaining count of interrupts allowed with no 415 * I/O completions, return failure (no dma advance after 416 * max retries), else return ok 417 */ 418 if (ctxtp->rem_noadv_intrs == 0) { 419 *donecodep = HCI1394_IXL_INTR_NOADV; 420 return (B_TRUE); 421 } 422 423 *donecodep = HCI1394_IXL_INTR_NOERROR; 424 return (B_TRUE); 425 } 426 427 /* 428 * else (intrstatus == IXL_CHECK_SKIP) indicating skip has 429 * occured, retrieve current IXL cmd, depth, and timestamp and 430 * continue interrupt processing 431 */ 432 skipped = 1; 433 *ixlnextpp = ctxtp->ixl_execp; 434 ixldepth = ctxtp->ixl_exec_depth; 435 *timestampp = ctxtp->dma_last_time; 436 437 /* 438 * also count as 1, intervening skips to next posted 439 * dma descriptor. 440 */ 441 dma_advances++; 442 } 443 444 /* 445 * if full depth reached at current IXL cmd, set back to start for next 446 * IXL xfer command that will be processed 447 */ 448 if ((skipped == 0) && (ixldepth >= xferctlp->cnt)) { 449 ctxtp->ixl_exec_depth = 0; 450 } 451 452 /* 453 * make sure rem_noadv_intrs is reset to max if we advanced. 454 */ 455 if (dma_advances > 0) { 456 ctxtp->rem_noadv_intrs = ctxtp->max_noadv_intrs; 457 } 458 459 /* continue to process next IXL command */ 460 return (B_FALSE); 461 } 462 463 /* 464 * hci1394_ixl_intr_check_done() 465 * checks if context has stopped, or if able to match hardware location 466 * with an expected IXL program location. 467 */ 468 static int 469 hci1394_ixl_intr_check_done(hci1394_state_t *soft_statep, 470 hci1394_iso_ctxt_t *ctxtp) 471 { 472 ixl1394_command_t *ixlp; 473 hci1394_xfer_ctl_t *xferctlp; 474 uint_t ixldepth; 475 hci1394_xfer_ctl_dma_t *dma; 476 ddi_acc_handle_t acc_hdl; 477 ddi_dma_handle_t dma_hdl; 478 uint32_t desc_status; 479 hci1394_desc_t *hcidescp; 480 off_t hcidesc_off; 481 uint32_t dma_cmd_cur_loc; 482 uint32_t dma_cmd_last_loc; 483 uint32_t dma_loc_check_enabled; 484 uint32_t dmastartp; 485 uint32_t dmaendp; 486 487 uint_t rem_dma_skips; 488 uint16_t skipmode; 489 uint16_t skipdepth; 490 ixl1394_command_t *skipdestp; 491 ixl1394_command_t *skipxferp; 492 493 /* 494 * start looking through the IXL list from the xfer start command where 495 * we last left off (for composite opcodes, need to start from the 496 * appropriate depth). 497 */ 498 499 ixlp = ctxtp->ixl_execp; 500 ixldepth = ctxtp->ixl_exec_depth; 501 502 /* control struct for xfer start IXL command */ 503 xferctlp = (hci1394_xfer_ctl_t *)ixlp->compiler_privatep; 504 dma = &xferctlp->dma[ixldepth]; 505 506 /* determine if dma location checking is enabled */ 507 if ((dma_loc_check_enabled = 508 (ctxtp->ctxt_flags & HCI1394_ISO_CTXT_CMDREG)) != 0) { 509 510 /* if so, get current dma command location */ 511 dma_cmd_last_loc = 0xFFFFFFFF; 512 513 while ((dma_cmd_cur_loc = HCI1394_ISOCH_CTXT_CMD_PTR( 514 soft_statep, ctxtp)) != dma_cmd_last_loc) { 515 516 /* retry get until location register stabilizes */ 517 dma_cmd_last_loc = dma_cmd_cur_loc; 518 } 519 } 520 521 /* 522 * compare the (bound) address of the DMA descriptor corresponding to 523 * the current xfer IXL command against the current value in the 524 * DMA location register. If exists and if matches, then 525 * if context stopped, return stopped, else return done. 526 * 527 * The dma start address is the first address of the descriptor block. 528 * Since "Z" is a count of 16-byte descriptors in the block, calculate 529 * the end address by adding Z*16 to the start addr. 530 */ 531 dmastartp = dma->dma_bound & ~DESC_Z_MASK; 532 dmaendp = dmastartp + ((dma->dma_bound & DESC_Z_MASK) << 4); 533 534 if (dma_loc_check_enabled && 535 ((dma_cmd_cur_loc >= dmastartp) && (dma_cmd_cur_loc < dmaendp))) { 536 537 if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) == 0) { 538 return (IXL_CHECK_STOP); 539 } 540 541 return (IXL_CHECK_DONE); 542 } 543 544 /* 545 * if receive mode: 546 */ 547 if ((ixlp->ixl_opcode & IXL1394_OPF_ONXMIT) == 0) { 548 /* 549 * if context stopped, return stopped, else, 550 * if there is no current dma location reg, return done 551 * else return location indeterminate 552 */ 553 if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) == 0) { 554 return (IXL_CHECK_STOP); 555 } 556 if (!dma_loc_check_enabled) { 557 return (IXL_CHECK_DONE); 558 } 559 560 return (IXL_CHECK_LOST); 561 } 562 563 /* 564 * else is xmit mode: 565 * check status of current xfer IXL command's dma descriptor 566 */ 567 acc_hdl = dma->dma_buf->bi_handle; 568 dma_hdl = dma->dma_buf->bi_dma_handle; 569 hcidescp = (hci1394_desc_t *)dma->dma_descp; 570 hcidesc_off = (off_t)hcidescp - (off_t)dma->dma_buf->bi_kaddr; 571 572 /* Sync the descriptor before we get the status */ 573 (void) ddi_dma_sync(dma_hdl, hcidesc_off, sizeof (hci1394_desc_t), 574 DDI_DMA_SYNC_FORCPU); 575 desc_status = ddi_get32(acc_hdl, &hcidescp->status); 576 577 if ((desc_status & DESC_XFER_ACTIVE_MASK) != 0) { 578 579 /* 580 * if status is now set here, return skipped, to cause calling 581 * function to continue, even though location hasn't changed 582 */ 583 return (IXL_CHECK_SKIP); 584 } 585 586 /* 587 * At this point, we have gotten to a DMA descriptor with an empty 588 * status. This is not enough information however to determine that 589 * we've found all processed DMA descriptors because during cycle-lost 590 * conditions, the HW will skip over some descriptors without writing 591 * status. So we have to look ahead until we're convinced that the HW 592 * hasn't jumped ahead. 593 * 594 * Follow the IXL skip-to links until find one whose status is set 595 * or until dma location register (if any) matches an xfer IXL 596 * command's dma location or until have examined max_dma_skips 597 * IXL commands. 598 */ 599 rem_dma_skips = ctxtp->max_dma_skips; 600 601 while (rem_dma_skips-- > 0) { 602 603 /* 604 * get either IXL command specific or 605 * system default skipmode info 606 */ 607 skipdepth = 0; 608 if (xferctlp->skipmodep != NULL) { 609 skipmode = xferctlp->skipmodep->skipmode; 610 skipdestp = xferctlp->skipmodep->label; 611 skipxferp = (ixl1394_command_t *) 612 xferctlp->skipmodep->compiler_privatep; 613 } else { 614 skipmode = ctxtp->default_skipmode; 615 skipdestp = ctxtp->default_skiplabelp; 616 skipxferp = ctxtp->default_skipxferp; 617 } 618 619 switch (skipmode) { 620 621 case IXL1394_SKIP_TO_SELF: 622 /* 623 * mode is skip to self: 624 * if context is stopped, return stopped, else 625 * if dma location reg not enabled, return done 626 * else, return location indeterminate 627 */ 628 if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) == 629 0) { 630 return (IXL_CHECK_STOP); 631 } 632 633 if (!dma_loc_check_enabled) { 634 return (IXL_CHECK_DONE); 635 } 636 637 return (IXL_CHECK_LOST); 638 639 case IXL1394_SKIP_TO_NEXT: 640 /* 641 * mode is skip to next: 642 * set potential skip target to current command at 643 * next depth 644 */ 645 skipdestp = ixlp; 646 skipxferp = ixlp; 647 skipdepth = ixldepth + 1; 648 649 /* 650 * else if at max depth at current cmd adjust to next 651 * IXL command. 652 * 653 * (NOTE: next means next IXL command along execution 654 * path, whatever IXL command it might be. e.g. store 655 * timestamp or callback or label or jump or send... ) 656 */ 657 if (skipdepth >= xferctlp->cnt) { 658 skipdepth = 0; 659 skipdestp = ixlp->next_ixlp; 660 skipxferp = xferctlp->execp; 661 } 662 663 /* evaluate skip to status further, below */ 664 break; 665 666 667 case IXL1394_SKIP_TO_LABEL: 668 /* 669 * mode is skip to label: 670 * set skip destination depth to 0 (should be 671 * redundant) 672 */ 673 skipdepth = 0; 674 675 /* evaluate skip to status further, below */ 676 break; 677 678 case IXL1394_SKIP_TO_STOP: 679 /* 680 * mode is skip to stop: 681 * set all xfer and destination skip to locations to 682 * null 683 */ 684 skipxferp = NULL; 685 skipdestp = NULL; 686 skipdepth = 0; 687 688 /* evaluate skip to status further, below */ 689 break; 690 691 } /* end switch */ 692 693 /* 694 * if no xfer IXL command follows at or after current skip-to 695 * location 696 */ 697 if (skipxferp == NULL) { 698 /* 699 * if context is stopped, return stopped, else 700 * if dma location reg not enabled, return done 701 * else, return location indeterminate 702 */ 703 if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) == 704 0) { 705 return (IXL_CHECK_STOP); 706 } 707 708 if (!dma_loc_check_enabled) { 709 return (IXL_CHECK_DONE); 710 } 711 return (IXL_CHECK_LOST); 712 } 713 714 /* 715 * if the skip to xfer IXL dma descriptor's status is set, 716 * then execution did skip 717 */ 718 xferctlp = (hci1394_xfer_ctl_t *)skipxferp->compiler_privatep; 719 dma = &xferctlp->dma[skipdepth]; 720 acc_hdl = dma->dma_buf->bi_handle; 721 dma_hdl = dma->dma_buf->bi_dma_handle; 722 hcidescp = (hci1394_desc_t *)dma->dma_descp; 723 hcidesc_off = (off_t)hcidescp - (off_t)dma->dma_buf->bi_kaddr; 724 725 /* Sync the descriptor before we get the status */ 726 (void) ddi_dma_sync(dma_hdl, hcidesc_off, 727 sizeof (hci1394_desc_t), DDI_DMA_SYNC_FORCPU); 728 desc_status = ddi_get32(acc_hdl, &hcidescp->status); 729 730 if ((desc_status & DESC_XFER_ACTIVE_MASK) != 0) { 731 732 /* 733 * adjust to continue from skip to IXL command and 734 * return skipped, to have calling func continue. 735 * (Note: next IXL command may be any allowed IXL 736 * command) 737 */ 738 ctxtp->ixl_execp = skipdestp; 739 ctxtp->ixl_exec_depth = skipdepth; 740 741 return (IXL_CHECK_SKIP); 742 } 743 744 /* 745 * if dma location command register checking is enabled, 746 * and the skip to xfer IXL dma location matches current 747 * dma location register value, execution did skip 748 */ 749 dmastartp = dma->dma_bound & ~DESC_Z_MASK; 750 dmaendp = dmastartp + ((dma->dma_bound & DESC_Z_MASK) << 4); 751 752 if (dma_loc_check_enabled && ((dma_cmd_cur_loc >= dmastartp) && 753 (dma_cmd_cur_loc < dmaendp))) { 754 755 /* if the context is stopped, return stopped */ 756 if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) == 757 0) { 758 return (IXL_CHECK_STOP); 759 } 760 /* 761 * adjust to continue from skip to IXL command and 762 * return skipped, to have calling func continue 763 * (Note: next IXL command may be any allowed IXL cmd) 764 */ 765 ctxtp->ixl_execp = skipdestp; 766 ctxtp->ixl_exec_depth = skipdepth; 767 768 return (IXL_CHECK_SKIP); 769 } 770 771 /* 772 * else, advance working current locn to skipxferp and 773 * skipdepth and continue skip evaluation loop processing 774 */ 775 ixlp = skipxferp; 776 ixldepth = skipdepth; 777 778 } /* end while */ 779 780 /* 781 * didn't find dma status set, nor location reg match, along skip path 782 * 783 * if context is stopped, return stopped, 784 * 785 * else if no current location reg active don't change context values, 786 * just return done (no skip) 787 * 788 * else, return location indeterminate 789 */ 790 791 if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) == 0) { 792 return (IXL_CHECK_STOP); 793 } 794 if (!dma_loc_check_enabled) { 795 return (IXL_CHECK_DONE); 796 } 797 798 return (IXL_CHECK_LOST); 799 } 800 801 /* 802 * hci1394_isoch_cycle_inconsistent() 803 * Called during interrupt notification to indicate that the cycle time 804 * has changed unexpectedly. We need to take this opportunity to 805 * update our tracking of each running transmit context's execution. 806 * cycle_inconsistent only affects transmit, so recv contexts are left alone. 807 */ 808 void 809 hci1394_isoch_cycle_inconsistent(hci1394_state_t *soft_statep) 810 { 811 int i, cnt_thresh; 812 boolean_t note; 813 hrtime_t current_time, last_time, delta, delta_thresh; 814 hci1394_iso_ctxt_t *ctxtp; /* current context */ 815 816 ASSERT(soft_statep); 817 818 hci1394_ohci_intr_clear(soft_statep->ohci, OHCI_INTR_CYC_INCONSISTENT); 819 820 /* grab the mutex before checking each context's INUSE and RUNNING */ 821 mutex_enter(&soft_statep->isoch->ctxt_list_mutex); 822 823 /* check for transmit contexts which are inuse and running */ 824 for (i = 0; i < soft_statep->isoch->ctxt_xmit_count; i++) { 825 ctxtp = &soft_statep->isoch->ctxt_xmit[i]; 826 827 if ((ctxtp->ctxt_flags & 828 (HCI1394_ISO_CTXT_INUSE | HCI1394_ISO_CTXT_RUNNING)) != 0) { 829 830 mutex_exit(&soft_statep->isoch->ctxt_list_mutex); 831 hci1394_ixl_interrupt(soft_statep, ctxtp, B_FALSE); 832 mutex_enter(&soft_statep->isoch->ctxt_list_mutex); 833 } 834 } 835 836 /* 837 * get the current time and calculate the delta between now and 838 * when the last interrupt was processed. (NOTE: if the time 839 * returned by gethrtime() rolls-over while we are counting these 840 * interrupts, we will incorrectly restart the counting process. 841 * However, because the probability of this happening is small and 842 * not catching the roll-over will AT MOST double the time it takes 843 * us to discover and correct from this condition, we can safely 844 * ignore it.) 845 */ 846 current_time = gethrtime(); 847 last_time = soft_statep->isoch->cycle_incon_thresh.last_intr_time; 848 delta = current_time - last_time; 849 850 /* 851 * compare the calculated delta to the delta T threshold. If it 852 * is less than the threshold, then increment the counter. If it 853 * is not then reset the counter. 854 */ 855 delta_thresh = soft_statep->isoch->cycle_incon_thresh.delta_t_thresh; 856 if (delta < delta_thresh) 857 soft_statep->isoch->cycle_incon_thresh.delta_t_counter++; 858 else 859 soft_statep->isoch->cycle_incon_thresh.delta_t_counter = 0; 860 861 /* 862 * compare the counter to the counter threshold. If it is greater, 863 * then disable the cycle inconsistent interrupt. 864 */ 865 cnt_thresh = soft_statep->isoch->cycle_incon_thresh.counter_thresh; 866 note = B_FALSE; 867 if (soft_statep->isoch->cycle_incon_thresh.delta_t_counter > 868 cnt_thresh) { 869 hci1394_ohci_intr_disable(soft_statep->ohci, 870 OHCI_INTR_CYC_INCONSISTENT); 871 note = B_TRUE; 872 } 873 874 /* save away the current time into the last_intr_time field */ 875 soft_statep->isoch->cycle_incon_thresh.last_intr_time = current_time; 876 877 mutex_exit(&soft_statep->isoch->ctxt_list_mutex); 878 879 if (note == B_TRUE) { 880 cmn_err(CE_NOTE, "!hci1394(%d): cycle_inconsistent interrupt " 881 "disabled until next bus reset", 882 soft_statep->drvinfo.di_instance); 883 } 884 } 885 886 887 /* 888 * hci1394_isoch_cycle_lost() 889 * Interrupt indicates an expected cycle_start packet (and therefore our 890 * opportunity to transmit) did not show up. Update our tracking of each 891 * running transmit context. 892 */ 893 void 894 hci1394_isoch_cycle_lost(hci1394_state_t *soft_statep) 895 { 896 int i, cnt_thresh; 897 boolean_t note; 898 hrtime_t current_time, last_time, delta, delta_thresh; 899 hci1394_iso_ctxt_t *ctxtp; /* current context */ 900 901 ASSERT(soft_statep); 902 903 hci1394_ohci_intr_clear(soft_statep->ohci, OHCI_INTR_CYC_LOST); 904 905 /* grab the mutex before checking each context's INUSE and RUNNING */ 906 mutex_enter(&soft_statep->isoch->ctxt_list_mutex); 907 908 /* check for transmit contexts which are inuse and running */ 909 for (i = 0; i < soft_statep->isoch->ctxt_xmit_count; i++) { 910 ctxtp = &soft_statep->isoch->ctxt_xmit[i]; 911 912 if ((ctxtp->ctxt_flags & 913 (HCI1394_ISO_CTXT_INUSE | HCI1394_ISO_CTXT_RUNNING)) != 0) { 914 915 mutex_exit(&soft_statep->isoch->ctxt_list_mutex); 916 hci1394_ixl_interrupt(soft_statep, ctxtp, B_FALSE); 917 mutex_enter(&soft_statep->isoch->ctxt_list_mutex); 918 } 919 } 920 921 /* 922 * get the current time and calculate the delta between now and 923 * when the last interrupt was processed. (NOTE: if the time 924 * returned by gethrtime() rolls-over while we are counting these 925 * interrupts, we will incorrectly restart the counting process. 926 * However, because the probability of this happening is small and 927 * not catching the roll-over will AT MOST double the time it takes 928 * us to discover and correct from this condition, we can safely 929 * ignore it.) 930 */ 931 current_time = gethrtime(); 932 last_time = soft_statep->isoch->cycle_lost_thresh.last_intr_time; 933 delta = current_time - last_time; 934 935 /* 936 * compare the calculated delta to the delta T threshold. If it 937 * is less than the threshold, then increment the counter. If it 938 * is not then reset the counter. 939 */ 940 delta_thresh = soft_statep->isoch->cycle_lost_thresh.delta_t_thresh; 941 if (delta < delta_thresh) 942 soft_statep->isoch->cycle_lost_thresh.delta_t_counter++; 943 else 944 soft_statep->isoch->cycle_lost_thresh.delta_t_counter = 0; 945 946 /* 947 * compare the counter to the counter threshold. If it is greater, 948 * then disable the cycle lost interrupt. 949 */ 950 cnt_thresh = soft_statep->isoch->cycle_lost_thresh.counter_thresh; 951 note = B_FALSE; 952 if (soft_statep->isoch->cycle_lost_thresh.delta_t_counter > 953 cnt_thresh) { 954 hci1394_ohci_intr_disable(soft_statep->ohci, 955 OHCI_INTR_CYC_LOST); 956 note = B_TRUE; 957 } 958 959 /* save away the current time into the last_intr_time field */ 960 soft_statep->isoch->cycle_lost_thresh.last_intr_time = current_time; 961 962 mutex_exit(&soft_statep->isoch->ctxt_list_mutex); 963 964 if (note == B_TRUE) { 965 cmn_err(CE_NOTE, "!hci1394(%d): cycle_lost interrupt " 966 "disabled until next bus reset", 967 soft_statep->drvinfo.di_instance); 968 } 969 } 970