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 transmit module
28 */
29 #include <sys/1394/targets/av1394/av1394_impl.h>
30
31 static int av1394_it_start_common(av1394_ic_t *);
32
33 /* configuration routines */
34 static void av1394_it_cleanup(av1394_ic_t *, int);
35 static int av1394_it_bld_ixl(av1394_ic_t *);
36 static void av1394_it_destroy_ixl(av1394_ic_t *);
37 static int av1394_it_ixl_bld_data(av1394_ic_t *);
38 static void av1394_it_ixl_destroy_data(av1394_ic_t *);
39 static av1394_it_ixl_buf_t *av1394_it_ixl_bld_buf(av1394_ic_t *, int, int,
40 off_t, int, int);
41 static void av1394_it_ixl_complete_buf(av1394_it_ixl_buf_t *,
42 av1394_it_ixl_empty_cip_t *);
43 static void av1394_it_ixl_complete_buf2(av1394_it_ixl_buf_t *,
44 av1394_it_ixl_buf_t *);
45 static av1394_it_ixl_empty_cip_t *av1394_it_ixl_bld_empty_cip(av1394_ic_t *,
46 int);
47 static void av1394_it_ixl_complete_empty_cip(av1394_it_ixl_empty_cip_t *,
48 av1394_it_ixl_buf_t *);
49 static void av1394_it_ixl_bld_begin(av1394_ic_t *);
50 static void av1394_it_ixl_begin_update_pkts(av1394_ic_t *,
51 av1394_it_ixl_buf_t *);
52 static int av1394_it_alloc_isoch_dma(av1394_ic_t *);
53 static void av1394_it_free_isoch_dma(av1394_ic_t *);
54 static void av1394_it_dma_sync_frames(av1394_ic_t *, int, int);
55
56 /* callbacks */
57 static void av1394_it_ixl_begin_cb(opaque_t, struct ixl1394_callback *);
58 static void av1394_it_ixl_buf_cb(opaque_t, struct ixl1394_callback *);
59 static void av1394_it_ixl_eof_cb(av1394_it_ixl_buf_t *bp);
60 static int av1394_it_underrun_resume(av1394_ic_t *);
61 static void av1394_it_dma_stopped_cb(t1394_isoch_dma_handle_t,
62 opaque_t, id1394_isoch_dma_stopped_t);
63
64 /* data transfer routines */
65 static int av1394_it_add_frames(av1394_ic_t *, int, int);
66 static int av1394_it_wait_frames(av1394_ic_t *, int *, int *, int *);
67
68 static void av1394_it_update_frame_syt(av1394_ic_t *, int, int, uint16_t);
69 static uint16_t av1394_it_ts_cyc2syt(uint16_t);
70 static uint16_t av1394_it_ts_syt_inc(uint16_t, uint16_t);
71
72 static void av1394_it_kcopyin(av1394_ic_t *, void *, size_t);
73 static int av1394_it_copyin(av1394_ic_t *, struct uio *, int *, int);
74 static boolean_t av1394_it_is_dv_frame_start(caddr_t);
75 static void av1394_it_reset_frame_syt(av1394_ic_t *, int);
76
77 /* tunables */
78 int av1394_it_hiwat_sub = 2;
79 int av1394_it_lowat = 3;
80 int av1394_it_start_thre = 3; /* xmit start threshold */
81 int av1394_it_syt_off = 3; /* SYT offset in cycles */
82 int av1394_it_dump_ixl = 0;
83
84 int
av1394_it_init(av1394_ic_t * icp,int * error)85 av1394_it_init(av1394_ic_t *icp, int *error)
86 {
87 av1394_it_t *itp = &icp->ic_it;
88 av1394_isoch_pool_t *pool = &itp->it_data_pool;
89 int nframes;
90
91 nframes = av1394_ic_alloc_pool(pool, icp->ic_framesz, icp->ic_nframes,
92 AV1394_IT_NFRAMES_MIN);
93 if (nframes == 0) {
94 *error = IEC61883_ERR_NOMEM;
95 return (EINVAL);
96 }
97 mutex_enter(&icp->ic_mutex);
98 icp->ic_nframes = nframes;
99 itp->it_hiwat = nframes - av1394_it_hiwat_sub;
100 itp->it_lowat = av1394_it_lowat;
101 itp->it_start_thre = av1394_it_start_thre;
102 itp->it_nempty = icp->ic_nframes;
103 itp->it_last_full = icp->ic_nframes - 1;
104
105 if (av1394_ic_dma_setup(icp, pool) != DDI_SUCCESS) {
106 mutex_exit(&icp->ic_mutex);
107 *error = IEC61883_ERR_NOMEM;
108 av1394_it_cleanup(icp, 1);
109 return (EINVAL);
110 }
111
112 if (av1394_it_bld_ixl(icp) != DDI_SUCCESS) {
113 mutex_exit(&icp->ic_mutex);
114 *error = IEC61883_ERR_NOMEM;
115 av1394_it_cleanup(icp, 2);
116 return (EINVAL);
117 }
118 mutex_exit(&icp->ic_mutex);
119
120 if (av1394_it_alloc_isoch_dma(icp) != DDI_SUCCESS) {
121 *error = IEC61883_ERR_NOMEM;
122 av1394_it_cleanup(icp, 3);
123 return (EINVAL);
124 }
125
126 return (0);
127 }
128
129 void
av1394_it_fini(av1394_ic_t * icp)130 av1394_it_fini(av1394_ic_t *icp)
131 {
132 av1394_it_cleanup(icp, AV1394_CLEANUP_LEVEL_MAX);
133 }
134
135 int
av1394_it_start(av1394_ic_t * icp)136 av1394_it_start(av1394_ic_t *icp)
137 {
138 av1394_it_t *itp = &icp->ic_it;
139 int ret = 0;
140
141 mutex_enter(&icp->ic_mutex);
142 ASSERT(icp->ic_state == AV1394_IC_IDLE);
143
144 /* should be enough full frames to be able to start */
145 if (itp->it_nfull >= itp->it_start_thre) {
146 ret = av1394_it_start_common(icp);
147 }
148 mutex_exit(&icp->ic_mutex);
149
150 return (ret);
151 }
152
153 static int
av1394_it_start_common(av1394_ic_t * icp)154 av1394_it_start_common(av1394_ic_t *icp)
155 {
156 av1394_inst_t *avp = icp->ic_avp;
157 id1394_isoch_dma_ctrlinfo_t idma_ctrlinfo = { 0 };
158 int result;
159 int err;
160 int ret = 0;
161
162 ASSERT(icp->ic_state == AV1394_IC_IDLE);
163
164 err = t1394_start_isoch_dma(avp->av_t1394_hdl, icp->ic_isoch_hdl,
165 &idma_ctrlinfo, 0, &result);
166 if (err == DDI_SUCCESS) {
167 icp->ic_state = AV1394_IC_DMA;
168 } else {
169 ret = EIO;
170 }
171
172 return (ret);
173 }
174
175
176 int
av1394_it_stop(av1394_ic_t * icp)177 av1394_it_stop(av1394_ic_t *icp)
178 {
179 av1394_inst_t *avp = icp->ic_avp;
180 av1394_it_t *itp = &icp->ic_it;
181
182 mutex_enter(&icp->ic_mutex);
183 if (icp->ic_state != AV1394_IC_IDLE) {
184 mutex_exit(&icp->ic_mutex);
185 t1394_stop_isoch_dma(avp->av_t1394_hdl, icp->ic_isoch_hdl, 0);
186 mutex_enter(&icp->ic_mutex);
187
188 icp->ic_state = AV1394_IC_IDLE;
189 itp->it_nempty = icp->ic_nframes;
190 itp->it_first_empty = 0;
191 itp->it_last_full = icp->ic_nframes - 1;
192 itp->it_nfull = 0;
193 }
194 mutex_exit(&icp->ic_mutex);
195
196 return (0);
197 }
198
199 int
av1394_it_xmit(av1394_ic_t * icp,iec61883_xmit_t * xmit)200 av1394_it_xmit(av1394_ic_t *icp, iec61883_xmit_t *xmit)
201 {
202 av1394_it_t *itp = &icp->ic_it;
203 int ret = 0;
204 int idx, cnt;
205
206 idx = xmit->tx_xfer.xf_full_idx;
207 cnt = xmit->tx_xfer.xf_full_cnt;
208
209 mutex_enter(&icp->ic_mutex);
210 /* check arguments */
211 if ((idx < 0) || (cnt < 0) || (cnt > itp->it_nempty)) {
212 mutex_exit(&icp->ic_mutex);
213 return (EINVAL);
214 }
215
216 /* add full frames to the pool */
217 if (cnt > 0) {
218 if ((ret = av1394_it_add_frames(icp, idx, cnt)) != 0) {
219 mutex_exit(&icp->ic_mutex);
220 return (ret);
221 }
222 }
223
224 if ((icp->ic_state == AV1394_IC_IDLE) &&
225 (itp->it_nfull >= itp->it_start_thre)) {
226 if ((ret = av1394_it_start_common(icp)) != 0) {
227 mutex_exit(&icp->ic_mutex);
228 return (ret);
229 }
230 }
231
232 /* wait for new empty frames */
233 ret = av1394_it_wait_frames(icp, &xmit->tx_xfer.xf_empty_idx,
234 &xmit->tx_xfer.xf_empty_cnt, &xmit->tx_miss_cnt);
235 mutex_exit(&icp->ic_mutex);
236
237 return (ret);
238 }
239
240 int
av1394_it_write(av1394_ic_t * icp,struct uio * uiop)241 av1394_it_write(av1394_ic_t *icp, struct uio *uiop)
242 {
243 av1394_inst_t *avp = icp->ic_avp;
244 av1394_it_t *itp = &icp->ic_it;
245 av1394_isoch_autoxmit_t *axp = &avp->av_i.i_autoxmit;
246 int dv;
247 int ret = 0;
248 int full_cnt;
249 int miss_cnt;
250
251 mutex_enter(&icp->ic_mutex);
252 dv = (axp->ax_fmt & AV1394_ISOCH_AUTOXMIT_DV);
253
254 while (uiop->uio_resid > 0) {
255 /* must have at least one empty frame */
256 if (itp->it_write_cnt == 0) {
257 ret = av1394_it_wait_frames(icp, &itp->it_write_idx,
258 &itp->it_write_cnt, &miss_cnt);
259 if (ret != 0) {
260 break;
261 }
262 }
263
264 /* copyin as much data as we can */
265 if (axp->ax_copy_ciph) {
266 ASSERT(itp->it_write_off == 0);
267 av1394_it_kcopyin(icp, axp->ax_ciph, AV1394_CIPSZ);
268 axp->ax_copy_ciph = B_FALSE;
269 }
270 if ((ret = av1394_it_copyin(icp, uiop, &full_cnt, dv)) != 0) {
271 break;
272 }
273
274 /* add full frames to the pool */
275 if (full_cnt > 0) {
276 ret = av1394_it_add_frames(icp,
277 itp->it_write_idx, full_cnt);
278 if (ret != 0) {
279 break;
280 }
281 itp->it_write_idx += full_cnt;
282 itp->it_write_idx %= icp->ic_nframes;
283 }
284
285 /* start xfer if not already */
286 if ((icp->ic_state == AV1394_IC_IDLE) &&
287 (itp->it_nfull >= itp->it_start_thre)) {
288 if ((ret = av1394_it_start_common(icp)) != 0) {
289 mutex_exit(&icp->ic_mutex);
290 return (ret);
291 }
292 }
293 }
294 mutex_exit(&icp->ic_mutex);
295
296 return (ret);
297 }
298
299 /*
300 *
301 * --- configuration routines
302 *
303 */
304 static void
av1394_it_cleanup(av1394_ic_t * icp,int level)305 av1394_it_cleanup(av1394_ic_t *icp, int level)
306 {
307 av1394_isoch_pool_t *pool = &icp->ic_it.it_data_pool;
308
309 ASSERT((level > 0) && (level <= AV1394_CLEANUP_LEVEL_MAX));
310
311 switch (level) {
312 default:
313 av1394_it_free_isoch_dma(icp);
314 /* FALLTHRU */
315 case 3:
316 av1394_it_destroy_ixl(icp);
317 /* FALLTHRU */
318 case 2:
319 av1394_ic_dma_cleanup(icp, pool);
320 /* FALLTHRU */
321 case 1:
322 av1394_ic_free_pool(pool);
323 /* FALLTHRU */
324 }
325 }
326
327 /*
328 * av1394_it_bld_ixl()
329 * Build an IXL chain out of several blocks.
330 */
331 static int
av1394_it_bld_ixl(av1394_ic_t * icp)332 av1394_it_bld_ixl(av1394_ic_t *icp)
333 {
334 av1394_it_t *itp = &icp->ic_it;
335 int ret;
336
337 /* data block */
338 if ((ret = av1394_it_ixl_bld_data(icp)) != DDI_SUCCESS) {
339 return (ret);
340 }
341
342 /* begin block */
343 if (icp->ic_param.cp_ts_mode != IEC61883_TS_NONE) {
344 av1394_it_ixl_bld_begin(icp);
345
346 itp->it_ixlp = (ixl1394_command_t *)&itp->it_ixl_begin;
347 } else {
348 itp->it_ixlp = (ixl1394_command_t *)
349 &((av1394_it_ixl_buf_t *)itp->it_ixl_data)->tb_label;
350 }
351
352 if (av1394_it_dump_ixl) {
353 av1394_ic_ixl_dump(itp->it_ixlp);
354 }
355
356 return (ret);
357 }
358
359 static void
av1394_it_destroy_ixl(av1394_ic_t * icp)360 av1394_it_destroy_ixl(av1394_ic_t *icp)
361 {
362 av1394_it_t *itp = &icp->ic_it;
363
364 av1394_it_ixl_destroy_data(icp);
365 itp->it_ixlp = NULL;
366 }
367
368 /*
369 * build data transmit part of the IXL chain
370 */
371 static int
av1394_it_ixl_bld_data(av1394_ic_t * icp)372 av1394_it_ixl_bld_data(av1394_ic_t *icp)
373 {
374 av1394_it_t *itp = &icp->ic_it;
375 av1394_isoch_pool_t *pool = &itp->it_data_pool;
376 int total = 0; /* # of pkts in the chain */
377 int nfull = 0; /* # of full CIPs in a series */
378 int framenum = -1; /* frame number */
379 int bufsz_max; /* max buffer size in pkts */
380 int segnum = 0; /* current segment number */
381 int segsz; /* segment size in pkts */
382 off_t segoff = 0; /* segment offset in pkts */
383 av1394_it_ixl_empty_cip_t *ep = NULL; /* last empty CIP */
384 av1394_it_ixl_buf_t *bp = NULL; /* last data buffer */
385 av1394_it_ixl_buf_t *prevbp = NULL;
386 int a, n, d; /* N/D algorithm variables */
387 int type, ptype; /* current and prev CIP type */
388 int tb_flags;
389
390 itp->it_frame_info = kmem_zalloc(icp->ic_nframes *
391 sizeof (av1394_it_frame_info_t), KM_SLEEP);
392
393 bufsz_max = AV1394_IXL_BUFSZ_MAX / icp->ic_pktsz;
394 n = icp->ic_param.cp_n;
395 d = icp->ic_param.cp_d;
396 /*
397 * following assert guarantees no more than one empty CIP in a row,
398 * i.e. empty CIPs account for <=50% of all packets.
399 * this should be ensured by ioctl argument validation.
400 */
401 ASSERT((n == 0) || (d / n > 1));
402 /*
403 * build the chain. it is hard to precalculate amount of memory
404 * needed for the entire chain, so we simply allocate as we go.
405 */
406 ptype = AV1394_CIP_EMPTY;
407 segsz = pool->ip_seg[0].is_size / icp->ic_pktsz;
408 a = n;
409 while (total < icp->ic_nframes * icp->ic_npkts) {
410 /* insert empty CIPs using N/D algorithm */
411 a += n;
412 if (a > d) {
413 a -= d;
414 type = AV1394_CIP_EMPTY;
415 } else {
416 type = AV1394_CIP_FULL;
417 nfull++;
418 }
419
420 /*
421 * merge series of full packets into single SEND_BUF commands.
422 * a series can be terminated by:
423 * - an empty CIP;
424 * - series buffer size reached maximum;
425 * - end of isoch segment;
426 * - end of frame (which is always at the end of segment);
427 */
428 if (((type == AV1394_CIP_EMPTY) || (segoff + nfull == segsz) ||
429 (nfull == bufsz_max)) && (nfull > 0)) {
430
431 /* build buffer block */
432 prevbp = bp;
433 tb_flags = 0;
434 if (type == AV1394_CIP_EMPTY) {
435 tb_flags |= AV1394_IT_IXL_BUF_NEXT_EMPTY;
436 }
437 if (total % icp->ic_npkts == 0) {
438 tb_flags |= AV1394_IT_IXL_BUF_SOF;
439 framenum++;
440 }
441 if ((total + nfull) % icp->ic_npkts == 0) {
442 tb_flags |= AV1394_IT_IXL_BUF_EOF;
443 }
444 bp = av1394_it_ixl_bld_buf(icp, nfull, segnum, segoff,
445 tb_flags, framenum);
446
447 if (itp->it_ixl_data == NULL) {
448 itp->it_ixl_data = &bp->tb_common;
449 }
450
451 /* complete previous empty CIP or a buffer */
452 if (ep) {
453 av1394_it_ixl_complete_empty_cip(ep, bp);
454 ep = NULL;
455 } else if (prevbp) {
456 av1394_it_ixl_complete_buf2(prevbp, bp);
457 }
458
459 /* if current segment is used up, pick next one */
460 segoff += nfull;
461 if (segoff == segsz) {
462 if (++segnum < pool->ip_nsegs) {
463 segsz = pool->ip_seg[segnum].is_size /
464 icp->ic_pktsz;
465 }
466 segoff = 0;
467 }
468
469 total += nfull;
470 nfull = 0;
471 }
472 /* insert an empty packet if needed */
473 if (type == AV1394_CIP_EMPTY) {
474 ep = av1394_it_ixl_bld_empty_cip(icp, framenum);
475 av1394_it_ixl_complete_buf(bp, ep);
476 }
477 ptype = type;
478 }
479 ASSERT(nfull == 0);
480
481 /* last packet must be an empty CIP, except when n == 0 */
482 if (n != 0) {
483 if (ptype != AV1394_CIP_EMPTY) {
484 ep = av1394_it_ixl_bld_empty_cip(icp, framenum);
485 av1394_it_ixl_complete_buf(bp, ep);
486 }
487 av1394_it_ixl_complete_empty_cip(ep,
488 (av1394_it_ixl_buf_t *)itp->it_ixl_data);
489 ep->te_jump.next_ixlp = NULL;
490 ep->te_common.tc_next = NULL;
491 } else {
492 bp->tb_jump.label = (ixl1394_command_t *)
493 &(((av1394_it_ixl_buf_t *)itp->it_ixl_data)->tb_label);
494 }
495
496 return (DDI_SUCCESS);
497 }
498
499 static void
av1394_it_ixl_destroy_data(av1394_ic_t * icp)500 av1394_it_ixl_destroy_data(av1394_ic_t *icp)
501 {
502 av1394_it_t *itp = &icp->ic_it;
503 av1394_it_ixl_common_t *cmd, *cmd_next;
504
505 for (cmd = itp->it_ixl_data; cmd != NULL; cmd = cmd_next) {
506 cmd_next = cmd->tc_next;
507 kmem_free(cmd, cmd->tc_size);
508 }
509 itp->it_ixl_data = NULL;
510
511 kmem_free(itp->it_frame_info,
512 icp->ic_nframes * sizeof (av1394_it_frame_info_t));
513 }
514
515 static av1394_it_ixl_buf_t *
av1394_it_ixl_bld_buf(av1394_ic_t * icp,int cnt,int segnum,off_t off,int flags,int framenum)516 av1394_it_ixl_bld_buf(av1394_ic_t *icp, int cnt, int segnum, off_t off,
517 int flags, int framenum)
518 {
519 av1394_it_t *itp = &icp->ic_it;
520 av1394_isoch_seg_t *isp = &itp->it_data_pool.ip_seg[segnum];
521 av1394_it_ixl_buf_t *bp;
522 int pktsz = icp->ic_pktsz;
523
524 bp = kmem_zalloc(sizeof (av1394_it_ixl_buf_t), KM_SLEEP);
525 bp->tb_common.tc_size = sizeof (av1394_it_ixl_buf_t);
526 /* tc_next later */
527 bp->tb_flags = flags;
528 bp->tb_framenum = framenum;
529 bp->tb_icp = icp;
530
531 bp->tb_label.ixl_opcode = IXL1394_OP_LABEL;
532 bp->tb_label.next_ixlp = (ixl1394_command_t *)&bp->tb_buf;
533
534 bp->tb_buf.ixl_opcode = IXL1394_OP_SEND_BUF;
535 bp->tb_buf.pkt_size = pktsz;
536 bp->tb_buf.size = cnt * pktsz;
537 bp->tb_buf.ixl_buf._dmac_ll =
538 isp->is_dma_cookie[0].dmac_laddress + off * pktsz;
539 bp->tb_buf.mem_bufp = isp->is_kaddr + off * pktsz;
540
541 if (flags & AV1394_IT_IXL_BUF_EOF) {
542 bp->tb_buf.next_ixlp = (ixl1394_command_t *)&bp->tb_store_ts;
543
544 bp->tb_store_ts.ixl_opcode = IXL1394_OP_STORE_TIMESTAMP;
545 bp->tb_store_ts.next_ixlp = (ixl1394_command_t *)&bp->tb_cb;
546
547 bp->tb_cb.ixl_opcode = IXL1394_OP_CALLBACK;
548 bp->tb_cb.callback = av1394_it_ixl_buf_cb;
549 bp->tb_cb.callback_arg = bp;
550 bp->tb_cb.next_ixlp = (ixl1394_command_t *)&bp->tb_jump;
551
552 bp->tb_jump.ixl_opcode = IXL1394_OP_JUMP_U;
553 } else {
554 bp->tb_buf.next_ixlp = (ixl1394_command_t *)&bp->tb_jump;
555
556 bp->tb_jump.ixl_opcode = IXL1394_OP_JUMP;
557 }
558 /*
559 * jump label and next_ixlp later.
560 * unset fields will be set in av1394_it_ixl_complete_buf()
561 *
562 * save additional frame info
563 */
564 if (flags & AV1394_IT_IXL_BUF_SOF) {
565 itp->it_frame_info[framenum].fi_first_buf = bp;
566 itp->it_frame_info[framenum].fi_ts_off = bp->tb_buf.mem_bufp +
567 AV1394_TS_MODE_GET_OFF(icp->ic_param.cp_ts_mode);
568 } else if (flags & AV1394_IT_IXL_BUF_EOF) {
569 itp->it_frame_info[framenum].fi_last_buf = bp;
570 }
571 itp->it_frame_info[framenum].fi_ncycs += cnt;
572
573 return (bp);
574 }
575
576 static void
av1394_it_ixl_complete_buf(av1394_it_ixl_buf_t * bp,av1394_it_ixl_empty_cip_t * ep)577 av1394_it_ixl_complete_buf(av1394_it_ixl_buf_t *bp,
578 av1394_it_ixl_empty_cip_t *ep)
579 {
580 bp->tb_common.tc_next = &ep->te_common;
581 bp->tb_jump.label = bp->tb_jump.next_ixlp =
582 (ixl1394_command_t *)&ep->te_label;
583 }
584
585 static void
av1394_it_ixl_complete_buf2(av1394_it_ixl_buf_t * bp,av1394_it_ixl_buf_t * nextbp)586 av1394_it_ixl_complete_buf2(av1394_it_ixl_buf_t *bp,
587 av1394_it_ixl_buf_t *nextbp)
588 {
589 bp->tb_common.tc_next = &nextbp->tb_common;
590 bp->tb_jump.label = bp->tb_jump.next_ixlp =
591 (ixl1394_command_t *)&nextbp->tb_label;
592 }
593
594 static av1394_it_ixl_empty_cip_t *
av1394_it_ixl_bld_empty_cip(av1394_ic_t * icp,int framenum)595 av1394_it_ixl_bld_empty_cip(av1394_ic_t *icp, int framenum)
596 {
597 av1394_it_t *itp = &icp->ic_it;
598 av1394_it_ixl_empty_cip_t *ep;
599
600 ep = kmem_zalloc(sizeof (av1394_it_ixl_empty_cip_t), KM_SLEEP);
601 ep->te_common.tc_size = sizeof (av1394_it_ixl_empty_cip_t);
602 /* tc_next later */
603
604 ep->te_label.ixl_opcode = IXL1394_OP_LABEL;
605 ep->te_label.next_ixlp = (ixl1394_command_t *)&ep->te_pkt;
606
607 ep->te_pkt.ixl_opcode = IXL1394_OP_SEND_PKT_ST;
608 ep->te_pkt.size = AV1394_CIPSZ;
609 /* ixl_buf and mem_bufp later */
610 ep->te_pkt.next_ixlp = (ixl1394_command_t *)&ep->te_jump;
611
612 ep->te_jump.ixl_opcode = IXL1394_OP_JUMP;
613 /*
614 * label and next_ixlp later.
615 * unset fields will be set in av1394_it_ixl_complete_empty_cip()
616 */
617
618 itp->it_frame_info[framenum].fi_ncycs++;
619
620 return (ep);
621 }
622
623 /*
624 * empty CIP packet contains CIP header of the next packet,
625 * so we just point to the same address as the next packet's header
626 */
627 static void
av1394_it_ixl_complete_empty_cip(av1394_it_ixl_empty_cip_t * ep,av1394_it_ixl_buf_t * bp)628 av1394_it_ixl_complete_empty_cip(av1394_it_ixl_empty_cip_t *ep,
629 av1394_it_ixl_buf_t *bp)
630 {
631 ep->te_common.tc_next = &bp->tb_common;
632
633 ep->te_pkt.ixl_buf._dmac_ll = bp->tb_buf.ixl_buf._dmac_ll;
634 ep->te_pkt.mem_bufp = bp->tb_buf.mem_bufp;
635
636 ep->te_jump.label = ep->te_jump.next_ixlp =
637 (ixl1394_command_t *)&bp->tb_label;
638 }
639
640 static void
av1394_it_ixl_bld_begin(av1394_ic_t * icp)641 av1394_it_ixl_bld_begin(av1394_ic_t *icp)
642 {
643 av1394_it_t *itp = &icp->ic_it;
644 av1394_it_ixl_buf_t *bp = (av1394_it_ixl_buf_t *)itp->it_ixl_data;
645 av1394_it_ixl_begin_t *bep = &itp->it_ixl_begin;
646 int i;
647
648 bep->be_label.ixl_opcode = IXL1394_OP_LABEL;
649 bep->be_label.next_ixlp = (ixl1394_command_t *)&bep->be_empty_pre;
650
651 bep->be_empty_pre.ixl_opcode = IXL1394_OP_SEND_PKT_ST;
652 bep->be_empty_pre.size = AV1394_CIPSZ;
653 bep->be_empty_pre.ixl_buf._dmac_ll = bp->tb_buf.ixl_buf._dmac_ll;
654 bep->be_empty_pre.mem_bufp = bp->tb_buf.mem_bufp;
655 bep->be_empty_pre.next_ixlp = (ixl1394_command_t *)&bep->be_store_ts;
656
657 bep->be_store_ts.ixl_opcode = IXL1394_OP_STORE_TIMESTAMP;
658 bep->be_store_ts.next_ixlp = (ixl1394_command_t *)&bep->be_cb;
659
660 bep->be_cb.ixl_opcode = IXL1394_OP_CALLBACK;
661 bep->be_cb.callback = av1394_it_ixl_begin_cb;
662 bep->be_cb.callback_arg = &bep->be_store_ts.timestamp;
663 bep->be_cb.next_ixlp = (ixl1394_command_t *)&bep->be_empty_post[0];
664
665 for (i = 0; i < AV1394_IT_IXL_BEGIN_NPOST; i++) {
666 bep->be_empty_post[i].ixl_opcode = IXL1394_OP_SEND_PKT_ST;
667 bep->be_empty_post[i].size = AV1394_CIPSZ;
668 bep->be_empty_post[i].ixl_buf._dmac_ll =
669 bp->tb_buf.ixl_buf._dmac_ll;
670 bep->be_empty_post[i].mem_bufp = bp->tb_buf.mem_bufp;
671 bep->be_empty_post[i].next_ixlp =
672 (ixl1394_command_t *)&bep->be_empty_post[i + 1];
673 }
674 bep->be_empty_post[AV1394_IT_IXL_BEGIN_NPOST - 1].next_ixlp =
675 (ixl1394_command_t *)&bep->be_jump;
676
677 bep->be_jump.ixl_opcode = IXL1394_OP_JUMP_U;
678 bep->be_jump.label = (ixl1394_command_t *)&bp->tb_label;
679 bep->be_jump.next_ixlp = (ixl1394_command_t *)&bp->tb_label;
680 }
681
682 static void
av1394_it_ixl_begin_update_pkts(av1394_ic_t * icp,av1394_it_ixl_buf_t * bp)683 av1394_it_ixl_begin_update_pkts(av1394_ic_t *icp, av1394_it_ixl_buf_t *bp)
684 {
685 av1394_it_t *itp = &icp->ic_it;
686 av1394_it_ixl_begin_t *bep = &itp->it_ixl_begin;
687 int i;
688
689 for (i = 0; i < AV1394_IT_IXL_BEGIN_NPOST; i++) {
690 bep->be_empty_post[i].ixl_buf._dmac_ll =
691 bp->tb_buf.ixl_buf._dmac_ll;
692 bep->be_empty_post[i].mem_bufp = bp->tb_buf.mem_bufp;
693 }
694 }
695
696 static int
av1394_it_alloc_isoch_dma(av1394_ic_t * icp)697 av1394_it_alloc_isoch_dma(av1394_ic_t *icp)
698 {
699 av1394_inst_t *avp = icp->ic_avp;
700 av1394_it_t *itp = &icp->ic_it;
701 id1394_isoch_dmainfo_t di;
702 int result;
703 int ret;
704
705 di.ixlp = itp->it_ixlp;
706 di.channel_num = icp->ic_num;
707 di.idma_options = ID1394_TALK;
708 di.it_speed = icp->ic_param.cp_bus_speed;
709 /*
710 * XXX this should really be IXL1394_SKIP_TO_NEXT,
711 * but it can't be used yet due to the Framework bug
712 */
713 di.it_default_skip = IXL1394_SKIP_TO_SELF;
714 di.default_tag = 1;
715 di.default_sync = 0;
716 di.global_callback_arg = icp;
717 di.isoch_dma_stopped = av1394_it_dma_stopped_cb;
718 di.idma_evt_arg = icp;
719
720 ret = t1394_alloc_isoch_dma(avp->av_t1394_hdl, &di, 0,
721 &icp->ic_isoch_hdl, &result);
722
723 return (ret);
724 }
725
726 static void
av1394_it_free_isoch_dma(av1394_ic_t * icp)727 av1394_it_free_isoch_dma(av1394_ic_t *icp)
728 {
729 av1394_inst_t *avp = icp->ic_avp;
730
731 t1394_free_isoch_dma(avp->av_t1394_hdl, 0, &icp->ic_isoch_hdl);
732 }
733
734 static void
av1394_it_dma_sync_frames(av1394_ic_t * icp,int idx,int cnt)735 av1394_it_dma_sync_frames(av1394_ic_t *icp, int idx, int cnt)
736 {
737 av1394_ic_dma_sync_frames(icp, idx, cnt,
738 &icp->ic_it.it_data_pool, DDI_DMA_SYNC_FORDEV);
739 }
740
741 /*
742 *
743 * --- callbacks
744 *
745 */
746 static void
av1394_it_ixl_begin_cb(opaque_t arg,struct ixl1394_callback * cb)747 av1394_it_ixl_begin_cb(opaque_t arg, struct ixl1394_callback *cb)
748 {
749 av1394_ic_t *icp = arg;
750 av1394_it_t *itp = &icp->ic_it;
751 uint16_t *cycp = cb->callback_arg; /* cycle timestamp pointer */
752 uint16_t syt;
753 int first;
754
755 mutex_enter(&icp->ic_mutex);
756 /* save initial timestamp value */
757 itp->it_ts_init.ts_syt = av1394_it_ts_cyc2syt(*cycp);
758
759 /*
760 * update frame timestamps if needed
761 */
762 if ((itp->it_nfull <= 0) ||
763 (AV1394_TS_MODE_GET_SIZE(icp->ic_param.cp_ts_mode) == 0)) {
764 mutex_exit(&icp->ic_mutex);
765 return;
766 }
767 ASSERT(itp->it_nfull <= icp->ic_nframes);
768
769 syt = av1394_it_ts_syt_inc(itp->it_ts_init.ts_syt,
770 AV1394_IT_IXL_BEGIN_NPOST + av1394_it_syt_off);
771 first = (itp->it_last_full + icp->ic_nframes - itp->it_nfull + 1) %
772 icp->ic_nframes;
773 av1394_it_update_frame_syt(icp, first, itp->it_nfull, syt);
774 mutex_exit(&icp->ic_mutex);
775 }
776
777 /*ARGSUSED*/
778 static void
av1394_it_ixl_buf_cb(opaque_t arg,struct ixl1394_callback * cb)779 av1394_it_ixl_buf_cb(opaque_t arg, struct ixl1394_callback *cb)
780 {
781 av1394_it_ixl_buf_t *bp = cb->callback_arg;
782
783 if (bp->tb_flags & AV1394_IT_IXL_BUF_EOF) {
784 av1394_it_ixl_eof_cb(bp);
785 }
786 }
787
788 static void
av1394_it_ixl_eof_cb(av1394_it_ixl_buf_t * bp)789 av1394_it_ixl_eof_cb(av1394_it_ixl_buf_t *bp)
790 {
791 av1394_ic_t *icp = bp->tb_icp;
792 av1394_isoch_t *ip = &icp->ic_avp->av_i;
793 av1394_it_t *itp = &icp->ic_it;
794
795 mutex_enter(&ip->i_mutex);
796 mutex_enter(&icp->ic_mutex);
797 if (itp->it_nempty < icp->ic_nframes) {
798 itp->it_nempty++;
799 itp->it_nfull--;
800 cv_signal(&icp->ic_xfer_cv);
801 }
802
803 if ((itp->it_nempty >= itp->it_hiwat) &&
804 (icp->ic_state == AV1394_IC_DMA)) {
805 av1394_ic_trigger_softintr(icp, icp->ic_num,
806 AV1394_PREQ_IT_UNDERRUN);
807 }
808 mutex_exit(&icp->ic_mutex);
809 mutex_exit(&ip->i_mutex);
810 }
811
812 void
av1394_it_underrun(av1394_ic_t * icp)813 av1394_it_underrun(av1394_ic_t *icp)
814 {
815 av1394_it_t *itp = &icp->ic_it;
816 av1394_inst_t *avp = icp->ic_avp;
817 int idx;
818 ixl1394_jump_t *old_jmp;
819 ixl1394_jump_t new_jmp;
820 id1394_isoch_dma_updateinfo_t update_info;
821 int err;
822 int result;
823
824 /*
825 * update the last full frame's jump to NULL
826 */
827 idx = (itp->it_first_empty + icp->ic_nframes - 1) % icp->ic_nframes;
828
829 old_jmp = &itp->it_frame_info[idx].fi_last_buf->tb_jump;
830 itp->it_saved_label = old_jmp->label;
831
832 new_jmp.ixl_opcode = IXL1394_OP_JUMP_U;
833 new_jmp.label = NULL;
834 new_jmp.next_ixlp = NULL;
835
836 update_info.orig_ixlp = (ixl1394_command_t *)old_jmp;
837 update_info.temp_ixlp = (ixl1394_command_t *)&new_jmp;
838 update_info.ixl_count = 1;
839
840 mutex_exit(&icp->ic_mutex);
841 err = t1394_update_isoch_dma(avp->av_t1394_hdl,
842 icp->ic_isoch_hdl, &update_info, 0, &result);
843 mutex_enter(&icp->ic_mutex);
844
845 if (err == DDI_SUCCESS) {
846 itp->it_underrun_idx = idx;
847 icp->ic_state = AV1394_IC_SUSPENDED;
848 cv_signal(&icp->ic_xfer_cv);
849 }
850 }
851
852 /*
853 * resume from the underrun condition
854 */
855 static int
av1394_it_underrun_resume(av1394_ic_t * icp)856 av1394_it_underrun_resume(av1394_ic_t *icp)
857 {
858 av1394_it_t *itp = &icp->ic_it;
859 av1394_inst_t *avp = icp->ic_avp;
860 av1394_it_ixl_buf_t *bp;
861 int idx;
862 ixl1394_jump_t *old_jmp;
863 ixl1394_jump_t new_jmp;
864 id1394_isoch_dma_updateinfo_t update_info;
865 int err;
866 int result;
867
868 /*
869 * resuming the transfer it a lot like starting the transfer:
870 * first the IXL begin block needs to be executed, then the rest
871 * of the IXL chain. The following dynamic updates are needed:
872 *
873 * 1. update the begin block to jump to the first empty frame;
874 * 2. restore the original jump label which we previously
875 * changed to jump to the underrun block;
876 *
877 * update #1
878 * start by updating the begin block with a new buffer address
879 */
880 idx = (itp->it_underrun_idx + 1) % icp->ic_nframes;
881 bp = itp->it_frame_info[idx].fi_first_buf;
882 av1394_it_ixl_begin_update_pkts(icp, bp);
883
884 old_jmp = &itp->it_ixl_begin.be_jump;
885
886 new_jmp.ixl_opcode = IXL1394_OP_JUMP_U;
887 new_jmp.label = (ixl1394_command_t *)&bp->tb_label;
888 new_jmp.next_ixlp = NULL;
889
890 update_info.orig_ixlp = (ixl1394_command_t *)old_jmp;
891 update_info.temp_ixlp = (ixl1394_command_t *)&new_jmp;
892 update_info.ixl_count = 1;
893
894 mutex_exit(&icp->ic_mutex);
895 err = t1394_update_isoch_dma(avp->av_t1394_hdl,
896 icp->ic_isoch_hdl, &update_info, 0, &result);
897 mutex_enter(&icp->ic_mutex);
898
899 if (err != DDI_SUCCESS) {
900 return (EIO);
901 }
902
903 /*
904 * update #2
905 */
906 bp = itp->it_frame_info[itp->it_underrun_idx].fi_last_buf;
907 old_jmp = &bp->tb_jump;
908
909 new_jmp.ixl_opcode = IXL1394_OP_JUMP_U;
910 new_jmp.label = itp->it_saved_label;
911 new_jmp.next_ixlp = NULL;
912
913 update_info.orig_ixlp = (ixl1394_command_t *)old_jmp;
914 update_info.temp_ixlp = (ixl1394_command_t *)&new_jmp;
915 update_info.ixl_count = 1;
916
917 mutex_exit(&icp->ic_mutex);
918 err = t1394_update_isoch_dma(avp->av_t1394_hdl,
919 icp->ic_isoch_hdl, &update_info, 0, &result);
920 mutex_enter(&icp->ic_mutex);
921
922 if (err != DDI_SUCCESS) {
923 return (EIO);
924 }
925
926 icp->ic_state = AV1394_IC_DMA;
927
928 return (0);
929 }
930
931 /*ARGSUSED*/
932 static void
av1394_it_dma_stopped_cb(t1394_isoch_dma_handle_t t1394_idma_hdl,opaque_t idma_evt_arg,id1394_isoch_dma_stopped_t status)933 av1394_it_dma_stopped_cb(t1394_isoch_dma_handle_t t1394_idma_hdl,
934 opaque_t idma_evt_arg, id1394_isoch_dma_stopped_t status)
935 {
936 av1394_ic_t *icp = idma_evt_arg;
937
938 mutex_enter(&icp->ic_mutex);
939 icp->ic_state = AV1394_IC_IDLE;
940 mutex_exit(&icp->ic_mutex);
941 }
942
943
944 /*
945 *
946 * --- data transfer routines
947 *
948 * av1394_it_add_frames()
949 * Add full frames to the pool.
950 */
951 static int
av1394_it_add_frames(av1394_ic_t * icp,int idx,int cnt)952 av1394_it_add_frames(av1394_ic_t *icp, int idx, int cnt)
953 {
954 av1394_it_t *itp = &icp->ic_it;
955 av1394_it_frame_info_t *fip;
956 int prev_full = itp->it_last_full;
957 uint16_t syt;
958 int ret = 0;
959
960 /* can only add to tail */
961 if (idx != ((itp->it_last_full + 1) % icp->ic_nframes)) {
962 return (EINVAL);
963 }
964
965 /* turn empty frames into full ones */
966 itp->it_nempty -= cnt;
967 itp->it_first_empty = (itp->it_first_empty + cnt) % icp->ic_nframes;
968 itp->it_nfull += cnt;
969 itp->it_last_full = (itp->it_last_full + cnt) % icp->ic_nframes;
970 ASSERT((itp->it_nempty >= 0) && (itp->it_nfull <= icp->ic_nframes));
971
972 /*
973 * update frame timestamps if needed
974 */
975 if (AV1394_TS_MODE_GET_SIZE(icp->ic_param.cp_ts_mode) > 0) {
976 ASSERT(prev_full >= 0);
977 fip = &itp->it_frame_info[prev_full];
978 syt = *(uint16_t *)fip->fi_ts_off;
979 syt = av1394_it_ts_syt_inc(syt, fip->fi_ncycs);
980 av1394_it_update_frame_syt(icp, idx, cnt, syt);
981 }
982
983 av1394_it_dma_sync_frames(icp, idx, cnt);
984
985 /* if suspended due to overrun, check if we can resume */
986 if ((icp->ic_state == AV1394_IC_SUSPENDED) &&
987 (itp->it_nempty >= itp->it_lowat)) {
988 ret = av1394_it_underrun_resume(icp);
989 }
990
991 return (ret);
992 }
993
994 /*
995 * wait for empty frames
996 */
997 static int
av1394_it_wait_frames(av1394_ic_t * icp,int * idx,int * cnt,int * nlost)998 av1394_it_wait_frames(av1394_ic_t *icp, int *idx, int *cnt, int *nlost)
999 {
1000 av1394_it_t *itp = &icp->ic_it;
1001 int ret = 0;
1002
1003 while ((itp->it_nempty == 0) && (icp->ic_state == AV1394_IC_DMA)) {
1004 if (cv_wait_sig(&icp->ic_xfer_cv, &icp->ic_mutex) <= 0) {
1005 ret = EINTR;
1006 break;
1007 }
1008 }
1009
1010 if (itp->it_nempty > 0) {
1011 *idx = itp->it_first_empty;
1012 *cnt = itp->it_nempty;
1013 *nlost = 0;
1014 ret = 0;
1015 }
1016 return (ret);
1017 }
1018
1019 /*
1020 * update frame timestamps for a range of frames
1021 */
1022 static void
av1394_it_update_frame_syt(av1394_ic_t * icp,int first,int cnt,uint16_t syt)1023 av1394_it_update_frame_syt(av1394_ic_t *icp, int first, int cnt, uint16_t syt)
1024 {
1025 av1394_it_t *itp = &icp->ic_it;
1026 int i;
1027 int j = first; /* frame number */
1028
1029 for (i = cnt; i > 0; i--) {
1030 *(uint16_t *)itp->it_frame_info[j].fi_ts_off = syt;
1031 syt = av1394_it_ts_syt_inc(syt, itp->it_frame_info[j].fi_ncycs);
1032 j = (j + 1) % icp->ic_nframes;
1033 }
1034 }
1035
1036 /*
1037 * convert cycle timestamp into SYT timestamp:
1038 *
1039 * Cycle timer: cycleSeconds cycleCount cycleOffset
1040 * 31_30_29_28_27_26_25 24___15_14_13_12 11________0
1041 * Cycle timestamp: |------------------------|
1042 * SYT timestamp: |----------------------|
1043 */
1044 static uint16_t
av1394_it_ts_cyc2syt(uint16_t cyc)1045 av1394_it_ts_cyc2syt(uint16_t cyc)
1046 {
1047 return (((cyc & 0xF) << 12) + 0x800);
1048 }
1049
1050 /*
1051 * increment SYT by a number of cycles
1052 */
1053 static uint16_t
av1394_it_ts_syt_inc(uint16_t syt,uint16_t ncycs)1054 av1394_it_ts_syt_inc(uint16_t syt, uint16_t ncycs)
1055 {
1056 return (syt + (ncycs << 12));
1057 }
1058
1059 /*
1060 * copyin from the kernel buffer
1061 */
1062 static void
av1394_it_kcopyin(av1394_ic_t * icp,void * buf,size_t len)1063 av1394_it_kcopyin(av1394_ic_t *icp, void *buf, size_t len)
1064 {
1065 av1394_it_t *itp = &icp->ic_it;
1066 av1394_isoch_seg_t *seg = itp->it_data_pool.ip_seg;
1067
1068 ASSERT(itp->it_write_off + len < icp->ic_framesz);
1069
1070 bcopy(buf, seg[itp->it_write_idx].is_kaddr + itp->it_write_off, len);
1071 itp->it_write_off += len;
1072 }
1073
1074 /*
1075 * copyin from the user buffer
1076 */
1077 static int
av1394_it_copyin(av1394_ic_t * icp,struct uio * uiop,int * full_cnt,int dv)1078 av1394_it_copyin(av1394_ic_t *icp, struct uio *uiop, int *full_cnt, int dv)
1079 {
1080 av1394_it_t *itp = &icp->ic_it;
1081 av1394_isoch_seg_t *seg = itp->it_data_pool.ip_seg;
1082 int idx = itp->it_write_idx;
1083 int framesz = icp->ic_framesz;
1084 size_t len, frame_resid, start_resid;
1085 caddr_t kaddr, kaddr_end;
1086 int ret = 0;
1087
1088 *full_cnt = 0;
1089
1090 while ((uiop->uio_resid > 0) && (itp->it_write_cnt > 0)) {
1091 kaddr = seg[idx].is_kaddr + itp->it_write_off;
1092 frame_resid = framesz - itp->it_write_off;
1093 len = min(uiop->uio_resid, frame_resid);
1094
1095 mutex_exit(&icp->ic_mutex);
1096 ret = uiomove(kaddr, len, UIO_WRITE, uiop);
1097 mutex_enter(&icp->ic_mutex);
1098 if (ret != 0) {
1099 break;
1100 }
1101
1102 itp->it_write_off += len;
1103 if ((itp->it_write_off == framesz) && dv) {
1104 /*
1105 * for DV formats, make sure we got a frame start.
1106 * this is to ensure correct timestamping
1107 */
1108 kaddr = seg[idx].is_kaddr;
1109 kaddr_end = kaddr + framesz;
1110 while (!av1394_it_is_dv_frame_start(kaddr)) {
1111 kaddr += icp->ic_pktsz;
1112 if (kaddr == kaddr_end) {
1113 break;
1114 }
1115 }
1116 start_resid = kaddr_end - kaddr;
1117 if (start_resid != framesz) {
1118 bcopy(kaddr, seg[idx].is_kaddr, start_resid);
1119 itp->it_write_off = start_resid;
1120 }
1121 }
1122 if (itp->it_write_off == framesz) {
1123 /* for DV formats, reset frame's SYT fields */
1124 if (dv) {
1125 av1394_it_reset_frame_syt(icp, idx);
1126 }
1127 itp->it_write_off = 0;
1128 itp->it_write_cnt--;
1129 idx = (idx + 1) % icp->ic_nframes;
1130 (*full_cnt)++;
1131 }
1132 }
1133
1134 return (ret);
1135 }
1136
1137 /*
1138 * check if a packet starts a new DV frame
1139 */
1140 static boolean_t
av1394_it_is_dv_frame_start(caddr_t kaddr)1141 av1394_it_is_dv_frame_start(caddr_t kaddr)
1142 {
1143 uint8_t *p = (uint8_t *)kaddr + 8;
1144 /*
1145 * in the DIF block ID data, which immediately follows CIP header,
1146 * SCT, Dseq and DBN fields should be zero (Ref: IEC 61834-2, Fig. 66)
1147 */
1148 return (((p[0] & 0xE0) == 0) && ((p[1] & 0xF0) == 0) && (p[2] == 0));
1149 }
1150
1151 /*
1152 * reset all frame's SYT fields
1153 */
1154 static void
av1394_it_reset_frame_syt(av1394_ic_t * icp,int idx)1155 av1394_it_reset_frame_syt(av1394_ic_t *icp, int idx)
1156 {
1157 caddr_t kaddr = icp->ic_it.it_data_pool.ip_seg[idx].is_kaddr;
1158 caddr_t kaddr_end = kaddr + icp->ic_framesz;
1159
1160 kaddr += 6;
1161 while (kaddr < kaddr_end) {
1162 *(uint16_t *)kaddr = 0xFFFF;
1163 kaddr += icp->ic_pktsz;
1164 }
1165 }
1166