msm: smd_tty: Introduce read available wakelock
The SMD TTY driver locks a wakelock only after reading data from
the SMD channel and is ready to be processed by the TTY framework.
This sometimes causes suspend to be triggered before the SMD TTY
driver reads the data from the SMD channel.
Introduce read available wakelock and lock the wakelock when there is
data available in the SMD channel.
Change-Id: I44dfcff016d9066be18524e4c5b57c544f28f972
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index a6b3d0c..9b2e732 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/smd_tty.c
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -37,6 +37,7 @@
#define MAX_SMD_TTYS 37
#define MAX_TTY_BUF_SIZE 2048
+#define MAX_RA_WAKE_LOCK_NAME_LEN 32
static DEFINE_MUTEX(smd_tty_lock);
@@ -59,6 +60,9 @@
int is_open;
wait_queue_head_t ch_opened_wait_queue;
spinlock_t reset_lock;
+ spinlock_t ra_lock; /* Read Available Lock*/
+ char ra_wake_lock_name[MAX_RA_WAKE_LOCK_NAME_LEN];
+ struct wake_lock ra_wake_lock; /* Read Available Wakelock */
struct smd_config *smd;
};
@@ -122,6 +126,7 @@
int avail;
struct smd_tty_info *info = (struct smd_tty_info *)param;
struct tty_struct *tty = info->tty;
+ unsigned long flags;
if (!tty)
return;
@@ -135,9 +140,14 @@
}
if (test_bit(TTY_THROTTLED, &tty->flags)) break;
+ spin_lock_irqsave(&info->ra_lock, flags);
avail = smd_read_avail(info->ch);
- if (avail == 0)
+ if (avail == 0) {
+ wake_unlock(&info->ra_wake_lock);
+ spin_unlock_irqrestore(&info->ra_lock, flags);
break;
+ }
+ spin_unlock_irqrestore(&info->ra_lock, flags);
if (avail > MAX_TTY_BUF_SIZE)
avail = MAX_TTY_BUF_SIZE;
@@ -188,7 +198,12 @@
if (info->tty)
wake_up_interruptible(&info->tty->write_wait);
}
- tasklet_hi_schedule(&info->tty_tsklt);
+ spin_lock_irqsave(&info->ra_lock, flags);
+ if (smd_read_avail(info->ch)) {
+ wake_lock(&info->ra_wake_lock);
+ tasklet_hi_schedule(&info->tty_tsklt);
+ }
+ spin_unlock_irqrestore(&info->ra_lock, flags);
break;
case SMD_EVENT_OPEN:
@@ -297,6 +312,11 @@
(unsigned long)info);
wake_lock_init(&info->wake_lock, WAKE_LOCK_SUSPEND,
smd_tty[n].smd->port_name);
+ scnprintf(info->ra_wake_lock_name,
+ MAX_RA_WAKE_LOCK_NAME_LEN,
+ "SMD_TTY_%s_RA", smd_tty[n].smd->port_name);
+ wake_lock_init(&info->ra_wake_lock, WAKE_LOCK_SUSPEND,
+ info->ra_wake_lock_name);
if (!info->ch) {
res = smd_named_open_on_edge(smd_tty[n].smd->port_name,
smd_tty[n].smd->edge,
@@ -357,6 +377,7 @@
if (info->ch) {
smd_close(info->ch);
info->ch = 0;
+ wake_lock_destroy(&info->ra_wake_lock);
subsystem_put(info->pil);
}
}
@@ -565,6 +586,7 @@
smd_tty[idx].driver.driver.name = smd_configs[n].dev_name;
smd_tty[idx].driver.driver.owner = THIS_MODULE;
spin_lock_init(&smd_tty[idx].reset_lock);
+ spin_lock_init(&smd_tty[idx].ra_lock);
smd_tty[idx].is_open = 0;
setup_timer(&smd_tty[idx].buf_req_timer, buf_req_retry,
(unsigned long)&smd_tty[idx]);