xref: /titanic_50/usr/src/uts/common/io/1394/targets/av1394/av1394_isoch_recv.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  * av1394 isochronous receive module
28  */
29 #include <sys/1394/targets/av1394/av1394_impl.h>
30 
31 /* configuration routines */
32 static void	av1394_ir_cleanup(av1394_ic_t *, int);
33 static int	av1394_ir_build_ixl(av1394_ic_t *);
34 static void	av1394_ir_ixl_label_init(av1394_ir_ixl_data_t *,
35 		ixl1394_command_t *);
36 static void	av1394_ir_ixl_buf_init(av1394_ic_t *, ixl1394_xfer_buf_t *,
37 		av1394_isoch_seg_t *, off_t, uint64_t, uint16_t,
38 		ixl1394_command_t *);
39 static void	av1394_ir_ixl_cb_init(av1394_ic_t *, av1394_ir_ixl_data_t *,
40 		int);
41 static void	av1394_ir_ixl_jump_init(av1394_ic_t *, av1394_ir_ixl_data_t *,
42 		int);
43 static void	av1394_ir_destroy_ixl(av1394_ic_t *);
44 static int	av1394_ir_alloc_isoch_dma(av1394_ic_t *);
45 static void	av1394_ir_free_isoch_dma(av1394_ic_t *);
46 static void	av1394_ir_dma_sync_frames(av1394_ic_t *, int, int);
47 
48 /* callbacks */
49 static void	av1394_ir_ixl_frame_cb(opaque_t, struct ixl1394_callback *);
50 static void	av1394_ir_overflow_resume(av1394_ic_t *icp);
51 static void	av1394_ir_dma_stopped_cb(t1394_isoch_dma_handle_t,
52 		opaque_t, id1394_isoch_dma_stopped_t);
53 
54 /* data transfer routines */
55 static int	av1394_ir_add_frames(av1394_ic_t *, int, int);
56 static int	av1394_ir_wait_frames(av1394_ic_t *, int *, int *);
57 static int	av1394_ir_copyout(av1394_ic_t *, struct uio *, int *);
58 static void	av1394_ir_zero_pkts(av1394_ic_t *, int, int);
59 
60 /* value complementary to hi & lo watermarks (modulo number of frames) */
61 int av1394_ir_hiwat_sub = 2;
62 int av1394_ir_lowat_sub = 3;
63 int av1394_ir_dump_ixl = 0;
64 
65 #define	AV1394_TNF_ENTER(func)	\
66 	TNF_PROBE_0_DEBUG(func##_enter, AV1394_TNF_ISOCH_STACK, "");
67 
68 #define	AV1394_TNF_EXIT(func)	\
69 	TNF_PROBE_0_DEBUG(func##_exit, AV1394_TNF_ISOCH_STACK, "");
70 
71 int
av1394_ir_init(av1394_ic_t * icp,int * error)72 av1394_ir_init(av1394_ic_t *icp, int *error)
73 {
74 	av1394_ir_t	*irp = &icp->ic_ir;
75 	av1394_isoch_pool_t *pool = &irp->ir_data_pool;
76 	int		nframes;
77 
78 	AV1394_TNF_ENTER(av1394_ir_init);
79 
80 	nframes = av1394_ic_alloc_pool(pool, icp->ic_framesz, icp->ic_nframes,
81 	    AV1394_IR_NFRAMES_MIN);
82 	if (nframes == 0) {
83 		*error = IEC61883_ERR_NOMEM;
84 		AV1394_TNF_EXIT(av1394_ir_init);
85 		return (EINVAL);
86 	}
87 	mutex_enter(&icp->ic_mutex);
88 	icp->ic_nframes = nframes;
89 	irp->ir_hiwat = nframes - av1394_ir_hiwat_sub;
90 	irp->ir_lowat = nframes - av1394_ir_lowat_sub;
91 
92 	if (av1394_ic_dma_setup(icp, pool) != DDI_SUCCESS) {
93 		mutex_exit(&icp->ic_mutex);
94 		*error = IEC61883_ERR_NOMEM;
95 		av1394_ir_cleanup(icp, 1);
96 		AV1394_TNF_EXIT(av1394_ir_init);
97 		return (EINVAL);
98 	}
99 
100 	if (av1394_ir_build_ixl(icp) != DDI_SUCCESS) {
101 		mutex_exit(&icp->ic_mutex);
102 		*error = IEC61883_ERR_NOMEM;
103 		av1394_ir_cleanup(icp, 2);
104 		AV1394_TNF_EXIT(av1394_ir_init);
105 		return (EINVAL);
106 	}
107 	mutex_exit(&icp->ic_mutex);
108 
109 	if (av1394_ir_alloc_isoch_dma(icp) != DDI_SUCCESS) {
110 		*error = IEC61883_ERR_NOMEM;
111 		av1394_ir_cleanup(icp, 3);
112 		AV1394_TNF_EXIT(av1394_ir_init);
113 		return (EINVAL);
114 	}
115 
116 	AV1394_TNF_EXIT(av1394_ir_init);
117 	return (0);
118 }
119 
120 void
av1394_ir_fini(av1394_ic_t * icp)121 av1394_ir_fini(av1394_ic_t *icp)
122 {
123 	AV1394_TNF_ENTER(av1394_ir_fini);
124 
125 	av1394_ir_cleanup(icp, AV1394_CLEANUP_LEVEL_MAX);
126 
127 	AV1394_TNF_ENTER(av1394_ir_fini);
128 }
129 
130 int
av1394_ir_start(av1394_ic_t * icp)131 av1394_ir_start(av1394_ic_t *icp)
132 {
133 	av1394_inst_t	*avp = icp->ic_avp;
134 	av1394_ir_t	*irp = &icp->ic_ir;
135 	id1394_isoch_dma_ctrlinfo_t idma_ctrlinfo = { 0 };
136 	int		result;
137 	int		err;
138 	int		ret = 0;
139 
140 	AV1394_TNF_ENTER(av1394_ir_start);
141 
142 	mutex_enter(&icp->ic_mutex);
143 	if (icp->ic_state != AV1394_IC_IDLE) {
144 		mutex_exit(&icp->ic_mutex);
145 		return (0);
146 	}
147 
148 	irp->ir_first_full = 0;
149 	irp->ir_last_empty = icp->ic_nframes - 1;
150 	irp->ir_nfull = 0;
151 	irp->ir_nempty = icp->ic_nframes;
152 	irp->ir_read_cnt = 0;
153 	mutex_exit(&icp->ic_mutex);
154 
155 	err = t1394_start_isoch_dma(avp->av_t1394_hdl, icp->ic_isoch_hdl,
156 	    &idma_ctrlinfo, 0, &result);
157 	if (err == DDI_SUCCESS) {
158 		mutex_enter(&icp->ic_mutex);
159 		icp->ic_state = AV1394_IC_DMA;
160 		mutex_exit(&icp->ic_mutex);
161 	} else {
162 		TNF_PROBE_1(av1394_ir_start_error, AV1394_TNF_ISOCH_ERROR, "",
163 		    tnf_int, result, result);
164 		ret = EIO;
165 	}
166 
167 	AV1394_TNF_EXIT(av1394_ir_start);
168 	return (ret);
169 }
170 
171 int
av1394_ir_stop(av1394_ic_t * icp)172 av1394_ir_stop(av1394_ic_t *icp)
173 {
174 	av1394_inst_t	*avp = icp->ic_avp;
175 
176 	AV1394_TNF_ENTER(av1394_ir_stop);
177 
178 	mutex_enter(&icp->ic_mutex);
179 	if (icp->ic_state != AV1394_IC_IDLE) {
180 		mutex_exit(&icp->ic_mutex);
181 		t1394_stop_isoch_dma(avp->av_t1394_hdl, icp->ic_isoch_hdl, 0);
182 		mutex_enter(&icp->ic_mutex);
183 		icp->ic_state = AV1394_IC_IDLE;
184 	}
185 	mutex_exit(&icp->ic_mutex);
186 
187 	AV1394_TNF_EXIT(av1394_ir_stop);
188 	return (0);
189 }
190 
191 int
av1394_ir_recv(av1394_ic_t * icp,iec61883_recv_t * recv)192 av1394_ir_recv(av1394_ic_t *icp, iec61883_recv_t *recv)
193 {
194 	int		ret = 0;
195 	int		idx, cnt;
196 
197 	idx = recv->rx_xfer.xf_empty_idx;
198 	cnt = recv->rx_xfer.xf_empty_cnt;
199 
200 	/* check arguments */
201 	if ((idx < 0) || (idx >= icp->ic_nframes) ||
202 	    (cnt < 0) || (cnt > icp->ic_nframes)) {
203 		TNF_PROBE_2(av1394_ir_recv_error_args, AV1394_TNF_ISOCH_ERROR,
204 		    "", tnf_int, idx, idx, tnf_int, cnt, cnt);
205 		return (EINVAL);
206 	}
207 
208 	mutex_enter(&icp->ic_mutex);
209 	if (cnt > 0) {
210 		/* add empty frames to the pool */
211 		if ((ret = av1394_ir_add_frames(icp, idx, cnt)) != 0) {
212 			mutex_exit(&icp->ic_mutex);
213 			return (ret);
214 		}
215 	}
216 
217 	/* wait for new frames to arrive */
218 	ret = av1394_ir_wait_frames(icp,
219 	    &recv->rx_xfer.xf_full_idx, &recv->rx_xfer.xf_full_cnt);
220 	mutex_exit(&icp->ic_mutex);
221 
222 	return (ret);
223 }
224 
225 int
av1394_ir_read(av1394_ic_t * icp,struct uio * uiop)226 av1394_ir_read(av1394_ic_t *icp, struct uio *uiop)
227 {
228 	av1394_ir_t	*irp = &icp->ic_ir;
229 	int		ret = 0;
230 	int		empty_cnt;
231 
232 	AV1394_TNF_ENTER(av1394_ir_read);
233 
234 	mutex_enter(&icp->ic_mutex);
235 	while (uiop->uio_resid) {
236 		/* wait for full frames, if necessary */
237 		if (irp->ir_read_cnt == 0) {
238 			irp->ir_read_off = 0;
239 			ret = av1394_ir_wait_frames(icp,
240 			    &irp->ir_read_idx, &irp->ir_read_cnt);
241 			if (ret != 0) {
242 				mutex_exit(&icp->ic_mutex);
243 				AV1394_TNF_EXIT(av1394_ir_read);
244 				return (ret);
245 			}
246 		}
247 
248 		/* copyout the data */
249 		ret = av1394_ir_copyout(icp, uiop, &empty_cnt);
250 
251 		/* return freed frames to the pool */
252 		if (empty_cnt > 0) {
253 			av1394_ir_zero_pkts(icp, irp->ir_read_idx, empty_cnt);
254 			ret = av1394_ir_add_frames(icp, irp->ir_read_idx,
255 			    empty_cnt);
256 			irp->ir_read_idx += empty_cnt;
257 			irp->ir_read_idx %= icp->ic_nframes;
258 			irp->ir_read_cnt -= empty_cnt;
259 		}
260 	}
261 	mutex_exit(&icp->ic_mutex);
262 
263 	AV1394_TNF_EXIT(av1394_ir_read);
264 	return (ret);
265 }
266 
267 /*
268  *
269  * --- configuration routines
270  *
271  */
272 static void
av1394_ir_cleanup(av1394_ic_t * icp,int level)273 av1394_ir_cleanup(av1394_ic_t *icp, int level)
274 {
275 	av1394_isoch_pool_t *pool = &icp->ic_ir.ir_data_pool;
276 
277 	ASSERT((level > 0) && (level <= AV1394_CLEANUP_LEVEL_MAX));
278 
279 	switch (level) {
280 	default:
281 		av1394_ir_free_isoch_dma(icp);
282 		/* FALLTHRU */
283 	case 3:
284 		av1394_ir_destroy_ixl(icp);
285 		/* FALLTHRU */
286 	case 2:
287 		av1394_ic_dma_cleanup(icp, pool);
288 		/* FALLTHRU */
289 	case 1:
290 		av1394_ic_free_pool(pool);
291 		/* FALLTHRU */
292 	}
293 }
294 
295 /*
296  * av1394_ir_build_ixl()
297  *    Build an IXL chain to receive CIP data. The smallest instance of data
298  *    that can be received is a packet, typically 512 bytes. Frames consist
299  *    of a number of packets, typically 250-300. Packet size, frame size and
300  *    number of frames allocated are set by a user process. The received data
301  *    made available to the user process in full frames, hence there an IXL
302  *    callback at the end of each frame. A sequence of IXL commands that
303  *    receives one frame is further referred to as an IXL data block.
304  *
305  *    During normal operation, frames are in a circular list and IXL chain
306  *    does not change. When the user process does not keep up with the
307  *    data flow and there are too few empty frames left, the jump following
308  *    last empty frame is dynamically updated to point to NULL -- otherwise
309  *    the first full frame would be overwritten. When IXL execution reaches
310  *    the nulled jump, it just waits until the driver updates it again or
311  *    stops the transfer. Once a user process frees up enough frames, the
312  *    jump is restored and transfer continues. User process will be able to
313  *    detect dropped packets using continuity conters embedded in the data.
314  *
315  *    Because RECV_BUF buffer size is limited to AV1394_IXL_BUFSZ_MAX, and due
316  *    to isoch pool segmentaion, the number of RECV_BUF commands per IXL data
317  *    block depends on frame size. Also, to simplify calculations, we consider
318  *    a sequence of RECV_BUF commands to consist of two parts: zero or more
319  *    equal-sized RECV_BUF commands followed by one "tail" REC_BUF command,
320  *    whose size may not be equal to others.
321  *
322  *    Schematically the IXL chain looks like this:
323  *
324  *    ...
325  *    LABEL N;
326  *    RECV_BUF(buf)
327  *    ...
328  *    RECV_BUF(tail)
329  *    CALLBACK(frame done);
330  *    JUMP_U(LABEL (N+1)%nframes or NULL);
331  *    ...
332  */
333 static int
av1394_ir_build_ixl(av1394_ic_t * icp)334 av1394_ir_build_ixl(av1394_ic_t *icp)
335 {
336 	av1394_ir_t		*irp = &icp->ic_ir;
337 	av1394_isoch_pool_t	*pool = &irp->ir_data_pool;
338 	int			i;	/* segment index */
339 	int			j;
340 	int			fi;	/* frame index */
341 	int			bi;	/* buffer index */
342 
343 	AV1394_TNF_ENTER(av1394_ir_build_ixl);
344 
345 	/* allocate space for IXL data blocks */
346 	irp->ir_ixl_data = kmem_zalloc(icp->ic_nframes *
347 	    sizeof (av1394_ir_ixl_data_t), KM_SLEEP);
348 
349 	/*
350 	 * We have a bunch of segments, and each is divided into cookies.  We
351 	 * need to cover the segments with RECV_BUFs such that they
352 	 *   - don't span cookies
353 	 *   - don't span frames
354 	 *   - are at most AV1394_IXL_BUFSZ_MAX
355 	 *
356 	 * The straightforward algorithm is to start from the beginning, find
357 	 * the next lowest frame or cookie boundary, and either make a buf for
358 	 * it if it is smaller than AV1394_IXL_BUFSZ_MAX, or make multiple
359 	 * bufs for it as with av1394_ic_ixl_seg_decomp().  And repeat.
360 	 */
361 
362 	irp->ir_ixl_nbufs = 0;
363 	for (i = 0; i < pool->ip_nsegs; ++i) {
364 		av1394_isoch_seg_t *isp = &pool->ip_seg[i];
365 		size_t dummy1, dummy2;
366 
367 		uint_t off = 0;
368 		uint_t end;
369 
370 		uint_t frame_end = icp->ic_framesz;
371 		int ci = 0;
372 		uint_t cookie_end = isp->is_dma_cookie[ci].dmac_size;
373 
374 		for (;;) {
375 			end = min(frame_end, cookie_end);
376 
377 			if (end - off <= AV1394_IXL_BUFSZ_MAX) {
378 				++irp->ir_ixl_nbufs;
379 			} else {
380 				irp->ir_ixl_nbufs += av1394_ic_ixl_seg_decomp(
381 				    end - off, icp->ic_pktsz, &dummy1, &dummy2);
382 				/* count the tail buffer */
383 				++irp->ir_ixl_nbufs;
384 			}
385 
386 			off = end;
387 			if (off >= isp->is_size)
388 				break;
389 
390 			if (off == frame_end)
391 				frame_end += icp->ic_framesz;
392 			if (off == cookie_end) {
393 				++ci;
394 				cookie_end += isp->is_dma_cookie[ci].dmac_size;
395 			}
396 		}
397 	}
398 
399 	irp->ir_ixl_buf = kmem_zalloc(irp->ir_ixl_nbufs *
400 	    sizeof (ixl1394_xfer_buf_t), KM_SLEEP);
401 
402 
403 	fi = 0;
404 	bi = 0;
405 
406 	for (i = 0; i < pool->ip_nsegs; ++i) {
407 		av1394_isoch_seg_t *isp = &pool->ip_seg[i];
408 
409 		uint_t off = 0;		/* offset into segment */
410 		uint_t end;
411 		uint_t coff = 0;	/* offset into cookie */
412 
413 
414 		uint_t frame_end = icp->ic_framesz;
415 		int ci = 0;
416 		uint_t cookie_end = isp->is_dma_cookie[ci].dmac_size;
417 
418 		ixl1394_command_t *nextp;
419 
420 		av1394_ir_ixl_label_init(&irp->ir_ixl_data[fi],
421 		    (ixl1394_command_t *)&irp->ir_ixl_buf[bi]);
422 
423 		for (;;) {
424 			end = min(frame_end, cookie_end);
425 
426 			if (end == frame_end)
427 				nextp = (ixl1394_command_t *)
428 				    &irp->ir_ixl_data[fi].rd_cb;
429 			else
430 				nextp = (ixl1394_command_t *)
431 				    &irp->ir_ixl_buf[bi + 1];
432 
433 			if (end - off <= AV1394_IXL_BUFSZ_MAX) {
434 				av1394_ir_ixl_buf_init(icp,
435 				    &irp->ir_ixl_buf[bi], isp, off,
436 				    isp->is_dma_cookie[ci].dmac_laddress + coff,
437 				    end - off, nextp);
438 				coff += end - off;
439 				off = end;
440 				++bi;
441 			} else {
442 				size_t reg, tail;
443 				uint_t nbufs;
444 
445 				nbufs = av1394_ic_ixl_seg_decomp(end - off,
446 				    icp->ic_pktsz, &reg, &tail);
447 
448 				for (j = 0; j < nbufs; ++j) {
449 					av1394_ir_ixl_buf_init(icp,
450 					    &irp->ir_ixl_buf[bi], isp, off,
451 					    isp->is_dma_cookie[ci].
452 					    dmac_laddress + coff, reg,
453 					    (ixl1394_command_t *)
454 					    &irp->ir_ixl_buf[bi + 1]);
455 					++bi;
456 					off += reg;
457 					coff += reg;
458 				}
459 
460 				av1394_ir_ixl_buf_init(icp,
461 				    &irp->ir_ixl_buf[bi], isp, off,
462 				    isp->is_dma_cookie[ci].dmac_laddress + coff,
463 				    tail, nextp);
464 				++bi;
465 				off += tail;
466 				coff += tail;
467 			}
468 
469 			ASSERT((off == frame_end) || (off == cookie_end));
470 
471 			if (off >= isp->is_size)
472 				break;
473 
474 			if (off == frame_end) {
475 				av1394_ir_ixl_cb_init(icp,
476 				    &irp->ir_ixl_data[fi], fi);
477 				av1394_ir_ixl_jump_init(icp,
478 				    &irp->ir_ixl_data[fi], fi);
479 				++fi;
480 				frame_end += icp->ic_framesz;
481 				av1394_ir_ixl_label_init(&irp->ir_ixl_data[fi],
482 				    (ixl1394_command_t *)&irp->ir_ixl_buf[bi]);
483 			}
484 
485 			if (off == cookie_end) {
486 				++ci;
487 				cookie_end += isp->is_dma_cookie[ci].dmac_size;
488 				coff = 0;
489 			}
490 		}
491 
492 		av1394_ir_ixl_cb_init(icp, &irp->ir_ixl_data[fi], fi);
493 		av1394_ir_ixl_jump_init(icp, &irp->ir_ixl_data[fi], fi);
494 		++fi;
495 	}
496 
497 	ASSERT(fi == icp->ic_nframes);
498 	ASSERT(bi == irp->ir_ixl_nbufs);
499 
500 	irp->ir_ixlp = (ixl1394_command_t *)irp->ir_ixl_data;
501 
502 	if (av1394_ir_dump_ixl) {
503 		av1394_ic_ixl_dump(irp->ir_ixlp);
504 	}
505 
506 	AV1394_TNF_EXIT(av1394_ir_build_ixl);
507 	return (DDI_SUCCESS);
508 }
509 
510 static void
av1394_ir_ixl_label_init(av1394_ir_ixl_data_t * dp,ixl1394_command_t * nextp)511 av1394_ir_ixl_label_init(av1394_ir_ixl_data_t *dp, ixl1394_command_t *nextp)
512 {
513 	dp->rd_label.ixl_opcode = IXL1394_OP_LABEL;
514 	dp->rd_label.next_ixlp	= nextp;
515 }
516 
517 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)518 av1394_ir_ixl_buf_init(av1394_ic_t *icp, ixl1394_xfer_buf_t *buf,
519 	av1394_isoch_seg_t *isp, off_t offset, uint64_t addr, uint16_t size,
520 	ixl1394_command_t *nextp)
521 {
522 	buf->ixl_opcode = IXL1394_OP_RECV_BUF;
523 	buf->size = size;
524 	buf->pkt_size = icp->ic_pktsz;
525 	buf->ixl_buf._dmac_ll = addr;
526 	buf->mem_bufp = isp->is_kaddr + offset;
527 	buf->next_ixlp = nextp;
528 }
529 
530 /*ARGSUSED*/
531 static void
av1394_ir_ixl_cb_init(av1394_ic_t * icp,av1394_ir_ixl_data_t * dp,int i)532 av1394_ir_ixl_cb_init(av1394_ic_t *icp, av1394_ir_ixl_data_t *dp, int i)
533 {
534 	dp->rd_cb.ixl_opcode = IXL1394_OP_CALLBACK;
535 	dp->rd_cb.callback = av1394_ir_ixl_frame_cb;
536 	dp->rd_cb.callback_arg = (void *)(intptr_t)i;
537 	dp->rd_cb.next_ixlp = (ixl1394_command_t *)&dp->rd_jump;
538 }
539 
540 static void
av1394_ir_ixl_jump_init(av1394_ic_t * icp,av1394_ir_ixl_data_t * dp,int i)541 av1394_ir_ixl_jump_init(av1394_ic_t *icp, av1394_ir_ixl_data_t *dp, int i)
542 {
543 	av1394_ir_t	*irp = &icp->ic_ir;
544 	int		next_idx;
545 	ixl1394_command_t *jump_cmd;
546 
547 	next_idx = (i + 1) % icp->ic_nframes;
548 	jump_cmd = (ixl1394_command_t *)&irp->ir_ixl_data[next_idx];
549 
550 	dp->rd_jump.ixl_opcode	= IXL1394_OP_JUMP_U;
551 	dp->rd_jump.label = jump_cmd;
552 	dp->rd_jump.next_ixlp = (next_idx != 0) ? jump_cmd : NULL;
553 }
554 
555 static void
av1394_ir_destroy_ixl(av1394_ic_t * icp)556 av1394_ir_destroy_ixl(av1394_ic_t *icp)
557 {
558 	av1394_ir_t		*irp = &icp->ic_ir;
559 
560 	AV1394_TNF_ENTER(av1394_ir_destroy_ixl);
561 
562 	mutex_enter(&icp->ic_mutex);
563 	kmem_free(irp->ir_ixl_buf,
564 	    irp->ir_ixl_nbufs * sizeof (ixl1394_xfer_buf_t));
565 	kmem_free(irp->ir_ixl_data,
566 	    icp->ic_nframes * sizeof (av1394_ir_ixl_data_t));
567 
568 	irp->ir_ixlp = NULL;
569 	irp->ir_ixl_buf = NULL;
570 	irp->ir_ixl_data = NULL;
571 	mutex_exit(&icp->ic_mutex);
572 
573 	AV1394_TNF_EXIT(av1394_ir_destroy_ixl);
574 }
575 
576 static int
av1394_ir_alloc_isoch_dma(av1394_ic_t * icp)577 av1394_ir_alloc_isoch_dma(av1394_ic_t *icp)
578 {
579 	av1394_inst_t		*avp = icp->ic_avp;
580 	av1394_ir_t		*irp = &icp->ic_ir;
581 	id1394_isoch_dmainfo_t	di;
582 	int			result;
583 	int			ret;
584 
585 	AV1394_TNF_ENTER(av1394_ir_alloc_isoch_dma);
586 
587 	di.ixlp = irp->ir_ixlp;
588 	di.channel_num = icp->ic_num;
589 	di.global_callback_arg = icp;
590 	di.idma_options = ID1394_LISTEN_PKT_MODE;
591 	di.isoch_dma_stopped = av1394_ir_dma_stopped_cb;
592 	di.idma_evt_arg = icp;
593 
594 	if ((ret = t1394_alloc_isoch_dma(avp->av_t1394_hdl, &di, 0,
595 	    &icp->ic_isoch_hdl, &result)) != DDI_SUCCESS) {
596 		TNF_PROBE_1(av1394_ir_alloc_isoch_dma_error,
597 		    AV1394_TNF_ISOCH_ERROR, "", tnf_int, result, result);
598 	}
599 
600 	AV1394_TNF_EXIT(av1394_ir_alloc_isoch_dma);
601 	return (ret);
602 }
603 
604 static void
av1394_ir_free_isoch_dma(av1394_ic_t * icp)605 av1394_ir_free_isoch_dma(av1394_ic_t *icp)
606 {
607 	av1394_inst_t		*avp = icp->ic_avp;
608 
609 	AV1394_TNF_ENTER(av1394_ir_free_isoch_rsrc);
610 
611 	t1394_free_isoch_dma(avp->av_t1394_hdl, 0, &icp->ic_isoch_hdl);
612 
613 	AV1394_TNF_EXIT(av1394_ir_free_isoch_rsrc);
614 }
615 
616 static void
av1394_ir_dma_sync_frames(av1394_ic_t * icp,int idx,int cnt)617 av1394_ir_dma_sync_frames(av1394_ic_t *icp, int idx, int cnt)
618 {
619 	av1394_ic_dma_sync_frames(icp, idx, cnt,
620 	    &icp->ic_ir.ir_data_pool, DDI_DMA_SYNC_FORCPU);
621 }
622 
623 /*
624  *
625  * --- callbacks
626  *
627  */
628 /*ARGSUSED*/
629 static void
av1394_ir_ixl_frame_cb(opaque_t arg,struct ixl1394_callback * cb)630 av1394_ir_ixl_frame_cb(opaque_t arg, struct ixl1394_callback *cb)
631 {
632 	av1394_ic_t	*icp = arg;
633 	av1394_isoch_t	*ip = &icp->ic_avp->av_i;
634 	av1394_ir_t	*irp = &icp->ic_ir;
635 
636 	AV1394_TNF_ENTER(av1394_ir_ixl_frame_cb);
637 
638 	mutex_enter(&ip->i_mutex);
639 	mutex_enter(&icp->ic_mutex);
640 	if (irp->ir_nfull < icp->ic_nframes) {
641 		irp->ir_nfull++;
642 		irp->ir_nempty--;
643 		cv_broadcast(&icp->ic_xfer_cv);
644 
645 		/*
646 		 * signal the overflow condition early, so we get enough
647 		 * time to handle it before old data is overwritten
648 		 */
649 		if (irp->ir_nfull >= irp->ir_hiwat) {
650 			av1394_ic_trigger_softintr(icp, icp->ic_num,
651 			    AV1394_PREQ_IR_OVERFLOW);
652 		}
653 	}
654 	mutex_exit(&icp->ic_mutex);
655 	mutex_exit(&ip->i_mutex);
656 
657 	AV1394_TNF_EXIT(av1394_ir_ixl_frame_cb);
658 }
659 
660 /*
661  * received data overflow
662  */
663 void
av1394_ir_overflow(av1394_ic_t * icp)664 av1394_ir_overflow(av1394_ic_t *icp)
665 {
666 	av1394_inst_t	*avp = icp->ic_avp;
667 	av1394_ir_t	*irp = &icp->ic_ir;
668 	int		idx;
669 	ixl1394_jump_t	*old_jmp;
670 	ixl1394_jump_t	new_jmp;
671 	id1394_isoch_dma_updateinfo_t update_info;
672 	int		err;
673 	int		result;
674 
675 	AV1394_TNF_ENTER(av1394_ir_overflow);
676 
677 	/*
678 	 * in the circular IXL chain overflow means overwriting the least
679 	 * recent data. to avoid that, we suspend the transfer by NULL'ing
680 	 * the last IXL block until the user process frees up some frames.
681 	 */
682 	idx = irp->ir_last_empty;
683 
684 	old_jmp = &irp->ir_ixl_data[idx].rd_jump;
685 
686 	new_jmp.ixl_opcode = IXL1394_OP_JUMP_U;
687 	new_jmp.label = NULL;
688 	new_jmp.next_ixlp = NULL;
689 
690 	update_info.orig_ixlp = (ixl1394_command_t *)old_jmp;
691 	update_info.temp_ixlp = (ixl1394_command_t *)&new_jmp;
692 	update_info.ixl_count = 1;
693 
694 	mutex_exit(&icp->ic_mutex);
695 	err = t1394_update_isoch_dma(avp->av_t1394_hdl, icp->ic_isoch_hdl,
696 	    &update_info, 0, &result);
697 	mutex_enter(&icp->ic_mutex);
698 
699 	if (err == DDI_SUCCESS) {
700 		irp->ir_overflow_idx = idx;
701 		icp->ic_state = AV1394_IC_SUSPENDED;
702 	} else {
703 		TNF_PROBE_2(av1394_ir_overflow_error_update,
704 		    AV1394_TNF_ISOCH_ERROR, "", tnf_int, err, err,
705 		    tnf_int, result, result);
706 	}
707 
708 	AV1394_TNF_EXIT(av1394_ir_overflow);
709 }
710 
711 /*
712  * restore from overflow condition
713  */
714 static void
av1394_ir_overflow_resume(av1394_ic_t * icp)715 av1394_ir_overflow_resume(av1394_ic_t *icp)
716 {
717 	av1394_inst_t	*avp = icp->ic_avp;
718 	av1394_ir_t	*irp = &icp->ic_ir;
719 	int		idx, next_idx;
720 	ixl1394_jump_t	*old_jmp;
721 	ixl1394_jump_t	new_jmp;
722 	id1394_isoch_dma_updateinfo_t update_info;
723 	int		err;
724 	int		result;
725 
726 	AV1394_TNF_ENTER(av1394_ir_overflow_resume);
727 
728 	/*
729 	 * restore the jump command we NULL'ed in av1394_ir_overflow()
730 	 */
731 	idx = irp->ir_overflow_idx;
732 	next_idx = (idx + 1) % icp->ic_nframes;
733 
734 	old_jmp = &irp->ir_ixl_data[idx].rd_jump;
735 
736 	new_jmp.ixl_opcode = IXL1394_OP_JUMP_U;
737 	new_jmp.label = (ixl1394_command_t *)&irp->ir_ixl_data[next_idx];
738 	new_jmp.next_ixlp = NULL;
739 
740 	update_info.orig_ixlp = (ixl1394_command_t *)old_jmp;
741 	update_info.temp_ixlp = (ixl1394_command_t *)&new_jmp;
742 	update_info.ixl_count = 1;
743 
744 	mutex_exit(&icp->ic_mutex);
745 	err = t1394_update_isoch_dma(avp->av_t1394_hdl,
746 	    icp->ic_isoch_hdl, &update_info, 0, &result);
747 	mutex_enter(&icp->ic_mutex);
748 
749 	if (err == DDI_SUCCESS) {
750 		icp->ic_state = AV1394_IC_DMA;
751 	} else {
752 		TNF_PROBE_2(av1394_ir_overflow_resume_error_update,
753 		    AV1394_TNF_ISOCH_ERROR, "", tnf_int, err, err,
754 		    tnf_int, result, result);
755 	}
756 
757 	AV1394_TNF_EXIT(av1394_ir_overflow_resume);
758 }
759 
760 /*ARGSUSED*/
761 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)762 av1394_ir_dma_stopped_cb(t1394_isoch_dma_handle_t t1394_idma_hdl,
763 	opaque_t idma_evt_arg, id1394_isoch_dma_stopped_t status)
764 {
765 	av1394_ic_t	*icp = idma_evt_arg;
766 
767 	AV1394_TNF_ENTER(av1394_ir_dma_stopped_cb);
768 
769 	mutex_enter(&icp->ic_mutex);
770 	icp->ic_state = AV1394_IC_IDLE;
771 	mutex_exit(&icp->ic_mutex);
772 
773 	AV1394_TNF_EXIT(av1394_ir_dma_stopped_cb);
774 }
775 
776 
777 /*
778  *
779  * --- data transfer routines
780  *
781  * av1394_ir_add_frames()
782  *    Add empty frames to the pool.
783  */
784 static int
av1394_ir_add_frames(av1394_ic_t * icp,int idx,int cnt)785 av1394_ir_add_frames(av1394_ic_t *icp, int idx, int cnt)
786 {
787 	av1394_ir_t	*irp = &icp->ic_ir;
788 
789 	/* can only add to the tail */
790 	if (idx != ((irp->ir_last_empty + 1) % icp->ic_nframes)) {
791 		TNF_PROBE_1(av1394_ir_add_frames_error,
792 		    AV1394_TNF_ISOCH_ERROR, "", tnf_int, idx, idx);
793 		return (EINVAL);
794 	}
795 
796 	/* turn full frames into empty ones */
797 	irp->ir_nfull -= cnt;
798 	irp->ir_first_full = (irp->ir_first_full + cnt) % icp->ic_nframes;
799 	irp->ir_nempty += cnt;
800 	irp->ir_last_empty = (irp->ir_last_empty + cnt) % icp->ic_nframes;
801 	ASSERT((irp->ir_nfull >= 0) && (irp->ir_nempty <= icp->ic_nframes));
802 
803 	/* if suspended due to overflow, check if iwe can resume */
804 	if ((icp->ic_state == AV1394_IC_SUSPENDED) &&
805 	    (irp->ir_nempty >= irp->ir_lowat)) {
806 		av1394_ir_overflow_resume(icp);
807 	}
808 
809 	return (0);
810 }
811 
812 static int
av1394_ir_wait_frames(av1394_ic_t * icp,int * idx,int * cnt)813 av1394_ir_wait_frames(av1394_ic_t *icp, int *idx, int *cnt)
814 {
815 	av1394_ir_t	*irp = &icp->ic_ir;
816 	int		ret = 0;
817 
818 	while (irp->ir_nfull == 0) {
819 		if (cv_wait_sig(&icp->ic_xfer_cv, &icp->ic_mutex) <= 0) {
820 			ret = EINTR;
821 			break;
822 		}
823 	}
824 	if (irp->ir_nfull > 0) {
825 		*idx = irp->ir_first_full;
826 		*cnt = irp->ir_nfull;
827 		av1394_ir_dma_sync_frames(icp, *idx, *cnt);
828 		ret = 0;
829 	}
830 	return (ret);
831 }
832 
833 /*
834  * copyout the data, adjust to data format and remove empty CIPs if possible
835  */
836 static int
av1394_ir_copyout(av1394_ic_t * icp,struct uio * uiop,int * empty_cnt)837 av1394_ir_copyout(av1394_ic_t *icp, struct uio *uiop, int *empty_cnt)
838 {
839 	av1394_ir_t	*irp = &icp->ic_ir;
840 	av1394_isoch_seg_t *seg = irp->ir_data_pool.ip_seg;
841 	int		idx = irp->ir_read_idx;
842 	int		cnt = irp->ir_read_cnt;
843 	int		pktsz = icp->ic_pktsz;
844 	int		bs;		/* data block size */
845 	caddr_t		kaddr_begin, kaddr;
846 	int		pkt_off;	/* offset into current packet */
847 	int		len;
848 	int		frame_resid;	/* bytes left in the current frame */
849 	int		ret = 0;
850 
851 	*empty_cnt = 0;
852 
853 	/* DBS -> block size */
854 	bs = *(uchar_t *)(seg[idx].is_kaddr + 1) * 4 + AV1394_CIPSZ;
855 	if ((bs > pktsz) || (bs < AV1394_CIPSZ + 8)) {
856 		bs = pktsz;
857 	}
858 
859 	while ((cnt > 0) && (uiop->uio_resid > 0) && (ret == 0)) {
860 		kaddr = kaddr_begin = seg[idx].is_kaddr + irp->ir_read_off;
861 		frame_resid = icp->ic_framesz - irp->ir_read_off;
862 
863 		mutex_exit(&icp->ic_mutex);
864 		/* copyout data blocks, skipping empty CIPs */
865 		while ((uiop->uio_resid > 0) && (frame_resid > 0)) {
866 			pkt_off = (uintptr_t)kaddr % pktsz;
867 			/*
868 			 * a quadlet following CIP header can't be zero
869 			 * unless in an empty packet
870 			 */
871 			if ((pkt_off == 0) &&
872 			    (*(uint32_t *)(kaddr + AV1394_CIPSZ) == 0)) {
873 				kaddr += pktsz;
874 				frame_resid -= pktsz;
875 				continue;
876 			}
877 
878 			len = bs - pkt_off;
879 			if (len > uiop->uio_resid) {
880 				len = uiop->uio_resid;
881 			}
882 			if (len > frame_resid) {
883 				len = frame_resid;
884 			}
885 			if ((ret = uiomove(kaddr, len, UIO_READ, uiop)) != 0) {
886 				break;
887 			}
888 
889 			if (pkt_off + len == bs) {
890 				kaddr += pktsz - pkt_off;
891 				frame_resid -= pktsz - pkt_off;
892 			} else {
893 				kaddr += len;
894 				frame_resid -= len;
895 			}
896 		}
897 		mutex_enter(&icp->ic_mutex);
898 
899 		if (frame_resid > 0) {
900 			irp->ir_read_off = kaddr - kaddr_begin;
901 		} else {
902 			irp->ir_read_off = 0;
903 			idx = (idx + 1) % icp->ic_nframes;
904 			cnt--;
905 			(*empty_cnt)++;
906 		}
907 	}
908 
909 	return (ret);
910 }
911 
912 /*
913  * zero a quadlet in each packet so we can recognize empty CIPs
914  */
915 static void
av1394_ir_zero_pkts(av1394_ic_t * icp,int idx,int cnt)916 av1394_ir_zero_pkts(av1394_ic_t *icp, int idx, int cnt)
917 {
918 	av1394_ir_t	*irp = &icp->ic_ir;
919 	av1394_isoch_seg_t *seg = irp->ir_data_pool.ip_seg;
920 	caddr_t		kaddr, kaddr_end;
921 	int		pktsz = icp->ic_pktsz;
922 	int		i;
923 
924 	for (i = cnt; i > 0; i--) {
925 		kaddr = seg[idx].is_kaddr + AV1394_CIPSZ;
926 		kaddr_end = seg[idx].is_kaddr + icp->ic_framesz;
927 		do {
928 			*(uint32_t *)kaddr = 0;
929 			kaddr += pktsz;
930 		} while (kaddr < kaddr_end);
931 
932 		idx = (idx + 1) % icp->ic_nframes;
933 	}
934 }
935