diff options
-rw-r--r-- | drivers/net/wireless/libertas/cfg.c | 39 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cfg.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmd.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/decl.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/dev.h | 16 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/if_usb.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 168 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/mesh.c | 9 |
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 | ||
1412 | static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, | 1412 | int 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 | ||
1436 | static 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 | ||
1445 | static int lbs_cfg_set_default_key(struct wiphy *wiphy, | 1452 | static 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); | |||
17 | void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event); | 17 | void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event); |
18 | 18 | ||
19 | void lbs_scan_deinit(struct lbs_private *priv); | 19 | void lbs_scan_deinit(struct lbs_private *priv); |
20 | int 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 | ||
1094 | void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, | 1094 | void 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); | |||
43 | void lbs_stop_card(struct lbs_private *priv); | 43 | void lbs_stop_card(struct lbs_private *priv); |
44 | void lbs_host_to_card_done(struct lbs_private *priv); | 44 | void lbs_host_to_card_done(struct lbs_private *priv); |
45 | 45 | ||
46 | int lbs_start_iface(struct lbs_private *priv); | ||
47 | int lbs_stop_iface(struct lbs_private *priv); | ||
48 | |||
46 | int lbs_rtap_supported(struct lbs_private *priv); | 49 | int lbs_rtap_supported(struct lbs_private *priv); |
47 | 50 | ||
48 | int lbs_set_mac_address(struct net_device *dev, void *addr); | 51 | int lbs_set_mac_address(struct net_device *dev, void *addr); |
49 | void lbs_set_multicast_list(struct net_device *dev); | 52 | void lbs_set_multicast_list(struct net_device *dev); |
53 | void lbs_update_mcast(struct lbs_private *priv); | ||
50 | 54 | ||
51 | int lbs_suspend(struct lbs_private *priv); | 55 | int lbs_suspend(struct lbs_private *priv); |
52 | int lbs_resume(struct lbs_private *priv); | 56 | int 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 | ||
183 | extern struct cmd_confirm_sleep confirm_sleep; | 185 | extern struct cmd_confirm_sleep confirm_sleep; |
184 | 186 | ||
187 | /* Check if there is an interface active. */ | ||
188 | static 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 | ||
102 | int 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 | |||
128 | err: | ||
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 | |||
161 | out: | ||
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 | ||
166 | static 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 | |||
176 | int 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 | ||
208 | done: | ||
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 | ||
262 | static void lbs_set_mcast_worker(struct work_struct *work) | 336 | void 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 | ||
393 | static 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 | |||
319 | void lbs_set_multicast_list(struct net_device *dev) | 399 | void 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); |
652 | out: | 732 | out: |
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); | |||
982 | void lbs_stop_card(struct lbs_private *priv) | 1056 | void 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 | ||
1025 | out: | 1073 | out: |
@@ -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 | ||