aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap/mailbox.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-omap/mailbox.c')
-rw-r--r--arch/arm/plat-omap/mailbox.c284
1 files changed, 51 insertions, 233 deletions
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
index 40424edae939..8e90633e4cb9 100644
--- a/arch/arm/plat-omap/mailbox.c
+++ b/arch/arm/plat-omap/mailbox.c
@@ -26,55 +26,12 @@
26#include <linux/device.h> 26#include <linux/device.h>
27#include <linux/delay.h> 27#include <linux/delay.h>
28 28
29#include <mach/mailbox.h> 29#include <plat/mailbox.h>
30
31static int enable_seq_bit;
32module_param(enable_seq_bit, bool, 0);
33MODULE_PARM_DESC(enable_seq_bit, "Enable sequence bit checking.");
34 30
35static struct omap_mbox *mboxes; 31static struct omap_mbox *mboxes;
36static DEFINE_RWLOCK(mboxes_lock); 32static DEFINE_RWLOCK(mboxes_lock);
37 33
38/* 34static int mbox_configured;
39 * Mailbox sequence bit API
40 */
41
42/* seq_rcv should be initialized with any value other than
43 * 0 and 1 << 31, to allow either value for the first
44 * message. */
45static inline void mbox_seq_init(struct omap_mbox *mbox)
46{
47 if (!enable_seq_bit)
48 return;
49
50 /* any value other than 0 and 1 << 31 */
51 mbox->seq_rcv = 0xffffffff;
52}
53
54static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg)
55{
56 if (!enable_seq_bit)
57 return;
58
59 /* add seq_snd to msg */
60 *msg = (*msg & 0x7fffffff) | mbox->seq_snd;
61 /* flip seq_snd */
62 mbox->seq_snd ^= 1 << 31;
63}
64
65static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg)
66{
67 mbox_msg_t seq;
68
69 if (!enable_seq_bit)
70 return 0;
71
72 seq = msg & (1 << 31);
73 if (seq == mbox->seq_rcv)
74 return -1;
75 mbox->seq_rcv = seq;
76 return 0;
77}
78 35
79/* Mailbox FIFO handle functions */ 36/* Mailbox FIFO handle functions */
80static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) 37static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
@@ -95,14 +52,6 @@ static inline int mbox_fifo_full(struct omap_mbox *mbox)
95} 52}
96 53
97/* Mailbox IRQ handle functions */ 54/* Mailbox IRQ handle functions */
98static inline void enable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
99{
100 mbox->ops->enable_irq(mbox, irq);
101}
102static inline void disable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
103{
104 mbox->ops->disable_irq(mbox, irq);
105}
106static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) 55static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
107{ 56{
108 if (mbox->ops->ack_irq) 57 if (mbox->ops->ack_irq)
@@ -113,17 +62,10 @@ static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
113 return mbox->ops->is_irq(mbox, irq); 62 return mbox->ops->is_irq(mbox, irq);
114} 63}
115 64
116/* Mailbox Sequence Bit function */
117void omap_mbox_init_seq(struct omap_mbox *mbox)
118{
119 mbox_seq_init(mbox);
120}
121EXPORT_SYMBOL(omap_mbox_init_seq);
122
123/* 65/*
124 * message sender 66 * message sender
125 */ 67 */
126static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg) 68static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
127{ 69{
128 int ret = 0, i = 1000; 70 int ret = 0, i = 1000;
129 71
@@ -134,89 +76,49 @@ static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg)
134 return -1; 76 return -1;
135 udelay(1); 77 udelay(1);
136 } 78 }
137
138 if (arg && mbox->txq->callback) {
139 ret = mbox->txq->callback(arg);
140 if (ret)
141 goto out;
142 }
143
144 mbox_seq_toggle(mbox, &msg);
145 mbox_fifo_write(mbox, msg); 79 mbox_fifo_write(mbox, msg);
146 out:
147 return ret; 80 return ret;
148} 81}
149 82
150struct omap_msg_tx_data {
151 mbox_msg_t msg;
152 void *arg;
153};
154 83
155static void omap_msg_tx_end_io(struct request *rq, int error) 84int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
156{ 85{
157 kfree(rq->special);
158 __blk_put_request(rq->q, rq);
159}
160 86
161int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg)
162{
163 struct omap_msg_tx_data *tx_data;
164 struct request *rq; 87 struct request *rq;
165 struct request_queue *q = mbox->txq->queue; 88 struct request_queue *q = mbox->txq->queue;
166 89
167 tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC);
168 if (unlikely(!tx_data))
169 return -ENOMEM;
170
171 rq = blk_get_request(q, WRITE, GFP_ATOMIC); 90 rq = blk_get_request(q, WRITE, GFP_ATOMIC);
172 if (unlikely(!rq)) { 91 if (unlikely(!rq))
173 kfree(tx_data);
174 return -ENOMEM; 92 return -ENOMEM;
175 }
176 93
177 tx_data->msg = msg; 94 blk_insert_request(q, rq, 0, (void *) msg);
178 tx_data->arg = arg; 95 tasklet_schedule(&mbox->txq->tasklet);
179 rq->end_io = omap_msg_tx_end_io;
180 blk_insert_request(q, rq, 0, tx_data);
181 96
182 schedule_work(&mbox->txq->work);
183 return 0; 97 return 0;
184} 98}
185EXPORT_SYMBOL(omap_mbox_msg_send); 99EXPORT_SYMBOL(omap_mbox_msg_send);
186 100
187static void mbox_tx_work(struct work_struct *work) 101static void mbox_tx_tasklet(unsigned long tx_data)
188{ 102{
189 int ret; 103 int ret;
190 struct request *rq; 104 struct request *rq;
191 struct omap_mbox_queue *mq = container_of(work, 105 struct omap_mbox *mbox = (struct omap_mbox *)tx_data;
192 struct omap_mbox_queue, work);
193 struct omap_mbox *mbox = mq->queue->queuedata;
194 struct request_queue *q = mbox->txq->queue; 106 struct request_queue *q = mbox->txq->queue;
195 107
196 while (1) { 108 while (1) {
197 struct omap_msg_tx_data *tx_data;
198 109
199 spin_lock(q->queue_lock);
200 rq = blk_fetch_request(q); 110 rq = blk_fetch_request(q);
201 spin_unlock(q->queue_lock);
202 111
203 if (!rq) 112 if (!rq)
204 break; 113 break;
205 114
206 tx_data = rq->special; 115 ret = __mbox_msg_send(mbox, (mbox_msg_t)rq->special);
207
208 ret = __mbox_msg_send(mbox, tx_data->msg, tx_data->arg);
209 if (ret) { 116 if (ret) {
210 enable_mbox_irq(mbox, IRQ_TX); 117 omap_mbox_enable_irq(mbox, IRQ_TX);
211 spin_lock(q->queue_lock);
212 blk_requeue_request(q, rq); 118 blk_requeue_request(q, rq);
213 spin_unlock(q->queue_lock);
214 return; 119 return;
215 } 120 }
216 121 blk_end_request_all(rq, 0);
217 spin_lock(q->queue_lock);
218 __blk_end_request_all(rq, 0);
219 spin_unlock(q->queue_lock);
220 } 122 }
221} 123}
222 124
@@ -233,11 +135,6 @@ static void mbox_rx_work(struct work_struct *work)
233 mbox_msg_t msg; 135 mbox_msg_t msg;
234 unsigned long flags; 136 unsigned long flags;
235 137
236 if (mbox->rxq->callback == NULL) {
237 sysfs_notify(&mbox->dev->kobj, NULL, "mbox");
238 return;
239 }
240
241 while (1) { 138 while (1) {
242 spin_lock_irqsave(q->queue_lock, flags); 139 spin_lock_irqsave(q->queue_lock, flags);
243 rq = blk_fetch_request(q); 140 rq = blk_fetch_request(q);
@@ -254,19 +151,19 @@ static void mbox_rx_work(struct work_struct *work)
254/* 151/*
255 * Mailbox interrupt handler 152 * Mailbox interrupt handler
256 */ 153 */
257static void mbox_txq_fn(struct request_queue * q) 154static void mbox_txq_fn(struct request_queue *q)
258{ 155{
259} 156}
260 157
261static void mbox_rxq_fn(struct request_queue * q) 158static void mbox_rxq_fn(struct request_queue *q)
262{ 159{
263} 160}
264 161
265static void __mbox_tx_interrupt(struct omap_mbox *mbox) 162static void __mbox_tx_interrupt(struct omap_mbox *mbox)
266{ 163{
267 disable_mbox_irq(mbox, IRQ_TX); 164 omap_mbox_disable_irq(mbox, IRQ_TX);
268 ack_mbox_irq(mbox, IRQ_TX); 165 ack_mbox_irq(mbox, IRQ_TX);
269 schedule_work(&mbox->txq->work); 166 tasklet_schedule(&mbox->txq->tasklet);
270} 167}
271 168
272static void __mbox_rx_interrupt(struct omap_mbox *mbox) 169static void __mbox_rx_interrupt(struct omap_mbox *mbox)
@@ -275,8 +172,6 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
275 mbox_msg_t msg; 172 mbox_msg_t msg;
276 struct request_queue *q = mbox->rxq->queue; 173 struct request_queue *q = mbox->rxq->queue;
277 174
278 disable_mbox_irq(mbox, IRQ_RX);
279
280 while (!mbox_fifo_empty(mbox)) { 175 while (!mbox_fifo_empty(mbox)) {
281 rq = blk_get_request(q, WRITE, GFP_ATOMIC); 176 rq = blk_get_request(q, WRITE, GFP_ATOMIC);
282 if (unlikely(!rq)) 177 if (unlikely(!rq))
@@ -284,11 +179,6 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
284 179
285 msg = mbox_fifo_read(mbox); 180 msg = mbox_fifo_read(mbox);
286 181
287 if (unlikely(mbox_seq_test(mbox, msg))) {
288 pr_info("mbox: Illegal seq bit!(%08x)\n", msg);
289 if (mbox->err_notify)
290 mbox->err_notify();
291 }
292 182
293 blk_insert_request(q, rq, 0, (void *)msg); 183 blk_insert_request(q, rq, 0, (void *)msg);
294 if (mbox->ops->type == OMAP_MBOX_TYPE1) 184 if (mbox->ops->type == OMAP_MBOX_TYPE1)
@@ -297,7 +187,6 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
297 187
298 /* no more messages in the fifo. clear IRQ source. */ 188 /* no more messages in the fifo. clear IRQ source. */
299 ack_mbox_irq(mbox, IRQ_RX); 189 ack_mbox_irq(mbox, IRQ_RX);
300 enable_mbox_irq(mbox, IRQ_RX);
301nomem: 190nomem:
302 schedule_work(&mbox->rxq->work); 191 schedule_work(&mbox->rxq->work);
303} 192}
@@ -315,76 +204,10 @@ static irqreturn_t mbox_interrupt(int irq, void *p)
315 return IRQ_HANDLED; 204 return IRQ_HANDLED;
316} 205}
317 206
318/*
319 * sysfs files
320 */
321static ssize_t
322omap_mbox_write(struct device *dev, struct device_attribute *attr,
323 const char * buf, size_t count)
324{
325 int ret;
326 mbox_msg_t *p = (mbox_msg_t *)buf;
327 struct omap_mbox *mbox = dev_get_drvdata(dev);
328
329 for (; count >= sizeof(mbox_msg_t); count -= sizeof(mbox_msg_t)) {
330 ret = omap_mbox_msg_send(mbox, be32_to_cpu(*p), NULL);
331 if (ret)
332 return -EAGAIN;
333 p++;
334 }
335
336 return (size_t)((char *)p - buf);
337}
338
339static ssize_t
340omap_mbox_read(struct device *dev, struct device_attribute *attr, char *buf)
341{
342 unsigned long flags;
343 struct request *rq;
344 mbox_msg_t *p = (mbox_msg_t *) buf;
345 struct omap_mbox *mbox = dev_get_drvdata(dev);
346 struct request_queue *q = mbox->rxq->queue;
347
348 while (1) {
349 spin_lock_irqsave(q->queue_lock, flags);
350 rq = blk_fetch_request(q);
351 spin_unlock_irqrestore(q->queue_lock, flags);
352
353 if (!rq)
354 break;
355
356 *p = (mbox_msg_t)rq->special;
357
358 blk_end_request_all(rq, 0);
359
360 if (unlikely(mbox_seq_test(mbox, *p))) {
361 pr_info("mbox: Illegal seq bit!(%08x) ignored\n", *p);
362 continue;
363 }
364 p++;
365 }
366
367 pr_debug("%02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
368
369 return (size_t) ((char *)p - buf);
370}
371
372static DEVICE_ATTR(mbox, S_IRUGO | S_IWUSR, omap_mbox_read, omap_mbox_write);
373
374static ssize_t mbox_show(struct class *class, char *buf)
375{
376 return sprintf(buf, "mbox");
377}
378
379static CLASS_ATTR(mbox, S_IRUGO, mbox_show, NULL);
380
381static struct class omap_mbox_class = {
382 .name = "omap-mailbox",
383};
384
385static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, 207static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
386 request_fn_proc * proc, 208 request_fn_proc *proc,
387 void (*work) (struct work_struct *)) 209 void (*work) (struct work_struct *),
210 void (*tasklet)(unsigned long))
388{ 211{
389 struct request_queue *q; 212 struct request_queue *q;
390 struct omap_mbox_queue *mq; 213 struct omap_mbox_queue *mq;
@@ -401,8 +224,11 @@ static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
401 q->queuedata = mbox; 224 q->queuedata = mbox;
402 mq->queue = q; 225 mq->queue = q;
403 226
404 INIT_WORK(&mq->work, work); 227 if (work)
228 INIT_WORK(&mq->work, work);
405 229
230 if (tasklet)
231 tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox);
406 return mq; 232 return mq;
407error: 233error:
408 kfree(mq); 234 kfree(mq);
@@ -415,18 +241,25 @@ static void mbox_queue_free(struct omap_mbox_queue *q)
415 kfree(q); 241 kfree(q);
416} 242}
417 243
418static int omap_mbox_init(struct omap_mbox *mbox) 244static int omap_mbox_startup(struct omap_mbox *mbox)
419{ 245{
420 int ret; 246 int ret = 0;
421 struct omap_mbox_queue *mq; 247 struct omap_mbox_queue *mq;
422 248
423 if (likely(mbox->ops->startup)) { 249 if (likely(mbox->ops->startup)) {
424 ret = mbox->ops->startup(mbox); 250 write_lock(&mboxes_lock);
425 if (unlikely(ret)) 251 if (!mbox_configured)
252 ret = mbox->ops->startup(mbox);
253
254 if (unlikely(ret)) {
255 write_unlock(&mboxes_lock);
426 return ret; 256 return ret;
257 }
258 mbox_configured++;
259 write_unlock(&mboxes_lock);
427 } 260 }
428 261
429 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED, 262 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
430 mbox->name, mbox); 263 mbox->name, mbox);
431 if (unlikely(ret)) { 264 if (unlikely(ret)) {
432 printk(KERN_ERR 265 printk(KERN_ERR
@@ -434,14 +267,14 @@ static int omap_mbox_init(struct omap_mbox *mbox)
434 goto fail_request_irq; 267 goto fail_request_irq;
435 } 268 }
436 269
437 mq = mbox_queue_alloc(mbox, mbox_txq_fn, mbox_tx_work); 270 mq = mbox_queue_alloc(mbox, mbox_txq_fn, NULL, mbox_tx_tasklet);
438 if (!mq) { 271 if (!mq) {
439 ret = -ENOMEM; 272 ret = -ENOMEM;
440 goto fail_alloc_txq; 273 goto fail_alloc_txq;
441 } 274 }
442 mbox->txq = mq; 275 mbox->txq = mq;
443 276
444 mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work); 277 mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work, NULL);
445 if (!mq) { 278 if (!mq) {
446 ret = -ENOMEM; 279 ret = -ENOMEM;
447 goto fail_alloc_rxq; 280 goto fail_alloc_rxq;
@@ -468,8 +301,14 @@ static void omap_mbox_fini(struct omap_mbox *mbox)
468 301
469 free_irq(mbox->irq, mbox); 302 free_irq(mbox->irq, mbox);
470 303
471 if (unlikely(mbox->ops->shutdown)) 304 if (unlikely(mbox->ops->shutdown)) {
472 mbox->ops->shutdown(mbox); 305 write_lock(&mboxes_lock);
306 if (mbox_configured > 0)
307 mbox_configured--;
308 if (!mbox_configured)
309 mbox->ops->shutdown(mbox);
310 write_unlock(&mboxes_lock);
311 }
473} 312}
474 313
475static struct omap_mbox **find_mboxes(const char *name) 314static struct omap_mbox **find_mboxes(const char *name)
@@ -498,7 +337,7 @@ struct omap_mbox *omap_mbox_get(const char *name)
498 337
499 read_unlock(&mboxes_lock); 338 read_unlock(&mboxes_lock);
500 339
501 ret = omap_mbox_init(mbox); 340 ret = omap_mbox_startup(mbox);
502 if (ret) 341 if (ret)
503 return ERR_PTR(-ENODEV); 342 return ERR_PTR(-ENODEV);
504 343
@@ -522,15 +361,6 @@ int omap_mbox_register(struct device *parent, struct omap_mbox *mbox)
522 if (mbox->next) 361 if (mbox->next)
523 return -EBUSY; 362 return -EBUSY;
524 363
525 mbox->dev = device_create(&omap_mbox_class,
526 parent, 0, mbox, "%s", mbox->name);
527 if (IS_ERR(mbox->dev))
528 return PTR_ERR(mbox->dev);
529
530 ret = device_create_file(mbox->dev, &dev_attr_mbox);
531 if (ret)
532 goto err_sysfs;
533
534 write_lock(&mboxes_lock); 364 write_lock(&mboxes_lock);
535 tmp = find_mboxes(mbox->name); 365 tmp = find_mboxes(mbox->name);
536 if (*tmp) { 366 if (*tmp) {
@@ -544,9 +374,6 @@ int omap_mbox_register(struct device *parent, struct omap_mbox *mbox)
544 return 0; 374 return 0;
545 375
546err_find: 376err_find:
547 device_remove_file(mbox->dev, &dev_attr_mbox);
548err_sysfs:
549 device_unregister(mbox->dev);
550 return ret; 377 return ret;
551} 378}
552EXPORT_SYMBOL(omap_mbox_register); 379EXPORT_SYMBOL(omap_mbox_register);
@@ -562,8 +389,6 @@ int omap_mbox_unregister(struct omap_mbox *mbox)
562 *tmp = mbox->next; 389 *tmp = mbox->next;
563 mbox->next = NULL; 390 mbox->next = NULL;
564 write_unlock(&mboxes_lock); 391 write_unlock(&mboxes_lock);
565 device_remove_file(mbox->dev, &dev_attr_mbox);
566 device_unregister(mbox->dev);
567 return 0; 392 return 0;
568 } 393 }
569 tmp = &(*tmp)->next; 394 tmp = &(*tmp)->next;
@@ -574,23 +399,16 @@ int omap_mbox_unregister(struct omap_mbox *mbox)
574} 399}
575EXPORT_SYMBOL(omap_mbox_unregister); 400EXPORT_SYMBOL(omap_mbox_unregister);
576 401
577static int __init omap_mbox_class_init(void) 402static int __init omap_mbox_init(void)
578{ 403{
579 int ret = class_register(&omap_mbox_class); 404 return 0;
580 if (!ret)
581 ret = class_create_file(&omap_mbox_class, &class_attr_mbox);
582
583 return ret;
584} 405}
406module_init(omap_mbox_init);
585 407
586static void __exit omap_mbox_class_exit(void) 408static void __exit omap_mbox_exit(void)
587{ 409{
588 class_remove_file(&omap_mbox_class, &class_attr_mbox);
589 class_unregister(&omap_mbox_class);
590} 410}
591 411module_exit(omap_mbox_exit);
592subsys_initcall(omap_mbox_class_init);
593module_exit(omap_mbox_class_exit);
594 412
595MODULE_LICENSE("GPL v2"); 413MODULE_LICENSE("GPL v2");
596MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging"); 414MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging");