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