xref: /titanic_44/usr/src/uts/common/io/1394/targets/av1394/av1394_isoch_chan.c (revision 47cd5876b2168926dea28a62f1857b167da29d6c)
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