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 (c) 1999-2000 by Sun Microsystems, Inc.
24*7c478bd9Sstevel@tonic-gate  * All rights reserved.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*
28*7c478bd9Sstevel@tonic-gate  * s1394_isoch.c
29*7c478bd9Sstevel@tonic-gate  *    1394 Services Layer Isochronous Communication Routines
30*7c478bd9Sstevel@tonic-gate  *    This file contains routines for managing isochronous bandwidth
31*7c478bd9Sstevel@tonic-gate  *    and channel needs for registered targets (through the target
32*7c478bd9Sstevel@tonic-gate  *    isoch interfaces).
33*7c478bd9Sstevel@tonic-gate  */
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/1394/t1394.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/1394/s1394.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/1394/h1394.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/1394/ieee1394.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate /*
45*7c478bd9Sstevel@tonic-gate  * s1394_isoch_rsrc_realloc()
46*7c478bd9Sstevel@tonic-gate  *    is called during bus reset processing to reallocate any isochronous
47*7c478bd9Sstevel@tonic-gate  *    resources that were previously allocated.
48*7c478bd9Sstevel@tonic-gate  */
49*7c478bd9Sstevel@tonic-gate void
s1394_isoch_rsrc_realloc(s1394_hal_t * hal)50*7c478bd9Sstevel@tonic-gate s1394_isoch_rsrc_realloc(s1394_hal_t *hal)
51*7c478bd9Sstevel@tonic-gate {
52*7c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_t *cec_curr;
53*7c478bd9Sstevel@tonic-gate 	uint32_t	  chnl_mask;
54*7c478bd9Sstevel@tonic-gate 	uint32_t	  old_chnl_mask;
55*7c478bd9Sstevel@tonic-gate 	uint_t		  bw_alloc_units;
56*7c478bd9Sstevel@tonic-gate 	uint_t		  generation;
57*7c478bd9Sstevel@tonic-gate 	uint_t		  chnl_num;
58*7c478bd9Sstevel@tonic-gate 	int		  err;
59*7c478bd9Sstevel@tonic-gate 	int		  ret;
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate 	/*
62*7c478bd9Sstevel@tonic-gate 	 * Get the current generation number - don't need the
63*7c478bd9Sstevel@tonic-gate 	 * topology tree mutex here because it is read-only, and
64*7c478bd9Sstevel@tonic-gate 	 * there is a race condition with or without it.
65*7c478bd9Sstevel@tonic-gate 	 */
66*7c478bd9Sstevel@tonic-gate 	generation = hal->generation_count;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate 	/* Lock the Isoch CEC list */
69*7c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->isoch_cec_list_mutex);
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate 	cec_curr = hal->isoch_cec_list_head;
72*7c478bd9Sstevel@tonic-gate 	while (cec_curr != NULL) {
73*7c478bd9Sstevel@tonic-gate 		/* Lock the Isoch CEC member list */
74*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cec_curr->isoch_cec_mutex);
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate 		/* Are we supposed to reallocate resources? */
77*7c478bd9Sstevel@tonic-gate 		if (!(cec_curr->cec_options & T1394_NO_IRM_ALLOC) &&
78*7c478bd9Sstevel@tonic-gate 		    (cec_curr->realloc_valid == B_TRUE) &&
79*7c478bd9Sstevel@tonic-gate 		    (cec_curr->realloc_failed == B_FALSE)) {
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 			/* Reallocate some bandwidth */
82*7c478bd9Sstevel@tonic-gate 			bw_alloc_units = s1394_compute_bw_alloc_units(hal,
83*7c478bd9Sstevel@tonic-gate 			    cec_curr->bandwidth, cec_curr->realloc_speed);
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate 			/* Check that the generation has not changed */
86*7c478bd9Sstevel@tonic-gate 			if (generation != hal->generation_count) {
87*7c478bd9Sstevel@tonic-gate 				/* Try the next Isoch CEC */
88*7c478bd9Sstevel@tonic-gate 				goto next_isoch_cec;
89*7c478bd9Sstevel@tonic-gate 			}
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate 			/* Unlock the Isoch CEC member list */
92*7c478bd9Sstevel@tonic-gate 			mutex_exit(&cec_curr->isoch_cec_mutex);
93*7c478bd9Sstevel@tonic-gate 			/*
94*7c478bd9Sstevel@tonic-gate 			 * We can unlock the Isoch CEC list here
95*7c478bd9Sstevel@tonic-gate 			 * because we know this Isoch CEC can not
96*7c478bd9Sstevel@tonic-gate 			 * go away (we are trying to realloc its
97*7c478bd9Sstevel@tonic-gate 			 * resources so it can't be in a state that
98*7c478bd9Sstevel@tonic-gate 			 * will allow a free).
99*7c478bd9Sstevel@tonic-gate 			 */
100*7c478bd9Sstevel@tonic-gate 			mutex_exit(&hal->isoch_cec_list_mutex);
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate 			/* Try to reallocate bandwidth */
103*7c478bd9Sstevel@tonic-gate 			ret = s1394_bandwidth_alloc(hal, bw_alloc_units,
104*7c478bd9Sstevel@tonic-gate 			    generation, &err);
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 			/* Lock the Isoch CEC list */
107*7c478bd9Sstevel@tonic-gate 			mutex_enter(&hal->isoch_cec_list_mutex);
108*7c478bd9Sstevel@tonic-gate 			/* Lock the Isoch CEC member list */
109*7c478bd9Sstevel@tonic-gate 			mutex_enter(&cec_curr->isoch_cec_mutex);
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate 			/* If we failed because we couldn't get bandwidth */
112*7c478bd9Sstevel@tonic-gate 			if (ret == DDI_FAILURE) {
113*7c478bd9Sstevel@tonic-gate 				cec_curr->realloc_failed = B_TRUE;
114*7c478bd9Sstevel@tonic-gate 				cec_curr->realloc_fail_reason =
115*7c478bd9Sstevel@tonic-gate 				    T1394_RSRC_BANDWIDTH;
116*7c478bd9Sstevel@tonic-gate 			}
117*7c478bd9Sstevel@tonic-gate 		}
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate 		/* Are we supposed to reallocate resources? */
120*7c478bd9Sstevel@tonic-gate 		if (!(cec_curr->cec_options & T1394_NO_IRM_ALLOC) &&
121*7c478bd9Sstevel@tonic-gate 		    (cec_curr->realloc_valid == B_TRUE) &&
122*7c478bd9Sstevel@tonic-gate 		    (cec_curr->realloc_failed == B_FALSE)) {
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 			/* Reallocate the channel */
125*7c478bd9Sstevel@tonic-gate 			chnl_num  = cec_curr->realloc_chnl_num;
126*7c478bd9Sstevel@tonic-gate 			chnl_mask = (1 << ((63 - chnl_num) % 32));
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 			/* Unlock the Isoch CEC member list */
129*7c478bd9Sstevel@tonic-gate 			mutex_exit(&cec_curr->isoch_cec_mutex);
130*7c478bd9Sstevel@tonic-gate 			/*
131*7c478bd9Sstevel@tonic-gate 			 * We can unlock the Isoch CEC list here
132*7c478bd9Sstevel@tonic-gate 			 * because we know this Isoch CEC can not
133*7c478bd9Sstevel@tonic-gate 			 * go away (we are trying to realloc its
134*7c478bd9Sstevel@tonic-gate 			 * resources so it can't be in a state that
135*7c478bd9Sstevel@tonic-gate 			 * will allow a free).
136*7c478bd9Sstevel@tonic-gate 			 */
137*7c478bd9Sstevel@tonic-gate 			mutex_exit(&hal->isoch_cec_list_mutex);
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 			if (chnl_num < 32) {
140*7c478bd9Sstevel@tonic-gate 				ret = s1394_channel_alloc(hal, chnl_mask,
141*7c478bd9Sstevel@tonic-gate 				    generation, S1394_CHANNEL_ALLOC_HI,
142*7c478bd9Sstevel@tonic-gate 				    &old_chnl_mask, &err);
143*7c478bd9Sstevel@tonic-gate 			} else {
144*7c478bd9Sstevel@tonic-gate 				ret = s1394_channel_alloc(hal, chnl_mask,
145*7c478bd9Sstevel@tonic-gate 				    generation, S1394_CHANNEL_ALLOC_LO,
146*7c478bd9Sstevel@tonic-gate 				    &old_chnl_mask, &err);
147*7c478bd9Sstevel@tonic-gate 			}
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 			/* Lock the Isoch CEC list */
150*7c478bd9Sstevel@tonic-gate 			mutex_enter(&hal->isoch_cec_list_mutex);
151*7c478bd9Sstevel@tonic-gate 			/* Lock the Isoch CEC member list */
152*7c478bd9Sstevel@tonic-gate 			mutex_enter(&cec_curr->isoch_cec_mutex);
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 			if (ret == DDI_FAILURE) {
155*7c478bd9Sstevel@tonic-gate 				if (err != CMD1394_EBUSRESET) {
156*7c478bd9Sstevel@tonic-gate 					/*
157*7c478bd9Sstevel@tonic-gate 					 * If we successfully reallocate
158*7c478bd9Sstevel@tonic-gate 					 * bandwidth, and then fail getting
159*7c478bd9Sstevel@tonic-gate 					 * the channel, we need to free up
160*7c478bd9Sstevel@tonic-gate 					 * the bandwidth
161*7c478bd9Sstevel@tonic-gate 					 */
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 					/* Try to free up the bandwidth */
164*7c478bd9Sstevel@tonic-gate 					ret = s1394_bandwidth_free(hal,
165*7c478bd9Sstevel@tonic-gate 					    bw_alloc_units, generation, &err);
166*7c478bd9Sstevel@tonic-gate 					/* Try the next Isoch CEC */
167*7c478bd9Sstevel@tonic-gate 					goto next_isoch_cec;
168*7c478bd9Sstevel@tonic-gate 				}
169*7c478bd9Sstevel@tonic-gate 				cec_curr->realloc_failed = B_TRUE;
170*7c478bd9Sstevel@tonic-gate 				cec_curr->realloc_fail_reason =
171*7c478bd9Sstevel@tonic-gate 				    T1394_RSRC_CHANNEL;
172*7c478bd9Sstevel@tonic-gate 			}
173*7c478bd9Sstevel@tonic-gate 		}
174*7c478bd9Sstevel@tonic-gate next_isoch_cec:
175*7c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
176*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
177*7c478bd9Sstevel@tonic-gate 		cec_curr = cec_curr->cec_next;
178*7c478bd9Sstevel@tonic-gate 	}
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	/* Unlock the Isoch CEC list */
181*7c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->isoch_cec_list_mutex);
182*7c478bd9Sstevel@tonic-gate }
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate /*
185*7c478bd9Sstevel@tonic-gate  * s1394_isoch_rsrc_realloc_notify()
186*7c478bd9Sstevel@tonic-gate  *    is called during bus reset processing to notify all targets for
187*7c478bd9Sstevel@tonic-gate  *    which isochronous resources were not able to be reallocated.
188*7c478bd9Sstevel@tonic-gate  */
189*7c478bd9Sstevel@tonic-gate void
s1394_isoch_rsrc_realloc_notify(s1394_hal_t * hal)190*7c478bd9Sstevel@tonic-gate s1394_isoch_rsrc_realloc_notify(s1394_hal_t *hal)
191*7c478bd9Sstevel@tonic-gate {
192*7c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_t	 *cec_curr;
193*7c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_member_t *member_curr;
194*7c478bd9Sstevel@tonic-gate 	t1394_isoch_rsrc_error_t fail_arg;
195*7c478bd9Sstevel@tonic-gate 	opaque_t		 evts_arg;
196*7c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_type_t	 type;
197*7c478bd9Sstevel@tonic-gate 	void (*rsrc_fail_callback)(t1394_isoch_cec_handle_t, opaque_t,
198*7c478bd9Sstevel@tonic-gate 				t1394_isoch_rsrc_error_t);
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	/* Lock the Isoch CEC list */
201*7c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->isoch_cec_list_mutex);
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	/* Notify all targets that failed realloc */
204*7c478bd9Sstevel@tonic-gate 	cec_curr = hal->isoch_cec_list_head;
205*7c478bd9Sstevel@tonic-gate 	while (cec_curr != NULL) {
206*7c478bd9Sstevel@tonic-gate 		/* Lock the Isoch CEC member list */
207*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cec_curr->isoch_cec_mutex);
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 		/* Do we notify of realloc failure? */
210*7c478bd9Sstevel@tonic-gate 		if (!(cec_curr->cec_options & T1394_NO_IRM_ALLOC) &&
211*7c478bd9Sstevel@tonic-gate 		    (cec_curr->realloc_valid == B_TRUE) &&
212*7c478bd9Sstevel@tonic-gate 		    (cec_curr->realloc_failed == B_TRUE)) {
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 			/* Reason for realloc failure */
215*7c478bd9Sstevel@tonic-gate 			fail_arg = cec_curr->realloc_fail_reason;
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 			/* Now we are going into the callbacks */
218*7c478bd9Sstevel@tonic-gate 			cec_curr->in_fail_callbacks = B_TRUE;
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 			type = cec_curr->cec_type;
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 			/* Unlock the Isoch CEC member list */
223*7c478bd9Sstevel@tonic-gate 			mutex_exit(&cec_curr->isoch_cec_mutex);
224*7c478bd9Sstevel@tonic-gate 			/*
225*7c478bd9Sstevel@tonic-gate 			 * We can unlock the Isoch CEC list here
226*7c478bd9Sstevel@tonic-gate 			 * because we have the in_fail_callbacks
227*7c478bd9Sstevel@tonic-gate 			 * field set to B_TRUE.  And free will fail
228*7c478bd9Sstevel@tonic-gate 			 * if we are in fail callbacks.
229*7c478bd9Sstevel@tonic-gate 			 */
230*7c478bd9Sstevel@tonic-gate 			mutex_exit(&hal->isoch_cec_list_mutex);
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 			/* Call all of the rsrc_fail_target() callbacks */
233*7c478bd9Sstevel@tonic-gate 			/* Start at the head (talker first) and */
234*7c478bd9Sstevel@tonic-gate 			/* go toward the tail (listeners last) */
235*7c478bd9Sstevel@tonic-gate 			member_curr = cec_curr->cec_member_list_head;
236*7c478bd9Sstevel@tonic-gate 			while (member_curr != NULL) {
237*7c478bd9Sstevel@tonic-gate 				rsrc_fail_callback = member_curr->
238*7c478bd9Sstevel@tonic-gate 				    isoch_cec_evts.rsrc_fail_target;
239*7c478bd9Sstevel@tonic-gate 				evts_arg = member_curr->isoch_cec_evts_arg;
240*7c478bd9Sstevel@tonic-gate 				if (rsrc_fail_callback != NULL) {
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 					if (type == S1394_PEER_TO_PEER) {
243*7c478bd9Sstevel@tonic-gate 						rsrc_fail_callback(
244*7c478bd9Sstevel@tonic-gate 						    (t1394_isoch_cec_handle_t)
245*7c478bd9Sstevel@tonic-gate 						    cec_curr, evts_arg,
246*7c478bd9Sstevel@tonic-gate 						    fail_arg);
247*7c478bd9Sstevel@tonic-gate 					} else {
248*7c478bd9Sstevel@tonic-gate 						rsrc_fail_callback(
249*7c478bd9Sstevel@tonic-gate 						    (t1394_isoch_cec_handle_t)
250*7c478bd9Sstevel@tonic-gate 						    cec_curr, evts_arg,
251*7c478bd9Sstevel@tonic-gate 						    fail_arg);
252*7c478bd9Sstevel@tonic-gate 					}
253*7c478bd9Sstevel@tonic-gate 				}
254*7c478bd9Sstevel@tonic-gate 				member_curr = member_curr->cec_mem_next;
255*7c478bd9Sstevel@tonic-gate 			}
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 			/* Lock the Isoch CEC list */
258*7c478bd9Sstevel@tonic-gate 			mutex_enter(&hal->isoch_cec_list_mutex);
259*7c478bd9Sstevel@tonic-gate 			/* Lock the Isoch CEC member list */
260*7c478bd9Sstevel@tonic-gate 			mutex_enter(&cec_curr->isoch_cec_mutex);
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 			/* We are finished with the callbacks */
263*7c478bd9Sstevel@tonic-gate 			cec_curr->in_fail_callbacks = B_FALSE;
264*7c478bd9Sstevel@tonic-gate 			if (cec_curr->cec_want_wakeup == B_TRUE) {
265*7c478bd9Sstevel@tonic-gate 				cec_curr->cec_want_wakeup = B_FALSE;
266*7c478bd9Sstevel@tonic-gate 				cv_broadcast(&cec_curr->in_callbacks_cv);
267*7c478bd9Sstevel@tonic-gate 			}
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 			/* Set flags back to original state */
270*7c478bd9Sstevel@tonic-gate 			cec_curr->realloc_valid	 = B_FALSE;
271*7c478bd9Sstevel@tonic-gate 			cec_curr->realloc_failed = B_FALSE;
272*7c478bd9Sstevel@tonic-gate 		}
273*7c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
274*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
275*7c478bd9Sstevel@tonic-gate 		cec_curr = cec_curr->cec_next;
276*7c478bd9Sstevel@tonic-gate 	}
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	/* Unlock the Isoch CEC list */
279*7c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->isoch_cec_list_mutex);
280*7c478bd9Sstevel@tonic-gate }
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate /*
283*7c478bd9Sstevel@tonic-gate  * s1394_channel_alloc()
284*7c478bd9Sstevel@tonic-gate  *    is used to allocate an isochronous channel.  A channel mask and
285*7c478bd9Sstevel@tonic-gate  *    generation are passed.  A request is sent to whichever node is the
286*7c478bd9Sstevel@tonic-gate  *    IRM for the appropriate channels.  If it fails because of a bus
287*7c478bd9Sstevel@tonic-gate  *    reset it can be retried.  If it fails for another reason the
288*7c478bd9Sstevel@tonic-gate  *    channel(s) may not be availble or there may be no IRM.
289*7c478bd9Sstevel@tonic-gate  */
290*7c478bd9Sstevel@tonic-gate int
s1394_channel_alloc(s1394_hal_t * hal,uint32_t channel_mask,uint_t generation,uint_t flags,uint32_t * old_channels,int * result)291*7c478bd9Sstevel@tonic-gate s1394_channel_alloc(s1394_hal_t *hal, uint32_t channel_mask, uint_t generation,
292*7c478bd9Sstevel@tonic-gate     uint_t flags, uint32_t *old_channels, int *result)
293*7c478bd9Sstevel@tonic-gate {
294*7c478bd9Sstevel@tonic-gate 	cmd1394_cmd_t	*cmd;
295*7c478bd9Sstevel@tonic-gate 	uint64_t	IRM_ID_addr;
296*7c478bd9Sstevel@tonic-gate 	uint32_t	compare;
297*7c478bd9Sstevel@tonic-gate 	uint32_t	swap;
298*7c478bd9Sstevel@tonic-gate 	uint32_t	old_value;
299*7c478bd9Sstevel@tonic-gate 	uint_t		hal_node_num;
300*7c478bd9Sstevel@tonic-gate 	uint_t		IRM_node;
301*7c478bd9Sstevel@tonic-gate 	uint_t		offset;
302*7c478bd9Sstevel@tonic-gate 	int		ret;
303*7c478bd9Sstevel@tonic-gate 	int		i;
304*7c478bd9Sstevel@tonic-gate 	int		num_retries = S1394_ISOCH_ALLOC_RETRIES;
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	/* Lock the topology tree */
307*7c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
310*7c478bd9Sstevel@tonic-gate 	IRM_node = hal->IRM_node;
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	/* Unlock the topology tree */
313*7c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	/* Make sure there is a valid IRM on the bus */
316*7c478bd9Sstevel@tonic-gate 	if (IRM_node == -1) {
317*7c478bd9Sstevel@tonic-gate 		*result = CMD1394_ERETRIES_EXCEEDED;
318*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
319*7c478bd9Sstevel@tonic-gate 	}
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	if (flags & S1394_CHANNEL_ALLOC_HI) {
322*7c478bd9Sstevel@tonic-gate 		offset =
323*7c478bd9Sstevel@tonic-gate 		    (IEEE1394_SCSR_CHANS_AVAIL_HI & IEEE1394_CSR_OFFSET_MASK);
324*7c478bd9Sstevel@tonic-gate 	} else {
325*7c478bd9Sstevel@tonic-gate 		offset =
326*7c478bd9Sstevel@tonic-gate 		    (IEEE1394_SCSR_CHANS_AVAIL_LO & IEEE1394_CSR_OFFSET_MASK);
327*7c478bd9Sstevel@tonic-gate 	}
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	/* Send compare-swap to CHANNELS_AVAILABLE */
330*7c478bd9Sstevel@tonic-gate 	/* register on the Isoch Rsrc Mgr */
331*7c478bd9Sstevel@tonic-gate 	if (IRM_node == hal_node_num) {
332*7c478bd9Sstevel@tonic-gate 		/* Local */
333*7c478bd9Sstevel@tonic-gate 		i = num_retries;
334*7c478bd9Sstevel@tonic-gate 		do {
335*7c478bd9Sstevel@tonic-gate 			(void) HAL_CALL(hal).csr_read(hal->halinfo.hal_private,
336*7c478bd9Sstevel@tonic-gate 			    offset, &old_value);
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 			/* Check that the generation has not changed */
339*7c478bd9Sstevel@tonic-gate 			if (generation != hal->generation_count) {
340*7c478bd9Sstevel@tonic-gate 				*result = CMD1394_EBUSRESET;
341*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
342*7c478bd9Sstevel@tonic-gate 			}
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 			compare = old_value;
345*7c478bd9Sstevel@tonic-gate 			swap	= old_value & (~channel_mask);
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 			ret = HAL_CALL(hal).csr_cswap32(
348*7c478bd9Sstevel@tonic-gate 			    hal->halinfo.hal_private, generation,
349*7c478bd9Sstevel@tonic-gate 			    offset, compare, swap, &old_value);
350*7c478bd9Sstevel@tonic-gate 			if (ret != DDI_SUCCESS) {
351*7c478bd9Sstevel@tonic-gate 				*result = CMD1394_EBUSRESET;
352*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
353*7c478bd9Sstevel@tonic-gate 			}
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 			if ((~old_value & channel_mask) != 0) {
356*7c478bd9Sstevel@tonic-gate 				*result = CMD1394_ERETRIES_EXCEEDED;
357*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
358*7c478bd9Sstevel@tonic-gate 			}
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 			if (old_value == compare) {
361*7c478bd9Sstevel@tonic-gate 				*result = CMD1394_CMDSUCCESS;
362*7c478bd9Sstevel@tonic-gate 				*old_channels = old_value;
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 				return (DDI_SUCCESS);
365*7c478bd9Sstevel@tonic-gate 			}
366*7c478bd9Sstevel@tonic-gate 		} while (i--);
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 		*result = CMD1394_ERETRIES_EXCEEDED;
369*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	} else {
372*7c478bd9Sstevel@tonic-gate 		/* Remote */
373*7c478bd9Sstevel@tonic-gate 		if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) {
374*7c478bd9Sstevel@tonic-gate 			*result = CMD1394_EUNKNOWN_ERROR;
375*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
376*7c478bd9Sstevel@tonic-gate 		}
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 		cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET |
379*7c478bd9Sstevel@tonic-gate 		    CMD1394_OVERRIDE_ADDR | CMD1394_BLOCKING);
380*7c478bd9Sstevel@tonic-gate 		cmd->cmd_type = CMD1394_ASYNCH_LOCK_32;
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 		if (flags & S1394_CHANNEL_ALLOC_HI) {
383*7c478bd9Sstevel@tonic-gate 			IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK |
384*7c478bd9Sstevel@tonic-gate 			    IEEE1394_SCSR_CHANS_AVAIL_HI) |
385*7c478bd9Sstevel@tonic-gate 			    (((uint64_t)IRM_node) <<
386*7c478bd9Sstevel@tonic-gate 			    IEEE1394_ADDR_PHY_ID_SHIFT);
387*7c478bd9Sstevel@tonic-gate 		} else {
388*7c478bd9Sstevel@tonic-gate 			IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK |
389*7c478bd9Sstevel@tonic-gate 			    IEEE1394_SCSR_CHANS_AVAIL_LO) |
390*7c478bd9Sstevel@tonic-gate 			    (((uint64_t)IRM_node) <<
391*7c478bd9Sstevel@tonic-gate 			    IEEE1394_ADDR_PHY_ID_SHIFT);
392*7c478bd9Sstevel@tonic-gate 		}
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 		cmd->cmd_addr		   = IRM_ID_addr;
395*7c478bd9Sstevel@tonic-gate 		cmd->bus_generation	   = generation;
396*7c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.data_value  = T1394_DATA32(~channel_mask);
397*7c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.num_retries = num_retries;
398*7c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.lock_type   = CMD1394_LOCK_BIT_AND;
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 		ret = s1394_split_lock_req(hal, NULL, cmd);
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 		if (ret == DDI_SUCCESS) {
403*7c478bd9Sstevel@tonic-gate 			if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
404*7c478bd9Sstevel@tonic-gate 				*old_channels = T1394_DATA32(
405*7c478bd9Sstevel@tonic-gate 				    cmd->cmd_u.l32.old_value);
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 				if ((~(*old_channels) & channel_mask) != 0) {
408*7c478bd9Sstevel@tonic-gate 					*result = CMD1394_ERETRIES_EXCEEDED;
409*7c478bd9Sstevel@tonic-gate 					ret = DDI_FAILURE;
410*7c478bd9Sstevel@tonic-gate 				} else {
411*7c478bd9Sstevel@tonic-gate 					*result = cmd->cmd_result;
412*7c478bd9Sstevel@tonic-gate 				}
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 				/* Need to free the command */
415*7c478bd9Sstevel@tonic-gate 				(void) s1394_free_cmd(hal, &cmd);
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 				return (ret);
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 			} else {
420*7c478bd9Sstevel@tonic-gate 				*result = cmd->cmd_result;
421*7c478bd9Sstevel@tonic-gate 				/* Need to free the command */
422*7c478bd9Sstevel@tonic-gate 				(void) s1394_free_cmd(hal, &cmd);
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
425*7c478bd9Sstevel@tonic-gate 			}
426*7c478bd9Sstevel@tonic-gate 		} else {
427*7c478bd9Sstevel@tonic-gate 			*result = cmd->cmd_result;
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 			/* Need to free the command */
430*7c478bd9Sstevel@tonic-gate 			(void) s1394_free_cmd(hal, &cmd);
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
433*7c478bd9Sstevel@tonic-gate 		}
434*7c478bd9Sstevel@tonic-gate 	}
435*7c478bd9Sstevel@tonic-gate }
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate /*
438*7c478bd9Sstevel@tonic-gate  * s1394_channel_free()
439*7c478bd9Sstevel@tonic-gate  *    is used to free up an isochronous channel.  A channel mask and
440*7c478bd9Sstevel@tonic-gate  *    generation are passed.  A request is sent to whichever node is the
441*7c478bd9Sstevel@tonic-gate  *    IRM for the appropriate channels.  If it fails because of a bus
442*7c478bd9Sstevel@tonic-gate  *    reset it can be retried.  If it fails for another reason the
443*7c478bd9Sstevel@tonic-gate  *    channel(s) may already be free or there may be no IRM.
444*7c478bd9Sstevel@tonic-gate  */
445*7c478bd9Sstevel@tonic-gate int
s1394_channel_free(s1394_hal_t * hal,uint32_t channel_mask,uint_t generation,uint_t flags,uint32_t * old_channels,int * result)446*7c478bd9Sstevel@tonic-gate s1394_channel_free(s1394_hal_t *hal, uint32_t channel_mask, uint_t generation,
447*7c478bd9Sstevel@tonic-gate     uint_t flags, uint32_t *old_channels, int *result)
448*7c478bd9Sstevel@tonic-gate {
449*7c478bd9Sstevel@tonic-gate 	cmd1394_cmd_t	*cmd;
450*7c478bd9Sstevel@tonic-gate 	uint64_t	IRM_ID_addr;
451*7c478bd9Sstevel@tonic-gate 	uint32_t	compare;
452*7c478bd9Sstevel@tonic-gate 	uint32_t	swap;
453*7c478bd9Sstevel@tonic-gate 	uint32_t	old_value;
454*7c478bd9Sstevel@tonic-gate 	uint_t		hal_node_num;
455*7c478bd9Sstevel@tonic-gate 	uint_t		IRM_node;
456*7c478bd9Sstevel@tonic-gate 	uint_t		offset;
457*7c478bd9Sstevel@tonic-gate 	int		ret;
458*7c478bd9Sstevel@tonic-gate 	int		i;
459*7c478bd9Sstevel@tonic-gate 	int		num_retries = S1394_ISOCH_ALLOC_RETRIES;
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	/* Lock the topology tree */
462*7c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
465*7c478bd9Sstevel@tonic-gate 	IRM_node = hal->IRM_node;
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	/* Unlock the topology tree */
468*7c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	/* Make sure there is a valid IRM on the bus */
471*7c478bd9Sstevel@tonic-gate 	if (IRM_node == -1) {
472*7c478bd9Sstevel@tonic-gate 		*result = CMD1394_ERETRIES_EXCEEDED;
473*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
474*7c478bd9Sstevel@tonic-gate 	}
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	if (flags & S1394_CHANNEL_ALLOC_HI) {
477*7c478bd9Sstevel@tonic-gate 		offset =
478*7c478bd9Sstevel@tonic-gate 		    (IEEE1394_SCSR_CHANS_AVAIL_HI & IEEE1394_CSR_OFFSET_MASK);
479*7c478bd9Sstevel@tonic-gate 	} else {
480*7c478bd9Sstevel@tonic-gate 		offset =
481*7c478bd9Sstevel@tonic-gate 		    (IEEE1394_SCSR_CHANS_AVAIL_LO & IEEE1394_CSR_OFFSET_MASK);
482*7c478bd9Sstevel@tonic-gate 	}
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 	/* Send compare-swap to CHANNELS_AVAILABLE */
485*7c478bd9Sstevel@tonic-gate 	/* register on the Isoch Rsrc Mgr */
486*7c478bd9Sstevel@tonic-gate 	if (hal->IRM_node == hal_node_num) {
487*7c478bd9Sstevel@tonic-gate 		/* Local */
488*7c478bd9Sstevel@tonic-gate 		i = num_retries;
489*7c478bd9Sstevel@tonic-gate 		do {
490*7c478bd9Sstevel@tonic-gate 			(void) HAL_CALL(hal).csr_read(hal->halinfo.hal_private,
491*7c478bd9Sstevel@tonic-gate 			    offset, &old_value);
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 			/* Check that the generation has not changed */
494*7c478bd9Sstevel@tonic-gate 			if (generation != hal->generation_count) {
495*7c478bd9Sstevel@tonic-gate 				*result = CMD1394_EBUSRESET;
496*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
497*7c478bd9Sstevel@tonic-gate 			}
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 			compare = old_value;
500*7c478bd9Sstevel@tonic-gate 			swap	= old_value | channel_mask;
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 			ret = HAL_CALL(hal).csr_cswap32(
503*7c478bd9Sstevel@tonic-gate 			    hal->halinfo.hal_private, hal->generation_count,
504*7c478bd9Sstevel@tonic-gate 			    offset, compare, swap, &old_value);
505*7c478bd9Sstevel@tonic-gate 			if (ret != DDI_SUCCESS) {
506*7c478bd9Sstevel@tonic-gate 				*result = CMD1394_EBUSRESET;
507*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
508*7c478bd9Sstevel@tonic-gate 			}
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 			if (old_value == compare) {
511*7c478bd9Sstevel@tonic-gate 				*result = CMD1394_CMDSUCCESS;
512*7c478bd9Sstevel@tonic-gate 				*old_channels = old_value;
513*7c478bd9Sstevel@tonic-gate 				return (DDI_SUCCESS);
514*7c478bd9Sstevel@tonic-gate 			}
515*7c478bd9Sstevel@tonic-gate 		} while (i--);
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 		*result = CMD1394_ERETRIES_EXCEEDED;
518*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 	} else {
521*7c478bd9Sstevel@tonic-gate 		/* Remote */
522*7c478bd9Sstevel@tonic-gate 		if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) {
523*7c478bd9Sstevel@tonic-gate 			*result = CMD1394_EUNKNOWN_ERROR;
524*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
525*7c478bd9Sstevel@tonic-gate 		}
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 		cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET |
528*7c478bd9Sstevel@tonic-gate 		    CMD1394_OVERRIDE_ADDR | CMD1394_BLOCKING);
529*7c478bd9Sstevel@tonic-gate 		cmd->cmd_type = CMD1394_ASYNCH_LOCK_32;
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 		if (flags & S1394_CHANNEL_ALLOC_HI) {
532*7c478bd9Sstevel@tonic-gate 			IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK |
533*7c478bd9Sstevel@tonic-gate 			    IEEE1394_SCSR_CHANS_AVAIL_HI) |
534*7c478bd9Sstevel@tonic-gate 			    (((uint64_t)IRM_node) <<
535*7c478bd9Sstevel@tonic-gate 			    IEEE1394_ADDR_PHY_ID_SHIFT);
536*7c478bd9Sstevel@tonic-gate 		} else {
537*7c478bd9Sstevel@tonic-gate 			IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK |
538*7c478bd9Sstevel@tonic-gate 			    IEEE1394_SCSR_CHANS_AVAIL_LO) |
539*7c478bd9Sstevel@tonic-gate 			    (((uint64_t)IRM_node) <<
540*7c478bd9Sstevel@tonic-gate 			    IEEE1394_ADDR_PHY_ID_SHIFT);
541*7c478bd9Sstevel@tonic-gate 		}
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 		cmd->cmd_addr		   = IRM_ID_addr;
544*7c478bd9Sstevel@tonic-gate 		cmd->bus_generation	   = generation;
545*7c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.data_value  = T1394_DATA32(channel_mask);
546*7c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.num_retries = num_retries;
547*7c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.lock_type   = CMD1394_LOCK_BIT_OR;
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 		ret = s1394_split_lock_req(hal, NULL, cmd);
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 		if (ret == DDI_SUCCESS) {
552*7c478bd9Sstevel@tonic-gate 			if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 				*old_channels = T1394_DATA32(
555*7c478bd9Sstevel@tonic-gate 				    cmd->cmd_u.l32.old_value);
556*7c478bd9Sstevel@tonic-gate 				*result = cmd->cmd_result;
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 				/* Need to free the command */
559*7c478bd9Sstevel@tonic-gate 				(void) s1394_free_cmd(hal, &cmd);
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 				return (DDI_SUCCESS);
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 			} else {
564*7c478bd9Sstevel@tonic-gate 				*result = cmd->cmd_result;
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 				/* Need to free the command */
567*7c478bd9Sstevel@tonic-gate 				(void) s1394_free_cmd(hal, &cmd);
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
570*7c478bd9Sstevel@tonic-gate 			}
571*7c478bd9Sstevel@tonic-gate 		} else {
572*7c478bd9Sstevel@tonic-gate 			*result = cmd->cmd_result;
573*7c478bd9Sstevel@tonic-gate 			/* Need to free the command */
574*7c478bd9Sstevel@tonic-gate 			(void) s1394_free_cmd(hal, &cmd);
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
577*7c478bd9Sstevel@tonic-gate 		}
578*7c478bd9Sstevel@tonic-gate 	}
579*7c478bd9Sstevel@tonic-gate }
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate /*
582*7c478bd9Sstevel@tonic-gate  * s1394_bandwidth_alloc()
583*7c478bd9Sstevel@tonic-gate  *    is used to allocate isochronous bandwidth.  A number of bandwidth
584*7c478bd9Sstevel@tonic-gate  *    allocation units and a generation are passed.  The request is sent
585*7c478bd9Sstevel@tonic-gate  *    to whichever node is the IRM for this amount of bandwidth.  If it
586*7c478bd9Sstevel@tonic-gate  *    fails because of a bus reset it can be retried.  If it fails for
587*7c478bd9Sstevel@tonic-gate  *    another reason the bandwidth may not be available or there may be
588*7c478bd9Sstevel@tonic-gate  *    no IRM.
589*7c478bd9Sstevel@tonic-gate  */
590*7c478bd9Sstevel@tonic-gate int
s1394_bandwidth_alloc(s1394_hal_t * hal,uint32_t bw_alloc_units,uint_t generation,int * result)591*7c478bd9Sstevel@tonic-gate s1394_bandwidth_alloc(s1394_hal_t *hal, uint32_t bw_alloc_units,
592*7c478bd9Sstevel@tonic-gate     uint_t generation, int *result)
593*7c478bd9Sstevel@tonic-gate {
594*7c478bd9Sstevel@tonic-gate 	cmd1394_cmd_t	*cmd;
595*7c478bd9Sstevel@tonic-gate 	uint64_t	IRM_ID_addr;
596*7c478bd9Sstevel@tonic-gate 	uint32_t	compare;
597*7c478bd9Sstevel@tonic-gate 	uint32_t	swap;
598*7c478bd9Sstevel@tonic-gate 	uint32_t	old_value;
599*7c478bd9Sstevel@tonic-gate 	uint_t		hal_node_num;
600*7c478bd9Sstevel@tonic-gate 	uint_t		IRM_node;
601*7c478bd9Sstevel@tonic-gate 	int		temp_value;
602*7c478bd9Sstevel@tonic-gate 	int		ret;
603*7c478bd9Sstevel@tonic-gate 	int		i;
604*7c478bd9Sstevel@tonic-gate 	int		num_retries = S1394_ISOCH_ALLOC_RETRIES;
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 	/* Lock the topology tree */
607*7c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
610*7c478bd9Sstevel@tonic-gate 	IRM_node = hal->IRM_node;
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 	/* Unlock the topology tree */
613*7c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	/* Make sure there is a valid IRM on the bus */
616*7c478bd9Sstevel@tonic-gate 	if (IRM_node == -1) {
617*7c478bd9Sstevel@tonic-gate 		*result = CMD1394_ERETRIES_EXCEEDED;
618*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
619*7c478bd9Sstevel@tonic-gate 	}
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 	/* Send compare-swap to BANDWIDTH_AVAILABLE */
622*7c478bd9Sstevel@tonic-gate 	/* register on the Isoch Rsrc Mgr */
623*7c478bd9Sstevel@tonic-gate 	if (IRM_node == hal_node_num) {
624*7c478bd9Sstevel@tonic-gate 		/* Local */
625*7c478bd9Sstevel@tonic-gate 		i = num_retries;
626*7c478bd9Sstevel@tonic-gate 		do {
627*7c478bd9Sstevel@tonic-gate 			(void) HAL_CALL(hal).csr_read(hal->halinfo.hal_private,
628*7c478bd9Sstevel@tonic-gate 			    (IEEE1394_SCSR_BANDWIDTH_AVAIL &
629*7c478bd9Sstevel@tonic-gate 			    IEEE1394_CSR_OFFSET_MASK), &old_value);
630*7c478bd9Sstevel@tonic-gate 			/*
631*7c478bd9Sstevel@tonic-gate 			 * Check that the generation has not changed -
632*7c478bd9Sstevel@tonic-gate 			 * don't need the lock (read-only)
633*7c478bd9Sstevel@tonic-gate 			 */
634*7c478bd9Sstevel@tonic-gate 			if (generation != hal->generation_count) {
635*7c478bd9Sstevel@tonic-gate 				*result = CMD1394_EBUSRESET;
636*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
637*7c478bd9Sstevel@tonic-gate 			}
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 			temp_value = (old_value - bw_alloc_units);
640*7c478bd9Sstevel@tonic-gate 			if ((old_value >= bw_alloc_units) &&
641*7c478bd9Sstevel@tonic-gate 			    (temp_value >= IEEE1394_BANDWIDTH_MIN)) {
642*7c478bd9Sstevel@tonic-gate 				compare = old_value;
643*7c478bd9Sstevel@tonic-gate 				swap	= (uint32_t)temp_value;
644*7c478bd9Sstevel@tonic-gate 			} else {
645*7c478bd9Sstevel@tonic-gate 				*result = CMD1394_ERETRIES_EXCEEDED;
646*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
647*7c478bd9Sstevel@tonic-gate 			}
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 			ret = HAL_CALL(hal).csr_cswap32(
650*7c478bd9Sstevel@tonic-gate 			    hal->halinfo.hal_private, generation,
651*7c478bd9Sstevel@tonic-gate 			    (IEEE1394_SCSR_BANDWIDTH_AVAIL &
652*7c478bd9Sstevel@tonic-gate 			    IEEE1394_CSR_OFFSET_MASK), compare, swap,
653*7c478bd9Sstevel@tonic-gate 			    &old_value);
654*7c478bd9Sstevel@tonic-gate 			if (ret != DDI_SUCCESS) {
655*7c478bd9Sstevel@tonic-gate 				*result = CMD1394_EBUSRESET;
656*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
657*7c478bd9Sstevel@tonic-gate 			}
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 			if (old_value == compare) {
660*7c478bd9Sstevel@tonic-gate 				*result = CMD1394_CMDSUCCESS;
661*7c478bd9Sstevel@tonic-gate 				return (DDI_SUCCESS);
662*7c478bd9Sstevel@tonic-gate 			}
663*7c478bd9Sstevel@tonic-gate 		} while (i--);
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 		*result = CMD1394_ERETRIES_EXCEEDED;
666*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 	} else {
669*7c478bd9Sstevel@tonic-gate 		/* Remote */
670*7c478bd9Sstevel@tonic-gate 		if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) {
671*7c478bd9Sstevel@tonic-gate 			*result = CMD1394_EUNKNOWN_ERROR;
672*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
673*7c478bd9Sstevel@tonic-gate 		}
674*7c478bd9Sstevel@tonic-gate 
675*7c478bd9Sstevel@tonic-gate 		cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET |
676*7c478bd9Sstevel@tonic-gate 		    CMD1394_OVERRIDE_ADDR | CMD1394_BLOCKING);
677*7c478bd9Sstevel@tonic-gate 		cmd->cmd_type = CMD1394_ASYNCH_LOCK_32;
678*7c478bd9Sstevel@tonic-gate 		IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK |
679*7c478bd9Sstevel@tonic-gate 		    IEEE1394_SCSR_BANDWIDTH_AVAIL) | (((uint64_t)IRM_node) <<
680*7c478bd9Sstevel@tonic-gate 		    IEEE1394_ADDR_PHY_ID_SHIFT);
681*7c478bd9Sstevel@tonic-gate 		cmd->cmd_addr		   = IRM_ID_addr;
682*7c478bd9Sstevel@tonic-gate 		cmd->bus_generation	   = generation;
683*7c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.arg_value   = 0;
684*7c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.data_value  = bw_alloc_units;
685*7c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.num_retries = num_retries;
686*7c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.lock_type   = CMD1394_LOCK_THRESH_SUBTRACT;
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 		ret = s1394_split_lock_req(hal, NULL, cmd);
689*7c478bd9Sstevel@tonic-gate 
690*7c478bd9Sstevel@tonic-gate 		if (ret == DDI_SUCCESS) {
691*7c478bd9Sstevel@tonic-gate 			if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
692*7c478bd9Sstevel@tonic-gate 				*result = cmd->cmd_result;
693*7c478bd9Sstevel@tonic-gate 				/* Need to free the command */
694*7c478bd9Sstevel@tonic-gate 				(void) s1394_free_cmd(hal, &cmd);
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 				return (DDI_SUCCESS);
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 			} else {
699*7c478bd9Sstevel@tonic-gate 				*result = cmd->cmd_result;
700*7c478bd9Sstevel@tonic-gate 				/* Need to free the command */
701*7c478bd9Sstevel@tonic-gate 				(void) s1394_free_cmd(hal, &cmd);
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
704*7c478bd9Sstevel@tonic-gate 			}
705*7c478bd9Sstevel@tonic-gate 		} else {
706*7c478bd9Sstevel@tonic-gate 			*result = cmd->cmd_result;
707*7c478bd9Sstevel@tonic-gate 			/* Need to free the command */
708*7c478bd9Sstevel@tonic-gate 			(void) s1394_free_cmd(hal, &cmd);
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
711*7c478bd9Sstevel@tonic-gate 		}
712*7c478bd9Sstevel@tonic-gate 	}
713*7c478bd9Sstevel@tonic-gate }
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate /*
716*7c478bd9Sstevel@tonic-gate  * s1394_compute_bw_alloc_units()
717*7c478bd9Sstevel@tonic-gate  *    is used to compute the number of "bandwidth allocation units" that
718*7c478bd9Sstevel@tonic-gate  *    are necessary for a given bit rate.  It calculates the overhead
719*7c478bd9Sstevel@tonic-gate  *    necessary for isoch packet headers, bus arbitration, etc.  (See
720*7c478bd9Sstevel@tonic-gate  *    IEEE 1394-1995 Section 8.3.2.3.7 for an explanation of what a
721*7c478bd9Sstevel@tonic-gate  *    "bandwidth allocation unit" is.
722*7c478bd9Sstevel@tonic-gate  */
723*7c478bd9Sstevel@tonic-gate uint_t
s1394_compute_bw_alloc_units(s1394_hal_t * hal,uint_t bandwidth,uint_t speed)724*7c478bd9Sstevel@tonic-gate s1394_compute_bw_alloc_units(s1394_hal_t *hal, uint_t bandwidth, uint_t speed)
725*7c478bd9Sstevel@tonic-gate {
726*7c478bd9Sstevel@tonic-gate 	uint_t	total_quads;
727*7c478bd9Sstevel@tonic-gate 	uint_t	speed_factor;
728*7c478bd9Sstevel@tonic-gate 	uint_t	bau;
729*7c478bd9Sstevel@tonic-gate 	int	max_hops;
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate 	/* Lock the topology tree */
732*7c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 	/* Calculate the 1394 bus diameter */
735*7c478bd9Sstevel@tonic-gate 	max_hops = s1394_topology_tree_calculate_diameter(hal);
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate 	/* Unlock the topology tree */
738*7c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 	/* Calculate the total bandwidth (including overhead) */
741*7c478bd9Sstevel@tonic-gate 	total_quads = (bandwidth >> 2) + IEEE1394_ISOCH_HDR_QUAD_SZ;
742*7c478bd9Sstevel@tonic-gate 	switch (speed) {
743*7c478bd9Sstevel@tonic-gate 	case IEEE1394_S400:
744*7c478bd9Sstevel@tonic-gate 		speed_factor = ISOCH_SPEED_FACTOR_S400;
745*7c478bd9Sstevel@tonic-gate 		break;
746*7c478bd9Sstevel@tonic-gate 	case IEEE1394_S200:
747*7c478bd9Sstevel@tonic-gate 		speed_factor = ISOCH_SPEED_FACTOR_S200;
748*7c478bd9Sstevel@tonic-gate 		break;
749*7c478bd9Sstevel@tonic-gate 	case IEEE1394_S100:
750*7c478bd9Sstevel@tonic-gate 		speed_factor = ISOCH_SPEED_FACTOR_S100;
751*7c478bd9Sstevel@tonic-gate 		break;
752*7c478bd9Sstevel@tonic-gate 	}
753*7c478bd9Sstevel@tonic-gate 	/* See IEC 61883-1 pp. 26-29 for this formula */
754*7c478bd9Sstevel@tonic-gate 	bau = (32 * max_hops) + (total_quads * speed_factor);
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 	return (bau);
757*7c478bd9Sstevel@tonic-gate }
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate /*
760*7c478bd9Sstevel@tonic-gate  * s1394_bandwidth_free()
761*7c478bd9Sstevel@tonic-gate  *    is used to free up isochronous bandwidth.  A number of bandwidth
762*7c478bd9Sstevel@tonic-gate  *    allocation units and a generation are passed. The request is sent
763*7c478bd9Sstevel@tonic-gate  *    to whichever node is the IRM for this amount of bandwidth.  If it
764*7c478bd9Sstevel@tonic-gate  *    fails because of a bus reset it can be retried. If it fails for
765*7c478bd9Sstevel@tonic-gate  *    another reason the bandwidth may already be freed or there may
766*7c478bd9Sstevel@tonic-gate  *    be no IRM.
767*7c478bd9Sstevel@tonic-gate  */
768*7c478bd9Sstevel@tonic-gate int
s1394_bandwidth_free(s1394_hal_t * hal,uint32_t bw_alloc_units,uint_t generation,int * result)769*7c478bd9Sstevel@tonic-gate s1394_bandwidth_free(s1394_hal_t *hal, uint32_t bw_alloc_units,
770*7c478bd9Sstevel@tonic-gate     uint_t generation, int *result)
771*7c478bd9Sstevel@tonic-gate {
772*7c478bd9Sstevel@tonic-gate 	cmd1394_cmd_t	*cmd;
773*7c478bd9Sstevel@tonic-gate 	uint64_t	IRM_ID_addr;
774*7c478bd9Sstevel@tonic-gate 	uint32_t	compare;
775*7c478bd9Sstevel@tonic-gate 	uint32_t	swap;
776*7c478bd9Sstevel@tonic-gate 	uint32_t	old_value;
777*7c478bd9Sstevel@tonic-gate 	uint32_t	temp_value;
778*7c478bd9Sstevel@tonic-gate 	uint_t		hal_node_num;
779*7c478bd9Sstevel@tonic-gate 	uint_t		IRM_node;
780*7c478bd9Sstevel@tonic-gate 	int		ret;
781*7c478bd9Sstevel@tonic-gate 	int		i;
782*7c478bd9Sstevel@tonic-gate 	int		num_retries = S1394_ISOCH_ALLOC_RETRIES;
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 	/* Lock the topology tree */
785*7c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
788*7c478bd9Sstevel@tonic-gate 	IRM_node = hal->IRM_node;
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 	/* Unlock the topology tree */
791*7c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
792*7c478bd9Sstevel@tonic-gate 
793*7c478bd9Sstevel@tonic-gate 	/* Make sure there is a valid IRM on the bus */
794*7c478bd9Sstevel@tonic-gate 	if (IRM_node == -1) {
795*7c478bd9Sstevel@tonic-gate 		*result = CMD1394_ERETRIES_EXCEEDED;
796*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
797*7c478bd9Sstevel@tonic-gate 	}
798*7c478bd9Sstevel@tonic-gate 
799*7c478bd9Sstevel@tonic-gate 	/* Send compare-swap to BANDWIDTH_AVAILABLE */
800*7c478bd9Sstevel@tonic-gate 	/* register on the Isoch Rsrc Mgr */
801*7c478bd9Sstevel@tonic-gate 	if (IRM_node == hal_node_num) {
802*7c478bd9Sstevel@tonic-gate 		i = num_retries;
803*7c478bd9Sstevel@tonic-gate 		do {
804*7c478bd9Sstevel@tonic-gate 			(void) HAL_CALL(hal).csr_read(hal->halinfo.hal_private,
805*7c478bd9Sstevel@tonic-gate 			    (IEEE1394_SCSR_BANDWIDTH_AVAIL &
806*7c478bd9Sstevel@tonic-gate 			    IEEE1394_CSR_OFFSET_MASK), &old_value);
807*7c478bd9Sstevel@tonic-gate 
808*7c478bd9Sstevel@tonic-gate 			/* Check that the generation has not changed */
809*7c478bd9Sstevel@tonic-gate 			if (generation != hal->generation_count) {
810*7c478bd9Sstevel@tonic-gate 				*result = CMD1394_EBUSRESET;
811*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
812*7c478bd9Sstevel@tonic-gate 			}
813*7c478bd9Sstevel@tonic-gate 
814*7c478bd9Sstevel@tonic-gate 			temp_value = (old_value + bw_alloc_units);
815*7c478bd9Sstevel@tonic-gate 			if ((temp_value >= old_value) &&
816*7c478bd9Sstevel@tonic-gate 			    (temp_value <= IEEE1394_BANDWIDTH_MAX)) {
817*7c478bd9Sstevel@tonic-gate 				compare = old_value;
818*7c478bd9Sstevel@tonic-gate 				swap	= temp_value;
819*7c478bd9Sstevel@tonic-gate 			} else {
820*7c478bd9Sstevel@tonic-gate 				*result = CMD1394_ERETRIES_EXCEEDED;
821*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
822*7c478bd9Sstevel@tonic-gate 			}
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 			ret = HAL_CALL(hal).csr_cswap32(
825*7c478bd9Sstevel@tonic-gate 			    hal->halinfo.hal_private, generation,
826*7c478bd9Sstevel@tonic-gate 			    (IEEE1394_SCSR_BANDWIDTH_AVAIL &
827*7c478bd9Sstevel@tonic-gate 			    IEEE1394_CSR_OFFSET_MASK), compare, swap,
828*7c478bd9Sstevel@tonic-gate 			    &old_value);
829*7c478bd9Sstevel@tonic-gate 			if (ret != DDI_SUCCESS) {
830*7c478bd9Sstevel@tonic-gate 				*result = CMD1394_EBUSRESET;
831*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
832*7c478bd9Sstevel@tonic-gate 			}
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 			if (old_value == compare) {
835*7c478bd9Sstevel@tonic-gate 				*result = CMD1394_CMDSUCCESS;
836*7c478bd9Sstevel@tonic-gate 				return (DDI_SUCCESS);
837*7c478bd9Sstevel@tonic-gate 			}
838*7c478bd9Sstevel@tonic-gate 		} while (i--);
839*7c478bd9Sstevel@tonic-gate 
840*7c478bd9Sstevel@tonic-gate 		*result = CMD1394_ERETRIES_EXCEEDED;
841*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 	} else {
844*7c478bd9Sstevel@tonic-gate 		/* Remote */
845*7c478bd9Sstevel@tonic-gate 		if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) {
846*7c478bd9Sstevel@tonic-gate 			*result = CMD1394_EUNKNOWN_ERROR;
847*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
848*7c478bd9Sstevel@tonic-gate 		}
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 		cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET |
851*7c478bd9Sstevel@tonic-gate 		    CMD1394_OVERRIDE_ADDR | CMD1394_BLOCKING);
852*7c478bd9Sstevel@tonic-gate 		cmd->cmd_type = CMD1394_ASYNCH_LOCK_32;
853*7c478bd9Sstevel@tonic-gate 		IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK |
854*7c478bd9Sstevel@tonic-gate 		    IEEE1394_SCSR_BANDWIDTH_AVAIL) |
855*7c478bd9Sstevel@tonic-gate 		    (((uint64_t)hal->IRM_node) << IEEE1394_ADDR_PHY_ID_SHIFT);
856*7c478bd9Sstevel@tonic-gate 		cmd->cmd_addr		   = IRM_ID_addr;
857*7c478bd9Sstevel@tonic-gate 		cmd->bus_generation	   = generation;
858*7c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.arg_value   = IEEE1394_BANDWIDTH_MAX;
859*7c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.data_value  = bw_alloc_units;
860*7c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.num_retries = num_retries;
861*7c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.lock_type   = CMD1394_LOCK_THRESH_ADD;
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 		ret = s1394_split_lock_req(hal, NULL, cmd);
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate 		if (ret == DDI_SUCCESS) {
866*7c478bd9Sstevel@tonic-gate 			if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
867*7c478bd9Sstevel@tonic-gate 				*result = cmd->cmd_result;
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate 				/* Need to free the command */
870*7c478bd9Sstevel@tonic-gate 				(void) s1394_free_cmd(hal, &cmd);
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate 				return (DDI_SUCCESS);
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate 			} else {
875*7c478bd9Sstevel@tonic-gate 				*result = cmd->cmd_result;
876*7c478bd9Sstevel@tonic-gate 				/* Need to free the command */
877*7c478bd9Sstevel@tonic-gate 				(void) s1394_free_cmd(hal, &cmd);
878*7c478bd9Sstevel@tonic-gate 
879*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
880*7c478bd9Sstevel@tonic-gate 			}
881*7c478bd9Sstevel@tonic-gate 		} else {
882*7c478bd9Sstevel@tonic-gate 			*result = cmd->cmd_result;
883*7c478bd9Sstevel@tonic-gate 			/* Need to free the command */
884*7c478bd9Sstevel@tonic-gate 			(void) s1394_free_cmd(hal, &cmd);
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
887*7c478bd9Sstevel@tonic-gate 		}
888*7c478bd9Sstevel@tonic-gate 	}
889*7c478bd9Sstevel@tonic-gate }
890*7c478bd9Sstevel@tonic-gate 
891*7c478bd9Sstevel@tonic-gate /*
892*7c478bd9Sstevel@tonic-gate  * s1394_isoch_cec_list_insert()
893*7c478bd9Sstevel@tonic-gate  *    is used to insert an Isoch CEC into a given HAL's list of Isoch CECs.
894*7c478bd9Sstevel@tonic-gate  */
895*7c478bd9Sstevel@tonic-gate void
s1394_isoch_cec_list_insert(s1394_hal_t * hal,s1394_isoch_cec_t * cec)896*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_list_insert(s1394_hal_t *hal, s1394_isoch_cec_t *cec)
897*7c478bd9Sstevel@tonic-gate {
898*7c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_t *cec_temp;
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->isoch_cec_list_mutex));
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 	/* Is the Isoch CEC list empty? */
903*7c478bd9Sstevel@tonic-gate 	if ((hal->isoch_cec_list_head == NULL) &&
904*7c478bd9Sstevel@tonic-gate 	    (hal->isoch_cec_list_tail == NULL)) {
905*7c478bd9Sstevel@tonic-gate 
906*7c478bd9Sstevel@tonic-gate 		hal->isoch_cec_list_head = cec;
907*7c478bd9Sstevel@tonic-gate 		hal->isoch_cec_list_tail = cec;
908*7c478bd9Sstevel@tonic-gate 
909*7c478bd9Sstevel@tonic-gate 		cec->cec_next = NULL;
910*7c478bd9Sstevel@tonic-gate 		cec->cec_prev = NULL;
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate 	} else {
913*7c478bd9Sstevel@tonic-gate 		cec->cec_next = hal->isoch_cec_list_head;
914*7c478bd9Sstevel@tonic-gate 		cec->cec_prev = NULL;
915*7c478bd9Sstevel@tonic-gate 		cec_temp = hal->isoch_cec_list_head;
916*7c478bd9Sstevel@tonic-gate 		cec_temp->cec_prev = cec;
917*7c478bd9Sstevel@tonic-gate 
918*7c478bd9Sstevel@tonic-gate 		hal->isoch_cec_list_head = cec;
919*7c478bd9Sstevel@tonic-gate 	}
920*7c478bd9Sstevel@tonic-gate }
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate /*
923*7c478bd9Sstevel@tonic-gate  * s1394_isoch_cec_list_remove()
924*7c478bd9Sstevel@tonic-gate  *    is used to remove an Isoch CEC from a given HAL's list of Isoch CECs.
925*7c478bd9Sstevel@tonic-gate  */
926*7c478bd9Sstevel@tonic-gate void
s1394_isoch_cec_list_remove(s1394_hal_t * hal,s1394_isoch_cec_t * cec)927*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_list_remove(s1394_hal_t *hal, s1394_isoch_cec_t *cec)
928*7c478bd9Sstevel@tonic-gate {
929*7c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_t *prev_cec;
930*7c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_t *next_cec;
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->isoch_cec_list_mutex));
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 	prev_cec = cec->cec_prev;
935*7c478bd9Sstevel@tonic-gate 	next_cec = cec->cec_next;
936*7c478bd9Sstevel@tonic-gate 	cec->cec_prev = NULL;
937*7c478bd9Sstevel@tonic-gate 	cec->cec_next = NULL;
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 	if (prev_cec != NULL) {
940*7c478bd9Sstevel@tonic-gate 		prev_cec->cec_next = next_cec;
941*7c478bd9Sstevel@tonic-gate 
942*7c478bd9Sstevel@tonic-gate 	} else {
943*7c478bd9Sstevel@tonic-gate 		if (hal->isoch_cec_list_head == cec)
944*7c478bd9Sstevel@tonic-gate 			hal->isoch_cec_list_head = next_cec;
945*7c478bd9Sstevel@tonic-gate 	}
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 	if (next_cec != NULL) {
948*7c478bd9Sstevel@tonic-gate 		next_cec->cec_prev = prev_cec;
949*7c478bd9Sstevel@tonic-gate 
950*7c478bd9Sstevel@tonic-gate 	} else {
951*7c478bd9Sstevel@tonic-gate 		if (hal->isoch_cec_list_tail == cec)
952*7c478bd9Sstevel@tonic-gate 			hal->isoch_cec_list_tail = prev_cec;
953*7c478bd9Sstevel@tonic-gate 	}
954*7c478bd9Sstevel@tonic-gate }
955*7c478bd9Sstevel@tonic-gate 
956*7c478bd9Sstevel@tonic-gate /*
957*7c478bd9Sstevel@tonic-gate  * s1394_isoch_cec_member_list_insert()
958*7c478bd9Sstevel@tonic-gate  *    is used to insert a new member (target) into the list of members for
959*7c478bd9Sstevel@tonic-gate  *    a given Isoch CEC.
960*7c478bd9Sstevel@tonic-gate  */
961*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
962*7c478bd9Sstevel@tonic-gate void
s1394_isoch_cec_member_list_insert(s1394_hal_t * hal,s1394_isoch_cec_t * cec,s1394_isoch_cec_member_t * member)963*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_member_list_insert(s1394_hal_t *hal, s1394_isoch_cec_t *cec,
964*7c478bd9Sstevel@tonic-gate     s1394_isoch_cec_member_t *member)
965*7c478bd9Sstevel@tonic-gate {
966*7c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_member_t *member_temp;
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cec->isoch_cec_mutex));
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 	/* Is the Isoch CEC member list empty? */
971*7c478bd9Sstevel@tonic-gate 	if ((cec->cec_member_list_head == NULL) &&
972*7c478bd9Sstevel@tonic-gate 	    (cec->cec_member_list_tail == NULL)) {
973*7c478bd9Sstevel@tonic-gate 
974*7c478bd9Sstevel@tonic-gate 		cec->cec_member_list_head = member;
975*7c478bd9Sstevel@tonic-gate 		cec->cec_member_list_tail = member;
976*7c478bd9Sstevel@tonic-gate 		member->cec_mem_next = NULL;
977*7c478bd9Sstevel@tonic-gate 		member->cec_mem_prev = NULL;
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 	} else if (member->cec_mem_options & T1394_TALKER) {
980*7c478bd9Sstevel@tonic-gate 		/* Put talker at the head of the list */
981*7c478bd9Sstevel@tonic-gate 		member->cec_mem_next = cec->cec_member_list_head;
982*7c478bd9Sstevel@tonic-gate 		member->cec_mem_prev = NULL;
983*7c478bd9Sstevel@tonic-gate 		member_temp = cec->cec_member_list_head;
984*7c478bd9Sstevel@tonic-gate 		member_temp->cec_mem_prev = member;
985*7c478bd9Sstevel@tonic-gate 		cec->cec_member_list_head = member;
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate 	} else {
988*7c478bd9Sstevel@tonic-gate 		/* Put listeners at the tail of the list */
989*7c478bd9Sstevel@tonic-gate 		member->cec_mem_prev = cec->cec_member_list_tail;
990*7c478bd9Sstevel@tonic-gate 		member->cec_mem_next = NULL;
991*7c478bd9Sstevel@tonic-gate 		member_temp = cec->cec_member_list_tail;
992*7c478bd9Sstevel@tonic-gate 		member_temp->cec_mem_next = member;
993*7c478bd9Sstevel@tonic-gate 		cec->cec_member_list_tail = member;
994*7c478bd9Sstevel@tonic-gate 	}
995*7c478bd9Sstevel@tonic-gate }
996*7c478bd9Sstevel@tonic-gate 
997*7c478bd9Sstevel@tonic-gate /*
998*7c478bd9Sstevel@tonic-gate  * s1394_isoch_cec_member_list_remove()
999*7c478bd9Sstevel@tonic-gate  *    is used to remove a member (target) from the list of members for
1000*7c478bd9Sstevel@tonic-gate  *    a given Isoch CEC.
1001*7c478bd9Sstevel@tonic-gate  */
1002*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1003*7c478bd9Sstevel@tonic-gate void
s1394_isoch_cec_member_list_remove(s1394_hal_t * hal,s1394_isoch_cec_t * cec,s1394_isoch_cec_member_t * member)1004*7c478bd9Sstevel@tonic-gate s1394_isoch_cec_member_list_remove(s1394_hal_t *hal, s1394_isoch_cec_t *cec,
1005*7c478bd9Sstevel@tonic-gate     s1394_isoch_cec_member_t *member)
1006*7c478bd9Sstevel@tonic-gate {
1007*7c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_member_t *prev_member;
1008*7c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_member_t *next_member;
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cec->isoch_cec_mutex));
1011*7c478bd9Sstevel@tonic-gate 
1012*7c478bd9Sstevel@tonic-gate 	prev_member = member->cec_mem_prev;
1013*7c478bd9Sstevel@tonic-gate 	next_member = member->cec_mem_next;
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 	member->cec_mem_prev = NULL;
1016*7c478bd9Sstevel@tonic-gate 	member->cec_mem_next = NULL;
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate 	if (prev_member != NULL) {
1019*7c478bd9Sstevel@tonic-gate 		prev_member->cec_mem_next = next_member;
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 	} else {
1022*7c478bd9Sstevel@tonic-gate 		if (cec->cec_member_list_head == member)
1023*7c478bd9Sstevel@tonic-gate 			cec->cec_member_list_head = next_member;
1024*7c478bd9Sstevel@tonic-gate 	}
1025*7c478bd9Sstevel@tonic-gate 
1026*7c478bd9Sstevel@tonic-gate 	if (next_member != NULL) {
1027*7c478bd9Sstevel@tonic-gate 		next_member->cec_mem_prev = prev_member;
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 	} else {
1030*7c478bd9Sstevel@tonic-gate 		if (cec->cec_member_list_tail == member)
1031*7c478bd9Sstevel@tonic-gate 			cec->cec_member_list_tail = prev_member;
1032*7c478bd9Sstevel@tonic-gate 	}
1033*7c478bd9Sstevel@tonic-gate }
1034