1/* 2 * strm.c 3 * 4 * DSP-BIOS Bridge driver support functions for TI OMAP processors. 5 * 6 * DSP/BIOS Bridge Stream Manager. 7 * 8 * Copyright (C) 2005-2006 Texas Instruments, Inc. 9 * 10 * This package is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 * 14 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 17 */ 18 19#include <linux/types.h> 20 21/* ----------------------------------- Host OS */ 22#include <dspbridge/host_os.h> 23 24/* ----------------------------------- DSP/BIOS Bridge */ 25#include <dspbridge/dbdefs.h> 26 27/* ----------------------------------- Trace & Debug */ 28#include <dspbridge/dbc.h> 29 30/* ----------------------------------- OS Adaptation Layer */ 31#include <dspbridge/sync.h> 32 33/* ----------------------------------- Bridge Driver */ 34#include <dspbridge/dspdefs.h> 35 36/* ----------------------------------- Resource Manager */ 37#include <dspbridge/nodepriv.h> 38 39/* ----------------------------------- Others */ 40#include <dspbridge/cmm.h> 41 42/* ----------------------------------- This */ 43#include <dspbridge/strm.h> 44 45#include <dspbridge/cfg.h> 46#include <dspbridge/resourcecleanup.h> 47 48/* ----------------------------------- Defines, Data Structures, Typedefs */ 49#define DEFAULTTIMEOUT 10000 50#define DEFAULTNUMBUFS 2 51 52/* 53 * ======== strm_mgr ======== 54 * The strm_mgr contains device information needed to open the underlying 55 * channels of a stream. 56 */ 57struct strm_mgr { 58 struct dev_object *dev_obj; /* Device for this processor */ 59 struct chnl_mgr *hchnl_mgr; /* Channel manager */ 60 /* Function interface to Bridge driver */ 61 struct bridge_drv_interface *intf_fxns; 62}; 63 64/* 65 * ======== strm_object ======== 66 * This object is allocated in strm_open(). 67 */ 68struct strm_object { 69 struct strm_mgr *strm_mgr_obj; 70 struct chnl_object *chnl_obj; 71 u32 dir; /* DSP_TONODE or DSP_FROMNODE */ 72 u32 utimeout; 73 u32 num_bufs; /* Max # of bufs allowed in stream */ 74 u32 un_bufs_in_strm; /* Current # of bufs in stream */ 75 u32 ul_n_bytes; /* bytes transferred since idled */ 76 /* STREAM_IDLE, STREAM_READY, ... */ 77 enum dsp_streamstate strm_state; 78 void *user_event; /* Saved for strm_get_info() */ 79 enum dsp_strmmode strm_mode; /* STRMMODE_[PROCCOPY][ZEROCOPY]... */ 80 u32 udma_chnl_id; /* DMA chnl id */ 81 u32 udma_priority; /* DMA priority:DMAPRI_[LOW][HIGH] */ 82 u32 segment_id; /* >0 is SM segment.=0 is local heap */ 83 u32 buf_alignment; /* Alignment for stream bufs */ 84 /* Stream's SM address translator */ 85 struct cmm_xlatorobject *xlator; 86}; 87 88/* ----------------------------------- Globals */ 89static u32 refs; /* module reference count */ 90 91/* ----------------------------------- Function Prototypes */ 92static int delete_strm(struct strm_object *stream_obj); 93 94/* 95 * ======== strm_allocate_buffer ======== 96 * Purpose: 97 * Allocates buffers for a stream. 98 */ 99int strm_allocate_buffer(struct strm_res_object *strmres, u32 usize, 100 u8 **ap_buffer, u32 num_bufs, 101 struct process_context *pr_ctxt) 102{ 103 int status = 0; 104 u32 alloc_cnt = 0; 105 u32 i; 106 struct strm_object *stream_obj = strmres->hstream; 107 108 DBC_REQUIRE(refs > 0); 109 DBC_REQUIRE(ap_buffer != NULL); 110 111 if (stream_obj) { 112 /* 113 * Allocate from segment specified at time of stream open. 114 */ 115 if (usize == 0) 116 status = -EINVAL; 117 118 } else { 119 status = -EFAULT; 120 } 121 122 if (status) 123 goto func_end; 124 125 for (i = 0; i < num_bufs; i++) { 126 DBC_ASSERT(stream_obj->xlator != NULL); 127 (void)cmm_xlator_alloc_buf(stream_obj->xlator, &ap_buffer[i], 128 usize); 129 if (ap_buffer[i] == NULL) { 130 status = -ENOMEM; 131 alloc_cnt = i; 132 break; 133 } 134 } 135 if (status) 136 strm_free_buffer(strmres, ap_buffer, alloc_cnt, pr_ctxt); 137 138 if (status) 139 goto func_end; 140 141 drv_proc_update_strm_res(num_bufs, strmres); 142 143func_end: 144 return status; 145} 146 147/* 148 * ======== strm_close ======== 149 * Purpose: 150 * Close a stream opened with strm_open(). 151 */ 152int strm_close(struct strm_res_object *strmres, 153 struct process_context *pr_ctxt) 154{ 155 struct bridge_drv_interface *intf_fxns; 156 struct chnl_info chnl_info_obj; 157 int status = 0; 158 struct strm_object *stream_obj = strmres->hstream; 159 160 DBC_REQUIRE(refs > 0); 161 162 if (!stream_obj) { 163 status = -EFAULT; 164 } else { 165 /* Have all buffers been reclaimed? If not, return 166 * -EPIPE */ 167 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns; 168 status = 169 (*intf_fxns->pfn_chnl_get_info) (stream_obj->chnl_obj, 170 &chnl_info_obj); 171 DBC_ASSERT(!status); 172 173 if (chnl_info_obj.cio_cs > 0 || chnl_info_obj.cio_reqs > 0) 174 status = -EPIPE; 175 else 176 status = delete_strm(stream_obj); 177 } 178 179 if (status) 180 goto func_end; 181 182 idr_remove(pr_ctxt->stream_id, strmres->id); 183func_end: 184 DBC_ENSURE(status == 0 || status == -EFAULT || 185 status == -EPIPE || status == -EPERM); 186 187 dev_dbg(bridge, "%s: stream_obj: %p, status 0x%x\n", __func__, 188 stream_obj, status); 189 return status; 190} 191 192/* 193 * ======== strm_create ======== 194 * Purpose: 195 * Create a STRM manager object. 196 */ 197int strm_create(struct strm_mgr **strm_man, 198 struct dev_object *dev_obj) 199{ 200 struct strm_mgr *strm_mgr_obj; 201 int status = 0; 202 203 DBC_REQUIRE(refs > 0); 204 DBC_REQUIRE(strm_man != NULL); 205 DBC_REQUIRE(dev_obj != NULL); 206 207 *strm_man = NULL; 208 /* Allocate STRM manager object */ 209 strm_mgr_obj = kzalloc(sizeof(struct strm_mgr), GFP_KERNEL); 210 if (strm_mgr_obj == NULL) 211 status = -ENOMEM; 212 else 213 strm_mgr_obj->dev_obj = dev_obj; 214 215 /* Get Channel manager and Bridge function interface */ 216 if (!status) { 217 status = dev_get_chnl_mgr(dev_obj, &(strm_mgr_obj->hchnl_mgr)); 218 if (!status) { 219 (void)dev_get_intf_fxns(dev_obj, 220 &(strm_mgr_obj->intf_fxns)); 221 DBC_ASSERT(strm_mgr_obj->intf_fxns != NULL); 222 } 223 } 224 225 if (!status) 226 *strm_man = strm_mgr_obj; 227 else 228 kfree(strm_mgr_obj); 229 230 DBC_ENSURE((!status && *strm_man) || (status && *strm_man == NULL)); 231 232 return status; 233} 234 235/* 236 * ======== strm_delete ======== 237 * Purpose: 238 * Delete the STRM Manager Object. 239 */ 240void strm_delete(struct strm_mgr *strm_mgr_obj) 241{ 242 DBC_REQUIRE(refs > 0); 243 DBC_REQUIRE(strm_mgr_obj); 244 245 kfree(strm_mgr_obj); 246} 247 248/* 249 * ======== strm_exit ======== 250 * Purpose: 251 * Discontinue usage of STRM module. 252 */ 253void strm_exit(void) 254{ 255 DBC_REQUIRE(refs > 0); 256 257 refs--; 258 259 DBC_ENSURE(refs >= 0); 260} 261 262/* 263 * ======== strm_free_buffer ======== 264 * Purpose: 265 * Frees the buffers allocated for a stream. 266 */ 267int strm_free_buffer(struct strm_res_object *strmres, u8 ** ap_buffer, 268 u32 num_bufs, struct process_context *pr_ctxt) 269{ 270 int status = 0; 271 u32 i = 0; 272 struct strm_object *stream_obj = strmres->hstream; 273 274 DBC_REQUIRE(refs > 0); 275 DBC_REQUIRE(ap_buffer != NULL); 276 277 if (!stream_obj) 278 status = -EFAULT; 279 280 if (!status) { 281 for (i = 0; i < num_bufs; i++) { 282 DBC_ASSERT(stream_obj->xlator != NULL); 283 status = 284 cmm_xlator_free_buf(stream_obj->xlator, 285 ap_buffer[i]); 286 if (status) 287 break; 288 ap_buffer[i] = NULL; 289 } 290 } 291 drv_proc_update_strm_res(num_bufs - i, strmres); 292 293 return status; 294} 295 296/* 297 * ======== strm_get_info ======== 298 * Purpose: 299 * Retrieves information about a stream. 300 */ 301int strm_get_info(struct strm_object *stream_obj, 302 struct stream_info *stream_info, 303 u32 stream_info_size) 304{ 305 struct bridge_drv_interface *intf_fxns; 306 struct chnl_info chnl_info_obj; 307 int status = 0; 308 void *virt_base = NULL; /* NULL if no SM used */ 309 310 DBC_REQUIRE(refs > 0); 311 DBC_REQUIRE(stream_info != NULL); 312 DBC_REQUIRE(stream_info_size >= sizeof(struct stream_info)); 313 314 if (!stream_obj) { 315 status = -EFAULT; 316 } else { 317 if (stream_info_size < sizeof(struct stream_info)) { 318 /* size of users info */ 319 status = -EINVAL; 320 } 321 } 322 if (status) 323 goto func_end; 324 325 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns; 326 status = 327 (*intf_fxns->pfn_chnl_get_info) (stream_obj->chnl_obj, 328 &chnl_info_obj); 329 if (status) 330 goto func_end; 331 332 if (stream_obj->xlator) { 333 /* We have a translator */ 334 DBC_ASSERT(stream_obj->segment_id > 0); 335 cmm_xlator_info(stream_obj->xlator, (u8 **) &virt_base, 0, 336 stream_obj->segment_id, false); 337 } 338 stream_info->segment_id = stream_obj->segment_id; 339 stream_info->strm_mode = stream_obj->strm_mode; 340 stream_info->virt_base = virt_base; 341 stream_info->user_strm->number_bufs_allowed = stream_obj->num_bufs; 342 stream_info->user_strm->number_bufs_in_stream = chnl_info_obj.cio_cs + 343 chnl_info_obj.cio_reqs; 344 /* # of bytes transferred since last call to DSPStream_Idle() */ 345 stream_info->user_strm->ul_number_bytes = chnl_info_obj.bytes_tx; 346 stream_info->user_strm->sync_object_handle = chnl_info_obj.event_obj; 347 /* Determine stream state based on channel state and info */ 348 if (chnl_info_obj.dw_state & CHNL_STATEEOS) { 349 stream_info->user_strm->ss_stream_state = STREAM_DONE; 350 } else { 351 if (chnl_info_obj.cio_cs > 0) 352 stream_info->user_strm->ss_stream_state = STREAM_READY; 353 else if (chnl_info_obj.cio_reqs > 0) 354 stream_info->user_strm->ss_stream_state = 355 STREAM_PENDING; 356 else 357 stream_info->user_strm->ss_stream_state = STREAM_IDLE; 358 359 } 360func_end: 361 return status; 362} 363 364/* 365 * ======== strm_idle ======== 366 * Purpose: 367 * Idles a particular stream. 368 */ 369int strm_idle(struct strm_object *stream_obj, bool flush_data) 370{ 371 struct bridge_drv_interface *intf_fxns; 372 int status = 0; 373 374 DBC_REQUIRE(refs > 0); 375 376 if (!stream_obj) { 377 status = -EFAULT; 378 } else { 379 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns; 380 381 status = (*intf_fxns->pfn_chnl_idle) (stream_obj->chnl_obj, 382 stream_obj->utimeout, 383 flush_data); 384 } 385 386 dev_dbg(bridge, "%s: stream_obj: %p flush_data: 0x%x status: 0x%x\n", 387 __func__, stream_obj, flush_data, status); 388 return status; 389} 390 391/* 392 * ======== strm_init ======== 393 * Purpose: 394 * Initialize the STRM module. 395 */ 396bool strm_init(void) 397{ 398 bool ret = true; 399 400 DBC_REQUIRE(refs >= 0); 401 402 if (ret) 403 refs++; 404 405 DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0))); 406 407 return ret; 408} 409 410/* 411 * ======== strm_issue ======== 412 * Purpose: 413 * Issues a buffer on a stream 414 */ 415int strm_issue(struct strm_object *stream_obj, u8 *pbuf, u32 ul_bytes, 416 u32 ul_buf_size, u32 dw_arg) 417{ 418 struct bridge_drv_interface *intf_fxns; 419 int status = 0; 420 void *tmp_buf = NULL; 421 422 DBC_REQUIRE(refs > 0); 423 DBC_REQUIRE(pbuf != NULL); 424 425 if (!stream_obj) { 426 status = -EFAULT; 427 } else { 428 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns; 429 430 if (stream_obj->segment_id != 0) { 431 tmp_buf = cmm_xlator_translate(stream_obj->xlator, 432 (void *)pbuf, 433 CMM_VA2DSPPA); 434 if (tmp_buf == NULL) 435 status = -ESRCH; 436 437 } 438 if (!status) { 439 status = (*intf_fxns->pfn_chnl_add_io_req) 440 (stream_obj->chnl_obj, pbuf, ul_bytes, ul_buf_size, 441 (u32) tmp_buf, dw_arg); 442 } 443 if (status == -EIO) 444 status = -ENOSR; 445 } 446 447 dev_dbg(bridge, "%s: stream_obj: %p pbuf: %p ul_bytes: 0x%x dw_arg:" 448 " 0x%x status: 0x%x\n", __func__, stream_obj, pbuf, 449 ul_bytes, dw_arg, status); 450 return status; 451} 452 453/* 454 * ======== strm_open ======== 455 * Purpose: 456 * Open a stream for sending/receiving data buffers to/from a task or 457 * XDAIS socket node on the DSP. 458 */ 459int strm_open(struct node_object *hnode, u32 dir, u32 index, 460 struct strm_attr *pattr, 461 struct strm_res_object **strmres, 462 struct process_context *pr_ctxt) 463{ 464 struct strm_mgr *strm_mgr_obj; 465 struct bridge_drv_interface *intf_fxns; 466 u32 ul_chnl_id; 467 struct strm_object *strm_obj = NULL; 468 s8 chnl_mode; 469 struct chnl_attr chnl_attr_obj; 470 int status = 0; 471 struct cmm_object *hcmm_mgr = NULL; /* Shared memory manager hndl */ 472 473 void *stream_res; 474 475 DBC_REQUIRE(refs > 0); 476 DBC_REQUIRE(strmres != NULL); 477 DBC_REQUIRE(pattr != NULL); 478 *strmres = NULL; 479 if (dir != DSP_TONODE && dir != DSP_FROMNODE) { 480 status = -EPERM; 481 } else { 482 /* Get the channel id from the node (set in node_connect()) */ 483 status = node_get_channel_id(hnode, dir, index, &ul_chnl_id); 484 } 485 if (!status) 486 status = node_get_strm_mgr(hnode, &strm_mgr_obj); 487 488 if (!status) { 489 strm_obj = kzalloc(sizeof(struct strm_object), GFP_KERNEL); 490 if (strm_obj == NULL) { 491 status = -ENOMEM; 492 } else { 493 strm_obj->strm_mgr_obj = strm_mgr_obj; 494 strm_obj->dir = dir; 495 strm_obj->strm_state = STREAM_IDLE; 496 strm_obj->user_event = pattr->user_event; 497 if (pattr->stream_attr_in != NULL) { 498 strm_obj->utimeout = 499 pattr->stream_attr_in->utimeout; 500 strm_obj->num_bufs = 501 pattr->stream_attr_in->num_bufs; 502 strm_obj->strm_mode = 503 pattr->stream_attr_in->strm_mode; 504 strm_obj->segment_id = 505 pattr->stream_attr_in->segment_id; 506 strm_obj->buf_alignment = 507 pattr->stream_attr_in->buf_alignment; 508 strm_obj->udma_chnl_id = 509 pattr->stream_attr_in->udma_chnl_id; 510 strm_obj->udma_priority = 511 pattr->stream_attr_in->udma_priority; 512 chnl_attr_obj.uio_reqs = 513 pattr->stream_attr_in->num_bufs; 514 } else { 515 strm_obj->utimeout = DEFAULTTIMEOUT; 516 strm_obj->num_bufs = DEFAULTNUMBUFS; 517 strm_obj->strm_mode = STRMMODE_PROCCOPY; 518 strm_obj->segment_id = 0; /* local mem */ 519 strm_obj->buf_alignment = 0; 520 strm_obj->udma_chnl_id = 0; 521 strm_obj->udma_priority = 0; 522 chnl_attr_obj.uio_reqs = DEFAULTNUMBUFS; 523 } 524 chnl_attr_obj.reserved1 = NULL; 525 /* DMA chnl flush timeout */ 526 chnl_attr_obj.reserved2 = strm_obj->utimeout; 527 chnl_attr_obj.event_obj = NULL; 528 if (pattr->user_event != NULL) 529 chnl_attr_obj.event_obj = pattr->user_event; 530 531 } 532 } 533 if (status) 534 goto func_cont; 535 536 if ((pattr->virt_base == NULL) || !(pattr->ul_virt_size > 0)) 537 goto func_cont; 538 539 /* No System DMA */ 540 DBC_ASSERT(strm_obj->strm_mode != STRMMODE_LDMA); 541 /* Get the shared mem mgr for this streams dev object */ 542 status = dev_get_cmm_mgr(strm_mgr_obj->dev_obj, &hcmm_mgr); 543 if (!status) { 544 /*Allocate a SM addr translator for this strm. */ 545 status = cmm_xlator_create(&strm_obj->xlator, hcmm_mgr, NULL); 546 if (!status) { 547 DBC_ASSERT(strm_obj->segment_id > 0); 548 /* Set translators Virt Addr attributes */ 549 status = cmm_xlator_info(strm_obj->xlator, 550 (u8 **) &pattr->virt_base, 551 pattr->ul_virt_size, 552 strm_obj->segment_id, true); 553 } 554 } 555func_cont: 556 if (!status) { 557 /* Open channel */ 558 chnl_mode = (dir == DSP_TONODE) ? 559 CHNL_MODETODSP : CHNL_MODEFROMDSP; 560 intf_fxns = strm_mgr_obj->intf_fxns; 561 status = (*intf_fxns->pfn_chnl_open) (&(strm_obj->chnl_obj), 562 strm_mgr_obj->hchnl_mgr, 563 chnl_mode, ul_chnl_id, 564 &chnl_attr_obj); 565 if (status) { 566 /* 567 * over-ride non-returnable status codes so we return 568 * something documented 569 */ 570 if (status != -ENOMEM && status != 571 -EINVAL && status != -EPERM) { 572 /* 573 * We got a status that's not return-able. 574 * Assert that we got something we were 575 * expecting (-EFAULT isn't acceptable, 576 * strm_mgr_obj->hchnl_mgr better be valid or we 577 * assert here), and then return -EPERM. 578 */ 579 DBC_ASSERT(status == -ENOSR || 580 status == -ECHRNG || 581 status == -EALREADY || 582 status == -EIO); 583 status = -EPERM; 584 } 585 } 586 } 587 if (!status) { 588 status = drv_proc_insert_strm_res_element(strm_obj, 589 &stream_res, pr_ctxt); 590 if (status) 591 delete_strm(strm_obj); 592 else 593 *strmres = (struct strm_res_object *)stream_res; 594 } else { 595 (void)delete_strm(strm_obj); 596 } 597 598 /* ensure we return a documented error code */ 599 DBC_ENSURE((!status && strm_obj) || 600 (*strmres == NULL && (status == -EFAULT || 601 status == -EPERM 602 || status == -EINVAL))); 603 604 dev_dbg(bridge, "%s: hnode: %p dir: 0x%x index: 0x%x pattr: %p " 605 "strmres: %p status: 0x%x\n", __func__, 606 hnode, dir, index, pattr, strmres, status); 607 return status; 608} 609 610/* 611 * ======== strm_reclaim ======== 612 * Purpose: 613 * Relcaims a buffer from a stream. 614 */ 615int strm_reclaim(struct strm_object *stream_obj, u8 ** buf_ptr, 616 u32 *nbytes, u32 *buff_size, u32 *pdw_arg) 617{ 618 struct bridge_drv_interface *intf_fxns; 619 struct chnl_ioc chnl_ioc_obj; 620 int status = 0; 621 void *tmp_buf = NULL; 622 623 DBC_REQUIRE(refs > 0); 624 DBC_REQUIRE(buf_ptr != NULL); 625 DBC_REQUIRE(nbytes != NULL); 626 DBC_REQUIRE(pdw_arg != NULL); 627 628 if (!stream_obj) { 629 status = -EFAULT; 630 goto func_end; 631 } 632 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns; 633 634 status = 635 (*intf_fxns->pfn_chnl_get_ioc) (stream_obj->chnl_obj, 636 stream_obj->utimeout, 637 &chnl_ioc_obj); 638 if (!status) { 639 *nbytes = chnl_ioc_obj.byte_size; 640 if (buff_size) 641 *buff_size = chnl_ioc_obj.buf_size; 642 643 *pdw_arg = chnl_ioc_obj.dw_arg; 644 if (!CHNL_IS_IO_COMPLETE(chnl_ioc_obj)) { 645 if (CHNL_IS_TIMED_OUT(chnl_ioc_obj)) { 646 status = -ETIME; 647 } else { 648 /* Allow reclaims after idle to succeed */ 649 if (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj)) 650 status = -EPERM; 651 652 } 653 } 654 /* Translate zerocopy buffer if channel not canceled. */ 655 if (!status 656 && (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj)) 657 && (stream_obj->strm_mode == STRMMODE_ZEROCOPY)) { 658 /* 659 * This is a zero-copy channel so chnl_ioc_obj.pbuf 660 * contains the DSP address of SM. We need to 661 * translate it to a virtual address for the user 662 * thread to access. 663 * Note: Could add CMM_DSPPA2VA to CMM in the future. 664 */ 665 tmp_buf = cmm_xlator_translate(stream_obj->xlator, 666 chnl_ioc_obj.pbuf, 667 CMM_DSPPA2PA); 668 if (tmp_buf != NULL) { 669 /* now convert this GPP Pa to Va */ 670 tmp_buf = cmm_xlator_translate(stream_obj-> 671 xlator, 672 tmp_buf, 673 CMM_PA2VA); 674 } 675 if (tmp_buf == NULL) 676 status = -ESRCH; 677 678 chnl_ioc_obj.pbuf = tmp_buf; 679 } 680 *buf_ptr = chnl_ioc_obj.pbuf; 681 } 682func_end: 683 /* ensure we return a documented return code */ 684 DBC_ENSURE(!status || status == -EFAULT || 685 status == -ETIME || status == -ESRCH || 686 status == -EPERM); 687 688 dev_dbg(bridge, "%s: stream_obj: %p buf_ptr: %p nbytes: %p " 689 "pdw_arg: %p status 0x%x\n", __func__, stream_obj, 690 buf_ptr, nbytes, pdw_arg, status); 691 return status; 692} 693 694/* 695 * ======== strm_register_notify ======== 696 * Purpose: 697 * Register to be notified on specific events for this stream. 698 */ 699int strm_register_notify(struct strm_object *stream_obj, u32 event_mask, 700 u32 notify_type, struct dsp_notification 701 * hnotification) 702{ 703 struct bridge_drv_interface *intf_fxns; 704 int status = 0; 705 706 DBC_REQUIRE(refs > 0); 707 DBC_REQUIRE(hnotification != NULL); 708 709 if (!stream_obj) { 710 status = -EFAULT; 711 } else if ((event_mask & ~((DSP_STREAMIOCOMPLETION) | 712 DSP_STREAMDONE)) != 0) { 713 status = -EINVAL; 714 } else { 715 if (notify_type != DSP_SIGNALEVENT) 716 status = -ENOSYS; 717 718 } 719 if (!status) { 720 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns; 721 722 status = 723 (*intf_fxns->pfn_chnl_register_notify) (stream_obj-> 724 chnl_obj, 725 event_mask, 726 notify_type, 727 hnotification); 728 } 729 /* ensure we return a documented return code */ 730 DBC_ENSURE(!status || status == -EFAULT || 731 status == -ETIME || status == -ESRCH || 732 status == -ENOSYS || status == -EPERM); 733 return status; 734} 735 736/* 737 * ======== strm_select ======== 738 * Purpose: 739 * Selects a ready stream. 740 */ 741int strm_select(struct strm_object **strm_tab, u32 strms, 742 u32 *pmask, u32 utimeout) 743{ 744 u32 index; 745 struct chnl_info chnl_info_obj; 746 struct bridge_drv_interface *intf_fxns; 747 struct sync_object **sync_events = NULL; 748 u32 i; 749 int status = 0; 750 751 DBC_REQUIRE(refs > 0); 752 DBC_REQUIRE(strm_tab != NULL); 753 DBC_REQUIRE(pmask != NULL); 754 DBC_REQUIRE(strms > 0); 755 756 *pmask = 0; 757 for (i = 0; i < strms; i++) { 758 if (!strm_tab[i]) { 759 status = -EFAULT; 760 break; 761 } 762 } 763 if (status) 764 goto func_end; 765 766 /* Determine which channels have IO ready */ 767 for (i = 0; i < strms; i++) { 768 intf_fxns = strm_tab[i]->strm_mgr_obj->intf_fxns; 769 status = (*intf_fxns->pfn_chnl_get_info) (strm_tab[i]->chnl_obj, 770 &chnl_info_obj); 771 if (status) { 772 break; 773 } else { 774 if (chnl_info_obj.cio_cs > 0) 775 *pmask |= (1 << i); 776 777 } 778 } 779 if (!status && utimeout > 0 && *pmask == 0) { 780 /* Non-zero timeout */ 781 sync_events = kmalloc(strms * sizeof(struct sync_object *), 782 GFP_KERNEL); 783 784 if (sync_events == NULL) { 785 status = -ENOMEM; 786 } else { 787 for (i = 0; i < strms; i++) { 788 intf_fxns = 789 strm_tab[i]->strm_mgr_obj->intf_fxns; 790 status = (*intf_fxns->pfn_chnl_get_info) 791 (strm_tab[i]->chnl_obj, &chnl_info_obj); 792 if (status) 793 break; 794 else 795 sync_events[i] = 796 chnl_info_obj.sync_event; 797 798 } 799 } 800 if (!status) { 801 status = 802 sync_wait_on_multiple_events(sync_events, strms, 803 utimeout, &index); 804 if (!status) { 805 /* Since we waited on the event, we have to 806 * reset it */ 807 sync_set_event(sync_events[index]); 808 *pmask = 1 << index; 809 } 810 } 811 } 812func_end: 813 kfree(sync_events); 814 815 DBC_ENSURE((!status && (*pmask != 0 || utimeout == 0)) || 816 (status && *pmask == 0)); 817 818 return status; 819} 820 821/* 822 * ======== delete_strm ======== 823 * Purpose: 824 * Frees the resources allocated for a stream. 825 */ 826static int delete_strm(struct strm_object *stream_obj) 827{ 828 struct bridge_drv_interface *intf_fxns; 829 int status = 0; 830 831 if (stream_obj) { 832 if (stream_obj->chnl_obj) { 833 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns; 834 /* Channel close can fail only if the channel handle 835 * is invalid. */ 836 status = (*intf_fxns->pfn_chnl_close) 837 (stream_obj->chnl_obj); 838 /* Free all SM address translator resources */ 839 if (!status) { 840 if (stream_obj->xlator) { 841 /* force free */ 842 (void)cmm_xlator_delete(stream_obj-> 843 xlator, 844 true); 845 } 846 } 847 } 848 kfree(stream_obj); 849 } else { 850 status = -EFAULT; 851 } 852 return status; 853} 854