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
s1394_isoch_rsrc_realloc(s1394_hal_t * hal)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
s1394_isoch_rsrc_realloc_notify(s1394_hal_t * hal)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
s1394_channel_alloc(s1394_hal_t * hal,uint32_t channel_mask,uint_t generation,uint_t flags,uint32_t * old_channels,int * result)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
s1394_channel_free(s1394_hal_t * hal,uint32_t channel_mask,uint_t generation,uint_t flags,uint32_t * old_channels,int * result)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
s1394_bandwidth_alloc(s1394_hal_t * hal,uint32_t bw_alloc_units,uint_t generation,int * result)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
s1394_compute_bw_alloc_units(s1394_hal_t * hal,uint_t bandwidth,uint_t speed)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
s1394_bandwidth_free(s1394_hal_t * hal,uint32_t bw_alloc_units,uint_t generation,int * result)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
s1394_isoch_cec_list_insert(s1394_hal_t * hal,s1394_isoch_cec_t * cec)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
s1394_isoch_cec_list_remove(s1394_hal_t * hal,s1394_isoch_cec_t * cec)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
s1394_isoch_cec_member_list_insert(s1394_hal_t * hal,s1394_isoch_cec_t * cec,s1394_isoch_cec_member_t * member)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
s1394_isoch_cec_member_list_remove(s1394_hal_t * hal,s1394_isoch_cec_t * cec,s1394_isoch_cec_member_t * member)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