diff options
Diffstat (limited to 'drivers/net/wireless/iwmc3200wifi/main.c')
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/main.c | 64 |
1 files changed, 58 insertions, 6 deletions
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 6a2640f16b6d..8be206d58222 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c | |||
@@ -112,6 +112,9 @@ static void iwm_statistics_request(struct work_struct *work) | |||
112 | iwm_send_umac_stats_req(iwm, 0); | 112 | iwm_send_umac_stats_req(iwm, 0); |
113 | } | 113 | } |
114 | 114 | ||
115 | int __iwm_up(struct iwm_priv *iwm); | ||
116 | int __iwm_down(struct iwm_priv *iwm); | ||
117 | |||
115 | static void iwm_reset_worker(struct work_struct *work) | 118 | static void iwm_reset_worker(struct work_struct *work) |
116 | { | 119 | { |
117 | struct iwm_priv *iwm; | 120 | struct iwm_priv *iwm; |
@@ -120,6 +123,19 @@ static void iwm_reset_worker(struct work_struct *work) | |||
120 | 123 | ||
121 | iwm = container_of(work, struct iwm_priv, reset_worker); | 124 | iwm = container_of(work, struct iwm_priv, reset_worker); |
122 | 125 | ||
126 | /* | ||
127 | * XXX: The iwm->mutex is introduced purely for this reset work, | ||
128 | * because the other users for iwm_up and iwm_down are only netdev | ||
129 | * ndo_open and ndo_stop which are already protected by rtnl. | ||
130 | * Please remove iwm->mutex together if iwm_reset_worker() is not | ||
131 | * required in the future. | ||
132 | */ | ||
133 | if (!mutex_trylock(&iwm->mutex)) { | ||
134 | IWM_WARN(iwm, "We are in the middle of interface bringing " | ||
135 | "UP/DOWN. Skip driver resetting.\n"); | ||
136 | return; | ||
137 | } | ||
138 | |||
123 | if (iwm->umac_profile_active) { | 139 | if (iwm->umac_profile_active) { |
124 | profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL); | 140 | profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL); |
125 | if (profile) | 141 | if (profile) |
@@ -128,10 +144,10 @@ static void iwm_reset_worker(struct work_struct *work) | |||
128 | IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); | 144 | IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); |
129 | } | 145 | } |
130 | 146 | ||
131 | iwm_down(iwm); | 147 | __iwm_down(iwm); |
132 | 148 | ||
133 | while (retry++ < 3) { | 149 | while (retry++ < 3) { |
134 | ret = iwm_up(iwm); | 150 | ret = __iwm_up(iwm); |
135 | if (!ret) | 151 | if (!ret) |
136 | break; | 152 | break; |
137 | 153 | ||
@@ -142,7 +158,7 @@ static void iwm_reset_worker(struct work_struct *work) | |||
142 | IWM_WARN(iwm, "iwm_up() failed: %d\n", ret); | 158 | IWM_WARN(iwm, "iwm_up() failed: %d\n", ret); |
143 | 159 | ||
144 | kfree(profile); | 160 | kfree(profile); |
145 | return; | 161 | goto out; |
146 | } | 162 | } |
147 | 163 | ||
148 | if (profile) { | 164 | if (profile) { |
@@ -151,6 +167,9 @@ static void iwm_reset_worker(struct work_struct *work) | |||
151 | iwm_send_mlme_profile(iwm); | 167 | iwm_send_mlme_profile(iwm); |
152 | kfree(profile); | 168 | kfree(profile); |
153 | } | 169 | } |
170 | |||
171 | out: | ||
172 | mutex_unlock(&iwm->mutex); | ||
154 | } | 173 | } |
155 | 174 | ||
156 | static void iwm_watchdog(unsigned long data) | 175 | static void iwm_watchdog(unsigned long data) |
@@ -215,10 +234,21 @@ int iwm_priv_init(struct iwm_priv *iwm) | |||
215 | init_timer(&iwm->watchdog); | 234 | init_timer(&iwm->watchdog); |
216 | iwm->watchdog.function = iwm_watchdog; | 235 | iwm->watchdog.function = iwm_watchdog; |
217 | iwm->watchdog.data = (unsigned long)iwm; | 236 | iwm->watchdog.data = (unsigned long)iwm; |
237 | mutex_init(&iwm->mutex); | ||
218 | 238 | ||
219 | return 0; | 239 | return 0; |
220 | } | 240 | } |
221 | 241 | ||
242 | void iwm_priv_deinit(struct iwm_priv *iwm) | ||
243 | { | ||
244 | int i; | ||
245 | |||
246 | for (i = 0; i < IWM_TX_QUEUES; i++) | ||
247 | destroy_workqueue(iwm->txq[i].wq); | ||
248 | |||
249 | destroy_workqueue(iwm->rx_wq); | ||
250 | } | ||
251 | |||
222 | /* | 252 | /* |
223 | * We reset all the structures, and we reset the UMAC. | 253 | * We reset all the structures, and we reset the UMAC. |
224 | * After calling this routine, you're expected to reload | 254 | * After calling this routine, you're expected to reload |
@@ -466,7 +496,7 @@ void iwm_link_off(struct iwm_priv *iwm) | |||
466 | 496 | ||
467 | iwm_rx_free(iwm); | 497 | iwm_rx_free(iwm); |
468 | 498 | ||
469 | cancel_delayed_work(&iwm->stats_request); | 499 | cancel_delayed_work_sync(&iwm->stats_request); |
470 | memset(wstats, 0, sizeof(struct iw_statistics)); | 500 | memset(wstats, 0, sizeof(struct iw_statistics)); |
471 | wstats->qual.updated = IW_QUAL_ALL_INVALID; | 501 | wstats->qual.updated = IW_QUAL_ALL_INVALID; |
472 | 502 | ||
@@ -511,7 +541,7 @@ static int iwm_channels_init(struct iwm_priv *iwm) | |||
511 | return 0; | 541 | return 0; |
512 | } | 542 | } |
513 | 543 | ||
514 | int iwm_up(struct iwm_priv *iwm) | 544 | int __iwm_up(struct iwm_priv *iwm) |
515 | { | 545 | { |
516 | int ret; | 546 | int ret; |
517 | struct iwm_notif *notif_reboot, *notif_ack = NULL; | 547 | struct iwm_notif *notif_reboot, *notif_ack = NULL; |
@@ -647,7 +677,18 @@ int iwm_up(struct iwm_priv *iwm) | |||
647 | return -EIO; | 677 | return -EIO; |
648 | } | 678 | } |
649 | 679 | ||
650 | int iwm_down(struct iwm_priv *iwm) | 680 | int iwm_up(struct iwm_priv *iwm) |
681 | { | ||
682 | int ret; | ||
683 | |||
684 | mutex_lock(&iwm->mutex); | ||
685 | ret = __iwm_up(iwm); | ||
686 | mutex_unlock(&iwm->mutex); | ||
687 | |||
688 | return ret; | ||
689 | } | ||
690 | |||
691 | int __iwm_down(struct iwm_priv *iwm) | ||
651 | { | 692 | { |
652 | int ret; | 693 | int ret; |
653 | 694 | ||
@@ -678,3 +719,14 @@ int iwm_down(struct iwm_priv *iwm) | |||
678 | 719 | ||
679 | return 0; | 720 | return 0; |
680 | } | 721 | } |
722 | |||
723 | int iwm_down(struct iwm_priv *iwm) | ||
724 | { | ||
725 | int ret; | ||
726 | |||
727 | mutex_lock(&iwm->mutex); | ||
728 | ret = __iwm_down(iwm); | ||
729 | mutex_unlock(&iwm->mutex); | ||
730 | |||
731 | return ret; | ||
732 | } | ||