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.c291
1 files changed, 58 insertions, 233 deletions
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
index 40424edae939..08a2df766289 100644
--- a/arch/arm/plat-omap/mailbox.c
+++ b/arch/arm/plat-omap/mailbox.c
@@ -25,56 +25,15 @@
25#include <linux/interrupt.h> 25#include <linux/interrupt.h>
26#include <linux/device.h> 26#include <linux/device.h>
27#include <linux/delay.h> 27#include <linux/delay.h>
28#include <linux/slab.h>
28 29
29#include <mach/mailbox.h> 30#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 31
32static struct workqueue_struct *mboxd;
35static struct omap_mbox *mboxes; 33static struct omap_mbox *mboxes;
36static DEFINE_RWLOCK(mboxes_lock); 34static DEFINE_RWLOCK(mboxes_lock);
37 35
38/* 36static 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 37
79/* Mailbox FIFO handle functions */ 38/* Mailbox FIFO handle functions */
80static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) 39static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
@@ -95,14 +54,6 @@ static inline int mbox_fifo_full(struct omap_mbox *mbox)
95} 54}
96 55
97/* Mailbox IRQ handle functions */ 56/* 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) 57static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
107{ 58{
108 if (mbox->ops->ack_irq) 59 if (mbox->ops->ack_irq)
@@ -113,17 +64,10 @@ static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
113 return mbox->ops->is_irq(mbox, irq); 64 return mbox->ops->is_irq(mbox, irq);
114} 65}
115 66
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/* 67/*
124 * message sender 68 * message sender
125 */ 69 */
126static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg) 70static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
127{ 71{
128 int ret = 0, i = 1000; 72 int ret = 0, i = 1000;
129 73
@@ -134,89 +78,49 @@ static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg)
134 return -1; 78 return -1;
135 udelay(1); 79 udelay(1);
136 } 80 }
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); 81 mbox_fifo_write(mbox, msg);
146 out:
147 return ret; 82 return ret;
148} 83}
149 84
150struct omap_msg_tx_data {
151 mbox_msg_t msg;
152 void *arg;
153};
154 85
155static void omap_msg_tx_end_io(struct request *rq, int error) 86int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
156{ 87{
157 kfree(rq->special);
158 __blk_put_request(rq->q, rq);
159}
160 88
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; 89 struct request *rq;
165 struct request_queue *q = mbox->txq->queue; 90 struct request_queue *q = mbox->txq->queue;
166 91
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); 92 rq = blk_get_request(q, WRITE, GFP_ATOMIC);
172 if (unlikely(!rq)) { 93 if (unlikely(!rq))
173 kfree(tx_data);
174 return -ENOMEM; 94 return -ENOMEM;
175 }
176 95
177 tx_data->msg = msg; 96 blk_insert_request(q, rq, 0, (void *) msg);
178 tx_data->arg = arg; 97 tasklet_schedule(&mbox->txq->tasklet);
179 rq->end_io = omap_msg_tx_end_io;
180 blk_insert_request(q, rq, 0, tx_data);
181 98
182 schedule_work(&mbox->txq->work);
183 return 0; 99 return 0;
184} 100}
185EXPORT_SYMBOL(omap_mbox_msg_send); 101EXPORT_SYMBOL(omap_mbox_msg_send);
186 102
187static void mbox_tx_work(struct work_struct *work) 103static void mbox_tx_tasklet(unsigned long tx_data)
188{ 104{
189 int ret; 105 int ret;
190 struct request *rq; 106 struct request *rq;
191 struct omap_mbox_queue *mq = container_of(work, 107 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; 108 struct request_queue *q = mbox->txq->queue;
195 109
196 while (1) { 110 while (1) {
197 struct omap_msg_tx_data *tx_data;
198 111
199 spin_lock(q->queue_lock);
200 rq = blk_fetch_request(q); 112 rq = blk_fetch_request(q);
201 spin_unlock(q->queue_lock);
202 113
203 if (!rq) 114 if (!rq)
204 break; 115 break;
205 116
206 tx_data = rq->special; 117 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) { 118 if (ret) {
210 enable_mbox_irq(mbox, IRQ_TX); 119 omap_mbox_enable_irq(mbox, IRQ_TX);
211 spin_lock(q->queue_lock);
212 blk_requeue_request(q, rq); 120 blk_requeue_request(q, rq);
213 spin_unlock(q->queue_lock);
214 return; 121 return;
215 } 122 }
216 123 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 } 124 }
221} 125}
222 126
@@ -233,11 +137,6 @@ static void mbox_rx_work(struct work_struct *work)
233 mbox_msg_t msg; 137 mbox_msg_t msg;
234 unsigned long flags; 138 unsigned long flags;
235 139
236 if (mbox->rxq->callback == NULL) {
237 sysfs_notify(&mbox->dev->kobj, NULL, "mbox");
238 return;
239 }
240
241 while (1) { 140 while (1) {
242 spin_lock_irqsave(q->queue_lock, flags); 141 spin_lock_irqsave(q->queue_lock, flags);
243 rq = blk_fetch_request(q); 142 rq = blk_fetch_request(q);
@@ -254,19 +153,19 @@ static void mbox_rx_work(struct work_struct *work)
254/* 153/*
255 * Mailbox interrupt handler 154 * Mailbox interrupt handler
256 */ 155 */
257static void mbox_txq_fn(struct request_queue * q) 156static void mbox_txq_fn(struct request_queue *q)
258{ 157{
259} 158}
260 159
261static void mbox_rxq_fn(struct request_queue * q) 160static void mbox_rxq_fn(struct request_queue *q)
262{ 161{
263} 162}
264 163
265static void __mbox_tx_interrupt(struct omap_mbox *mbox) 164static void __mbox_tx_interrupt(struct omap_mbox *mbox)
266{ 165{
267 disable_mbox_irq(mbox, IRQ_TX); 166 omap_mbox_disable_irq(mbox, IRQ_TX);
268 ack_mbox_irq(mbox, IRQ_TX); 167 ack_mbox_irq(mbox, IRQ_TX);
269 schedule_work(&mbox->txq->work); 168 tasklet_schedule(&mbox->txq->tasklet);
270} 169}
271 170
272static void __mbox_rx_interrupt(struct omap_mbox *mbox) 171static void __mbox_rx_interrupt(struct omap_mbox *mbox)
@@ -275,8 +174,6 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
275 mbox_msg_t msg; 174 mbox_msg_t msg;
276 struct request_queue *q = mbox->rxq->queue; 175 struct request_queue *q = mbox->rxq->queue;
277 176
278 disable_mbox_irq(mbox, IRQ_RX);
279
280 while (!mbox_fifo_empty(mbox)) { 177 while (!mbox_fifo_empty(mbox)) {
281 rq = blk_get_request(q, WRITE, GFP_ATOMIC); 178 rq = blk_get_request(q, WRITE, GFP_ATOMIC);
282 if (unlikely(!rq)) 179 if (unlikely(!rq))
@@ -284,11 +181,6 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
284 181
285 msg = mbox_fifo_read(mbox); 182 msg = mbox_fifo_read(mbox);
286 183
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 184
293 blk_insert_request(q, rq, 0, (void *)msg); 185 blk_insert_request(q, rq, 0, (void *)msg);
294 if (mbox->ops->type == OMAP_MBOX_TYPE1) 186 if (mbox->ops->type == OMAP_MBOX_TYPE1)
@@ -297,9 +189,8 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
297 189
298 /* no more messages in the fifo. clear IRQ source. */ 190 /* no more messages in the fifo. clear IRQ source. */
299 ack_mbox_irq(mbox, IRQ_RX); 191 ack_mbox_irq(mbox, IRQ_RX);
300 enable_mbox_irq(mbox, IRQ_RX);
301nomem: 192nomem:
302 schedule_work(&mbox->rxq->work); 193 queue_work(mboxd, &mbox->rxq->work);
303} 194}
304 195
305static irqreturn_t mbox_interrupt(int irq, void *p) 196static irqreturn_t mbox_interrupt(int irq, void *p)
@@ -315,76 +206,10 @@ static irqreturn_t mbox_interrupt(int irq, void *p)
315 return IRQ_HANDLED; 206 return IRQ_HANDLED;
316} 207}
317 208
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, 209static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
386 request_fn_proc * proc, 210 request_fn_proc *proc,
387 void (*work) (struct work_struct *)) 211 void (*work) (struct work_struct *),
212 void (*tasklet)(unsigned long))
388{ 213{
389 struct request_queue *q; 214 struct request_queue *q;
390 struct omap_mbox_queue *mq; 215 struct omap_mbox_queue *mq;
@@ -401,8 +226,11 @@ static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
401 q->queuedata = mbox; 226 q->queuedata = mbox;
402 mq->queue = q; 227 mq->queue = q;
403 228
404 INIT_WORK(&mq->work, work); 229 if (work)
230 INIT_WORK(&mq->work, work);
405 231
232 if (tasklet)
233 tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox);
406 return mq; 234 return mq;
407error: 235error:
408 kfree(mq); 236 kfree(mq);
@@ -415,18 +243,25 @@ static void mbox_queue_free(struct omap_mbox_queue *q)
415 kfree(q); 243 kfree(q);
416} 244}
417 245
418static int omap_mbox_init(struct omap_mbox *mbox) 246static int omap_mbox_startup(struct omap_mbox *mbox)
419{ 247{
420 int ret; 248 int ret = 0;
421 struct omap_mbox_queue *mq; 249 struct omap_mbox_queue *mq;
422 250
423 if (likely(mbox->ops->startup)) { 251 if (likely(mbox->ops->startup)) {
424 ret = mbox->ops->startup(mbox); 252 write_lock(&mboxes_lock);
425 if (unlikely(ret)) 253 if (!mbox_configured)
254 ret = mbox->ops->startup(mbox);
255
256 if (unlikely(ret)) {
257 write_unlock(&mboxes_lock);
426 return ret; 258 return ret;
259 }
260 mbox_configured++;
261 write_unlock(&mboxes_lock);
427 } 262 }
428 263
429 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED, 264 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
430 mbox->name, mbox); 265 mbox->name, mbox);
431 if (unlikely(ret)) { 266 if (unlikely(ret)) {
432 printk(KERN_ERR 267 printk(KERN_ERR
@@ -434,14 +269,14 @@ static int omap_mbox_init(struct omap_mbox *mbox)
434 goto fail_request_irq; 269 goto fail_request_irq;
435 } 270 }
436 271
437 mq = mbox_queue_alloc(mbox, mbox_txq_fn, mbox_tx_work); 272 mq = mbox_queue_alloc(mbox, mbox_txq_fn, NULL, mbox_tx_tasklet);
438 if (!mq) { 273 if (!mq) {
439 ret = -ENOMEM; 274 ret = -ENOMEM;
440 goto fail_alloc_txq; 275 goto fail_alloc_txq;
441 } 276 }
442 mbox->txq = mq; 277 mbox->txq = mq;
443 278
444 mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work); 279 mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work, NULL);
445 if (!mq) { 280 if (!mq) {
446 ret = -ENOMEM; 281 ret = -ENOMEM;
447 goto fail_alloc_rxq; 282 goto fail_alloc_rxq;
@@ -468,8 +303,14 @@ static void omap_mbox_fini(struct omap_mbox *mbox)
468 303
469 free_irq(mbox->irq, mbox); 304 free_irq(mbox->irq, mbox);
470 305
471 if (unlikely(mbox->ops->shutdown)) 306 if (unlikely(mbox->ops->shutdown)) {
472 mbox->ops->shutdown(mbox); 307 write_lock(&mboxes_lock);
308 if (mbox_configured > 0)
309 mbox_configured--;
310 if (!mbox_configured)
311 mbox->ops->shutdown(mbox);
312 write_unlock(&mboxes_lock);
313 }
473} 314}
474 315
475static struct omap_mbox **find_mboxes(const char *name) 316static struct omap_mbox **find_mboxes(const char *name)
@@ -498,7 +339,7 @@ struct omap_mbox *omap_mbox_get(const char *name)
498 339
499 read_unlock(&mboxes_lock); 340 read_unlock(&mboxes_lock);
500 341
501 ret = omap_mbox_init(mbox); 342 ret = omap_mbox_startup(mbox);
502 if (ret) 343 if (ret)
503 return ERR_PTR(-ENODEV); 344 return ERR_PTR(-ENODEV);
504 345
@@ -522,15 +363,6 @@ int omap_mbox_register(struct device *parent, struct omap_mbox *mbox)
522 if (mbox->next) 363 if (mbox->next)
523 return -EBUSY; 364 return -EBUSY;
524 365
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); 366 write_lock(&mboxes_lock);
535 tmp = find_mboxes(mbox->name); 367 tmp = find_mboxes(mbox->name);
536 if (*tmp) { 368 if (*tmp) {
@@ -544,9 +376,6 @@ int omap_mbox_register(struct device *parent, struct omap_mbox *mbox)
544 return 0; 376 return 0;
545 377
546err_find: 378err_find:
547 device_remove_file(mbox->dev, &dev_attr_mbox);
548err_sysfs:
549 device_unregister(mbox->dev);
550 return ret; 379 return ret;
551} 380}
552EXPORT_SYMBOL(omap_mbox_register); 381EXPORT_SYMBOL(omap_mbox_register);
@@ -562,8 +391,6 @@ int omap_mbox_unregister(struct omap_mbox *mbox)
562 *tmp = mbox->next; 391 *tmp = mbox->next;
563 mbox->next = NULL; 392 mbox->next = NULL;
564 write_unlock(&mboxes_lock); 393 write_unlock(&mboxes_lock);
565 device_remove_file(mbox->dev, &dev_attr_mbox);
566 device_unregister(mbox->dev);
567 return 0; 394 return 0;
568 } 395 }
569 tmp = &(*tmp)->next; 396 tmp = &(*tmp)->next;
@@ -574,23 +401,21 @@ int omap_mbox_unregister(struct omap_mbox *mbox)
574} 401}
575EXPORT_SYMBOL(omap_mbox_unregister); 402EXPORT_SYMBOL(omap_mbox_unregister);
576 403
577static int __init omap_mbox_class_init(void) 404static int __init omap_mbox_init(void)
578{ 405{
579 int ret = class_register(&omap_mbox_class); 406 mboxd = create_workqueue("mboxd");
580 if (!ret) 407 if (!mboxd)
581 ret = class_create_file(&omap_mbox_class, &class_attr_mbox); 408 return -ENOMEM;
582 409
583 return ret; 410 return 0;
584} 411}
412module_init(omap_mbox_init);
585 413
586static void __exit omap_mbox_class_exit(void) 414static void __exit omap_mbox_exit(void)
587{ 415{
588 class_remove_file(&omap_mbox_class, &class_attr_mbox); 416 destroy_workqueue(mboxd);
589 class_unregister(&omap_mbox_class);
590} 417}
591 418module_exit(omap_mbox_exit);
592subsys_initcall(omap_mbox_class_init);
593module_exit(omap_mbox_class_exit);
594 419
595MODULE_LICENSE("GPL v2"); 420MODULE_LICENSE("GPL v2");
596MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging"); 421MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging");