From 29aef3fdabeef18b65b329b2353bd9469158cf34 Mon Sep 17 00:00:00 2001 From: Arun Murthy Date: Fri, 30 Sep 2011 14:21:55 +0530 Subject: 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 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32680 Reviewed-by: Srinidhi KASAGAR --- arch/arm/mach-ux500/include/mach/mbox-db5500.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch/arm/mach-ux500/include/mach/mbox-db5500.h') 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 }; /** -- cgit v1.2.3 From 9728fed1646a4457003a8862e3cb91a3ccf8bdb6 Mon Sep 17 00:00:00 2001 From: Arun Murthy Date: Fri, 25 Nov 2011 12:49:12 +0530 Subject: u5500-mbox: API to reset mailbox state API that can be used by modem control driver to reset the mailbox state on receiving the modem reset interrupt. This APE will be called in case of modem silen reboot. ST-Ericsson Linux next: NA ST-Ericsson ID: 341807 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Idc7e4eeeaa410185d34c1be9abcb59f4dd0a60af Signed-off-by: Arun Murthy Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/39815 Reviewed-by: Bibek BASU Reviewed-by: QABUILD Reviewed-by: Srinidhi KASAGAR --- arch/arm/mach-ux500/include/mach/mbox-db5500.h | 2 +- drivers/misc/mbox.c | 125 ++++++++++++++++++++++--- 2 files changed, 115 insertions(+), 12 deletions(-) (limited to 'arch/arm/mach-ux500/include/mach/mbox-db5500.h') diff --git a/arch/arm/mach-ux500/include/mach/mbox-db5500.h b/arch/arm/mach-ux500/include/mach/mbox-db5500.h index 24af854befe..2da180b8df6 100644 --- a/arch/arm/mach-ux500/include/mach/mbox-db5500.h +++ b/arch/arm/mach-ux500/include/mach/mbox-db5500.h @@ -89,5 +89,5 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv); * specify "block" in order to block until send is possible). */ int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block); - +void mbox_state_reset(void); #endif /*INC_STE_MBOX_H*/ diff --git a/drivers/misc/mbox.c b/drivers/misc/mbox.c index 6e22653eed9..acea6962478 100644 --- a/drivers/misc/mbox.c +++ b/drivers/misc/mbox.c @@ -60,11 +60,13 @@ #define MBOX_LATCH 1 struct mbox_device_info { + struct mbox *mbox; struct workqueue_struct *mbox_modem_rel_wq; struct work_struct mbox_modem_rel; struct completion mod_req_ack_work; atomic_t ape_state; atomic_t mod_req; + atomic_t mod_reset; }; /* Global list of all mailboxes */ @@ -95,7 +97,7 @@ static void mbox_modem_rel_work(struct work_struct *work) mutex_unlock(&modem_state_mutex); } -static void mbox_modem_req() +static void mbox_modem_req(void) { mutex_lock(&modem_state_mutex); if (!db5500_prcmu_is_modem_requested()) { @@ -123,6 +125,11 @@ int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block) int res = 0; unsigned long flag; + if (atomic_read(&mb->mod_reset)) { + dev_err(&mbox->pdev->dev, + "mbox_send called after modem reset\n"); + return -EINVAL; + } dev_dbg(&(mbox->pdev->dev), "About to buffer 0x%X to mailbox 0x%X." " ri = %d, wi = %d\n", @@ -160,6 +167,12 @@ int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block) * Indicate that we want an IRQ as soon as there is a slot * in the FIFO */ + if (atomic_read(&mb->mod_reset)) { + dev_err(&mbox->pdev->dev, + "modem is in reset state, cannot proceed\n"); + res -EINVAL; + goto exit; + } writel(MBOX_ENABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE); exit: @@ -217,6 +230,10 @@ static ssize_t mbox_read_fifo(struct device *dev, struct platform_device *pdev = to_platform_device(dev); struct mbox *mbox = platform_get_drvdata(pdev); + if (atomic_read(&mb->mod_reset)) { + dev_err(&mbox->pdev->dev, "modem crashed, returning\n"); + return 0; + } if ((readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7) <= 0) return sprintf(buf, "Mailbox is empty\n"); @@ -251,6 +268,11 @@ static int mbox_show(struct seq_file *s, void *data) continue; } + if (atomic_read(&mb->mod_reset)) { + dev_err(&m->pdev->dev, "modem crashed, returning\n"); + spin_unlock(&m->lock); + return 0; + } seq_printf(s, "===========================\n" " MAILBOX %d\n" @@ -330,6 +352,10 @@ static irqreturn_t mbox_irq(int irq, void *arg) int nbr_free; struct mbox *mbox = (struct mbox *) arg; + if (atomic_read(&mb->mod_reset)) { + dev_err(&mbox->pdev->dev, "modem in reset state\n"); + return IRQ_HANDLED; + } spin_lock(&mbox->lock); dev_dbg(&(mbox->pdev->dev), @@ -353,6 +379,11 @@ static irqreturn_t mbox_irq(int irq, void *arg) while ((nbr_free > 0) && (mbox->read_index != mbox->write_index)) { + if (atomic_read(&mb->mod_reset)) { + dev_err(&mbox->pdev->dev, + "modem in reset state\n"); + goto exit; + } /* Write the message and latch it into the FIFO */ writel(mbox->buffer[mbox->read_index], (mbox->virtbase_peer + MBOX_FIFO_DATA)); @@ -368,6 +399,10 @@ static irqreturn_t mbox_irq(int irq, void *arg) (mbox->read_index + 1) % MBOX_BUF_SIZE; } + if (atomic_read(&mb->mod_reset)) { + dev_err(&mbox->pdev->dev, "modem in reset state\n"); + goto exit; + } /* * Check if we still want IRQ:s when there is free * space to send @@ -404,6 +439,10 @@ static irqreturn_t mbox_irq(int irq, void *arg) hrtimer_start(&ape_timer, ktime_set(0, 10*NSEC_PER_MSEC), HRTIMER_MODE_REL); + if (atomic_read(&mb->mod_reset)) { + dev_err(&mbox->pdev->dev, "modem in reset state\n"); + goto exit; + } /* Check if we have any incoming messages */ nbr_occup = readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7; if (nbr_occup == 0) @@ -417,6 +456,10 @@ redo: } atomic_set(&mb->ape_state, 1); + if (atomic_read(&mb->mod_reset)) { + dev_err(&mbox->pdev->dev, "modem in reset state\n"); + goto exit; + } /* Read and acknowledge the message */ mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA); writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE)); @@ -444,13 +487,20 @@ exit: static void mbox_shutdown(struct mbox *mbox) { + if (!mbox->allocated) + return; #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); + /* TODO: Need to check if we can write after modem reset */ + if (!atomic_read(&mb->mod_reset)) { + 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, (void *)mbox); mbox->client_blocked = 0; iounmap(mbox->virtbase_local); iounmap(mbox->virtbase_peer); @@ -459,11 +509,39 @@ static void mbox_shutdown(struct mbox *mbox) mbox->allocated = false; } -void mbox_reset_state(struct mbox *mbox) +/** mbox_state_reset - Reset the mailbox state machine + * + * This function is called on receiving modem reset interrupt. Reset all + * the mailbox state machine, disable irq, cancel timers, shutdown the + * mailboxs and re-enable irq's. + */ +void mbox_state_reset(void) { + struct mbox *mbox = mb->mbox; + + /* Common for all mailbox */ + atomic_set(&mb->mod_reset, 1); + + /* Disable IRQ */ + disable_irq_nosync(IRQ_DB5500_PRCMU_APE_REQ); + disable_irq_nosync(IRQ_DB5500_PRCMU_AC_WAKE_ACK); + + /* Cancel sleep_req timers */ + hrtimer_cancel(&modem_timer); + hrtimer_cancel(&ape_timer); + + /* specific to each mailbox */ list_for_each_entry(mbox, &mboxs, list) { mbox_shutdown(mbox); } + + /* Reset mailbox state machine */ + atomic_set(&mb->mod_req, 0); + atomic_set(&mb->ape_state, 0); + + /* Enable irq */ + enable_irq(IRQ_DB5500_PRCMU_APE_REQ); + enable_irq(IRQ_DB5500_PRCMU_AC_WAKE_ACK); } @@ -474,6 +552,13 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv) int res; struct mbox *mbox; + /* + * set mod_reset flag to '0', clients calling this APE should make sure + * that modem is rebooted after MSR. Mailbox doesnt have any means of + * knowing the boot status of modem. + */ + atomic_set(&mb->mod_reset, 0); + mbox = get_mbox_with_id(mbox_id); if (mbox == NULL) { dev_err(&(mbox->pdev->dev), "Incorrect mailbox id: %d!\n", @@ -507,7 +592,7 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv) dev_err(&(mbox->pdev->dev), "Unable to retrieve mbox peer resource\n"); mbox = NULL; - goto exit; + goto free_mbox; } dev_dbg(&(mbox->pdev->dev), "Resource name: %s start: 0x%X, end: 0x%X\n", @@ -516,7 +601,7 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv) if (!mbox->virtbase_peer) { dev_err(&(mbox->pdev->dev), "Unable to ioremap peer mbox\n"); mbox = NULL; - goto exit; + goto free_mbox; } dev_dbg(&(mbox->pdev->dev), "ioremapped peer physical: (0x%X-0x%X) to virtual: 0x%X\n", @@ -530,7 +615,7 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv) dev_err(&(mbox->pdev->dev), "Unable to retrieve mbox local resource\n"); mbox = NULL; - goto exit; + goto free_map; } dev_dbg(&(mbox->pdev->dev), "Resource name: %s start: 0x%X, end: 0x%X\n", @@ -539,7 +624,7 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv) if (!mbox->virtbase_local) { dev_err(&(mbox->pdev->dev), "Unable to ioremap local mbox\n"); mbox = NULL; - goto exit; + goto free_map; } dev_dbg(&(mbox->pdev->dev), "ioremapped local physical: (0x%X-0x%X) to virtual: 0x%X\n", @@ -554,7 +639,7 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv) dev_err(&(mbox->pdev->dev), "Unable to retrieve mbox irq resource\n"); mbox = NULL; - goto exit; + goto free_map1; } dev_dbg(&(mbox->pdev->dev), "Allocating irq %d...\n", mbox->irq); @@ -568,6 +653,13 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv) goto exit; } + /* check if modem has reset */ + if (atomic_read(&mb->mod_reset)) { + dev_err(&mbox->pdev->dev, + "modem is in reset state, cannot proceed\n"); + mbox = NULL; + goto free_irq; + } /* Set up mailbox to not launch IRQ on free space in mailbox */ writel(MBOX_DISABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE); @@ -592,10 +684,19 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv) mbox->dentry = debugfs_create_file("mbox", S_IFREG | S_IRUGO, NULL, NULL, &mbox_operations); #endif - dev_info(&(mbox->pdev->dev), "Mailbox driver with index %d initiated!\n", mbox_id); + return mbox; +free_irq: + free_irq(mbox->irq, (void *)mbox); +free_map1: + iounmap(mbox->virtbase_local); +free_map: + iounmap(mbox->virtbase_peer); +free_mbox: + mbox->client_data = NULL; + mbox->cb = NULL; exit: return mbox; } @@ -637,6 +738,7 @@ int __init mbox_probe(struct platform_device *pdev) spin_lock_init(&mbox->lock); platform_set_drvdata(pdev, mbox); + mb->mbox = mbox; dev_info(&(pdev->dev), "Mailbox driver loaded\n"); return res; @@ -736,6 +838,7 @@ static int __init mbox_init(void) atomic_set(&mb_di->ape_state, 0); atomic_set(&mb_di->mod_req, 0); + atomic_set(&mb_di->mod_reset, 0); err = request_irq(IRQ_DB5500_PRCMU_APE_REQ, mbox_prcmu_ape_req_handler, IRQF_NO_SUSPEND, "ape_req", NULL); -- cgit v1.2.3