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 * Copyright (c) 2018, Joyent, Inc. 28 */ 29 30 /* 31 * routines common to isoch receive and isoch transmit 32 */ 33 #include <sys/stat.h> 34 #include <sys/systm.h> 35 #include <sys/ddi.h> 36 #include <sys/sunddi.h> 37 #include <sys/bitmap.h> 38 #include <sys/av/iec61883.h> 39 #include <sys/1394/targets/av1394/av1394_impl.h> 40 41 /* configuration routines */ 42 static void av1394_ic_cleanup(av1394_ic_t *icp, int level); 43 static int av1394_ic_validate_init_params(iec61883_isoch_init_t *ii); 44 static void av1394_ic_set_params(av1394_inst_t *avp, 45 iec61883_isoch_init_t *ii, av1394_ic_t *icp, int num); 46 static int av1394_ic_alloc_channel(av1394_ic_t *icp, uint64_t mask, int *); 47 static void av1394_ic_free_channel(av1394_ic_t *icp); 48 49 /* callbacks */ 50 static void av1394_ic_rsrc_fail(t1394_isoch_single_handle_t t1394_sii_hdl, 51 opaque_t arg, t1394_isoch_rsrc_error_t fail_args); 52 53 uint64_t av1394_ic_bitreverse(uint64_t); 54 boolean_t av1394_ic_onebit(uint64_t); 55 56 #define AV1394_TNF_ENTER(func) \ 57 TNF_PROBE_0_DEBUG(func##_enter, AV1394_TNF_ISOCH_STACK, ""); 58 59 #define AV1394_TNF_EXIT(func) \ 60 TNF_PROBE_0_DEBUG(func##_exit, AV1394_TNF_ISOCH_STACK, ""); 61 62 /* tunables */ 63 extern int av1394_rate_n_dv_ntsc; 64 extern int av1394_rate_d_dv_ntsc; 65 extern int av1394_rate_n_dv_pal; 66 extern int av1394_rate_d_dv_pal; 67 68 /*ARGSUSED*/ 69 int 70 av1394_ic_close(av1394_inst_t *avp, int flags) 71 { 72 av1394_isoch_t *ip = &avp->av_i; 73 av1394_ic_t *icp; 74 int i; 75 76 AV1394_TNF_ENTER(av1394_ic_close); 77 78 /* cleanup channels in case application didn't */ 79 for (i = 0; i < NELEM(ip->i_ic); i++) { 80 icp = ip->i_ic[i]; 81 if (icp != NULL) { 82 (void) av1394_ic_stop(icp); 83 av1394_ic_fini(icp); 84 } 85 } 86 87 AV1394_TNF_EXIT(av1394_ic_close); 88 return (0); 89 } 90 91 /* 92 * av1394_ic_init() 93 * Channel allocation and initialization. 94 */ 95 int 96 av1394_ic_init(av1394_inst_t *avp, iec61883_isoch_init_t *ii, 97 av1394_ic_t **icpp) 98 { 99 av1394_isoch_t *ip = &avp->av_i; 100 av1394_ic_t *icp = NULL; 101 int num; 102 av1394_isoch_pool_t *pool; 103 uint64_t mask; /* channel mask */ 104 int ret; 105 ddi_iblock_cookie_t ibc = avp->av_attachinfo.iblock_cookie; 106 107 AV1394_TNF_ENTER(av1394_ic_init); 108 109 ii->ii_frame_rcnt = 0; 110 ii->ii_rchannel = 0; 111 ii->ii_error = 0; 112 113 if ((ret = av1394_ic_validate_init_params(ii)) != 0) { 114 AV1394_TNF_EXIT(av1394_ic_init); 115 return (ret); 116 } 117 118 /* allocate channel structure */ 119 icp = kmem_zalloc(sizeof (av1394_ic_t), KM_SLEEP); 120 121 mutex_init(&icp->ic_mutex, NULL, MUTEX_DRIVER, ibc); 122 cv_init(&icp->ic_xfer_cv, NULL, CV_DRIVER, NULL); 123 124 av1394_ic_set_params(avp, ii, icp, -1); 125 126 /* allocate isoch channel and bandwidth, except for broadcast */ 127 if (ii->ii_channel == (1ULL << 63)) { 128 num = 63; 129 } else if (ii->ii_flags & IEC61883_PRIV_ISOCH_NOALLOC) { 130 num = lowbit(ii->ii_channel) - 1; 131 } else { 132 mask = av1394_ic_bitreverse(ii->ii_channel); 133 ret = av1394_ic_alloc_channel(icp, mask, &num); 134 if (ret != DDI_SUCCESS) { 135 ii->ii_error = IEC61883_ERR_NOCHANNEL; 136 av1394_ic_cleanup(icp, 1); 137 AV1394_TNF_EXIT(av1394_ic_init); 138 return (EINVAL); 139 } 140 } 141 ASSERT((num >= 0) && (num < 64)); 142 143 mutex_enter(&icp->ic_mutex); 144 icp->ic_num = num; 145 mutex_exit(&icp->ic_mutex); 146 147 mutex_enter(&ip->i_mutex); 148 if (ip->i_ic[num] != NULL) { 149 mutex_exit(&ip->i_mutex); 150 ii->ii_error = IEC61883_ERR_NOCHANNEL; 151 av1394_ic_cleanup(icp, 2); 152 TNF_PROBE_0(av1394_ic_init_error_chan_used, 153 AV1394_TNF_ISOCH_ERROR, ""); 154 AV1394_TNF_EXIT(av1394_ic_init); 155 return (EINVAL); 156 } 157 ip->i_ic[num] = icp; 158 mutex_exit(&ip->i_mutex); 159 160 /* do direction specific initialization */ 161 if (icp->ic_dir == AV1394_IR) { 162 ret = av1394_ir_init(icp, &ii->ii_error); 163 pool = &icp->ic_ir.ir_data_pool; 164 } else { 165 ret = av1394_it_init(icp, &ii->ii_error); 166 pool = &icp->ic_it.it_data_pool; 167 } 168 169 if (ret != 0) { 170 av1394_ic_cleanup(icp, 3); 171 AV1394_TNF_EXIT(av1394_ic_init); 172 return (ret); 173 } 174 175 /* allocate mmap space */ 176 mutex_enter(&ip->i_mutex); 177 mutex_enter(&icp->ic_mutex); 178 icp->ic_mmap_sz = pool->ip_umem_size; 179 icp->ic_mmap_off = av1394_as_alloc(&ip->i_mmap_as, icp->ic_mmap_sz); 180 181 icp->ic_state = AV1394_IC_IDLE; 182 183 *icpp = icp; 184 ii->ii_handle = icp->ic_num; 185 ii->ii_frame_rcnt = icp->ic_nframes; 186 ii->ii_mmap_off = icp->ic_mmap_off; 187 ii->ii_rchannel = icp->ic_num; 188 mutex_exit(&icp->ic_mutex); 189 mutex_exit(&ip->i_mutex); 190 191 TNF_PROBE_2_DEBUG(av1394_ic_init, AV1394_TNF_ISOCH, "", 192 tnf_string, msg, "channel allocated", tnf_int, num, icp->ic_num); 193 194 AV1394_TNF_EXIT(av1394_ic_init); 195 return (0); 196 } 197 198 void 199 av1394_ic_fini(av1394_ic_t *icp) 200 { 201 AV1394_TNF_ENTER(av1394_ic_fini); 202 203 av1394_ic_cleanup(icp, AV1394_CLEANUP_LEVEL_MAX); 204 205 AV1394_TNF_EXIT(av1394_ic_fini); 206 } 207 208 /* 209 * 210 * --- configuration routines 211 * 212 */ 213 static void 214 av1394_ic_cleanup(av1394_ic_t *icp, int level) 215 { 216 av1394_inst_t *avp = icp->ic_avp; 217 av1394_isoch_t *ip = &avp->av_i; 218 219 ASSERT((level > 0) && (level <= AV1394_CLEANUP_LEVEL_MAX)); 220 221 switch (level) { 222 default: 223 if (icp->ic_dir == AV1394_IR) { 224 av1394_ir_fini(icp); 225 } else { 226 av1394_it_fini(icp); 227 } 228 /* FALLTHRU */ 229 case 3: 230 mutex_enter(&ip->i_mutex); 231 av1394_as_free(&ip->i_mmap_as, icp->ic_mmap_off); 232 ip->i_ic[icp->ic_num] = NULL; 233 mutex_exit(&ip->i_mutex); 234 /* FALLTHRU */ 235 case 2: 236 av1394_ic_free_channel(icp); 237 /* FALLTHRU */ 238 case 1: 239 cv_destroy(&icp->ic_xfer_cv); 240 mutex_destroy(&icp->ic_mutex); 241 kmem_free(icp, sizeof (av1394_ic_t)); 242 } 243 } 244 245 static int 246 av1394_ic_validate_init_params(iec61883_isoch_init_t *ii) 247 { 248 int framesz; 249 250 ii->ii_error = 0; 251 if ((IEC61883_IMPL_VER_MAJOR(ii->ii_version) != 252 IEC61883_IMPL_VER_MAJOR(AV1394_IEC61883_VER)) || 253 (IEC61883_IMPL_VER_MINOR(ii->ii_version) > 254 IEC61883_IMPL_VER_MINOR(AV1394_IEC61883_VER))) { 255 TNF_PROBE_0(av1394_ic_validate_init_params_ver_error, 256 AV1394_TNF_ISOCH_ERROR, ""); 257 ii->ii_error = IEC61883_ERR_VERSION; 258 return (EINVAL); 259 } 260 if ((ii->ii_pkt_size % 4) || (ii->ii_pkt_size > 512)) { 261 TNF_PROBE_0(av1394_ic_validate_init_params_pktsz_error, 262 AV1394_TNF_ISOCH_ERROR, ""); 263 ii->ii_error = IEC61883_ERR_PKT_SIZE; 264 return (EINVAL); 265 } 266 framesz = ii->ii_frame_size * ii->ii_pkt_size; 267 if (framesz > AV1394_IC_FRAME_SIZE_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 = framesz * fps; 458 nsegs = totalsz / segsz; 459 if ((totalsz % segsz) != 0) 460 nsegs++; /* remainder in non-full segment */ 461 } 462 ASSERT(segsz * nsegs >= totalsz); 463 464 /* allocate segment array */ 465 pool->ip_alloc_size = nsegs * sizeof (av1394_isoch_seg_t); 466 pool->ip_seg = kmem_zalloc(pool->ip_alloc_size, KM_SLEEP); 467 468 /* allocate page-aligned user-mappable memory for each segment */ 469 pool->ip_nsegs = 0; 470 pool->ip_size = 0; 471 pool->ip_umem_size = 0; 472 for (i = 0; i < nsegs; i++) { 473 seg = &pool->ip_seg[i]; 474 475 seg->is_umem_size = ptob(btopr(segsz)); 476 seg->is_kaddr = ddi_umem_alloc(seg->is_umem_size, 477 DDI_UMEM_SLEEP, &seg->is_umem_cookie); 478 if (seg->is_kaddr == NULL) { 479 TNF_PROBE_0(av1394_ic_alloc_pool_error_umem_alloc, 480 AV1394_TNF_ISOCH_ERROR, ""); 481 break; 482 } 483 seg->is_size = segsz; 484 485 pool->ip_size += seg->is_size; 486 pool->ip_umem_size += seg->is_umem_size; 487 pool->ip_nsegs++; 488 } 489 490 /* number of frames the pool can hold */ 491 ret = pool->ip_size / framesz; 492 if (ret < mincnt) { 493 TNF_PROBE_0(av1394_ic_alloc_pool_error_mincnt, 494 AV1394_TNF_ISOCH_ERROR, ""); 495 av1394_ic_free_pool(pool); 496 ret = 0; 497 } 498 499 AV1394_TNF_EXIT(av1394_ic_alloc_pool); 500 return (ret); 501 } 502 503 void 504 av1394_ic_free_pool(av1394_isoch_pool_t *pool) 505 { 506 int i; 507 508 AV1394_TNF_ENTER(av1394_ic_free_pool); 509 510 if (pool->ip_seg != NULL) { 511 for (i = 0; i < pool->ip_nsegs; i++) { 512 ddi_umem_free(pool->ip_seg[i].is_umem_cookie); 513 } 514 kmem_free(pool->ip_seg, pool->ip_alloc_size); 515 pool->ip_seg = NULL; 516 } 517 518 AV1394_TNF_EXIT(av1394_ic_free_pool); 519 } 520 521 int 522 av1394_ic_dma_setup(av1394_ic_t *icp, av1394_isoch_pool_t *pool) 523 { 524 av1394_inst_t *avp = icp->ic_avp; 525 av1394_isoch_seg_t *isp; 526 uint_t dma_dir; 527 int ret; 528 int i; 529 int j; 530 531 AV1394_TNF_ENTER(av1394_ic_dma_setup); 532 533 dma_dir = (icp->ic_dir == AV1394_IR) ? DDI_DMA_READ : DDI_DMA_WRITE; 534 /* 535 * Alloc and bind a DMA handle for each segment. 536 * Note that we need packet size alignment, but since ddi_umem_alloc'ed 537 * memory is page-aligned and our packets are less than page size (yet) 538 * we don't need to do anything special here. 539 */ 540 for (i = 0; i < pool->ip_nsegs; i++) { 541 isp = &pool->ip_seg[i]; 542 543 ret = ddi_dma_alloc_handle(avp->av_dip, 544 &avp->av_attachinfo.dma_attr, DDI_DMA_DONTWAIT, NULL, 545 &isp->is_dma_hdl); 546 if (ret != DDI_SUCCESS) { 547 TNF_PROBE_0(av1394_ic_dma_setup_error_alloc_hdl, 548 AV1394_TNF_ISOCH_ERROR, ""); 549 av1394_ic_dma_cleanup(icp, pool); 550 AV1394_TNF_EXIT(av1394_ic_dma_setup); 551 return (ret); 552 } 553 554 ret = ddi_dma_addr_bind_handle(isp->is_dma_hdl, NULL, 555 isp->is_kaddr, isp->is_size, 556 dma_dir | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 557 &isp->is_dma_cookie[0], &isp->is_dma_ncookies); 558 559 if (ret != DDI_DMA_MAPPED) { 560 TNF_PROBE_0(av1394_ic_dma_setup_error_bind_hdl, 561 AV1394_TNF_ISOCH_ERROR, ""); 562 av1394_ic_dma_cleanup(icp, pool); 563 AV1394_TNF_EXIT(av1394_ic_dma_setup); 564 return (DDI_FAILURE); 565 } 566 567 if (isp->is_dma_ncookies > COOKIES) { 568 TNF_PROBE_0(av1394_ic_dma_setup_error_ncookies, 569 AV1394_TNF_ISOCH_ERROR, ""); 570 av1394_ic_dma_cleanup(icp, pool); 571 AV1394_TNF_EXIT(av1394_ic_dma_setup); 572 return (DDI_FAILURE); 573 } 574 575 for (j = 1; j < isp->is_dma_ncookies; ++j) 576 ddi_dma_nextcookie(isp->is_dma_hdl, 577 &isp->is_dma_cookie[j]); 578 } 579 580 AV1394_TNF_EXIT(av1394_ic_dma_setup); 581 return (DDI_SUCCESS); 582 } 583 584 /*ARGSUSED*/ 585 void 586 av1394_ic_dma_cleanup(av1394_ic_t *icp, av1394_isoch_pool_t *pool) 587 { 588 av1394_isoch_seg_t *seg; 589 int i; 590 591 AV1394_TNF_ENTER(av1394_ic_dma_cleanup); 592 593 for (i = 0; i < pool->ip_nsegs; i++) { 594 seg = &pool->ip_seg[i]; 595 if (seg->is_dma_hdl != NULL) { 596 if (seg->is_dma_ncookies > 0) { 597 (void) ddi_dma_unbind_handle(seg->is_dma_hdl); 598 } 599 ddi_dma_free_handle(&seg->is_dma_hdl); 600 } 601 } 602 603 AV1394_TNF_EXIT(av1394_ic_dma_cleanup); 604 } 605 606 /* 607 * sync frames for CPU access 608 */ 609 void 610 av1394_ic_dma_sync_frames(av1394_ic_t *icp, int idx, int cnt, 611 av1394_isoch_pool_t *pool, uint_t type) 612 { 613 int fps; /* frames per segment */ 614 int nsegs; /* number of segments for indicated frames */ 615 int seg; /* index of segment to sync */ 616 617 fps = icp->ic_nframes / pool->ip_nsegs; 618 619 nsegs = (cnt / fps) + 1; 620 621 seg = idx / fps; 622 623 for (;;) { 624 (void) ddi_dma_sync(pool->ip_seg[seg].is_dma_hdl, 0, 625 icp->ic_framesz, type); 626 627 --nsegs; 628 if (nsegs == 0) 629 break; 630 631 ++seg; 632 if (seg == pool->ip_nsegs) 633 seg = 0; /* wrap segment index */ 634 } 635 } 636 637 /* 638 * 639 * --- transfer 640 * 641 */ 642 int 643 av1394_ic_start(av1394_ic_t *icp) 644 { 645 if (icp->ic_dir == AV1394_IR) { 646 return (av1394_ir_start(icp)); 647 } else { 648 return (av1394_it_start(icp)); 649 } 650 } 651 652 int 653 av1394_ic_stop(av1394_ic_t *icp) 654 { 655 if (icp->ic_dir == AV1394_IR) { 656 return (av1394_ir_stop(icp)); 657 } else { 658 return (av1394_it_stop(icp)); 659 } 660 } 661 662 /* 663 * 664 * --- callbacks 665 * 666 */ 667 /*ARGSUSED*/ 668 static void 669 av1394_ic_rsrc_fail(t1394_isoch_single_handle_t t1394_sii_hdl, opaque_t arg, 670 t1394_isoch_rsrc_error_t fail_args) 671 { 672 AV1394_TNF_ENTER(av1394_ic_rsrc_fail); 673 674 /* XXX this could be handled more gracefully */ 675 cmn_err(CE_CONT, "av1394: can't reallocate isochronous resources" 676 " after bus reset\n"); 677 678 AV1394_TNF_EXIT(av1394_ic_rsrc_fail); 679 } 680 681 /* 682 * 683 * --- misc 684 * 685 * 686 * av1394_ic_ixl_seg_decomp() 687 * Calculate the best decomposition of a segment into buffers. 688 * Return number of buffers, buffer and tail buffer sizes. 689 * 690 * We are looking to divide a segment evenly into equally-sized or almost 691 * equally-sized buffers. Maximum buffer size is AV1394_IXL_BUFSZ_MAX. 692 * Algorithm: 693 * 1. If segment size divides evenly by maximum size, terminate. 694 * 2. n = number of maximum-size buffers than fits into the segment. 695 * 3. Divide the segment by n+1, calculate buffer size and tail 696 * (remainder) size. 697 * 4. If the tail can be appended to the last buffer and the resulting 698 * buffer is still less than maximum size, terminate. 699 * 5. Repeat steps 3-5 for n+2, n+3, ... until division is too small. 700 * 701 * Since all sizes are packet-aligned, we scale them down (divide by 702 * packet size) in the beginning, do all calculations and scale them up 703 * in the end. 704 */ 705 int 706 av1394_ic_ixl_seg_decomp(size_t segsz, size_t pktsz, size_t *bufszp, 707 size_t *tailszp) 708 { 709 size_t nbufs, bufsz, tailsz; 710 size_t maxsz = AV1394_IXL_BUFSZ_MAX; 711 712 ASSERT(segsz >= maxsz); 713 ASSERT(segsz % pktsz == 0); 714 715 if (segsz % maxsz == 0) { 716 *tailszp = *bufszp = maxsz; 717 return (segsz / *bufszp - 1); 718 } 719 720 maxsz /= pktsz; 721 segsz /= pktsz; 722 723 nbufs = segsz / maxsz; 724 do { 725 nbufs++; 726 bufsz = segsz / nbufs; 727 tailsz = bufsz + (segsz - bufsz * nbufs); 728 } while ((tailsz > maxsz) && ((segsz / (nbufs + 1)) > 1)); 729 nbufs--; 730 731 *bufszp = bufsz * pktsz; 732 *tailszp = tailsz * pktsz; 733 return (nbufs); 734 } 735 736 void 737 av1394_ic_ixl_dump(ixl1394_command_t *cmd) 738 { 739 ixl1394_callback_t *cb; 740 ixl1394_jump_t *jmp; 741 ixl1394_xfer_buf_t *buf; 742 ixl1394_xfer_pkt_t *pkt; 743 744 while (cmd) { 745 switch (cmd->ixl_opcode) { 746 case IXL1394_OP_LABEL: 747 cmn_err(CE_CONT, "%p: LABEL\n", (void *)cmd); 748 break; 749 case IXL1394_OP_RECV_BUF: 750 case IXL1394_OP_RECV_BUF_U: 751 buf = (ixl1394_xfer_buf_t *)cmd; 752 cmn_err(CE_CONT, "%p: RECV_BUF addr=%p size=%d " 753 "pkt_size=%d\n", (void *)cmd, (void *)buf->mem_bufp, 754 buf->size, buf->pkt_size); 755 break; 756 case IXL1394_OP_SEND_BUF: 757 case IXL1394_OP_SEND_BUF_U: 758 buf = (ixl1394_xfer_buf_t *)cmd; 759 cmn_err(CE_CONT, "%p: SEND_BUF addr=%p size=%d " 760 "pkt_size=%d\n", (void *)cmd, (void *)buf->mem_bufp, 761 buf->size, buf->pkt_size); 762 break; 763 case IXL1394_OP_SEND_PKT_ST: 764 pkt = (ixl1394_xfer_pkt_t *)cmd; 765 cmn_err(CE_CONT, "%p: SEND_PKT_ST addr=%p size=%d\n", 766 (void *)cmd, (void *)pkt->mem_bufp, pkt->size); 767 break; 768 case IXL1394_OP_CALLBACK: 769 case IXL1394_OP_CALLBACK_U: 770 cb = (ixl1394_callback_t *)cmd; 771 cmn_err(CE_CONT, "%p: CALLBACK %p\n", (void *)cmd, 772 (void *)cb->callback); 773 break; 774 case IXL1394_OP_JUMP: 775 jmp = (ixl1394_jump_t *)cmd; 776 cmn_err(CE_CONT, "%p: JUMP %p\n", (void *)cmd, 777 (void *)jmp->label); 778 break; 779 case IXL1394_OP_JUMP_U: 780 jmp = (ixl1394_jump_t *)cmd; 781 cmn_err(CE_CONT, "%p: JUMP_U %p\n", (void *)cmd, 782 (void *)jmp->label); 783 break; 784 case IXL1394_OP_STORE_TIMESTAMP: 785 cmn_err(CE_CONT, "%p: STORE_TIMESTAMP\n", (void *)cmd); 786 break; 787 default: 788 cmn_err(CE_CONT, "%p: other\n", (void *)cmd); 789 } 790 cmd = cmd->next_ixlp; 791 } 792 } 793 794 /* 795 * trigger a soft interrupt, if not already, for a given channel and type 796 */ 797 void 798 av1394_ic_trigger_softintr(av1394_ic_t *icp, int num, int preq) 799 { 800 av1394_isoch_t *ip = &icp->ic_avp->av_i; 801 uint64_t chmask = (1ULL << num); 802 803 if (((ip->i_softintr_ch & chmask) == 0) || 804 ((icp->ic_preq & preq) == 0)) { 805 ip->i_softintr_ch |= chmask; 806 icp->ic_preq |= preq; 807 ddi_trigger_softintr(ip->i_softintr_id); 808 } 809 } 810 811 /* 812 * reverse bits in a 64-bit word 813 */ 814 uint64_t 815 av1394_ic_bitreverse(uint64_t x) 816 { 817 x = (((x >> 1) & 0x5555555555555555) | ((x & 0x5555555555555555) << 1)); 818 x = (((x >> 2) & 0x3333333333333333) | ((x & 0x3333333333333333) << 2)); 819 x = (((x >> 4) & 0x0f0f0f0f0f0f0f0f) | ((x & 0x0f0f0f0f0f0f0f0f) << 4)); 820 x = (((x >> 8) & 0x00ff00ff00ff00ff) | ((x & 0x00ff00ff00ff00ff) << 8)); 821 x = (((x >> 16) & 0x0000ffff0000ffff) | 822 ((x & 0x0000ffff0000ffff) << 16)); 823 824 return ((x >> 32) | (x << 32)); 825 } 826 827 /* 828 * return B_TRUE if a 64-bit value has only one bit set to 1 829 */ 830 boolean_t 831 av1394_ic_onebit(uint64_t i) 832 { 833 return (((~i + 1) | ~i) == 0xFFFFFFFFFFFFFFFF); 834 } 835