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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * av1394 CMP (Connection Management Procedures) 28 */ 29 #include <sys/1394/targets/av1394/av1394_impl.h> 30 31 /* configuration routines */ 32 static void av1394_cmp_cleanup(av1394_inst_t *icp); 33 34 /* ioctl routines */ 35 static int av1394_ioctl_plug_init_local(av1394_inst_t *, 36 iec61883_plug_init_t *); 37 static int av1394_ioctl_plug_init_remote(av1394_inst_t *, 38 iec61883_plug_init_t *); 39 40 /* local PCR routines */ 41 static int av1394_pcr_init(av1394_inst_t *, int, uint32_t); 42 static void av1394_pcr_fini(av1394_inst_t *, int); 43 static int av1394_pcr_alloc_addr(av1394_inst_t *, uint64_t, 44 t1394_addr_handle_t *); 45 static void av1394_pcr_free_addr(av1394_inst_t *, t1394_addr_handle_t *); 46 static int av1394_pcr_make_ph(int, int, int); 47 static int av1394_pcr_ph2idx(int); 48 static av1394_pcr_t *av1394_pcr_ph2pcr(av1394_cmp_t *, int); 49 static uint64_t av1394_pcr_idx2addr(int); 50 static int av1394_pcr_idx2num(int); 51 static boolean_t av1394_pcr_idx_is_mpr(int); 52 static boolean_t av1394_pcr_ph_is_mpr(int); 53 static boolean_t av1394_pcr_ph_is_remote(int); 54 55 /* callbacks */ 56 static void av1394_pcr_recv_read_request(cmd1394_cmd_t *); 57 static void av1394_pcr_recv_lock_request(cmd1394_cmd_t *); 58 59 /* remote PCR routines */ 60 static int av1394_pcr_remote_read(av1394_inst_t *, int, uint32_t *); 61 static int av1394_pcr_remote_cas(av1394_inst_t *, int, uint32_t *, 62 uint32_t, uint32_t); 63 64 #define AV1394_TNF_ENTER(func) \ 65 TNF_PROBE_0_DEBUG(func##_enter, AV1394_TNF_CMP_STACK, ""); 66 67 #define AV1394_TNF_EXIT(func) \ 68 TNF_PROBE_0_DEBUG(func##_exit, AV1394_TNF_CMP_STACK, ""); 69 70 71 int 72 av1394_cmp_init(av1394_inst_t *avp) 73 { 74 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 75 ddi_iblock_cookie_t ibc = avp->av_attachinfo.iblock_cookie; 76 int ret; 77 78 AV1394_TNF_ENTER(av1394_cmp_init); 79 80 ret = t1394_cmp_register(avp->av_t1394_hdl, NULL, 0); 81 82 if (ret == DDI_SUCCESS) { 83 rw_init(&cmp->cmp_pcr_rwlock, NULL, RW_DRIVER, ibc); 84 } 85 86 AV1394_TNF_EXIT(av1394_cmp_init); 87 return (ret); 88 } 89 90 void 91 av1394_cmp_fini(av1394_inst_t *avp) 92 { 93 AV1394_TNF_ENTER(av1394_cmp_fini); 94 95 av1394_cmp_cleanup(avp); 96 97 AV1394_TNF_EXIT(av1394_cmp_fini); 98 } 99 100 void 101 av1394_cmp_bus_reset(av1394_inst_t *avp) 102 { 103 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 104 int i; 105 106 AV1394_TNF_ENTER(av1394_cmp_bus_reset); 107 108 /* reset PCR values */ 109 rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER); 110 for (i = 0; i < NELEM(cmp->cmp_pcr); i++) { 111 if ((i == AV1394_OMPR_IDX) || (i == AV1394_IMPR_IDX)) { 112 continue; 113 } 114 if (cmp->cmp_pcr[i]) { 115 if (i < AV1394_IMPR_IDX) { 116 cmp->cmp_pcr[i]->pcr_val &= 117 ~AV1394_OPCR_BR_CLEAR_MASK; 118 } else { 119 cmp->cmp_pcr[i]->pcr_val &= 120 ~AV1394_IPCR_BR_CLEAR_MASK; 121 } 122 } 123 } 124 rw_exit(&cmp->cmp_pcr_rwlock); 125 126 AV1394_TNF_EXIT(av1394_cmp_bus_reset); 127 } 128 129 /* 130 * on close, free iPCRs and oPCRs not finalized by application 131 */ 132 void 133 av1394_cmp_close(av1394_inst_t *avp) 134 { 135 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 136 int i; 137 138 rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER); 139 for (i = 0; i < NELEM(cmp->cmp_pcr); i++) { 140 if ((i == AV1394_OMPR_IDX) || (i == AV1394_IMPR_IDX)) { 141 continue; 142 } 143 if (cmp->cmp_pcr[i]) { 144 av1394_pcr_fini(avp, i); 145 } 146 } 147 rw_exit(&cmp->cmp_pcr_rwlock); 148 } 149 150 /* 151 * 152 * --- ioctls 153 * 154 * IEC61883_PLUG_INIT 155 */ 156 int 157 av1394_ioctl_plug_init(av1394_inst_t *avp, void *arg, int mode) 158 { 159 int ret = 0; 160 iec61883_plug_init_t pi; 161 162 if (ddi_copyin(arg, &pi, sizeof (pi), mode) != 0) { 163 return (EFAULT); 164 } 165 166 /* check arguments */ 167 if (((pi.pi_type != IEC61883_PLUG_IN) && 168 (pi.pi_type != IEC61883_PLUG_OUT) && 169 (pi.pi_type != IEC61883_PLUG_MASTER_IN) && 170 (pi.pi_type != IEC61883_PLUG_MASTER_OUT)) || 171 (((pi.pi_num < 0) || (pi.pi_num >= AV1394_NPCR)) && 172 (pi.pi_num != IEC61883_PLUG_ANY))) { 173 return (EINVAL); 174 } 175 176 if (pi.pi_loc == IEC61883_LOC_LOCAL) { 177 ret = av1394_ioctl_plug_init_local(avp, &pi); 178 } else if (pi.pi_loc == IEC61883_LOC_REMOTE) { 179 ret = av1394_ioctl_plug_init_remote(avp, &pi); 180 } else { 181 ret = EINVAL; 182 } 183 184 if (ret == 0) { 185 if (ddi_copyout(&pi, arg, sizeof (pi), mode) != 0) { 186 ret = EFAULT; 187 } 188 } 189 190 return (ret); 191 } 192 193 /* 194 * IEC61883_PLUG_FINI 195 */ 196 /*ARGSUSED*/ 197 int 198 av1394_ioctl_plug_fini(av1394_inst_t *avp, void *arg, int mode) 199 { 200 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 201 int ret; 202 int ph; 203 204 ph = (int)(intptr_t)arg; 205 206 if (av1394_pcr_ph_is_remote(ph) || av1394_pcr_ph_is_mpr(ph)) { 207 return (0); 208 } 209 210 rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER); 211 if (av1394_pcr_ph2pcr(cmp, ph) != NULL) { 212 av1394_pcr_fini(avp, av1394_pcr_ph2idx(ph)); 213 ret = 0; 214 } else { 215 ret = EINVAL; 216 } 217 rw_exit(&cmp->cmp_pcr_rwlock); 218 219 return (ret); 220 } 221 222 /* 223 * IEC61883_PLUG_REG_READ 224 */ 225 int 226 av1394_ioctl_plug_reg_read(av1394_inst_t *avp, void *arg, int mode) 227 { 228 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 229 int ret = 0; 230 iec61883_plug_reg_val_t pr; 231 int ph; 232 av1394_pcr_t *pcr; 233 234 if (ddi_copyin(arg, &pr, sizeof (pr), mode) != 0) { 235 return (EFAULT); 236 } 237 ph = pr.pr_handle; 238 239 if (av1394_pcr_ph_is_remote(ph)) { 240 ret = av1394_pcr_remote_read(avp, ph, &pr.pr_val); 241 } else { 242 switch (av1394_pcr_ph2idx(ph)) { 243 case AV1394_OMPR_IDX: 244 ret = t1394_cmp_read(avp->av_t1394_hdl, T1394_CMP_OMPR, 245 &pr.pr_val); 246 break; 247 case AV1394_IMPR_IDX: 248 ret = t1394_cmp_read(avp->av_t1394_hdl, T1394_CMP_IMPR, 249 &pr.pr_val); 250 break; 251 default: 252 rw_enter(&cmp->cmp_pcr_rwlock, RW_READER); 253 if ((pcr = av1394_pcr_ph2pcr(cmp, ph)) != NULL) { 254 pr.pr_val = pcr->pcr_val; 255 } else { 256 ret = EINVAL; 257 } 258 rw_exit(&cmp->cmp_pcr_rwlock); 259 } 260 } 261 262 if (ret == 0) { 263 if (ddi_copyout(&pr, arg, sizeof (pr), mode) != 0) { 264 ret = EFAULT; 265 } 266 } 267 268 return (ret); 269 } 270 271 /* 272 * IEC61883_PLUG_REG_CAS 273 */ 274 int 275 av1394_ioctl_plug_reg_cas(av1394_inst_t *avp, void *arg, int mode) 276 { 277 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 278 int ret = 0; 279 iec61883_plug_reg_lock_t pl; 280 int ph; 281 av1394_pcr_t *pcr; 282 283 if (ddi_copyin(arg, &pl, sizeof (pl), mode) != 0) { 284 return (EFAULT); 285 } 286 ph = pl.pl_handle; 287 288 if (av1394_pcr_ph_is_remote(ph)) { 289 ret = av1394_pcr_remote_cas(avp, ph, 290 &pl.pl_old, pl.pl_data, pl.pl_arg); 291 } else { 292 switch (av1394_pcr_ph2idx(ph)) { 293 case AV1394_OMPR_IDX: 294 ret = t1394_cmp_cas(avp->av_t1394_hdl, T1394_CMP_OMPR, 295 pl.pl_arg, pl.pl_data, &pl.pl_old); 296 break; 297 case AV1394_IMPR_IDX: 298 ret = t1394_cmp_cas(avp->av_t1394_hdl, T1394_CMP_IMPR, 299 pl.pl_arg, pl.pl_data, &pl.pl_old); 300 break; 301 default: 302 rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER); 303 if ((pcr = av1394_pcr_ph2pcr(cmp, ph)) != NULL) { 304 /* compare_swap */ 305 pl.pl_old = pcr->pcr_val; 306 if (pcr->pcr_val == pl.pl_arg) { 307 pcr->pcr_val = pl.pl_data; 308 } 309 } else { 310 ret = EINVAL; 311 } 312 rw_exit(&cmp->cmp_pcr_rwlock); 313 } 314 } 315 316 if (ret == 0) { 317 if (ddi_copyout(&pl, arg, sizeof (pl), mode) != 0) { 318 ret = EFAULT; 319 } 320 } 321 322 return (ret); 323 } 324 325 326 /* 327 * 328 * --- configuration routines 329 * 330 */ 331 static void 332 av1394_cmp_cleanup(av1394_inst_t *avp) 333 { 334 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 335 int i; 336 337 rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER); 338 for (i = 0; i < NELEM(cmp->cmp_pcr); i++) { 339 if (cmp->cmp_pcr[i]) { 340 av1394_pcr_fini(avp, i); 341 } 342 } 343 rw_exit(&cmp->cmp_pcr_rwlock); 344 rw_destroy(&cmp->cmp_pcr_rwlock); 345 (void) t1394_cmp_unregister(avp->av_t1394_hdl); 346 } 347 348 349 /* 350 * 351 * --- ioctl routines 352 * 353 * IEC61883_PLUG_INIT for local plugs 354 */ 355 static int 356 av1394_ioctl_plug_init_local(av1394_inst_t *avp, iec61883_plug_init_t *pip) 357 { 358 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 359 int err; 360 int ph; /* plug handle */ 361 int idx, max_idx; /* plug index */ 362 363 /* MPR's are a special case */ 364 if ((pip->pi_type == IEC61883_PLUG_MASTER_IN) || 365 (pip->pi_type == IEC61883_PLUG_MASTER_OUT)) { 366 pip->pi_handle = av1394_pcr_make_ph(pip->pi_loc, 367 pip->pi_type, 0); 368 return (0); 369 } 370 371 /* PCR */ 372 rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER); 373 if (pip->pi_num == IEC61883_PLUG_ANY) { 374 if (pip->pi_type == IEC61883_PLUG_OUT) { 375 idx = AV1394_OPCR0_IDX; 376 max_idx = idx + AV1394_PCR_ADDR_NOPCR - 1; 377 } else { 378 ASSERT(pip->pi_type == IEC61883_PLUG_IN); 379 idx = AV1394_IPCR0_IDX; 380 max_idx = idx + AV1394_PCR_ADDR_NIPCR - 1; 381 } 382 383 /* find unused PCR */ 384 for (; idx <= max_idx; idx++) { 385 if (cmp->cmp_pcr[idx] != NULL) { 386 continue; 387 } 388 err = av1394_pcr_init(avp, idx, AV1394_PCR_INIT_VAL); 389 if (err == DDI_SUCCESS) { 390 break; 391 } 392 } 393 } else { 394 ph = av1394_pcr_make_ph(pip->pi_loc, pip->pi_type, pip->pi_num); 395 idx = max_idx = av1394_pcr_ph2idx(ph); 396 397 /* create PCR if not already */ 398 if (cmp->cmp_pcr[idx] == NULL) { 399 err = av1394_pcr_init(avp, idx, AV1394_PCR_INIT_VAL); 400 } 401 } 402 403 rw_exit(&cmp->cmp_pcr_rwlock); 404 405 if ((err != DDI_SUCCESS) || (idx > max_idx)) { 406 return (EBUSY); 407 } 408 pip->pi_rnum = av1394_pcr_idx2num(idx); 409 pip->pi_handle = av1394_pcr_make_ph(pip->pi_loc, pip->pi_type, 410 pip->pi_rnum); 411 412 return (0); 413 } 414 415 /* 416 * IEC61883_PLUG_INIT for remote plugs 417 */ 418 static int 419 av1394_ioctl_plug_init_remote(av1394_inst_t *avp, iec61883_plug_init_t *pip) 420 { 421 int ph; 422 uint32_t val; 423 int ret; 424 425 if (pip->pi_num == IEC61883_PLUG_ANY) { 426 return (EINVAL); 427 } 428 429 ph = av1394_pcr_make_ph(pip->pi_loc, pip->pi_type, pip->pi_num); 430 431 /* check PCR existance by attempting to read it */ 432 if ((ret = av1394_pcr_remote_read(avp, ph, &val)) == 0) { 433 pip->pi_handle = ph; 434 pip->pi_rnum = pip->pi_num; 435 } 436 437 return (ret); 438 } 439 440 441 /* 442 * 443 * --- plug routines 444 * 445 * initialize a PCR 446 */ 447 static int 448 av1394_pcr_init(av1394_inst_t *avp, int idx, uint32_t val) 449 { 450 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 451 av1394_pcr_t *pcr; 452 uint64_t addr; 453 int ret; 454 455 pcr = kmem_zalloc(sizeof (av1394_pcr_t), KM_SLEEP); 456 pcr->pcr_val = val; 457 cmp->cmp_pcr[idx] = pcr; 458 459 addr = av1394_pcr_idx2addr(idx); 460 ret = av1394_pcr_alloc_addr(avp, addr, &pcr->pcr_addr_hdl); 461 if (ret != DDI_SUCCESS) { 462 kmem_free(pcr, sizeof (av1394_pcr_t)); 463 cmp->cmp_pcr[idx] = NULL; 464 } 465 466 return (ret); 467 } 468 469 /* 470 * finalize a PCR 471 */ 472 static void 473 av1394_pcr_fini(av1394_inst_t *avp, int idx) 474 { 475 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 476 477 av1394_pcr_free_addr(avp, &cmp->cmp_pcr[idx]->pcr_addr_hdl); 478 kmem_free(cmp->cmp_pcr[idx], sizeof (av1394_pcr_t)); 479 cmp->cmp_pcr[idx] = NULL; 480 } 481 482 /* 483 * allocate CSR address for a PCR 484 */ 485 static int 486 av1394_pcr_alloc_addr(av1394_inst_t *avp, uint64_t addr, 487 t1394_addr_handle_t *hdlp) 488 { 489 t1394_alloc_addr_t aa; 490 int ret; 491 int result; 492 493 AV1394_TNF_ENTER(av1394_pcr_addr_alloc); 494 495 bzero(&aa, sizeof (aa)); 496 aa.aa_address = addr; 497 aa.aa_length = 4; 498 aa.aa_type = T1394_ADDR_FIXED; 499 aa.aa_enable = T1394_ADDR_RDENBL | T1394_ADDR_LKENBL; 500 aa.aa_evts.recv_read_request = av1394_pcr_recv_read_request; 501 aa.aa_evts.recv_lock_request = av1394_pcr_recv_lock_request; 502 aa.aa_arg = avp; 503 504 ret = t1394_alloc_addr(avp->av_t1394_hdl, &aa, 0, &result); 505 if (ret != DDI_SUCCESS) { 506 TNF_PROBE_2(av1394_pcr_alloc_addr_error, AV1394_TNF_CMP_ERROR, 507 "", tnf_int, ret, ret, tnf_int, result, result); 508 } else { 509 *hdlp = aa.aa_hdl; 510 } 511 512 AV1394_TNF_EXIT(av1394_pcr_addr_alloc); 513 return (ret); 514 } 515 516 /* 517 * free CSR address occupied by a PCR 518 */ 519 static void 520 av1394_pcr_free_addr(av1394_inst_t *avp, t1394_addr_handle_t *hdlp) 521 { 522 int ret; 523 524 ret = t1394_free_addr(avp->av_t1394_hdl, hdlp, 0); 525 if (ret != DDI_SUCCESS) { 526 TNF_PROBE_1(av1394_pcr_free_addr_error, AV1394_TNF_CMP_ERROR, 527 "", tnf_int, ret, ret); 528 } 529 } 530 531 /* 532 * make plug handle. range checking should be performed by caller 533 */ 534 static int 535 av1394_pcr_make_ph(int loc, int type, int num) 536 { 537 int ph; 538 539 switch (type) { 540 case IEC61883_PLUG_IN: 541 ph = num + AV1394_IPCR0_IDX; 542 break; 543 case IEC61883_PLUG_OUT: 544 ph = num + AV1394_OPCR0_IDX; 545 break; 546 case IEC61883_PLUG_MASTER_IN: 547 ph = AV1394_IMPR_IDX; 548 break; 549 case IEC61883_PLUG_MASTER_OUT: 550 ph = AV1394_OMPR_IDX; 551 break; 552 default: 553 ASSERT(0); 554 } 555 556 if (loc == IEC61883_LOC_REMOTE) { 557 ph |= AV1394_PCR_REMOTE; 558 } 559 560 return (ph); 561 } 562 563 /* 564 * convert plug handle to PCR index 565 */ 566 static int 567 av1394_pcr_ph2idx(int ph) 568 { 569 return (ph & ~AV1394_PCR_REMOTE); 570 } 571 572 /* 573 * convert plug handle to PCR pointer 574 */ 575 static av1394_pcr_t * 576 av1394_pcr_ph2pcr(av1394_cmp_t *cmp, int ph) 577 { 578 int idx = av1394_pcr_ph2idx(ph); 579 580 if ((idx >= 0) && (idx < NELEM(cmp->cmp_pcr))) { 581 return (cmp->cmp_pcr[idx]); 582 } else { 583 return (NULL); 584 } 585 } 586 587 /* 588 * convert PCR index to CSR address 589 */ 590 static uint64_t 591 av1394_pcr_idx2addr(int idx) 592 { 593 return (AV1394_PCR_ADDR_START + idx * 4); 594 } 595 596 /* 597 * convert PCR index to number 598 */ 599 static int 600 av1394_pcr_idx2num(int idx) 601 { 602 ASSERT(!av1394_pcr_idx_is_mpr(idx)); 603 604 return ((idx - 1) % 32); 605 } 606 607 /* 608 * returns B_TRUE if a master plug 609 */ 610 static boolean_t 611 av1394_pcr_idx_is_mpr(int idx) 612 { 613 return (idx % 32 == 0); 614 } 615 616 static boolean_t 617 av1394_pcr_ph_is_mpr(int ph) 618 { 619 return (av1394_pcr_ph2idx(ph) % 32 == 0); 620 } 621 622 /* 623 * returns B_TRUE if a remote plug 624 */ 625 static boolean_t 626 av1394_pcr_ph_is_remote(int ph) 627 { 628 return ((ph & AV1394_PCR_REMOTE) != 0); 629 } 630 631 632 /* 633 * 634 * --- callbacks 635 * 636 */ 637 static void 638 av1394_pcr_recv_read_request(cmd1394_cmd_t *req) 639 { 640 av1394_inst_t *avp = req->cmd_callback_arg; 641 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 642 int idx; /* PCR index */ 643 av1394_pcr_t *pcr; 644 int err; 645 646 AV1394_TNF_ENTER(av1394_pcr_recv_read_request); 647 648 idx = (req->cmd_addr - AV1394_PCR_ADDR_START) / 4; 649 650 if (req->cmd_type != CMD1394_ASYNCH_RD_QUAD) { 651 req->cmd_result = IEEE1394_RESP_TYPE_ERROR; 652 } else if ((idx >= NELEM(cmp->cmp_pcr)) || 653 ((pcr = cmp->cmp_pcr[idx]) == NULL)) { 654 req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR; 655 } else { 656 /* read */ 657 rw_enter(&cmp->cmp_pcr_rwlock, RW_READER); 658 req->cmd_u.q.quadlet_data = pcr->pcr_val; 659 rw_exit(&cmp->cmp_pcr_rwlock); 660 661 req->cmd_result = IEEE1394_RESP_COMPLETE; 662 } 663 664 err = t1394_recv_request_done(avp->av_t1394_hdl, req, 0); 665 if (err != DDI_SUCCESS) { 666 TNF_PROBE_1(av1394_pcr_recv_read_request_done_error, 667 AV1394_TNF_CMP_ERROR, "", tnf_int, err, err); 668 } 669 670 AV1394_TNF_EXIT(av1394_pcr_recv_read_request); 671 } 672 673 static void 674 av1394_pcr_recv_lock_request(cmd1394_cmd_t *req) 675 { 676 av1394_inst_t *avp = req->cmd_callback_arg; 677 av1394_cmp_t *cmp = &avp->av_i.i_cmp; 678 int idx; /* PCR index */ 679 av1394_pcr_t *pcr; 680 int err; 681 682 AV1394_TNF_ENTER(av1394_pcr_recv_lock_request); 683 684 idx = (req->cmd_addr - AV1394_PCR_ADDR_START) / 4; 685 686 if ((req->cmd_type != CMD1394_ASYNCH_LOCK_32) || 687 (req->cmd_u.l32.lock_type != CMD1394_LOCK_COMPARE_SWAP)) { 688 req->cmd_result = IEEE1394_RESP_TYPE_ERROR; 689 } else if ((idx >= NELEM(cmp->cmp_pcr)) || 690 ((pcr = cmp->cmp_pcr[idx]) == NULL)) { 691 req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR; 692 } else { 693 /* compare_swap */ 694 rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER); 695 if (pcr->pcr_val == req->cmd_u.l32.arg_value) { 696 pcr->pcr_val = req->cmd_u.l32.data_value; 697 } 698 req->cmd_u.l32.old_value = pcr->pcr_val; 699 rw_exit(&cmp->cmp_pcr_rwlock); 700 701 req->cmd_result = IEEE1394_RESP_COMPLETE; 702 } 703 704 err = t1394_recv_request_done(avp->av_t1394_hdl, req, 0); 705 if (err != DDI_SUCCESS) { 706 TNF_PROBE_2(av1394_pcr_recv_lock_request_done_error, 707 AV1394_TNF_CMP_ERROR, "", tnf_int, err, err, 708 tnf_int, result, req->cmd_result); 709 } 710 711 AV1394_TNF_EXIT(av1394_pcr_recv_lock_request); 712 } 713 714 715 /* 716 * 717 * --- remote PCR routines 718 * 719 * read specified PCR on the remote node 720 */ 721 static int 722 av1394_pcr_remote_read(av1394_inst_t *avp, int ph, uint32_t *valp) 723 { 724 cmd1394_cmd_t *cmd; 725 int ret = 0; 726 int err; 727 728 ret = t1394_alloc_cmd(avp->av_t1394_hdl, 0, &cmd); 729 if (ret != DDI_SUCCESS) { 730 return (ENOMEM); 731 } 732 733 cmd->cmd_addr = av1394_pcr_idx2addr(av1394_pcr_ph2idx(ph)); 734 cmd->cmd_type = CMD1394_ASYNCH_RD_QUAD; 735 cmd->cmd_options = CMD1394_BLOCKING; 736 737 if (((err = t1394_read(avp->av_t1394_hdl, cmd)) == DDI_SUCCESS) && 738 (cmd->cmd_result == CMD1394_CMDSUCCESS)) { 739 *valp = cmd->cmd_u.q.quadlet_data; 740 } else { 741 TNF_PROBE_2(av1394_pcr_remote_read_error, AV1394_TNF_CMP_ERROR, 742 "", tnf_int, err, err, tnf_int, result, cmd->cmd_result); 743 ret = EIO; 744 } 745 746 err = t1394_free_cmd(avp->av_t1394_hdl, 0, &cmd); 747 ASSERT(err == DDI_SUCCESS); 748 749 return (ret); 750 } 751 752 /* 753 * compare_swap specified PCR on the remote node 754 */ 755 static int 756 av1394_pcr_remote_cas(av1394_inst_t *avp, int ph, uint32_t *old_valuep, 757 uint32_t data_value, uint32_t arg_value) 758 { 759 cmd1394_cmd_t *cmd; 760 int ret = 0; 761 int err; 762 763 ret = t1394_alloc_cmd(avp->av_t1394_hdl, 0, &cmd); 764 if (ret != DDI_SUCCESS) { 765 return (ENOMEM); 766 } 767 768 cmd->cmd_addr = av1394_pcr_idx2addr(av1394_pcr_ph2idx(ph)); 769 cmd->cmd_type = CMD1394_ASYNCH_LOCK_32; 770 cmd->cmd_u.l32.lock_type = CMD1394_LOCK_COMPARE_SWAP; 771 cmd->cmd_u.l32.data_value = data_value; 772 cmd->cmd_u.l32.arg_value = arg_value; 773 cmd->cmd_u.l32.num_retries = 0; 774 cmd->cmd_options = CMD1394_BLOCKING; 775 776 if (((err = t1394_lock(avp->av_t1394_hdl, cmd)) == DDI_SUCCESS) && 777 (cmd->cmd_result == CMD1394_CMDSUCCESS)) { 778 *old_valuep = cmd->cmd_u.l32.old_value; 779 } else { 780 TNF_PROBE_2(av1394_pcr_remote_cas_error, AV1394_TNF_CMP_ERROR, 781 "", tnf_int, err, err, tnf_int, result, cmd->cmd_result); 782 ret = EIO; 783 } 784 785 err = t1394_free_cmd(avp->av_t1394_hdl, 0, &cmd); 786 ASSERT(err == DDI_SUCCESS); 787 788 return (ret); 789 } 790