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