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