13ca2365f2791edc678b9f53205861518584b947
[cascardo/linux.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  */
23
24 #include <linux/module.h>
25 #include <linux/interrupt.h>
26 #include <linux/device.h>
27 #include <linux/delay.h>
28
29 #include <plat/mailbox.h>
30
31 static struct omap_mbox *mboxes;
32 static DEFINE_RWLOCK(mboxes_lock);
33
34 /* Mailbox FIFO handle functions */
35 static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
36 {
37         return mbox->ops->fifo_read(mbox);
38 }
39 static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
40 {
41         mbox->ops->fifo_write(mbox, msg);
42 }
43 static inline int mbox_fifo_empty(struct omap_mbox *mbox)
44 {
45         return mbox->ops->fifo_empty(mbox);
46 }
47 static inline int mbox_fifo_full(struct omap_mbox *mbox)
48 {
49         return mbox->ops->fifo_full(mbox);
50 }
51
52 /* Mailbox IRQ handle functions */
53 static inline void enable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
54 {
55         mbox->ops->enable_irq(mbox, irq);
56 }
57 static inline void disable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
58 {
59         mbox->ops->disable_irq(mbox, irq);
60 }
61 static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
62 {
63         if (mbox->ops->ack_irq)
64                 mbox->ops->ack_irq(mbox, irq);
65 }
66 static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
67 {
68         return mbox->ops->is_irq(mbox, irq);
69 }
70
71 /*
72  * message sender
73  */
74 static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
75 {
76         int ret = 0, i = 1000;
77
78         while (mbox_fifo_full(mbox)) {
79                 if (mbox->ops->type == OMAP_MBOX_TYPE2)
80                         return -1;
81                 if (--i == 0)
82                         return -1;
83                 udelay(1);
84         }
85         mbox_fifo_write(mbox, msg);
86         return ret;
87 }
88
89 struct omap_msg_tx_data {
90         mbox_msg_t      msg;
91         void            *arg;
92 };
93
94 static void omap_msg_tx_end_io(struct request *rq, int error)
95 {
96         kfree(rq->special);
97         __blk_put_request(rq->q, rq);
98 }
99
100 int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg)
101 {
102         struct omap_msg_tx_data *tx_data;
103         struct request *rq;
104         struct request_queue *q = mbox->txq->queue;
105
106         tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC);
107         if (unlikely(!tx_data))
108                 return -ENOMEM;
109
110         rq = blk_get_request(q, WRITE, GFP_ATOMIC);
111         if (unlikely(!rq)) {
112                 kfree(tx_data);
113                 return -ENOMEM;
114         }
115
116         tx_data->msg = msg;
117         tx_data->arg = arg;
118         rq->end_io = omap_msg_tx_end_io;
119         blk_insert_request(q, rq, 0, tx_data);
120
121         schedule_work(&mbox->txq->work);
122         return 0;
123 }
124 EXPORT_SYMBOL(omap_mbox_msg_send);
125
126 static void mbox_tx_work(struct work_struct *work)
127 {
128         int ret;
129         struct request *rq;
130         struct omap_mbox_queue *mq = container_of(work,
131                                 struct omap_mbox_queue, work);
132         struct omap_mbox *mbox = mq->queue->queuedata;
133         struct request_queue *q = mbox->txq->queue;
134
135         while (1) {
136                 struct omap_msg_tx_data *tx_data;
137
138                 spin_lock(q->queue_lock);
139                 rq = blk_fetch_request(q);
140                 spin_unlock(q->queue_lock);
141
142                 if (!rq)
143                         break;
144
145                 tx_data = rq->special;
146
147                 ret = __mbox_msg_send(mbox, tx_data->msg);
148                 if (ret) {
149                         enable_mbox_irq(mbox, IRQ_TX);
150                         spin_lock(q->queue_lock);
151                         blk_requeue_request(q, rq);
152                         spin_unlock(q->queue_lock);
153                         return;
154                 }
155
156                 spin_lock(q->queue_lock);
157                 __blk_end_request_all(rq, 0);
158                 spin_unlock(q->queue_lock);
159         }
160 }
161
162 /*
163  * Message receiver(workqueue)
164  */
165 static void mbox_rx_work(struct work_struct *work)
166 {
167         struct omap_mbox_queue *mq =
168                         container_of(work, struct omap_mbox_queue, work);
169         struct omap_mbox *mbox = mq->queue->queuedata;
170         struct request_queue *q = mbox->rxq->queue;
171         struct request *rq;
172         mbox_msg_t msg;
173         unsigned long flags;
174
175         while (1) {
176                 spin_lock_irqsave(q->queue_lock, flags);
177                 rq = blk_fetch_request(q);
178                 spin_unlock_irqrestore(q->queue_lock, flags);
179                 if (!rq)
180                         break;
181
182                 msg = (mbox_msg_t)rq->special;
183                 blk_end_request_all(rq, 0);
184                 mbox->rxq->callback((void *)msg);
185         }
186 }
187
188 /*
189  * Mailbox interrupt handler
190  */
191 static void mbox_txq_fn(struct request_queue *q)
192 {
193 }
194
195 static void mbox_rxq_fn(struct request_queue *q)
196 {
197 }
198
199 static void __mbox_tx_interrupt(struct omap_mbox *mbox)
200 {
201         disable_mbox_irq(mbox, IRQ_TX);
202         ack_mbox_irq(mbox, IRQ_TX);
203         schedule_work(&mbox->txq->work);
204 }
205
206 static void __mbox_rx_interrupt(struct omap_mbox *mbox)
207 {
208         struct request *rq;
209         mbox_msg_t msg;
210         struct request_queue *q = mbox->rxq->queue;
211
212         disable_mbox_irq(mbox, IRQ_RX);
213
214         while (!mbox_fifo_empty(mbox)) {
215                 rq = blk_get_request(q, WRITE, GFP_ATOMIC);
216                 if (unlikely(!rq))
217                         goto nomem;
218
219                 msg = mbox_fifo_read(mbox);
220
221
222                 blk_insert_request(q, rq, 0, (void *)msg);
223                 if (mbox->ops->type == OMAP_MBOX_TYPE1)
224                         break;
225         }
226
227         /* no more messages in the fifo. clear IRQ source. */
228         ack_mbox_irq(mbox, IRQ_RX);
229         enable_mbox_irq(mbox, IRQ_RX);
230 nomem:
231         schedule_work(&mbox->rxq->work);
232 }
233
234 static irqreturn_t mbox_interrupt(int irq, void *p)
235 {
236         struct omap_mbox *mbox = p;
237
238         if (is_mbox_irq(mbox, IRQ_TX))
239                 __mbox_tx_interrupt(mbox);
240
241         if (is_mbox_irq(mbox, IRQ_RX))
242                 __mbox_rx_interrupt(mbox);
243
244         return IRQ_HANDLED;
245 }
246
247 static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
248                                         request_fn_proc *proc,
249                                         void (*work) (struct work_struct *))
250 {
251         struct request_queue *q;
252         struct omap_mbox_queue *mq;
253
254         mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL);
255         if (!mq)
256                 return NULL;
257
258         spin_lock_init(&mq->lock);
259
260         q = blk_init_queue(proc, &mq->lock);
261         if (!q)
262                 goto error;
263         q->queuedata = mbox;
264         mq->queue = q;
265
266         INIT_WORK(&mq->work, work);
267
268         return mq;
269 error:
270         kfree(mq);
271         return NULL;
272 }
273
274 static void mbox_queue_free(struct omap_mbox_queue *q)
275 {
276         blk_cleanup_queue(q->queue);
277         kfree(q);
278 }
279
280 static int omap_mbox_startup(struct omap_mbox *mbox)
281 {
282         int ret;
283         struct omap_mbox_queue *mq;
284
285         if (likely(mbox->ops->startup)) {
286                 ret = mbox->ops->startup(mbox);
287                 if (unlikely(ret))
288                         return ret;
289         }
290
291         ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED,
292                                 mbox->name, mbox);
293         if (unlikely(ret)) {
294                 printk(KERN_ERR
295                         "failed to register mailbox interrupt:%d\n", ret);
296                 goto fail_request_irq;
297         }
298
299         mq = mbox_queue_alloc(mbox, mbox_txq_fn, mbox_tx_work);
300         if (!mq) {
301                 ret = -ENOMEM;
302                 goto fail_alloc_txq;
303         }
304         mbox->txq = mq;
305
306         mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work);
307         if (!mq) {
308                 ret = -ENOMEM;
309                 goto fail_alloc_rxq;
310         }
311         mbox->rxq = mq;
312
313         return 0;
314
315  fail_alloc_rxq:
316         mbox_queue_free(mbox->txq);
317  fail_alloc_txq:
318         free_irq(mbox->irq, mbox);
319  fail_request_irq:
320         if (unlikely(mbox->ops->shutdown))
321                 mbox->ops->shutdown(mbox);
322
323         return ret;
324 }
325
326 static void omap_mbox_fini(struct omap_mbox *mbox)
327 {
328         mbox_queue_free(mbox->txq);
329         mbox_queue_free(mbox->rxq);
330
331         free_irq(mbox->irq, mbox);
332
333         if (unlikely(mbox->ops->shutdown))
334                 mbox->ops->shutdown(mbox);
335 }
336
337 static struct omap_mbox **find_mboxes(const char *name)
338 {
339         struct omap_mbox **p;
340
341         for (p = &mboxes; *p; p = &(*p)->next) {
342                 if (strcmp((*p)->name, name) == 0)
343                         break;
344         }
345
346         return p;
347 }
348
349 struct omap_mbox *omap_mbox_get(const char *name)
350 {
351         struct omap_mbox *mbox;
352         int ret;
353
354         read_lock(&mboxes_lock);
355         mbox = *(find_mboxes(name));
356         if (mbox == NULL) {
357                 read_unlock(&mboxes_lock);
358                 return ERR_PTR(-ENOENT);
359         }
360
361         read_unlock(&mboxes_lock);
362
363         ret = omap_mbox_startup(mbox);
364         if (ret)
365                 return ERR_PTR(-ENODEV);
366
367         return mbox;
368 }
369 EXPORT_SYMBOL(omap_mbox_get);
370
371 void omap_mbox_put(struct omap_mbox *mbox)
372 {
373         omap_mbox_fini(mbox);
374 }
375 EXPORT_SYMBOL(omap_mbox_put);
376
377 int omap_mbox_register(struct device *parent, struct omap_mbox *mbox)
378 {
379         int ret = 0;
380         struct omap_mbox **tmp;
381
382         if (!mbox)
383                 return -EINVAL;
384         if (mbox->next)
385                 return -EBUSY;
386
387         write_lock(&mboxes_lock);
388         tmp = find_mboxes(mbox->name);
389         if (*tmp) {
390                 ret = -EBUSY;
391                 write_unlock(&mboxes_lock);
392                 goto err_find;
393         }
394         *tmp = mbox;
395         write_unlock(&mboxes_lock);
396
397         return 0;
398
399 err_find:
400         return ret;
401 }
402 EXPORT_SYMBOL(omap_mbox_register);
403
404 int omap_mbox_unregister(struct omap_mbox *mbox)
405 {
406         struct omap_mbox **tmp;
407
408         write_lock(&mboxes_lock);
409         tmp = &mboxes;
410         while (*tmp) {
411                 if (mbox == *tmp) {
412                         *tmp = mbox->next;
413                         mbox->next = NULL;
414                         write_unlock(&mboxes_lock);
415                         return 0;
416                 }
417                 tmp = &(*tmp)->next;
418         }
419         write_unlock(&mboxes_lock);
420
421         return -EINVAL;
422 }
423 EXPORT_SYMBOL(omap_mbox_unregister);
424
425 static int __init omap_mbox_init(void)
426 {
427         return 0;
428 }
429 module_init(omap_mbox_init);
430
431 static void __exit omap_mbox_exit(void)
432 {
433 }
434 module_exit(omap_mbox_exit);
435
436 MODULE_LICENSE("GPL v2");
437 MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging");
438 MODULE_AUTHOR("Toshihiro Kobayashi and Hiroshi DOYU");