summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiangwei Dong <liangwei@codeaurora.org>2017-10-26 06:47:52 -0400
committerLiangwei Dong <liangwei@codeaurora.org>2017-11-03 02:32:30 -0400
commitca76249c74434fe68afacca3ccfc5cf3a2b28e51 (patch)
treea286bc982ebdc2d0f9d8192955d65b26eec64b83
parent11734d0451bd4ba9722ca5b2609490f66ead332c (diff)
net:wireless:cnss2: Fix driver loading failure
When driver loading and registering to cnss, the interruptible wait in cnss_driver_event_post could be woken up by signal. In this driver register failure case, the __hdd_module_init will release all the driver resource. But the cnss_driver_event_work is still probing the driver normally in the same time. The driver state mismatch will cause crash. Fixed by using non interruptible wait for driver register Change-Id: I6e99e83f1f3312e0b7d74e432ce90ff23631bc19 Signed-off-by: Liangwei Dong <liangwei@codeaurora.org> CRs-Fixed: 2134631
-rw-r--r--drivers/net/wireless/cnss2/debug.c4
-rw-r--r--drivers/net/wireless/cnss2/main.c43
-rw-r--r--drivers/net/wireless/cnss2/main.h7
-rw-r--r--drivers/net/wireless/cnss2/qmi.c12
4 files changed, 37 insertions, 29 deletions
diff --git a/drivers/net/wireless/cnss2/debug.c b/drivers/net/wireless/cnss2/debug.c
index 916820ee4f5d..5e2d44ce1c55 100644
--- a/drivers/net/wireless/cnss2/debug.c
+++ b/drivers/net/wireless/cnss2/debug.c
@@ -168,11 +168,11 @@ static ssize_t cnss_dev_boot_debug_write(struct file *fp,
set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
ret = cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_POWER_UP,
- true, NULL);
+ CNSS_EVENT_SYNC, NULL);
} else if (sysfs_streq(cmd, "shutdown")) {
ret = cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_POWER_DOWN,
- true, NULL);
+ CNSS_EVENT_SYNC, NULL);
clear_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
} else {
cnss_pr_err("Device boot debugfs command is invalid\n");
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
index d3afb516b119..3ebb0db5335a 100644
--- a/drivers/net/wireless/cnss2/main.c
+++ b/drivers/net/wireless/cnss2/main.c
@@ -712,19 +712,19 @@ static char *cnss_driver_event_to_str(enum cnss_driver_event_type type)
int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
enum cnss_driver_event_type type,
- bool sync, void *data)
+ u32 flags, void *data)
{
struct cnss_driver_event *event;
- unsigned long flags;
+ unsigned long irq_flags;
int gfp = GFP_KERNEL;
int ret = 0;
if (!plat_priv)
return -ENODEV;
- cnss_pr_dbg("Posting event: %s(%d)%s, state: 0x%lx\n",
+ cnss_pr_dbg("Posting event: %s(%d)%s, state: 0x%lx flags: 0x%0x\n",
cnss_driver_event_to_str(type), type,
- sync ? "-sync" : "", plat_priv->driver_state);
+ flags ? "-sync" : "", plat_priv->driver_state, flags);
if (type >= CNSS_DRIVER_EVENT_MAX) {
cnss_pr_err("Invalid Event type: %d, can't post", type);
@@ -744,31 +744,33 @@ int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
event->data = data;
init_completion(&event->complete);
event->ret = CNSS_EVENT_PENDING;
- event->sync = sync;
+ event->sync = !!(flags & CNSS_EVENT_SYNC);
- spin_lock_irqsave(&plat_priv->event_lock, flags);
+ spin_lock_irqsave(&plat_priv->event_lock, irq_flags);
list_add_tail(&event->list, &plat_priv->event_list);
- spin_unlock_irqrestore(&plat_priv->event_lock, flags);
+ spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
queue_work(plat_priv->event_wq, &plat_priv->event_work);
- if (!sync)
+ if (!(flags & CNSS_EVENT_SYNC))
goto out;
- ret = wait_for_completion_interruptible(&event->complete);
+ if (flags & CNSS_EVENT_UNINTERRUPTIBLE)
+ wait_for_completion(&event->complete);
+ else
+ ret = wait_for_completion_interruptible(&event->complete);
cnss_pr_dbg("Completed event: %s(%d), state: 0x%lx, ret: %d/%d\n",
cnss_driver_event_to_str(type), type,
plat_priv->driver_state, ret, event->ret);
-
- spin_lock_irqsave(&plat_priv->event_lock, flags);
+ spin_lock_irqsave(&plat_priv->event_lock, irq_flags);
if (ret == -ERESTARTSYS && event->ret == CNSS_EVENT_PENDING) {
event->sync = false;
- spin_unlock_irqrestore(&plat_priv->event_lock, flags);
+ spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
ret = -EINTR;
goto out;
}
- spin_unlock_irqrestore(&plat_priv->event_lock, flags);
+ spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
ret = event->ret;
kfree(event);
@@ -793,7 +795,7 @@ int cnss_power_up(struct device *dev)
ret = cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_POWER_UP,
- true, NULL);
+ CNSS_EVENT_SYNC, NULL);
if (ret)
goto out;
@@ -831,7 +833,7 @@ int cnss_power_down(struct device *dev)
return cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_POWER_DOWN,
- true, NULL);
+ CNSS_EVENT_SYNC, NULL);
}
EXPORT_SYMBOL(cnss_power_down);
@@ -852,7 +854,8 @@ int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
ret = cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_REGISTER_DRIVER,
- true, driver_ops);
+ CNSS_EVENT_SYNC_UNINTERRUPTIBLE,
+ driver_ops);
return ret;
}
EXPORT_SYMBOL(cnss_wlan_register_driver);
@@ -868,7 +871,7 @@ void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver_ops)
cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
- true, NULL);
+ CNSS_EVENT_SYNC, NULL);
}
EXPORT_SYMBOL(cnss_wlan_unregister_driver);
@@ -1554,7 +1557,7 @@ void cnss_schedule_recovery(struct device *dev,
data->reason = reason;
cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_RECOVERY,
- false, data);
+ 0, data);
}
EXPORT_SYMBOL(cnss_schedule_recovery);
@@ -1601,7 +1604,7 @@ int cnss_force_fw_assert(struct device *dev)
cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
- false, NULL);
+ 0, NULL);
return 0;
}
@@ -2113,7 +2116,7 @@ static ssize_t cnss_fs_ready_store(struct device *dev,
if (fs_ready == FILE_SYSTEM_READY) {
cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START,
- true, NULL);
+ CNSS_EVENT_SYNC, NULL);
}
return count;
diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h
index 4bf1c27d99de..81b5de8bc66f 100644
--- a/drivers/net/wireless/cnss2/main.h
+++ b/drivers/net/wireless/cnss2/main.h
@@ -25,6 +25,11 @@
#define MAX_NO_OF_MAC_ADDR 4
+#define CNSS_EVENT_SYNC BIT(0)
+#define CNSS_EVENT_UNINTERRUPTIBLE BIT(1)
+#define CNSS_EVENT_SYNC_UNINTERRUPTIBLE (CNSS_EVENT_SYNC | \
+ CNSS_EVENT_UNINTERRUPTIBLE)
+
enum cnss_dev_bus_type {
CNSS_BUS_NONE = -1,
CNSS_BUS_PCI,
@@ -205,7 +210,7 @@ void *cnss_bus_dev_to_bus_priv(struct device *dev);
struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev);
int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
enum cnss_driver_event_type type,
- bool sync, void *data);
+ u32 flags, void *data);
int cnss_get_vreg(struct cnss_plat_data *plat_priv);
int cnss_get_pinctrl(struct cnss_plat_data *plat_priv);
int cnss_power_on_device(struct cnss_plat_data *plat_priv);
diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c
index e010e2c39f02..f4344aee54ee 100644
--- a/drivers/net/wireless/cnss2/qmi.c
+++ b/drivers/net/wireless/cnss2/qmi.c
@@ -130,13 +130,13 @@ static int cnss_wlfw_clnt_svc_event_notifier(struct notifier_block *nb,
case QMI_SERVER_ARRIVE:
ret = cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_SERVER_ARRIVE,
- false, NULL);
+ 0, NULL);
break;
case QMI_SERVER_EXIT:
ret = cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_SERVER_EXIT,
- false, NULL);
+ 0, NULL);
break;
default:
cnss_pr_dbg("Invalid QMI service event: %ld\n", code);
@@ -278,7 +278,7 @@ static int cnss_wlfw_request_mem_ind_hdlr(struct cnss_plat_data *plat_priv,
fw_mem->size = ind_msg.size;
cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_REQUEST_MEM,
- false, NULL);
+ 0, NULL);
return 0;
}
@@ -906,17 +906,17 @@ static void cnss_wlfw_clnt_ind(struct qmi_handle *handle,
case QMI_WLFW_FW_MEM_READY_IND_V01:
cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_FW_MEM_READY,
- false, NULL);
+ 0, NULL);
break;
case QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01:
cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE,
- false, NULL);
+ 0, NULL);
break;
case QMI_WLFW_FW_READY_IND_V01:
cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_FW_READY,
- false, NULL);
+ 0, NULL);
break;
case QMI_WLFW_PIN_CONNECT_RESULT_IND_V01:
cnss_qmi_pin_result_ind_hdlr(plat_priv, msg, msg_len);