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