aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/libertas/cfg.c39
-rw-r--r--drivers/net/wireless/libertas/cfg.h1
-rw-r--r--drivers/net/wireless/libertas/cmd.c6
-rw-r--r--drivers/net/wireless/libertas/decl.h4
-rw-r--r--drivers/net/wireless/libertas/dev.h16
-rw-r--r--drivers/net/wireless/libertas/if_usb.c2
-rw-r--r--drivers/net/wireless/libertas/main.c168
-rw-r--r--drivers/net/wireless/libertas/mesh.c9
8 files changed, 163 insertions, 82 deletions
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 63009c7eb2f1..85b3169c40d7 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -712,7 +712,7 @@ static void lbs_scan_worker(struct work_struct *work)
712 712
713 if (priv->scan_channel < priv->scan_req->n_channels) { 713 if (priv->scan_channel < priv->scan_req->n_channels) {
714 cancel_delayed_work(&priv->scan_work); 714 cancel_delayed_work(&priv->scan_work);
715 if (!priv->stopping) 715 if (netif_running(priv->dev))
716 queue_delayed_work(priv->work_thread, &priv->scan_work, 716 queue_delayed_work(priv->work_thread, &priv->scan_work,
717 msecs_to_jiffies(300)); 717 msecs_to_jiffies(300));
718 } 718 }
@@ -1409,31 +1409,23 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
1409 return ret; 1409 return ret;
1410} 1410}
1411 1411
1412static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, 1412int lbs_disconnect(struct lbs_private *priv, u16 reason)
1413 u16 reason_code)
1414{ 1413{
1415 struct lbs_private *priv = wiphy_priv(wiphy);
1416 struct cmd_ds_802_11_deauthenticate cmd; 1414 struct cmd_ds_802_11_deauthenticate cmd;
1417 1415 int ret;
1418 if (dev == priv->mesh_dev)
1419 return -EOPNOTSUPP;
1420
1421 lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
1422
1423 /* store for lbs_cfg_ret_disconnect() */
1424 priv->disassoc_reason = reason_code;
1425 1416
1426 memset(&cmd, 0, sizeof(cmd)); 1417 memset(&cmd, 0, sizeof(cmd));
1427 cmd.hdr.size = cpu_to_le16(sizeof(cmd)); 1418 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1428 /* Mildly ugly to use a locally store my own BSSID ... */ 1419 /* Mildly ugly to use a locally store my own BSSID ... */
1429 memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN); 1420 memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN);
1430 cmd.reasoncode = cpu_to_le16(reason_code); 1421 cmd.reasoncode = cpu_to_le16(reason);
1431 1422
1432 if (lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd)) 1423 ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd);
1433 return -EFAULT; 1424 if (ret)
1425 return ret;
1434 1426
1435 cfg80211_disconnected(priv->dev, 1427 cfg80211_disconnected(priv->dev,
1436 priv->disassoc_reason, 1428 reason,
1437 NULL, 0, 1429 NULL, 0,
1438 GFP_KERNEL); 1430 GFP_KERNEL);
1439 priv->connect_status = LBS_DISCONNECTED; 1431 priv->connect_status = LBS_DISCONNECTED;
@@ -1441,6 +1433,21 @@ static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
1441 return 0; 1433 return 0;
1442} 1434}
1443 1435
1436static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
1437 u16 reason_code)
1438{
1439 struct lbs_private *priv = wiphy_priv(wiphy);
1440
1441 if (dev == priv->mesh_dev)
1442 return -EOPNOTSUPP;
1443
1444 lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
1445
1446 /* store for lbs_cfg_ret_disconnect() */
1447 priv->disassoc_reason = reason_code;
1448
1449 return lbs_disconnect(priv, reason_code);
1450}
1444 1451
1445static int lbs_cfg_set_default_key(struct wiphy *wiphy, 1452static int lbs_cfg_set_default_key(struct wiphy *wiphy,
1446 struct net_device *netdev, 1453 struct net_device *netdev,
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
index 4f46bb744bee..a02ee151710e 100644
--- a/drivers/net/wireless/libertas/cfg.h
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -17,5 +17,6 @@ void lbs_send_disconnect_notification(struct lbs_private *priv);
17void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event); 17void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
18 18
19void lbs_scan_deinit(struct lbs_private *priv); 19void lbs_scan_deinit(struct lbs_private *priv);
20int lbs_disconnect(struct lbs_private *priv, u16 reason);
20 21
21#endif 22#endif
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index dbd24a4607ec..e08ab1de3d9d 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -1088,7 +1088,7 @@ void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
1088 if (!cmd->callback || cmd->callback == lbs_cmd_async_callback) 1088 if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
1089 __lbs_cleanup_and_insert_cmd(priv, cmd); 1089 __lbs_cleanup_and_insert_cmd(priv, cmd);
1090 priv->cur_cmd = NULL; 1090 priv->cur_cmd = NULL;
1091 wake_up_interruptible(&priv->waitq); 1091 wake_up(&priv->waitq);
1092} 1092}
1093 1093
1094void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, 1094void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
@@ -1627,7 +1627,7 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
1627 lbs_deb_host("PREP_CMD: cmdnode is NULL\n"); 1627 lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
1628 1628
1629 /* Wake up main thread to execute next command */ 1629 /* Wake up main thread to execute next command */
1630 wake_up_interruptible(&priv->waitq); 1630 wake_up(&priv->waitq);
1631 cmdnode = ERR_PTR(-ENOBUFS); 1631 cmdnode = ERR_PTR(-ENOBUFS);
1632 goto done; 1632 goto done;
1633 } 1633 }
@@ -1647,7 +1647,7 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
1647 1647
1648 cmdnode->cmdwaitqwoken = 0; 1648 cmdnode->cmdwaitqwoken = 0;
1649 lbs_queue_cmd(priv, cmdnode); 1649 lbs_queue_cmd(priv, cmdnode);
1650 wake_up_interruptible(&priv->waitq); 1650 wake_up(&priv->waitq);
1651 1651
1652 done: 1652 done:
1653 lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode); 1653 lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index da0b05bb89fe..9304e6fc421f 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -43,10 +43,14 @@ int lbs_start_card(struct lbs_private *priv);
43void lbs_stop_card(struct lbs_private *priv); 43void lbs_stop_card(struct lbs_private *priv);
44void lbs_host_to_card_done(struct lbs_private *priv); 44void lbs_host_to_card_done(struct lbs_private *priv);
45 45
46int lbs_start_iface(struct lbs_private *priv);
47int lbs_stop_iface(struct lbs_private *priv);
48
46int lbs_rtap_supported(struct lbs_private *priv); 49int lbs_rtap_supported(struct lbs_private *priv);
47 50
48int lbs_set_mac_address(struct net_device *dev, void *addr); 51int lbs_set_mac_address(struct net_device *dev, void *addr);
49void lbs_set_multicast_list(struct net_device *dev); 52void lbs_set_multicast_list(struct net_device *dev);
53void lbs_update_mcast(struct lbs_private *priv);
50 54
51int lbs_suspend(struct lbs_private *priv); 55int lbs_suspend(struct lbs_private *priv);
52int lbs_resume(struct lbs_private *priv); 56int lbs_resume(struct lbs_private *priv);
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 133ff1cac524..814838916b82 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -46,7 +46,6 @@ struct lbs_private {
46 /* CFG80211 */ 46 /* CFG80211 */
47 struct wireless_dev *wdev; 47 struct wireless_dev *wdev;
48 bool wiphy_registered; 48 bool wiphy_registered;
49 bool stopping;
50 struct cfg80211_scan_request *scan_req; 49 struct cfg80211_scan_request *scan_req;
51 u8 assoc_bss[ETH_ALEN]; 50 u8 assoc_bss[ETH_ALEN];
52 u8 disassoc_reason; 51 u8 disassoc_reason;
@@ -96,11 +95,14 @@ struct lbs_private {
96 95
97 /* Hardware access */ 96 /* Hardware access */
98 void *card; 97 void *card;
98 bool iface_running;
99 u8 fw_ready; 99 u8 fw_ready;
100 u8 surpriseremoved; 100 u8 surpriseremoved;
101 u8 setup_fw_on_resume; 101 u8 setup_fw_on_resume;
102 int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); 102 int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
103 void (*reset_card) (struct lbs_private *priv); 103 void (*reset_card) (struct lbs_private *priv);
104 int (*power_save) (struct lbs_private *priv);
105 int (*power_restore) (struct lbs_private *priv);
104 int (*enter_deep_sleep) (struct lbs_private *priv); 106 int (*enter_deep_sleep) (struct lbs_private *priv);
105 int (*exit_deep_sleep) (struct lbs_private *priv); 107 int (*exit_deep_sleep) (struct lbs_private *priv);
106 int (*reset_deep_sleep_wakeup) (struct lbs_private *priv); 108 int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
@@ -182,4 +184,16 @@ struct lbs_private {
182 184
183extern struct cmd_confirm_sleep confirm_sleep; 185extern struct cmd_confirm_sleep confirm_sleep;
184 186
187/* Check if there is an interface active. */
188static inline int lbs_iface_active(struct lbs_private *priv)
189{
190 int r;
191
192 r = netif_running(priv->dev);
193 if (priv->mesh_dev);
194 r |= netif_running(priv->dev);
195
196 return r;
197}
198
185#endif 199#endif
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index ca6e0a411e9c..0c846f5a646a 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -956,7 +956,7 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp,
956 priv->dnld_sent = DNLD_RES_RECEIVED; 956 priv->dnld_sent = DNLD_RES_RECEIVED;
957 spin_unlock_irqrestore(&priv->driver_lock, flags); 957 spin_unlock_irqrestore(&priv->driver_lock, flags);
958 958
959 wake_up_interruptible(&priv->waitq); 959 wake_up(&priv->waitq);
960 960
961 return ret; 961 return ret;
962} 962}
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index ee28ae510935..d62d1fb4177f 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -99,6 +99,37 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
99 return 0; 99 return 0;
100} 100}
101 101
102int lbs_start_iface(struct lbs_private *priv)
103{
104 struct cmd_ds_802_11_mac_address cmd;
105 int ret;
106
107 if (priv->power_restore) {
108 ret = priv->power_restore(priv);
109 if (ret)
110 return ret;
111 }
112
113 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
114 cmd.action = cpu_to_le16(CMD_ACT_SET);
115 memcpy(cmd.macadd, priv->current_addr, ETH_ALEN);
116
117 ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd);
118 if (ret) {
119 lbs_deb_net("set MAC address failed\n");
120 goto err;
121 }
122
123 lbs_update_channel(priv);
124
125 priv->iface_running = true;
126 return 0;
127
128err:
129 if (priv->power_save)
130 priv->power_save(priv);
131 return ret;
132}
102 133
103/** 134/**
104 * lbs_dev_open - open the ethX interface 135 * lbs_dev_open - open the ethX interface
@@ -112,23 +143,64 @@ static int lbs_dev_open(struct net_device *dev)
112 int ret = 0; 143 int ret = 0;
113 144
114 lbs_deb_enter(LBS_DEB_NET); 145 lbs_deb_enter(LBS_DEB_NET);
146 if (!priv->iface_running) {
147 ret = lbs_start_iface(priv);
148 if (ret)
149 goto out;
150 }
115 151
116 spin_lock_irq(&priv->driver_lock); 152 spin_lock_irq(&priv->driver_lock);
117 priv->stopping = false;
118 153
119 if (priv->connect_status == LBS_CONNECTED) 154 netif_carrier_off(dev);
120 netif_carrier_on(dev);
121 else
122 netif_carrier_off(dev);
123 155
124 if (!priv->tx_pending_len) 156 if (!priv->tx_pending_len)
125 netif_wake_queue(dev); 157 netif_wake_queue(dev);
126 158
127 spin_unlock_irq(&priv->driver_lock); 159 spin_unlock_irq(&priv->driver_lock);
160
161out:
128 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); 162 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
129 return ret; 163 return ret;
130} 164}
131 165
166static bool lbs_command_queue_empty(struct lbs_private *priv)
167{
168 unsigned long flags;
169 bool ret;
170 spin_lock_irqsave(&priv->driver_lock, flags);
171 ret = priv->cur_cmd == NULL && list_empty(&priv->cmdpendingq);
172 spin_unlock_irqrestore(&priv->driver_lock, flags);
173 return ret;
174}
175
176int lbs_stop_iface(struct lbs_private *priv)
177{
178 unsigned long flags;
179 int ret = 0;
180
181 lbs_deb_enter(LBS_DEB_MAIN);
182
183 spin_lock_irqsave(&priv->driver_lock, flags);
184 priv->iface_running = false;
185 kfree_skb(priv->currenttxskb);
186 priv->currenttxskb = NULL;
187 priv->tx_pending_len = 0;
188 spin_unlock_irqrestore(&priv->driver_lock, flags);
189
190 cancel_work_sync(&priv->mcast_work);
191
192 /* Disable command processing, and wait for all commands to complete */
193 lbs_deb_main("waiting for commands to complete\n");
194 wait_event(priv->waitq, lbs_command_queue_empty(priv));
195 lbs_deb_main("all commands completed\n");
196
197 if (priv->power_save)
198 ret = priv->power_save(priv);
199
200 lbs_deb_leave(LBS_DEB_MAIN);
201 return ret;
202}
203
132/** 204/**
133 * lbs_eth_stop - close the ethX interface 205 * lbs_eth_stop - close the ethX interface
134 * 206 *
@@ -141,18 +213,25 @@ static int lbs_eth_stop(struct net_device *dev)
141 213
142 lbs_deb_enter(LBS_DEB_NET); 214 lbs_deb_enter(LBS_DEB_NET);
143 215
216 if (priv->connect_status == LBS_CONNECTED)
217 lbs_disconnect(priv, WLAN_REASON_DEAUTH_LEAVING);
218
144 spin_lock_irq(&priv->driver_lock); 219 spin_lock_irq(&priv->driver_lock);
145 priv->stopping = true;
146 netif_stop_queue(dev); 220 netif_stop_queue(dev);
147 spin_unlock_irq(&priv->driver_lock); 221 spin_unlock_irq(&priv->driver_lock);
148 222
149 schedule_work(&priv->mcast_work); 223 lbs_update_mcast(priv);
150 cancel_delayed_work_sync(&priv->scan_work); 224 cancel_delayed_work_sync(&priv->scan_work);
151 if (priv->scan_req) { 225 if (priv->scan_req) {
152 cfg80211_scan_done(priv->scan_req, false); 226 cfg80211_scan_done(priv->scan_req, false);
153 priv->scan_req = NULL; 227 priv->scan_req = NULL;
154 } 228 }
155 229
230 netif_carrier_off(priv->dev);
231
232 if (!lbs_iface_active(priv))
233 lbs_stop_iface(priv);
234
156 lbs_deb_leave(LBS_DEB_NET); 235 lbs_deb_leave(LBS_DEB_NET);
157 return 0; 236 return 0;
158} 237}
@@ -170,7 +249,7 @@ void lbs_host_to_card_done(struct lbs_private *priv)
170 /* Wake main thread if commands are pending */ 249 /* Wake main thread if commands are pending */
171 if (!priv->cur_cmd || priv->tx_pending_len > 0) { 250 if (!priv->cur_cmd || priv->tx_pending_len > 0) {
172 if (!priv->wakeup_dev_required) 251 if (!priv->wakeup_dev_required)
173 wake_up_interruptible(&priv->waitq); 252 wake_up(&priv->waitq);
174 } 253 }
175 254
176 spin_unlock_irqrestore(&priv->driver_lock, flags); 255 spin_unlock_irqrestore(&priv->driver_lock, flags);
@@ -183,29 +262,24 @@ int lbs_set_mac_address(struct net_device *dev, void *addr)
183 int ret = 0; 262 int ret = 0;
184 struct lbs_private *priv = dev->ml_priv; 263 struct lbs_private *priv = dev->ml_priv;
185 struct sockaddr *phwaddr = addr; 264 struct sockaddr *phwaddr = addr;
186 struct cmd_ds_802_11_mac_address cmd;
187 265
188 lbs_deb_enter(LBS_DEB_NET); 266 lbs_deb_enter(LBS_DEB_NET);
189 267
268 /*
269 * Can only set MAC address when all interfaces are down, to be written
270 * to the hardware when one of them is brought up.
271 */
272 if (lbs_iface_active(priv))
273 return -EBUSY;
274
190 /* In case it was called from the mesh device */ 275 /* In case it was called from the mesh device */
191 dev = priv->dev; 276 dev = priv->dev;
192 277
193 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
194 cmd.action = cpu_to_le16(CMD_ACT_SET);
195 memcpy(cmd.macadd, phwaddr->sa_data, ETH_ALEN);
196
197 ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd);
198 if (ret) {
199 lbs_deb_net("set MAC address failed\n");
200 goto done;
201 }
202
203 memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN); 278 memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN);
204 memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN); 279 memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
205 if (priv->mesh_dev) 280 if (priv->mesh_dev)
206 memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN); 281 memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
207 282
208done:
209 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); 283 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
210 return ret; 284 return ret;
211} 285}
@@ -259,18 +333,18 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
259 return i; 333 return i;
260} 334}
261 335
262static void lbs_set_mcast_worker(struct work_struct *work) 336void lbs_update_mcast(struct lbs_private *priv)
263{ 337{
264 struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
265 struct cmd_ds_mac_multicast_adr mcast_cmd; 338 struct cmd_ds_mac_multicast_adr mcast_cmd;
266 int dev_flags; 339 int dev_flags = 0;
267 int nr_addrs; 340 int nr_addrs;
268 int old_mac_control = priv->mac_control; 341 int old_mac_control = priv->mac_control;
269 342
270 lbs_deb_enter(LBS_DEB_NET); 343 lbs_deb_enter(LBS_DEB_NET);
271 344
272 dev_flags = priv->dev->flags; 345 if (netif_running(priv->dev))
273 if (priv->mesh_dev) 346 dev_flags |= priv->dev->flags;
347 if (priv->mesh_dev && netif_running(priv->mesh_dev))
274 dev_flags |= priv->mesh_dev->flags; 348 dev_flags |= priv->mesh_dev->flags;
275 349
276 if (dev_flags & IFF_PROMISC) { 350 if (dev_flags & IFF_PROMISC) {
@@ -316,6 +390,12 @@ static void lbs_set_mcast_worker(struct work_struct *work)
316 lbs_deb_leave(LBS_DEB_NET); 390 lbs_deb_leave(LBS_DEB_NET);
317} 391}
318 392
393static void lbs_set_mcast_worker(struct work_struct *work)
394{
395 struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
396 lbs_update_mcast(priv);
397}
398
319void lbs_set_multicast_list(struct net_device *dev) 399void lbs_set_multicast_list(struct net_device *dev)
320{ 400{
321 struct lbs_private *priv = dev->ml_priv; 401 struct lbs_private *priv = dev->ml_priv;
@@ -648,7 +728,7 @@ static void lbs_cmd_timeout_handler(unsigned long data)
648 if (priv->dnld_sent == DNLD_CMD_SENT) 728 if (priv->dnld_sent == DNLD_CMD_SENT)
649 priv->dnld_sent = DNLD_RES_RECEIVED; 729 priv->dnld_sent = DNLD_RES_RECEIVED;
650 730
651 wake_up_interruptible(&priv->waitq); 731 wake_up(&priv->waitq);
652out: 732out:
653 spin_unlock_irqrestore(&priv->driver_lock, flags); 733 spin_unlock_irqrestore(&priv->driver_lock, flags);
654 lbs_deb_leave(LBS_DEB_CMD); 734 lbs_deb_leave(LBS_DEB_CMD);
@@ -890,10 +970,6 @@ void lbs_remove_card(struct lbs_private *priv)
890 lbs_remove_mesh(priv); 970 lbs_remove_mesh(priv);
891 lbs_scan_deinit(priv); 971 lbs_scan_deinit(priv);
892 972
893 dev = priv->dev;
894
895 cancel_work_sync(&priv->mcast_work);
896
897 /* worker thread destruction blocks on the in-flight command which 973 /* worker thread destruction blocks on the in-flight command which
898 * should have been cleared already in lbs_stop_card(). 974 * should have been cleared already in lbs_stop_card().
899 */ 975 */
@@ -964,8 +1040,6 @@ int lbs_start_card(struct lbs_private *priv)
964 if (lbs_mesh_activated(priv)) 1040 if (lbs_mesh_activated(priv))
965 lbs_start_mesh(priv); 1041 lbs_start_mesh(priv);
966 1042
967 lbs_update_channel(priv);
968
969 lbs_debugfs_init_one(priv, dev); 1043 lbs_debugfs_init_one(priv, dev);
970 1044
971 netdev_info(dev, "Marvell WLAN 802.11 adapter\n"); 1045 netdev_info(dev, "Marvell WLAN 802.11 adapter\n");
@@ -982,8 +1056,6 @@ EXPORT_SYMBOL_GPL(lbs_start_card);
982void lbs_stop_card(struct lbs_private *priv) 1056void lbs_stop_card(struct lbs_private *priv)
983{ 1057{
984 struct net_device *dev; 1058 struct net_device *dev;
985 struct cmd_ctrl_node *cmdnode;
986 unsigned long flags;
987 1059
988 lbs_deb_enter(LBS_DEB_MAIN); 1060 lbs_deb_enter(LBS_DEB_MAIN);
989 1061
@@ -996,30 +1068,6 @@ void lbs_stop_card(struct lbs_private *priv)
996 1068
997 lbs_debugfs_remove_one(priv); 1069 lbs_debugfs_remove_one(priv);
998 lbs_deinit_mesh(priv); 1070 lbs_deinit_mesh(priv);
999
1000 /* Delete the timeout of the currently processing command */
1001 del_timer_sync(&priv->command_timer);
1002 del_timer_sync(&priv->auto_deepsleep_timer);
1003
1004 /* Flush pending command nodes */
1005 spin_lock_irqsave(&priv->driver_lock, flags);
1006 lbs_deb_main("clearing pending commands\n");
1007 list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
1008 cmdnode->result = -ENOENT;
1009 cmdnode->cmdwaitqwoken = 1;
1010 wake_up(&cmdnode->cmdwait_q);
1011 }
1012
1013 /* Flush the command the card is currently processing */
1014 if (priv->cur_cmd) {
1015 lbs_deb_main("clearing current command\n");
1016 priv->cur_cmd->result = -ENOENT;
1017 priv->cur_cmd->cmdwaitqwoken = 1;
1018 wake_up(&priv->cur_cmd->cmdwait_q);
1019 }
1020 lbs_deb_main("done clearing commands\n");
1021 spin_unlock_irqrestore(&priv->driver_lock, flags);
1022
1023 unregister_netdev(dev); 1071 unregister_netdev(dev);
1024 1072
1025out: 1073out:
@@ -1040,7 +1088,7 @@ void lbs_queue_event(struct lbs_private *priv, u32 event)
1040 1088
1041 kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32)); 1089 kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32));
1042 1090
1043 wake_up_interruptible(&priv->waitq); 1091 wake_up(&priv->waitq);
1044 1092
1045 spin_unlock_irqrestore(&priv->driver_lock, flags); 1093 spin_unlock_irqrestore(&priv->driver_lock, flags);
1046 lbs_deb_leave(LBS_DEB_THREAD); 1094 lbs_deb_leave(LBS_DEB_THREAD);
@@ -1058,7 +1106,7 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
1058 BUG_ON(resp_idx > 1); 1106 BUG_ON(resp_idx > 1);
1059 priv->resp_idx = resp_idx; 1107 priv->resp_idx = resp_idx;
1060 1108
1061 wake_up_interruptible(&priv->waitq); 1109 wake_up(&priv->waitq);
1062 1110
1063 lbs_deb_leave(LBS_DEB_THREAD); 1111 lbs_deb_leave(LBS_DEB_THREAD);
1064} 1112}
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index 2a635d279ffe..138699baf90e 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -924,7 +924,9 @@ static int lbs_mesh_stop(struct net_device *dev)
924 924
925 spin_unlock_irq(&priv->driver_lock); 925 spin_unlock_irq(&priv->driver_lock);
926 926
927 schedule_work(&priv->mcast_work); 927 lbs_update_mcast(priv);
928 if (!lbs_iface_active(priv))
929 lbs_stop_iface(priv);
928 930
929 lbs_deb_leave(LBS_DEB_MESH); 931 lbs_deb_leave(LBS_DEB_MESH);
930 return 0; 932 return 0;
@@ -942,6 +944,11 @@ static int lbs_mesh_dev_open(struct net_device *dev)
942 int ret = 0; 944 int ret = 0;
943 945
944 lbs_deb_enter(LBS_DEB_NET); 946 lbs_deb_enter(LBS_DEB_NET);
947 if (!priv->iface_running) {
948 ret = lbs_start_iface(priv);
949 if (ret)
950 goto out;
951 }
945 952
946 spin_lock_irq(&priv->driver_lock); 953 spin_lock_irq(&priv->driver_lock);
947 954