diff options
author | Arun Murthy <arun.murthy@stericsson.com> | 2011-09-30 14:21:55 +0530 |
---|---|---|
committer | Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com> | 2011-09-30 11:29:11 +0200 |
commit | 7076f3f9150973c05f8687cc5b97b8944350f54b (patch) | |
tree | 1a0cad3ecb84b3572867dba2f933c3f4e43027f2 | |
parent | 9a901dfdc8c1b1dfda8bfe777e3a4445692dabf7 (diff) |
ux500-mbox: Proper shutdown of mailbox
Implement clean shutdown of mailbox, which includes, unmapping the io mapped
memory, free the requested interrupt, reset all state machine and remove from
list. A function has been added to reset the mailbox which will be used in
case of MSR.
ST-Ericsson Linux next: NA
ST-Ericsson ID: 341807
ST-Ericsson FOSS-OUT ID: Trivial
Change-Id: I1435345d155717a5276a7a5d74da84d3eeef7f61
Signed-off-by: Arun Murthy <arun.murthy@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32680
Reviewed-by: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
-rw-r--r-- | arch/arm/mach-ux500/include/mach/mbox-db5500.h | 5 | ||||
-rw-r--r-- | drivers/misc/mbox.c | 79 |
2 files changed, 77 insertions, 7 deletions
diff --git a/arch/arm/mach-ux500/include/mach/mbox-db5500.h b/arch/arm/mach-ux500/include/mach/mbox-db5500.h index 7f9da4d2fbd..24af854befe 100644 --- a/arch/arm/mach-ux500/include/mach/mbox-db5500.h +++ b/arch/arm/mach-ux500/include/mach/mbox-db5500.h @@ -40,6 +40,7 @@ typedef void mbox_recv_cb_t (u32 mbox_msg, void *priv); * @lock: Spinlock to protect this mailbox instance. * @write_index: Index in internal buffer to write to. * @read_index: Index in internal buffer to read from. + * @irq: mailbox interrupt. * @allocated: Indicates whether this particular mailbox * id has been allocated by someone. */ @@ -57,7 +58,11 @@ struct mbox { spinlock_t lock; u8 write_index; u8 read_index; + int irq; bool allocated; +#if defined(CONFIG_DEBUG_FS) + struct dentry *dentry; +#endif }; /** diff --git a/drivers/misc/mbox.c b/drivers/misc/mbox.c index 73f34069d84..9bd5db9b23c 100644 --- a/drivers/misc/mbox.c +++ b/drivers/misc/mbox.c @@ -380,11 +380,35 @@ exit: return IRQ_HANDLED; } +static void mbox_shutdown(struct mbox *mbox) +{ +#if defined(CONFIG_DEBUG_FS) + debugfs_remove(mbox->dentry); + device_remove_file(&mbox->pdev->dev, &dev_attr_fifo); +#endif + writel(MBOX_DISABLE_IRQ, mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP); + writel(MBOX_DISABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE); + free_irq(mbox->irq, NULL); + mbox->client_blocked = 0; + iounmap(mbox->virtbase_local); + iounmap(mbox->virtbase_peer); + mbox->cb = NULL; + mbox->client_data = NULL; + mbox->allocated = false; +} + +void mbox_reset_state(struct mbox *mbox) +{ + list_for_each_entry(mbox, &mboxs, list) { + mbox_shutdown(mbox); + } +} + + /* Setup is executed once for each mbox pair */ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv) { struct resource *resource; - int irq; int res; struct mbox *mbox; @@ -463,21 +487,21 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv) mbox->client_blocked = 0; /* Get IRQ for mailbox and allocate it */ - irq = platform_get_irq_byname(mbox->pdev, "mbox_irq"); - if (irq < 0) { + mbox->irq = platform_get_irq_byname(mbox->pdev, "mbox_irq"); + if (mbox->irq < 0) { dev_err(&(mbox->pdev->dev), "Unable to retrieve mbox irq resource\n"); mbox = NULL; goto exit; } - dev_dbg(&(mbox->pdev->dev), "Allocating irq %d...\n", irq); - res = request_threaded_irq(irq, NULL, mbox_irq, + dev_dbg(&(mbox->pdev->dev), "Allocating irq %d...\n", mbox->irq); + res = request_threaded_irq(mbox->irq, NULL, mbox_irq, IRQF_NO_SUSPEND | IRQF_ONESHOT, mbox->name, (void *) mbox); if (res < 0) { dev_err(&(mbox->pdev->dev), - "Unable to allocate mbox irq %d\n", irq); + "Unable to allocate mbox irq %d\n", mbox->irq); mbox = NULL; goto exit; } @@ -503,7 +527,7 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv) dev_warn(&(mbox->pdev->dev), "Unable to create mbox sysfs entry"); - (void) debugfs_create_file("mbox", S_IFREG | S_IRUGO, NULL, + mbox->dentry = debugfs_create_file("mbox", S_IFREG | S_IRUGO, NULL, NULL, &mbox_operations); #endif @@ -550,16 +574,57 @@ static int __exit mbox_remove(struct platform_device *pdev) { struct mbox *mbox = platform_get_drvdata(pdev); + mbox_shutdown(mbox); list_del(&mbox->list); kfree(mbox); return 0; } +#ifdef CONFIG_PM +int mbox_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mbox *mbox = platform_get_drvdata(pdev); + + /* + * Nothing to be done for now, once APE-Modem power management is + * in place communication will have to be stopped. + */ + + list_for_each_entry(mbox, &mboxs, list) { + if (mbox->client_blocked) + return -EBUSY; + } + return 0; +} + +int mbox_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mbox *mbox = platform_get_drvdata(pdev); + + /* + * Nothing to be done for now, once APE-Modem power management is + * in place communication will have to be resumed. + */ + + return 0; +} + +static const struct dev_pm_ops mbox_dev_pm_ops = { + .suspend_noirq = mbox_suspend, + .resume_noirq = mbox_resume, +}; +#endif + static struct platform_driver mbox_driver = { .remove = __exit_p(mbox_remove), .driver = { .name = MBOX_NAME, .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &mbox_dev_pm_ops, +#endif }, }; |