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