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