omap: mailbox: Add an API for flushing the FIFO
[sitara-epos/sitara-epos-kernel.git] / arch / arm / plat-omap / mailbox.c
1 /*
2  * OMAP mailbox driver
3  *
4  * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved.
5  *
6  * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * version 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA
21  *
22  */
24 #include <linux/interrupt.h>
25 #include <linux/spinlock.h>
26 #include <linux/mutex.h>
27 #include <linux/delay.h>
28 #include <linux/slab.h>
29 #include <linux/kfifo.h>
30 #include <linux/err.h>
31 #include <linux/notifier.h>
32 #include <linux/module.h>
34 #include <plat/mailbox.h>
36 static struct omap_mbox **mboxes;
38 static int mbox_configured;
39 static DEFINE_MUTEX(mbox_configured_lock);
41 static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE;
42 module_param(mbox_kfifo_size, uint, S_IRUGO);
43 MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)");
45 /* Mailbox FIFO handle functions */
46 static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
47 {
48         return mbox->ops->fifo_read(mbox);
49 }
50 static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
51 {
52         mbox->ops->fifo_write(mbox, msg);
53 }
54 static inline int mbox_fifo_empty(struct omap_mbox *mbox)
55 {
56         return mbox->ops->fifo_empty(mbox);
57 }
58 static inline int mbox_fifo_full(struct omap_mbox *mbox)
59 {
60         return mbox->ops->fifo_full(mbox);
61 }
62 static inline int mbox_fifo_needs_flush(struct omap_mbox *mbox)
63 {
64         return mbox->ops->fifo_needs_flush(mbox);
65 }
66 static inline mbox_msg_t mbox_fifo_readback(struct omap_mbox *mbox)
67 {
68         return mbox->ops->fifo_readback(mbox);
69 }
71 /* Mailbox IRQ handle functions */
72 static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
73 {
74         if (mbox->ops->ack_irq)
75                 mbox->ops->ack_irq(mbox, irq);
76 }
77 static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
78 {
79         return mbox->ops->is_irq(mbox, irq);
80 }
82 /*
83  * message sender
84  */
85 static int __mbox_poll_for_space(struct omap_mbox *mbox)
86 {
87         int ret = 0, i = 1000;
89         while (mbox_fifo_full(mbox)) {
90                 if (mbox->ops->type == OMAP_MBOX_TYPE2)
91                         return -1;
92                 if (--i == 0)
93                         return -1;
94                 udelay(1);
95         }
96         return ret;
97 }
99 int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
101         struct omap_mbox_queue *mq = mbox->txq;
102         int ret = 0, len;
104         spin_lock_bh(&mq->lock);
106         if (kfifo_avail(&mq->fifo) < sizeof(msg)) {
107                 ret = -ENOMEM;
108                 goto out;
109         }
111         if (kfifo_is_empty(&mq->fifo) && !__mbox_poll_for_space(mbox)) {
112                 mbox_fifo_write(mbox, msg);
113                 goto out;
114         }
116         len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
117         WARN_ON(len != sizeof(msg));
119         tasklet_schedule(&mbox->txq->tasklet);
121 out:
122         spin_unlock_bh(&mq->lock);
123         return ret;
125 EXPORT_SYMBOL(omap_mbox_msg_send);
127 /*
128  * Flush the Rx FIFO by reading back the messages
129  * Since the normal expectation is that the Rx will do the
130  * reading, add a debug message to indicate if we really flush
131  * returns the no. of messages read back
132  */
133 int omap_mbox_msg_rx_flush(struct omap_mbox *mbox)
135         int ret = 0;
136         mbox_msg_t msg;
138         while (!mbox_fifo_needs_flush(mbox)) {
139                 ret++;
140                 msg = mbox_fifo_readback(mbox);
141         }
142         if (!ret)
143                 pr_info("Flushed %s Rx FIFO by reading back\n", mbox->name);
145         return ret;
147 EXPORT_SYMBOL(omap_mbox_msg_rx_flush);
149 static void mbox_tx_tasklet(unsigned long tx_data)
151         struct omap_mbox *mbox = (struct omap_mbox *)tx_data;
152         struct omap_mbox_queue *mq = mbox->txq;
153         mbox_msg_t msg;
154         int ret;
156         while (kfifo_len(&mq->fifo)) {
157                 if (__mbox_poll_for_space(mbox)) {
158                         omap_mbox_enable_irq(mbox, IRQ_TX);
159                         break;
160                 }
162                 ret = kfifo_out(&mq->fifo, (unsigned char *)&msg,
163                                                                 sizeof(msg));
164                 WARN_ON(ret != sizeof(msg));
166                 mbox_fifo_write(mbox, msg);
167         }
170 /*
171  * Message receiver(workqueue)
172  */
173 static void mbox_rx_work(struct work_struct *work)
175         struct omap_mbox_queue *mq =
176                         container_of(work, struct omap_mbox_queue, work);
177         mbox_msg_t msg;
178         int len;
180         while (kfifo_len(&mq->fifo) >= sizeof(msg)) {
181                 len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
182                 WARN_ON(len != sizeof(msg));
184                 blocking_notifier_call_chain(&mq->mbox->notifier, len,
185                                                                 (void *)msg);
186                 spin_lock_irq(&mq->lock);
187                 if (mq->full) {
188                         mq->full = false;
189                         omap_mbox_enable_irq(mq->mbox, IRQ_RX);
190                 }
191                 spin_unlock_irq(&mq->lock);
192         }
195 /*
196  * Mailbox interrupt handler
197  */
198 static void __mbox_tx_interrupt(struct omap_mbox *mbox)
200         omap_mbox_disable_irq(mbox, IRQ_TX);
201         ack_mbox_irq(mbox, IRQ_TX);
202         tasklet_schedule(&mbox->txq->tasklet);
205 static void __mbox_rx_interrupt(struct omap_mbox *mbox)
207         struct omap_mbox_queue *mq = mbox->rxq;
208         mbox_msg_t msg;
209         int len;
211         while (!mbox_fifo_empty(mbox)) {
212                 if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) {
213                         omap_mbox_disable_irq(mbox, IRQ_RX);
214                         mq->full = true;
215                         goto nomem;
216                 }
218                 msg = mbox_fifo_read(mbox);
220                 len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
221                 WARN_ON(len != sizeof(msg));
223                 if (mbox->ops->type == OMAP_MBOX_TYPE1)
224                         break;
225         }
227         /* no more messages in the fifo. clear IRQ source. */
228         ack_mbox_irq(mbox, IRQ_RX);
229 nomem:
230         schedule_work(&mbox->rxq->work);
233 static irqreturn_t mbox_interrupt(int irq, void *p)
235         struct omap_mbox *mbox = p;
237         if (is_mbox_irq(mbox, IRQ_TX))
238                 __mbox_tx_interrupt(mbox);
240         if (is_mbox_irq(mbox, IRQ_RX))
241                 __mbox_rx_interrupt(mbox);
243         return IRQ_HANDLED;
246 static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
247                                         void (*work) (struct work_struct *),
248                                         void (*tasklet)(unsigned long))
250         struct omap_mbox_queue *mq;
252         mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL);
253         if (!mq)
254                 return NULL;
256         spin_lock_init(&mq->lock);
258         if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL))
259                 goto error;
261         if (work)
262                 INIT_WORK(&mq->work, work);
264         if (tasklet)
265                 tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox);
266         return mq;
267 error:
268         kfree(mq);
269         return NULL;
272 static void mbox_queue_free(struct omap_mbox_queue *q)
274         kfifo_free(&q->fifo);
275         kfree(q);
278 static int omap_mbox_startup(struct omap_mbox *mbox)
280         int ret = 0;
281         struct omap_mbox_queue *mq;
283         mutex_lock(&mbox_configured_lock);
284         if (!mbox_configured++) {
285                 if (likely(mbox->ops->startup)) {
286                         ret = mbox->ops->startup(mbox);
287                         if (unlikely(ret))
288                                 goto fail_startup;
289                 } else
290                         goto fail_startup;
291         }
293         if (!mbox->use_count++) {
294                 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
295                                                         mbox->name, mbox);
296                 if (unlikely(ret)) {
297                         pr_err("failed to register mailbox interrupt:%d\n",
298                                                                         ret);
299                         goto fail_request_irq;
300                 }
301                 mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
302                 if (!mq) {
303                         ret = -ENOMEM;
304                         goto fail_alloc_txq;
305                 }
306                 mbox->txq = mq;
308                 mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL);
309                 if (!mq) {
310                         ret = -ENOMEM;
311                         goto fail_alloc_rxq;
312                 }
313                 mbox->rxq = mq;
314                 mq->mbox = mbox;
315         }
316         mutex_unlock(&mbox_configured_lock);
317         return 0;
319 fail_alloc_rxq:
320         mbox_queue_free(mbox->txq);
321 fail_alloc_txq:
322         free_irq(mbox->irq, mbox);
323 fail_request_irq:
324         if (mbox->ops->shutdown)
325                 mbox->ops->shutdown(mbox);
326         mbox->use_count--;
327 fail_startup:
328         mbox_configured--;
329         mutex_unlock(&mbox_configured_lock);
330         return ret;
333 static void omap_mbox_fini(struct omap_mbox *mbox)
335         mutex_lock(&mbox_configured_lock);
337         if (!--mbox->use_count) {
338                 free_irq(mbox->irq, mbox);
339                 tasklet_kill(&mbox->txq->tasklet);
340         flush_work_sync(&mbox->rxq->work);
341                 mbox_queue_free(mbox->txq);
342                 mbox_queue_free(mbox->rxq);
343         }
345         if (likely(mbox->ops->shutdown)) {
346                 if (!--mbox_configured)
347                         mbox->ops->shutdown(mbox);
348         }
350         mutex_unlock(&mbox_configured_lock);
353 struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb)
355         struct omap_mbox *_mbox, *mbox = NULL;
356         int i, ret;
358         if (!mboxes)
359                 return ERR_PTR(-EINVAL);
361         for (i = 0; (_mbox = mboxes[i]); i++) {
362                 if (!strcmp(_mbox->name, name)) {
363                         mbox = _mbox;
364                         break;
365                 }
366         }
368         if (!mbox)
369                 return ERR_PTR(-ENOENT);
371         ret = omap_mbox_startup(mbox);
372         if (ret)
373                 return ERR_PTR(-ENODEV);
375         if (nb)
376                 blocking_notifier_chain_register(&mbox->notifier, nb);
378         return mbox;
380 EXPORT_SYMBOL(omap_mbox_get);
382 void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb)
384         blocking_notifier_chain_unregister(&mbox->notifier, nb);
385         omap_mbox_fini(mbox);
387 EXPORT_SYMBOL(omap_mbox_put);
389 static struct class omap_mbox_class = { .name = "mbox", };
391 int omap_mbox_register(struct device *parent, struct omap_mbox **list)
393         int ret;
394         int i;
396         mboxes = list;
397         if (!mboxes)
398                 return -EINVAL;
400         for (i = 0; mboxes[i]; i++) {
401                 struct omap_mbox *mbox = mboxes[i];
402                 mbox->dev = device_create(&omap_mbox_class,
403                                 parent, 0, mbox, "%s", mbox->name);
404                 if (IS_ERR(mbox->dev)) {
405                         ret = PTR_ERR(mbox->dev);
406                         goto err_out;
407                 }
409                 BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier);
410         }
411         return 0;
413 err_out:
414         while (i--)
415                 device_unregister(mboxes[i]->dev);
416         return ret;
418 EXPORT_SYMBOL(omap_mbox_register);
420 int omap_mbox_unregister(void)
422         int i;
424         if (!mboxes)
425                 return -EINVAL;
427         for (i = 0; mboxes[i]; i++)
428                 device_unregister(mboxes[i]->dev);
429         mboxes = NULL;
430         return 0;
432 EXPORT_SYMBOL(omap_mbox_unregister);
434 static int __init omap_mbox_init(void)
436         int err;
438         err = class_register(&omap_mbox_class);
439         if (err)
440                 return err;
442         /* kfifo size sanity check: alignment and minimal size */
443         mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t));
444         mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size,
445                                                         sizeof(mbox_msg_t));
447         return 0;
449 subsys_initcall(omap_mbox_init);
451 static void __exit omap_mbox_exit(void)
453         class_unregister(&omap_mbox_class);
455 module_exit(omap_mbox_exit);
457 MODULE_LICENSE("GPL v2");
458 MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging");
459 MODULE_AUTHOR("Toshihiro Kobayashi");
460 MODULE_AUTHOR("Hiroshi DOYU");