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
av1394_cmp_init(av1394_inst_t * avp)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
av1394_cmp_fini(av1394_inst_t * avp)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
av1394_cmp_bus_reset(av1394_inst_t * avp)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
av1394_cmp_close(av1394_inst_t * avp)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
av1394_ioctl_plug_init(av1394_inst_t * avp,void * arg,int mode)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
av1394_ioctl_plug_fini(av1394_inst_t * avp,void * arg,int mode)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
av1394_ioctl_plug_reg_read(av1394_inst_t * avp,void * arg,int mode)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
av1394_ioctl_plug_reg_cas(av1394_inst_t * avp,void * arg,int mode)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
av1394_cmp_cleanup(av1394_inst_t * avp)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
av1394_ioctl_plug_init_local(av1394_inst_t * avp,iec61883_plug_init_t * pip)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
av1394_ioctl_plug_init_remote(av1394_inst_t * avp,iec61883_plug_init_t * pip)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
av1394_pcr_init(av1394_inst_t * avp,int idx,uint32_t val)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
av1394_pcr_fini(av1394_inst_t * avp,int idx)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
av1394_pcr_alloc_addr(av1394_inst_t * avp,uint64_t addr,t1394_addr_handle_t * hdlp)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
av1394_pcr_free_addr(av1394_inst_t * avp,t1394_addr_handle_t * hdlp)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
av1394_pcr_make_ph(int loc,int type,int num)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
av1394_pcr_ph2idx(int ph)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 *
av1394_pcr_ph2pcr(av1394_cmp_t * cmp,int ph)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
av1394_pcr_idx2addr(int idx)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
av1394_pcr_idx2num(int idx)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
av1394_pcr_idx_is_mpr(int idx)611 av1394_pcr_idx_is_mpr(int idx)
612 {
613 return (idx % 32 == 0);
614 }
615
616 static boolean_t
av1394_pcr_ph_is_mpr(int ph)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
av1394_pcr_ph_is_remote(int ph)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
av1394_pcr_recv_read_request(cmd1394_cmd_t * req)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
av1394_pcr_recv_lock_request(cmd1394_cmd_t * req)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
av1394_pcr_remote_read(av1394_inst_t * avp,int ph,uint32_t * valp)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
av1394_pcr_remote_cas(av1394_inst_t * avp,int ph,uint32_t * old_valuep,uint32_t data_value,uint32_t arg_value)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