diff options
| author | Liangwei Dong <liangwei@codeaurora.org> | 2017-10-26 06:47:52 -0400 |
|---|---|---|
| committer | Liangwei Dong <liangwei@codeaurora.org> | 2017-11-03 02:32:30 -0400 |
| commit | ca76249c74434fe68afacca3ccfc5cf3a2b28e51 (patch) | |
| tree | a286bc982ebdc2d0f9d8192955d65b26eec64b83 | |
| parent | 11734d0451bd4ba9722ca5b2609490f66ead332c (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.c | 4 | ||||
| -rw-r--r-- | drivers/net/wireless/cnss2/main.c | 43 | ||||
| -rw-r--r-- | drivers/net/wireless/cnss2/main.h | 7 | ||||
| -rw-r--r-- | drivers/net/wireless/cnss2/qmi.c | 12 |
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); |
