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 * routines common to isoch receive and isoch transmit
28 */
29 #include <sys/stat.h>
30 #include <sys/systm.h>
31 #include <sys/ddi.h>
32 #include <sys/sunddi.h>
33 #include <sys/bitmap.h>
34 #include <sys/av/iec61883.h>
35 #include <sys/1394/targets/av1394/av1394_impl.h>
36
37 /* configuration routines */
38 static void av1394_ic_cleanup(av1394_ic_t *icp, int level);
39 static int av1394_ic_validate_init_params(iec61883_isoch_init_t *ii);
40 static void av1394_ic_set_params(av1394_inst_t *avp,
41 iec61883_isoch_init_t *ii, av1394_ic_t *icp, int num);
42 static int av1394_ic_alloc_channel(av1394_ic_t *icp, uint64_t mask, int *);
43 static void av1394_ic_free_channel(av1394_ic_t *icp);
44
45 /* callbacks */
46 static void av1394_ic_rsrc_fail(t1394_isoch_single_handle_t t1394_sii_hdl,
47 opaque_t arg, t1394_isoch_rsrc_error_t fail_args);
48
49 uint64_t av1394_ic_bitreverse(uint64_t);
50 boolean_t av1394_ic_onebit(uint64_t);
51
52 #define AV1394_TNF_ENTER(func) \
53 TNF_PROBE_0_DEBUG(func##_enter, AV1394_TNF_ISOCH_STACK, "");
54
55 #define AV1394_TNF_EXIT(func) \
56 TNF_PROBE_0_DEBUG(func##_exit, AV1394_TNF_ISOCH_STACK, "");
57
58 /* tunables */
59 extern int av1394_rate_n_dv_ntsc;
60 extern int av1394_rate_d_dv_ntsc;
61 extern int av1394_rate_n_dv_pal;
62 extern int av1394_rate_d_dv_pal;
63
64 /*ARGSUSED*/
65 int
av1394_ic_close(av1394_inst_t * avp,int flags)66 av1394_ic_close(av1394_inst_t *avp, int flags)
67 {
68 av1394_isoch_t *ip = &avp->av_i;
69 av1394_ic_t *icp;
70 int i;
71
72 AV1394_TNF_ENTER(av1394_ic_close);
73
74 /* cleanup channels in case application didn't */
75 for (i = 0; i < NELEM(ip->i_ic); i++) {
76 icp = ip->i_ic[i];
77 if (icp != NULL) {
78 (void) av1394_ic_stop(icp);
79 av1394_ic_fini(icp);
80 }
81 }
82
83 AV1394_TNF_EXIT(av1394_ic_close);
84 return (0);
85 }
86
87 /*
88 * av1394_ic_init()
89 * Channel allocation and initialization.
90 */
91 int
av1394_ic_init(av1394_inst_t * avp,iec61883_isoch_init_t * ii,av1394_ic_t ** icpp)92 av1394_ic_init(av1394_inst_t *avp, iec61883_isoch_init_t *ii,
93 av1394_ic_t **icpp)
94 {
95 av1394_isoch_t *ip = &avp->av_i;
96 av1394_ic_t *icp = NULL;
97 int num;
98 av1394_isoch_pool_t *pool;
99 uint64_t mask; /* channel mask */
100 int ret;
101 ddi_iblock_cookie_t ibc = avp->av_attachinfo.iblock_cookie;
102
103 AV1394_TNF_ENTER(av1394_ic_init);
104
105 ii->ii_frame_rcnt = 0;
106 ii->ii_rchannel = 0;
107 ii->ii_error = 0;
108
109 if ((ret = av1394_ic_validate_init_params(ii)) != 0) {
110 AV1394_TNF_EXIT(av1394_ic_init);
111 return (ret);
112 }
113
114 /* allocate channel structure */
115 icp = kmem_zalloc(sizeof (av1394_ic_t), KM_SLEEP);
116
117 mutex_init(&icp->ic_mutex, NULL, MUTEX_DRIVER, ibc);
118 cv_init(&icp->ic_xfer_cv, NULL, CV_DRIVER, NULL);
119
120 av1394_ic_set_params(avp, ii, icp, -1);
121
122 /* allocate isoch channel and bandwidth, except for broadcast */
123 if (ii->ii_channel == (1ULL << 63)) {
124 num = 63;
125 } else if (ii->ii_flags & IEC61883_PRIV_ISOCH_NOALLOC) {
126 num = lowbit(ii->ii_channel) - 1;
127 } else {
128 mask = av1394_ic_bitreverse(ii->ii_channel);
129 ret = av1394_ic_alloc_channel(icp, mask, &num);
130 if (ret != DDI_SUCCESS) {
131 ii->ii_error = IEC61883_ERR_NOCHANNEL;
132 av1394_ic_cleanup(icp, 1);
133 AV1394_TNF_EXIT(av1394_ic_init);
134 return (EINVAL);
135 }
136 }
137 ASSERT((num >= 0) && (num < 64));
138
139 mutex_enter(&icp->ic_mutex);
140 icp->ic_num = num;
141 mutex_exit(&icp->ic_mutex);
142
143 mutex_enter(&ip->i_mutex);
144 if (ip->i_ic[num] != NULL) {
145 mutex_exit(&ip->i_mutex);
146 ii->ii_error = IEC61883_ERR_NOCHANNEL;
147 av1394_ic_cleanup(icp, 2);
148 TNF_PROBE_0(av1394_ic_init_error_chan_used,
149 AV1394_TNF_ISOCH_ERROR, "");
150 AV1394_TNF_EXIT(av1394_ic_init);
151 return (EINVAL);
152 }
153 ip->i_ic[num] = icp;
154 mutex_exit(&ip->i_mutex);
155
156 /* do direction specific initialization */
157 if (icp->ic_dir == AV1394_IR) {
158 ret = av1394_ir_init(icp, &ii->ii_error);
159 pool = &icp->ic_ir.ir_data_pool;
160 } else {
161 ret = av1394_it_init(icp, &ii->ii_error);
162 pool = &icp->ic_it.it_data_pool;
163 }
164
165 if (ret != 0) {
166 av1394_ic_cleanup(icp, 3);
167 AV1394_TNF_EXIT(av1394_ic_init);
168 return (ret);
169 }
170
171 /* allocate mmap space */
172 mutex_enter(&ip->i_mutex);
173 mutex_enter(&icp->ic_mutex);
174 icp->ic_mmap_sz = pool->ip_umem_size;
175 icp->ic_mmap_off = av1394_as_alloc(&ip->i_mmap_as, icp->ic_mmap_sz);
176
177 icp->ic_state = AV1394_IC_IDLE;
178
179 *icpp = icp;
180 ii->ii_handle = icp->ic_num;
181 ii->ii_frame_rcnt = icp->ic_nframes;
182 ii->ii_mmap_off = icp->ic_mmap_off;
183 ii->ii_rchannel = icp->ic_num;
184 mutex_exit(&icp->ic_mutex);
185 mutex_exit(&ip->i_mutex);
186
187 TNF_PROBE_2_DEBUG(av1394_ic_init, AV1394_TNF_ISOCH, "",
188 tnf_string, msg, "channel allocated", tnf_int, num, icp->ic_num);
189
190 AV1394_TNF_EXIT(av1394_ic_init);
191 return (0);
192 }
193
194 void
av1394_ic_fini(av1394_ic_t * icp)195 av1394_ic_fini(av1394_ic_t *icp)
196 {
197 AV1394_TNF_ENTER(av1394_ic_fini);
198
199 av1394_ic_cleanup(icp, AV1394_CLEANUP_LEVEL_MAX);
200
201 AV1394_TNF_EXIT(av1394_ic_fini);
202 }
203
204 /*
205 *
206 * --- configuration routines
207 *
208 */
209 static void
av1394_ic_cleanup(av1394_ic_t * icp,int level)210 av1394_ic_cleanup(av1394_ic_t *icp, int level)
211 {
212 av1394_inst_t *avp = icp->ic_avp;
213 av1394_isoch_t *ip = &avp->av_i;
214
215 ASSERT((level > 0) && (level <= AV1394_CLEANUP_LEVEL_MAX));
216
217 switch (level) {
218 default:
219 if (icp->ic_dir == AV1394_IR) {
220 av1394_ir_fini(icp);
221 } else {
222 av1394_it_fini(icp);
223 }
224 /* FALLTHRU */
225 case 3:
226 mutex_enter(&ip->i_mutex);
227 av1394_as_free(&ip->i_mmap_as, icp->ic_mmap_off);
228 ip->i_ic[icp->ic_num] = NULL;
229 mutex_exit(&ip->i_mutex);
230 /* FALLTHRU */
231 case 2:
232 av1394_ic_free_channel(icp);
233 /* FALLTHRU */
234 case 1:
235 cv_destroy(&icp->ic_xfer_cv);
236 mutex_destroy(&icp->ic_mutex);
237 kmem_free(icp, sizeof (av1394_ic_t));
238 }
239 }
240
241 static int
av1394_ic_validate_init_params(iec61883_isoch_init_t * ii)242 av1394_ic_validate_init_params(iec61883_isoch_init_t *ii)
243 {
244 int framesz;
245
246 ii->ii_error = 0;
247 if ((IEC61883_IMPL_VER_MAJOR(ii->ii_version) !=
248 IEC61883_IMPL_VER_MAJOR(AV1394_IEC61883_VER)) ||
249 (IEC61883_IMPL_VER_MINOR(ii->ii_version) >
250 IEC61883_IMPL_VER_MINOR(AV1394_IEC61883_VER))) {
251 TNF_PROBE_0(av1394_ic_validate_init_params_ver_error,
252 AV1394_TNF_ISOCH_ERROR, "");
253 ii->ii_error = IEC61883_ERR_VERSION;
254 return (EINVAL);
255 }
256 if ((ii->ii_pkt_size % 4) || (ii->ii_pkt_size > 512)) {
257 TNF_PROBE_0(av1394_ic_validate_init_params_pktsz_error,
258 AV1394_TNF_ISOCH_ERROR, "");
259 ii->ii_error = IEC61883_ERR_PKT_SIZE;
260 return (EINVAL);
261 }
262 framesz = ii->ii_frame_size * ii->ii_pkt_size;
263 if (framesz > AV1394_IC_FRAME_SIZE_MAX) {
264 TNF_PROBE_0(av1394_ic_validate_init_params_frsz_error,
265 AV1394_TNF_ISOCH_ERROR, "");
266 ii->ii_error = IEC61883_ERR_NOMEM;
267 return (EINVAL);
268 }
269 if ((ii->ii_direction != IEC61883_DIR_RECV) &&
270 (ii->ii_direction != IEC61883_DIR_XMIT)) {
271 TNF_PROBE_0(av1394_ic_validate_init_params_dir_error,
272 AV1394_TNF_ISOCH_ERROR, "");
273 ii->ii_error = IEC61883_ERR_INVAL;
274 return (EINVAL);
275 }
276 if (((ii->ii_direction == IEC61883_DIR_RECV) &&
277 (ii->ii_frame_cnt < AV1394_IR_NFRAMES_MIN)) ||
278 ((ii->ii_direction == IEC61883_DIR_XMIT) &&
279 (ii->ii_frame_cnt < AV1394_IT_NFRAMES_MIN))) {
280 TNF_PROBE_0(av1394_ic_validate_init_params_frcnt_error,
281 AV1394_TNF_ISOCH_ERROR, "");
282 ii->ii_error = IEC61883_ERR_INVAL;
283 return (EINVAL);
284 }
285 if ((ii->ii_bus_speed != IEC61883_S100) &&
286 (ii->ii_bus_speed != IEC61883_S200) &&
287 (ii->ii_bus_speed != IEC61883_S400)) {
288 TNF_PROBE_0(av1394_ic_validate_init_params_speed_error,
289 AV1394_TNF_ISOCH_ERROR, "");
290 ii->ii_error = IEC61883_ERR_INVAL;
291 return (EINVAL);
292 }
293 if (ii->ii_channel == 0) {
294 TNF_PROBE_0(av1394_ic_validate_init_params_chan_error,
295 AV1394_TNF_ISOCH_ERROR, "");
296 ii->ii_error = IEC61883_ERR_INVAL;
297 return (EINVAL);
298 }
299 if ((ii->ii_flags & IEC61883_PRIV_ISOCH_NOALLOC) &&
300 !av1394_ic_onebit(ii->ii_channel)) {
301 TNF_PROBE_0(av1394_ic_validate_init_params_chan_onebit_error,
302 AV1394_TNF_ISOCH_ERROR, "");
303 ii->ii_error = IEC61883_ERR_INVAL;
304 return (EINVAL);
305 }
306 /* the rest are xmit only */
307 if (ii->ii_direction == IEC61883_DIR_RECV) {
308 return (0);
309 }
310 if (((ii->ii_rate_d != 0) ||
311 (ii->ii_rate_n != IEC61883_RATE_N_DV_NTSC) &&
312 (ii->ii_rate_n != IEC61883_RATE_N_DV_PAL)) &&
313 ((ii->ii_rate_d <= 0) || (ii->ii_rate_n < 0) ||
314 ((ii->ii_rate_n != 0) && (ii->ii_rate_d / ii->ii_rate_n < 2)))) {
315 TNF_PROBE_0(av1394_ic_validate_init_params_rate_error,
316 AV1394_TNF_ISOCH_ERROR, "");
317 ii->ii_error = IEC61883_ERR_INVAL;
318 return (EINVAL);
319 }
320 if (AV1394_TS_MODE_GET_OFF(ii->ii_ts_mode) +
321 AV1394_TS_MODE_GET_SIZE(ii->ii_ts_mode) > ii->ii_pkt_size) {
322 TNF_PROBE_0(av1394_ic_validate_init_params_ts_error,
323 AV1394_TNF_ISOCH_ERROR, "");
324 ii->ii_error = IEC61883_ERR_INVAL;
325 return (EINVAL);
326 }
327 return (0);
328 }
329
330 static void
av1394_ic_set_params(av1394_inst_t * avp,iec61883_isoch_init_t * ii,av1394_ic_t * icp,int num)331 av1394_ic_set_params(av1394_inst_t *avp, iec61883_isoch_init_t *ii,
332 av1394_ic_t *icp, int num)
333 {
334 av1394_ic_param_t *cp = &icp->ic_param;
335
336 mutex_enter(&icp->ic_mutex);
337 icp->ic_avp = avp;
338 icp->ic_num = num;
339 icp->ic_dir = (ii->ii_direction == IEC61883_DIR_RECV) ?
340 AV1394_IR : AV1394_IT;
341 icp->ic_pktsz = ii->ii_pkt_size;
342 icp->ic_npkts = ii->ii_frame_size;
343 icp->ic_framesz = icp->ic_pktsz * icp->ic_npkts;
344 icp->ic_nframes = ii->ii_frame_cnt;
345 cp->cp_bus_speed = ii->ii_bus_speed;
346 cp->cp_dbs = ii->ii_dbs;
347 cp->cp_fn = ii->ii_fn;
348 if (icp->ic_dir == AV1394_IT) {
349 if (ii->ii_rate_d == 0) {
350 switch (ii->ii_rate_n) {
351 case IEC61883_RATE_N_DV_NTSC:
352 cp->cp_n = av1394_rate_n_dv_ntsc;
353 cp->cp_d = av1394_rate_d_dv_ntsc;
354 break;
355 case IEC61883_RATE_N_DV_PAL:
356 cp->cp_n = av1394_rate_n_dv_pal;
357 cp->cp_d = av1394_rate_d_dv_pal;
358 break;
359 default:
360 ASSERT(0); /* can't happen */
361 }
362 } else {
363 cp->cp_n = ii->ii_rate_n;
364 cp->cp_d = ii->ii_rate_d;
365 }
366 }
367 cp->cp_ts_mode = ii->ii_ts_mode;
368 mutex_exit(&icp->ic_mutex);
369 }
370
371 static int
av1394_ic_alloc_channel(av1394_ic_t * icp,uint64_t mask,int * num)372 av1394_ic_alloc_channel(av1394_ic_t *icp, uint64_t mask, int *num)
373 {
374 av1394_inst_t *avp = icp->ic_avp;
375 int ret, result;
376 t1394_isoch_singleinfo_t sii;
377 t1394_isoch_single_out_t so;
378
379 /* allocate isoch channel */
380 sii.si_channel_mask = mask;
381 sii.si_bandwidth = icp->ic_pktsz;
382 sii.rsrc_fail_target = av1394_ic_rsrc_fail;
383 sii.single_evt_arg = icp;
384 sii.si_speed = icp->ic_param.cp_bus_speed;
385
386 ret = t1394_alloc_isoch_single(avp->av_t1394_hdl, &sii, 0, &so,
387 &icp->ic_sii_hdl, &result);
388 if (ret != DDI_SUCCESS) {
389 TNF_PROBE_1(av1394_ic_alloc_channel_error,
390 AV1394_TNF_ISOCH_ERROR, "", tnf_int, result, result);
391 } else {
392 *num = so.channel_num;
393 }
394 return (ret);
395 }
396
397 static void
av1394_ic_free_channel(av1394_ic_t * icp)398 av1394_ic_free_channel(av1394_ic_t *icp)
399 {
400 av1394_inst_t *avp = icp->ic_avp;
401
402 if (icp->ic_sii_hdl != NULL) {
403 t1394_free_isoch_single(avp->av_t1394_hdl, &icp->ic_sii_hdl, 0);
404 }
405 }
406
407 /*
408 *
409 * --- memory allocation and mapping routines
410 *
411 * av1394_ic_alloc_pool()
412 * Allocate isoch pool for at least 'mincnt' and at most 'cnt' frames
413 * 'framesz' bytes each. The strategy is to allocate segments of reasonably
414 * large size, to avoid fragmentation and use resources efficiently in case
415 * of a large number of very small frames.
416 *
417 * Another problem is that RECV/SEND_BUF IXL commands can address limited
418 * amount of buffer space (AV1394_IXL_BUFSZ_MAX), and if segment size and
419 * buffer size are not aligned, it can make much harder to build IXL chains.
420 * To simplify things, segments shall always contain full frames.
421 *
422 * Function returns number of frames the resulting pool can hold.
423 */
424 int
av1394_ic_alloc_pool(av1394_isoch_pool_t * pool,size_t framesz,int cnt,int mincnt)425 av1394_ic_alloc_pool(av1394_isoch_pool_t *pool, size_t framesz, int cnt,
426 int mincnt)
427 {
428 av1394_isoch_seg_t *seg;
429 int fps; /* frames per segment */
430 int nsegs;
431 size_t totalsz, segsz;
432 int i;
433 int ret;
434
435 AV1394_TNF_ENTER(av1394_ic_alloc_pool);
436
437 totalsz = framesz * cnt;
438 ASSERT(totalsz > 0);
439
440 /* request should be reasonable */
441 if (btopr(totalsz) > physmem / AV1394_MEM_MAX_PERCENT) {
442 TNF_PROBE_0(av1394_ic_alloc_pool_error_physmem,
443 AV1394_TNF_ISOCH_ERROR, "");
444 AV1394_TNF_EXIT(av1394_ic_alloc_pool);
445 return (0);
446 }
447
448 /* calculate segment size and number of segments */
449 segsz = framesz;
450 nsegs = cnt;
451 if (framesz < AV1394_IXL_BUFSZ_MAX / 2) {
452 fps = AV1394_IXL_BUFSZ_MAX / framesz;
453 segsz = framesz * fps;
454 nsegs = totalsz / segsz;
455 if ((totalsz % segsz) != 0)
456 nsegs++; /* remainder in non-full segment */
457 }
458 ASSERT(segsz * nsegs >= totalsz);
459
460 /* allocate segment array */
461 pool->ip_alloc_size = nsegs * sizeof (av1394_isoch_seg_t);
462 pool->ip_seg = kmem_zalloc(pool->ip_alloc_size, KM_SLEEP);
463
464 /* allocate page-aligned user-mappable memory for each segment */
465 pool->ip_nsegs = 0;
466 pool->ip_size = 0;
467 pool->ip_umem_size = 0;
468 for (i = 0; i < nsegs; i++) {
469 seg = &pool->ip_seg[i];
470
471 seg->is_umem_size = ptob(btopr(segsz));
472 seg->is_kaddr = ddi_umem_alloc(seg->is_umem_size,
473 DDI_UMEM_SLEEP, &seg->is_umem_cookie);
474 if (seg->is_kaddr == NULL) {
475 TNF_PROBE_0(av1394_ic_alloc_pool_error_umem_alloc,
476 AV1394_TNF_ISOCH_ERROR, "");
477 break;
478 }
479 seg->is_size = segsz;
480
481 pool->ip_size += seg->is_size;
482 pool->ip_umem_size += seg->is_umem_size;
483 pool->ip_nsegs++;
484 }
485
486 /* number of frames the pool can hold */
487 ret = pool->ip_size / framesz;
488 if (ret < mincnt) {
489 TNF_PROBE_0(av1394_ic_alloc_pool_error_mincnt,
490 AV1394_TNF_ISOCH_ERROR, "");
491 av1394_ic_free_pool(pool);
492 ret = 0;
493 }
494
495 AV1394_TNF_EXIT(av1394_ic_alloc_pool);
496 return (ret);
497 }
498
499 void
av1394_ic_free_pool(av1394_isoch_pool_t * pool)500 av1394_ic_free_pool(av1394_isoch_pool_t *pool)
501 {
502 int i;
503
504 AV1394_TNF_ENTER(av1394_ic_free_pool);
505
506 if (pool->ip_seg != NULL) {
507 for (i = 0; i < pool->ip_nsegs; i++) {
508 ddi_umem_free(pool->ip_seg[i].is_umem_cookie);
509 }
510 kmem_free(pool->ip_seg, pool->ip_alloc_size);
511 pool->ip_seg = NULL;
512 }
513
514 AV1394_TNF_EXIT(av1394_ic_free_pool);
515 }
516
517 int
av1394_ic_dma_setup(av1394_ic_t * icp,av1394_isoch_pool_t * pool)518 av1394_ic_dma_setup(av1394_ic_t *icp, av1394_isoch_pool_t *pool)
519 {
520 av1394_inst_t *avp = icp->ic_avp;
521 av1394_isoch_seg_t *isp;
522 uint_t dma_dir;
523 int ret;
524 int i;
525 int j;
526
527 AV1394_TNF_ENTER(av1394_ic_dma_setup);
528
529 dma_dir = (icp->ic_dir == AV1394_IR) ? DDI_DMA_READ : DDI_DMA_WRITE;
530 /*
531 * Alloc and bind a DMA handle for each segment.
532 * Note that we need packet size alignment, but since ddi_umem_alloc'ed
533 * memory is page-aligned and our packets are less than page size (yet)
534 * we don't need to do anything special here.
535 */
536 for (i = 0; i < pool->ip_nsegs; i++) {
537 isp = &pool->ip_seg[i];
538
539 ret = ddi_dma_alloc_handle(avp->av_dip,
540 &avp->av_attachinfo.dma_attr, DDI_DMA_DONTWAIT, NULL,
541 &isp->is_dma_hdl);
542 if (ret != DDI_SUCCESS) {
543 TNF_PROBE_0(av1394_ic_dma_setup_error_alloc_hdl,
544 AV1394_TNF_ISOCH_ERROR, "");
545 av1394_ic_dma_cleanup(icp, pool);
546 AV1394_TNF_EXIT(av1394_ic_dma_setup);
547 return (ret);
548 }
549
550 ret = ddi_dma_addr_bind_handle(isp->is_dma_hdl, NULL,
551 isp->is_kaddr, isp->is_size,
552 dma_dir | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
553 &isp->is_dma_cookie[0], &isp->is_dma_ncookies);
554
555 if (ret != DDI_DMA_MAPPED) {
556 TNF_PROBE_0(av1394_ic_dma_setup_error_bind_hdl,
557 AV1394_TNF_ISOCH_ERROR, "");
558 av1394_ic_dma_cleanup(icp, pool);
559 AV1394_TNF_EXIT(av1394_ic_dma_setup);
560 return (DDI_FAILURE);
561 }
562
563 if (isp->is_dma_ncookies > COOKIES) {
564 TNF_PROBE_0(av1394_ic_dma_setup_error_ncookies,
565 AV1394_TNF_ISOCH_ERROR, "");
566 av1394_ic_dma_cleanup(icp, pool);
567 AV1394_TNF_EXIT(av1394_ic_dma_setup);
568 return (DDI_FAILURE);
569 }
570
571 for (j = 1; j < isp->is_dma_ncookies; ++j)
572 ddi_dma_nextcookie(isp->is_dma_hdl,
573 &isp->is_dma_cookie[j]);
574 }
575
576 AV1394_TNF_EXIT(av1394_ic_dma_setup);
577 return (DDI_SUCCESS);
578 }
579
580 /*ARGSUSED*/
581 void
av1394_ic_dma_cleanup(av1394_ic_t * icp,av1394_isoch_pool_t * pool)582 av1394_ic_dma_cleanup(av1394_ic_t *icp, av1394_isoch_pool_t *pool)
583 {
584 av1394_isoch_seg_t *seg;
585 int i;
586
587 AV1394_TNF_ENTER(av1394_ic_dma_cleanup);
588
589 for (i = 0; i < pool->ip_nsegs; i++) {
590 seg = &pool->ip_seg[i];
591 if (seg->is_dma_hdl != NULL) {
592 if (seg->is_dma_ncookies > 0) {
593 (void) ddi_dma_unbind_handle(seg->is_dma_hdl);
594 }
595 ddi_dma_free_handle(&seg->is_dma_hdl);
596 }
597 }
598
599 AV1394_TNF_EXIT(av1394_ic_dma_cleanup);
600 }
601
602 /*
603 * sync frames for CPU access
604 */
605 void
av1394_ic_dma_sync_frames(av1394_ic_t * icp,int idx,int cnt,av1394_isoch_pool_t * pool,uint_t type)606 av1394_ic_dma_sync_frames(av1394_ic_t *icp, int idx, int cnt,
607 av1394_isoch_pool_t *pool, uint_t type)
608 {
609 int fps; /* frames per segment */
610 int nsegs; /* number of segments for indicated frames */
611 int seg; /* index of segment to sync */
612
613 fps = icp->ic_nframes / pool->ip_nsegs;
614
615 nsegs = (cnt / fps) + 1;
616
617 seg = idx / fps;
618 for (;;) {
619 (void) ddi_dma_sync(pool->ip_seg[seg].is_dma_hdl, 0,
620 icp->ic_framesz, type);
621
622 --nsegs;
623 if (nsegs == 0)
624 break;
625
626 ++seg;
627 if (seg == pool->ip_nsegs)
628 seg = 0; /* wrap segment index */
629 }
630 }
631
632 /*
633 *
634 * --- transfer
635 *
636 */
637 int
av1394_ic_start(av1394_ic_t * icp)638 av1394_ic_start(av1394_ic_t *icp)
639 {
640 if (icp->ic_dir == AV1394_IR) {
641 return (av1394_ir_start(icp));
642 } else {
643 return (av1394_it_start(icp));
644 }
645 }
646
647 int
av1394_ic_stop(av1394_ic_t * icp)648 av1394_ic_stop(av1394_ic_t *icp)
649 {
650 if (icp->ic_dir == AV1394_IR) {
651 return (av1394_ir_stop(icp));
652 } else {
653 return (av1394_it_stop(icp));
654 }
655 }
656
657 /*
658 *
659 * --- callbacks
660 *
661 */
662 /*ARGSUSED*/
663 static void
av1394_ic_rsrc_fail(t1394_isoch_single_handle_t t1394_sii_hdl,opaque_t arg,t1394_isoch_rsrc_error_t fail_args)664 av1394_ic_rsrc_fail(t1394_isoch_single_handle_t t1394_sii_hdl, opaque_t arg,
665 t1394_isoch_rsrc_error_t fail_args)
666 {
667 AV1394_TNF_ENTER(av1394_ic_rsrc_fail);
668
669 /* XXX this could be handled more gracefully */
670 cmn_err(CE_CONT, "av1394: can't reallocate isochronous resources"
671 " after bus reset\n");
672
673 AV1394_TNF_EXIT(av1394_ic_rsrc_fail);
674 }
675
676 /*
677 *
678 * --- misc
679 *
680 *
681 * av1394_ic_ixl_seg_decomp()
682 * Calculate the best decomposition of a segment into buffers.
683 * Return number of buffers, buffer and tail buffer sizes.
684 *
685 * We are looking to divide a segment evenly into equally-sized or almost
686 * equally-sized buffers. Maximum buffer size is AV1394_IXL_BUFSZ_MAX.
687 * Algorithm:
688 * 1. If segment size divides evenly by maximum size, terminate.
689 * 2. n = number of maximum-size buffers than fits into the segment.
690 * 3. Divide the segment by n+1, calculate buffer size and tail
691 * (remainder) size.
692 * 4. If the tail can be appended to the last buffer and the resulting
693 * buffer is still less than maximum size, terminate.
694 * 5. Repeat steps 3-5 for n+2, n+3, ... until division is too small.
695 *
696 * Since all sizes are packet-aligned, we scale them down (divide by
697 * packet size) in the beginning, do all calculations and scale them up
698 * in the end.
699 */
700 int
av1394_ic_ixl_seg_decomp(size_t segsz,size_t pktsz,size_t * bufszp,size_t * tailszp)701 av1394_ic_ixl_seg_decomp(size_t segsz, size_t pktsz, size_t *bufszp,
702 size_t *tailszp)
703 {
704 size_t nbufs, bufsz, tailsz;
705 size_t maxsz = AV1394_IXL_BUFSZ_MAX;
706
707 ASSERT(segsz >= maxsz);
708 ASSERT(segsz % pktsz == 0);
709
710 if (segsz % maxsz == 0) {
711 *tailszp = *bufszp = maxsz;
712 return (segsz / *bufszp - 1);
713 }
714
715 maxsz /= pktsz;
716 segsz /= pktsz;
717
718 nbufs = segsz / maxsz;
719 do {
720 nbufs++;
721 bufsz = segsz / nbufs;
722 tailsz = bufsz + (segsz - bufsz * nbufs);
723 } while ((tailsz > maxsz) && ((segsz / (nbufs + 1)) > 1));
724 nbufs--;
725
726 *bufszp = bufsz * pktsz;
727 *tailszp = tailsz * pktsz;
728 return (nbufs);
729 }
730
731 void
av1394_ic_ixl_dump(ixl1394_command_t * cmd)732 av1394_ic_ixl_dump(ixl1394_command_t *cmd)
733 {
734 ixl1394_callback_t *cb;
735 ixl1394_jump_t *jmp;
736 ixl1394_xfer_buf_t *buf;
737 ixl1394_xfer_pkt_t *pkt;
738
739 while (cmd) {
740 switch (cmd->ixl_opcode) {
741 case IXL1394_OP_LABEL:
742 cmn_err(CE_CONT, "%p: LABEL\n", (void *)cmd);
743 break;
744 case IXL1394_OP_RECV_BUF:
745 case IXL1394_OP_RECV_BUF_U:
746 buf = (ixl1394_xfer_buf_t *)cmd;
747 cmn_err(CE_CONT, "%p: RECV_BUF addr=%p size=%d "
748 "pkt_size=%d\n", (void *)cmd, (void *)buf->mem_bufp,
749 buf->size, buf->pkt_size);
750 break;
751 case IXL1394_OP_SEND_BUF:
752 case IXL1394_OP_SEND_BUF_U:
753 buf = (ixl1394_xfer_buf_t *)cmd;
754 cmn_err(CE_CONT, "%p: SEND_BUF addr=%p size=%d "
755 "pkt_size=%d\n", (void *)cmd, (void *)buf->mem_bufp,
756 buf->size, buf->pkt_size);
757 break;
758 case IXL1394_OP_SEND_PKT_ST:
759 pkt = (ixl1394_xfer_pkt_t *)cmd;
760 cmn_err(CE_CONT, "%p: SEND_PKT_ST addr=%p size=%d\n",
761 (void *)cmd, (void *)pkt->mem_bufp, pkt->size);
762 break;
763 case IXL1394_OP_CALLBACK:
764 case IXL1394_OP_CALLBACK_U:
765 cb = (ixl1394_callback_t *)cmd;
766 cmn_err(CE_CONT, "%p: CALLBACK %p\n", (void *)cmd,
767 (void *)cb->callback);
768 break;
769 case IXL1394_OP_JUMP:
770 jmp = (ixl1394_jump_t *)cmd;
771 cmn_err(CE_CONT, "%p: JUMP %p\n", (void *)cmd,
772 (void *)jmp->label);
773 break;
774 case IXL1394_OP_JUMP_U:
775 jmp = (ixl1394_jump_t *)cmd;
776 cmn_err(CE_CONT, "%p: JUMP_U %p\n", (void *)cmd,
777 (void *)jmp->label);
778 break;
779 case IXL1394_OP_STORE_TIMESTAMP:
780 cmn_err(CE_CONT, "%p: STORE_TIMESTAMP\n", (void *)cmd);
781 break;
782 default:
783 cmn_err(CE_CONT, "%p: other\n", (void *)cmd);
784 }
785 cmd = cmd->next_ixlp;
786 }
787 }
788
789 /*
790 * trigger a soft interrupt, if not already, for a given channel and type
791 */
792 void
av1394_ic_trigger_softintr(av1394_ic_t * icp,int num,int preq)793 av1394_ic_trigger_softintr(av1394_ic_t *icp, int num, int preq)
794 {
795 av1394_isoch_t *ip = &icp->ic_avp->av_i;
796 uint64_t chmask = (1ULL << num);
797
798 if (((ip->i_softintr_ch & chmask) == 0) ||
799 ((icp->ic_preq & preq) == 0)) {
800 ip->i_softintr_ch |= chmask;
801 icp->ic_preq |= preq;
802 ddi_trigger_softintr(ip->i_softintr_id);
803 }
804 }
805
806 /*
807 * reverse bits in a 64-bit word
808 */
809 uint64_t
av1394_ic_bitreverse(uint64_t x)810 av1394_ic_bitreverse(uint64_t x)
811 {
812 x = (((x >> 1) & 0x5555555555555555) | ((x & 0x5555555555555555) << 1));
813 x = (((x >> 2) & 0x3333333333333333) | ((x & 0x3333333333333333) << 2));
814 x = (((x >> 4) & 0x0f0f0f0f0f0f0f0f) | ((x & 0x0f0f0f0f0f0f0f0f) << 4));
815 x = (((x >> 8) & 0x00ff00ff00ff00ff) | ((x & 0x00ff00ff00ff00ff) << 8));
816 x = (((x >> 16) & 0x0000ffff0000ffff) |
817 ((x & 0x0000ffff0000ffff) << 16));
818
819 return ((x >> 32) | (x << 32));
820 }
821
822 /*
823 * return B_TRUE if a 64-bit value has only one bit set to 1
824 */
825 boolean_t
av1394_ic_onebit(uint64_t i)826 av1394_ic_onebit(uint64_t i)
827 {
828 return (((~i + 1) | ~i) == 0xFFFFFFFFFFFFFFFF);
829 }
830