]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/staging/intel_sst/intel_sst_pvt.c
Merge branch 'x86-tsc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mv-sheeva.git] / drivers / staging / intel_sst / intel_sst_pvt.c
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 #include <linux/pci.h>
33 #include <linux/fs.h>
34 #include <linux/firmware.h>
35 #include <linux/sched.h>
36 #include "intel_sst.h"
37 #include "intel_sst_ioctl.h"
38 #include "intel_sst_fw_ipc.h"
39 #include "intel_sst_common.h"
40
41 /*
42  * sst_get_block_stream - get a new block stream
43  *
44  * @sst_drv_ctx: Driver context structure
45  *
46  * This function assigns a block for the calls that dont have stream context yet
47  * the blocks are used for waiting on Firmware's response for any operation
48  * Should be called with stream lock held
49  */
50 int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx)
51 {
52         int i;
53
54         for (i = 0; i < MAX_ACTIVE_STREAM; i++) {
55                 if (sst_drv_ctx->alloc_block[i].sst_id == BLOCK_UNINIT) {
56                         sst_drv_ctx->alloc_block[i].ops_block.condition = false;
57                         sst_drv_ctx->alloc_block[i].ops_block.ret_code = 0;
58                         sst_drv_ctx->alloc_block[i].sst_id = 0;
59                         break;
60                 }
61         }
62         if (i == MAX_ACTIVE_STREAM) {
63                 pr_err("sst: max alloc_stream reached");
64                 i = -EBUSY; /* active stream limit reached */
65         }
66         return i;
67 }
68
69 /*
70  * sst_wait_interruptible - wait on event
71  *
72  * @sst_drv_ctx: Driver context
73  * @block: Driver block to wait on
74  *
75  * This function waits without a timeout (and is interruptable) for a
76  * given block event
77  */
78 int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
79                                 struct sst_block *block)
80 {
81         int retval = 0;
82
83         if (!wait_event_interruptible(sst_drv_ctx->wait_queue,
84                                 block->condition)) {
85                 /* event wake */
86                 if (block->ret_code < 0) {
87                         pr_err("sst: stream failed %d\n", block->ret_code);
88                         retval = -EBUSY;
89                 } else {
90                         pr_debug("sst: event up\n");
91                         retval = 0;
92                 }
93         } else {
94                 pr_err("sst: signal interrupted\n");
95                 retval = -EINTR;
96         }
97         return retval;
98
99 }
100
101
102 /*
103  * sst_wait_interruptible_timeout - wait on event interruptable
104  *
105  * @sst_drv_ctx: Driver context
106  * @block: Driver block to wait on
107  * @timeout: time for wait on
108  *
109  * This function waits with a timeout value (and is interruptible) on a
110  * given block event
111  */
112 int sst_wait_interruptible_timeout(
113                         struct intel_sst_drv *sst_drv_ctx,
114                         struct sst_block *block, int timeout)
115 {
116         int retval = 0;
117
118         pr_debug("sst: sst_wait_interruptible_timeout - waiting....\n");
119         if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue,
120                                                 block->condition,
121                                                 msecs_to_jiffies(timeout))) {
122                 if (block->ret_code < 0)
123                         pr_err("sst: stream failed %d\n", block->ret_code);
124                 else
125                         pr_debug("sst: event up\n");
126                 retval = block->ret_code;
127         } else {
128                 block->on = false;
129                 pr_err("sst: timeout occured...\n");
130                 /*setting firmware state as uninit so that the
131                 firmware will get re-downloaded on next request
132                 this is because firmare not responding for 5 sec
133                 is equalant to some unrecoverable error of FW
134                 sst_drv_ctx->sst_state = SST_UN_INIT;*/
135                 retval = -EBUSY;
136         }
137         return retval;
138
139 }
140
141
142 /*
143  * sst_wait_timeout - wait on event for timeout
144  *
145  * @sst_drv_ctx: Driver context
146  * @block: Driver block to wait on
147  *
148  * This function waits with a timeout value (and is not interruptible) on a
149  * given block event
150  */
151 int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx,
152                 struct stream_alloc_block *block)
153 {
154         int retval = 0;
155
156         /* NOTE:
157         Observed that FW processes the alloc msg and replies even
158         before the alloc thread has finished execution */
159         pr_debug("sst: waiting for %x, condition %x\n",
160                        block->sst_id, block->ops_block.condition);
161         if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue,
162                                 block->ops_block.condition,
163                                 msecs_to_jiffies(SST_BLOCK_TIMEOUT))) {
164                 /* event wake */
165                 pr_debug("sst: Event wake %x\n", block->ops_block.condition);
166                 pr_debug("sst: message ret: %d\n", block->ops_block.ret_code);
167                 retval = block->ops_block.ret_code;
168         } else {
169                 block->ops_block.on = false;
170                 pr_err("sst: Wait timed-out %x\n", block->ops_block.condition);
171                 /* settign firmware state as uninit so that the
172                 firmware will get redownloaded on next request
173                 this is because firmare not responding for 5 sec
174                 is equalant to some unrecoverable error of FW
175                 sst_drv_ctx->sst_state = SST_UN_INIT;*/
176                 retval = -EBUSY;
177         }
178         return retval;
179
180 }
181
182 /*
183  * sst_create_large_msg - create a large IPC message
184  *
185  * @arg: ipc message
186  *
187  * this function allocates structures to send a large message to the firmware
188  */
189 int sst_create_large_msg(struct ipc_post **arg)
190 {
191         struct ipc_post *msg;
192
193         msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
194         if (!msg) {
195                 pr_err("sst: kzalloc msg failed\n");
196                 return -ENOMEM;
197         }
198
199         msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
200         if (!msg->mailbox_data) {
201                 kfree(msg);
202                 pr_err("sst: kzalloc mailbox_data failed");
203                 return -ENOMEM;
204         };
205         *arg = msg;
206         return 0;
207 }
208
209 /*
210  * sst_create_short_msg - create a short IPC message
211  *
212  * @arg: ipc message
213  *
214  * this function allocates structures to send a short message to the firmware
215  */
216 int sst_create_short_msg(struct ipc_post **arg)
217 {
218         struct ipc_post *msg;
219
220         msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
221         if (!msg) {
222                 pr_err("sst: kzalloc msg failed\n");
223                 return -ENOMEM;
224         }
225         msg->mailbox_data = NULL;
226         *arg = msg;
227         return 0;
228 }
229
230 /*
231  * sst_clean_stream - clean the stream context
232  *
233  * @stream: stream structure
234  *
235  * this function resets the stream contexts
236  * should be called in free
237  */
238 void sst_clean_stream(struct stream_info *stream)
239 {
240         struct sst_stream_bufs *bufs = NULL, *_bufs;
241         stream->status = STREAM_UN_INIT;
242         stream->prev = STREAM_UN_INIT;
243         mutex_lock(&stream->lock);
244         list_for_each_entry_safe(bufs, _bufs, &stream->bufs, node) {
245                 list_del(&bufs->node);
246                 kfree(bufs);
247         }
248         mutex_unlock(&stream->lock);
249
250         if (stream->ops != STREAM_OPS_PLAYBACK_DRM)
251                 kfree(stream->decode_ibuf);
252 }
253
254 /*
255  * sst_wake_up_alloc_block - wake up waiting block
256  *
257  * @sst_drv_ctx: Driver context
258  * @sst_id: stream id
259  * @status: status of wakeup
260  * @data: data pointer of wakeup
261  *
262  * This function wakes up a sleeping block event based on the response
263  */
264 void sst_wake_up_alloc_block(struct intel_sst_drv *sst_drv_ctx,
265                 u8 sst_id, int status, void *data)
266 {
267         int i;
268
269         /* Unblock with retval code */
270         for (i = 0; i < MAX_ACTIVE_STREAM; i++) {
271                 if (sst_id == sst_drv_ctx->alloc_block[i].sst_id) {
272                         sst_drv_ctx->alloc_block[i].ops_block.condition = true;
273                         sst_drv_ctx->alloc_block[i].ops_block.ret_code = status;
274                         sst_drv_ctx->alloc_block[i].ops_block.data = data;
275                         wake_up(&sst_drv_ctx->wait_queue);
276                         break;
277                 }
278         }
279 }
280
281 /*
282  * sst_enable_rx_timeslot - Send msg to query for stream parameters
283  * @status: rx timeslot to be enabled
284  *
285  * This function is called when the RX timeslot is required to be enabled
286  */
287 int sst_enable_rx_timeslot(int status)
288 {
289         int retval = 0;
290         struct ipc_post *msg = NULL;
291
292         if (sst_create_short_msg(&msg)) {
293                 pr_err("sst: mem allocation failed\n");
294                         return -ENOMEM;
295         }
296         pr_debug("sst: ipc message sending: ENABLE_RX_TIME_SLOT\n");
297         sst_fill_header(&msg->header, IPC_IA_ENABLE_RX_TIME_SLOT, 0, 0);
298         msg->header.part.data = status;
299         sst_drv_ctx->hs_info_blk.condition = false;
300         sst_drv_ctx->hs_info_blk.ret_code = 0;
301         sst_drv_ctx->hs_info_blk.on = true;
302         spin_lock(&sst_drv_ctx->list_spin_lock);
303         list_add_tail(&msg->node,
304                         &sst_drv_ctx->ipc_dispatch_list);
305         spin_unlock(&sst_drv_ctx->list_spin_lock);
306         sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
307         retval = sst_wait_interruptible_timeout(sst_drv_ctx,
308                                 &sst_drv_ctx->hs_info_blk, SST_BLOCK_TIMEOUT);
309         return retval;
310 }
311