17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
547cd5876SAlan Perry * Common Development and Distribution License (the "License").
647cd5876SAlan Perry * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
2247cd5876SAlan Perry * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate * av1394 isochronous receive module
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate #include <sys/1394/targets/av1394/av1394_impl.h>
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate /* configuration routines */
327c478bd9Sstevel@tonic-gate static void av1394_ir_cleanup(av1394_ic_t *, int);
337c478bd9Sstevel@tonic-gate static int av1394_ir_build_ixl(av1394_ic_t *);
347c478bd9Sstevel@tonic-gate static void av1394_ir_ixl_label_init(av1394_ir_ixl_data_t *,
357c478bd9Sstevel@tonic-gate ixl1394_command_t *);
367c478bd9Sstevel@tonic-gate static void av1394_ir_ixl_buf_init(av1394_ic_t *, ixl1394_xfer_buf_t *,
3747cd5876SAlan Perry av1394_isoch_seg_t *, off_t, uint64_t, uint16_t,
3847cd5876SAlan Perry ixl1394_command_t *);
397c478bd9Sstevel@tonic-gate static void av1394_ir_ixl_cb_init(av1394_ic_t *, av1394_ir_ixl_data_t *,
407c478bd9Sstevel@tonic-gate int);
417c478bd9Sstevel@tonic-gate static void av1394_ir_ixl_jump_init(av1394_ic_t *, av1394_ir_ixl_data_t *,
427c478bd9Sstevel@tonic-gate int);
437c478bd9Sstevel@tonic-gate static void av1394_ir_destroy_ixl(av1394_ic_t *);
447c478bd9Sstevel@tonic-gate static int av1394_ir_alloc_isoch_dma(av1394_ic_t *);
457c478bd9Sstevel@tonic-gate static void av1394_ir_free_isoch_dma(av1394_ic_t *);
467c478bd9Sstevel@tonic-gate static void av1394_ir_dma_sync_frames(av1394_ic_t *, int, int);
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate /* callbacks */
497c478bd9Sstevel@tonic-gate static void av1394_ir_ixl_frame_cb(opaque_t, struct ixl1394_callback *);
507c478bd9Sstevel@tonic-gate static void av1394_ir_overflow_resume(av1394_ic_t *icp);
517c478bd9Sstevel@tonic-gate static void av1394_ir_dma_stopped_cb(t1394_isoch_dma_handle_t,
527c478bd9Sstevel@tonic-gate opaque_t, id1394_isoch_dma_stopped_t);
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate /* data transfer routines */
557c478bd9Sstevel@tonic-gate static int av1394_ir_add_frames(av1394_ic_t *, int, int);
567c478bd9Sstevel@tonic-gate static int av1394_ir_wait_frames(av1394_ic_t *, int *, int *);
577c478bd9Sstevel@tonic-gate static int av1394_ir_copyout(av1394_ic_t *, struct uio *, int *);
587c478bd9Sstevel@tonic-gate static void av1394_ir_zero_pkts(av1394_ic_t *, int, int);
597c478bd9Sstevel@tonic-gate
607c478bd9Sstevel@tonic-gate /* value complementary to hi & lo watermarks (modulo number of frames) */
617c478bd9Sstevel@tonic-gate int av1394_ir_hiwat_sub = 2;
627c478bd9Sstevel@tonic-gate int av1394_ir_lowat_sub = 3;
637c478bd9Sstevel@tonic-gate int av1394_ir_dump_ixl = 0;
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate int
av1394_ir_init(av1394_ic_t * icp,int * error)667c478bd9Sstevel@tonic-gate av1394_ir_init(av1394_ic_t *icp, int *error)
677c478bd9Sstevel@tonic-gate {
687c478bd9Sstevel@tonic-gate av1394_ir_t *irp = &icp->ic_ir;
697c478bd9Sstevel@tonic-gate av1394_isoch_pool_t *pool = &irp->ir_data_pool;
707c478bd9Sstevel@tonic-gate int nframes;
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate nframes = av1394_ic_alloc_pool(pool, icp->ic_framesz, icp->ic_nframes,
737c478bd9Sstevel@tonic-gate AV1394_IR_NFRAMES_MIN);
747c478bd9Sstevel@tonic-gate if (nframes == 0) {
757c478bd9Sstevel@tonic-gate *error = IEC61883_ERR_NOMEM;
767c478bd9Sstevel@tonic-gate return (EINVAL);
777c478bd9Sstevel@tonic-gate }
787c478bd9Sstevel@tonic-gate mutex_enter(&icp->ic_mutex);
797c478bd9Sstevel@tonic-gate icp->ic_nframes = nframes;
807c478bd9Sstevel@tonic-gate irp->ir_hiwat = nframes - av1394_ir_hiwat_sub;
817c478bd9Sstevel@tonic-gate irp->ir_lowat = nframes - av1394_ir_lowat_sub;
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate if (av1394_ic_dma_setup(icp, pool) != DDI_SUCCESS) {
847c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
857c478bd9Sstevel@tonic-gate *error = IEC61883_ERR_NOMEM;
867c478bd9Sstevel@tonic-gate av1394_ir_cleanup(icp, 1);
877c478bd9Sstevel@tonic-gate return (EINVAL);
887c478bd9Sstevel@tonic-gate }
897c478bd9Sstevel@tonic-gate
907c478bd9Sstevel@tonic-gate if (av1394_ir_build_ixl(icp) != DDI_SUCCESS) {
917c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
927c478bd9Sstevel@tonic-gate *error = IEC61883_ERR_NOMEM;
937c478bd9Sstevel@tonic-gate av1394_ir_cleanup(icp, 2);
947c478bd9Sstevel@tonic-gate return (EINVAL);
957c478bd9Sstevel@tonic-gate }
967c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate if (av1394_ir_alloc_isoch_dma(icp) != DDI_SUCCESS) {
997c478bd9Sstevel@tonic-gate *error = IEC61883_ERR_NOMEM;
1007c478bd9Sstevel@tonic-gate av1394_ir_cleanup(icp, 3);
1017c478bd9Sstevel@tonic-gate return (EINVAL);
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate return (0);
1057c478bd9Sstevel@tonic-gate }
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate void
av1394_ir_fini(av1394_ic_t * icp)1087c478bd9Sstevel@tonic-gate av1394_ir_fini(av1394_ic_t *icp)
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate av1394_ir_cleanup(icp, AV1394_CLEANUP_LEVEL_MAX);
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate int
av1394_ir_start(av1394_ic_t * icp)1147c478bd9Sstevel@tonic-gate av1394_ir_start(av1394_ic_t *icp)
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate av1394_inst_t *avp = icp->ic_avp;
1177c478bd9Sstevel@tonic-gate av1394_ir_t *irp = &icp->ic_ir;
1187c478bd9Sstevel@tonic-gate id1394_isoch_dma_ctrlinfo_t idma_ctrlinfo = { 0 };
1197c478bd9Sstevel@tonic-gate int result;
1207c478bd9Sstevel@tonic-gate int err;
1217c478bd9Sstevel@tonic-gate int ret = 0;
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate mutex_enter(&icp->ic_mutex);
1247c478bd9Sstevel@tonic-gate if (icp->ic_state != AV1394_IC_IDLE) {
1257c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
1267c478bd9Sstevel@tonic-gate return (0);
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate
1297c478bd9Sstevel@tonic-gate irp->ir_first_full = 0;
1307c478bd9Sstevel@tonic-gate irp->ir_last_empty = icp->ic_nframes - 1;
1317c478bd9Sstevel@tonic-gate irp->ir_nfull = 0;
1327c478bd9Sstevel@tonic-gate irp->ir_nempty = icp->ic_nframes;
1337c478bd9Sstevel@tonic-gate irp->ir_read_cnt = 0;
1347c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate err = t1394_start_isoch_dma(avp->av_t1394_hdl, icp->ic_isoch_hdl,
1377c478bd9Sstevel@tonic-gate &idma_ctrlinfo, 0, &result);
1387c478bd9Sstevel@tonic-gate if (err == DDI_SUCCESS) {
1397c478bd9Sstevel@tonic-gate mutex_enter(&icp->ic_mutex);
1407c478bd9Sstevel@tonic-gate icp->ic_state = AV1394_IC_DMA;
1417c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
1427c478bd9Sstevel@tonic-gate } else {
1437c478bd9Sstevel@tonic-gate ret = EIO;
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate return (ret);
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate int
av1394_ir_stop(av1394_ic_t * icp)1507c478bd9Sstevel@tonic-gate av1394_ir_stop(av1394_ic_t *icp)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate av1394_inst_t *avp = icp->ic_avp;
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate mutex_enter(&icp->ic_mutex);
1557c478bd9Sstevel@tonic-gate if (icp->ic_state != AV1394_IC_IDLE) {
1567c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
1577c478bd9Sstevel@tonic-gate t1394_stop_isoch_dma(avp->av_t1394_hdl, icp->ic_isoch_hdl, 0);
1587c478bd9Sstevel@tonic-gate mutex_enter(&icp->ic_mutex);
1597c478bd9Sstevel@tonic-gate icp->ic_state = AV1394_IC_IDLE;
1607c478bd9Sstevel@tonic-gate }
1617c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate return (0);
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate int
av1394_ir_recv(av1394_ic_t * icp,iec61883_recv_t * recv)1677c478bd9Sstevel@tonic-gate av1394_ir_recv(av1394_ic_t *icp, iec61883_recv_t *recv)
1687c478bd9Sstevel@tonic-gate {
1697c478bd9Sstevel@tonic-gate int ret = 0;
1707c478bd9Sstevel@tonic-gate int idx, cnt;
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate idx = recv->rx_xfer.xf_empty_idx;
1737c478bd9Sstevel@tonic-gate cnt = recv->rx_xfer.xf_empty_cnt;
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate /* check arguments */
1767c478bd9Sstevel@tonic-gate if ((idx < 0) || (idx >= icp->ic_nframes) ||
1777c478bd9Sstevel@tonic-gate (cnt < 0) || (cnt > icp->ic_nframes)) {
1787c478bd9Sstevel@tonic-gate return (EINVAL);
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate mutex_enter(&icp->ic_mutex);
1827c478bd9Sstevel@tonic-gate if (cnt > 0) {
1837c478bd9Sstevel@tonic-gate /* add empty frames to the pool */
1847c478bd9Sstevel@tonic-gate if ((ret = av1394_ir_add_frames(icp, idx, cnt)) != 0) {
1857c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
1867c478bd9Sstevel@tonic-gate return (ret);
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate /* wait for new frames to arrive */
1917c478bd9Sstevel@tonic-gate ret = av1394_ir_wait_frames(icp,
1927c478bd9Sstevel@tonic-gate &recv->rx_xfer.xf_full_idx, &recv->rx_xfer.xf_full_cnt);
1937c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate return (ret);
1967c478bd9Sstevel@tonic-gate }
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@tonic-gate int
av1394_ir_read(av1394_ic_t * icp,struct uio * uiop)1997c478bd9Sstevel@tonic-gate av1394_ir_read(av1394_ic_t *icp, struct uio *uiop)
2007c478bd9Sstevel@tonic-gate {
2017c478bd9Sstevel@tonic-gate av1394_ir_t *irp = &icp->ic_ir;
2027c478bd9Sstevel@tonic-gate int ret = 0;
2037c478bd9Sstevel@tonic-gate int empty_cnt;
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate mutex_enter(&icp->ic_mutex);
2067c478bd9Sstevel@tonic-gate while (uiop->uio_resid) {
2077c478bd9Sstevel@tonic-gate /* wait for full frames, if necessary */
2087c478bd9Sstevel@tonic-gate if (irp->ir_read_cnt == 0) {
2097c478bd9Sstevel@tonic-gate irp->ir_read_off = 0;
2107c478bd9Sstevel@tonic-gate ret = av1394_ir_wait_frames(icp,
2117c478bd9Sstevel@tonic-gate &irp->ir_read_idx, &irp->ir_read_cnt);
2127c478bd9Sstevel@tonic-gate if (ret != 0) {
2137c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
2147c478bd9Sstevel@tonic-gate return (ret);
2157c478bd9Sstevel@tonic-gate }
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate /* copyout the data */
2197c478bd9Sstevel@tonic-gate ret = av1394_ir_copyout(icp, uiop, &empty_cnt);
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate /* return freed frames to the pool */
2227c478bd9Sstevel@tonic-gate if (empty_cnt > 0) {
2237c478bd9Sstevel@tonic-gate av1394_ir_zero_pkts(icp, irp->ir_read_idx, empty_cnt);
2247c478bd9Sstevel@tonic-gate ret = av1394_ir_add_frames(icp, irp->ir_read_idx,
2257c478bd9Sstevel@tonic-gate empty_cnt);
2267c478bd9Sstevel@tonic-gate irp->ir_read_idx += empty_cnt;
2277c478bd9Sstevel@tonic-gate irp->ir_read_idx %= icp->ic_nframes;
2287c478bd9Sstevel@tonic-gate irp->ir_read_cnt -= empty_cnt;
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate return (ret);
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate /*
2377c478bd9Sstevel@tonic-gate *
2387c478bd9Sstevel@tonic-gate * --- configuration routines
2397c478bd9Sstevel@tonic-gate *
2407c478bd9Sstevel@tonic-gate */
2417c478bd9Sstevel@tonic-gate static void
av1394_ir_cleanup(av1394_ic_t * icp,int level)2427c478bd9Sstevel@tonic-gate av1394_ir_cleanup(av1394_ic_t *icp, int level)
2437c478bd9Sstevel@tonic-gate {
2447c478bd9Sstevel@tonic-gate av1394_isoch_pool_t *pool = &icp->ic_ir.ir_data_pool;
2457c478bd9Sstevel@tonic-gate
2467c478bd9Sstevel@tonic-gate ASSERT((level > 0) && (level <= AV1394_CLEANUP_LEVEL_MAX));
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate switch (level) {
2497c478bd9Sstevel@tonic-gate default:
2507c478bd9Sstevel@tonic-gate av1394_ir_free_isoch_dma(icp);
2517c478bd9Sstevel@tonic-gate /* FALLTHRU */
2527c478bd9Sstevel@tonic-gate case 3:
2537c478bd9Sstevel@tonic-gate av1394_ir_destroy_ixl(icp);
2547c478bd9Sstevel@tonic-gate /* FALLTHRU */
2557c478bd9Sstevel@tonic-gate case 2:
2567c478bd9Sstevel@tonic-gate av1394_ic_dma_cleanup(icp, pool);
2577c478bd9Sstevel@tonic-gate /* FALLTHRU */
2587c478bd9Sstevel@tonic-gate case 1:
2597c478bd9Sstevel@tonic-gate av1394_ic_free_pool(pool);
2607c478bd9Sstevel@tonic-gate /* FALLTHRU */
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate * av1394_ir_build_ixl()
2667c478bd9Sstevel@tonic-gate * Build an IXL chain to receive CIP data. The smallest instance of data
2677c478bd9Sstevel@tonic-gate * that can be received is a packet, typically 512 bytes. Frames consist
2687c478bd9Sstevel@tonic-gate * of a number of packets, typically 250-300. Packet size, frame size and
2697c478bd9Sstevel@tonic-gate * number of frames allocated are set by a user process. The received data
2707c478bd9Sstevel@tonic-gate * made available to the user process in full frames, hence there an IXL
2717c478bd9Sstevel@tonic-gate * callback at the end of each frame. A sequence of IXL commands that
2727c478bd9Sstevel@tonic-gate * receives one frame is further referred to as an IXL data block.
2737c478bd9Sstevel@tonic-gate *
2747c478bd9Sstevel@tonic-gate * During normal operation, frames are in a circular list and IXL chain
2757c478bd9Sstevel@tonic-gate * does not change. When the user process does not keep up with the
2767c478bd9Sstevel@tonic-gate * data flow and there are too few empty frames left, the jump following
2777c478bd9Sstevel@tonic-gate * last empty frame is dynamically updated to point to NULL -- otherwise
2787c478bd9Sstevel@tonic-gate * the first full frame would be overwritten. When IXL execution reaches
2797c478bd9Sstevel@tonic-gate * the nulled jump, it just waits until the driver updates it again or
2807c478bd9Sstevel@tonic-gate * stops the transfer. Once a user process frees up enough frames, the
2817c478bd9Sstevel@tonic-gate * jump is restored and transfer continues. User process will be able to
2827c478bd9Sstevel@tonic-gate * detect dropped packets using continuity conters embedded in the data.
2837c478bd9Sstevel@tonic-gate *
2847c478bd9Sstevel@tonic-gate * Because RECV_BUF buffer size is limited to AV1394_IXL_BUFSZ_MAX, and due
2857c478bd9Sstevel@tonic-gate * to isoch pool segmentaion, the number of RECV_BUF commands per IXL data
2867c478bd9Sstevel@tonic-gate * block depends on frame size. Also, to simplify calculations, we consider
2877c478bd9Sstevel@tonic-gate * a sequence of RECV_BUF commands to consist of two parts: zero or more
2887c478bd9Sstevel@tonic-gate * equal-sized RECV_BUF commands followed by one "tail" REC_BUF command,
2897c478bd9Sstevel@tonic-gate * whose size may not be equal to others.
2907c478bd9Sstevel@tonic-gate *
2917c478bd9Sstevel@tonic-gate * Schematically the IXL chain looks like this:
2927c478bd9Sstevel@tonic-gate *
2937c478bd9Sstevel@tonic-gate * ...
2947c478bd9Sstevel@tonic-gate * LABEL N;
2957c478bd9Sstevel@tonic-gate * RECV_BUF(buf)
2967c478bd9Sstevel@tonic-gate * ...
2977c478bd9Sstevel@tonic-gate * RECV_BUF(tail)
2987c478bd9Sstevel@tonic-gate * CALLBACK(frame done);
2997c478bd9Sstevel@tonic-gate * JUMP_U(LABEL (N+1)%nframes or NULL);
3007c478bd9Sstevel@tonic-gate * ...
3017c478bd9Sstevel@tonic-gate */
3027c478bd9Sstevel@tonic-gate static int
av1394_ir_build_ixl(av1394_ic_t * icp)3037c478bd9Sstevel@tonic-gate av1394_ir_build_ixl(av1394_ic_t *icp)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate av1394_ir_t *irp = &icp->ic_ir;
3067c478bd9Sstevel@tonic-gate av1394_isoch_pool_t *pool = &irp->ir_data_pool;
30747cd5876SAlan Perry int i; /* segment index */
30847cd5876SAlan Perry int j;
30947cd5876SAlan Perry int fi; /* frame index */
31047cd5876SAlan Perry int bi; /* buffer index */
3117c478bd9Sstevel@tonic-gate
3127c478bd9Sstevel@tonic-gate /* allocate space for IXL data blocks */
3137c478bd9Sstevel@tonic-gate irp->ir_ixl_data = kmem_zalloc(icp->ic_nframes *
3147c478bd9Sstevel@tonic-gate sizeof (av1394_ir_ixl_data_t), KM_SLEEP);
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate /*
31747cd5876SAlan Perry * We have a bunch of segments, and each is divided into cookies. We
31847cd5876SAlan Perry * need to cover the segments with RECV_BUFs such that they
31947cd5876SAlan Perry * - don't span cookies
32047cd5876SAlan Perry * - don't span frames
32147cd5876SAlan Perry * - are at most AV1394_IXL_BUFSZ_MAX
32247cd5876SAlan Perry *
32347cd5876SAlan Perry * The straightforward algorithm is to start from the beginning, find
32447cd5876SAlan Perry * the next lowest frame or cookie boundary, and either make a buf for
32547cd5876SAlan Perry * it if it is smaller than AV1394_IXL_BUFSZ_MAX, or make multiple
32647cd5876SAlan Perry * bufs for it as with av1394_ic_ixl_seg_decomp(). And repeat.
3277c478bd9Sstevel@tonic-gate */
3287c478bd9Sstevel@tonic-gate
32947cd5876SAlan Perry irp->ir_ixl_nbufs = 0;
33047cd5876SAlan Perry for (i = 0; i < pool->ip_nsegs; ++i) {
33147cd5876SAlan Perry av1394_isoch_seg_t *isp = &pool->ip_seg[i];
33247cd5876SAlan Perry size_t dummy1, dummy2;
33347cd5876SAlan Perry
33447cd5876SAlan Perry uint_t off = 0;
33547cd5876SAlan Perry uint_t end;
33647cd5876SAlan Perry
33747cd5876SAlan Perry uint_t frame_end = icp->ic_framesz;
33847cd5876SAlan Perry int ci = 0;
33947cd5876SAlan Perry uint_t cookie_end = isp->is_dma_cookie[ci].dmac_size;
34047cd5876SAlan Perry
34147cd5876SAlan Perry for (;;) {
34247cd5876SAlan Perry end = min(frame_end, cookie_end);
34347cd5876SAlan Perry
34447cd5876SAlan Perry if (end - off <= AV1394_IXL_BUFSZ_MAX) {
34547cd5876SAlan Perry ++irp->ir_ixl_nbufs;
3467c478bd9Sstevel@tonic-gate } else {
34747cd5876SAlan Perry irp->ir_ixl_nbufs += av1394_ic_ixl_seg_decomp(
34847cd5876SAlan Perry end - off, icp->ic_pktsz, &dummy1, &dummy2);
34947cd5876SAlan Perry /* count the tail buffer */
35047cd5876SAlan Perry ++irp->ir_ixl_nbufs;
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate
35347cd5876SAlan Perry off = end;
35447cd5876SAlan Perry if (off >= isp->is_size)
35547cd5876SAlan Perry break;
35647cd5876SAlan Perry
35747cd5876SAlan Perry if (off == frame_end)
35847cd5876SAlan Perry frame_end += icp->ic_framesz;
35947cd5876SAlan Perry if (off == cookie_end) {
36047cd5876SAlan Perry ++ci;
36147cd5876SAlan Perry cookie_end += isp->is_dma_cookie[ci].dmac_size;
36247cd5876SAlan Perry }
36347cd5876SAlan Perry }
36447cd5876SAlan Perry }
36547cd5876SAlan Perry
3667c478bd9Sstevel@tonic-gate irp->ir_ixl_buf = kmem_zalloc(irp->ir_ixl_nbufs *
3677c478bd9Sstevel@tonic-gate sizeof (ixl1394_xfer_buf_t), KM_SLEEP);
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate
37047cd5876SAlan Perry fi = 0;
37147cd5876SAlan Perry bi = 0;
3727c478bd9Sstevel@tonic-gate
37347cd5876SAlan Perry for (i = 0; i < pool->ip_nsegs; ++i) {
37447cd5876SAlan Perry av1394_isoch_seg_t *isp = &pool->ip_seg[i];
3757c478bd9Sstevel@tonic-gate
37647cd5876SAlan Perry uint_t off = 0; /* offset into segment */
37747cd5876SAlan Perry uint_t end;
37847cd5876SAlan Perry uint_t coff = 0; /* offset into cookie */
37947cd5876SAlan Perry
38047cd5876SAlan Perry
38147cd5876SAlan Perry uint_t frame_end = icp->ic_framesz;
38247cd5876SAlan Perry int ci = 0;
38347cd5876SAlan Perry uint_t cookie_end = isp->is_dma_cookie[ci].dmac_size;
38447cd5876SAlan Perry
38547cd5876SAlan Perry ixl1394_command_t *nextp;
38647cd5876SAlan Perry
38747cd5876SAlan Perry av1394_ir_ixl_label_init(&irp->ir_ixl_data[fi],
38847cd5876SAlan Perry (ixl1394_command_t *)&irp->ir_ixl_buf[bi]);
38947cd5876SAlan Perry
39047cd5876SAlan Perry for (;;) {
39147cd5876SAlan Perry end = min(frame_end, cookie_end);
39247cd5876SAlan Perry
39347cd5876SAlan Perry if (end == frame_end)
39447cd5876SAlan Perry nextp = (ixl1394_command_t *)
39547cd5876SAlan Perry &irp->ir_ixl_data[fi].rd_cb;
39647cd5876SAlan Perry else
39747cd5876SAlan Perry nextp = (ixl1394_command_t *)
39847cd5876SAlan Perry &irp->ir_ixl_buf[bi + 1];
39947cd5876SAlan Perry
40047cd5876SAlan Perry if (end - off <= AV1394_IXL_BUFSZ_MAX) {
40147cd5876SAlan Perry av1394_ir_ixl_buf_init(icp,
40247cd5876SAlan Perry &irp->ir_ixl_buf[bi], isp, off,
40347cd5876SAlan Perry isp->is_dma_cookie[ci].dmac_laddress + coff,
40447cd5876SAlan Perry end - off, nextp);
40547cd5876SAlan Perry coff += end - off;
40647cd5876SAlan Perry off = end;
40747cd5876SAlan Perry ++bi;
4087c478bd9Sstevel@tonic-gate } else {
40947cd5876SAlan Perry size_t reg, tail;
41047cd5876SAlan Perry uint_t nbufs;
41147cd5876SAlan Perry
41247cd5876SAlan Perry nbufs = av1394_ic_ixl_seg_decomp(end - off,
41347cd5876SAlan Perry icp->ic_pktsz, ®, &tail);
41447cd5876SAlan Perry
41547cd5876SAlan Perry for (j = 0; j < nbufs; ++j) {
41647cd5876SAlan Perry av1394_ir_ixl_buf_init(icp,
41747cd5876SAlan Perry &irp->ir_ixl_buf[bi], isp, off,
41847cd5876SAlan Perry isp->is_dma_cookie[ci].
41947cd5876SAlan Perry dmac_laddress + coff, reg,
42047cd5876SAlan Perry (ixl1394_command_t *)
42147cd5876SAlan Perry &irp->ir_ixl_buf[bi + 1]);
42247cd5876SAlan Perry ++bi;
42347cd5876SAlan Perry off += reg;
42447cd5876SAlan Perry coff += reg;
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate
42747cd5876SAlan Perry av1394_ir_ixl_buf_init(icp,
42847cd5876SAlan Perry &irp->ir_ixl_buf[bi], isp, off,
42947cd5876SAlan Perry isp->is_dma_cookie[ci].dmac_laddress + coff,
43047cd5876SAlan Perry tail, nextp);
43147cd5876SAlan Perry ++bi;
43247cd5876SAlan Perry off += tail;
43347cd5876SAlan Perry coff += tail;
4347c478bd9Sstevel@tonic-gate }
4357c478bd9Sstevel@tonic-gate
43647cd5876SAlan Perry ASSERT((off == frame_end) || (off == cookie_end));
43747cd5876SAlan Perry
43847cd5876SAlan Perry if (off >= isp->is_size)
43947cd5876SAlan Perry break;
44047cd5876SAlan Perry
44147cd5876SAlan Perry if (off == frame_end) {
44247cd5876SAlan Perry av1394_ir_ixl_cb_init(icp,
44347cd5876SAlan Perry &irp->ir_ixl_data[fi], fi);
44447cd5876SAlan Perry av1394_ir_ixl_jump_init(icp,
44547cd5876SAlan Perry &irp->ir_ixl_data[fi], fi);
44647cd5876SAlan Perry ++fi;
44747cd5876SAlan Perry frame_end += icp->ic_framesz;
44847cd5876SAlan Perry av1394_ir_ixl_label_init(&irp->ir_ixl_data[fi],
44947cd5876SAlan Perry (ixl1394_command_t *)&irp->ir_ixl_buf[bi]);
45047cd5876SAlan Perry }
45147cd5876SAlan Perry
45247cd5876SAlan Perry if (off == cookie_end) {
45347cd5876SAlan Perry ++ci;
45447cd5876SAlan Perry cookie_end += isp->is_dma_cookie[ci].dmac_size;
45547cd5876SAlan Perry coff = 0;
45647cd5876SAlan Perry }
45747cd5876SAlan Perry }
45847cd5876SAlan Perry
45947cd5876SAlan Perry av1394_ir_ixl_cb_init(icp, &irp->ir_ixl_data[fi], fi);
46047cd5876SAlan Perry av1394_ir_ixl_jump_init(icp, &irp->ir_ixl_data[fi], fi);
46147cd5876SAlan Perry ++fi;
46247cd5876SAlan Perry }
46347cd5876SAlan Perry
46447cd5876SAlan Perry ASSERT(fi == icp->ic_nframes);
46547cd5876SAlan Perry ASSERT(bi == irp->ir_ixl_nbufs);
46647cd5876SAlan Perry
4677c478bd9Sstevel@tonic-gate irp->ir_ixlp = (ixl1394_command_t *)irp->ir_ixl_data;
4687c478bd9Sstevel@tonic-gate
4697c478bd9Sstevel@tonic-gate if (av1394_ir_dump_ixl) {
4707c478bd9Sstevel@tonic-gate av1394_ic_ixl_dump(irp->ir_ixlp);
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate static void
av1394_ir_ixl_label_init(av1394_ir_ixl_data_t * dp,ixl1394_command_t * nextp)4777c478bd9Sstevel@tonic-gate av1394_ir_ixl_label_init(av1394_ir_ixl_data_t *dp, ixl1394_command_t *nextp)
4787c478bd9Sstevel@tonic-gate {
4797c478bd9Sstevel@tonic-gate dp->rd_label.ixl_opcode = IXL1394_OP_LABEL;
4807c478bd9Sstevel@tonic-gate dp->rd_label.next_ixlp = nextp;
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate
4837c478bd9Sstevel@tonic-gate static void
av1394_ir_ixl_buf_init(av1394_ic_t * icp,ixl1394_xfer_buf_t * buf,av1394_isoch_seg_t * isp,off_t offset,uint64_t addr,uint16_t size,ixl1394_command_t * nextp)4847c478bd9Sstevel@tonic-gate av1394_ir_ixl_buf_init(av1394_ic_t *icp, ixl1394_xfer_buf_t *buf,
48547cd5876SAlan Perry av1394_isoch_seg_t *isp, off_t offset, uint64_t addr, uint16_t size,
4867c478bd9Sstevel@tonic-gate ixl1394_command_t *nextp)
4877c478bd9Sstevel@tonic-gate {
4887c478bd9Sstevel@tonic-gate buf->ixl_opcode = IXL1394_OP_RECV_BUF;
4897c478bd9Sstevel@tonic-gate buf->size = size;
4907c478bd9Sstevel@tonic-gate buf->pkt_size = icp->ic_pktsz;
49147cd5876SAlan Perry buf->ixl_buf._dmac_ll = addr;
4927c478bd9Sstevel@tonic-gate buf->mem_bufp = isp->is_kaddr + offset;
4937c478bd9Sstevel@tonic-gate buf->next_ixlp = nextp;
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4977c478bd9Sstevel@tonic-gate static void
av1394_ir_ixl_cb_init(av1394_ic_t * icp,av1394_ir_ixl_data_t * dp,int i)4987c478bd9Sstevel@tonic-gate av1394_ir_ixl_cb_init(av1394_ic_t *icp, av1394_ir_ixl_data_t *dp, int i)
4997c478bd9Sstevel@tonic-gate {
5007c478bd9Sstevel@tonic-gate dp->rd_cb.ixl_opcode = IXL1394_OP_CALLBACK;
5017c478bd9Sstevel@tonic-gate dp->rd_cb.callback = av1394_ir_ixl_frame_cb;
5027c478bd9Sstevel@tonic-gate dp->rd_cb.callback_arg = (void *)(intptr_t)i;
5037c478bd9Sstevel@tonic-gate dp->rd_cb.next_ixlp = (ixl1394_command_t *)&dp->rd_jump;
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate
5067c478bd9Sstevel@tonic-gate static void
av1394_ir_ixl_jump_init(av1394_ic_t * icp,av1394_ir_ixl_data_t * dp,int i)5077c478bd9Sstevel@tonic-gate av1394_ir_ixl_jump_init(av1394_ic_t *icp, av1394_ir_ixl_data_t *dp, int i)
5087c478bd9Sstevel@tonic-gate {
5097c478bd9Sstevel@tonic-gate av1394_ir_t *irp = &icp->ic_ir;
5107c478bd9Sstevel@tonic-gate int next_idx;
5117c478bd9Sstevel@tonic-gate ixl1394_command_t *jump_cmd;
5127c478bd9Sstevel@tonic-gate
5137c478bd9Sstevel@tonic-gate next_idx = (i + 1) % icp->ic_nframes;
5147c478bd9Sstevel@tonic-gate jump_cmd = (ixl1394_command_t *)&irp->ir_ixl_data[next_idx];
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate dp->rd_jump.ixl_opcode = IXL1394_OP_JUMP_U;
5177c478bd9Sstevel@tonic-gate dp->rd_jump.label = jump_cmd;
5187c478bd9Sstevel@tonic-gate dp->rd_jump.next_ixlp = (next_idx != 0) ? jump_cmd : NULL;
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate
5217c478bd9Sstevel@tonic-gate static void
av1394_ir_destroy_ixl(av1394_ic_t * icp)5227c478bd9Sstevel@tonic-gate av1394_ir_destroy_ixl(av1394_ic_t *icp)
5237c478bd9Sstevel@tonic-gate {
5247c478bd9Sstevel@tonic-gate av1394_ir_t *irp = &icp->ic_ir;
5257c478bd9Sstevel@tonic-gate
5267c478bd9Sstevel@tonic-gate mutex_enter(&icp->ic_mutex);
5277c478bd9Sstevel@tonic-gate kmem_free(irp->ir_ixl_buf,
5287c478bd9Sstevel@tonic-gate irp->ir_ixl_nbufs * sizeof (ixl1394_xfer_buf_t));
5297c478bd9Sstevel@tonic-gate kmem_free(irp->ir_ixl_data,
5307c478bd9Sstevel@tonic-gate icp->ic_nframes * sizeof (av1394_ir_ixl_data_t));
5317c478bd9Sstevel@tonic-gate
5327c478bd9Sstevel@tonic-gate irp->ir_ixlp = NULL;
5337c478bd9Sstevel@tonic-gate irp->ir_ixl_buf = NULL;
5347c478bd9Sstevel@tonic-gate irp->ir_ixl_data = NULL;
5357c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate
5387c478bd9Sstevel@tonic-gate static int
av1394_ir_alloc_isoch_dma(av1394_ic_t * icp)5397c478bd9Sstevel@tonic-gate av1394_ir_alloc_isoch_dma(av1394_ic_t *icp)
5407c478bd9Sstevel@tonic-gate {
5417c478bd9Sstevel@tonic-gate av1394_inst_t *avp = icp->ic_avp;
5427c478bd9Sstevel@tonic-gate av1394_ir_t *irp = &icp->ic_ir;
5437c478bd9Sstevel@tonic-gate id1394_isoch_dmainfo_t di;
5447c478bd9Sstevel@tonic-gate int result;
5457c478bd9Sstevel@tonic-gate int ret;
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gate di.ixlp = irp->ir_ixlp;
5487c478bd9Sstevel@tonic-gate di.channel_num = icp->ic_num;
5497c478bd9Sstevel@tonic-gate di.global_callback_arg = icp;
5507c478bd9Sstevel@tonic-gate di.idma_options = ID1394_LISTEN_PKT_MODE;
5517c478bd9Sstevel@tonic-gate di.isoch_dma_stopped = av1394_ir_dma_stopped_cb;
5527c478bd9Sstevel@tonic-gate di.idma_evt_arg = icp;
5537c478bd9Sstevel@tonic-gate
554*2570281cSToomas Soome ret = t1394_alloc_isoch_dma(avp->av_t1394_hdl, &di, 0,
555*2570281cSToomas Soome &icp->ic_isoch_hdl, &result);
5567c478bd9Sstevel@tonic-gate
5577c478bd9Sstevel@tonic-gate return (ret);
5587c478bd9Sstevel@tonic-gate }
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate static void
av1394_ir_free_isoch_dma(av1394_ic_t * icp)5617c478bd9Sstevel@tonic-gate av1394_ir_free_isoch_dma(av1394_ic_t *icp)
5627c478bd9Sstevel@tonic-gate {
5637c478bd9Sstevel@tonic-gate av1394_inst_t *avp = icp->ic_avp;
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate t1394_free_isoch_dma(avp->av_t1394_hdl, 0, &icp->ic_isoch_hdl);
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate
5687c478bd9Sstevel@tonic-gate static void
av1394_ir_dma_sync_frames(av1394_ic_t * icp,int idx,int cnt)5697c478bd9Sstevel@tonic-gate av1394_ir_dma_sync_frames(av1394_ic_t *icp, int idx, int cnt)
5707c478bd9Sstevel@tonic-gate {
5717c478bd9Sstevel@tonic-gate av1394_ic_dma_sync_frames(icp, idx, cnt,
5727c478bd9Sstevel@tonic-gate &icp->ic_ir.ir_data_pool, DDI_DMA_SYNC_FORCPU);
5737c478bd9Sstevel@tonic-gate }
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate /*
5767c478bd9Sstevel@tonic-gate *
5777c478bd9Sstevel@tonic-gate * --- callbacks
5787c478bd9Sstevel@tonic-gate *
5797c478bd9Sstevel@tonic-gate */
5807c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5817c478bd9Sstevel@tonic-gate static void
av1394_ir_ixl_frame_cb(opaque_t arg,struct ixl1394_callback * cb)5827c478bd9Sstevel@tonic-gate av1394_ir_ixl_frame_cb(opaque_t arg, struct ixl1394_callback *cb)
5837c478bd9Sstevel@tonic-gate {
5847c478bd9Sstevel@tonic-gate av1394_ic_t *icp = arg;
5857c478bd9Sstevel@tonic-gate av1394_isoch_t *ip = &icp->ic_avp->av_i;
5867c478bd9Sstevel@tonic-gate av1394_ir_t *irp = &icp->ic_ir;
5877c478bd9Sstevel@tonic-gate
5887c478bd9Sstevel@tonic-gate mutex_enter(&ip->i_mutex);
5897c478bd9Sstevel@tonic-gate mutex_enter(&icp->ic_mutex);
5907c478bd9Sstevel@tonic-gate if (irp->ir_nfull < icp->ic_nframes) {
5917c478bd9Sstevel@tonic-gate irp->ir_nfull++;
5927c478bd9Sstevel@tonic-gate irp->ir_nempty--;
5937c478bd9Sstevel@tonic-gate cv_broadcast(&icp->ic_xfer_cv);
5947c478bd9Sstevel@tonic-gate
5957c478bd9Sstevel@tonic-gate /*
5967c478bd9Sstevel@tonic-gate * signal the overflow condition early, so we get enough
5977c478bd9Sstevel@tonic-gate * time to handle it before old data is overwritten
5987c478bd9Sstevel@tonic-gate */
5997c478bd9Sstevel@tonic-gate if (irp->ir_nfull >= irp->ir_hiwat) {
6007c478bd9Sstevel@tonic-gate av1394_ic_trigger_softintr(icp, icp->ic_num,
6017c478bd9Sstevel@tonic-gate AV1394_PREQ_IR_OVERFLOW);
6027c478bd9Sstevel@tonic-gate }
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
6057c478bd9Sstevel@tonic-gate mutex_exit(&ip->i_mutex);
6067c478bd9Sstevel@tonic-gate }
6077c478bd9Sstevel@tonic-gate
6087c478bd9Sstevel@tonic-gate /*
6097c478bd9Sstevel@tonic-gate * received data overflow
6107c478bd9Sstevel@tonic-gate */
6117c478bd9Sstevel@tonic-gate void
av1394_ir_overflow(av1394_ic_t * icp)6127c478bd9Sstevel@tonic-gate av1394_ir_overflow(av1394_ic_t *icp)
6137c478bd9Sstevel@tonic-gate {
6147c478bd9Sstevel@tonic-gate av1394_inst_t *avp = icp->ic_avp;
6157c478bd9Sstevel@tonic-gate av1394_ir_t *irp = &icp->ic_ir;
6167c478bd9Sstevel@tonic-gate int idx;
6177c478bd9Sstevel@tonic-gate ixl1394_jump_t *old_jmp;
6187c478bd9Sstevel@tonic-gate ixl1394_jump_t new_jmp;
6197c478bd9Sstevel@tonic-gate id1394_isoch_dma_updateinfo_t update_info;
6207c478bd9Sstevel@tonic-gate int err;
6217c478bd9Sstevel@tonic-gate int result;
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate /*
6247c478bd9Sstevel@tonic-gate * in the circular IXL chain overflow means overwriting the least
6257c478bd9Sstevel@tonic-gate * recent data. to avoid that, we suspend the transfer by NULL'ing
6267c478bd9Sstevel@tonic-gate * the last IXL block until the user process frees up some frames.
6277c478bd9Sstevel@tonic-gate */
6287c478bd9Sstevel@tonic-gate idx = irp->ir_last_empty;
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate old_jmp = &irp->ir_ixl_data[idx].rd_jump;
6317c478bd9Sstevel@tonic-gate
6327c478bd9Sstevel@tonic-gate new_jmp.ixl_opcode = IXL1394_OP_JUMP_U;
6337c478bd9Sstevel@tonic-gate new_jmp.label = NULL;
6347c478bd9Sstevel@tonic-gate new_jmp.next_ixlp = NULL;
6357c478bd9Sstevel@tonic-gate
6367c478bd9Sstevel@tonic-gate update_info.orig_ixlp = (ixl1394_command_t *)old_jmp;
6377c478bd9Sstevel@tonic-gate update_info.temp_ixlp = (ixl1394_command_t *)&new_jmp;
6387c478bd9Sstevel@tonic-gate update_info.ixl_count = 1;
6397c478bd9Sstevel@tonic-gate
6407c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
6417c478bd9Sstevel@tonic-gate err = t1394_update_isoch_dma(avp->av_t1394_hdl, icp->ic_isoch_hdl,
6427c478bd9Sstevel@tonic-gate &update_info, 0, &result);
6437c478bd9Sstevel@tonic-gate mutex_enter(&icp->ic_mutex);
6447c478bd9Sstevel@tonic-gate
6457c478bd9Sstevel@tonic-gate if (err == DDI_SUCCESS) {
6467c478bd9Sstevel@tonic-gate irp->ir_overflow_idx = idx;
6477c478bd9Sstevel@tonic-gate icp->ic_state = AV1394_IC_SUSPENDED;
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate /*
6527c478bd9Sstevel@tonic-gate * restore from overflow condition
6537c478bd9Sstevel@tonic-gate */
6547c478bd9Sstevel@tonic-gate static void
av1394_ir_overflow_resume(av1394_ic_t * icp)6557c478bd9Sstevel@tonic-gate av1394_ir_overflow_resume(av1394_ic_t *icp)
6567c478bd9Sstevel@tonic-gate {
6577c478bd9Sstevel@tonic-gate av1394_inst_t *avp = icp->ic_avp;
6587c478bd9Sstevel@tonic-gate av1394_ir_t *irp = &icp->ic_ir;
6597c478bd9Sstevel@tonic-gate int idx, next_idx;
6607c478bd9Sstevel@tonic-gate ixl1394_jump_t *old_jmp;
6617c478bd9Sstevel@tonic-gate ixl1394_jump_t new_jmp;
6627c478bd9Sstevel@tonic-gate id1394_isoch_dma_updateinfo_t update_info;
6637c478bd9Sstevel@tonic-gate int err;
6647c478bd9Sstevel@tonic-gate int result;
6657c478bd9Sstevel@tonic-gate
6667c478bd9Sstevel@tonic-gate /*
6677c478bd9Sstevel@tonic-gate * restore the jump command we NULL'ed in av1394_ir_overflow()
6687c478bd9Sstevel@tonic-gate */
6697c478bd9Sstevel@tonic-gate idx = irp->ir_overflow_idx;
6707c478bd9Sstevel@tonic-gate next_idx = (idx + 1) % icp->ic_nframes;
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate old_jmp = &irp->ir_ixl_data[idx].rd_jump;
6737c478bd9Sstevel@tonic-gate
6747c478bd9Sstevel@tonic-gate new_jmp.ixl_opcode = IXL1394_OP_JUMP_U;
6757c478bd9Sstevel@tonic-gate new_jmp.label = (ixl1394_command_t *)&irp->ir_ixl_data[next_idx];
6767c478bd9Sstevel@tonic-gate new_jmp.next_ixlp = NULL;
6777c478bd9Sstevel@tonic-gate
6787c478bd9Sstevel@tonic-gate update_info.orig_ixlp = (ixl1394_command_t *)old_jmp;
6797c478bd9Sstevel@tonic-gate update_info.temp_ixlp = (ixl1394_command_t *)&new_jmp;
6807c478bd9Sstevel@tonic-gate update_info.ixl_count = 1;
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
6837c478bd9Sstevel@tonic-gate err = t1394_update_isoch_dma(avp->av_t1394_hdl,
6847c478bd9Sstevel@tonic-gate icp->ic_isoch_hdl, &update_info, 0, &result);
6857c478bd9Sstevel@tonic-gate mutex_enter(&icp->ic_mutex);
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate if (err == DDI_SUCCESS) {
6887c478bd9Sstevel@tonic-gate icp->ic_state = AV1394_IC_DMA;
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate }
6917c478bd9Sstevel@tonic-gate
6927c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6937c478bd9Sstevel@tonic-gate static void
av1394_ir_dma_stopped_cb(t1394_isoch_dma_handle_t t1394_idma_hdl,opaque_t idma_evt_arg,id1394_isoch_dma_stopped_t status)6947c478bd9Sstevel@tonic-gate av1394_ir_dma_stopped_cb(t1394_isoch_dma_handle_t t1394_idma_hdl,
6957c478bd9Sstevel@tonic-gate opaque_t idma_evt_arg, id1394_isoch_dma_stopped_t status)
6967c478bd9Sstevel@tonic-gate {
6977c478bd9Sstevel@tonic-gate av1394_ic_t *icp = idma_evt_arg;
6987c478bd9Sstevel@tonic-gate
6997c478bd9Sstevel@tonic-gate mutex_enter(&icp->ic_mutex);
7007c478bd9Sstevel@tonic-gate icp->ic_state = AV1394_IC_IDLE;
7017c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
7027c478bd9Sstevel@tonic-gate }
7037c478bd9Sstevel@tonic-gate
7047c478bd9Sstevel@tonic-gate
7057c478bd9Sstevel@tonic-gate /*
7067c478bd9Sstevel@tonic-gate *
7077c478bd9Sstevel@tonic-gate * --- data transfer routines
7087c478bd9Sstevel@tonic-gate *
7097c478bd9Sstevel@tonic-gate * av1394_ir_add_frames()
7107c478bd9Sstevel@tonic-gate * Add empty frames to the pool.
7117c478bd9Sstevel@tonic-gate */
7127c478bd9Sstevel@tonic-gate static int
av1394_ir_add_frames(av1394_ic_t * icp,int idx,int cnt)7137c478bd9Sstevel@tonic-gate av1394_ir_add_frames(av1394_ic_t *icp, int idx, int cnt)
7147c478bd9Sstevel@tonic-gate {
7157c478bd9Sstevel@tonic-gate av1394_ir_t *irp = &icp->ic_ir;
7167c478bd9Sstevel@tonic-gate
7177c478bd9Sstevel@tonic-gate /* can only add to the tail */
7187c478bd9Sstevel@tonic-gate if (idx != ((irp->ir_last_empty + 1) % icp->ic_nframes)) {
7197c478bd9Sstevel@tonic-gate return (EINVAL);
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate
7227c478bd9Sstevel@tonic-gate /* turn full frames into empty ones */
7237c478bd9Sstevel@tonic-gate irp->ir_nfull -= cnt;
7247c478bd9Sstevel@tonic-gate irp->ir_first_full = (irp->ir_first_full + cnt) % icp->ic_nframes;
7257c478bd9Sstevel@tonic-gate irp->ir_nempty += cnt;
7267c478bd9Sstevel@tonic-gate irp->ir_last_empty = (irp->ir_last_empty + cnt) % icp->ic_nframes;
7277c478bd9Sstevel@tonic-gate ASSERT((irp->ir_nfull >= 0) && (irp->ir_nempty <= icp->ic_nframes));
7287c478bd9Sstevel@tonic-gate
7297c478bd9Sstevel@tonic-gate /* if suspended due to overflow, check if iwe can resume */
7307c478bd9Sstevel@tonic-gate if ((icp->ic_state == AV1394_IC_SUSPENDED) &&
7317c478bd9Sstevel@tonic-gate (irp->ir_nempty >= irp->ir_lowat)) {
7327c478bd9Sstevel@tonic-gate av1394_ir_overflow_resume(icp);
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate
7357c478bd9Sstevel@tonic-gate return (0);
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate
7387c478bd9Sstevel@tonic-gate static int
av1394_ir_wait_frames(av1394_ic_t * icp,int * idx,int * cnt)7397c478bd9Sstevel@tonic-gate av1394_ir_wait_frames(av1394_ic_t *icp, int *idx, int *cnt)
7407c478bd9Sstevel@tonic-gate {
7417c478bd9Sstevel@tonic-gate av1394_ir_t *irp = &icp->ic_ir;
7427c478bd9Sstevel@tonic-gate int ret = 0;
7437c478bd9Sstevel@tonic-gate
7447c478bd9Sstevel@tonic-gate while (irp->ir_nfull == 0) {
7457c478bd9Sstevel@tonic-gate if (cv_wait_sig(&icp->ic_xfer_cv, &icp->ic_mutex) <= 0) {
7467c478bd9Sstevel@tonic-gate ret = EINTR;
7477c478bd9Sstevel@tonic-gate break;
7487c478bd9Sstevel@tonic-gate }
7497c478bd9Sstevel@tonic-gate }
7507c478bd9Sstevel@tonic-gate if (irp->ir_nfull > 0) {
7517c478bd9Sstevel@tonic-gate *idx = irp->ir_first_full;
7527c478bd9Sstevel@tonic-gate *cnt = irp->ir_nfull;
7537c478bd9Sstevel@tonic-gate av1394_ir_dma_sync_frames(icp, *idx, *cnt);
7547c478bd9Sstevel@tonic-gate ret = 0;
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate return (ret);
7577c478bd9Sstevel@tonic-gate }
7587c478bd9Sstevel@tonic-gate
7597c478bd9Sstevel@tonic-gate /*
7607c478bd9Sstevel@tonic-gate * copyout the data, adjust to data format and remove empty CIPs if possible
7617c478bd9Sstevel@tonic-gate */
7627c478bd9Sstevel@tonic-gate static int
av1394_ir_copyout(av1394_ic_t * icp,struct uio * uiop,int * empty_cnt)7637c478bd9Sstevel@tonic-gate av1394_ir_copyout(av1394_ic_t *icp, struct uio *uiop, int *empty_cnt)
7647c478bd9Sstevel@tonic-gate {
7657c478bd9Sstevel@tonic-gate av1394_ir_t *irp = &icp->ic_ir;
7667c478bd9Sstevel@tonic-gate av1394_isoch_seg_t *seg = irp->ir_data_pool.ip_seg;
7677c478bd9Sstevel@tonic-gate int idx = irp->ir_read_idx;
7687c478bd9Sstevel@tonic-gate int cnt = irp->ir_read_cnt;
7697c478bd9Sstevel@tonic-gate int pktsz = icp->ic_pktsz;
7707c478bd9Sstevel@tonic-gate int bs; /* data block size */
7717c478bd9Sstevel@tonic-gate caddr_t kaddr_begin, kaddr;
7727c478bd9Sstevel@tonic-gate int pkt_off; /* offset into current packet */
7737c478bd9Sstevel@tonic-gate int len;
7747c478bd9Sstevel@tonic-gate int frame_resid; /* bytes left in the current frame */
7757c478bd9Sstevel@tonic-gate int ret = 0;
7767c478bd9Sstevel@tonic-gate
7777c478bd9Sstevel@tonic-gate *empty_cnt = 0;
7787c478bd9Sstevel@tonic-gate
7797c478bd9Sstevel@tonic-gate /* DBS -> block size */
7807c478bd9Sstevel@tonic-gate bs = *(uchar_t *)(seg[idx].is_kaddr + 1) * 4 + AV1394_CIPSZ;
7817c478bd9Sstevel@tonic-gate if ((bs > pktsz) || (bs < AV1394_CIPSZ + 8)) {
7827c478bd9Sstevel@tonic-gate bs = pktsz;
7837c478bd9Sstevel@tonic-gate }
7847c478bd9Sstevel@tonic-gate
7857c478bd9Sstevel@tonic-gate while ((cnt > 0) && (uiop->uio_resid > 0) && (ret == 0)) {
7867c478bd9Sstevel@tonic-gate kaddr = kaddr_begin = seg[idx].is_kaddr + irp->ir_read_off;
7877c478bd9Sstevel@tonic-gate frame_resid = icp->ic_framesz - irp->ir_read_off;
7887c478bd9Sstevel@tonic-gate
7897c478bd9Sstevel@tonic-gate mutex_exit(&icp->ic_mutex);
7907c478bd9Sstevel@tonic-gate /* copyout data blocks, skipping empty CIPs */
7917c478bd9Sstevel@tonic-gate while ((uiop->uio_resid > 0) && (frame_resid > 0)) {
7927c478bd9Sstevel@tonic-gate pkt_off = (uintptr_t)kaddr % pktsz;
7937c478bd9Sstevel@tonic-gate /*
7947c478bd9Sstevel@tonic-gate * a quadlet following CIP header can't be zero
7957c478bd9Sstevel@tonic-gate * unless in an empty packet
7967c478bd9Sstevel@tonic-gate */
7977c478bd9Sstevel@tonic-gate if ((pkt_off == 0) &&
7987c478bd9Sstevel@tonic-gate (*(uint32_t *)(kaddr + AV1394_CIPSZ) == 0)) {
7997c478bd9Sstevel@tonic-gate kaddr += pktsz;
8007c478bd9Sstevel@tonic-gate frame_resid -= pktsz;
8017c478bd9Sstevel@tonic-gate continue;
8027c478bd9Sstevel@tonic-gate }
8037c478bd9Sstevel@tonic-gate
8047c478bd9Sstevel@tonic-gate len = bs - pkt_off;
8057c478bd9Sstevel@tonic-gate if (len > uiop->uio_resid) {
8067c478bd9Sstevel@tonic-gate len = uiop->uio_resid;
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate if (len > frame_resid) {
8097c478bd9Sstevel@tonic-gate len = frame_resid;
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate if ((ret = uiomove(kaddr, len, UIO_READ, uiop)) != 0) {
8127c478bd9Sstevel@tonic-gate break;
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate
8157c478bd9Sstevel@tonic-gate if (pkt_off + len == bs) {
8167c478bd9Sstevel@tonic-gate kaddr += pktsz - pkt_off;
8177c478bd9Sstevel@tonic-gate frame_resid -= pktsz - pkt_off;
8187c478bd9Sstevel@tonic-gate } else {
8197c478bd9Sstevel@tonic-gate kaddr += len;
8207c478bd9Sstevel@tonic-gate frame_resid -= len;
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate }
8237c478bd9Sstevel@tonic-gate mutex_enter(&icp->ic_mutex);
8247c478bd9Sstevel@tonic-gate
8257c478bd9Sstevel@tonic-gate if (frame_resid > 0) {
8267c478bd9Sstevel@tonic-gate irp->ir_read_off = kaddr - kaddr_begin;
8277c478bd9Sstevel@tonic-gate } else {
8287c478bd9Sstevel@tonic-gate irp->ir_read_off = 0;
8297c478bd9Sstevel@tonic-gate idx = (idx + 1) % icp->ic_nframes;
8307c478bd9Sstevel@tonic-gate cnt--;
8317c478bd9Sstevel@tonic-gate (*empty_cnt)++;
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate
8357c478bd9Sstevel@tonic-gate return (ret);
8367c478bd9Sstevel@tonic-gate }
8377c478bd9Sstevel@tonic-gate
8387c478bd9Sstevel@tonic-gate /*
8397c478bd9Sstevel@tonic-gate * zero a quadlet in each packet so we can recognize empty CIPs
8407c478bd9Sstevel@tonic-gate */
8417c478bd9Sstevel@tonic-gate static void
av1394_ir_zero_pkts(av1394_ic_t * icp,int idx,int cnt)8427c478bd9Sstevel@tonic-gate av1394_ir_zero_pkts(av1394_ic_t *icp, int idx, int cnt)
8437c478bd9Sstevel@tonic-gate {
8447c478bd9Sstevel@tonic-gate av1394_ir_t *irp = &icp->ic_ir;
8457c478bd9Sstevel@tonic-gate av1394_isoch_seg_t *seg = irp->ir_data_pool.ip_seg;
8467c478bd9Sstevel@tonic-gate caddr_t kaddr, kaddr_end;
8477c478bd9Sstevel@tonic-gate int pktsz = icp->ic_pktsz;
8487c478bd9Sstevel@tonic-gate int i;
8497c478bd9Sstevel@tonic-gate
8507c478bd9Sstevel@tonic-gate for (i = cnt; i > 0; i--) {
8517c478bd9Sstevel@tonic-gate kaddr = seg[idx].is_kaddr + AV1394_CIPSZ;
8527c478bd9Sstevel@tonic-gate kaddr_end = seg[idx].is_kaddr + icp->ic_framesz;
8537c478bd9Sstevel@tonic-gate do {
8547c478bd9Sstevel@tonic-gate *(uint32_t *)kaddr = 0;
8557c478bd9Sstevel@tonic-gate kaddr += pktsz;
8567c478bd9Sstevel@tonic-gate } while (kaddr < kaddr_end);
8577c478bd9Sstevel@tonic-gate
8587c478bd9Sstevel@tonic-gate idx = (idx + 1) % icp->ic_nframes;
8597c478bd9Sstevel@tonic-gate }
8607c478bd9Sstevel@tonic-gate }
861