diff options
| author | Tony Lindgren <tony@atomide.com> | 2010-08-04 09:10:38 -0400 |
|---|---|---|
| committer | Tony Lindgren <tony@atomide.com> | 2010-08-04 09:10:38 -0400 |
| commit | d21872b3683ff37f73c68993749a6e6aeeaed265 (patch) | |
| tree | 0a84ae436325d6e646fe987516fb6bfccfff8a1c | |
| parent | 80690ccc41f01df6edfb6684006824d8edff189e (diff) | |
| parent | b3e69146f43fa351aa3cdffe2e76ec42174da612 (diff) | |
Merge branch 'v2.6.35-omap-mailbox-for-next' of git://gitorious.org/~doyu/lk/mainline into omap-for-linus
Conflicts:
arch/arm/mach-omap1/devices.c
| -rw-r--r-- | arch/arm/mach-omap1/mailbox.c | 55 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/devices.c | 6 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/mailbox.c | 182 | ||||
| -rw-r--r-- | arch/arm/plat-omap/Kconfig | 9 | ||||
| -rw-r--r-- | arch/arm/plat-omap/include/plat/mailbox.h | 20 | ||||
| -rw-r--r-- | arch/arm/plat-omap/mailbox.c | 248 |
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 | }; |
| 144 | EXPORT_SYMBOL(mbox_dsp_info); | 141 | |
| 142 | struct omap_mbox *omap1_mboxes[] = { &mbox_dsp_info, NULL }; | ||
| 145 | 143 | ||
| 146 | static int __devinit omap1_mbox_probe(struct platform_device *pdev) | 144 | static 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 | ||
| 181 | static int __devexit omap1_mbox_remove(struct platform_device *pdev) | 168 | static 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 | }; |
| 161 | static int omap2_mbox_resources_sz = ARRAY_SIZE(omap2_mbox_resources); | 163 | static 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 | }; |
| 179 | static int omap3_mbox_resources_sz = ARRAY_SIZE(omap3_mbox_resources); | 182 | static 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 | }; |
| 200 | static int omap4_mbox_resources_sz = ARRAY_SIZE(omap4_mbox_resources); | 204 | static 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 | ||
| 206 | static struct platform_device mbox_device = { | 210 | static 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 */ |
| 287 | static struct omap_mbox2_priv omap2_mbox_dsp_priv = { | 286 | static 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 | ||
| 302 | struct 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) | ||
| 310 | struct omap_mbox *omap3_mboxes[] = { &mbox_dsp_info, NULL }; | ||
| 311 | #endif | ||
| 312 | |||
| 313 | #if defined(CONFIG_ARCH_OMAP2420) | ||
| 314 | /* IVA */ | ||
| 315 | static 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 | |||
| 331 | static struct omap_mbox mbox_iva_info = { | ||
| 332 | .name = "iva", | ||
| 333 | .ops = &omap2_mbox_ops, | ||
| 334 | .priv = &omap2_mbox_iva_priv, | ||
| 335 | }; | ||
| 303 | 336 | ||
| 337 | struct 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) |
| 306 | to use this*/ | 341 | /* OMAP4 */ |
| 307 | static struct omap_mbox2_priv omap2_mbox_1_priv = { | 342 | static 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 | }; |
| 328 | EXPORT_SYMBOL(mbox_1_info); | ||
| 329 | |||
| 330 | struct omap_mbox mbox_dsp_info = { | ||
| 331 | .name = "dsp", | ||
| 332 | .ops = &omap2_mbox_ops, | ||
| 333 | .priv = &omap2_mbox_dsp_priv, | ||
| 334 | }; | ||
| 335 | EXPORT_SYMBOL(mbox_dsp_info); | ||
| 336 | 363 | ||
| 337 | static struct omap_mbox2_priv omap2_mbox_2_priv = { | 364 | static 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 | }; |
| 358 | EXPORT_SYMBOL(mbox_2_info); | ||
| 359 | |||
| 360 | |||
| 361 | #if defined(CONFIG_ARCH_OMAP2420) /* IVA */ | ||
| 362 | static 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 | ||
| 378 | static struct omap_mbox mbox_iva_info = { | 386 | struct 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 | ||
| 385 | static int __devinit omap2_mbox_probe(struct platform_device *pdev) | 389 | static 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 | ||
| 446 | err_dsp: | ||
| 447 | iounmap(mbox_base); | ||
| 448 | return ret; | 437 | return ret; |
| 449 | } | 438 | } |
| 450 | 439 | ||
| 451 | static int __devexit omap2_mbox_remove(struct platform_device *pdev) | 440 | static 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 | ||
| 487 | MODULE_LICENSE("GPL v2"); | 468 | MODULE_LICENSE("GPL v2"); |
| 488 | MODULE_DESCRIPTION("omap mailbox: omap2/3/4 architecture specific functions"); | 469 | MODULE_DESCRIPTION("omap mailbox: omap2/3/4 architecture specific functions"); |
| 489 | MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>, Paul Mundt"); | 470 | MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>"); |
| 490 | MODULE_ALIAS("platform:"DRV_NAME); | 471 | MODULE_AUTHOR("Paul Mundt"); |
| 472 | MODULE_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 | ||
| 91 | config 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 | |||
| 91 | config OMAP_IOMMU | 100 | config 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 | ||
| 11 | typedef u32 mbox_msg_t; | 12 | typedef u32 mbox_msg_t; |
| 12 | struct omap_mbox; | 13 | struct omap_mbox; |
| @@ -42,7 +43,7 @@ struct omap_mbox_ops { | |||
| 42 | 43 | ||
| 43 | struct omap_mbox_queue { | 44 | struct 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 { | |||
| 52 | struct omap_mbox { | 53 | struct 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 | ||
| 70 | int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg); | 62 | int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg); |
| @@ -73,8 +65,8 @@ void omap_mbox_init_seq(struct omap_mbox *); | |||
| 73 | struct omap_mbox *omap_mbox_get(const char *); | 65 | struct omap_mbox *omap_mbox_get(const char *); |
| 74 | void omap_mbox_put(struct omap_mbox *); | 66 | void omap_mbox_put(struct omap_mbox *); |
| 75 | 67 | ||
| 76 | int omap_mbox_register(struct device *parent, struct omap_mbox *); | 68 | int omap_mbox_register(struct device *parent, struct omap_mbox **); |
| 77 | int omap_mbox_unregister(struct omap_mbox *); | 69 | int omap_mbox_unregister(void); |
| 78 | 70 | ||
| 79 | static inline void omap_mbox_save_ctx(struct omap_mbox *mbox) | 71 | static 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 | ||
| 32 | static struct workqueue_struct *mboxd; | 34 | static struct workqueue_struct *mboxd; |
| 33 | static struct omap_mbox *mboxes; | 35 | static struct omap_mbox **mboxes; |
| 34 | static DEFINE_RWLOCK(mboxes_lock); | 36 | static bool rq_full; |
| 35 | 37 | ||
| 36 | static int mbox_configured; | 38 | static int mbox_configured; |
| 39 | static DEFINE_MUTEX(mbox_configured_lock); | ||
| 40 | |||
| 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)"); | ||
| 37 | 44 | ||
| 38 | /* Mailbox FIFO handle functions */ | 45 | /* Mailbox FIFO handle functions */ |
| 39 | static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) | 46 | static 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 | */ |
| 70 | static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) | 77 | static 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 | |||
| 86 | int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) | 91 | int 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; | 108 | out: |
| 109 | spin_unlock(&mq->lock); | ||
| 110 | return ret; | ||
| 100 | } | 111 | } |
| 101 | EXPORT_SYMBOL(omap_mbox_msg_send); | 112 | EXPORT_SYMBOL(omap_mbox_msg_send); |
| 102 | 113 | ||
| 103 | static void mbox_tx_tasklet(unsigned long tx_data) | 114 | static 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 | */ |
| 156 | static void mbox_txq_fn(struct request_queue *q) | ||
| 157 | { | ||
| 158 | } | ||
| 159 | |||
| 160 | static void mbox_rxq_fn(struct request_queue *q) | ||
| 161 | { | ||
| 162 | } | ||
| 163 | |||
| 164 | static void __mbox_tx_interrupt(struct omap_mbox *mbox) | 157 | static 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 | ||
| 171 | static void __mbox_rx_interrupt(struct omap_mbox *mbox) | 164 | static 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 | ||
| 209 | static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, | 205 | static 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 | ||
| 240 | static void mbox_queue_free(struct omap_mbox_queue *q) | 231 | static 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 | ||
| 299 | static void omap_mbox_fini(struct omap_mbox *mbox) | 290 | static 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 | |||
| 316 | static 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 | ||
| 328 | struct omap_mbox *omap_mbox_get(const char *name) | 308 | struct 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 | } |
| 354 | EXPORT_SYMBOL(omap_mbox_put); | 335 | EXPORT_SYMBOL(omap_mbox_put); |
| 355 | 336 | ||
| 356 | int omap_mbox_register(struct device *parent, struct omap_mbox *mbox) | 337 | static struct class omap_mbox_class = { .name = "mbox", }; |
| 338 | |||
| 339 | int 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 | ||
| 378 | err_find: | 359 | err_out: |
| 360 | while (i--) | ||
| 361 | device_unregister(mboxes[i]->dev); | ||
| 379 | return ret; | 362 | return ret; |
| 380 | } | 363 | } |
| 381 | EXPORT_SYMBOL(omap_mbox_register); | 364 | EXPORT_SYMBOL(omap_mbox_register); |
| 382 | 365 | ||
| 383 | int omap_mbox_unregister(struct omap_mbox *mbox) | 366 | int 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 | } |
| 402 | EXPORT_SYMBOL(omap_mbox_unregister); | 378 | EXPORT_SYMBOL(omap_mbox_unregister); |
| 403 | 379 | ||
| 404 | static int __init omap_mbox_init(void) | 380 | static 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 | } |
| 412 | module_init(omap_mbox_init); | 398 | subsys_initcall(omap_mbox_init); |
| 413 | 399 | ||
| 414 | static void __exit omap_mbox_exit(void) | 400 | static void __exit omap_mbox_exit(void) |
| 415 | { | 401 | { |
| 416 | destroy_workqueue(mboxd); | 402 | destroy_workqueue(mboxd); |
| 403 | class_unregister(&omap_mbox_class); | ||
| 417 | } | 404 | } |
| 418 | module_exit(omap_mbox_exit); | 405 | module_exit(omap_mbox_exit); |
| 419 | 406 | ||
| 420 | MODULE_LICENSE("GPL v2"); | 407 | MODULE_LICENSE("GPL v2"); |
| 421 | MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging"); | 408 | MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging"); |
| 422 | MODULE_AUTHOR("Toshihiro Kobayashi and Hiroshi DOYU"); | 409 | MODULE_AUTHOR("Toshihiro Kobayashi"); |
| 410 | MODULE_AUTHOR("Hiroshi DOYU"); | ||
