From 0e203b4b2fceee9a6a1ae3236f4e1bbe03db0320 Mon Sep 17 00:00:00 2001 From: Yue Ma Date: Mon, 11 May 2020 17:35:27 -0700 Subject: [PATCH] cnss2: Add mutex protection between unregister driver and idle restart Since idle restart is a multiple stages power up sequence, there will be race conditions when idle restart and unregister driver (which is power down sequence) come at the same time. Add mutex protection for them so that they can be serialized completely. Change-Id: Icc28b5f759cd690cb505b16ab70eaa4abaf2e4cc Signed-off-by: Yue Ma --- drivers/net/wireless/cnss2/main.c | 5 +++++ drivers/net/wireless/cnss2/main.h | 1 + drivers/net/wireless/cnss2/pci.c | 8 +++++--- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index a5c419a6c451..5a8e8eebbcbe 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -628,6 +628,8 @@ int cnss_idle_restart(struct device *dev) return -ENODEV; } + mutex_lock(&plat_priv->driver_ops_lock); + cnss_pr_dbg("Doing idle restart\n"); reinit_completion(&plat_priv->power_up_complete); @@ -666,9 +668,11 @@ int cnss_idle_restart(struct device *dev) goto out; } + mutex_unlock(&plat_priv->driver_ops_lock); return 0; out: + mutex_unlock(&plat_priv->driver_ops_lock); return ret; } EXPORT_SYMBOL(cnss_idle_restart); @@ -2146,6 +2150,7 @@ static int cnss_misc_init(struct cnss_plat_data *plat_priv) init_completion(&plat_priv->rddm_complete); init_completion(&plat_priv->recovery_complete); mutex_init(&plat_priv->dev_lock); + mutex_init(&plat_priv->driver_ops_lock); return 0; } diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index c1fac9e0b05d..0302ea83a7b7 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -372,6 +372,7 @@ struct cnss_plat_data { struct completion power_up_complete; struct completion cal_complete; struct mutex dev_lock; /* mutex for register access through debugfs */ + struct mutex driver_ops_lock; /* mutex for external driver ops */ u32 device_freq_hz; u32 diag_reg_read_addr; u32 diag_reg_read_mem_type; diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index be41b74f88bd..00c8f6998ccf 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -2179,9 +2179,9 @@ void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver_ops) return; } - if (plat_priv->device_id == QCA6174_DEVICE_ID || - !(test_bit(CNSS_DRIVER_IDLE_RESTART, &plat_priv->driver_state) || - test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state))) + mutex_lock(&plat_priv->driver_ops_lock); + + if (plat_priv->device_id == QCA6174_DEVICE_ID) goto skip_wait_power_up; timeout = cnss_get_qmi_timeout(plat_priv); @@ -2210,6 +2210,8 @@ skip_wait_recovery: cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_UNREGISTER_DRIVER, CNSS_EVENT_SYNC_UNKILLABLE, NULL); + + mutex_unlock(&plat_priv->driver_ops_lock); } EXPORT_SYMBOL(cnss_wlan_unregister_driver);