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