upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / staging / tidspbridge / core / chnl_sm.c
1 /*
2  * chnl_sm.c
3  *
4  * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5  *
6  * Implements upper edge functions for Bridge driver channel module.
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 /*
20  *      The lower edge functions must be implemented by the Bridge driver
21  *      writer, and are declared in chnl_sm.h.
22  *
23  *      Care is taken in this code to prevent simulataneous access to channel
24  *      queues from
25  *      1. Threads.
26  *      2. io_dpc(), scheduled from the io_isr() as an event.
27  *
28  *      This is done primarily by:
29  *      - Semaphores.
30  *      - state flags in the channel object; and
31  *      - ensuring the IO_Dispatch() routine, which is called from both
32  *        CHNL_AddIOReq() and the DPC(if implemented), is not re-entered.
33  *
34  *  Channel Invariant:
35  *      There is an important invariant condition which must be maintained per
36  *      channel outside of bridge_chnl_get_ioc() and IO_Dispatch(), violation of
37  *      which may cause timeouts and/or failure offunction sync_wait_on_event.
38  *      This invariant condition is:
39  *
40  *          LST_Empty(pchnl->pio_completions) ==> pchnl->sync_event is reset
41  *      and
42  *          !LST_Empty(pchnl->pio_completions) ==> pchnl->sync_event is set.
43  */
44
45 #include <linux/types.h>
46
47 /*  ----------------------------------- OS */
48 #include <dspbridge/host_os.h>
49
50 /*  ----------------------------------- DSP/BIOS Bridge */
51 #include <dspbridge/dbdefs.h>
52
53 /*  ----------------------------------- Trace & Debug */
54 #include <dspbridge/dbc.h>
55
56 /*  ----------------------------------- OS Adaptation Layer */
57 #include <dspbridge/cfg.h>
58 #include <dspbridge/sync.h>
59
60 /*  ----------------------------------- Bridge Driver */
61 #include <dspbridge/dspdefs.h>
62 #include <dspbridge/dspchnl.h>
63 #include "_tiomap.h"
64
65 /*  ----------------------------------- Platform Manager */
66 #include <dspbridge/dev.h>
67
68 /*  ----------------------------------- Others */
69 #include <dspbridge/io_sm.h>
70
71 /*  ----------------------------------- Define for This */
72 #define USERMODE_ADDR   PAGE_OFFSET
73
74 #define MAILBOX_IRQ INT_MAIL_MPU_IRQ
75
76 /*  ----------------------------------- Function Prototypes */
77 static struct lst_list *create_chirp_list(u32 chirps);
78
79 static void free_chirp_list(struct lst_list *chirp_list);
80
81 static struct chnl_irp *make_new_chirp(void);
82
83 static int search_free_channel(struct chnl_mgr *chnl_mgr_obj,
84                                       u32 *chnl);
85
86 /*
87  *  ======== bridge_chnl_add_io_req ========
88  *      Enqueue an I/O request for data transfer on a channel to the DSP.
89  *      The direction (mode) is specified in the channel object. Note the DSP
90  *      address is specified for channels opened in direct I/O mode.
91  */
92 int bridge_chnl_add_io_req(struct chnl_object *chnl_obj, void *host_buf,
93                                u32 byte_size, u32 buf_size,
94                                u32 dw_dsp_addr, u32 dw_arg)
95 {
96         int status = 0;
97         struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
98         struct chnl_irp *chnl_packet_obj = NULL;
99         struct bridge_dev_context *dev_ctxt;
100         struct dev_object *dev_obj;
101         u8 dw_state;
102         bool is_eos;
103         struct chnl_mgr *chnl_mgr_obj = pchnl->chnl_mgr_obj;
104         u8 *host_sys_buf = NULL;
105         bool sched_dpc = false;
106         u16 mb_val = 0;
107
108         is_eos = (byte_size == 0);
109
110         /* Validate args */
111         if (!host_buf || !pchnl) {
112                 status = -EFAULT;
113         } else if (is_eos && CHNL_IS_INPUT(pchnl->chnl_mode)) {
114                 status = -EPERM;
115         } else {
116                 /*
117                  * Check the channel state: only queue chirp if channel state
118                  * allows it.
119                  */
120                 dw_state = pchnl->dw_state;
121                 if (dw_state != CHNL_STATEREADY) {
122                         if (dw_state & CHNL_STATECANCEL)
123                                 status = -ECANCELED;
124                         else if ((dw_state & CHNL_STATEEOS) &&
125                                  CHNL_IS_OUTPUT(pchnl->chnl_mode))
126                                 status = -EPIPE;
127                         else
128                                 /* No other possible states left */
129                                 DBC_ASSERT(0);
130                 }
131         }
132
133         dev_obj = dev_get_first();
134         dev_get_bridge_context(dev_obj, &dev_ctxt);
135         if (!dev_ctxt)
136                 status = -EFAULT;
137
138         if (status)
139                 goto func_end;
140
141         if (pchnl->chnl_type == CHNL_PCPY && pchnl->chnl_id > 1 && host_buf) {
142                 if (!(host_buf < (void *)USERMODE_ADDR)) {
143                         host_sys_buf = host_buf;
144                         goto func_cont;
145                 }
146                 /* if addr in user mode, then copy to kernel space */
147                 host_sys_buf = kmalloc(buf_size, GFP_KERNEL);
148                 if (host_sys_buf == NULL) {
149                         status = -ENOMEM;
150                         goto func_end;
151                 }
152                 if (CHNL_IS_OUTPUT(pchnl->chnl_mode)) {
153                         status = copy_from_user(host_sys_buf, host_buf,
154                                                 buf_size);
155                         if (status) {
156                                 kfree(host_sys_buf);
157                                 host_sys_buf = NULL;
158                                 status = -EFAULT;
159                                 goto func_end;
160                         }
161                 }
162         }
163 func_cont:
164         /* Mailbox IRQ is disabled to avoid race condition with DMA/ZCPY
165          * channels. DPCCS is held to avoid race conditions with PCPY channels.
166          * If DPC is scheduled in process context (iosm_schedule) and any
167          * non-mailbox interrupt occurs, that DPC will run and break CS. Hence
168          * we disable ALL DPCs. We will try to disable ONLY IO DPC later. */
169         spin_lock_bh(&chnl_mgr_obj->chnl_mgr_lock);
170         omap_mbox_disable_irq(dev_ctxt->mbox, IRQ_RX);
171         if (pchnl->chnl_type == CHNL_PCPY) {
172                 /* This is a processor-copy channel. */
173                 if (!status && CHNL_IS_OUTPUT(pchnl->chnl_mode)) {
174                         /* Check buffer size on output channels for fit. */
175                         if (byte_size >
176                             io_buf_size(pchnl->chnl_mgr_obj->hio_mgr))
177                                 status = -EINVAL;
178
179                 }
180         }
181         if (!status) {
182                 /* Get a free chirp: */
183                 chnl_packet_obj =
184                     (struct chnl_irp *)lst_get_head(pchnl->free_packets_list);
185                 if (chnl_packet_obj == NULL)
186                         status = -EIO;
187
188         }
189         if (!status) {
190                 /* Enqueue the chirp on the chnl's IORequest queue: */
191                 chnl_packet_obj->host_user_buf = chnl_packet_obj->host_sys_buf =
192                     host_buf;
193                 if (pchnl->chnl_type == CHNL_PCPY && pchnl->chnl_id > 1)
194                         chnl_packet_obj->host_sys_buf = host_sys_buf;
195
196                 /*
197                  * Note: for dma chans dw_dsp_addr contains dsp address
198                  * of SM buffer.
199                  */
200                 DBC_ASSERT(chnl_mgr_obj->word_size != 0);
201                 /* DSP address */
202                 chnl_packet_obj->dsp_tx_addr =
203                     dw_dsp_addr / chnl_mgr_obj->word_size;
204                 chnl_packet_obj->byte_size = byte_size;
205                 chnl_packet_obj->buf_size = buf_size;
206                 /* Only valid for output channel */
207                 chnl_packet_obj->dw_arg = dw_arg;
208                 chnl_packet_obj->status = (is_eos ? CHNL_IOCSTATEOS :
209                                            CHNL_IOCSTATCOMPLETE);
210                 lst_put_tail(pchnl->pio_requests,
211                              (struct list_head *)chnl_packet_obj);
212                 pchnl->cio_reqs++;
213                 DBC_ASSERT(pchnl->cio_reqs <= pchnl->chnl_packets);
214                 /*
215                  * If end of stream, update the channel state to prevent
216                  * more IOR's.
217                  */
218                 if (is_eos)
219                         pchnl->dw_state |= CHNL_STATEEOS;
220
221                 /* Legacy DSM Processor-Copy */
222                 DBC_ASSERT(pchnl->chnl_type == CHNL_PCPY);
223                 /* Request IO from the DSP */
224                 io_request_chnl(chnl_mgr_obj->hio_mgr, pchnl,
225                                 (CHNL_IS_INPUT(pchnl->chnl_mode) ? IO_INPUT :
226                                  IO_OUTPUT), &mb_val);
227                 sched_dpc = true;
228
229         }
230         omap_mbox_enable_irq(dev_ctxt->mbox, IRQ_RX);
231         spin_unlock_bh(&chnl_mgr_obj->chnl_mgr_lock);
232         if (mb_val != 0)
233                 sm_interrupt_dsp(dev_ctxt, mb_val);
234
235         /* Schedule a DPC, to do the actual data transfer */
236         if (sched_dpc)
237                 iosm_schedule(chnl_mgr_obj->hio_mgr);
238
239 func_end:
240         return status;
241 }
242
243 /*
244  *  ======== bridge_chnl_cancel_io ========
245  *      Return all I/O requests to the client which have not yet been
246  *      transferred.  The channel's I/O completion object is
247  *      signalled, and all the I/O requests are queued as IOC's, with the
248  *      status field set to CHNL_IOCSTATCANCEL.
249  *      This call is typically used in abort situations, and is a prelude to
250  *      chnl_close();
251  */
252 int bridge_chnl_cancel_io(struct chnl_object *chnl_obj)
253 {
254         int status = 0;
255         struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
256         u32 chnl_id = -1;
257         s8 chnl_mode;
258         struct chnl_irp *chnl_packet_obj;
259         struct chnl_mgr *chnl_mgr_obj = NULL;
260
261         /* Check args: */
262         if (pchnl && pchnl->chnl_mgr_obj) {
263                 chnl_id = pchnl->chnl_id;
264                 chnl_mode = pchnl->chnl_mode;
265                 chnl_mgr_obj = pchnl->chnl_mgr_obj;
266         } else {
267                 status = -EFAULT;
268         }
269         if (status)
270                 goto func_end;
271
272         /*  Mark this channel as cancelled, to prevent further IORequests or
273          *  IORequests or dispatching. */
274         spin_lock_bh(&chnl_mgr_obj->chnl_mgr_lock);
275         pchnl->dw_state |= CHNL_STATECANCEL;
276         if (LST_IS_EMPTY(pchnl->pio_requests))
277                 goto func_cont;
278
279         if (pchnl->chnl_type == CHNL_PCPY) {
280                 /* Indicate we have no more buffers available for transfer: */
281                 if (CHNL_IS_INPUT(pchnl->chnl_mode)) {
282                         io_cancel_chnl(chnl_mgr_obj->hio_mgr, chnl_id);
283                 } else {
284                         /* Record that we no longer have output buffers
285                          * available: */
286                         chnl_mgr_obj->dw_output_mask &= ~(1 << chnl_id);
287                 }
288         }
289         /* Move all IOR's to IOC queue: */
290         while (!LST_IS_EMPTY(pchnl->pio_requests)) {
291                 chnl_packet_obj =
292                     (struct chnl_irp *)lst_get_head(pchnl->pio_requests);
293                 if (chnl_packet_obj) {
294                         chnl_packet_obj->byte_size = 0;
295                         chnl_packet_obj->status |= CHNL_IOCSTATCANCEL;
296                         lst_put_tail(pchnl->pio_completions,
297                                      (struct list_head *)chnl_packet_obj);
298                         pchnl->cio_cs++;
299                         pchnl->cio_reqs--;
300                         DBC_ASSERT(pchnl->cio_reqs >= 0);
301                 }
302         }
303 func_cont:
304         spin_unlock_bh(&chnl_mgr_obj->chnl_mgr_lock);
305 func_end:
306         return status;
307 }
308
309 /*
310  *  ======== bridge_chnl_close ========
311  *  Purpose:
312  *      Ensures all pending I/O on this channel is cancelled, discards all
313  *      queued I/O completion notifications, then frees the resources allocated
314  *      for this channel, and makes the corresponding logical channel id
315  *      available for subsequent use.
316  */
317 int bridge_chnl_close(struct chnl_object *chnl_obj)
318 {
319         int status;
320         struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
321
322         /* Check args: */
323         if (!pchnl) {
324                 status = -EFAULT;
325                 goto func_cont;
326         }
327         {
328                 /* Cancel IO: this ensures no further IO requests or
329                  * notifications. */
330                 status = bridge_chnl_cancel_io(chnl_obj);
331         }
332 func_cont:
333         if (!status) {
334                 /* Assert I/O on this channel is now cancelled: Protects
335                  * from io_dpc. */
336                 DBC_ASSERT((pchnl->dw_state & CHNL_STATECANCEL));
337                 /* Invalidate channel object: Protects from
338                  * CHNL_GetIOCompletion(). */
339                 /* Free the slot in the channel manager: */
340                 pchnl->chnl_mgr_obj->ap_channel[pchnl->chnl_id] = NULL;
341                 spin_lock_bh(&pchnl->chnl_mgr_obj->chnl_mgr_lock);
342                 pchnl->chnl_mgr_obj->open_channels -= 1;
343                 spin_unlock_bh(&pchnl->chnl_mgr_obj->chnl_mgr_lock);
344                 if (pchnl->ntfy_obj) {
345                         ntfy_delete(pchnl->ntfy_obj);
346                         kfree(pchnl->ntfy_obj);
347                         pchnl->ntfy_obj = NULL;
348                 }
349                 /* Reset channel event: (NOTE: user_event freed in user
350                  * context.). */
351                 if (pchnl->sync_event) {
352                         sync_reset_event(pchnl->sync_event);
353                         kfree(pchnl->sync_event);
354                         pchnl->sync_event = NULL;
355                 }
356                 /* Free I/O request and I/O completion queues: */
357                 if (pchnl->pio_completions) {
358                         free_chirp_list(pchnl->pio_completions);
359                         pchnl->pio_completions = NULL;
360                         pchnl->cio_cs = 0;
361                 }
362                 if (pchnl->pio_requests) {
363                         free_chirp_list(pchnl->pio_requests);
364                         pchnl->pio_requests = NULL;
365                         pchnl->cio_reqs = 0;
366                 }
367                 if (pchnl->free_packets_list) {
368                         free_chirp_list(pchnl->free_packets_list);
369                         pchnl->free_packets_list = NULL;
370                 }
371                 /* Release channel object. */
372                 kfree(pchnl);
373                 pchnl = NULL;
374         }
375         DBC_ENSURE(status || !pchnl);
376         return status;
377 }
378
379 /*
380  *  ======== bridge_chnl_create ========
381  *      Create a channel manager object, responsible for opening new channels
382  *      and closing old ones for a given board.
383  */
384 int bridge_chnl_create(struct chnl_mgr **channel_mgr,
385                               struct dev_object *hdev_obj,
386                               const struct chnl_mgrattrs *mgr_attrts)
387 {
388         int status = 0;
389         struct chnl_mgr *chnl_mgr_obj = NULL;
390         u8 max_channels;
391
392         /* Check DBC requirements: */
393         DBC_REQUIRE(channel_mgr != NULL);
394         DBC_REQUIRE(mgr_attrts != NULL);
395         DBC_REQUIRE(mgr_attrts->max_channels > 0);
396         DBC_REQUIRE(mgr_attrts->max_channels <= CHNL_MAXCHANNELS);
397         DBC_REQUIRE(mgr_attrts->word_size != 0);
398
399         /* Allocate channel manager object */
400         chnl_mgr_obj = kzalloc(sizeof(struct chnl_mgr), GFP_KERNEL);
401         if (chnl_mgr_obj) {
402                 /*
403                  * The max_channels attr must equal the # of supported chnls for
404                  * each transport(# chnls for PCPY = DDMA = ZCPY): i.e.
405                  *      mgr_attrts->max_channels = CHNL_MAXCHANNELS =
406                  *                       DDMA_MAXDDMACHNLS = DDMA_MAXZCPYCHNLS.
407                  */
408                 DBC_ASSERT(mgr_attrts->max_channels == CHNL_MAXCHANNELS);
409                 max_channels = CHNL_MAXCHANNELS + CHNL_MAXCHANNELS * CHNL_PCPY;
410                 /* Create array of channels */
411                 chnl_mgr_obj->ap_channel = kzalloc(sizeof(struct chnl_object *)
412                                                 * max_channels, GFP_KERNEL);
413                 if (chnl_mgr_obj->ap_channel) {
414                         /* Initialize chnl_mgr object */
415                         chnl_mgr_obj->dw_type = CHNL_TYPESM;
416                         chnl_mgr_obj->word_size = mgr_attrts->word_size;
417                         /* Total # chnls supported */
418                         chnl_mgr_obj->max_channels = max_channels;
419                         chnl_mgr_obj->open_channels = 0;
420                         chnl_mgr_obj->dw_output_mask = 0;
421                         chnl_mgr_obj->dw_last_output = 0;
422                         chnl_mgr_obj->hdev_obj = hdev_obj;
423                         spin_lock_init(&chnl_mgr_obj->chnl_mgr_lock);
424                 } else {
425                         status = -ENOMEM;
426                 }
427         } else {
428                 status = -ENOMEM;
429         }
430
431         if (status) {
432                 bridge_chnl_destroy(chnl_mgr_obj);
433                 *channel_mgr = NULL;
434         } else {
435                 /* Return channel manager object to caller... */
436                 *channel_mgr = chnl_mgr_obj;
437         }
438         return status;
439 }
440
441 /*
442  *  ======== bridge_chnl_destroy ========
443  *  Purpose:
444  *      Close all open channels, and destroy the channel manager.
445  */
446 int bridge_chnl_destroy(struct chnl_mgr *hchnl_mgr)
447 {
448         int status = 0;
449         struct chnl_mgr *chnl_mgr_obj = hchnl_mgr;
450         u32 chnl_id;
451
452         if (hchnl_mgr) {
453                 /* Close all open channels: */
454                 for (chnl_id = 0; chnl_id < chnl_mgr_obj->max_channels;
455                      chnl_id++) {
456                         status =
457                             bridge_chnl_close(chnl_mgr_obj->ap_channel
458                                               [chnl_id]);
459                         if (status)
460                                 dev_dbg(bridge, "%s: Error status 0x%x\n",
461                                         __func__, status);
462                 }
463
464                 /* Free channel manager object: */
465                 kfree(chnl_mgr_obj->ap_channel);
466
467                 /* Set hchnl_mgr to NULL in device object. */
468                 dev_set_chnl_mgr(chnl_mgr_obj->hdev_obj, NULL);
469                 /* Free this Chnl Mgr object: */
470                 kfree(hchnl_mgr);
471         } else {
472                 status = -EFAULT;
473         }
474         return status;
475 }
476
477 /*
478  *  ======== bridge_chnl_flush_io ========
479  *  purpose:
480  *      Flushes all the outstanding data requests on a channel.
481  */
482 int bridge_chnl_flush_io(struct chnl_object *chnl_obj, u32 timeout)
483 {
484         int status = 0;
485         struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
486         s8 chnl_mode = -1;
487         struct chnl_mgr *chnl_mgr_obj;
488         struct chnl_ioc chnl_ioc_obj;
489         /* Check args: */
490         if (pchnl) {
491                 if ((timeout == CHNL_IOCNOWAIT)
492                     && CHNL_IS_OUTPUT(pchnl->chnl_mode)) {
493                         status = -EINVAL;
494                 } else {
495                         chnl_mode = pchnl->chnl_mode;
496                         chnl_mgr_obj = pchnl->chnl_mgr_obj;
497                 }
498         } else {
499                 status = -EFAULT;
500         }
501         if (!status) {
502                 /* Note: Currently, if another thread continues to add IO
503                  * requests to this channel, this function will continue to
504                  * flush all such queued IO requests. */
505                 if (CHNL_IS_OUTPUT(chnl_mode)
506                     && (pchnl->chnl_type == CHNL_PCPY)) {
507                         /* Wait for IO completions, up to the specified
508                          * timeout: */
509                         while (!LST_IS_EMPTY(pchnl->pio_requests) && !status) {
510                                 status = bridge_chnl_get_ioc(chnl_obj,
511                                                 timeout, &chnl_ioc_obj);
512                                 if (status)
513                                         continue;
514
515                                 if (chnl_ioc_obj.status & CHNL_IOCSTATTIMEOUT)
516                                         status = -ETIMEDOUT;
517
518                         }
519                 } else {
520                         status = bridge_chnl_cancel_io(chnl_obj);
521                         /* Now, leave the channel in the ready state: */
522                         pchnl->dw_state &= ~CHNL_STATECANCEL;
523                 }
524         }
525         DBC_ENSURE(status || LST_IS_EMPTY(pchnl->pio_requests));
526         return status;
527 }
528
529 /*
530  *  ======== bridge_chnl_get_info ========
531  *  Purpose:
532  *      Retrieve information related to a channel.
533  */
534 int bridge_chnl_get_info(struct chnl_object *chnl_obj,
535                              struct chnl_info *channel_info)
536 {
537         int status = 0;
538         struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
539         if (channel_info != NULL) {
540                 if (pchnl) {
541                         /* Return the requested information: */
542                         channel_info->hchnl_mgr = pchnl->chnl_mgr_obj;
543                         channel_info->event_obj = pchnl->user_event;
544                         channel_info->cnhl_id = pchnl->chnl_id;
545                         channel_info->dw_mode = pchnl->chnl_mode;
546                         channel_info->bytes_tx = pchnl->bytes_moved;
547                         channel_info->process = pchnl->process;
548                         channel_info->sync_event = pchnl->sync_event;
549                         channel_info->cio_cs = pchnl->cio_cs;
550                         channel_info->cio_reqs = pchnl->cio_reqs;
551                         channel_info->dw_state = pchnl->dw_state;
552                 } else {
553                         status = -EFAULT;
554                 }
555         } else {
556                 status = -EFAULT;
557         }
558         return status;
559 }
560
561 /*
562  *  ======== bridge_chnl_get_ioc ========
563  *      Optionally wait for I/O completion on a channel.  Dequeue an I/O
564  *      completion record, which contains information about the completed
565  *      I/O request.
566  *      Note: Ensures Channel Invariant (see notes above).
567  */
568 int bridge_chnl_get_ioc(struct chnl_object *chnl_obj, u32 timeout,
569                             struct chnl_ioc *chan_ioc)
570 {
571         int status = 0;
572         struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
573         struct chnl_irp *chnl_packet_obj;
574         int stat_sync;
575         bool dequeue_ioc = true;
576         struct chnl_ioc ioc = { NULL, 0, 0, 0, 0 };
577         u8 *host_sys_buf = NULL;
578         struct bridge_dev_context *dev_ctxt;
579         struct dev_object *dev_obj;
580
581         /* Check args: */
582         if (!chan_ioc || !pchnl) {
583                 status = -EFAULT;
584         } else if (timeout == CHNL_IOCNOWAIT) {
585                 if (LST_IS_EMPTY(pchnl->pio_completions))
586                         status = -EREMOTEIO;
587
588         }
589
590         dev_obj = dev_get_first();
591         dev_get_bridge_context(dev_obj, &dev_ctxt);
592         if (!dev_ctxt)
593                 status = -EFAULT;
594
595         if (status)
596                 goto func_end;
597
598         ioc.status = CHNL_IOCSTATCOMPLETE;
599         if (timeout !=
600             CHNL_IOCNOWAIT && LST_IS_EMPTY(pchnl->pio_completions)) {
601                 if (timeout == CHNL_IOCINFINITE)
602                         timeout = SYNC_INFINITE;
603
604                 stat_sync = sync_wait_on_event(pchnl->sync_event, timeout);
605                 if (stat_sync == -ETIME) {
606                         /* No response from DSP */
607                         ioc.status |= CHNL_IOCSTATTIMEOUT;
608                         dequeue_ioc = false;
609                 } else if (stat_sync == -EPERM) {
610                         /* This can occur when the user mode thread is
611                          * aborted (^C), or when _VWIN32_WaitSingleObject()
612                          * fails due to unkown causes. */
613                         /* Even though Wait failed, there may be something in
614                          * the Q: */
615                         if (LST_IS_EMPTY(pchnl->pio_completions)) {
616                                 ioc.status |= CHNL_IOCSTATCANCEL;
617                                 dequeue_ioc = false;
618                         }
619                 }
620         }
621         /* See comment in AddIOReq */
622         spin_lock_bh(&pchnl->chnl_mgr_obj->chnl_mgr_lock);
623         omap_mbox_disable_irq(dev_ctxt->mbox, IRQ_RX);
624         if (dequeue_ioc) {
625                 /* Dequeue IOC and set chan_ioc; */
626                 DBC_ASSERT(!LST_IS_EMPTY(pchnl->pio_completions));
627                 chnl_packet_obj =
628                     (struct chnl_irp *)lst_get_head(pchnl->pio_completions);
629                 /* Update chan_ioc from channel state and chirp: */
630                 if (chnl_packet_obj) {
631                         pchnl->cio_cs--;
632                         /*  If this is a zero-copy channel, then set IOC's pbuf
633                          *  to the DSP's address. This DSP address will get
634                          *  translated to user's virtual addr later. */
635                         {
636                                 host_sys_buf = chnl_packet_obj->host_sys_buf;
637                                 ioc.pbuf = chnl_packet_obj->host_user_buf;
638                         }
639                         ioc.byte_size = chnl_packet_obj->byte_size;
640                         ioc.buf_size = chnl_packet_obj->buf_size;
641                         ioc.dw_arg = chnl_packet_obj->dw_arg;
642                         ioc.status |= chnl_packet_obj->status;
643                         /* Place the used chirp on the free list: */
644                         lst_put_tail(pchnl->free_packets_list,
645                                      (struct list_head *)chnl_packet_obj);
646                 } else {
647                         ioc.pbuf = NULL;
648                         ioc.byte_size = 0;
649                 }
650         } else {
651                 ioc.pbuf = NULL;
652                 ioc.byte_size = 0;
653                 ioc.dw_arg = 0;
654                 ioc.buf_size = 0;
655         }
656         /* Ensure invariant: If any IOC's are queued for this channel... */
657         if (!LST_IS_EMPTY(pchnl->pio_completions)) {
658                 /*  Since DSPStream_Reclaim() does not take a timeout
659                  *  parameter, we pass the stream's timeout value to
660                  *  bridge_chnl_get_ioc. We cannot determine whether or not
661                  *  we have waited in User mode. Since the stream's timeout
662                  *  value may be non-zero, we still have to set the event.
663                  *  Therefore, this optimization is taken out.
664                  *
665                  *  if (timeout == CHNL_IOCNOWAIT) {
666                  *    ... ensure event is set..
667                  *      sync_set_event(pchnl->sync_event);
668                  *  } */
669                 sync_set_event(pchnl->sync_event);
670         } else {
671                 /* else, if list is empty, ensure event is reset. */
672                 sync_reset_event(pchnl->sync_event);
673         }
674         omap_mbox_enable_irq(dev_ctxt->mbox, IRQ_RX);
675         spin_unlock_bh(&pchnl->chnl_mgr_obj->chnl_mgr_lock);
676         if (dequeue_ioc
677             && (pchnl->chnl_type == CHNL_PCPY && pchnl->chnl_id > 1)) {
678                 if (!(ioc.pbuf < (void *)USERMODE_ADDR))
679                         goto func_cont;
680
681                 /* If the addr is in user mode, then copy it */
682                 if (!host_sys_buf || !ioc.pbuf) {
683                         status = -EFAULT;
684                         goto func_cont;
685                 }
686                 if (!CHNL_IS_INPUT(pchnl->chnl_mode))
687                         goto func_cont1;
688
689                 /*host_user_buf */
690                 status = copy_to_user(ioc.pbuf, host_sys_buf, ioc.byte_size);
691                 if (status) {
692                         if (current->flags & PF_EXITING)
693                                 status = 0;
694                 }
695                 if (status)
696                         status = -EFAULT;
697 func_cont1:
698                 kfree(host_sys_buf);
699         }
700 func_cont:
701         /* Update User's IOC block: */
702         *chan_ioc = ioc;
703 func_end:
704         return status;
705 }
706
707 /*
708  *  ======== bridge_chnl_get_mgr_info ========
709  *      Retrieve information related to the channel manager.
710  */
711 int bridge_chnl_get_mgr_info(struct chnl_mgr *hchnl_mgr, u32 ch_id,
712                                  struct chnl_mgrinfo *mgr_info)
713 {
714         int status = 0;
715         struct chnl_mgr *chnl_mgr_obj = (struct chnl_mgr *)hchnl_mgr;
716
717         if (mgr_info != NULL) {
718                 if (ch_id <= CHNL_MAXCHANNELS) {
719                         if (hchnl_mgr) {
720                                 /* Return the requested information: */
721                                 mgr_info->chnl_obj =
722                                     chnl_mgr_obj->ap_channel[ch_id];
723                                 mgr_info->open_channels =
724                                     chnl_mgr_obj->open_channels;
725                                 mgr_info->dw_type = chnl_mgr_obj->dw_type;
726                                 /* total # of chnls */
727                                 mgr_info->max_channels =
728                                     chnl_mgr_obj->max_channels;
729                         } else {
730                                 status = -EFAULT;
731                         }
732                 } else {
733                         status = -ECHRNG;
734                 }
735         } else {
736                 status = -EFAULT;
737         }
738
739         return status;
740 }
741
742 /*
743  *  ======== bridge_chnl_idle ========
744  *      Idles a particular channel.
745  */
746 int bridge_chnl_idle(struct chnl_object *chnl_obj, u32 timeout,
747                             bool flush_data)
748 {
749         s8 chnl_mode;
750         struct chnl_mgr *chnl_mgr_obj;
751         int status = 0;
752
753         DBC_REQUIRE(chnl_obj);
754
755         chnl_mode = chnl_obj->chnl_mode;
756         chnl_mgr_obj = chnl_obj->chnl_mgr_obj;
757
758         if (CHNL_IS_OUTPUT(chnl_mode) && !flush_data) {
759                 /* Wait for IO completions, up to the specified timeout: */
760                 status = bridge_chnl_flush_io(chnl_obj, timeout);
761         } else {
762                 status = bridge_chnl_cancel_io(chnl_obj);
763
764                 /* Reset the byte count and put channel back in ready state. */
765                 chnl_obj->bytes_moved = 0;
766                 chnl_obj->dw_state &= ~CHNL_STATECANCEL;
767         }
768
769         return status;
770 }
771
772 /*
773  *  ======== bridge_chnl_open ========
774  *      Open a new half-duplex channel to the DSP board.
775  */
776 int bridge_chnl_open(struct chnl_object **chnl,
777                             struct chnl_mgr *hchnl_mgr, s8 chnl_mode,
778                             u32 ch_id, const struct chnl_attr *pattrs)
779 {
780         int status = 0;
781         struct chnl_mgr *chnl_mgr_obj = hchnl_mgr;
782         struct chnl_object *pchnl = NULL;
783         struct sync_object *sync_event = NULL;
784         /* Ensure DBC requirements: */
785         DBC_REQUIRE(chnl != NULL);
786         DBC_REQUIRE(pattrs != NULL);
787         DBC_REQUIRE(hchnl_mgr != NULL);
788         *chnl = NULL;
789         /* Validate Args: */
790         if (pattrs->uio_reqs == 0) {
791                 status = -EINVAL;
792         } else {
793                 if (!hchnl_mgr) {
794                         status = -EFAULT;
795                 } else {
796                         if (ch_id != CHNL_PICKFREE) {
797                                 if (ch_id >= chnl_mgr_obj->max_channels)
798                                         status = -ECHRNG;
799                                 else if (chnl_mgr_obj->ap_channel[ch_id] !=
800                                          NULL)
801                                         status = -EALREADY;
802                         } else {
803                                 /* Check for free channel */
804                                 status =
805                                     search_free_channel(chnl_mgr_obj, &ch_id);
806                         }
807                 }
808         }
809         if (status)
810                 goto func_end;
811
812         DBC_ASSERT(ch_id < chnl_mgr_obj->max_channels);
813         /* Create channel object: */
814         pchnl = kzalloc(sizeof(struct chnl_object), GFP_KERNEL);
815         if (!pchnl) {
816                 status = -ENOMEM;
817                 goto func_end;
818         }
819         /* Protect queues from io_dpc: */
820         pchnl->dw_state = CHNL_STATECANCEL;
821         /* Allocate initial IOR and IOC queues: */
822         pchnl->free_packets_list = create_chirp_list(pattrs->uio_reqs);
823         pchnl->pio_requests = create_chirp_list(0);
824         pchnl->pio_completions = create_chirp_list(0);
825         pchnl->chnl_packets = pattrs->uio_reqs;
826         pchnl->cio_cs = 0;
827         pchnl->cio_reqs = 0;
828         sync_event = kzalloc(sizeof(struct sync_object), GFP_KERNEL);
829         if (sync_event)
830                 sync_init_event(sync_event);
831         else
832                 status = -ENOMEM;
833
834         if (!status) {
835                 pchnl->ntfy_obj = kmalloc(sizeof(struct ntfy_object),
836                                                         GFP_KERNEL);
837                 if (pchnl->ntfy_obj)
838                         ntfy_init(pchnl->ntfy_obj);
839                 else
840                         status = -ENOMEM;
841         }
842
843         if (!status) {
844                 if (pchnl->pio_completions && pchnl->pio_requests &&
845                     pchnl->free_packets_list) {
846                         /* Initialize CHNL object fields: */
847                         pchnl->chnl_mgr_obj = chnl_mgr_obj;
848                         pchnl->chnl_id = ch_id;
849                         pchnl->chnl_mode = chnl_mode;
850                         pchnl->user_event = sync_event;
851                         pchnl->sync_event = sync_event;
852                         /* Get the process handle */
853                         pchnl->process = current->tgid;
854                         pchnl->pcb_arg = 0;
855                         pchnl->bytes_moved = 0;
856                         /* Default to proc-copy */
857                         pchnl->chnl_type = CHNL_PCPY;
858                 } else {
859                         status = -ENOMEM;
860                 }
861         }
862
863         if (status) {
864                 /* Free memory */
865                 if (pchnl->pio_completions) {
866                         free_chirp_list(pchnl->pio_completions);
867                         pchnl->pio_completions = NULL;
868                         pchnl->cio_cs = 0;
869                 }
870                 if (pchnl->pio_requests) {
871                         free_chirp_list(pchnl->pio_requests);
872                         pchnl->pio_requests = NULL;
873                 }
874                 if (pchnl->free_packets_list) {
875                         free_chirp_list(pchnl->free_packets_list);
876                         pchnl->free_packets_list = NULL;
877                 }
878                 kfree(sync_event);
879                 sync_event = NULL;
880
881                 if (pchnl->ntfy_obj) {
882                         ntfy_delete(pchnl->ntfy_obj);
883                         kfree(pchnl->ntfy_obj);
884                         pchnl->ntfy_obj = NULL;
885                 }
886                 kfree(pchnl);
887         } else {
888                 /* Insert channel object in channel manager: */
889                 chnl_mgr_obj->ap_channel[pchnl->chnl_id] = pchnl;
890                 spin_lock_bh(&chnl_mgr_obj->chnl_mgr_lock);
891                 chnl_mgr_obj->open_channels++;
892                 spin_unlock_bh(&chnl_mgr_obj->chnl_mgr_lock);
893                 /* Return result... */
894                 pchnl->dw_state = CHNL_STATEREADY;
895                 *chnl = pchnl;
896         }
897 func_end:
898         DBC_ENSURE((!status && pchnl) || (*chnl == NULL));
899         return status;
900 }
901
902 /*
903  *  ======== bridge_chnl_register_notify ========
904  *      Registers for events on a particular channel.
905  */
906 int bridge_chnl_register_notify(struct chnl_object *chnl_obj,
907                                     u32 event_mask, u32 notify_type,
908                                     struct dsp_notification *hnotification)
909 {
910         int status = 0;
911
912         DBC_ASSERT(!(event_mask & ~(DSP_STREAMDONE | DSP_STREAMIOCOMPLETION)));
913
914         if (event_mask)
915                 status = ntfy_register(chnl_obj->ntfy_obj, hnotification,
916                                                 event_mask, notify_type);
917         else
918                 status = ntfy_unregister(chnl_obj->ntfy_obj, hnotification);
919
920         return status;
921 }
922
923 /*
924  *  ======== create_chirp_list ========
925  *  Purpose:
926  *      Initialize a queue of channel I/O Request/Completion packets.
927  *  Parameters:
928  *      chirps:     Number of Chirps to allocate.
929  *  Returns:
930  *      Pointer to queue of IRPs, or NULL.
931  *  Requires:
932  *  Ensures:
933  */
934 static struct lst_list *create_chirp_list(u32 chirps)
935 {
936         struct lst_list *chirp_list;
937         struct chnl_irp *chnl_packet_obj;
938         u32 i;
939
940         chirp_list = kzalloc(sizeof(struct lst_list), GFP_KERNEL);
941
942         if (chirp_list) {
943                 INIT_LIST_HEAD(&chirp_list->head);
944                 /* Make N chirps and place on queue. */
945                 for (i = 0; (i < chirps)
946                      && ((chnl_packet_obj = make_new_chirp()) != NULL); i++) {
947                         lst_put_tail(chirp_list,
948                                      (struct list_head *)chnl_packet_obj);
949                 }
950
951                 /* If we couldn't allocate all chirps, free those allocated: */
952                 if (i != chirps) {
953                         free_chirp_list(chirp_list);
954                         chirp_list = NULL;
955                 }
956         }
957
958         return chirp_list;
959 }
960
961 /*
962  *  ======== free_chirp_list ========
963  *  Purpose:
964  *      Free the queue of Chirps.
965  */
966 static void free_chirp_list(struct lst_list *chirp_list)
967 {
968         DBC_REQUIRE(chirp_list != NULL);
969
970         while (!LST_IS_EMPTY(chirp_list))
971                 kfree(lst_get_head(chirp_list));
972
973         kfree(chirp_list);
974 }
975
976 /*
977  *  ======== make_new_chirp ========
978  *      Allocate the memory for a new channel IRP.
979  */
980 static struct chnl_irp *make_new_chirp(void)
981 {
982         struct chnl_irp *chnl_packet_obj;
983
984         chnl_packet_obj = kzalloc(sizeof(struct chnl_irp), GFP_KERNEL);
985         if (chnl_packet_obj != NULL) {
986                 /* lst_init_elem only resets the list's member values. */
987                 lst_init_elem(&chnl_packet_obj->link);
988         }
989
990         return chnl_packet_obj;
991 }
992
993 /*
994  *  ======== search_free_channel ========
995  *      Search for a free channel slot in the array of channel pointers.
996  */
997 static int search_free_channel(struct chnl_mgr *chnl_mgr_obj,
998                                       u32 *chnl)
999 {
1000         int status = -ENOSR;
1001         u32 i;
1002
1003         DBC_REQUIRE(chnl_mgr_obj);
1004
1005         for (i = 0; i < chnl_mgr_obj->max_channels; i++) {
1006                 if (chnl_mgr_obj->ap_channel[i] == NULL) {
1007                         status = 0;
1008                         *chnl = i;
1009                         break;
1010                 }
1011         }
1012
1013         return status;
1014 }