summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArun Murthy <arun.murthy@stericsson.com>2011-11-25 12:49:12 +0530
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-06-05 10:40:17 +0200
commit9ef60a27aa29dd8cb514685f21c6026263c41a94 (patch)
tree1af4b02dee40dfc4a078d9f81c3d02e2173fc860
parente41f0ad6aa95be14a04dcaa101992d256b8c47d7 (diff)
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 <arun.murthy@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/39815 Reviewed-by: Bibek BASU <bibek.basu@stericsson.com> Reviewed-by: QABUILD Reviewed-by: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
-rw-r--r--arch/arm/mach-ux500/include/mach/mbox-db5500.h2
-rw-r--r--drivers/misc/mbox.c125
2 files changed, 115 insertions, 12 deletions
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);