diff options
author | Zhu Yi <yi.zhu@intel.com> | 2009-06-15 15:59:49 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-06-19 11:50:16 -0400 |
commit | 68810c5dc5f6bbaa0bbf6acce7cb56d97a1c8fd0 (patch) | |
tree | c74e43daa2833b6e9e2b0ddbda5b2e02bb609257 /drivers/net | |
parent | 4e9aa52e36a7beb4c0163324a3de759d7cf2e442 (diff) |
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: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/iwm.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/main.c | 54 |
2 files changed, 49 insertions, 6 deletions
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 4aa0ad1932ff..77c339f8516c 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h | |||
@@ -288,6 +288,7 @@ struct iwm_priv { | |||
288 | u8 *eeprom; | 288 | u8 *eeprom; |
289 | struct timer_list watchdog; | 289 | struct timer_list watchdog; |
290 | struct work_struct reset_worker; | 290 | struct work_struct reset_worker; |
291 | struct mutex mutex; | ||
291 | struct rfkill *rfkill; | 292 | struct rfkill *rfkill; |
292 | 293 | ||
293 | char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); | 294 | char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); |
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 4d3c423d8ffc..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,6 +234,7 @@ 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 | } |
@@ -476,7 +496,7 @@ void iwm_link_off(struct iwm_priv *iwm) | |||
476 | 496 | ||
477 | iwm_rx_free(iwm); | 497 | iwm_rx_free(iwm); |
478 | 498 | ||
479 | cancel_delayed_work(&iwm->stats_request); | 499 | cancel_delayed_work_sync(&iwm->stats_request); |
480 | memset(wstats, 0, sizeof(struct iw_statistics)); | 500 | memset(wstats, 0, sizeof(struct iw_statistics)); |
481 | wstats->qual.updated = IW_QUAL_ALL_INVALID; | 501 | wstats->qual.updated = IW_QUAL_ALL_INVALID; |
482 | 502 | ||
@@ -521,7 +541,7 @@ static int iwm_channels_init(struct iwm_priv *iwm) | |||
521 | return 0; | 541 | return 0; |
522 | } | 542 | } |
523 | 543 | ||
524 | int iwm_up(struct iwm_priv *iwm) | 544 | int __iwm_up(struct iwm_priv *iwm) |
525 | { | 545 | { |
526 | int ret; | 546 | int ret; |
527 | struct iwm_notif *notif_reboot, *notif_ack = NULL; | 547 | struct iwm_notif *notif_reboot, *notif_ack = NULL; |
@@ -657,7 +677,18 @@ int iwm_up(struct iwm_priv *iwm) | |||
657 | return -EIO; | 677 | return -EIO; |
658 | } | 678 | } |
659 | 679 | ||
660 | 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) | ||
661 | { | 692 | { |
662 | int ret; | 693 | int ret; |
663 | 694 | ||
@@ -688,3 +719,14 @@ int iwm_down(struct iwm_priv *iwm) | |||
688 | 719 | ||
689 | return 0; | 720 | return 0; |
690 | } | 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 | } | ||