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