xref: /titanic_50/usr/src/uts/common/io/1394/s1394_isoch.c (revision 3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1999-2000 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #pragma	ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * s1394_isoch.c
31  *    1394 Services Layer Isochronous Communication Routines
32  *    This file contains routines for managing isochronous bandwidth
33  *    and channel needs for registered targets (through the target
34  *    isoch interfaces).
35  */
36 
37 #include <sys/conf.h>
38 #include <sys/ddi.h>
39 #include <sys/sunddi.h>
40 #include <sys/types.h>
41 #include <sys/tnf_probe.h>
42 
43 #include <sys/1394/t1394.h>
44 #include <sys/1394/s1394.h>
45 #include <sys/1394/h1394.h>
46 #include <sys/1394/ieee1394.h>
47 
48 /*
49  * s1394_isoch_rsrc_realloc()
50  *    is called during bus reset processing to reallocate any isochronous
51  *    resources that were previously allocated.
52  */
53 void
54 s1394_isoch_rsrc_realloc(s1394_hal_t *hal)
55 {
56 	s1394_isoch_cec_t *cec_curr;
57 	uint32_t	  chnl_mask;
58 	uint32_t	  old_chnl_mask;
59 	uint_t		  bw_alloc_units;
60 	uint_t		  generation;
61 	uint_t		  chnl_num;
62 	int		  err;
63 	int		  ret;
64 
65 	TNF_PROBE_0_DEBUG(s1394_isoch_rsrc_realloc_enter,
66 	    S1394_TNF_SL_ISOCH_STACK, "");
67 
68 	/*
69 	 * Get the current generation number - don't need the
70 	 * topology tree mutex here because it is read-only, and
71 	 * there is a race condition with or without it.
72 	 */
73 	generation = hal->generation_count;
74 
75 	/* Lock the Isoch CEC list */
76 	mutex_enter(&hal->isoch_cec_list_mutex);
77 
78 	cec_curr = hal->isoch_cec_list_head;
79 	while (cec_curr != NULL) {
80 		/* Lock the Isoch CEC member list */
81 		mutex_enter(&cec_curr->isoch_cec_mutex);
82 
83 		/* Are we supposed to reallocate resources? */
84 		if (!(cec_curr->cec_options & T1394_NO_IRM_ALLOC) &&
85 		    (cec_curr->realloc_valid == B_TRUE) &&
86 		    (cec_curr->realloc_failed == B_FALSE)) {
87 
88 			/* Reallocate some bandwidth */
89 			bw_alloc_units = s1394_compute_bw_alloc_units(hal,
90 			    cec_curr->bandwidth, cec_curr->realloc_speed);
91 
92 			/* Check that the generation has not changed */
93 			if (generation != hal->generation_count) {
94 				/* Try the next Isoch CEC */
95 				goto next_isoch_cec;
96 			}
97 
98 			/* Unlock the Isoch CEC member list */
99 			mutex_exit(&cec_curr->isoch_cec_mutex);
100 			/*
101 			 * We can unlock the Isoch CEC list here
102 			 * because we know this Isoch CEC can not
103 			 * go away (we are trying to realloc its
104 			 * resources so it can't be in a state that
105 			 * will allow a free).
106 			 */
107 			mutex_exit(&hal->isoch_cec_list_mutex);
108 
109 			/* Try to reallocate bandwidth */
110 			ret = s1394_bandwidth_alloc(hal, bw_alloc_units,
111 			    generation, &err);
112 
113 			/* Lock the Isoch CEC list */
114 			mutex_enter(&hal->isoch_cec_list_mutex);
115 			/* Lock the Isoch CEC member list */
116 			mutex_enter(&cec_curr->isoch_cec_mutex);
117 
118 			/* If we failed because we couldn't get bandwidth */
119 			if (ret == DDI_FAILURE) {
120 				cec_curr->realloc_failed = B_TRUE;
121 				cec_curr->realloc_fail_reason =
122 				    T1394_RSRC_BANDWIDTH;
123 			}
124 		}
125 
126 		/* Are we supposed to reallocate resources? */
127 		if (!(cec_curr->cec_options & T1394_NO_IRM_ALLOC) &&
128 		    (cec_curr->realloc_valid == B_TRUE) &&
129 		    (cec_curr->realloc_failed == B_FALSE)) {
130 
131 			/* Reallocate the channel */
132 			chnl_num  = cec_curr->realloc_chnl_num;
133 			chnl_mask = (1 << ((63 - chnl_num) % 32));
134 
135 			/* Unlock the Isoch CEC member list */
136 			mutex_exit(&cec_curr->isoch_cec_mutex);
137 			/*
138 			 * We can unlock the Isoch CEC list here
139 			 * because we know this Isoch CEC can not
140 			 * go away (we are trying to realloc its
141 			 * resources so it can't be in a state that
142 			 * will allow a free).
143 			 */
144 			mutex_exit(&hal->isoch_cec_list_mutex);
145 
146 			if (chnl_num < 32) {
147 				ret = s1394_channel_alloc(hal, chnl_mask,
148 				    generation, S1394_CHANNEL_ALLOC_HI,
149 				    &old_chnl_mask, &err);
150 			} else {
151 				ret = s1394_channel_alloc(hal, chnl_mask,
152 				    generation, S1394_CHANNEL_ALLOC_LO,
153 				    &old_chnl_mask, &err);
154 			}
155 
156 			/* Lock the Isoch CEC list */
157 			mutex_enter(&hal->isoch_cec_list_mutex);
158 			/* Lock the Isoch CEC member list */
159 			mutex_enter(&cec_curr->isoch_cec_mutex);
160 
161 			if (ret == DDI_FAILURE) {
162 				if (err != CMD1394_EBUSRESET) {
163 					/*
164 					 * If we successfully reallocate
165 					 * bandwidth, and then fail getting
166 					 * the channel, we need to free up
167 					 * the bandwidth
168 					 */
169 
170 					/* Try to free up the bandwidth */
171 					ret = s1394_bandwidth_free(hal,
172 					    bw_alloc_units, generation, &err);
173 					if ((ret == DDI_FAILURE) &&
174 					    (err != CMD1394_EBUSRESET)) {
175 						TNF_PROBE_1(
176 						s1394_isoch_rsrc_realloc_error,
177 						    S1394_TNF_SL_ISOCH_ERROR,
178 						    "", tnf_string, msg,
179 						    "Unable to free bandwidth");
180 					}
181 					/* Try the next Isoch CEC */
182 					goto next_isoch_cec;
183 				}
184 				cec_curr->realloc_failed = B_TRUE;
185 				cec_curr->realloc_fail_reason =
186 				    T1394_RSRC_CHANNEL;
187 			}
188 		}
189 next_isoch_cec:
190 		/* Unlock the Isoch CEC member list */
191 		mutex_exit(&cec_curr->isoch_cec_mutex);
192 		cec_curr = cec_curr->cec_next;
193 	}
194 
195 	/* Unlock the Isoch CEC list */
196 	mutex_exit(&hal->isoch_cec_list_mutex);
197 	TNF_PROBE_0_DEBUG(s1394_isoch_rsrc_realloc_exit,
198 	    S1394_TNF_SL_ISOCH_STACK, "");
199 }
200 
201 /*
202  * s1394_isoch_rsrc_realloc_notify()
203  *    is called during bus reset processing to notify all targets for
204  *    which isochronous resources were not able to be reallocated.
205  */
206 void
207 s1394_isoch_rsrc_realloc_notify(s1394_hal_t *hal)
208 {
209 	s1394_isoch_cec_t	 *cec_curr;
210 	s1394_isoch_cec_member_t *member_curr;
211 	t1394_isoch_rsrc_error_t fail_arg;
212 	opaque_t		 evts_arg;
213 	s1394_isoch_cec_type_t	 type;
214 	void (*rsrc_fail_callback)(t1394_isoch_cec_handle_t, opaque_t,
215 				t1394_isoch_rsrc_error_t);
216 
217 	TNF_PROBE_0_DEBUG(s1394_isoch_rsrc_realloc_notify_enter,
218 	    S1394_TNF_SL_ISOCH_STACK, "");
219 
220 	/* Lock the Isoch CEC list */
221 	mutex_enter(&hal->isoch_cec_list_mutex);
222 
223 	/* Notify all targets that failed realloc */
224 	cec_curr = hal->isoch_cec_list_head;
225 	while (cec_curr != NULL) {
226 		/* Lock the Isoch CEC member list */
227 		mutex_enter(&cec_curr->isoch_cec_mutex);
228 
229 		/* Do we notify of realloc failure? */
230 		if (!(cec_curr->cec_options & T1394_NO_IRM_ALLOC) &&
231 		    (cec_curr->realloc_valid == B_TRUE) &&
232 		    (cec_curr->realloc_failed == B_TRUE)) {
233 
234 			/* Reason for realloc failure */
235 			fail_arg = cec_curr->realloc_fail_reason;
236 
237 			/* Now we are going into the callbacks */
238 			cec_curr->in_fail_callbacks = B_TRUE;
239 
240 			type = cec_curr->cec_type;
241 
242 			/* Unlock the Isoch CEC member list */
243 			mutex_exit(&cec_curr->isoch_cec_mutex);
244 			/*
245 			 * We can unlock the Isoch CEC list here
246 			 * because we have the in_fail_callbacks
247 			 * field set to B_TRUE.  And free will fail
248 			 * if we are in fail callbacks.
249 			 */
250 			mutex_exit(&hal->isoch_cec_list_mutex);
251 
252 			/* Call all of the rsrc_fail_target() callbacks */
253 			/* Start at the head (talker first) and */
254 			/* go toward the tail (listeners last) */
255 			member_curr = cec_curr->cec_member_list_head;
256 			while (member_curr != NULL) {
257 				rsrc_fail_callback = member_curr->
258 				    isoch_cec_evts.rsrc_fail_target;
259 				evts_arg = member_curr->isoch_cec_evts_arg;
260 				if (rsrc_fail_callback != NULL) {
261 
262 					if (type == S1394_PEER_TO_PEER) {
263 						rsrc_fail_callback(
264 						    (t1394_isoch_cec_handle_t)
265 						    cec_curr, evts_arg,
266 						    fail_arg);
267 					} else {
268 						rsrc_fail_callback(
269 						    (t1394_isoch_cec_handle_t)
270 						    cec_curr, evts_arg,
271 						    fail_arg);
272 					}
273 				}
274 				member_curr = member_curr->cec_mem_next;
275 			}
276 
277 			/* Lock the Isoch CEC list */
278 			mutex_enter(&hal->isoch_cec_list_mutex);
279 			/* Lock the Isoch CEC member list */
280 			mutex_enter(&cec_curr->isoch_cec_mutex);
281 
282 			/* We are finished with the callbacks */
283 			cec_curr->in_fail_callbacks = B_FALSE;
284 			if (cec_curr->cec_want_wakeup == B_TRUE) {
285 				cec_curr->cec_want_wakeup = B_FALSE;
286 				cv_broadcast(&cec_curr->in_callbacks_cv);
287 			}
288 
289 			/* Set flags back to original state */
290 			cec_curr->realloc_valid	 = B_FALSE;
291 			cec_curr->realloc_failed = B_FALSE;
292 		}
293 		/* Unlock the Isoch CEC member list */
294 		mutex_exit(&cec_curr->isoch_cec_mutex);
295 		cec_curr = cec_curr->cec_next;
296 	}
297 
298 	/* Unlock the Isoch CEC list */
299 	mutex_exit(&hal->isoch_cec_list_mutex);
300 	TNF_PROBE_0_DEBUG(s1394_isoch_rsrc_realloc_notify_exit,
301 	    S1394_TNF_SL_ISOCH_STACK, "");
302 }
303 
304 /*
305  * s1394_channel_alloc()
306  *    is used to allocate an isochronous channel.  A channel mask and
307  *    generation are passed.  A request is sent to whichever node is the
308  *    IRM for the appropriate channels.  If it fails because of a bus
309  *    reset it can be retried.  If it fails for another reason the
310  *    channel(s) may not be availble or there may be no IRM.
311  */
312 int
313 s1394_channel_alloc(s1394_hal_t *hal, uint32_t channel_mask, uint_t generation,
314     uint_t flags, uint32_t *old_channels, int *result)
315 {
316 	cmd1394_cmd_t	*cmd;
317 	uint64_t	IRM_ID_addr;
318 	uint32_t	compare;
319 	uint32_t	swap;
320 	uint32_t	old_value;
321 	uint_t		hal_node_num;
322 	uint_t		IRM_node;
323 	uint_t		offset;
324 	int		ret;
325 	int		i;
326 	int		num_retries = S1394_ISOCH_ALLOC_RETRIES;
327 
328 	TNF_PROBE_0_DEBUG(s1394_channel_alloc_enter,
329 	    S1394_TNF_SL_ISOCH_STACK, "");
330 
331 	/* Lock the topology tree */
332 	mutex_enter(&hal->topology_tree_mutex);
333 
334 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
335 	IRM_node = hal->IRM_node;
336 
337 	/* Unlock the topology tree */
338 	mutex_exit(&hal->topology_tree_mutex);
339 
340 	/* Make sure there is a valid IRM on the bus */
341 	if (IRM_node == -1) {
342 		*result = CMD1394_ERETRIES_EXCEEDED;
343 		TNF_PROBE_1(s1394_channel_alloc_error,
344 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
345 		    "No IRM on the 1394 bus");
346 		TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit,
347 		    S1394_TNF_SL_ISOCH_STACK, "");
348 		return (DDI_FAILURE);
349 	}
350 
351 	if (flags & S1394_CHANNEL_ALLOC_HI) {
352 		offset =
353 		    (IEEE1394_SCSR_CHANS_AVAIL_HI & IEEE1394_CSR_OFFSET_MASK);
354 	} else {
355 		offset =
356 		    (IEEE1394_SCSR_CHANS_AVAIL_LO & IEEE1394_CSR_OFFSET_MASK);
357 	}
358 
359 	/* Send compare-swap to CHANNELS_AVAILABLE */
360 	/* register on the Isoch Rsrc Mgr */
361 	if (IRM_node == hal_node_num) {
362 		/* Local */
363 		i = num_retries;
364 		do {
365 			(void) HAL_CALL(hal).csr_read(hal->halinfo.hal_private,
366 			    offset, &old_value);
367 
368 			/* Check that the generation has not changed */
369 			if (generation != hal->generation_count) {
370 				*result = CMD1394_EBUSRESET;
371 				TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit,
372 				    S1394_TNF_SL_ISOCH_STACK, "");
373 				return (DDI_FAILURE);
374 			}
375 
376 			compare = old_value;
377 			swap	= old_value & (~channel_mask);
378 
379 			ret = HAL_CALL(hal).csr_cswap32(
380 			    hal->halinfo.hal_private, generation,
381 			    offset, compare, swap, &old_value);
382 			if (ret != DDI_SUCCESS) {
383 				*result = CMD1394_EBUSRESET;
384 				TNF_PROBE_1(s1394_channel_alloc_error,
385 				    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string,
386 				    msg, "Error in cswap32");
387 				TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit,
388 				    "stacktrace 1394 s1394", "");
389 				return (DDI_FAILURE);
390 			}
391 
392 			if ((~old_value & channel_mask) != 0) {
393 				*result = CMD1394_ERETRIES_EXCEEDED;
394 				TNF_PROBE_1(s1394_channel_alloc_error,
395 				    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string,
396 				    msg, "Channels already taken");
397 				TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit,
398 				    S1394_TNF_SL_ISOCH_STACK, "");
399 				return (DDI_FAILURE);
400 			}
401 
402 			if (old_value == compare) {
403 				*result = CMD1394_CMDSUCCESS;
404 				*old_channels = old_value;
405 
406 				TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit,
407 				    S1394_TNF_SL_ISOCH_STACK, "");
408 				return (DDI_SUCCESS);
409 			}
410 		} while (i--);
411 
412 		*result = CMD1394_ERETRIES_EXCEEDED;
413 		TNF_PROBE_1(s1394_channel_alloc_error,
414 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
415 		    "Retries exceeded");
416 		TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit,
417 		    S1394_TNF_SL_ISOCH_STACK, "");
418 		return (DDI_FAILURE);
419 
420 	} else {
421 		/* Remote */
422 		if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) {
423 			*result = CMD1394_EUNKNOWN_ERROR;
424 			TNF_PROBE_1(s1394_channel_alloc_error,
425 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
426 			    "Unable to allocate command");
427 			TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit,
428 			    S1394_TNF_SL_ISOCH_STACK, "");
429 			return (DDI_FAILURE);
430 		}
431 
432 		cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET |
433 		    CMD1394_OVERRIDE_ADDR | CMD1394_BLOCKING);
434 		cmd->cmd_type = CMD1394_ASYNCH_LOCK_32;
435 
436 		if (flags & S1394_CHANNEL_ALLOC_HI) {
437 			IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK |
438 			    IEEE1394_SCSR_CHANS_AVAIL_HI) |
439 			    (((uint64_t)IRM_node) <<
440 			    IEEE1394_ADDR_PHY_ID_SHIFT);
441 		} else {
442 			IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK |
443 			    IEEE1394_SCSR_CHANS_AVAIL_LO) |
444 			    (((uint64_t)IRM_node) <<
445 			    IEEE1394_ADDR_PHY_ID_SHIFT);
446 		}
447 
448 		cmd->cmd_addr		   = IRM_ID_addr;
449 		cmd->bus_generation	   = generation;
450 		cmd->cmd_u.l32.data_value  = T1394_DATA32(~channel_mask);
451 		cmd->cmd_u.l32.num_retries = num_retries;
452 		cmd->cmd_u.l32.lock_type   = CMD1394_LOCK_BIT_AND;
453 
454 		ret = s1394_split_lock_req(hal, NULL, cmd);
455 
456 		if (ret == DDI_SUCCESS) {
457 			if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
458 				*old_channels = T1394_DATA32(
459 				    cmd->cmd_u.l32.old_value);
460 
461 				if ((~(*old_channels) & channel_mask) != 0) {
462 					*result = CMD1394_ERETRIES_EXCEEDED;
463 					TNF_PROBE_1(s1394_channel_alloc_error,
464 					    S1394_TNF_SL_ISOCH_ERROR, "",
465 					    tnf_string, msg,
466 					    "Channels already taken");
467 					TNF_PROBE_0_DEBUG(
468 					    s1394_channel_alloc_exit,
469 					    S1394_TNF_SL_ISOCH_STACK, "");
470 					ret = DDI_FAILURE;
471 				} else {
472 					*result = cmd->cmd_result;
473 				}
474 
475 				/* Need to free the command */
476 				(void) s1394_free_cmd(hal, &cmd);
477 
478 				TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit,
479 				    S1394_TNF_SL_ISOCH_STACK, "");
480 				return (ret);
481 
482 			} else {
483 				*result = cmd->cmd_result;
484 				/* Need to free the command */
485 				(void) s1394_free_cmd(hal, &cmd);
486 
487 				TNF_PROBE_1(s1394_channel_alloc_error,
488 				    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string,
489 				    msg, "Error allocating isoch channel");
490 				TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit,
491 				    S1394_TNF_SL_ISOCH_STACK, "");
492 				return (DDI_FAILURE);
493 			}
494 		} else {
495 			*result = cmd->cmd_result;
496 
497 			/* Need to free the command */
498 			(void) s1394_free_cmd(hal, &cmd);
499 
500 			TNF_PROBE_1(s1394_channel_alloc_error,
501 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
502 			    "Error allocating isoch channel");
503 			TNF_PROBE_0_DEBUG(s1394_channel_alloc_exit,
504 			    S1394_TNF_SL_ISOCH_STACK, "");
505 			return (DDI_FAILURE);
506 		}
507 	}
508 }
509 
510 /*
511  * s1394_channel_free()
512  *    is used to free up an isochronous channel.  A channel mask and
513  *    generation are passed.  A request is sent to whichever node is the
514  *    IRM for the appropriate channels.  If it fails because of a bus
515  *    reset it can be retried.  If it fails for another reason the
516  *    channel(s) may already be free or there may be no IRM.
517  */
518 int
519 s1394_channel_free(s1394_hal_t *hal, uint32_t channel_mask, uint_t generation,
520     uint_t flags, uint32_t *old_channels, int *result)
521 {
522 	cmd1394_cmd_t	*cmd;
523 	uint64_t	IRM_ID_addr;
524 	uint32_t	compare;
525 	uint32_t	swap;
526 	uint32_t	old_value;
527 	uint_t		hal_node_num;
528 	uint_t		IRM_node;
529 	uint_t		offset;
530 	int		ret;
531 	int		i;
532 	int		num_retries = S1394_ISOCH_ALLOC_RETRIES;
533 
534 	TNF_PROBE_0_DEBUG(s1394_channel_free_enter,
535 	    S1394_TNF_SL_ISOCH_STACK, "");
536 
537 	/* Lock the topology tree */
538 	mutex_enter(&hal->topology_tree_mutex);
539 
540 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
541 	IRM_node = hal->IRM_node;
542 
543 	/* Unlock the topology tree */
544 	mutex_exit(&hal->topology_tree_mutex);
545 
546 	/* Make sure there is a valid IRM on the bus */
547 	if (IRM_node == -1) {
548 		*result = CMD1394_ERETRIES_EXCEEDED;
549 		TNF_PROBE_1(s1394_channel_free_error,
550 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
551 		    "No IRM on the 1394 bus");
552 		TNF_PROBE_0_DEBUG(s1394_channel_free_exit,
553 		    S1394_TNF_SL_ISOCH_STACK, "");
554 		return (DDI_FAILURE);
555 	}
556 
557 	if (flags & S1394_CHANNEL_ALLOC_HI) {
558 		offset =
559 		    (IEEE1394_SCSR_CHANS_AVAIL_HI & IEEE1394_CSR_OFFSET_MASK);
560 	} else {
561 		offset =
562 		    (IEEE1394_SCSR_CHANS_AVAIL_LO & IEEE1394_CSR_OFFSET_MASK);
563 	}
564 
565 	/* Send compare-swap to CHANNELS_AVAILABLE */
566 	/* register on the Isoch Rsrc Mgr */
567 	if (hal->IRM_node == hal_node_num) {
568 		/* Local */
569 		i = num_retries;
570 		do {
571 			(void) HAL_CALL(hal).csr_read(hal->halinfo.hal_private,
572 			    offset, &old_value);
573 
574 			/* Check that the generation has not changed */
575 			if (generation != hal->generation_count) {
576 				*result = CMD1394_EBUSRESET;
577 				TNF_PROBE_0_DEBUG(s1394_channel_free_exit,
578 				    S1394_TNF_SL_ISOCH_STACK, "");
579 				return (DDI_FAILURE);
580 			}
581 
582 			compare = old_value;
583 			swap	= old_value | channel_mask;
584 
585 			ret = HAL_CALL(hal).csr_cswap32(
586 			    hal->halinfo.hal_private, hal->generation_count,
587 			    offset, compare, swap, &old_value);
588 			if (ret != DDI_SUCCESS) {
589 				*result = CMD1394_EBUSRESET;
590 				TNF_PROBE_1(s1394_channel_free_error,
591 				    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string,
592 				    msg, "Error in cswap32");
593 				TNF_PROBE_0_DEBUG(s1394_channel_free_exit,
594 				    "stacktrace 1394 s1394", "");
595 				return (DDI_FAILURE);
596 			}
597 
598 			if (old_value == compare) {
599 				*result = CMD1394_CMDSUCCESS;
600 				*old_channels = old_value;
601 				TNF_PROBE_0_DEBUG(s1394_channel_free_exit,
602 				    S1394_TNF_SL_ISOCH_STACK, "");
603 				return (DDI_SUCCESS);
604 			}
605 		} while (i--);
606 
607 		*result = CMD1394_ERETRIES_EXCEEDED;
608 		TNF_PROBE_1(s1394_channel_free_error,
609 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
610 		    "Retries exceeded");
611 		TNF_PROBE_0_DEBUG(s1394_channel_free_exit,
612 		    S1394_TNF_SL_ISOCH_STACK, "");
613 		return (DDI_FAILURE);
614 
615 	} else {
616 		/* Remote */
617 		if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) {
618 			*result = CMD1394_EUNKNOWN_ERROR;
619 			TNF_PROBE_1(s1394_channel_free_error,
620 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
621 			    "Unable to allocate command");
622 			TNF_PROBE_0_DEBUG(s1394_channel_free_exit,
623 			    S1394_TNF_SL_ISOCH_STACK, "");
624 			return (DDI_FAILURE);
625 		}
626 
627 		cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET |
628 		    CMD1394_OVERRIDE_ADDR | CMD1394_BLOCKING);
629 		cmd->cmd_type = CMD1394_ASYNCH_LOCK_32;
630 
631 		if (flags & S1394_CHANNEL_ALLOC_HI) {
632 			IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK |
633 			    IEEE1394_SCSR_CHANS_AVAIL_HI) |
634 			    (((uint64_t)IRM_node) <<
635 			    IEEE1394_ADDR_PHY_ID_SHIFT);
636 		} else {
637 			IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK |
638 			    IEEE1394_SCSR_CHANS_AVAIL_LO) |
639 			    (((uint64_t)IRM_node) <<
640 			    IEEE1394_ADDR_PHY_ID_SHIFT);
641 		}
642 
643 		cmd->cmd_addr		   = IRM_ID_addr;
644 		cmd->bus_generation	   = generation;
645 		cmd->cmd_u.l32.data_value  = T1394_DATA32(channel_mask);
646 		cmd->cmd_u.l32.num_retries = num_retries;
647 		cmd->cmd_u.l32.lock_type   = CMD1394_LOCK_BIT_OR;
648 
649 		ret = s1394_split_lock_req(hal, NULL, cmd);
650 
651 		if (ret == DDI_SUCCESS) {
652 			if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
653 
654 				*old_channels = T1394_DATA32(
655 				    cmd->cmd_u.l32.old_value);
656 				*result = cmd->cmd_result;
657 
658 				/* Need to free the command */
659 				(void) s1394_free_cmd(hal, &cmd);
660 
661 				TNF_PROBE_0_DEBUG(s1394_channel_free_exit,
662 				    S1394_TNF_SL_ISOCH_STACK, "");
663 				return (DDI_SUCCESS);
664 
665 			} else {
666 				*result = cmd->cmd_result;
667 
668 				/* Need to free the command */
669 				(void) s1394_free_cmd(hal, &cmd);
670 
671 				TNF_PROBE_1(s1394_channel_free_error,
672 				    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string,
673 				    msg, "Error freeing isoch channel");
674 				TNF_PROBE_0_DEBUG(s1394_channel_free_exit,
675 				    S1394_TNF_SL_ISOCH_STACK, "");
676 				return (DDI_FAILURE);
677 			}
678 		} else {
679 			*result = cmd->cmd_result;
680 			/* Need to free the command */
681 			(void) s1394_free_cmd(hal, &cmd);
682 
683 			TNF_PROBE_1(s1394_channel_free_error,
684 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
685 			    "Error freeing isoch channel");
686 			TNF_PROBE_0_DEBUG(s1394_channel_free_exit,
687 			    S1394_TNF_SL_ISOCH_STACK, "");
688 			return (DDI_FAILURE);
689 		}
690 	}
691 }
692 
693 /*
694  * s1394_bandwidth_alloc()
695  *    is used to allocate isochronous bandwidth.  A number of bandwidth
696  *    allocation units and a generation are passed.  The request is sent
697  *    to whichever node is the IRM for this amount of bandwidth.  If it
698  *    fails because of a bus reset it can be retried.  If it fails for
699  *    another reason the bandwidth may not be available or there may be
700  *    no IRM.
701  */
702 int
703 s1394_bandwidth_alloc(s1394_hal_t *hal, uint32_t bw_alloc_units,
704     uint_t generation, int *result)
705 {
706 	cmd1394_cmd_t	*cmd;
707 	uint64_t	IRM_ID_addr;
708 	uint32_t	compare;
709 	uint32_t	swap;
710 	uint32_t	old_value;
711 	uint_t		hal_node_num;
712 	uint_t		IRM_node;
713 	int		temp_value;
714 	int		ret;
715 	int		i;
716 	int		num_retries = S1394_ISOCH_ALLOC_RETRIES;
717 
718 	TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_enter,
719 	    S1394_TNF_SL_ISOCH_STACK, "");
720 
721 	/* Lock the topology tree */
722 	mutex_enter(&hal->topology_tree_mutex);
723 
724 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
725 	IRM_node = hal->IRM_node;
726 
727 	/* Unlock the topology tree */
728 	mutex_exit(&hal->topology_tree_mutex);
729 
730 	/* Make sure there is a valid IRM on the bus */
731 	if (IRM_node == -1) {
732 		*result = CMD1394_ERETRIES_EXCEEDED;
733 		TNF_PROBE_1(s1394_bandwidth_alloc_error,
734 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
735 		    "No IRM on the 1394 bus");
736 		TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit,
737 		    S1394_TNF_SL_ISOCH_STACK, "");
738 		return (DDI_FAILURE);
739 	}
740 
741 	/* Send compare-swap to BANDWIDTH_AVAILABLE */
742 	/* register on the Isoch Rsrc Mgr */
743 	if (IRM_node == hal_node_num) {
744 		/* Local */
745 		i = num_retries;
746 		do {
747 			(void) HAL_CALL(hal).csr_read(hal->halinfo.hal_private,
748 			    (IEEE1394_SCSR_BANDWIDTH_AVAIL &
749 			    IEEE1394_CSR_OFFSET_MASK), &old_value);
750 			/*
751 			 * Check that the generation has not changed -
752 			 * don't need the lock (read-only)
753 			 */
754 			if (generation != hal->generation_count) {
755 				*result = CMD1394_EBUSRESET;
756 				TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit,
757 				    S1394_TNF_SL_ISOCH_STACK, "");
758 				return (DDI_FAILURE);
759 			}
760 
761 			temp_value = (old_value - bw_alloc_units);
762 			if ((old_value >= bw_alloc_units) &&
763 			    (temp_value >= IEEE1394_BANDWIDTH_MIN)) {
764 				compare = old_value;
765 				swap	= (uint32_t)temp_value;
766 			} else {
767 				*result = CMD1394_ERETRIES_EXCEEDED;
768 				TNF_PROBE_1(s1394_bandwidth_alloc_error,
769 				    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string,
770 				    msg, "Retries exceeded");
771 				TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit,
772 				    S1394_TNF_SL_ISOCH_STACK, "");
773 				return (DDI_FAILURE);
774 			}
775 
776 			ret = HAL_CALL(hal).csr_cswap32(
777 			    hal->halinfo.hal_private, generation,
778 			    (IEEE1394_SCSR_BANDWIDTH_AVAIL &
779 			    IEEE1394_CSR_OFFSET_MASK), compare, swap,
780 			    &old_value);
781 			if (ret != DDI_SUCCESS) {
782 				*result = CMD1394_EBUSRESET;
783 				TNF_PROBE_1(s1394_bandwidth_alloc_error,
784 				    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string,
785 				    msg, "Error in cswap32");
786 				TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit,
787 				    S1394_TNF_SL_ISOCH_STACK, "");
788 				return (DDI_FAILURE);
789 			}
790 
791 			if (old_value == compare) {
792 				*result = CMD1394_CMDSUCCESS;
793 				TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit,
794 				    S1394_TNF_SL_ISOCH_STACK, "");
795 				return (DDI_SUCCESS);
796 			}
797 		} while (i--);
798 
799 		*result = CMD1394_ERETRIES_EXCEEDED;
800 		TNF_PROBE_1(s1394_bandwidth_alloc_error,
801 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
802 		    "Too many retries");
803 		TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit,
804 		    S1394_TNF_SL_ISOCH_STACK, "");
805 		return (DDI_FAILURE);
806 
807 	} else {
808 		/* Remote */
809 		if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) {
810 			*result = CMD1394_EUNKNOWN_ERROR;
811 			TNF_PROBE_1(s1394_bandwidth_alloc_error,
812 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
813 			    "Unable to allocate command");
814 			TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit,
815 			    S1394_TNF_SL_ISOCH_STACK, "");
816 			return (DDI_FAILURE);
817 		}
818 
819 		cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET |
820 		    CMD1394_OVERRIDE_ADDR | CMD1394_BLOCKING);
821 		cmd->cmd_type = CMD1394_ASYNCH_LOCK_32;
822 		IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK |
823 		    IEEE1394_SCSR_BANDWIDTH_AVAIL) | (((uint64_t)IRM_node) <<
824 		    IEEE1394_ADDR_PHY_ID_SHIFT);
825 		cmd->cmd_addr		   = IRM_ID_addr;
826 		cmd->bus_generation	   = generation;
827 		cmd->cmd_u.l32.arg_value   = 0;
828 		cmd->cmd_u.l32.data_value  = bw_alloc_units;
829 		cmd->cmd_u.l32.num_retries = num_retries;
830 		cmd->cmd_u.l32.lock_type   = CMD1394_LOCK_THRESH_SUBTRACT;
831 
832 		ret = s1394_split_lock_req(hal, NULL, cmd);
833 
834 		if (ret == DDI_SUCCESS) {
835 			if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
836 				*result = cmd->cmd_result;
837 				/* Need to free the command */
838 				(void) s1394_free_cmd(hal, &cmd);
839 
840 				TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit,
841 				    S1394_TNF_SL_ISOCH_STACK, "");
842 				return (DDI_SUCCESS);
843 
844 			} else {
845 				*result = cmd->cmd_result;
846 				/* Need to free the command */
847 				(void) s1394_free_cmd(hal, &cmd);
848 
849 				TNF_PROBE_1(s1394_bandwidth_alloc_error,
850 				    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string,
851 				    msg, "Error allocating isoch bandwidth");
852 				TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit,
853 				    S1394_TNF_SL_ISOCH_STACK, "");
854 				return (DDI_FAILURE);
855 			}
856 		} else {
857 			*result = cmd->cmd_result;
858 			/* Need to free the command */
859 			(void) s1394_free_cmd(hal, &cmd);
860 
861 			TNF_PROBE_1(s1394_bandwidth_alloc_error,
862 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
863 			    "Error allocating isoch bandwidth");
864 			TNF_PROBE_0_DEBUG(s1394_bandwidth_alloc_exit,
865 			    S1394_TNF_SL_ISOCH_STACK, "");
866 			return (DDI_FAILURE);
867 		}
868 	}
869 }
870 
871 /*
872  * s1394_compute_bw_alloc_units()
873  *    is used to compute the number of "bandwidth allocation units" that
874  *    are necessary for a given bit rate.  It calculates the overhead
875  *    necessary for isoch packet headers, bus arbitration, etc.  (See
876  *    IEEE 1394-1995 Section 8.3.2.3.7 for an explanation of what a
877  *    "bandwidth allocation unit" is.
878  */
879 uint_t
880 s1394_compute_bw_alloc_units(s1394_hal_t *hal, uint_t bandwidth, uint_t speed)
881 {
882 	uint_t	total_quads;
883 	uint_t	speed_factor;
884 	uint_t	bau;
885 	int	max_hops;
886 
887 	/* Lock the topology tree */
888 	mutex_enter(&hal->topology_tree_mutex);
889 
890 	/* Calculate the 1394 bus diameter */
891 	max_hops = s1394_topology_tree_calculate_diameter(hal);
892 
893 	/* Unlock the topology tree */
894 	mutex_exit(&hal->topology_tree_mutex);
895 
896 	/* Calculate the total bandwidth (including overhead) */
897 	total_quads = (bandwidth >> 2) + IEEE1394_ISOCH_HDR_QUAD_SZ;
898 	switch (speed) {
899 	case IEEE1394_S400:
900 		speed_factor = ISOCH_SPEED_FACTOR_S400;
901 		break;
902 	case IEEE1394_S200:
903 		speed_factor = ISOCH_SPEED_FACTOR_S200;
904 		break;
905 	case IEEE1394_S100:
906 		speed_factor = ISOCH_SPEED_FACTOR_S100;
907 		break;
908 	}
909 	/* See IEC 61883-1 pp. 26-29 for this formula */
910 	bau = (32 * max_hops) + (total_quads * speed_factor);
911 
912 	return (bau);
913 }
914 
915 /*
916  * s1394_bandwidth_free()
917  *    is used to free up isochronous bandwidth.  A number of bandwidth
918  *    allocation units and a generation are passed. The request is sent
919  *    to whichever node is the IRM for this amount of bandwidth.  If it
920  *    fails because of a bus reset it can be retried. If it fails for
921  *    another reason the bandwidth may already be freed or there may
922  *    be no IRM.
923  */
924 int
925 s1394_bandwidth_free(s1394_hal_t *hal, uint32_t bw_alloc_units,
926     uint_t generation, int *result)
927 {
928 	cmd1394_cmd_t	*cmd;
929 	uint64_t	IRM_ID_addr;
930 	uint32_t	compare;
931 	uint32_t	swap;
932 	uint32_t	old_value;
933 	uint32_t	temp_value;
934 	uint_t		hal_node_num;
935 	uint_t		IRM_node;
936 	int		ret;
937 	int		i;
938 	int		num_retries = S1394_ISOCH_ALLOC_RETRIES;
939 
940 	TNF_PROBE_0_DEBUG(s1394_bandwidth_free_enter,
941 	    S1394_TNF_SL_ISOCH_STACK, "");
942 
943 	/* Lock the topology tree */
944 	mutex_enter(&hal->topology_tree_mutex);
945 
946 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
947 	IRM_node = hal->IRM_node;
948 
949 	/* Unlock the topology tree */
950 	mutex_exit(&hal->topology_tree_mutex);
951 
952 	/* Make sure there is a valid IRM on the bus */
953 	if (IRM_node == -1) {
954 		*result = CMD1394_ERETRIES_EXCEEDED;
955 		TNF_PROBE_1(s1394_bandwidth_free_error,
956 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
957 		    "No IRM on the 1394 bus");
958 		TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit,
959 		    S1394_TNF_SL_ISOCH_STACK, "");
960 		return (DDI_FAILURE);
961 	}
962 
963 	/* Send compare-swap to BANDWIDTH_AVAILABLE */
964 	/* register on the Isoch Rsrc Mgr */
965 	if (IRM_node == hal_node_num) {
966 		i = num_retries;
967 		do {
968 			(void) HAL_CALL(hal).csr_read(hal->halinfo.hal_private,
969 			    (IEEE1394_SCSR_BANDWIDTH_AVAIL &
970 			    IEEE1394_CSR_OFFSET_MASK), &old_value);
971 
972 			/* Check that the generation has not changed */
973 			if (generation != hal->generation_count) {
974 				*result = CMD1394_EBUSRESET;
975 				TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit,
976 				    S1394_TNF_SL_ISOCH_STACK, "");
977 				return (DDI_FAILURE);
978 			}
979 
980 			temp_value = (old_value + bw_alloc_units);
981 			if ((temp_value >= old_value) &&
982 			    (temp_value <= IEEE1394_BANDWIDTH_MAX)) {
983 				compare = old_value;
984 				swap	= temp_value;
985 			} else {
986 				*result = CMD1394_ERETRIES_EXCEEDED;
987 				TNF_PROBE_1(s1394_bandwidth_free_error,
988 				    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string,
989 				    msg, "Too many retries");
990 				TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit,
991 				    S1394_TNF_SL_ISOCH_STACK, "");
992 				return (DDI_FAILURE);
993 			}
994 
995 			ret = HAL_CALL(hal).csr_cswap32(
996 			    hal->halinfo.hal_private, generation,
997 			    (IEEE1394_SCSR_BANDWIDTH_AVAIL &
998 			    IEEE1394_CSR_OFFSET_MASK), compare, swap,
999 			    &old_value);
1000 			if (ret != DDI_SUCCESS) {
1001 				*result = CMD1394_EBUSRESET;
1002 				TNF_PROBE_1(s1394_bandwidth_free_error,
1003 				    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string,
1004 				    msg, "Error in cswap32");
1005 				TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit,
1006 				    S1394_TNF_SL_ISOCH_STACK, "");
1007 				return (DDI_FAILURE);
1008 			}
1009 
1010 			if (old_value == compare) {
1011 				*result = CMD1394_CMDSUCCESS;
1012 				TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit,
1013 				    S1394_TNF_SL_ISOCH_STACK, "");
1014 				return (DDI_SUCCESS);
1015 			}
1016 		} while (i--);
1017 
1018 		*result = CMD1394_ERETRIES_EXCEEDED;
1019 		TNF_PROBE_1(s1394_bandwidth_free_error,
1020 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1021 		    "Retries exceeded");
1022 		TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit,
1023 		    S1394_TNF_SL_ISOCH_STACK, "");
1024 		return (DDI_FAILURE);
1025 
1026 	} else {
1027 		/* Remote */
1028 		if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) {
1029 			*result = CMD1394_EUNKNOWN_ERROR;
1030 			TNF_PROBE_1(s1394_bandwidth_free_error,
1031 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1032 			    "Unable to allocate command");
1033 			TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit,
1034 			    S1394_TNF_SL_ISOCH_STACK, "");
1035 			return (DDI_FAILURE);
1036 		}
1037 
1038 		cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET |
1039 		    CMD1394_OVERRIDE_ADDR | CMD1394_BLOCKING);
1040 		cmd->cmd_type = CMD1394_ASYNCH_LOCK_32;
1041 		IRM_ID_addr = (IEEE1394_ADDR_BUS_ID_MASK |
1042 		    IEEE1394_SCSR_BANDWIDTH_AVAIL) |
1043 		    (((uint64_t)hal->IRM_node) << IEEE1394_ADDR_PHY_ID_SHIFT);
1044 		cmd->cmd_addr		   = IRM_ID_addr;
1045 		cmd->bus_generation	   = generation;
1046 		cmd->cmd_u.l32.arg_value   = IEEE1394_BANDWIDTH_MAX;
1047 		cmd->cmd_u.l32.data_value  = bw_alloc_units;
1048 		cmd->cmd_u.l32.num_retries = num_retries;
1049 		cmd->cmd_u.l32.lock_type   = CMD1394_LOCK_THRESH_ADD;
1050 
1051 		ret = s1394_split_lock_req(hal, NULL, cmd);
1052 
1053 		if (ret == DDI_SUCCESS) {
1054 			if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
1055 				*result = cmd->cmd_result;
1056 
1057 				/* Need to free the command */
1058 				(void) s1394_free_cmd(hal, &cmd);
1059 
1060 				TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit,
1061 				    S1394_TNF_SL_ISOCH_STACK, "");
1062 				return (DDI_SUCCESS);
1063 
1064 			} else {
1065 				*result = cmd->cmd_result;
1066 				/* Need to free the command */
1067 				(void) s1394_free_cmd(hal, &cmd);
1068 
1069 				TNF_PROBE_1(s1394_bandwidth_free_error,
1070 				    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string,
1071 				    msg, "Error freeing isoch bandwidth");
1072 				TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit,
1073 				    S1394_TNF_SL_ISOCH_STACK, "");
1074 				return (DDI_FAILURE);
1075 			}
1076 		} else {
1077 			*result = cmd->cmd_result;
1078 			/* Need to free the command */
1079 			(void) s1394_free_cmd(hal, &cmd);
1080 
1081 			TNF_PROBE_1(s1394_bandwidth_free_error,
1082 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1083 			    "Error freeing isoch bandwidth");
1084 			TNF_PROBE_0_DEBUG(s1394_bandwidth_free_exit,
1085 			    S1394_TNF_SL_ISOCH_STACK, "");
1086 			return (DDI_FAILURE);
1087 		}
1088 	}
1089 }
1090 
1091 /*
1092  * s1394_isoch_cec_list_insert()
1093  *    is used to insert an Isoch CEC into a given HAL's list of Isoch CECs.
1094  */
1095 void
1096 s1394_isoch_cec_list_insert(s1394_hal_t *hal, s1394_isoch_cec_t *cec)
1097 {
1098 	s1394_isoch_cec_t *cec_temp;
1099 
1100 	TNF_PROBE_0_DEBUG(s1394_isoch_cec_list_insert_enter,
1101 	    S1394_TNF_SL_ISOCH_STACK, "");
1102 
1103 	ASSERT(MUTEX_HELD(&hal->isoch_cec_list_mutex));
1104 
1105 	/* Is the Isoch CEC list empty? */
1106 	if ((hal->isoch_cec_list_head == NULL) &&
1107 	    (hal->isoch_cec_list_tail == NULL)) {
1108 
1109 		hal->isoch_cec_list_head = cec;
1110 		hal->isoch_cec_list_tail = cec;
1111 
1112 		cec->cec_next = NULL;
1113 		cec->cec_prev = NULL;
1114 
1115 	} else {
1116 		cec->cec_next = hal->isoch_cec_list_head;
1117 		cec->cec_prev = NULL;
1118 		cec_temp = hal->isoch_cec_list_head;
1119 		cec_temp->cec_prev = cec;
1120 
1121 		hal->isoch_cec_list_head = cec;
1122 	}
1123 
1124 	TNF_PROBE_0_DEBUG(s1394_isoch_cec_list_insert_exit,
1125 	    S1394_TNF_SL_ISOCH_STACK, "");
1126 }
1127 
1128 /*
1129  * s1394_isoch_cec_list_remove()
1130  *    is used to remove an Isoch CEC from a given HAL's list of Isoch CECs.
1131  */
1132 void
1133 s1394_isoch_cec_list_remove(s1394_hal_t *hal, s1394_isoch_cec_t *cec)
1134 {
1135 	s1394_isoch_cec_t *prev_cec;
1136 	s1394_isoch_cec_t *next_cec;
1137 
1138 	TNF_PROBE_0_DEBUG(s1394_isoch_cec_list_remove_enter,
1139 	    S1394_TNF_SL_ISOCH_STACK, "");
1140 
1141 	ASSERT(MUTEX_HELD(&hal->isoch_cec_list_mutex));
1142 
1143 	prev_cec = cec->cec_prev;
1144 	next_cec = cec->cec_next;
1145 	cec->cec_prev = NULL;
1146 	cec->cec_next = NULL;
1147 
1148 	if (prev_cec != NULL) {
1149 		prev_cec->cec_next = next_cec;
1150 
1151 	} else {
1152 		if (hal->isoch_cec_list_head == cec)
1153 			hal->isoch_cec_list_head = next_cec;
1154 	}
1155 
1156 	if (next_cec != NULL) {
1157 		next_cec->cec_prev = prev_cec;
1158 
1159 	} else {
1160 		if (hal->isoch_cec_list_tail == cec)
1161 			hal->isoch_cec_list_tail = prev_cec;
1162 	}
1163 
1164 	TNF_PROBE_0_DEBUG(s1394_isoch_cec_list_remove_exit,
1165 	    S1394_TNF_SL_ISOCH_STACK, "");
1166 }
1167 
1168 /*
1169  * s1394_isoch_cec_member_list_insert()
1170  *    is used to insert a new member (target) into the list of members for
1171  *    a given Isoch CEC.
1172  */
1173 /* ARGSUSED */
1174 void
1175 s1394_isoch_cec_member_list_insert(s1394_hal_t *hal, s1394_isoch_cec_t *cec,
1176     s1394_isoch_cec_member_t *member)
1177 {
1178 	s1394_isoch_cec_member_t *member_temp;
1179 
1180 	TNF_PROBE_0_DEBUG(s1394_isoch_cec_member_list_insert_enter,
1181 	    S1394_TNF_SL_ISOCH_STACK, "");
1182 
1183 	ASSERT(MUTEX_HELD(&cec->isoch_cec_mutex));
1184 
1185 	/* Is the Isoch CEC member list empty? */
1186 	if ((cec->cec_member_list_head == NULL) &&
1187 	    (cec->cec_member_list_tail == NULL)) {
1188 
1189 		cec->cec_member_list_head = member;
1190 		cec->cec_member_list_tail = member;
1191 		member->cec_mem_next = NULL;
1192 		member->cec_mem_prev = NULL;
1193 
1194 	} else if (member->cec_mem_options & T1394_TALKER) {
1195 		/* Put talker at the head of the list */
1196 		member->cec_mem_next = cec->cec_member_list_head;
1197 		member->cec_mem_prev = NULL;
1198 		member_temp = cec->cec_member_list_head;
1199 		member_temp->cec_mem_prev = member;
1200 		cec->cec_member_list_head = member;
1201 
1202 	} else {
1203 		/* Put listeners at the tail of the list */
1204 		member->cec_mem_prev = cec->cec_member_list_tail;
1205 		member->cec_mem_next = NULL;
1206 		member_temp = cec->cec_member_list_tail;
1207 		member_temp->cec_mem_next = member;
1208 		cec->cec_member_list_tail = member;
1209 	}
1210 
1211 	TNF_PROBE_0_DEBUG(s1394_isoch_cec_member_list_insert_exit,
1212 	    S1394_TNF_SL_ISOCH_STACK, "");
1213 }
1214 
1215 /*
1216  * s1394_isoch_cec_member_list_remove()
1217  *    is used to remove a member (target) from the list of members for
1218  *    a given Isoch CEC.
1219  */
1220 /* ARGSUSED */
1221 void
1222 s1394_isoch_cec_member_list_remove(s1394_hal_t *hal, s1394_isoch_cec_t *cec,
1223     s1394_isoch_cec_member_t *member)
1224 {
1225 	s1394_isoch_cec_member_t *prev_member;
1226 	s1394_isoch_cec_member_t *next_member;
1227 
1228 	TNF_PROBE_0_DEBUG(s1394_isoch_cec_member_list_remove_enter,
1229 	    S1394_TNF_SL_ISOCH_STACK, "");
1230 
1231 	ASSERT(MUTEX_HELD(&cec->isoch_cec_mutex));
1232 
1233 	prev_member = member->cec_mem_prev;
1234 	next_member = member->cec_mem_next;
1235 
1236 	member->cec_mem_prev = NULL;
1237 	member->cec_mem_next = NULL;
1238 
1239 	if (prev_member != NULL) {
1240 		prev_member->cec_mem_next = next_member;
1241 
1242 	} else {
1243 		if (cec->cec_member_list_head == member)
1244 			cec->cec_member_list_head = next_member;
1245 	}
1246 
1247 	if (next_member != NULL) {
1248 		next_member->cec_mem_prev = prev_member;
1249 
1250 	} else {
1251 		if (cec->cec_member_list_tail == member)
1252 			cec->cec_member_list_tail = prev_member;
1253 	}
1254 
1255 	TNF_PROBE_0_DEBUG(s1394_isoch_cec_member_list_remove_exit,
1256 	    S1394_TNF_SL_ISOCH_STACK, "");
1257 }
1258