aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-omap1/mailbox.c55
-rw-r--r--arch/arm/mach-omap2/devices.c6
-rw-r--r--arch/arm/mach-omap2/mailbox.c182
-rw-r--r--arch/arm/plat-omap/Kconfig9
-rw-r--r--arch/arm/plat-omap/include/plat/mailbox.h20
-rw-r--r--arch/arm/plat-omap/mailbox.c248
6 files changed, 241 insertions, 279 deletions
diff --git a/arch/arm/mach-omap1/mailbox.c b/arch/arm/mach-omap1/mailbox.c
index 4f5b3da3d559..1a85a421007f 100644
--- a/arch/arm/mach-omap1/mailbox.c
+++ b/arch/arm/mach-omap1/mailbox.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Mailbox reservation modules for DSP 2 * Mailbox reservation modules for OMAP1
3 * 3 *
4 * Copyright (C) 2006-2009 Nokia Corporation 4 * Copyright (C) 2006-2009 Nokia Corporation
5 * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com> 5 * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
@@ -9,13 +9,10 @@
9 * for more details. 9 * for more details.
10 */ 10 */
11 11
12#include <linux/kernel.h>
13#include <linux/resource.h>
14#include <linux/interrupt.h> 12#include <linux/interrupt.h>
15#include <linux/platform_device.h> 13#include <linux/platform_device.h>
16#include <linux/io.h> 14#include <linux/io.h>
17#include <plat/mailbox.h> 15#include <plat/mailbox.h>
18#include <mach/irqs.h>
19 16
20#define MAILBOX_ARM2DSP1 0x00 17#define MAILBOX_ARM2DSP1 0x00
21#define MAILBOX_ARM2DSP1b 0x04 18#define MAILBOX_ARM2DSP1b 0x04
@@ -83,7 +80,7 @@ static int omap1_mbox_fifo_full(struct omap_mbox *mbox)
83 struct omap_mbox1_fifo *fifo = 80 struct omap_mbox1_fifo *fifo =
84 &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo; 81 &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo;
85 82
86 return (mbox_read_reg(fifo->flag)); 83 return mbox_read_reg(fifo->flag);
87} 84}
88 85
89/* irq */ 86/* irq */
@@ -141,47 +138,37 @@ struct omap_mbox mbox_dsp_info = {
141 .ops = &omap1_mbox_ops, 138 .ops = &omap1_mbox_ops,
142 .priv = &omap1_mbox_dsp_priv, 139 .priv = &omap1_mbox_dsp_priv,
143}; 140};
144EXPORT_SYMBOL(mbox_dsp_info); 141
142struct omap_mbox *omap1_mboxes[] = { &mbox_dsp_info, NULL };
145 143
146static int __devinit omap1_mbox_probe(struct platform_device *pdev) 144static int __devinit omap1_mbox_probe(struct platform_device *pdev)
147{ 145{
148 struct resource *res; 146 struct resource *mem;
147 int ret;
148 int i;
149 struct omap_mbox **list;
149 150
150 if (pdev->num_resources != 2) { 151 list = omap1_mboxes;
151 dev_err(&pdev->dev, "invalid number of resources: %d\n", 152 list[0]->irq = platform_get_irq_byname(pdev, "dsp");
152 pdev->num_resources);
153 return -ENODEV;
154 }
155 153
156 /* MBOX base */ 154 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
157 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 155 mbox_base = ioremap(mem->start, resource_size(mem));
158 if (unlikely(!res)) { 156 if (!mbox_base)
159 dev_err(&pdev->dev, "invalid mem resource\n"); 157 return -ENOMEM;
160 return -ENODEV;
161 }
162 158
163 mbox_base = ioremap(res->start, resource_size(res)); 159 ret = omap_mbox_register(&pdev->dev, list);
164 if (!mbox_base) { 160 if (ret) {
165 dev_err(&pdev->dev, "ioremap failed\n");
166 return -ENODEV;
167 }
168
169 /* DSP IRQ */
170 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
171 if (unlikely(!res)) {
172 dev_err(&pdev->dev, "invalid irq resource\n");
173 iounmap(mbox_base); 161 iounmap(mbox_base);
174 return -ENODEV; 162 return ret;
175 } 163 }
176 mbox_dsp_info.irq = res->start;
177 164
178 return omap_mbox_register(&pdev->dev, &mbox_dsp_info); 165 return 0;
179} 166}
180 167
181static int __devexit omap1_mbox_remove(struct platform_device *pdev) 168static int __devexit omap1_mbox_remove(struct platform_device *pdev)
182{ 169{
183 omap_mbox_unregister(&mbox_dsp_info); 170 omap_mbox_unregister();
184 171 iounmap(mbox_base);
185 return 0; 172 return 0;
186} 173}
187 174
@@ -189,7 +176,7 @@ static struct platform_driver omap1_mbox_driver = {
189 .probe = omap1_mbox_probe, 176 .probe = omap1_mbox_probe,
190 .remove = __devexit_p(omap1_mbox_remove), 177 .remove = __devexit_p(omap1_mbox_remove),
191 .driver = { 178 .driver = {
192 .name = "omap1-mailbox", 179 .name = "omap-mailbox",
193 }, 180 },
194}; 181};
195 182
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 162a9be3cbb1..2dbb265bedd4 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -152,10 +152,12 @@ static struct resource omap2_mbox_resources[] = {
152 { 152 {
153 .start = INT_24XX_MAIL_U0_MPU, 153 .start = INT_24XX_MAIL_U0_MPU,
154 .flags = IORESOURCE_IRQ, 154 .flags = IORESOURCE_IRQ,
155 .name = "dsp",
155 }, 156 },
156 { 157 {
157 .start = INT_24XX_MAIL_U3_MPU, 158 .start = INT_24XX_MAIL_U3_MPU,
158 .flags = IORESOURCE_IRQ, 159 .flags = IORESOURCE_IRQ,
160 .name = "iva",
159 }, 161 },
160}; 162};
161static int omap2_mbox_resources_sz = ARRAY_SIZE(omap2_mbox_resources); 163static int omap2_mbox_resources_sz = ARRAY_SIZE(omap2_mbox_resources);
@@ -174,6 +176,7 @@ static struct resource omap3_mbox_resources[] = {
174 { 176 {
175 .start = INT_24XX_MAIL_U0_MPU, 177 .start = INT_24XX_MAIL_U0_MPU,
176 .flags = IORESOURCE_IRQ, 178 .flags = IORESOURCE_IRQ,
179 .name = "dsp",
177 }, 180 },
178}; 181};
179static int omap3_mbox_resources_sz = ARRAY_SIZE(omap3_mbox_resources); 182static int omap3_mbox_resources_sz = ARRAY_SIZE(omap3_mbox_resources);
@@ -195,6 +198,7 @@ static struct resource omap4_mbox_resources[] = {
195 { 198 {
196 .start = OMAP44XX_IRQ_MAIL_U0, 199 .start = OMAP44XX_IRQ_MAIL_U0,
197 .flags = IORESOURCE_IRQ, 200 .flags = IORESOURCE_IRQ,
201 .name = "mbox",
198 }, 202 },
199}; 203};
200static int omap4_mbox_resources_sz = ARRAY_SIZE(omap4_mbox_resources); 204static int omap4_mbox_resources_sz = ARRAY_SIZE(omap4_mbox_resources);
@@ -204,7 +208,7 @@ static int omap4_mbox_resources_sz = ARRAY_SIZE(omap4_mbox_resources);
204#endif 208#endif
205 209
206static struct platform_device mbox_device = { 210static struct platform_device mbox_device = {
207 .name = "omap2-mailbox", 211 .name = "omap-mailbox",
208 .id = -1, 212 .id = -1,
209}; 213};
210 214
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
index 318f3638653c..42dbfa46e656 100644
--- a/arch/arm/mach-omap2/mailbox.c
+++ b/arch/arm/mach-omap2/mailbox.c
@@ -10,7 +10,6 @@
10 * for more details. 10 * for more details.
11 */ 11 */
12 12
13#include <linux/kernel.h>
14#include <linux/clk.h> 13#include <linux/clk.h>
15#include <linux/err.h> 14#include <linux/err.h>
16#include <linux/platform_device.h> 15#include <linux/platform_device.h>
@@ -18,8 +17,6 @@
18#include <plat/mailbox.h> 17#include <plat/mailbox.h>
19#include <mach/irqs.h> 18#include <mach/irqs.h>
20 19
21#define DRV_NAME "omap2-mailbox"
22
23#define MAILBOX_REVISION 0x000 20#define MAILBOX_REVISION 0x000
24#define MAILBOX_SYSCONFIG 0x010 21#define MAILBOX_SYSCONFIG 0x010
25#define MAILBOX_SYSSTATUS 0x014 22#define MAILBOX_SYSSTATUS 0x014
@@ -131,7 +128,7 @@ static int omap2_mbox_startup(struct omap_mbox *mbox)
131 } 128 }
132 129
133 l = mbox_read_reg(MAILBOX_REVISION); 130 l = mbox_read_reg(MAILBOX_REVISION);
134 pr_info("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f)); 131 pr_debug("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f));
135 132
136 if (cpu_is_omap44xx()) 133 if (cpu_is_omap44xx())
137 l = OMAP4_SMARTIDLE; 134 l = OMAP4_SMARTIDLE;
@@ -283,6 +280,8 @@ static struct omap_mbox_ops omap2_mbox_ops = {
283 */ 280 */
284 281
285/* FIXME: the following structs should be filled automatically by the user id */ 282/* FIXME: the following structs should be filled automatically by the user id */
283
284#if defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_ARCH_OMAP2420)
286/* DSP */ 285/* DSP */
287static struct omap_mbox2_priv omap2_mbox_dsp_priv = { 286static struct omap_mbox2_priv omap2_mbox_dsp_priv = {
288 .tx_fifo = { 287 .tx_fifo = {
@@ -300,10 +299,46 @@ static struct omap_mbox2_priv omap2_mbox_dsp_priv = {
300 .irqdisable = MAILBOX_IRQENABLE(0), 299 .irqdisable = MAILBOX_IRQENABLE(0),
301}; 300};
302 301
302struct omap_mbox mbox_dsp_info = {
303 .name = "dsp",
304 .ops = &omap2_mbox_ops,
305 .priv = &omap2_mbox_dsp_priv,
306};
307#endif
308
309#if defined(CONFIG_ARCH_OMAP3430)
310struct omap_mbox *omap3_mboxes[] = { &mbox_dsp_info, NULL };
311#endif
312
313#if defined(CONFIG_ARCH_OMAP2420)
314/* IVA */
315static struct omap_mbox2_priv omap2_mbox_iva_priv = {
316 .tx_fifo = {
317 .msg = MAILBOX_MESSAGE(2),
318 .fifo_stat = MAILBOX_FIFOSTATUS(2),
319 },
320 .rx_fifo = {
321 .msg = MAILBOX_MESSAGE(3),
322 .msg_stat = MAILBOX_MSGSTATUS(3),
323 },
324 .irqenable = MAILBOX_IRQENABLE(3),
325 .irqstatus = MAILBOX_IRQSTATUS(3),
326 .notfull_bit = MAILBOX_IRQ_NOTFULL(2),
327 .newmsg_bit = MAILBOX_IRQ_NEWMSG(3),
328 .irqdisable = MAILBOX_IRQENABLE(3),
329};
330
331static struct omap_mbox mbox_iva_info = {
332 .name = "iva",
333 .ops = &omap2_mbox_ops,
334 .priv = &omap2_mbox_iva_priv,
335};
303 336
337struct omap_mbox *omap2_mboxes[] = { &mbox_iva_info, &mbox_dsp_info, NULL };
338#endif
304 339
305/* OMAP4 specific data structure. Use the cpu_is_omap4xxx() 340#if defined(CONFIG_ARCH_OMAP4)
306to use this*/ 341/* OMAP4 */
307static struct omap_mbox2_priv omap2_mbox_1_priv = { 342static struct omap_mbox2_priv omap2_mbox_1_priv = {
308 .tx_fifo = { 343 .tx_fifo = {
309 .msg = MAILBOX_MESSAGE(0), 344 .msg = MAILBOX_MESSAGE(0),
@@ -325,14 +360,6 @@ struct omap_mbox mbox_1_info = {
325 .ops = &omap2_mbox_ops, 360 .ops = &omap2_mbox_ops,
326 .priv = &omap2_mbox_1_priv, 361 .priv = &omap2_mbox_1_priv,
327}; 362};
328EXPORT_SYMBOL(mbox_1_info);
329
330struct omap_mbox mbox_dsp_info = {
331 .name = "dsp",
332 .ops = &omap2_mbox_ops,
333 .priv = &omap2_mbox_dsp_priv,
334};
335EXPORT_SYMBOL(mbox_dsp_info);
336 363
337static struct omap_mbox2_priv omap2_mbox_2_priv = { 364static struct omap_mbox2_priv omap2_mbox_2_priv = {
338 .tx_fifo = { 365 .tx_fifo = {
@@ -355,110 +382,64 @@ struct omap_mbox mbox_2_info = {
355 .ops = &omap2_mbox_ops, 382 .ops = &omap2_mbox_ops,
356 .priv = &omap2_mbox_2_priv, 383 .priv = &omap2_mbox_2_priv,
357}; 384};
358EXPORT_SYMBOL(mbox_2_info);
359
360
361#if defined(CONFIG_ARCH_OMAP2420) /* IVA */
362static struct omap_mbox2_priv omap2_mbox_iva_priv = {
363 .tx_fifo = {
364 .msg = MAILBOX_MESSAGE(2),
365 .fifo_stat = MAILBOX_FIFOSTATUS(2),
366 },
367 .rx_fifo = {
368 .msg = MAILBOX_MESSAGE(3),
369 .msg_stat = MAILBOX_MSGSTATUS(3),
370 },
371 .irqenable = MAILBOX_IRQENABLE(3),
372 .irqstatus = MAILBOX_IRQSTATUS(3),
373 .notfull_bit = MAILBOX_IRQ_NOTFULL(2),
374 .newmsg_bit = MAILBOX_IRQ_NEWMSG(3),
375 .irqdisable = MAILBOX_IRQENABLE(3),
376};
377 385
378static struct omap_mbox mbox_iva_info = { 386struct omap_mbox *omap4_mboxes[] = { &mbox_1_info, &mbox_2_info, NULL };
379 .name = "iva",
380 .ops = &omap2_mbox_ops,
381 .priv = &omap2_mbox_iva_priv,
382};
383#endif 387#endif
384 388
385static int __devinit omap2_mbox_probe(struct platform_device *pdev) 389static int __devinit omap2_mbox_probe(struct platform_device *pdev)
386{ 390{
387 struct resource *res; 391 struct resource *mem;
388 int ret; 392 int ret;
393 struct omap_mbox **list;
389 394
390 /* MBOX base */ 395 if (false)
391 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 396 ;
392 if (unlikely(!res)) { 397#if defined(CONFIG_ARCH_OMAP3430)
393 dev_err(&pdev->dev, "invalid mem resource\n"); 398 else if (cpu_is_omap3430()) {
394 return -ENODEV; 399 list = omap3_mboxes;
400
401 list[0]->irq = platform_get_irq_byname(pdev, "dsp");
395 } 402 }
396 mbox_base = ioremap(res->start, resource_size(res)); 403#endif
397 if (!mbox_base) 404#if defined(CONFIG_ARCH_OMAP2420)
398 return -ENOMEM; 405 else if (cpu_is_omap2420()) {
406 list = omap2_mboxes;
399 407
400 /* DSP or IVA2 IRQ */ 408 list[0]->irq = platform_get_irq_byname(pdev, "dsp");
401 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 409 list[1]->irq = platform_get_irq_byname(pdev, "iva");
410 }
411#endif
412#if defined(CONFIG_ARCH_OMAP4)
413 else if (cpu_is_omap44xx()) {
414 list = omap4_mboxes;
402 415
403 if (unlikely(!res)) { 416 list[0]->irq = list[1]->irq =
404 dev_err(&pdev->dev, "invalid irq resource\n"); 417 platform_get_irq_byname(pdev, "mbox");
405 ret = -ENODEV;
406 goto err_dsp;
407 } 418 }
408 if (cpu_is_omap44xx()) { 419#endif
409 mbox_1_info.irq = res->start; 420 else {
410 ret = omap_mbox_register(&pdev->dev, &mbox_1_info); 421 pr_err("%s: platform not supported\n", __func__);
411 } else { 422 return -ENODEV;
412 mbox_dsp_info.irq = res->start;
413 ret = omap_mbox_register(&pdev->dev, &mbox_dsp_info);
414 } 423 }
415 if (ret)
416 goto err_dsp;
417 424
418 if (cpu_is_omap44xx()) { 425 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
419 mbox_2_info.irq = res->start; 426 mbox_base = ioremap(mem->start, resource_size(mem));
420 ret = omap_mbox_register(&pdev->dev, &mbox_2_info); 427 if (!mbox_base)
421 if (ret) { 428 return -ENOMEM;
422 omap_mbox_unregister(&mbox_1_info); 429
423 goto err_dsp; 430 ret = omap_mbox_register(&pdev->dev, list);
424 } 431 if (ret) {
425 } 432 iounmap(mbox_base);
426#if defined(CONFIG_ARCH_OMAP2420) /* IVA */ 433 return ret;
427 if (cpu_is_omap2420()) {
428 /* IVA IRQ */
429 res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
430 if (unlikely(!res)) {
431 dev_err(&pdev->dev, "invalid irq resource\n");
432 ret = -ENODEV;
433 omap_mbox_unregister(&mbox_dsp_info);
434 goto err_dsp;
435 }
436 mbox_iva_info.irq = res->start;
437 ret = omap_mbox_register(&pdev->dev, &mbox_iva_info);
438 if (ret) {
439 omap_mbox_unregister(&mbox_dsp_info);
440 goto err_dsp;
441 }
442 } 434 }
443#endif
444 return 0; 435 return 0;
445 436
446err_dsp:
447 iounmap(mbox_base);
448 return ret; 437 return ret;
449} 438}
450 439
451static int __devexit omap2_mbox_remove(struct platform_device *pdev) 440static int __devexit omap2_mbox_remove(struct platform_device *pdev)
452{ 441{
453#if defined(CONFIG_ARCH_OMAP2420) 442 omap_mbox_unregister();
454 omap_mbox_unregister(&mbox_iva_info);
455#endif
456
457 if (cpu_is_omap44xx()) {
458 omap_mbox_unregister(&mbox_2_info);
459 omap_mbox_unregister(&mbox_1_info);
460 } else
461 omap_mbox_unregister(&mbox_dsp_info);
462 iounmap(mbox_base); 443 iounmap(mbox_base);
463 return 0; 444 return 0;
464} 445}
@@ -467,7 +448,7 @@ static struct platform_driver omap2_mbox_driver = {
467 .probe = omap2_mbox_probe, 448 .probe = omap2_mbox_probe,
468 .remove = __devexit_p(omap2_mbox_remove), 449 .remove = __devexit_p(omap2_mbox_remove),
469 .driver = { 450 .driver = {
470 .name = DRV_NAME, 451 .name = "omap-mailbox",
471 }, 452 },
472}; 453};
473 454
@@ -486,5 +467,6 @@ module_exit(omap2_mbox_exit);
486 467
487MODULE_LICENSE("GPL v2"); 468MODULE_LICENSE("GPL v2");
488MODULE_DESCRIPTION("omap mailbox: omap2/3/4 architecture specific functions"); 469MODULE_DESCRIPTION("omap mailbox: omap2/3/4 architecture specific functions");
489MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>, Paul Mundt"); 470MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
490MODULE_ALIAS("platform:"DRV_NAME); 471MODULE_AUTHOR("Paul Mundt");
472MODULE_ALIAS("platform:omap2-mailbox");
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index e2ed952df23d..e39a417a368d 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -88,6 +88,15 @@ config OMAP_MBOX_FWK
88 Say Y here if you want to use OMAP Mailbox framework support for 88 Say Y here if you want to use OMAP Mailbox framework support for
89 DSP, IVA1.0 and IVA2 in OMAP1/2/3. 89 DSP, IVA1.0 and IVA2 in OMAP1/2/3.
90 90
91config OMAP_MBOX_KFIFO_SIZE
92 int "Mailbox kfifo default buffer size (bytes)"
93 depends on OMAP_MBOX_FWK
94 default 256
95 help
96 Specify the default size of mailbox's kfifo buffers (bytes).
97 This can also be changed at runtime (via the mbox_kfifo_size
98 module parameter).
99
91config OMAP_IOMMU 100config OMAP_IOMMU
92 tristate 101 tristate
93 102
diff --git a/arch/arm/plat-omap/include/plat/mailbox.h b/arch/arm/plat-omap/include/plat/mailbox.h
index 729166b76a7c..997656552109 100644
--- a/arch/arm/plat-omap/include/plat/mailbox.h
+++ b/arch/arm/plat-omap/include/plat/mailbox.h
@@ -3,10 +3,11 @@
3#ifndef MAILBOX_H 3#ifndef MAILBOX_H
4#define MAILBOX_H 4#define MAILBOX_H
5 5
6#include <linux/wait.h> 6#include <linux/spinlock.h>
7#include <linux/workqueue.h> 7#include <linux/workqueue.h>
8#include <linux/blkdev.h>
9#include <linux/interrupt.h> 8#include <linux/interrupt.h>
9#include <linux/device.h>
10#include <linux/kfifo.h>
10 11
11typedef u32 mbox_msg_t; 12typedef u32 mbox_msg_t;
12struct omap_mbox; 13struct omap_mbox;
@@ -42,7 +43,7 @@ struct omap_mbox_ops {
42 43
43struct omap_mbox_queue { 44struct omap_mbox_queue {
44 spinlock_t lock; 45 spinlock_t lock;
45 struct request_queue *queue; 46 struct kfifo fifo;
46 struct work_struct work; 47 struct work_struct work;
47 struct tasklet_struct tasklet; 48 struct tasklet_struct tasklet;
48 int (*callback)(void *); 49 int (*callback)(void *);
@@ -52,19 +53,10 @@ struct omap_mbox_queue {
52struct omap_mbox { 53struct omap_mbox {
53 char *name; 54 char *name;
54 unsigned int irq; 55 unsigned int irq;
55
56 struct omap_mbox_queue *txq, *rxq; 56 struct omap_mbox_queue *txq, *rxq;
57
58 struct omap_mbox_ops *ops; 57 struct omap_mbox_ops *ops;
59
60 mbox_msg_t seq_snd, seq_rcv;
61
62 struct device *dev; 58 struct device *dev;
63
64 struct omap_mbox *next;
65 void *priv; 59 void *priv;
66
67 void (*err_notify)(void);
68}; 60};
69 61
70int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg); 62int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg);
@@ -73,8 +65,8 @@ void omap_mbox_init_seq(struct omap_mbox *);
73struct omap_mbox *omap_mbox_get(const char *); 65struct omap_mbox *omap_mbox_get(const char *);
74void omap_mbox_put(struct omap_mbox *); 66void omap_mbox_put(struct omap_mbox *);
75 67
76int omap_mbox_register(struct device *parent, struct omap_mbox *); 68int omap_mbox_register(struct device *parent, struct omap_mbox **);
77int omap_mbox_unregister(struct omap_mbox *); 69int omap_mbox_unregister(void);
78 70
79static inline void omap_mbox_save_ctx(struct omap_mbox *mbox) 71static inline void omap_mbox_save_ctx(struct omap_mbox *mbox)
80{ 72{
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
index 08a2df766289..d2fafb892f7f 100644
--- a/arch/arm/plat-omap/mailbox.c
+++ b/arch/arm/plat-omap/mailbox.c
@@ -21,19 +21,26 @@
21 * 21 *
22 */ 22 */
23 23
24#include <linux/module.h>
25#include <linux/interrupt.h> 24#include <linux/interrupt.h>
26#include <linux/device.h> 25#include <linux/spinlock.h>
26#include <linux/mutex.h>
27#include <linux/delay.h> 27#include <linux/delay.h>
28#include <linux/slab.h> 28#include <linux/slab.h>
29#include <linux/kfifo.h>
30#include <linux/err.h>
29 31
30#include <plat/mailbox.h> 32#include <plat/mailbox.h>
31 33
32static struct workqueue_struct *mboxd; 34static struct workqueue_struct *mboxd;
33static struct omap_mbox *mboxes; 35static struct omap_mbox **mboxes;
34static DEFINE_RWLOCK(mboxes_lock); 36static bool rq_full;
35 37
36static int mbox_configured; 38static int mbox_configured;
39static DEFINE_MUTEX(mbox_configured_lock);
40
41static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE;
42module_param(mbox_kfifo_size, uint, S_IRUGO);
43MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)");
37 44
38/* Mailbox FIFO handle functions */ 45/* Mailbox FIFO handle functions */
39static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) 46static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
@@ -67,7 +74,7 @@ static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
67/* 74/*
68 * message sender 75 * message sender
69 */ 76 */
70static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) 77static int __mbox_poll_for_space(struct omap_mbox *mbox)
71{ 78{
72 int ret = 0, i = 1000; 79 int ret = 0, i = 1000;
73 80
@@ -78,49 +85,50 @@ static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
78 return -1; 85 return -1;
79 udelay(1); 86 udelay(1);
80 } 87 }
81 mbox_fifo_write(mbox, msg);
82 return ret; 88 return ret;
83} 89}
84 90
85
86int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) 91int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
87{ 92{
93 struct omap_mbox_queue *mq = mbox->txq;
94 int ret = 0, len;
88 95
89 struct request *rq; 96 spin_lock(&mq->lock);
90 struct request_queue *q = mbox->txq->queue;
91 97
92 rq = blk_get_request(q, WRITE, GFP_ATOMIC); 98 if (kfifo_avail(&mq->fifo) < sizeof(msg)) {
93 if (unlikely(!rq)) 99 ret = -ENOMEM;
94 return -ENOMEM; 100 goto out;
101 }
102
103 len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
104 WARN_ON(len != sizeof(msg));
95 105
96 blk_insert_request(q, rq, 0, (void *) msg);
97 tasklet_schedule(&mbox->txq->tasklet); 106 tasklet_schedule(&mbox->txq->tasklet);
98 107
99 return 0; 108out:
109 spin_unlock(&mq->lock);
110 return ret;
100} 111}
101EXPORT_SYMBOL(omap_mbox_msg_send); 112EXPORT_SYMBOL(omap_mbox_msg_send);
102 113
103static void mbox_tx_tasklet(unsigned long tx_data) 114static void mbox_tx_tasklet(unsigned long tx_data)
104{ 115{
105 int ret;
106 struct request *rq;
107 struct omap_mbox *mbox = (struct omap_mbox *)tx_data; 116 struct omap_mbox *mbox = (struct omap_mbox *)tx_data;
108 struct request_queue *q = mbox->txq->queue; 117 struct omap_mbox_queue *mq = mbox->txq;
109 118 mbox_msg_t msg;
110 while (1) { 119 int ret;
111
112 rq = blk_fetch_request(q);
113
114 if (!rq)
115 break;
116 120
117 ret = __mbox_msg_send(mbox, (mbox_msg_t)rq->special); 121 while (kfifo_len(&mq->fifo)) {
118 if (ret) { 122 if (__mbox_poll_for_space(mbox)) {
119 omap_mbox_enable_irq(mbox, IRQ_TX); 123 omap_mbox_enable_irq(mbox, IRQ_TX);
120 blk_requeue_request(q, rq); 124 break;
121 return;
122 } 125 }
123 blk_end_request_all(rq, 0); 126
127 ret = kfifo_out(&mq->fifo, (unsigned char *)&msg,
128 sizeof(msg));
129 WARN_ON(ret != sizeof(msg));
130
131 mbox_fifo_write(mbox, msg);
124 } 132 }
125} 133}
126 134
@@ -131,36 +139,21 @@ static void mbox_rx_work(struct work_struct *work)
131{ 139{
132 struct omap_mbox_queue *mq = 140 struct omap_mbox_queue *mq =
133 container_of(work, struct omap_mbox_queue, work); 141 container_of(work, struct omap_mbox_queue, work);
134 struct omap_mbox *mbox = mq->queue->queuedata;
135 struct request_queue *q = mbox->rxq->queue;
136 struct request *rq;
137 mbox_msg_t msg; 142 mbox_msg_t msg;
138 unsigned long flags; 143 int len;
139 144
140 while (1) { 145 while (kfifo_len(&mq->fifo) >= sizeof(msg)) {
141 spin_lock_irqsave(q->queue_lock, flags); 146 len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
142 rq = blk_fetch_request(q); 147 WARN_ON(len != sizeof(msg));
143 spin_unlock_irqrestore(q->queue_lock, flags);
144 if (!rq)
145 break;
146 148
147 msg = (mbox_msg_t)rq->special; 149 if (mq->callback)
148 blk_end_request_all(rq, 0); 150 mq->callback((void *)msg);
149 mbox->rxq->callback((void *)msg);
150 } 151 }
151} 152}
152 153
153/* 154/*
154 * Mailbox interrupt handler 155 * Mailbox interrupt handler
155 */ 156 */
156static void mbox_txq_fn(struct request_queue *q)
157{
158}
159
160static void mbox_rxq_fn(struct request_queue *q)
161{
162}
163
164static void __mbox_tx_interrupt(struct omap_mbox *mbox) 157static void __mbox_tx_interrupt(struct omap_mbox *mbox)
165{ 158{
166 omap_mbox_disable_irq(mbox, IRQ_TX); 159 omap_mbox_disable_irq(mbox, IRQ_TX);
@@ -170,19 +163,22 @@ static void __mbox_tx_interrupt(struct omap_mbox *mbox)
170 163
171static void __mbox_rx_interrupt(struct omap_mbox *mbox) 164static void __mbox_rx_interrupt(struct omap_mbox *mbox)
172{ 165{
173 struct request *rq; 166 struct omap_mbox_queue *mq = mbox->rxq;
174 mbox_msg_t msg; 167 mbox_msg_t msg;
175 struct request_queue *q = mbox->rxq->queue; 168 int len;
176 169
177 while (!mbox_fifo_empty(mbox)) { 170 while (!mbox_fifo_empty(mbox)) {
178 rq = blk_get_request(q, WRITE, GFP_ATOMIC); 171 if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) {
179 if (unlikely(!rq)) 172 omap_mbox_disable_irq(mbox, IRQ_RX);
173 rq_full = true;
180 goto nomem; 174 goto nomem;
175 }
181 176
182 msg = mbox_fifo_read(mbox); 177 msg = mbox_fifo_read(mbox);
183 178
179 len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
180 WARN_ON(len != sizeof(msg));
184 181
185 blk_insert_request(q, rq, 0, (void *)msg);
186 if (mbox->ops->type == OMAP_MBOX_TYPE1) 182 if (mbox->ops->type == OMAP_MBOX_TYPE1)
187 break; 183 break;
188 } 184 }
@@ -207,11 +203,9 @@ static irqreturn_t mbox_interrupt(int irq, void *p)
207} 203}
208 204
209static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, 205static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
210 request_fn_proc *proc,
211 void (*work) (struct work_struct *), 206 void (*work) (struct work_struct *),
212 void (*tasklet)(unsigned long)) 207 void (*tasklet)(unsigned long))
213{ 208{
214 struct request_queue *q;
215 struct omap_mbox_queue *mq; 209 struct omap_mbox_queue *mq;
216 210
217 mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL); 211 mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL);
@@ -220,11 +214,8 @@ static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
220 214
221 spin_lock_init(&mq->lock); 215 spin_lock_init(&mq->lock);
222 216
223 q = blk_init_queue(proc, &mq->lock); 217 if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL))
224 if (!q)
225 goto error; 218 goto error;
226 q->queuedata = mbox;
227 mq->queue = q;
228 219
229 if (work) 220 if (work)
230 INIT_WORK(&mq->work, work); 221 INIT_WORK(&mq->work, work);
@@ -239,7 +230,7 @@ error:
239 230
240static void mbox_queue_free(struct omap_mbox_queue *q) 231static void mbox_queue_free(struct omap_mbox_queue *q)
241{ 232{
242 blk_cleanup_queue(q->queue); 233 kfifo_free(&q->fifo);
243 kfree(q); 234 kfree(q);
244} 235}
245 236
@@ -248,35 +239,35 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
248 int ret = 0; 239 int ret = 0;
249 struct omap_mbox_queue *mq; 240 struct omap_mbox_queue *mq;
250 241
251 if (likely(mbox->ops->startup)) { 242 if (mbox->ops->startup) {
252 write_lock(&mboxes_lock); 243 mutex_lock(&mbox_configured_lock);
253 if (!mbox_configured) 244 if (!mbox_configured)
254 ret = mbox->ops->startup(mbox); 245 ret = mbox->ops->startup(mbox);
255 246
256 if (unlikely(ret)) { 247 if (ret) {
257 write_unlock(&mboxes_lock); 248 mutex_unlock(&mbox_configured_lock);
258 return ret; 249 return ret;
259 } 250 }
260 mbox_configured++; 251 mbox_configured++;
261 write_unlock(&mboxes_lock); 252 mutex_unlock(&mbox_configured_lock);
262 } 253 }
263 254
264 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, 255 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
265 mbox->name, mbox); 256 mbox->name, mbox);
266 if (unlikely(ret)) { 257 if (ret) {
267 printk(KERN_ERR 258 printk(KERN_ERR
268 "failed to register mailbox interrupt:%d\n", ret); 259 "failed to register mailbox interrupt:%d\n", ret);
269 goto fail_request_irq; 260 goto fail_request_irq;
270 } 261 }
271 262
272 mq = mbox_queue_alloc(mbox, mbox_txq_fn, NULL, mbox_tx_tasklet); 263 mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
273 if (!mq) { 264 if (!mq) {
274 ret = -ENOMEM; 265 ret = -ENOMEM;
275 goto fail_alloc_txq; 266 goto fail_alloc_txq;
276 } 267 }
277 mbox->txq = mq; 268 mbox->txq = mq;
278 269
279 mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work, NULL); 270 mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL);
280 if (!mq) { 271 if (!mq) {
281 ret = -ENOMEM; 272 ret = -ENOMEM;
282 goto fail_alloc_rxq; 273 goto fail_alloc_rxq;
@@ -290,7 +281,7 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
290 fail_alloc_txq: 281 fail_alloc_txq:
291 free_irq(mbox->irq, mbox); 282 free_irq(mbox->irq, mbox);
292 fail_request_irq: 283 fail_request_irq:
293 if (unlikely(mbox->ops->shutdown)) 284 if (mbox->ops->shutdown)
294 mbox->ops->shutdown(mbox); 285 mbox->ops->shutdown(mbox);
295 286
296 return ret; 287 return ret;
@@ -298,31 +289,20 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
298 289
299static void omap_mbox_fini(struct omap_mbox *mbox) 290static void omap_mbox_fini(struct omap_mbox *mbox)
300{ 291{
292 free_irq(mbox->irq, mbox);
293 tasklet_kill(&mbox->txq->tasklet);
294 flush_work(&mbox->rxq->work);
301 mbox_queue_free(mbox->txq); 295 mbox_queue_free(mbox->txq);
302 mbox_queue_free(mbox->rxq); 296 mbox_queue_free(mbox->rxq);
303 297
304 free_irq(mbox->irq, mbox); 298 if (mbox->ops->shutdown) {
305 299 mutex_lock(&mbox_configured_lock);
306 if (unlikely(mbox->ops->shutdown)) {
307 write_lock(&mboxes_lock);
308 if (mbox_configured > 0) 300 if (mbox_configured > 0)
309 mbox_configured--; 301 mbox_configured--;
310 if (!mbox_configured) 302 if (!mbox_configured)
311 mbox->ops->shutdown(mbox); 303 mbox->ops->shutdown(mbox);
312 write_unlock(&mboxes_lock); 304 mutex_unlock(&mbox_configured_lock);
313 }
314}
315
316static struct omap_mbox **find_mboxes(const char *name)
317{
318 struct omap_mbox **p;
319
320 for (p = &mboxes; *p; p = &(*p)->next) {
321 if (strcmp((*p)->name, name) == 0)
322 break;
323 } 305 }
324
325 return p;
326} 306}
327 307
328struct omap_mbox *omap_mbox_get(const char *name) 308struct omap_mbox *omap_mbox_get(const char *name)
@@ -330,14 +310,15 @@ struct omap_mbox *omap_mbox_get(const char *name)
330 struct omap_mbox *mbox; 310 struct omap_mbox *mbox;
331 int ret; 311 int ret;
332 312
333 read_lock(&mboxes_lock); 313 if (!mboxes)
334 mbox = *(find_mboxes(name)); 314 return ERR_PTR(-EINVAL);
335 if (mbox == NULL) {
336 read_unlock(&mboxes_lock);
337 return ERR_PTR(-ENOENT);
338 }
339 315
340 read_unlock(&mboxes_lock); 316 for (mbox = *mboxes; mbox; mbox++)
317 if (!strcmp(mbox->name, name))
318 break;
319
320 if (!mbox)
321 return ERR_PTR(-ENOENT);
341 322
342 ret = omap_mbox_startup(mbox); 323 ret = omap_mbox_startup(mbox);
343 if (ret) 324 if (ret)
@@ -353,70 +334,77 @@ void omap_mbox_put(struct omap_mbox *mbox)
353} 334}
354EXPORT_SYMBOL(omap_mbox_put); 335EXPORT_SYMBOL(omap_mbox_put);
355 336
356int omap_mbox_register(struct device *parent, struct omap_mbox *mbox) 337static struct class omap_mbox_class = { .name = "mbox", };
338
339int omap_mbox_register(struct device *parent, struct omap_mbox **list)
357{ 340{
358 int ret = 0; 341 int ret;
359 struct omap_mbox **tmp; 342 int i;
360 343
361 if (!mbox) 344 mboxes = list;
345 if (!mboxes)
362 return -EINVAL; 346 return -EINVAL;
363 if (mbox->next)
364 return -EBUSY;
365
366 write_lock(&mboxes_lock);
367 tmp = find_mboxes(mbox->name);
368 if (*tmp) {
369 ret = -EBUSY;
370 write_unlock(&mboxes_lock);
371 goto err_find;
372 }
373 *tmp = mbox;
374 write_unlock(&mboxes_lock);
375 347
348 for (i = 0; mboxes[i]; i++) {
349 struct omap_mbox *mbox = mboxes[i];
350 mbox->dev = device_create(&omap_mbox_class,
351 parent, 0, mbox, "%s", mbox->name);
352 if (IS_ERR(mbox->dev)) {
353 ret = PTR_ERR(mbox->dev);
354 goto err_out;
355 }
356 }
376 return 0; 357 return 0;
377 358
378err_find: 359err_out:
360 while (i--)
361 device_unregister(mboxes[i]->dev);
379 return ret; 362 return ret;
380} 363}
381EXPORT_SYMBOL(omap_mbox_register); 364EXPORT_SYMBOL(omap_mbox_register);
382 365
383int omap_mbox_unregister(struct omap_mbox *mbox) 366int omap_mbox_unregister(void)
384{ 367{
385 struct omap_mbox **tmp; 368 int i;
386 369
387 write_lock(&mboxes_lock); 370 if (!mboxes)
388 tmp = &mboxes; 371 return -EINVAL;
389 while (*tmp) {
390 if (mbox == *tmp) {
391 *tmp = mbox->next;
392 mbox->next = NULL;
393 write_unlock(&mboxes_lock);
394 return 0;
395 }
396 tmp = &(*tmp)->next;
397 }
398 write_unlock(&mboxes_lock);
399 372
400 return -EINVAL; 373 for (i = 0; mboxes[i]; i++)
374 device_unregister(mboxes[i]->dev);
375 mboxes = NULL;
376 return 0;
401} 377}
402EXPORT_SYMBOL(omap_mbox_unregister); 378EXPORT_SYMBOL(omap_mbox_unregister);
403 379
404static int __init omap_mbox_init(void) 380static int __init omap_mbox_init(void)
405{ 381{
382 int err;
383
384 err = class_register(&omap_mbox_class);
385 if (err)
386 return err;
387
406 mboxd = create_workqueue("mboxd"); 388 mboxd = create_workqueue("mboxd");
407 if (!mboxd) 389 if (!mboxd)
408 return -ENOMEM; 390 return -ENOMEM;
409 391
392 /* kfifo size sanity check: alignment and minimal size */
393 mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t));
394 mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, sizeof(mbox_msg_t));
395
410 return 0; 396 return 0;
411} 397}
412module_init(omap_mbox_init); 398subsys_initcall(omap_mbox_init);
413 399
414static void __exit omap_mbox_exit(void) 400static void __exit omap_mbox_exit(void)
415{ 401{
416 destroy_workqueue(mboxd); 402 destroy_workqueue(mboxd);
403 class_unregister(&omap_mbox_class);
417} 404}
418module_exit(omap_mbox_exit); 405module_exit(omap_mbox_exit);
419 406
420MODULE_LICENSE("GPL v2"); 407MODULE_LICENSE("GPL v2");
421MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging"); 408MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging");
422MODULE_AUTHOR("Toshihiro Kobayashi and Hiroshi DOYU"); 409MODULE_AUTHOR("Toshihiro Kobayashi");
410MODULE_AUTHOR("Hiroshi DOYU");