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