Commit 68810c5d authored by Zhu Yi's avatar Zhu Yi Committed by John W. Linville

iwmc3200wifi: add a mutex to protect iwm_reset_worker

The patch adds a mutex to protect the iwm_reset_worker against netdev
ndo_open and ndo_stop because all of them call iwm_up and iwm_down in
the implementation. Note the latter two are already protected by
rtnl. So if iwm_reset_worker is not required in the future, the mutex
can also be removed.
Signed-off-by: default avatarZhu Yi <yi.zhu@intel.com>
Signed-off-by: default avatarSamuel Ortiz <samuel.ortiz@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 4e9aa52e
...@@ -288,6 +288,7 @@ struct iwm_priv { ...@@ -288,6 +288,7 @@ struct iwm_priv {
u8 *eeprom; u8 *eeprom;
struct timer_list watchdog; struct timer_list watchdog;
struct work_struct reset_worker; struct work_struct reset_worker;
struct mutex mutex;
struct rfkill *rfkill; struct rfkill *rfkill;
char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
......
...@@ -112,6 +112,9 @@ static void iwm_statistics_request(struct work_struct *work) ...@@ -112,6 +112,9 @@ static void iwm_statistics_request(struct work_struct *work)
iwm_send_umac_stats_req(iwm, 0); iwm_send_umac_stats_req(iwm, 0);
} }
int __iwm_up(struct iwm_priv *iwm);
int __iwm_down(struct iwm_priv *iwm);
static void iwm_reset_worker(struct work_struct *work) static void iwm_reset_worker(struct work_struct *work)
{ {
struct iwm_priv *iwm; struct iwm_priv *iwm;
...@@ -120,6 +123,19 @@ static void iwm_reset_worker(struct work_struct *work) ...@@ -120,6 +123,19 @@ static void iwm_reset_worker(struct work_struct *work)
iwm = container_of(work, struct iwm_priv, reset_worker); iwm = container_of(work, struct iwm_priv, reset_worker);
/*
* XXX: The iwm->mutex is introduced purely for this reset work,
* because the other users for iwm_up and iwm_down are only netdev
* ndo_open and ndo_stop which are already protected by rtnl.
* Please remove iwm->mutex together if iwm_reset_worker() is not
* required in the future.
*/
if (!mutex_trylock(&iwm->mutex)) {
IWM_WARN(iwm, "We are in the middle of interface bringing "
"UP/DOWN. Skip driver resetting.\n");
return;
}
if (iwm->umac_profile_active) { if (iwm->umac_profile_active) {
profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL); profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL);
if (profile) if (profile)
...@@ -128,10 +144,10 @@ static void iwm_reset_worker(struct work_struct *work) ...@@ -128,10 +144,10 @@ static void iwm_reset_worker(struct work_struct *work)
IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); IWM_ERR(iwm, "Couldn't alloc memory for profile\n");
} }
iwm_down(iwm); __iwm_down(iwm);
while (retry++ < 3) { while (retry++ < 3) {
ret = iwm_up(iwm); ret = __iwm_up(iwm);
if (!ret) if (!ret)
break; break;
...@@ -142,7 +158,7 @@ static void iwm_reset_worker(struct work_struct *work) ...@@ -142,7 +158,7 @@ static void iwm_reset_worker(struct work_struct *work)
IWM_WARN(iwm, "iwm_up() failed: %d\n", ret); IWM_WARN(iwm, "iwm_up() failed: %d\n", ret);
kfree(profile); kfree(profile);
return; goto out;
} }
if (profile) { if (profile) {
...@@ -151,6 +167,9 @@ static void iwm_reset_worker(struct work_struct *work) ...@@ -151,6 +167,9 @@ static void iwm_reset_worker(struct work_struct *work)
iwm_send_mlme_profile(iwm); iwm_send_mlme_profile(iwm);
kfree(profile); kfree(profile);
} }
out:
mutex_unlock(&iwm->mutex);
} }
static void iwm_watchdog(unsigned long data) static void iwm_watchdog(unsigned long data)
...@@ -215,6 +234,7 @@ int iwm_priv_init(struct iwm_priv *iwm) ...@@ -215,6 +234,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
init_timer(&iwm->watchdog); init_timer(&iwm->watchdog);
iwm->watchdog.function = iwm_watchdog; iwm->watchdog.function = iwm_watchdog;
iwm->watchdog.data = (unsigned long)iwm; iwm->watchdog.data = (unsigned long)iwm;
mutex_init(&iwm->mutex);
return 0; return 0;
} }
...@@ -476,7 +496,7 @@ void iwm_link_off(struct iwm_priv *iwm) ...@@ -476,7 +496,7 @@ void iwm_link_off(struct iwm_priv *iwm)
iwm_rx_free(iwm); iwm_rx_free(iwm);
cancel_delayed_work(&iwm->stats_request); cancel_delayed_work_sync(&iwm->stats_request);
memset(wstats, 0, sizeof(struct iw_statistics)); memset(wstats, 0, sizeof(struct iw_statistics));
wstats->qual.updated = IW_QUAL_ALL_INVALID; wstats->qual.updated = IW_QUAL_ALL_INVALID;
...@@ -521,7 +541,7 @@ static int iwm_channels_init(struct iwm_priv *iwm) ...@@ -521,7 +541,7 @@ static int iwm_channels_init(struct iwm_priv *iwm)
return 0; return 0;
} }
int iwm_up(struct iwm_priv *iwm) int __iwm_up(struct iwm_priv *iwm)
{ {
int ret; int ret;
struct iwm_notif *notif_reboot, *notif_ack = NULL; struct iwm_notif *notif_reboot, *notif_ack = NULL;
...@@ -657,7 +677,18 @@ int iwm_up(struct iwm_priv *iwm) ...@@ -657,7 +677,18 @@ int iwm_up(struct iwm_priv *iwm)
return -EIO; return -EIO;
} }
int iwm_down(struct iwm_priv *iwm) int iwm_up(struct iwm_priv *iwm)
{
int ret;
mutex_lock(&iwm->mutex);
ret = __iwm_up(iwm);
mutex_unlock(&iwm->mutex);
return ret;
}
int __iwm_down(struct iwm_priv *iwm)
{ {
int ret; int ret;
...@@ -688,3 +719,14 @@ int iwm_down(struct iwm_priv *iwm) ...@@ -688,3 +719,14 @@ int iwm_down(struct iwm_priv *iwm)
return 0; return 0;
} }
int iwm_down(struct iwm_priv *iwm)
{
int ret;
mutex_lock(&iwm->mutex);
ret = __iwm_down(iwm);
mutex_unlock(&iwm->mutex);
return ret;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment