|
@@ -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)
|
|
|
|
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
|
|
|
|
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)
|
|
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)
|
|
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)
|
|
|
|
|
|
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;
|
|
|
|
+}
|