summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitaly Wool <vitaly.wool@sonyericsson.com>2012-02-29 15:15:22 +0100
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:06:47 +0200
commitfd079d0c51ec4831187025d77de67a99f3ded897 (patch)
tree1c1b39616dcf73f5349f8ca743f0424aa8a19d09
parentd4cdabfadee8cfc9c0cad8e6559a518883bfa153 (diff)
cw1200: Driver hung detection and reporting
If there is a firmware exception or a bh error, report this to the userspace. Userspace will then take care of handling this event, e. g. by reloading the driver completely. Category: bugfix FIX=DMS01117799 ST-Ericsson ID: 401162 ST-Ericsson FOSS-OUT ID: NA Change-Id: I74a8a434f9befbab66ff4cf6c5b5ce82a359c766 Signed-off-by: Vitaly Wool <vitaly.wool@sonyericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/44302 Reviewed-by: QATOOLS Reviewed-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com> Tested-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com>
-rw-r--r--drivers/staging/cw1200/bh.c4
-rw-r--r--drivers/staging/cw1200/debug.c34
-rw-r--r--drivers/staging/cw1200/wsm.c45
3 files changed, 71 insertions, 12 deletions
diff --git a/drivers/staging/cw1200/bh.c b/drivers/staging/cw1200/bh.c
index 4b678f40c40..34bf7d733b8 100644
--- a/drivers/staging/cw1200/bh.c
+++ b/drivers/staging/cw1200/bh.c
@@ -549,6 +549,10 @@ tx:
if (!term) {
cw1200_dbg(CW1200_DBG_ERROR, "[BH] Fatal error, exitting.\n");
priv->bh_error = 1;
+#if defined(CONFIG_CW1200_USE_STE_EXTENSIONS)
+ ieee80211_driver_hang_notify(priv->vif, GFP_KERNEL);
+ cw1200_pm_stay_awake(&priv->pm_state, 3*HZ);
+#endif
/* TODO: schedule_work(recovery) */
#ifndef HAS_PUT_TASK_STRUCT
/* The only reason of having this stupid code here is
diff --git a/drivers/staging/cw1200/debug.c b/drivers/staging/cw1200/debug.c
index 597f94de87f..2056101a3f4 100644
--- a/drivers/staging/cw1200/debug.c
+++ b/drivers/staging/cw1200/debug.c
@@ -426,6 +426,34 @@ static const struct file_operations fops_11n = {
.llseek = default_llseek,
};
+#if defined(CONFIG_CW1200_USE_STE_EXTENSIONS)
+static ssize_t cw1200_hang_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct cw1200_common *priv = file->private_data;
+ char buf[1];
+
+ if (!count)
+ return -EINVAL;
+ if (copy_from_user(buf, user_buf, 1))
+ return -EFAULT;
+
+ if (priv->vif) {
+ cw1200_pm_stay_awake(&priv->pm_state, 3*HZ);
+ ieee80211_driver_hang_notify(priv->vif, GFP_KERNEL);
+ } else
+ return -ENODEV;
+
+ return count;
+}
+
+static const struct file_operations fops_hang = {
+ .open = cw1200_generic_open,
+ .write = cw1200_hang_write,
+ .llseek = default_llseek,
+};
+#endif
+
int cw1200_debug_init(struct cw1200_common *priv)
{
struct cw1200_debug_priv *d = kzalloc(sizeof(struct cw1200_debug_priv),
@@ -451,6 +479,12 @@ int cw1200_debug_init(struct cw1200_common *priv)
d->debugfs_phy, priv, &fops_11n))
goto err;
+#if defined(CONFIG_CW1200_USE_STE_EXTENSIONS)
+ if (!debugfs_create_file("hang", S_IWUSR, d->debugfs_phy,
+ priv, &fops_hang))
+ goto err;
+#endif
+
return 0;
err:
diff --git a/drivers/staging/cw1200/wsm.c b/drivers/staging/cw1200/wsm.c
index 5c52cdbb1c2..bb94d19da08 100644
--- a/drivers/staging/cw1200/wsm.c
+++ b/drivers/staging/cw1200/wsm.c
@@ -1083,9 +1083,15 @@ void wsm_lock_tx(struct cw1200_common *priv)
{
wsm_cmd_lock(priv);
if (atomic_add_return(1, &priv->tx_lock) == 1) {
- WARN_ON(wait_event_timeout(priv->bh_evt_wq,
- !priv->hw_bufs_used, WSM_CMD_LAST_CHANCE_TIMEOUT) <= 0);
- wsm_printk(KERN_DEBUG "[WSM] TX is locked.\n");
+ if (priv->bh_error) {
+ wsm_printk(KERN_ERR "fatal error occured, "
+ "could not take lock\n");
+ } else {
+ WARN_ON(wait_event_timeout(priv->bh_evt_wq,
+ !priv->hw_bufs_used,
+ WSM_CMD_LAST_CHANCE_TIMEOUT) <= 0);
+ wsm_printk(KERN_DEBUG "[WSM] TX is locked.\n");
+ }
}
wsm_cmd_unlock(priv);
}
@@ -1098,20 +1104,29 @@ void wsm_lock_tx_async(struct cw1200_common *priv)
void wsm_flush_tx(struct cw1200_common *priv)
{
- BUG_ON(!atomic_read(&priv->tx_lock));
- WARN_ON(wait_event_timeout(priv->bh_evt_wq,
- !priv->hw_bufs_used, WSM_CMD_LAST_CHANCE_TIMEOUT) <= 0);
+ if (priv->bh_error)
+ wsm_printk(KERN_ERR "fatal error occured, will not flush\n");
+ else {
+ BUG_ON(!atomic_read(&priv->tx_lock));
+ WARN_ON(wait_event_timeout(priv->bh_evt_wq,
+ !priv->hw_bufs_used,
+ WSM_CMD_LAST_CHANCE_TIMEOUT) <= 0);
+ }
}
void wsm_unlock_tx(struct cw1200_common *priv)
{
int tx_lock;
- tx_lock = atomic_sub_return(1, &priv->tx_lock);
- if (tx_lock < 0) {
- BUG_ON(1);
- } else if (tx_lock == 0) {
- cw1200_bh_wakeup(priv);
- wsm_printk(KERN_DEBUG "[WSM] TX is unlocked.\n");
+ if (priv->bh_error)
+ wsm_printk(KERN_ERR "fatal error occured, unlock is unsafe\n");
+ else {
+ tx_lock = atomic_sub_return(1, &priv->tx_lock);
+ if (tx_lock < 0) {
+ BUG_ON(1);
+ } else if (tx_lock == 0) {
+ cw1200_bh_wakeup(priv);
+ wsm_printk(KERN_DEBUG "[WSM] TX is unlocked.\n");
+ }
}
}
@@ -1133,6 +1148,12 @@ int wsm_handle_exception(struct cw1200_common *priv, u8 *data, size_t len)
"unknown error",
};
+#if defined(CONFIG_CW1200_USE_STE_EXTENSIONS)
+ /* Send the event upwards on the FW exception */
+ cw1200_pm_stay_awake(&priv->pm_state, 3*HZ);
+ ieee80211_driver_hang_notify(priv->vif, GFP_KERNEL);
+#endif
+
buf.begin = buf.data = data;
buf.end = &buf.begin[len];