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 * routines common to isoch receive and isoch transmit 31 */ 32 #include <sys/stat.h> 33 #include <sys/systm.h> 34 #include <sys/ddi.h> 35 #include <sys/sunddi.h> 36 #include <sys/bitmap.h> 37 #include <sys/av/iec61883.h> 38 #include <sys/1394/targets/av1394/av1394_impl.h> 39 40 /* configuration routines */ 41 static void av1394_ic_cleanup(av1394_ic_t *icp, int level); 42 static int av1394_ic_validate_init_params(iec61883_isoch_init_t *ii); 43 static void av1394_ic_set_params(av1394_inst_t *avp, 44 iec61883_isoch_init_t *ii, av1394_ic_t *icp, int num); 45 static int av1394_ic_alloc_channel(av1394_ic_t *icp, uint64_t mask, int *); 46 static void av1394_ic_free_channel(av1394_ic_t *icp); 47 48 /* callbacks */ 49 static void av1394_ic_rsrc_fail(t1394_isoch_single_handle_t t1394_sii_hdl, 50 opaque_t arg, t1394_isoch_rsrc_error_t fail_args); 51 52 uint64_t av1394_ic_bitreverse(uint64_t); 53 boolean_t av1394_ic_onebit(uint64_t); 54 55 #define AV1394_TNF_ENTER(func) \ 56 TNF_PROBE_0_DEBUG(func##_enter, AV1394_TNF_ISOCH_STACK, ""); 57 58 #define AV1394_TNF_EXIT(func) \ 59 TNF_PROBE_0_DEBUG(func##_exit, AV1394_TNF_ISOCH_STACK, ""); 60 61 /* tunables */ 62 extern int av1394_rate_n_dv_ntsc; 63 extern int av1394_rate_d_dv_ntsc; 64 extern int av1394_rate_n_dv_pal; 65 extern int av1394_rate_d_dv_pal; 66 67 /*ARGSUSED*/ 68 int 69 av1394_ic_close(av1394_inst_t *avp, int flags) 70 { 71 av1394_isoch_t *ip = &avp->av_i; 72 av1394_ic_t *icp; 73 int i; 74 75 AV1394_TNF_ENTER(av1394_ic_close); 76 77 /* cleanup channels in case application didn't */ 78 for (i = 0; i < NELEM(ip->i_ic); i++) { 79 icp = ip->i_ic[i]; 80 if (icp != NULL) { 81 (void) av1394_ic_stop(icp); 82 av1394_ic_fini(icp); 83 } 84 } 85 86 AV1394_TNF_EXIT(av1394_ic_close); 87 return (0); 88 } 89 90 /* 91 * av1394_ic_init() 92 * Channel allocation and initialization. 93 */ 94 int 95 av1394_ic_init(av1394_inst_t *avp, iec61883_isoch_init_t *ii, 96 av1394_ic_t **icpp) 97 { 98 av1394_isoch_t *ip = &avp->av_i; 99 av1394_ic_t *icp = NULL; 100 int num; 101 av1394_isoch_pool_t *pool; 102 uint64_t mask; /* channel mask */ 103 int ret; 104 ddi_iblock_cookie_t ibc = avp->av_attachinfo.iblock_cookie; 105 106 AV1394_TNF_ENTER(av1394_ic_init); 107 108 ii->ii_frame_rcnt = 0; 109 ii->ii_rchannel = 0; 110 ii->ii_error = 0; 111 112 if ((ret = av1394_ic_validate_init_params(ii)) != 0) { 113 AV1394_TNF_EXIT(av1394_ic_init); 114 return (ret); 115 } 116 117 /* allocate channel structure */ 118 icp = kmem_zalloc(sizeof (av1394_ic_t), KM_SLEEP); 119 120 mutex_init(&icp->ic_mutex, NULL, MUTEX_DRIVER, ibc); 121 cv_init(&icp->ic_xfer_cv, NULL, CV_DRIVER, NULL); 122 123 av1394_ic_set_params(avp, ii, icp, -1); 124 125 /* allocate isoch channel and bandwidth, except for broadcast */ 126 if (ii->ii_channel == (1ULL << 63)) { 127 num = 63; 128 } else if (ii->ii_flags & IEC61883_PRIV_ISOCH_NOALLOC) { 129 num = lowbit(ii->ii_channel) - 1; 130 } else { 131 mask = av1394_ic_bitreverse(ii->ii_channel); 132 ret = av1394_ic_alloc_channel(icp, mask, &num); 133 if (ret != DDI_SUCCESS) { 134 ii->ii_error = IEC61883_ERR_NOCHANNEL; 135 av1394_ic_cleanup(icp, 1); 136 AV1394_TNF_EXIT(av1394_ic_init); 137 return (EINVAL); 138 } 139 } 140 ASSERT((num >= 0) && (num < 64)); 141 142 mutex_enter(&icp->ic_mutex); 143 icp->ic_num = num; 144 mutex_exit(&icp->ic_mutex); 145 146 mutex_enter(&ip->i_mutex); 147 if (ip->i_ic[num] != NULL) { 148 mutex_exit(&ip->i_mutex); 149 ii->ii_error = IEC61883_ERR_NOCHANNEL; 150 av1394_ic_cleanup(icp, 2); 151 TNF_PROBE_0(av1394_ic_init_error_chan_used, 152 AV1394_TNF_ISOCH_ERROR, ""); 153 AV1394_TNF_EXIT(av1394_ic_init); 154 return (EINVAL); 155 } 156 ip->i_ic[num] = icp; 157 mutex_exit(&ip->i_mutex); 158 159 /* do direction specific initialization */ 160 if (icp->ic_dir == AV1394_IR) { 161 ret = av1394_ir_init(icp, &ii->ii_error); 162 pool = &icp->ic_ir.ir_data_pool; 163 } else { 164 ret = av1394_it_init(icp, &ii->ii_error); 165 pool = &icp->ic_it.it_data_pool; 166 } 167 168 if (ret != 0) { 169 av1394_ic_cleanup(icp, 3); 170 AV1394_TNF_EXIT(av1394_ic_init); 171 return (ret); 172 } 173 174 /* allocate mmap space */ 175 mutex_enter(&ip->i_mutex); 176 mutex_enter(&icp->ic_mutex); 177 icp->ic_mmap_sz = pool->ip_umem_size; 178 icp->ic_mmap_off = av1394_as_alloc(&ip->i_mmap_as, icp->ic_mmap_sz); 179 180 icp->ic_state = AV1394_IC_IDLE; 181 182 *icpp = icp; 183 ii->ii_handle = icp->ic_num; 184 ii->ii_frame_rcnt = icp->ic_nframes; 185 ii->ii_mmap_off = icp->ic_mmap_off; 186 ii->ii_rchannel = icp->ic_num; 187 mutex_exit(&icp->ic_mutex); 188 mutex_exit(&ip->i_mutex); 189 190 TNF_PROBE_2_DEBUG(av1394_ic_init, AV1394_TNF_ISOCH, "", 191 tnf_string, msg, "channel allocated", tnf_int, num, icp->ic_num); 192 193 AV1394_TNF_EXIT(av1394_ic_init); 194 return (0); 195 } 196 197 void 198 av1394_ic_fini(av1394_ic_t *icp) 199 { 200 AV1394_TNF_ENTER(av1394_ic_fini); 201 202 av1394_ic_cleanup(icp, AV1394_CLEANUP_LEVEL_MAX); 203 204 AV1394_TNF_EXIT(av1394_ic_fini); 205 } 206 207 /* 208 * 209 * --- configuration routines 210 * 211 */ 212 static void 213 av1394_ic_cleanup(av1394_ic_t *icp, int level) 214 { 215 av1394_inst_t *avp = icp->ic_avp; 216 av1394_isoch_t *ip = &avp->av_i; 217 218 ASSERT((level > 0) && (level <= AV1394_CLEANUP_LEVEL_MAX)); 219 220 switch (level) { 221 default: 222 if (icp->ic_dir == AV1394_IR) { 223 av1394_ir_fini(icp); 224 } else { 225 av1394_it_fini(icp); 226 } 227 /* FALLTHRU */ 228 case 3: 229 mutex_enter(&ip->i_mutex); 230 av1394_as_free(&ip->i_mmap_as, icp->ic_mmap_off); 231 ip->i_ic[icp->ic_num] = NULL; 232 mutex_exit(&ip->i_mutex); 233 /* FALLTHRU */ 234 case 2: 235 av1394_ic_free_channel(icp); 236 /* FALLTHRU */ 237 case 1: 238 cv_destroy(&icp->ic_xfer_cv); 239 mutex_destroy(&icp->ic_mutex); 240 kmem_free(icp, sizeof (av1394_ic_t)); 241 } 242 } 243 244 static int 245 av1394_ic_validate_init_params(iec61883_isoch_init_t *ii) 246 { 247 int framesz; 248 249 ii->ii_error = 0; 250 if ((IEC61883_IMPL_VER_MAJOR(ii->ii_version) != 251 IEC61883_IMPL_VER_MAJOR(AV1394_IEC61883_VER)) || 252 (IEC61883_IMPL_VER_MINOR(ii->ii_version) > 253 IEC61883_IMPL_VER_MINOR(AV1394_IEC61883_VER))) { 254 TNF_PROBE_0(av1394_ic_validate_init_params_ver_error, 255 AV1394_TNF_ISOCH_ERROR, ""); 256 ii->ii_error = IEC61883_ERR_VERSION; 257 return (EINVAL); 258 } 259 if ((ii->ii_pkt_size % 4) || (ii->ii_pkt_size > 512)) { 260 TNF_PROBE_0(av1394_ic_validate_init_params_pktsz_error, 261 AV1394_TNF_ISOCH_ERROR, ""); 262 ii->ii_error = IEC61883_ERR_PKT_SIZE; 263 return (EINVAL); 264 } 265 framesz = ii->ii_frame_size * ii->ii_pkt_size; 266 if ((framesz > AV1394_IC_FRAME_SIZE_MAX) || 267 (framesz < AV1394_IXL_BUFSZ_MAX)) { 268 TNF_PROBE_0(av1394_ic_validate_init_params_frsz_error, 269 AV1394_TNF_ISOCH_ERROR, ""); 270 ii->ii_error = IEC61883_ERR_NOMEM; 271 return (EINVAL); 272 } 273 if ((ii->ii_direction != IEC61883_DIR_RECV) && 274 (ii->ii_direction != IEC61883_DIR_XMIT)) { 275 TNF_PROBE_0(av1394_ic_validate_init_params_dir_error, 276 AV1394_TNF_ISOCH_ERROR, ""); 277 ii->ii_error = IEC61883_ERR_INVAL; 278 return (EINVAL); 279 } 280 if (((ii->ii_direction == IEC61883_DIR_RECV) && 281 (ii->ii_frame_cnt < AV1394_IR_NFRAMES_MIN)) || 282 ((ii->ii_direction == IEC61883_DIR_XMIT) && 283 (ii->ii_frame_cnt < AV1394_IT_NFRAMES_MIN))) { 284 TNF_PROBE_0(av1394_ic_validate_init_params_frcnt_error, 285 AV1394_TNF_ISOCH_ERROR, ""); 286 ii->ii_error = IEC61883_ERR_INVAL; 287 return (EINVAL); 288 } 289 if ((ii->ii_bus_speed != IEC61883_S100) && 290 (ii->ii_bus_speed != IEC61883_S200) && 291 (ii->ii_bus_speed != IEC61883_S400)) { 292 TNF_PROBE_0(av1394_ic_validate_init_params_speed_error, 293 AV1394_TNF_ISOCH_ERROR, ""); 294 ii->ii_error = IEC61883_ERR_INVAL; 295 return (EINVAL); 296 } 297 if (ii->ii_channel == 0) { 298 TNF_PROBE_0(av1394_ic_validate_init_params_chan_error, 299 AV1394_TNF_ISOCH_ERROR, ""); 300 ii->ii_error = IEC61883_ERR_INVAL; 301 return (EINVAL); 302 } 303 if ((ii->ii_flags & IEC61883_PRIV_ISOCH_NOALLOC) && 304 !av1394_ic_onebit(ii->ii_channel)) { 305 TNF_PROBE_0(av1394_ic_validate_init_params_chan_onebit_error, 306 AV1394_TNF_ISOCH_ERROR, ""); 307 ii->ii_error = IEC61883_ERR_INVAL; 308 return (EINVAL); 309 } 310 /* the rest are xmit only */ 311 if (ii->ii_direction == IEC61883_DIR_RECV) { 312 return (0); 313 } 314 if (((ii->ii_rate_d != 0) || 315 (ii->ii_rate_n != IEC61883_RATE_N_DV_NTSC) && 316 (ii->ii_rate_n != IEC61883_RATE_N_DV_PAL)) && 317 ((ii->ii_rate_d <= 0) || (ii->ii_rate_n < 0) || 318 ((ii->ii_rate_n != 0) && (ii->ii_rate_d / ii->ii_rate_n < 2)))) { 319 TNF_PROBE_0(av1394_ic_validate_init_params_rate_error, 320 AV1394_TNF_ISOCH_ERROR, ""); 321 ii->ii_error = IEC61883_ERR_INVAL; 322 return (EINVAL); 323 } 324 if (AV1394_TS_MODE_GET_OFF(ii->ii_ts_mode) + 325 AV1394_TS_MODE_GET_SIZE(ii->ii_ts_mode) > ii->ii_pkt_size) { 326 TNF_PROBE_0(av1394_ic_validate_init_params_ts_error, 327 AV1394_TNF_ISOCH_ERROR, ""); 328 ii->ii_error = IEC61883_ERR_INVAL; 329 return (EINVAL); 330 } 331 return (0); 332 } 333 334 static void 335 av1394_ic_set_params(av1394_inst_t *avp, iec61883_isoch_init_t *ii, 336 av1394_ic_t *icp, int num) 337 { 338 av1394_ic_param_t *cp = &icp->ic_param; 339 340 mutex_enter(&icp->ic_mutex); 341 icp->ic_avp = avp; 342 icp->ic_num = num; 343 icp->ic_dir = (ii->ii_direction == IEC61883_DIR_RECV) ? 344 AV1394_IR : AV1394_IT; 345 icp->ic_pktsz = ii->ii_pkt_size; 346 icp->ic_npkts = ii->ii_frame_size; 347 icp->ic_framesz = icp->ic_pktsz * icp->ic_npkts; 348 icp->ic_nframes = ii->ii_frame_cnt; 349 cp->cp_bus_speed = ii->ii_bus_speed; 350 cp->cp_dbs = ii->ii_dbs; 351 cp->cp_fn = ii->ii_fn; 352 if (icp->ic_dir == AV1394_IT) { 353 if (ii->ii_rate_d == 0) { 354 switch (ii->ii_rate_n) { 355 case IEC61883_RATE_N_DV_NTSC: 356 cp->cp_n = av1394_rate_n_dv_ntsc; 357 cp->cp_d = av1394_rate_d_dv_ntsc; 358 break; 359 case IEC61883_RATE_N_DV_PAL: 360 cp->cp_n = av1394_rate_n_dv_pal; 361 cp->cp_d = av1394_rate_d_dv_pal; 362 break; 363 default: 364 ASSERT(0); /* can't happen */ 365 } 366 } else { 367 cp->cp_n = ii->ii_rate_n; 368 cp->cp_d = ii->ii_rate_d; 369 } 370 } 371 cp->cp_ts_mode = ii->ii_ts_mode; 372 mutex_exit(&icp->ic_mutex); 373 } 374 375 static int 376 av1394_ic_alloc_channel(av1394_ic_t *icp, uint64_t mask, int *num) 377 { 378 av1394_inst_t *avp = icp->ic_avp; 379 int ret, result; 380 t1394_isoch_singleinfo_t sii; 381 t1394_isoch_single_out_t so; 382 383 /* allocate isoch channel */ 384 sii.si_channel_mask = mask; 385 sii.si_bandwidth = icp->ic_pktsz; 386 sii.rsrc_fail_target = av1394_ic_rsrc_fail; 387 sii.single_evt_arg = icp; 388 sii.si_speed = icp->ic_param.cp_bus_speed; 389 390 ret = t1394_alloc_isoch_single(avp->av_t1394_hdl, &sii, 0, &so, 391 &icp->ic_sii_hdl, &result); 392 if (ret != DDI_SUCCESS) { 393 TNF_PROBE_1(av1394_ic_alloc_channel_error, 394 AV1394_TNF_ISOCH_ERROR, "", tnf_int, result, result); 395 } else { 396 *num = so.channel_num; 397 } 398 return (ret); 399 } 400 401 static void 402 av1394_ic_free_channel(av1394_ic_t *icp) 403 { 404 av1394_inst_t *avp = icp->ic_avp; 405 406 if (icp->ic_sii_hdl != NULL) { 407 t1394_free_isoch_single(avp->av_t1394_hdl, &icp->ic_sii_hdl, 0); 408 } 409 } 410 411 /* 412 * 413 * --- memory allocation and mapping routines 414 * 415 * av1394_ic_alloc_pool() 416 * Allocate isoch pool for at least 'mincnt' and at most 'cnt' frames 417 * 'framesz' bytes each. The strategy is to allocate segments of reasonably 418 * large size, to avoid fragmentation and use resources efficiently in case 419 * of a large number of very small frames. 420 * 421 * Another problem is that RECV/SEND_BUF IXL commands can address limited 422 * amount of buffer space (AV1394_IXL_BUFSZ_MAX), and if segment size and 423 * buffer size are not aligned, it can make much harder to build IXL chains. 424 * To simplify things, segments shall always contain full frames. 425 * 426 * Function returns number of frames the resulting pool can hold. 427 */ 428 int 429 av1394_ic_alloc_pool(av1394_isoch_pool_t *pool, size_t framesz, int cnt, 430 int mincnt) 431 { 432 av1394_isoch_seg_t *seg; 433 int fps; /* frames per segment */ 434 int nsegs; 435 size_t totalsz, segsz; 436 int i; 437 int ret; 438 439 AV1394_TNF_ENTER(av1394_ic_alloc_pool); 440 441 totalsz = framesz * cnt; 442 ASSERT(totalsz > 0); 443 444 /* request should be reasonable */ 445 if (btopr(totalsz) > physmem / AV1394_MEM_MAX_PERCENT) { 446 TNF_PROBE_0(av1394_ic_alloc_pool_error_physmem, 447 AV1394_TNF_ISOCH_ERROR, ""); 448 AV1394_TNF_EXIT(av1394_ic_alloc_pool); 449 return (0); 450 } 451 452 /* calculate segment size and number of segments */ 453 segsz = framesz; 454 nsegs = cnt; 455 if (framesz < AV1394_IXL_BUFSZ_MAX / 2) { 456 fps = AV1394_IXL_BUFSZ_MAX / framesz; 457 segsz *= fps; 458 nsegs /= fps; 459 } 460 ASSERT(segsz * nsegs >= totalsz); 461 462 /* allocate segment array */ 463 pool->ip_alloc_size = nsegs * sizeof (av1394_isoch_seg_t); 464 pool->ip_seg = kmem_zalloc(pool->ip_alloc_size, KM_SLEEP); 465 466 /* allocate page-aligned user-mappable memory for each segment */ 467 pool->ip_nsegs = 0; 468 pool->ip_size = 0; 469 pool->ip_umem_size = 0; 470 for (i = 0; i < nsegs; i++) { 471 seg = &pool->ip_seg[i]; 472 473 seg->is_umem_size = ptob(btopr(segsz)); 474 seg->is_kaddr = ddi_umem_alloc(seg->is_umem_size, 475 DDI_UMEM_SLEEP, &seg->is_umem_cookie); 476 if (seg->is_kaddr == NULL) { 477 TNF_PROBE_0(av1394_ic_alloc_pool_error_umem_alloc, 478 AV1394_TNF_ISOCH_ERROR, ""); 479 break; 480 } 481 seg->is_size = segsz; 482 483 pool->ip_size += seg->is_size; 484 pool->ip_umem_size += seg->is_umem_size; 485 pool->ip_nsegs++; 486 } 487 488 /* number of frames the pool can hold */ 489 ret = pool->ip_size / framesz; 490 if (ret < mincnt) { 491 TNF_PROBE_0(av1394_ic_alloc_pool_error_mincnt, 492 AV1394_TNF_ISOCH_ERROR, ""); 493 av1394_ic_free_pool(pool); 494 ret = 0; 495 } 496 497 AV1394_TNF_EXIT(av1394_ic_alloc_pool); 498 return (ret); 499 } 500 501 void 502 av1394_ic_free_pool(av1394_isoch_pool_t *pool) 503 { 504 int i; 505 506 AV1394_TNF_ENTER(av1394_ic_free_pool); 507 508 if (pool->ip_seg != NULL) { 509 for (i = 0; i < pool->ip_nsegs; i++) { 510 ddi_umem_free(pool->ip_seg[i].is_umem_cookie); 511 } 512 kmem_free(pool->ip_seg, pool->ip_alloc_size); 513 pool->ip_seg = NULL; 514 } 515 516 AV1394_TNF_EXIT(av1394_ic_free_pool); 517 } 518 519 int 520 av1394_ic_dma_setup(av1394_ic_t *icp, av1394_isoch_pool_t *pool) 521 { 522 av1394_inst_t *avp = icp->ic_avp; 523 av1394_isoch_seg_t *isp; 524 uint_t dma_dir; 525 int ret; 526 int i; 527 528 AV1394_TNF_ENTER(av1394_ic_dma_setup); 529 530 dma_dir = (icp->ic_dir == AV1394_IR) ? DDI_DMA_READ : DDI_DMA_WRITE; 531 /* 532 * Alloc and bind a DMA handle for each segment. 533 * Note that we need packet size alignment, but since ddi_umem_alloc'ed 534 * memory is page-aligned and our packets are less than page size (yet) 535 * we don't need to do anything special here. 536 */ 537 for (i = 0; i < pool->ip_nsegs; i++) { 538 isp = &pool->ip_seg[i]; 539 540 ret = ddi_dma_alloc_handle(avp->av_dip, 541 &avp->av_attachinfo.dma_attr, DDI_DMA_DONTWAIT, NULL, 542 &isp->is_dma_hdl); 543 if (ret != DDI_SUCCESS) { 544 TNF_PROBE_0(av1394_ic_dma_setup_error_alloc_hdl, 545 AV1394_TNF_ISOCH_ERROR, ""); 546 av1394_ic_dma_cleanup(icp, pool); 547 AV1394_TNF_EXIT(av1394_ic_dma_setup); 548 return (ret); 549 } 550 551 ret = ddi_dma_addr_bind_handle(isp->is_dma_hdl, NULL, 552 isp->is_kaddr, isp->is_size, 553 dma_dir | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 554 &isp->is_dma_cookie, &isp->is_dma_ncookies); 555 556 if (ret != DDI_DMA_MAPPED) { 557 TNF_PROBE_0(av1394_ic_dma_setup_error_bind_hdl, 558 AV1394_TNF_ISOCH_ERROR, ""); 559 av1394_ic_dma_cleanup(icp, pool); 560 AV1394_TNF_EXIT(av1394_ic_dma_setup); 561 return (DDI_FAILURE); 562 } 563 564 /* multiple cookies not supported (yet) */ 565 if (isp->is_dma_ncookies != 1) { 566 TNF_PROBE_0(av1394_ic_dma_setup_error_ncookies, 567 AV1394_TNF_ISOCH_ERROR, ""); 568 av1394_ic_dma_cleanup(icp, pool); 569 AV1394_TNF_EXIT(av1394_ic_dma_setup); 570 return (DDI_FAILURE); 571 } 572 } 573 574 AV1394_TNF_EXIT(av1394_ic_dma_setup); 575 return (DDI_SUCCESS); 576 } 577 578 /*ARGSUSED*/ 579 void 580 av1394_ic_dma_cleanup(av1394_ic_t *icp, av1394_isoch_pool_t *pool) 581 { 582 av1394_isoch_seg_t *seg; 583 int i; 584 585 AV1394_TNF_ENTER(av1394_ic_dma_cleanup); 586 587 for (i = 0; i < pool->ip_nsegs; i++) { 588 seg = &pool->ip_seg[i]; 589 if (seg->is_dma_hdl != NULL) { 590 if (seg->is_dma_ncookies > 0) { 591 (void) ddi_dma_unbind_handle(seg->is_dma_hdl); 592 } 593 ddi_dma_free_handle(&seg->is_dma_hdl); 594 } 595 } 596 597 AV1394_TNF_EXIT(av1394_ic_dma_cleanup); 598 } 599 600 /* 601 * sync frames for CPU access 602 */ 603 void 604 av1394_ic_dma_sync_frames(av1394_ic_t *icp, int idx, int cnt, 605 av1394_isoch_pool_t *pool, uint_t type) 606 { 607 int i; 608 int j = idx; 609 610 for (i = cnt; i > 0; i--) { 611 (void) ddi_dma_sync(pool->ip_seg[j].is_dma_hdl, 0, 612 icp->ic_framesz, type); 613 j = (j + 1) % icp->ic_nframes; 614 } 615 } 616 617 /* 618 * 619 * --- transfer 620 * 621 */ 622 int 623 av1394_ic_start(av1394_ic_t *icp) 624 { 625 if (icp->ic_dir == AV1394_IR) { 626 return (av1394_ir_start(icp)); 627 } else { 628 return (av1394_it_start(icp)); 629 } 630 } 631 632 int 633 av1394_ic_stop(av1394_ic_t *icp) 634 { 635 if (icp->ic_dir == AV1394_IR) { 636 return (av1394_ir_stop(icp)); 637 } else { 638 return (av1394_it_stop(icp)); 639 } 640 } 641 642 /* 643 * 644 * --- callbacks 645 * 646 */ 647 /*ARGSUSED*/ 648 static void 649 av1394_ic_rsrc_fail(t1394_isoch_single_handle_t t1394_sii_hdl, opaque_t arg, 650 t1394_isoch_rsrc_error_t fail_args) 651 { 652 AV1394_TNF_ENTER(av1394_ic_rsrc_fail); 653 654 /* XXX this could be handled more gracefully */ 655 cmn_err(CE_CONT, "av1394: can't reallocate isochronous resources" 656 " after bus reset\n"); 657 658 AV1394_TNF_EXIT(av1394_ic_rsrc_fail); 659 } 660 661 /* 662 * 663 * --- misc 664 * 665 * 666 * av1394_ic_ixl_seg_decomp() 667 * Calculate the best decomposition of a segment into buffers. 668 * Return number of buffers, buffer and tail buffer sizes. 669 * 670 * We are looking to divide a segment evenly into equally-sized or almost 671 * equally-sized buffers. Maximum buffer size is AV1394_IXL_BUFSZ_MAX. 672 * Algorithm: 673 * 1. If segment size divides evenly by maximum size, terminate. 674 * 2. n = number of maximum-size buffers than fits into the segment. 675 * 3. Divide the segment by n+1, calculate buffer size and tail 676 * (remainder) size. 677 * 4. If the tail can be appended to the last buffer and the resulting 678 * buffer is still less than maximum size, terminate. 679 * 5. Repeat steps 3-5 for n+2, n+3, ... until division is too small. 680 * 681 * Since all sizes are packet-aligned, we scale them down (divide by 682 * packet size) in the beginning, do all calculations and scale them up 683 * in the end. 684 */ 685 int 686 av1394_ic_ixl_seg_decomp(size_t segsz, size_t pktsz, size_t *bufszp, 687 size_t *tailszp) 688 { 689 size_t nbufs, bufsz, tailsz; 690 size_t maxsz = AV1394_IXL_BUFSZ_MAX; 691 692 ASSERT(segsz >= maxsz); 693 ASSERT(segsz % pktsz == 0); 694 695 if (segsz % maxsz == 0) { 696 *tailszp = *bufszp = maxsz; 697 return (segsz / *bufszp - 1); 698 } 699 700 maxsz /= pktsz; 701 segsz /= pktsz; 702 703 nbufs = segsz / maxsz; 704 do { 705 nbufs++; 706 bufsz = segsz / nbufs; 707 tailsz = bufsz + (segsz - bufsz * nbufs); 708 } while ((tailsz > maxsz) && ((segsz / (nbufs + 1)) > 1)); 709 nbufs--; 710 711 *bufszp = bufsz * pktsz; 712 *tailszp = tailsz * pktsz; 713 return (nbufs); 714 } 715 716 void 717 av1394_ic_ixl_dump(ixl1394_command_t *cmd) 718 { 719 ixl1394_callback_t *cb; 720 ixl1394_jump_t *jmp; 721 ixl1394_xfer_buf_t *buf; 722 ixl1394_xfer_pkt_t *pkt; 723 724 while (cmd) { 725 switch (cmd->ixl_opcode) { 726 case IXL1394_OP_LABEL: 727 cmn_err(CE_CONT, "%p: LABEL\n", (void *)cmd); 728 break; 729 case IXL1394_OP_RECV_BUF: 730 case IXL1394_OP_RECV_BUF_U: 731 buf = (ixl1394_xfer_buf_t *)cmd; 732 cmn_err(CE_CONT, "%p: RECV_BUF addr=%p size=%d " 733 "pkt_size=%d\n", (void *)cmd, (void *)buf->mem_bufp, 734 buf->size, buf->pkt_size); 735 break; 736 case IXL1394_OP_SEND_BUF: 737 case IXL1394_OP_SEND_BUF_U: 738 buf = (ixl1394_xfer_buf_t *)cmd; 739 cmn_err(CE_CONT, "%p: SEND_BUF addr=%p size=%d " 740 "pkt_size=%d\n", (void *)cmd, (void *)buf->mem_bufp, 741 buf->size, buf->pkt_size); 742 break; 743 case IXL1394_OP_SEND_PKT_ST: 744 pkt = (ixl1394_xfer_pkt_t *)cmd; 745 cmn_err(CE_CONT, "%p: SEND_PKT_ST addr=%p size=%d\n", 746 (void *)cmd, (void *)pkt->mem_bufp, pkt->size); 747 break; 748 case IXL1394_OP_CALLBACK: 749 case IXL1394_OP_CALLBACK_U: 750 cb = (ixl1394_callback_t *)cmd; 751 cmn_err(CE_CONT, "%p: CALLBACK %p\n", (void *)cmd, 752 (void *)cb->callback); 753 break; 754 case IXL1394_OP_JUMP: 755 jmp = (ixl1394_jump_t *)cmd; 756 cmn_err(CE_CONT, "%p: JUMP %p\n", (void *)cmd, 757 (void *)jmp->label); 758 break; 759 case IXL1394_OP_JUMP_U: 760 jmp = (ixl1394_jump_t *)cmd; 761 cmn_err(CE_CONT, "%p: JUMP_U %p\n", (void *)cmd, 762 (void *)jmp->label); 763 break; 764 case IXL1394_OP_STORE_TIMESTAMP: 765 cmn_err(CE_CONT, "%p: STORE_TIMESTAMP\n", (void *)cmd); 766 break; 767 default: 768 cmn_err(CE_CONT, "%p: other\n", (void *)cmd); 769 } 770 cmd = cmd->next_ixlp; 771 } 772 } 773 774 /* 775 * trigger a soft interrupt, if not already, for a given channel and type 776 */ 777 void 778 av1394_ic_trigger_softintr(av1394_ic_t *icp, int num, int preq) 779 { 780 av1394_isoch_t *ip = &icp->ic_avp->av_i; 781 uint64_t chmask = (1UL << num); 782 783 if (((ip->i_softintr_ch & chmask) == 0) || 784 ((icp->ic_preq & preq) == 0)) { 785 ip->i_softintr_ch |= chmask; 786 icp->ic_preq |= preq; 787 ddi_trigger_softintr(ip->i_softintr_id); 788 } 789 } 790 791 /* 792 * reverse bits in a 64-bit word 793 */ 794 uint64_t 795 av1394_ic_bitreverse(uint64_t x) 796 { 797 x = (((x >> 1) & 0x5555555555555555) | ((x & 0x5555555555555555) << 1)); 798 x = (((x >> 2) & 0x3333333333333333) | ((x & 0x3333333333333333) << 2)); 799 x = (((x >> 4) & 0x0f0f0f0f0f0f0f0f) | ((x & 0x0f0f0f0f0f0f0f0f) << 4)); 800 x = (((x >> 8) & 0x00ff00ff00ff00ff) | ((x & 0x00ff00ff00ff00ff) << 8)); 801 x = (((x >> 16) & 0x0000ffff0000ffff) | 802 ((x & 0x0000ffff0000ffff) << 16)); 803 return ((x >> 32) | (x << 32)); 804 } 805 806 /* 807 * return B_TRUE if a 64-bit value has only one bit set to 1 808 */ 809 boolean_t 810 av1394_ic_onebit(uint64_t i) 811 { 812 return (((~i + 1) | ~i) == 0xFFFFFFFFFFFFFFFF); 813 } 814