Merge illumos-gate
[unleashed/lotheac.git] / usr / src / uts / common / io / 1394 / targets / av1394 / av1394_isoch_chan.c
blob84d9efbad35768f80ef996a35e7bff7ccb87ac9a
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Copyright (c) 2018, Joyent, Inc.
31 * routines common to isoch receive and isoch transmit
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>
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);
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);
53 uint64_t av1394_ic_bitreverse(uint64_t);
54 boolean_t av1394_ic_onebit(uint64_t);
56 #define AV1394_TNF_ENTER(func)
58 #define AV1394_TNF_EXIT(func)
60 /* tunables */
61 extern int av1394_rate_n_dv_ntsc;
62 extern int av1394_rate_d_dv_ntsc;
63 extern int av1394_rate_n_dv_pal;
64 extern int av1394_rate_d_dv_pal;
66 /*ARGSUSED*/
67 int
68 av1394_ic_close(av1394_inst_t *avp, int flags)
70 av1394_isoch_t *ip = &avp->av_i;
71 av1394_ic_t *icp;
72 int i;
74 AV1394_TNF_ENTER(av1394_ic_close);
76 /* cleanup channels in case application didn't */
77 for (i = 0; i < NELEM(ip->i_ic); i++) {
78 icp = ip->i_ic[i];
79 if (icp != NULL) {
80 (void) av1394_ic_stop(icp);
81 av1394_ic_fini(icp);
85 AV1394_TNF_EXIT(av1394_ic_close);
86 return (0);
90 * av1394_ic_init()
91 * Channel allocation and initialization.
93 int
94 av1394_ic_init(av1394_inst_t *avp, iec61883_isoch_init_t *ii,
95 av1394_ic_t **icpp)
97 av1394_isoch_t *ip = &avp->av_i;
98 av1394_ic_t *icp = NULL;
99 int num;
100 av1394_isoch_pool_t *pool;
101 uint64_t mask; /* channel mask */
102 int ret;
103 ddi_iblock_cookie_t ibc = avp->av_attachinfo.iblock_cookie;
105 AV1394_TNF_ENTER(av1394_ic_init);
107 ii->ii_frame_rcnt = 0;
108 ii->ii_rchannel = 0;
109 ii->ii_error = 0;
111 if ((ret = av1394_ic_validate_init_params(ii)) != 0) {
112 AV1394_TNF_EXIT(av1394_ic_init);
113 return (ret);
116 /* allocate channel structure */
117 icp = kmem_zalloc(sizeof (av1394_ic_t), KM_SLEEP);
119 mutex_init(&icp->ic_mutex, NULL, MUTEX_DRIVER, ibc);
120 cv_init(&icp->ic_xfer_cv, NULL, CV_DRIVER, NULL);
122 av1394_ic_set_params(avp, ii, icp, -1);
124 /* allocate isoch channel and bandwidth, except for broadcast */
125 if (ii->ii_channel == (1ULL << 63)) {
126 num = 63;
127 } else if (ii->ii_flags & IEC61883_PRIV_ISOCH_NOALLOC) {
128 num = lowbit(ii->ii_channel) - 1;
129 } else {
130 mask = av1394_ic_bitreverse(ii->ii_channel);
131 ret = av1394_ic_alloc_channel(icp, mask, &num);
132 if (ret != DDI_SUCCESS) {
133 ii->ii_error = IEC61883_ERR_NOCHANNEL;
134 av1394_ic_cleanup(icp, 1);
135 AV1394_TNF_EXIT(av1394_ic_init);
136 return (EINVAL);
139 ASSERT((num >= 0) && (num < 64));
141 mutex_enter(&icp->ic_mutex);
142 icp->ic_num = num;
143 mutex_exit(&icp->ic_mutex);
145 mutex_enter(&ip->i_mutex);
146 if (ip->i_ic[num] != NULL) {
147 mutex_exit(&ip->i_mutex);
148 ii->ii_error = IEC61883_ERR_NOCHANNEL;
149 av1394_ic_cleanup(icp, 2);
150 AV1394_TNF_EXIT(av1394_ic_init);
151 return (EINVAL);
153 ip->i_ic[num] = icp;
154 mutex_exit(&ip->i_mutex);
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;
165 if (ret != 0) {
166 av1394_ic_cleanup(icp, 3);
167 AV1394_TNF_EXIT(av1394_ic_init);
168 return (ret);
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);
177 icp->ic_state = AV1394_IC_IDLE;
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);
187 AV1394_TNF_EXIT(av1394_ic_init);
188 return (0);
191 void
192 av1394_ic_fini(av1394_ic_t *icp)
194 AV1394_TNF_ENTER(av1394_ic_fini);
196 av1394_ic_cleanup(icp, AV1394_CLEANUP_LEVEL_MAX);
198 AV1394_TNF_EXIT(av1394_ic_fini);
203 * --- configuration routines
206 static void
207 av1394_ic_cleanup(av1394_ic_t *icp, int level)
209 av1394_inst_t *avp = icp->ic_avp;
210 av1394_isoch_t *ip = &avp->av_i;
212 ASSERT((level > 0) && (level <= AV1394_CLEANUP_LEVEL_MAX));
214 switch (level) {
215 default:
216 if (icp->ic_dir == AV1394_IR) {
217 av1394_ir_fini(icp);
218 } else {
219 av1394_it_fini(icp);
221 /* FALLTHRU */
222 case 3:
223 mutex_enter(&ip->i_mutex);
224 av1394_as_free(&ip->i_mmap_as, icp->ic_mmap_off);
225 ip->i_ic[icp->ic_num] = NULL;
226 mutex_exit(&ip->i_mutex);
227 /* FALLTHRU */
228 case 2:
229 av1394_ic_free_channel(icp);
230 /* FALLTHRU */
231 case 1:
232 cv_destroy(&icp->ic_xfer_cv);
233 mutex_destroy(&icp->ic_mutex);
234 kmem_free(icp, sizeof (av1394_ic_t));
238 static int
239 av1394_ic_validate_init_params(iec61883_isoch_init_t *ii)
241 int framesz;
243 ii->ii_error = 0;
244 if ((IEC61883_IMPL_VER_MAJOR(ii->ii_version) !=
245 IEC61883_IMPL_VER_MAJOR(AV1394_IEC61883_VER)) ||
246 (IEC61883_IMPL_VER_MINOR(ii->ii_version) >
247 IEC61883_IMPL_VER_MINOR(AV1394_IEC61883_VER))) {
248 ii->ii_error = IEC61883_ERR_VERSION;
249 return (EINVAL);
251 if ((ii->ii_pkt_size % 4) || (ii->ii_pkt_size > 512)) {
252 ii->ii_error = IEC61883_ERR_PKT_SIZE;
253 return (EINVAL);
255 framesz = ii->ii_frame_size * ii->ii_pkt_size;
256 if (framesz > AV1394_IC_FRAME_SIZE_MAX) {
257 ii->ii_error = IEC61883_ERR_NOMEM;
258 return (EINVAL);
260 if ((ii->ii_direction != IEC61883_DIR_RECV) &&
261 (ii->ii_direction != IEC61883_DIR_XMIT)) {
262 ii->ii_error = IEC61883_ERR_INVAL;
263 return (EINVAL);
265 if (((ii->ii_direction == IEC61883_DIR_RECV) &&
266 (ii->ii_frame_cnt < AV1394_IR_NFRAMES_MIN)) ||
267 ((ii->ii_direction == IEC61883_DIR_XMIT) &&
268 (ii->ii_frame_cnt < AV1394_IT_NFRAMES_MIN))) {
269 ii->ii_error = IEC61883_ERR_INVAL;
270 return (EINVAL);
272 if ((ii->ii_bus_speed != IEC61883_S100) &&
273 (ii->ii_bus_speed != IEC61883_S200) &&
274 (ii->ii_bus_speed != IEC61883_S400)) {
275 ii->ii_error = IEC61883_ERR_INVAL;
276 return (EINVAL);
278 if (ii->ii_channel == 0) {
279 ii->ii_error = IEC61883_ERR_INVAL;
280 return (EINVAL);
282 if ((ii->ii_flags & IEC61883_PRIV_ISOCH_NOALLOC) &&
283 !av1394_ic_onebit(ii->ii_channel)) {
284 ii->ii_error = IEC61883_ERR_INVAL;
285 return (EINVAL);
287 /* the rest are xmit only */
288 if (ii->ii_direction == IEC61883_DIR_RECV) {
289 return (0);
291 if (((ii->ii_rate_d != 0) ||
292 (ii->ii_rate_n != IEC61883_RATE_N_DV_NTSC) &&
293 (ii->ii_rate_n != IEC61883_RATE_N_DV_PAL)) &&
294 ((ii->ii_rate_d <= 0) || (ii->ii_rate_n < 0) ||
295 ((ii->ii_rate_n != 0) && (ii->ii_rate_d / ii->ii_rate_n < 2)))) {
296 ii->ii_error = IEC61883_ERR_INVAL;
297 return (EINVAL);
299 if (AV1394_TS_MODE_GET_OFF(ii->ii_ts_mode) +
300 AV1394_TS_MODE_GET_SIZE(ii->ii_ts_mode) > ii->ii_pkt_size) {
301 ii->ii_error = IEC61883_ERR_INVAL;
302 return (EINVAL);
304 return (0);
307 static void
308 av1394_ic_set_params(av1394_inst_t *avp, iec61883_isoch_init_t *ii,
309 av1394_ic_t *icp, int num)
311 av1394_ic_param_t *cp = &icp->ic_param;
313 mutex_enter(&icp->ic_mutex);
314 icp->ic_avp = avp;
315 icp->ic_num = num;
316 icp->ic_dir = (ii->ii_direction == IEC61883_DIR_RECV) ?
317 AV1394_IR : AV1394_IT;
318 icp->ic_pktsz = ii->ii_pkt_size;
319 icp->ic_npkts = ii->ii_frame_size;
320 icp->ic_framesz = icp->ic_pktsz * icp->ic_npkts;
321 icp->ic_nframes = ii->ii_frame_cnt;
322 cp->cp_bus_speed = ii->ii_bus_speed;
323 cp->cp_dbs = ii->ii_dbs;
324 cp->cp_fn = ii->ii_fn;
325 if (icp->ic_dir == AV1394_IT) {
326 if (ii->ii_rate_d == 0) {
327 switch (ii->ii_rate_n) {
328 case IEC61883_RATE_N_DV_NTSC:
329 cp->cp_n = av1394_rate_n_dv_ntsc;
330 cp->cp_d = av1394_rate_d_dv_ntsc;
331 break;
332 case IEC61883_RATE_N_DV_PAL:
333 cp->cp_n = av1394_rate_n_dv_pal;
334 cp->cp_d = av1394_rate_d_dv_pal;
335 break;
336 default:
337 ASSERT(0); /* can't happen */
339 } else {
340 cp->cp_n = ii->ii_rate_n;
341 cp->cp_d = ii->ii_rate_d;
344 cp->cp_ts_mode = ii->ii_ts_mode;
345 mutex_exit(&icp->ic_mutex);
348 static int
349 av1394_ic_alloc_channel(av1394_ic_t *icp, uint64_t mask, int *num)
351 av1394_inst_t *avp = icp->ic_avp;
352 int ret, result;
353 t1394_isoch_singleinfo_t sii;
354 t1394_isoch_single_out_t so;
356 /* allocate isoch channel */
357 sii.si_channel_mask = mask;
358 sii.si_bandwidth = icp->ic_pktsz;
359 sii.rsrc_fail_target = av1394_ic_rsrc_fail;
360 sii.single_evt_arg = icp;
361 sii.si_speed = icp->ic_param.cp_bus_speed;
363 ret = t1394_alloc_isoch_single(avp->av_t1394_hdl, &sii, 0, &so,
364 &icp->ic_sii_hdl, &result);
365 if (ret != DDI_SUCCESS) {
366 } else {
367 *num = so.channel_num;
369 return (ret);
372 static void
373 av1394_ic_free_channel(av1394_ic_t *icp)
375 av1394_inst_t *avp = icp->ic_avp;
377 if (icp->ic_sii_hdl != NULL) {
378 t1394_free_isoch_single(avp->av_t1394_hdl, &icp->ic_sii_hdl, 0);
384 * --- memory allocation and mapping routines
386 * av1394_ic_alloc_pool()
387 * Allocate isoch pool for at least 'mincnt' and at most 'cnt' frames
388 * 'framesz' bytes each. The strategy is to allocate segments of reasonably
389 * large size, to avoid fragmentation and use resources efficiently in case
390 * of a large number of very small frames.
392 * Another problem is that RECV/SEND_BUF IXL commands can address limited
393 * amount of buffer space (AV1394_IXL_BUFSZ_MAX), and if segment size and
394 * buffer size are not aligned, it can make much harder to build IXL chains.
395 * To simplify things, segments shall always contain full frames.
397 * Function returns number of frames the resulting pool can hold.
400 av1394_ic_alloc_pool(av1394_isoch_pool_t *pool, size_t framesz, int cnt,
401 int mincnt)
403 av1394_isoch_seg_t *seg;
404 int fps; /* frames per segment */
405 int nsegs;
406 size_t totalsz, segsz;
407 int i;
408 int ret;
410 AV1394_TNF_ENTER(av1394_ic_alloc_pool);
412 totalsz = framesz * cnt;
413 ASSERT(totalsz > 0);
415 /* request should be reasonable */
416 if (btopr(totalsz) > physmem / AV1394_MEM_MAX_PERCENT) {
417 AV1394_TNF_EXIT(av1394_ic_alloc_pool);
418 return (0);
421 /* calculate segment size and number of segments */
422 segsz = framesz;
423 nsegs = cnt;
424 if (framesz < AV1394_IXL_BUFSZ_MAX / 2) {
425 fps = AV1394_IXL_BUFSZ_MAX / framesz;
426 segsz = framesz * fps;
427 nsegs = totalsz / segsz;
428 if ((totalsz % segsz) != 0)
429 nsegs++; /* remainder in non-full segment */
431 ASSERT(segsz * nsegs >= totalsz);
433 /* allocate segment array */
434 pool->ip_alloc_size = nsegs * sizeof (av1394_isoch_seg_t);
435 pool->ip_seg = kmem_zalloc(pool->ip_alloc_size, KM_SLEEP);
437 /* allocate page-aligned user-mappable memory for each segment */
438 pool->ip_nsegs = 0;
439 pool->ip_size = 0;
440 pool->ip_umem_size = 0;
441 for (i = 0; i < nsegs; i++) {
442 seg = &pool->ip_seg[i];
444 seg->is_umem_size = ptob(btopr(segsz));
445 seg->is_kaddr = ddi_umem_alloc(seg->is_umem_size,
446 DDI_UMEM_SLEEP, &seg->is_umem_cookie);
447 if (seg->is_kaddr == NULL) {
448 break;
450 seg->is_size = segsz;
452 pool->ip_size += seg->is_size;
453 pool->ip_umem_size += seg->is_umem_size;
454 pool->ip_nsegs++;
457 /* number of frames the pool can hold */
458 ret = pool->ip_size / framesz;
459 if (ret < mincnt) {
460 av1394_ic_free_pool(pool);
461 ret = 0;
464 AV1394_TNF_EXIT(av1394_ic_alloc_pool);
465 return (ret);
468 void
469 av1394_ic_free_pool(av1394_isoch_pool_t *pool)
471 int i;
473 AV1394_TNF_ENTER(av1394_ic_free_pool);
475 if (pool->ip_seg != NULL) {
476 for (i = 0; i < pool->ip_nsegs; i++) {
477 ddi_umem_free(pool->ip_seg[i].is_umem_cookie);
479 kmem_free(pool->ip_seg, pool->ip_alloc_size);
480 pool->ip_seg = NULL;
483 AV1394_TNF_EXIT(av1394_ic_free_pool);
487 av1394_ic_dma_setup(av1394_ic_t *icp, av1394_isoch_pool_t *pool)
489 av1394_inst_t *avp = icp->ic_avp;
490 av1394_isoch_seg_t *isp;
491 uint_t dma_dir;
492 int ret;
493 int i;
494 int j;
496 AV1394_TNF_ENTER(av1394_ic_dma_setup);
498 dma_dir = (icp->ic_dir == AV1394_IR) ? DDI_DMA_READ : DDI_DMA_WRITE;
500 * Alloc and bind a DMA handle for each segment.
501 * Note that we need packet size alignment, but since ddi_umem_alloc'ed
502 * memory is page-aligned and our packets are less than page size (yet)
503 * we don't need to do anything special here.
505 for (i = 0; i < pool->ip_nsegs; i++) {
506 isp = &pool->ip_seg[i];
508 ret = ddi_dma_alloc_handle(avp->av_dip,
509 &avp->av_attachinfo.dma_attr, DDI_DMA_DONTWAIT, NULL,
510 &isp->is_dma_hdl);
511 if (ret != DDI_SUCCESS) {
512 av1394_ic_dma_cleanup(icp, pool);
513 AV1394_TNF_EXIT(av1394_ic_dma_setup);
514 return (ret);
517 ret = ddi_dma_addr_bind_handle(isp->is_dma_hdl, NULL,
518 isp->is_kaddr, isp->is_size,
519 dma_dir | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
520 &isp->is_dma_cookie[0], &isp->is_dma_ncookies);
522 if (ret != DDI_DMA_MAPPED) {
523 av1394_ic_dma_cleanup(icp, pool);
524 AV1394_TNF_EXIT(av1394_ic_dma_setup);
525 return (DDI_FAILURE);
528 if (isp->is_dma_ncookies > COOKIES) {
529 av1394_ic_dma_cleanup(icp, pool);
530 AV1394_TNF_EXIT(av1394_ic_dma_setup);
531 return (DDI_FAILURE);
534 for (j = 1; j < isp->is_dma_ncookies; ++j)
535 ddi_dma_nextcookie(isp->is_dma_hdl,
536 &isp->is_dma_cookie[j]);
539 AV1394_TNF_EXIT(av1394_ic_dma_setup);
540 return (DDI_SUCCESS);
543 /*ARGSUSED*/
544 void
545 av1394_ic_dma_cleanup(av1394_ic_t *icp, av1394_isoch_pool_t *pool)
547 av1394_isoch_seg_t *seg;
548 int i;
550 AV1394_TNF_ENTER(av1394_ic_dma_cleanup);
552 for (i = 0; i < pool->ip_nsegs; i++) {
553 seg = &pool->ip_seg[i];
554 if (seg->is_dma_hdl != NULL) {
555 if (seg->is_dma_ncookies > 0) {
556 (void) ddi_dma_unbind_handle(seg->is_dma_hdl);
558 ddi_dma_free_handle(&seg->is_dma_hdl);
562 AV1394_TNF_EXIT(av1394_ic_dma_cleanup);
566 * sync frames for CPU access
568 void
569 av1394_ic_dma_sync_frames(av1394_ic_t *icp, int idx, int cnt,
570 av1394_isoch_pool_t *pool, uint_t type)
572 int fps; /* frames per segment */
573 int nsegs; /* number of segments for indicated frames */
574 int seg; /* index of segment to sync */
576 fps = icp->ic_nframes / pool->ip_nsegs;
578 nsegs = (cnt / fps) + 1;
580 seg = idx / fps;
582 for (;;) {
583 (void) ddi_dma_sync(pool->ip_seg[seg].is_dma_hdl, 0,
584 icp->ic_framesz, type);
586 --nsegs;
587 if (nsegs == 0)
588 break;
590 ++seg;
591 if (seg == pool->ip_nsegs)
592 seg = 0; /* wrap segment index */
598 * --- transfer
602 av1394_ic_start(av1394_ic_t *icp)
604 if (icp->ic_dir == AV1394_IR) {
605 return (av1394_ir_start(icp));
606 } else {
607 return (av1394_it_start(icp));
612 av1394_ic_stop(av1394_ic_t *icp)
614 if (icp->ic_dir == AV1394_IR) {
615 return (av1394_ir_stop(icp));
616 } else {
617 return (av1394_it_stop(icp));
623 * --- callbacks
626 /*ARGSUSED*/
627 static void
628 av1394_ic_rsrc_fail(t1394_isoch_single_handle_t t1394_sii_hdl, opaque_t arg,
629 t1394_isoch_rsrc_error_t fail_args)
631 AV1394_TNF_ENTER(av1394_ic_rsrc_fail);
633 /* XXX this could be handled more gracefully */
634 cmn_err(CE_CONT, "av1394: can't reallocate isochronous resources"
635 " after bus reset\n");
637 AV1394_TNF_EXIT(av1394_ic_rsrc_fail);
642 * --- misc
645 * av1394_ic_ixl_seg_decomp()
646 * Calculate the best decomposition of a segment into buffers.
647 * Return number of buffers, buffer and tail buffer sizes.
649 * We are looking to divide a segment evenly into equally-sized or almost
650 * equally-sized buffers. Maximum buffer size is AV1394_IXL_BUFSZ_MAX.
651 * Algorithm:
652 * 1. If segment size divides evenly by maximum size, terminate.
653 * 2. n = number of maximum-size buffers than fits into the segment.
654 * 3. Divide the segment by n+1, calculate buffer size and tail
655 * (remainder) size.
656 * 4. If the tail can be appended to the last buffer and the resulting
657 * buffer is still less than maximum size, terminate.
658 * 5. Repeat steps 3-5 for n+2, n+3, ... until division is too small.
660 * Since all sizes are packet-aligned, we scale them down (divide by
661 * packet size) in the beginning, do all calculations and scale them up
662 * in the end.
665 av1394_ic_ixl_seg_decomp(size_t segsz, size_t pktsz, size_t *bufszp,
666 size_t *tailszp)
668 size_t nbufs, bufsz, tailsz;
669 size_t maxsz = AV1394_IXL_BUFSZ_MAX;
671 ASSERT(segsz >= maxsz);
672 ASSERT(segsz % pktsz == 0);
674 if (segsz % maxsz == 0) {
675 *tailszp = *bufszp = maxsz;
676 return (segsz / *bufszp - 1);
679 maxsz /= pktsz;
680 segsz /= pktsz;
682 nbufs = segsz / maxsz;
683 do {
684 nbufs++;
685 bufsz = segsz / nbufs;
686 tailsz = bufsz + (segsz - bufsz * nbufs);
687 } while ((tailsz > maxsz) && ((segsz / (nbufs + 1)) > 1));
688 nbufs--;
690 *bufszp = bufsz * pktsz;
691 *tailszp = tailsz * pktsz;
692 return (nbufs);
695 void
696 av1394_ic_ixl_dump(ixl1394_command_t *cmd)
698 ixl1394_callback_t *cb;
699 ixl1394_jump_t *jmp;
700 ixl1394_xfer_buf_t *buf;
701 ixl1394_xfer_pkt_t *pkt;
703 while (cmd) {
704 switch (cmd->ixl_opcode) {
705 case IXL1394_OP_LABEL:
706 cmn_err(CE_CONT, "%p: LABEL\n", (void *)cmd);
707 break;
708 case IXL1394_OP_RECV_BUF:
709 case IXL1394_OP_RECV_BUF_U:
710 buf = (ixl1394_xfer_buf_t *)cmd;
711 cmn_err(CE_CONT, "%p: RECV_BUF addr=%p size=%d "
712 "pkt_size=%d\n", (void *)cmd, (void *)buf->mem_bufp,
713 buf->size, buf->pkt_size);
714 break;
715 case IXL1394_OP_SEND_BUF:
716 case IXL1394_OP_SEND_BUF_U:
717 buf = (ixl1394_xfer_buf_t *)cmd;
718 cmn_err(CE_CONT, "%p: SEND_BUF addr=%p size=%d "
719 "pkt_size=%d\n", (void *)cmd, (void *)buf->mem_bufp,
720 buf->size, buf->pkt_size);
721 break;
722 case IXL1394_OP_SEND_PKT_ST:
723 pkt = (ixl1394_xfer_pkt_t *)cmd;
724 cmn_err(CE_CONT, "%p: SEND_PKT_ST addr=%p size=%d\n",
725 (void *)cmd, (void *)pkt->mem_bufp, pkt->size);
726 break;
727 case IXL1394_OP_CALLBACK:
728 case IXL1394_OP_CALLBACK_U:
729 cb = (ixl1394_callback_t *)cmd;
730 cmn_err(CE_CONT, "%p: CALLBACK %p\n", (void *)cmd,
731 (void *)cb->callback);
732 break;
733 case IXL1394_OP_JUMP:
734 jmp = (ixl1394_jump_t *)cmd;
735 cmn_err(CE_CONT, "%p: JUMP %p\n", (void *)cmd,
736 (void *)jmp->label);
737 break;
738 case IXL1394_OP_JUMP_U:
739 jmp = (ixl1394_jump_t *)cmd;
740 cmn_err(CE_CONT, "%p: JUMP_U %p\n", (void *)cmd,
741 (void *)jmp->label);
742 break;
743 case IXL1394_OP_STORE_TIMESTAMP:
744 cmn_err(CE_CONT, "%p: STORE_TIMESTAMP\n", (void *)cmd);
745 break;
746 default:
747 cmn_err(CE_CONT, "%p: other\n", (void *)cmd);
749 cmd = cmd->next_ixlp;
754 * trigger a soft interrupt, if not already, for a given channel and type
756 void
757 av1394_ic_trigger_softintr(av1394_ic_t *icp, int num, int preq)
759 av1394_isoch_t *ip = &icp->ic_avp->av_i;
760 uint64_t chmask = (1ULL << num);
762 if (((ip->i_softintr_ch & chmask) == 0) ||
763 ((icp->ic_preq & preq) == 0)) {
764 ip->i_softintr_ch |= chmask;
765 icp->ic_preq |= preq;
766 ddi_trigger_softintr(ip->i_softintr_id);
771 * reverse bits in a 64-bit word
773 uint64_t
774 av1394_ic_bitreverse(uint64_t x)
776 x = (((x >> 1) & 0x5555555555555555) | ((x & 0x5555555555555555) << 1));
777 x = (((x >> 2) & 0x3333333333333333) | ((x & 0x3333333333333333) << 2));
778 x = (((x >> 4) & 0x0f0f0f0f0f0f0f0f) | ((x & 0x0f0f0f0f0f0f0f0f) << 4));
779 x = (((x >> 8) & 0x00ff00ff00ff00ff) | ((x & 0x00ff00ff00ff00ff) << 8));
780 x = (((x >> 16) & 0x0000ffff0000ffff) |
781 ((x & 0x0000ffff0000ffff) << 16));
783 return ((x >> 32) | (x << 32));
787 * return B_TRUE if a 64-bit value has only one bit set to 1
789 boolean_t
790 av1394_ic_onebit(uint64_t i)
792 return (((~i + 1) | ~i) == 0xFFFFFFFFFFFFFFFF);