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