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
hci1394_ixl_interrupt(hci1394_state_t * soft_statep,hci1394_iso_ctxt_t * ctxtp,boolean_t in_stop)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
hci1394_ixl_dma_sync(hci1394_state_t * soft_statep,hci1394_iso_ctxt_t * ctxtp)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
hci1394_ixl_intr_check_xfer(hci1394_state_t * soft_statep,hci1394_iso_ctxt_t * ctxtp,ixl1394_command_t * ixlp,ixl1394_command_t ** ixlnextpp,uint16_t * timestampp,int * donecodep)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
hci1394_ixl_intr_check_done(hci1394_state_t * soft_statep,hci1394_iso_ctxt_t * ctxtp)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
hci1394_isoch_cycle_inconsistent(hci1394_state_t * soft_statep)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
hci1394_isoch_cycle_lost(hci1394_state_t * soft_statep)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