aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas
diff options
context:
space:
mode:
authorDaniel Drake <dsd@laptop.org>2011-08-01 11:43:13 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-08-09 15:52:02 -0400
commitd2e7b3425c474300318e1d28b10a93c2401b9255 (patch)
treeaf286b83e34688202d7a2345b3900a42a547a043 /drivers/net/wireless/libertas
parent6de062ced91d894936edc54d79158b9f69f85d0e (diff)
libertas: disable functionality when interface is down
Modify the driver so that it does not function when the interface is down, in preparation for runtime power management. No commands can be run while the interface is down, so the ndo_dev_stop routine now directly does all necessary work (including asking the device to disconnect from the network and disabling multicast functionality) directly. power_save and power_restore hooks are added meaning that card drivers can take steps to turn the device off when the interface is down. The MAC address can now only be changed when all interfaces are down; the new address will be programmed when an interface gets brought up. This matches mac80211 behaviour. Also, some small cleanups/simplifications were made in the surrounding device handling logic. Signed-off-by: Daniel Drake <dsd@laptop.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas')
-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