linux/drivers/staging/intel_sst/intel_sst_pvt.c
<<
>>
Prefs
   1/*
   2 *  intel_sst_pvt.c - Intel SST Driver for audio engine
   3 *
   4 *  Copyright (C) 2008-10       Intel Corp
   5 *  Authors:    Vinod Koul <vinod.koul@intel.com>
   6 *              Harsha Priya <priya.harsha@intel.com>
   7 *              Dharageswari R <dharageswari.r@intel.com>
   8 *              KP Jeeja <jeeja.kp@intel.com>
   9 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  10 *
  11 *  This program is free software; you can redistribute it and/or modify
  12 *  it under the terms of the GNU General Public License as published by
  13 *  the Free Software Foundation; version 2 of the License.
  14 *
  15 *  This program is distributed in the hope that it will be useful, but
  16 *  WITHOUT ANY WARRANTY; without even the implied warranty of
  17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18 *  General Public License for more details.
  19 *
  20 *  You should have received a copy of the GNU General Public License along
  21 *  with this program; if not, write to the Free Software Foundation, Inc.,
  22 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  23 *
  24 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  25 *
  26 *  This driver exposes the audio engine functionalities to the ALSA
  27 *      and middleware.
  28 *
  29 *  This file contains all private functions
  30 */
  31
  32#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  33
  34#include <linux/pci.h>
  35#include <linux/fs.h>
  36#include <linux/firmware.h>
  37#include <linux/sched.h>
  38#include "intel_sst.h"
  39#include "intel_sst_ioctl.h"
  40#include "intel_sst_fw_ipc.h"
  41#include "intel_sst_common.h"
  42
  43/*
  44 * sst_get_block_stream - get a new block stream
  45 *
  46 * @sst_drv_ctx: Driver context structure
  47 *
  48 * This function assigns a block for the calls that dont have stream context yet
  49 * the blocks are used for waiting on Firmware's response for any operation
  50 * Should be called with stream lock held
  51 */
  52int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx)
  53{
  54        int i;
  55
  56        for (i = 0; i < MAX_ACTIVE_STREAM; i++) {
  57                if (sst_drv_ctx->alloc_block[i].sst_id == BLOCK_UNINIT) {
  58                        sst_drv_ctx->alloc_block[i].ops_block.condition = false;
  59                        sst_drv_ctx->alloc_block[i].ops_block.ret_code = 0;
  60                        sst_drv_ctx->alloc_block[i].sst_id = 0;
  61                        break;
  62                }
  63        }
  64        if (i == MAX_ACTIVE_STREAM) {
  65                pr_err("max alloc_stream reached\n");
  66                i = -EBUSY; /* active stream limit reached */
  67        }
  68        return i;
  69}
  70
  71/*
  72 * sst_wait_interruptible - wait on event
  73 *
  74 * @sst_drv_ctx: Driver context
  75 * @block: Driver block to wait on
  76 *
  77 * This function waits without a timeout (and is interruptable) for a
  78 * given block event
  79 */
  80int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
  81                                struct sst_block *block)
  82{
  83        int retval = 0;
  84
  85        if (!wait_event_interruptible(sst_drv_ctx->wait_queue,
  86                                block->condition)) {
  87                /* event wake */
  88                if (block->ret_code < 0) {
  89                        pr_err("stream failed %d\n", block->ret_code);
  90                        retval = -EBUSY;
  91                } else {
  92                        pr_debug("event up\n");
  93                        retval = 0;
  94                }
  95        } else {
  96                pr_err("signal interrupted\n");
  97                retval = -EINTR;
  98        }
  99        return retval;
 100
 101}
 102
 103
 104/*
 105 * sst_wait_interruptible_timeout - wait on event interruptable
 106 *
 107 * @sst_drv_ctx: Driver context
 108 * @block: Driver block to wait on
 109 * @timeout: time for wait on
 110 *
 111 * This function waits with a timeout value (and is interruptible) on a
 112 * given block event
 113 */
 114int sst_wait_interruptible_timeout(
 115                        struct intel_sst_drv *sst_drv_ctx,
 116                        struct sst_block *block, int timeout)
 117{
 118        int retval = 0;
 119
 120        pr_debug("sst_wait_interruptible_timeout - waiting....\n");
 121        if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue,
 122                                                block->condition,
 123                                                msecs_to_jiffies(timeout))) {
 124                if (block->ret_code < 0)
 125                        pr_err("stream failed %d\n", block->ret_code);
 126                else
 127                        pr_debug("event up\n");
 128                retval = block->ret_code;
 129        } else {
 130                block->on = false;
 131                pr_err("timeout occurred...\n");
 132                /*setting firmware state as uninit so that the
 133                firmware will get re-downloaded on next request
 134                this is because firmare not responding for 5 sec
 135                is equalant to some unrecoverable error of FW
 136                sst_drv_ctx->sst_state = SST_UN_INIT;*/
 137                retval = -EBUSY;
 138        }
 139        return retval;
 140
 141}
 142
 143
 144/*
 145 * sst_wait_timeout - wait on event for timeout
 146 *
 147 * @sst_drv_ctx: Driver context
 148 * @block: Driver block to wait on
 149 *
 150 * This function waits with a timeout value (and is not interruptible) on a
 151 * given block event
 152 */
 153int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx,
 154                struct stream_alloc_block *block)
 155{
 156        int retval = 0;
 157
 158        /* NOTE:
 159        Observed that FW processes the alloc msg and replies even
 160        before the alloc thread has finished execution */
 161        pr_debug("waiting for %x, condition %x\n",
 162                       block->sst_id, block->ops_block.condition);
 163        if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue,
 164                                block->ops_block.condition,
 165                                msecs_to_jiffies(SST_BLOCK_TIMEOUT))) {
 166                /* event wake */
 167                pr_debug("Event wake %x\n", block->ops_block.condition);
 168                pr_debug("message ret: %d\n", block->ops_block.ret_code);
 169                retval = block->ops_block.ret_code;
 170        } else {
 171                block->ops_block.on = false;
 172                pr_err("Wait timed-out %x\n", block->ops_block.condition);
 173                /* settign firmware state as uninit so that the
 174                firmware will get redownloaded on next request
 175                this is because firmare not responding for 5 sec
 176                is equalant to some unrecoverable error of FW
 177                sst_drv_ctx->sst_state = SST_UN_INIT;*/
 178                retval = -EBUSY;
 179        }
 180        return retval;
 181
 182}
 183
 184/*
 185 * sst_create_large_msg - create a large IPC message
 186 *
 187 * @arg: ipc message
 188 *
 189 * this function allocates structures to send a large message to the firmware
 190 */
 191int sst_create_large_msg(struct ipc_post **arg)
 192{
 193        struct ipc_post *msg;
 194
 195        msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
 196        if (!msg) {
 197                pr_err("kzalloc msg failed\n");
 198                return -ENOMEM;
 199        }
 200
 201        msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
 202        if (!msg->mailbox_data) {
 203                kfree(msg);
 204                pr_err("kzalloc mailbox_data failed");
 205                return -ENOMEM;
 206        };
 207        *arg = msg;
 208        return 0;
 209}
 210
 211/*
 212 * sst_create_short_msg - create a short IPC message
 213 *
 214 * @arg: ipc message
 215 *
 216 * this function allocates structures to send a short message to the firmware
 217 */
 218int sst_create_short_msg(struct ipc_post **arg)
 219{
 220        struct ipc_post *msg;
 221
 222        msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
 223        if (!msg) {
 224                pr_err("kzalloc msg failed\n");
 225                return -ENOMEM;
 226        }
 227        msg->mailbox_data = NULL;
 228        *arg = msg;
 229        return 0;
 230}
 231
 232/*
 233 * sst_clean_stream - clean the stream context
 234 *
 235 * @stream: stream structure
 236 *
 237 * this function resets the stream contexts
 238 * should be called in free
 239 */
 240void sst_clean_stream(struct stream_info *stream)
 241{
 242        struct sst_stream_bufs *bufs = NULL, *_bufs;
 243        stream->status = STREAM_UN_INIT;
 244        stream->prev = STREAM_UN_INIT;
 245        mutex_lock(&stream->lock);
 246        list_for_each_entry_safe(bufs, _bufs, &stream->bufs, node) {
 247                list_del(&bufs->node);
 248                kfree(bufs);
 249        }
 250        mutex_unlock(&stream->lock);
 251
 252        if (stream->ops != STREAM_OPS_PLAYBACK_DRM)
 253                kfree(stream->decode_ibuf);
 254}
 255
 256/*
 257 * sst_wake_up_alloc_block - wake up waiting block
 258 *
 259 * @sst_drv_ctx: Driver context
 260 * @sst_id: stream id
 261 * @status: status of wakeup
 262 * @data: data pointer of wakeup
 263 *
 264 * This function wakes up a sleeping block event based on the response
 265 */
 266void sst_wake_up_alloc_block(struct intel_sst_drv *sst_drv_ctx,
 267                u8 sst_id, int status, void *data)
 268{
 269        int i;
 270
 271        /* Unblock with retval code */
 272        for (i = 0; i < MAX_ACTIVE_STREAM; i++) {
 273                if (sst_id == sst_drv_ctx->alloc_block[i].sst_id) {
 274                        sst_drv_ctx->alloc_block[i].ops_block.condition = true;
 275                        sst_drv_ctx->alloc_block[i].ops_block.ret_code = status;
 276                        sst_drv_ctx->alloc_block[i].ops_block.data = data;
 277                        wake_up(&sst_drv_ctx->wait_queue);
 278                        break;
 279                }
 280        }
 281}
 282
 283/*
 284 * sst_enable_rx_timeslot - Send msg to query for stream parameters
 285 * @status: rx timeslot to be enabled
 286 *
 287 * This function is called when the RX timeslot is required to be enabled
 288 */
 289int sst_enable_rx_timeslot(int status)
 290{
 291        int retval = 0;
 292        struct ipc_post *msg = NULL;
 293
 294        if (sst_create_short_msg(&msg)) {
 295                pr_err("mem allocation failed\n");
 296                        return -ENOMEM;
 297        }
 298        pr_debug("ipc message sending: ENABLE_RX_TIME_SLOT\n");
 299        sst_fill_header(&msg->header, IPC_IA_ENABLE_RX_TIME_SLOT, 0, 0);
 300        msg->header.part.data = status;
 301        sst_drv_ctx->hs_info_blk.condition = false;
 302        sst_drv_ctx->hs_info_blk.ret_code = 0;
 303        sst_drv_ctx->hs_info_blk.on = true;
 304        spin_lock(&sst_drv_ctx->list_spin_lock);
 305        list_add_tail(&msg->node,
 306                        &sst_drv_ctx->ipc_dispatch_list);
 307        spin_unlock(&sst_drv_ctx->list_spin_lock);
 308        sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
 309        retval = sst_wait_interruptible_timeout(sst_drv_ctx,
 310                                &sst_drv_ctx->hs_info_blk, SST_BLOCK_TIMEOUT);
 311        return retval;
 312}
 313
 314