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