aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r--drivers/net/wireless/libertas/cfg.c69
-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.h28
-rw-r--r--drivers/net/wireless/libertas/ethtool.c1
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c277
-rw-r--r--drivers/net/wireless/libertas/if_spi.c4
-rw-r--r--drivers/net/wireless/libertas/if_usb.c13
-rw-r--r--drivers/net/wireless/libertas/main.c180
-rw-r--r--drivers/net/wireless/libertas/mesh.c77
-rw-r--r--drivers/net/wireless/libertas/mesh.h27
-rw-r--r--drivers/net/wireless/libertas/rx.c1
-rw-r--r--drivers/net/wireless/libertas/tx.c1
14 files changed, 457 insertions, 232 deletions
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index b456a53b64b1..85b3169c40d7 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -19,6 +19,7 @@
19#include "decl.h" 19#include "decl.h"
20#include "cfg.h" 20#include "cfg.h"
21#include "cmd.h" 21#include "cmd.h"
22#include "mesh.h"
22 23
23 24
24#define CHAN2G(_channel, _freq, _flags) { \ 25#define CHAN2G(_channel, _freq, _flags) { \
@@ -442,13 +443,16 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy,
442 struct lbs_private *priv = wiphy_priv(wiphy); 443 struct lbs_private *priv = wiphy_priv(wiphy);
443 int ret = -ENOTSUPP; 444 int ret = -ENOTSUPP;
444 445
445 lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", 446 lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d, type %d",
446 channel->center_freq, channel_type); 447 netdev_name(netdev), channel->center_freq, channel_type);
447 448
448 if (channel_type != NL80211_CHAN_NO_HT) 449 if (channel_type != NL80211_CHAN_NO_HT)
449 goto out; 450 goto out;
450 451
451 ret = lbs_set_channel(priv, channel->hw_value); 452 if (netdev == priv->mesh_dev)
453 ret = lbs_mesh_set_channel(priv, channel->hw_value);
454 else
455 ret = lbs_set_channel(priv, channel->hw_value);
452 456
453 out: 457 out:
454 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); 458 lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -708,7 +712,7 @@ static void lbs_scan_worker(struct work_struct *work)
708 712
709 if (priv->scan_channel < priv->scan_req->n_channels) { 713 if (priv->scan_channel < priv->scan_req->n_channels) {
710 cancel_delayed_work(&priv->scan_work); 714 cancel_delayed_work(&priv->scan_work);
711 if (!priv->stopping) 715 if (netif_running(priv->dev))
712 queue_delayed_work(priv->work_thread, &priv->scan_work, 716 queue_delayed_work(priv->work_thread, &priv->scan_work,
713 msecs_to_jiffies(300)); 717 msecs_to_jiffies(300));
714 } 718 }
@@ -1292,6 +1296,9 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
1292 int ret = 0; 1296 int ret = 0;
1293 u8 preamble = RADIO_PREAMBLE_SHORT; 1297 u8 preamble = RADIO_PREAMBLE_SHORT;
1294 1298
1299 if (dev == priv->mesh_dev)
1300 return -EOPNOTSUPP;
1301
1295 lbs_deb_enter(LBS_DEB_CFG80211); 1302 lbs_deb_enter(LBS_DEB_CFG80211);
1296 1303
1297 if (!sme->bssid) { 1304 if (!sme->bssid) {
@@ -1402,28 +1409,23 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
1402 return ret; 1409 return ret;
1403} 1410}
1404 1411
1405static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, 1412int lbs_disconnect(struct lbs_private *priv, u16 reason)
1406 u16 reason_code)
1407{ 1413{
1408 struct lbs_private *priv = wiphy_priv(wiphy);
1409 struct cmd_ds_802_11_deauthenticate cmd; 1414 struct cmd_ds_802_11_deauthenticate cmd;
1410 1415 int ret;
1411 lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
1412
1413 /* store for lbs_cfg_ret_disconnect() */
1414 priv->disassoc_reason = reason_code;
1415 1416
1416 memset(&cmd, 0, sizeof(cmd)); 1417 memset(&cmd, 0, sizeof(cmd));
1417 cmd.hdr.size = cpu_to_le16(sizeof(cmd)); 1418 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1418 /* Mildly ugly to use a locally store my own BSSID ... */ 1419 /* Mildly ugly to use a locally store my own BSSID ... */
1419 memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN); 1420 memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN);
1420 cmd.reasoncode = cpu_to_le16(reason_code); 1421 cmd.reasoncode = cpu_to_le16(reason);
1421 1422
1422 if (lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd)) 1423 ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd);
1423 return -EFAULT; 1424 if (ret)
1425 return ret;
1424 1426
1425 cfg80211_disconnected(priv->dev, 1427 cfg80211_disconnected(priv->dev,
1426 priv->disassoc_reason, 1428 reason,
1427 NULL, 0, 1429 NULL, 0,
1428 GFP_KERNEL); 1430 GFP_KERNEL);
1429 priv->connect_status = LBS_DISCONNECTED; 1431 priv->connect_status = LBS_DISCONNECTED;
@@ -1431,6 +1433,21 @@ static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
1431 return 0; 1433 return 0;
1432} 1434}
1433 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}
1434 1451
1435static int lbs_cfg_set_default_key(struct wiphy *wiphy, 1452static int lbs_cfg_set_default_key(struct wiphy *wiphy,
1436 struct net_device *netdev, 1453 struct net_device *netdev,
@@ -1439,6 +1456,9 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy,
1439{ 1456{
1440 struct lbs_private *priv = wiphy_priv(wiphy); 1457 struct lbs_private *priv = wiphy_priv(wiphy);
1441 1458
1459 if (netdev == priv->mesh_dev)
1460 return -EOPNOTSUPP;
1461
1442 lbs_deb_enter(LBS_DEB_CFG80211); 1462 lbs_deb_enter(LBS_DEB_CFG80211);
1443 1463
1444 if (key_index != priv->wep_tx_key) { 1464 if (key_index != priv->wep_tx_key) {
@@ -1460,6 +1480,9 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
1460 u16 key_type; 1480 u16 key_type;
1461 int ret = 0; 1481 int ret = 0;
1462 1482
1483 if (netdev == priv->mesh_dev)
1484 return -EOPNOTSUPP;
1485
1463 lbs_deb_enter(LBS_DEB_CFG80211); 1486 lbs_deb_enter(LBS_DEB_CFG80211);
1464 1487
1465 lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n", 1488 lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n",
@@ -1603,6 +1626,9 @@ static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev,
1603 s8 signal, noise; 1626 s8 signal, noise;
1604 int ret; 1627 int ret;
1605 1628
1629 if (dev == priv->mesh_dev)
1630 return -EOPNOTSUPP;
1631
1606 if (idx != 0) 1632 if (idx != 0)
1607 ret = -ENOENT; 1633 ret = -ENOENT;
1608 1634
@@ -1636,6 +1662,9 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
1636 struct lbs_private *priv = wiphy_priv(wiphy); 1662 struct lbs_private *priv = wiphy_priv(wiphy);
1637 int ret = 0; 1663 int ret = 0;
1638 1664
1665 if (dev == priv->mesh_dev)
1666 return -EOPNOTSUPP;
1667
1639 lbs_deb_enter(LBS_DEB_CFG80211); 1668 lbs_deb_enter(LBS_DEB_CFG80211);
1640 1669
1641 switch (type) { 1670 switch (type) {
@@ -1959,6 +1988,9 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
1959 struct cfg80211_bss *bss; 1988 struct cfg80211_bss *bss;
1960 DECLARE_SSID_BUF(ssid_buf); 1989 DECLARE_SSID_BUF(ssid_buf);
1961 1990
1991 if (dev == priv->mesh_dev)
1992 return -EOPNOTSUPP;
1993
1962 lbs_deb_enter(LBS_DEB_CFG80211); 1994 lbs_deb_enter(LBS_DEB_CFG80211);
1963 1995
1964 if (!params->channel) { 1996 if (!params->channel) {
@@ -1995,6 +2027,9 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
1995 struct cmd_ds_802_11_ad_hoc_stop cmd; 2027 struct cmd_ds_802_11_ad_hoc_stop cmd;
1996 int ret = 0; 2028 int ret = 0;
1997 2029
2030 if (dev == priv->mesh_dev)
2031 return -EOPNOTSUPP;
2032
1998 lbs_deb_enter(LBS_DEB_CFG80211); 2033 lbs_deb_enter(LBS_DEB_CFG80211);
1999 2034
2000 memset(&cmd, 0, sizeof(cmd)); 2035 memset(&cmd, 0, sizeof(cmd));
@@ -2117,6 +2152,8 @@ int lbs_cfg_register(struct lbs_private *priv)
2117 BIT(NL80211_IFTYPE_ADHOC); 2152 BIT(NL80211_IFTYPE_ADHOC);
2118 if (lbs_rtap_supported(priv)) 2153 if (lbs_rtap_supported(priv))
2119 wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); 2154 wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
2155 if (lbs_mesh_activated(priv))
2156 wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MESH_POINT);
2120 2157
2121 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz; 2158 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
2122 2159
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 adb3490e3cf5..814838916b82 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -6,7 +6,6 @@
6#ifndef _LBS_DEV_H_ 6#ifndef _LBS_DEV_H_
7#define _LBS_DEV_H_ 7#define _LBS_DEV_H_
8 8
9#include "mesh.h"
10#include "defs.h" 9#include "defs.h"
11#include "host.h" 10#include "host.h"
12 11
@@ -22,6 +21,17 @@ struct sleep_params {
22 uint16_t sp_reserved; 21 uint16_t sp_reserved;
23}; 22};
24 23
24/* Mesh statistics */
25struct lbs_mesh_stats {
26 u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
27 u32 fwd_unicast_cnt; /* Fwd: Unicast counter */
28 u32 fwd_drop_ttl; /* Fwd: TTL zero */
29 u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */
30 u32 fwd_drop_noroute; /* Fwd: No route to Destination */
31 u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */
32 u32 drop_blind; /* Rx: Dropped by blinding table */
33 u32 tx_failed_cnt; /* Tx: Failed transmissions */
34};
25 35
26/* Private structure for the MV device */ 36/* Private structure for the MV device */
27struct lbs_private { 37struct lbs_private {
@@ -36,7 +46,6 @@ struct lbs_private {
36 /* CFG80211 */ 46 /* CFG80211 */
37 struct wireless_dev *wdev; 47 struct wireless_dev *wdev;
38 bool wiphy_registered; 48 bool wiphy_registered;
39 bool stopping;
40 struct cfg80211_scan_request *scan_req; 49 struct cfg80211_scan_request *scan_req;
41 u8 assoc_bss[ETH_ALEN]; 50 u8 assoc_bss[ETH_ALEN];
42 u8 disassoc_reason; 51 u8 disassoc_reason;
@@ -86,11 +95,14 @@ struct lbs_private {
86 95
87 /* Hardware access */ 96 /* Hardware access */
88 void *card; 97 void *card;
98 bool iface_running;
89 u8 fw_ready; 99 u8 fw_ready;
90 u8 surpriseremoved; 100 u8 surpriseremoved;
91 u8 setup_fw_on_resume; 101 u8 setup_fw_on_resume;
92 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);
93 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);
94 int (*enter_deep_sleep) (struct lbs_private *priv); 106 int (*enter_deep_sleep) (struct lbs_private *priv);
95 int (*exit_deep_sleep) (struct lbs_private *priv); 107 int (*exit_deep_sleep) (struct lbs_private *priv);
96 int (*reset_deep_sleep_wakeup) (struct lbs_private *priv); 108 int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
@@ -172,4 +184,16 @@ struct lbs_private {
172 184
173extern struct cmd_confirm_sleep confirm_sleep; 185extern struct cmd_confirm_sleep confirm_sleep;
174 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
175#endif 199#endif
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 4dfb3bfd2cf3..885ddc1c4fed 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -5,6 +5,7 @@
5 5
6#include "decl.h" 6#include "decl.h"
7#include "cmd.h" 7#include "cmd.h"
8#include "mesh.h"
8 9
9 10
10static void lbs_ethtool_get_drvinfo(struct net_device *dev, 11static void lbs_ethtool_get_drvinfo(struct net_device *dev,
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 387786e1b394..c962e21762dc 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -39,6 +39,7 @@
39#include <linux/mmc/sdio_ids.h> 39#include <linux/mmc/sdio_ids.h>
40#include <linux/mmc/sdio.h> 40#include <linux/mmc/sdio.h>
41#include <linux/mmc/host.h> 41#include <linux/mmc/host.h>
42#include <linux/pm_runtime.h>
42 43
43#include "host.h" 44#include "host.h"
44#include "decl.h" 45#include "decl.h"
@@ -47,6 +48,8 @@
47#include "cmd.h" 48#include "cmd.h"
48#include "if_sdio.h" 49#include "if_sdio.h"
49 50
51static void if_sdio_interrupt(struct sdio_func *func);
52
50/* The if_sdio_remove() callback function is called when 53/* The if_sdio_remove() callback function is called when
51 * user removes this module from kernel space or ejects 54 * user removes this module from kernel space or ejects
52 * the card from the slot. The driver handles these 2 cases 55 * the card from the slot. The driver handles these 2 cases
@@ -757,6 +760,136 @@ out:
757 return ret; 760 return ret;
758} 761}
759 762
763/********************************************************************/
764/* Power management */
765/********************************************************************/
766
767static int if_sdio_power_on(struct if_sdio_card *card)
768{
769 struct sdio_func *func = card->func;
770 struct lbs_private *priv = card->priv;
771 struct mmc_host *host = func->card->host;
772 int ret;
773
774 sdio_claim_host(func);
775
776 ret = sdio_enable_func(func);
777 if (ret)
778 goto release;
779
780 /* For 1-bit transfers to the 8686 model, we need to enable the
781 * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
782 * bit to allow access to non-vendor registers. */
783 if ((card->model == MODEL_8686) &&
784 (host->caps & MMC_CAP_SDIO_IRQ) &&
785 (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
786 u8 reg;
787
788 func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
789 reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
790 if (ret)
791 goto disable;
792
793 reg |= SDIO_BUS_ECSI;
794 sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
795 if (ret)
796 goto disable;
797 }
798
799 card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
800 if (ret)
801 goto disable;
802
803 card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
804 if (ret)
805 goto disable;
806
807 card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
808 if (ret)
809 goto disable;
810
811 sdio_release_host(func);
812 ret = if_sdio_prog_firmware(card);
813 sdio_claim_host(func);
814 if (ret)
815 goto disable;
816
817 /*
818 * Get rx_unit if the chip is SD8688 or newer.
819 * SD8385 & SD8686 do not have rx_unit.
820 */
821 if ((card->model != MODEL_8385)
822 && (card->model != MODEL_8686))
823 card->rx_unit = if_sdio_read_rx_unit(card);
824 else
825 card->rx_unit = 0;
826
827 /*
828 * Set up the interrupt handler late.
829 *
830 * If we set it up earlier, the (buggy) hardware generates a spurious
831 * interrupt, even before the interrupt has been enabled, with
832 * CCCR_INTx = 0.
833 *
834 * We register the interrupt handler late so that we can handle any
835 * spurious interrupts, and also to avoid generation of that known
836 * spurious interrupt in the first place.
837 */
838 ret = sdio_claim_irq(func, if_sdio_interrupt);
839 if (ret)
840 goto disable;
841
842 /*
843 * Enable interrupts now that everything is set up
844 */
845 sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
846 if (ret)
847 goto release_irq;
848
849 sdio_release_host(func);
850
851 /*
852 * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
853 */
854 if (card->model == MODEL_8688) {
855 struct cmd_header cmd;
856
857 memset(&cmd, 0, sizeof(cmd));
858
859 lbs_deb_sdio("send function INIT command\n");
860 if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
861 lbs_cmd_copyback, (unsigned long) &cmd))
862 netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");
863 }
864
865 priv->fw_ready = 1;
866
867 return 0;
868
869release_irq:
870 sdio_release_irq(func);
871disable:
872 sdio_disable_func(func);
873release:
874 sdio_release_host(func);
875 return ret;
876}
877
878static int if_sdio_power_off(struct if_sdio_card *card)
879{
880 struct sdio_func *func = card->func;
881 struct lbs_private *priv = card->priv;
882
883 priv->fw_ready = 0;
884
885 sdio_claim_host(func);
886 sdio_release_irq(func);
887 sdio_disable_func(func);
888 sdio_release_host(func);
889 return 0;
890}
891
892
760/*******************************************************************/ 893/*******************************************************************/
761/* Libertas callbacks */ 894/* Libertas callbacks */
762/*******************************************************************/ 895/*******************************************************************/
@@ -923,6 +1056,32 @@ static void if_sdio_reset_card(struct lbs_private *priv)
923 schedule_work(&card_reset_work); 1056 schedule_work(&card_reset_work);
924} 1057}
925 1058
1059static int if_sdio_power_save(struct lbs_private *priv)
1060{
1061 struct if_sdio_card *card = priv->card;
1062 int ret;
1063
1064 flush_workqueue(card->workqueue);
1065
1066 ret = if_sdio_power_off(card);
1067
1068 /* Let runtime PM know the card is powered off */
1069 pm_runtime_put_sync(&card->func->dev);
1070
1071 return ret;
1072}
1073
1074static int if_sdio_power_restore(struct lbs_private *priv)
1075{
1076 struct if_sdio_card *card = priv->card;
1077
1078 /* Make sure the card will not be powered off by runtime PM */
1079 pm_runtime_get_sync(&card->func->dev);
1080
1081 return if_sdio_power_on(card);
1082}
1083
1084
926/*******************************************************************/ 1085/*******************************************************************/
927/* SDIO callbacks */ 1086/* SDIO callbacks */
928/*******************************************************************/ 1087/*******************************************************************/
@@ -976,7 +1135,6 @@ static int if_sdio_probe(struct sdio_func *func,
976 int ret, i; 1135 int ret, i;
977 unsigned int model; 1136 unsigned int model;
978 struct if_sdio_packet *packet; 1137 struct if_sdio_packet *packet;
979 struct mmc_host *host = func->card->host;
980 1138
981 lbs_deb_enter(LBS_DEB_SDIO); 1139 lbs_deb_enter(LBS_DEB_SDIO);
982 1140
@@ -1033,45 +1191,6 @@ static int if_sdio_probe(struct sdio_func *func,
1033 goto free; 1191 goto free;
1034 } 1192 }
1035 1193
1036 sdio_claim_host(func);
1037
1038 ret = sdio_enable_func(func);
1039 if (ret)
1040 goto release;
1041
1042 /* For 1-bit transfers to the 8686 model, we need to enable the
1043 * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
1044 * bit to allow access to non-vendor registers. */
1045 if ((card->model == MODEL_8686) &&
1046 (host->caps & MMC_CAP_SDIO_IRQ) &&
1047 (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
1048 u8 reg;
1049
1050 func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
1051 reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
1052 if (ret)
1053 goto release_int;
1054
1055 reg |= SDIO_BUS_ECSI;
1056 sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
1057 if (ret)
1058 goto release_int;
1059 }
1060
1061 card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
1062 if (ret)
1063 goto release_int;
1064
1065 card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
1066 if (ret)
1067 goto release_int;
1068
1069 card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
1070 if (ret)
1071 goto release_int;
1072
1073 sdio_release_host(func);
1074
1075 sdio_set_drvdata(func, card); 1194 sdio_set_drvdata(func, card);
1076 1195
1077 lbs_deb_sdio("class = 0x%X, vendor = 0x%X, " 1196 lbs_deb_sdio("class = 0x%X, vendor = 0x%X, "
@@ -1079,14 +1198,11 @@ static int if_sdio_probe(struct sdio_func *func,
1079 func->class, func->vendor, func->device, 1198 func->class, func->vendor, func->device,
1080 model, (unsigned)card->ioport); 1199 model, (unsigned)card->ioport);
1081 1200
1082 ret = if_sdio_prog_firmware(card);
1083 if (ret)
1084 goto reclaim;
1085 1201
1086 priv = lbs_add_card(card, &func->dev); 1202 priv = lbs_add_card(card, &func->dev);
1087 if (!priv) { 1203 if (!priv) {
1088 ret = -ENOMEM; 1204 ret = -ENOMEM;
1089 goto reclaim; 1205 goto free;
1090 } 1206 }
1091 1207
1092 card->priv = priv; 1208 card->priv = priv;
@@ -1097,62 +1213,21 @@ static int if_sdio_probe(struct sdio_func *func,
1097 priv->exit_deep_sleep = if_sdio_exit_deep_sleep; 1213 priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
1098 priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup; 1214 priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
1099 priv->reset_card = if_sdio_reset_card; 1215 priv->reset_card = if_sdio_reset_card;
1216 priv->power_save = if_sdio_power_save;
1217 priv->power_restore = if_sdio_power_restore;
1100 1218
1101 sdio_claim_host(func); 1219 ret = if_sdio_power_on(card);
1102
1103 /*
1104 * Get rx_unit if the chip is SD8688 or newer.
1105 * SD8385 & SD8686 do not have rx_unit.
1106 */
1107 if ((card->model != MODEL_8385)
1108 && (card->model != MODEL_8686))
1109 card->rx_unit = if_sdio_read_rx_unit(card);
1110 else
1111 card->rx_unit = 0;
1112
1113 /*
1114 * Set up the interrupt handler late.
1115 *
1116 * If we set it up earlier, the (buggy) hardware generates a spurious
1117 * interrupt, even before the interrupt has been enabled, with
1118 * CCCR_INTx = 0.
1119 *
1120 * We register the interrupt handler late so that we can handle any
1121 * spurious interrupts, and also to avoid generation of that known
1122 * spurious interrupt in the first place.
1123 */
1124 ret = sdio_claim_irq(func, if_sdio_interrupt);
1125 if (ret)
1126 goto disable;
1127
1128 /*
1129 * Enable interrupts now that everything is set up
1130 */
1131 sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
1132 sdio_release_host(func);
1133 if (ret) 1220 if (ret)
1134 goto reclaim; 1221 goto err_activate_card;
1135
1136 priv->fw_ready = 1;
1137
1138 /*
1139 * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
1140 */
1141 if (card->model == MODEL_8688) {
1142 struct cmd_header cmd;
1143
1144 memset(&cmd, 0, sizeof(cmd));
1145
1146 lbs_deb_sdio("send function INIT command\n");
1147 if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
1148 lbs_cmd_copyback, (unsigned long) &cmd))
1149 netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");
1150 }
1151 1222
1152 ret = lbs_start_card(priv); 1223 ret = lbs_start_card(priv);
1224 if_sdio_power_off(card);
1153 if (ret) 1225 if (ret)
1154 goto err_activate_card; 1226 goto err_activate_card;
1155 1227
1228 /* Tell PM core that we don't need the card to be powered now */
1229 pm_runtime_put_noidle(&func->dev);
1230
1156out: 1231out:
1157 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); 1232 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
1158 1233
@@ -1161,14 +1236,6 @@ out:
1161err_activate_card: 1236err_activate_card:
1162 flush_workqueue(card->workqueue); 1237 flush_workqueue(card->workqueue);
1163 lbs_remove_card(priv); 1238 lbs_remove_card(priv);
1164reclaim:
1165 sdio_claim_host(func);
1166release_int:
1167 sdio_release_irq(func);
1168disable:
1169 sdio_disable_func(func);
1170release:
1171 sdio_release_host(func);
1172free: 1239free:
1173 destroy_workqueue(card->workqueue); 1240 destroy_workqueue(card->workqueue);
1174 while (card->packets) { 1241 while (card->packets) {
@@ -1195,6 +1262,9 @@ static void if_sdio_remove(struct sdio_func *func)
1195 1262
1196 card = sdio_get_drvdata(func); 1263 card = sdio_get_drvdata(func);
1197 1264
1265 /* Undo decrement done above in if_sdio_probe */
1266 pm_runtime_get_noresume(&func->dev);
1267
1198 if (user_rmmod && (card->model == MODEL_8688)) { 1268 if (user_rmmod && (card->model == MODEL_8688)) {
1199 /* 1269 /*
1200 * FUNC_SHUTDOWN is required for SD8688 WLAN/BT 1270 * FUNC_SHUTDOWN is required for SD8688 WLAN/BT
@@ -1219,11 +1289,6 @@ static void if_sdio_remove(struct sdio_func *func)
1219 flush_workqueue(card->workqueue); 1289 flush_workqueue(card->workqueue);
1220 destroy_workqueue(card->workqueue); 1290 destroy_workqueue(card->workqueue);
1221 1291
1222 sdio_claim_host(func);
1223 sdio_release_irq(func);
1224 sdio_disable_func(func);
1225 sdio_release_host(func);
1226
1227 while (card->packets) { 1292 while (card->packets) {
1228 packet = card->packets; 1293 packet = card->packets;
1229 card->packets = card->packets->next; 1294 card->packets = card->packets->next;
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index e0286cfbc91d..622ae6de0d8b 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -531,10 +531,6 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
531 goto out; 531 goto out;
532 err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG, 532 err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
533 IF_SPI_CIC_CMD_DOWNLOAD_OVER); 533 IF_SPI_CIC_CMD_DOWNLOAD_OVER);
534 goto out;
535
536 lbs_deb_spi("waiting for helper to boot...\n");
537
538out: 534out:
539 if (err) 535 if (err)
540 pr_err("failed to load helper firmware (err=%d)\n", err); 536 pr_err("failed to load helper firmware (err=%d)\n", err);
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index b5acc393a65a..0c846f5a646a 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -324,7 +324,7 @@ static int if_usb_probe(struct usb_interface *intf,
324 } 324 }
325 kparam_unblock_sysfs_write(fw_name); 325 kparam_unblock_sysfs_write(fw_name);
326 326
327 if (!(priv = lbs_add_card(cardp, &udev->dev))) 327 if (!(priv = lbs_add_card(cardp, &intf->dev)))
328 goto err_prog_firmware; 328 goto err_prog_firmware;
329 329
330 cardp->priv = priv; 330 cardp->priv = priv;
@@ -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}
@@ -1112,6 +1112,15 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
1112 if (priv->psstate != PS_STATE_FULL_POWER) 1112 if (priv->psstate != PS_STATE_FULL_POWER)
1113 return -1; 1113 return -1;
1114 1114
1115#ifdef CONFIG_OLPC
1116 if (machine_is_olpc()) {
1117 if (priv->wol_criteria == EHS_REMOVE_WAKEUP)
1118 olpc_ec_wakeup_clear(EC_SCI_SRC_WLAN);
1119 else
1120 olpc_ec_wakeup_set(EC_SCI_SRC_WLAN);
1121 }
1122#endif
1123
1115 ret = lbs_suspend(priv); 1124 ret = lbs_suspend(priv);
1116 if (ret) 1125 if (ret)
1117 goto out; 1126 goto out;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 2fdeb81ce5b2..d1c1d52931f1 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -23,6 +23,7 @@
23#include "cfg.h" 23#include "cfg.h"
24#include "debugfs.h" 24#include "debugfs.h"
25#include "cmd.h" 25#include "cmd.h"
26#include "mesh.h"
26 27
27#define DRIVER_RELEASE_VERSION "323.p0" 28#define DRIVER_RELEASE_VERSION "323.p0"
28const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION 29const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
@@ -98,6 +99,37 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
98 return 0; 99 return 0;
99} 100}
100 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}
101 133
102/** 134/**
103 * lbs_dev_open - open the ethX interface 135 * lbs_dev_open - open the ethX interface
@@ -111,23 +143,64 @@ static int lbs_dev_open(struct net_device *dev)
111 int ret = 0; 143 int ret = 0;
112 144
113 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 }
114 151
115 spin_lock_irq(&priv->driver_lock); 152 spin_lock_irq(&priv->driver_lock);
116 priv->stopping = false;
117 153
118 if (priv->connect_status == LBS_CONNECTED) 154 netif_carrier_off(dev);
119 netif_carrier_on(dev);
120 else
121 netif_carrier_off(dev);
122 155
123 if (!priv->tx_pending_len) 156 if (!priv->tx_pending_len)
124 netif_wake_queue(dev); 157 netif_wake_queue(dev);
125 158
126 spin_unlock_irq(&priv->driver_lock); 159 spin_unlock_irq(&priv->driver_lock);
160
161out:
127 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); 162 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
128 return ret; 163 return ret;
129} 164}
130 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
131/** 204/**
132 * lbs_eth_stop - close the ethX interface 205 * lbs_eth_stop - close the ethX interface
133 * 206 *
@@ -140,18 +213,25 @@ static int lbs_eth_stop(struct net_device *dev)
140 213
141 lbs_deb_enter(LBS_DEB_NET); 214 lbs_deb_enter(LBS_DEB_NET);
142 215
216 if (priv->connect_status == LBS_CONNECTED)
217 lbs_disconnect(priv, WLAN_REASON_DEAUTH_LEAVING);
218
143 spin_lock_irq(&priv->driver_lock); 219 spin_lock_irq(&priv->driver_lock);
144 priv->stopping = true;
145 netif_stop_queue(dev); 220 netif_stop_queue(dev);
146 spin_unlock_irq(&priv->driver_lock); 221 spin_unlock_irq(&priv->driver_lock);
147 222
148 schedule_work(&priv->mcast_work); 223 lbs_update_mcast(priv);
149 cancel_delayed_work_sync(&priv->scan_work); 224 cancel_delayed_work_sync(&priv->scan_work);
150 if (priv->scan_req) { 225 if (priv->scan_req) {
151 cfg80211_scan_done(priv->scan_req, false); 226 cfg80211_scan_done(priv->scan_req, false);
152 priv->scan_req = NULL; 227 priv->scan_req = NULL;
153 } 228 }
154 229
230 netif_carrier_off(priv->dev);
231
232 if (!lbs_iface_active(priv))
233 lbs_stop_iface(priv);
234
155 lbs_deb_leave(LBS_DEB_NET); 235 lbs_deb_leave(LBS_DEB_NET);
156 return 0; 236 return 0;
157} 237}
@@ -169,7 +249,7 @@ void lbs_host_to_card_done(struct lbs_private *priv)
169 /* Wake main thread if commands are pending */ 249 /* Wake main thread if commands are pending */
170 if (!priv->cur_cmd || priv->tx_pending_len > 0) { 250 if (!priv->cur_cmd || priv->tx_pending_len > 0) {
171 if (!priv->wakeup_dev_required) 251 if (!priv->wakeup_dev_required)
172 wake_up_interruptible(&priv->waitq); 252 wake_up(&priv->waitq);
173 } 253 }
174 254
175 spin_unlock_irqrestore(&priv->driver_lock, flags); 255 spin_unlock_irqrestore(&priv->driver_lock, flags);
@@ -182,29 +262,24 @@ int lbs_set_mac_address(struct net_device *dev, void *addr)
182 int ret = 0; 262 int ret = 0;
183 struct lbs_private *priv = dev->ml_priv; 263 struct lbs_private *priv = dev->ml_priv;
184 struct sockaddr *phwaddr = addr; 264 struct sockaddr *phwaddr = addr;
185 struct cmd_ds_802_11_mac_address cmd;
186 265
187 lbs_deb_enter(LBS_DEB_NET); 266 lbs_deb_enter(LBS_DEB_NET);
188 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
189 /* In case it was called from the mesh device */ 275 /* In case it was called from the mesh device */
190 dev = priv->dev; 276 dev = priv->dev;
191 277
192 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
193 cmd.action = cpu_to_le16(CMD_ACT_SET);
194 memcpy(cmd.macadd, phwaddr->sa_data, ETH_ALEN);
195
196 ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd);
197 if (ret) {
198 lbs_deb_net("set MAC address failed\n");
199 goto done;
200 }
201
202 memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN); 278 memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN);
203 memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN); 279 memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
204 if (priv->mesh_dev) 280 if (priv->mesh_dev)
205 memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN); 281 memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
206 282
207done:
208 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); 283 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
209 return ret; 284 return ret;
210} 285}
@@ -258,18 +333,18 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
258 return i; 333 return i;
259} 334}
260 335
261static void lbs_set_mcast_worker(struct work_struct *work) 336void lbs_update_mcast(struct lbs_private *priv)
262{ 337{
263 struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
264 struct cmd_ds_mac_multicast_adr mcast_cmd; 338 struct cmd_ds_mac_multicast_adr mcast_cmd;
265 int dev_flags; 339 int dev_flags = 0;
266 int nr_addrs; 340 int nr_addrs;
267 int old_mac_control = priv->mac_control; 341 int old_mac_control = priv->mac_control;
268 342
269 lbs_deb_enter(LBS_DEB_NET); 343 lbs_deb_enter(LBS_DEB_NET);
270 344
271 dev_flags = priv->dev->flags; 345 if (netif_running(priv->dev))
272 if (priv->mesh_dev) 346 dev_flags |= priv->dev->flags;
347 if (priv->mesh_dev && netif_running(priv->mesh_dev))
273 dev_flags |= priv->mesh_dev->flags; 348 dev_flags |= priv->mesh_dev->flags;
274 349
275 if (dev_flags & IFF_PROMISC) { 350 if (dev_flags & IFF_PROMISC) {
@@ -315,6 +390,12 @@ static void lbs_set_mcast_worker(struct work_struct *work)
315 lbs_deb_leave(LBS_DEB_NET); 390 lbs_deb_leave(LBS_DEB_NET);
316} 391}
317 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
318void lbs_set_multicast_list(struct net_device *dev) 399void lbs_set_multicast_list(struct net_device *dev)
319{ 400{
320 struct lbs_private *priv = dev->ml_priv; 401 struct lbs_private *priv = dev->ml_priv;
@@ -647,7 +728,7 @@ static void lbs_cmd_timeout_handler(unsigned long data)
647 if (priv->dnld_sent == DNLD_CMD_SENT) 728 if (priv->dnld_sent == DNLD_CMD_SENT)
648 priv->dnld_sent = DNLD_RES_RECEIVED; 729 priv->dnld_sent = DNLD_RES_RECEIVED;
649 730
650 wake_up_interruptible(&priv->waitq); 731 wake_up(&priv->waitq);
651out: 732out:
652 spin_unlock_irqrestore(&priv->driver_lock, flags); 733 spin_unlock_irqrestore(&priv->driver_lock, flags);
653 lbs_deb_leave(LBS_DEB_CMD); 734 lbs_deb_leave(LBS_DEB_CMD);
@@ -889,10 +970,6 @@ void lbs_remove_card(struct lbs_private *priv)
889 lbs_remove_mesh(priv); 970 lbs_remove_mesh(priv);
890 lbs_scan_deinit(priv); 971 lbs_scan_deinit(priv);
891 972
892 dev = priv->dev;
893
894 cancel_work_sync(&priv->mcast_work);
895
896 /* worker thread destruction blocks on the in-flight command which 973 /* worker thread destruction blocks on the in-flight command which
897 * should have been cleared already in lbs_stop_card(). 974 * should have been cleared already in lbs_stop_card().
898 */ 975 */
@@ -950,17 +1027,18 @@ int lbs_start_card(struct lbs_private *priv)
950 if (ret) 1027 if (ret)
951 goto done; 1028 goto done;
952 1029
1030 if (!lbs_disablemesh)
1031 lbs_init_mesh(priv);
1032 else
1033 pr_info("%s: mesh disabled\n", dev->name);
1034
953 if (lbs_cfg_register(priv)) { 1035 if (lbs_cfg_register(priv)) {
954 pr_err("cannot register device\n"); 1036 pr_err("cannot register device\n");
955 goto done; 1037 goto done;
956 } 1038 }
957 1039
958 lbs_update_channel(priv); 1040 if (lbs_mesh_activated(priv))
959 1041 lbs_start_mesh(priv);
960 if (!lbs_disablemesh)
961 lbs_init_mesh(priv);
962 else
963 pr_info("%s: mesh disabled\n", dev->name);
964 1042
965 lbs_debugfs_init_one(priv, dev); 1043 lbs_debugfs_init_one(priv, dev);
966 1044
@@ -978,8 +1056,6 @@ EXPORT_SYMBOL_GPL(lbs_start_card);
978void lbs_stop_card(struct lbs_private *priv) 1056void lbs_stop_card(struct lbs_private *priv)
979{ 1057{
980 struct net_device *dev; 1058 struct net_device *dev;
981 struct cmd_ctrl_node *cmdnode;
982 unsigned long flags;
983 1059
984 lbs_deb_enter(LBS_DEB_MAIN); 1060 lbs_deb_enter(LBS_DEB_MAIN);
985 1061
@@ -992,30 +1068,6 @@ void lbs_stop_card(struct lbs_private *priv)
992 1068
993 lbs_debugfs_remove_one(priv); 1069 lbs_debugfs_remove_one(priv);
994 lbs_deinit_mesh(priv); 1070 lbs_deinit_mesh(priv);
995
996 /* Delete the timeout of the currently processing command */
997 del_timer_sync(&priv->command_timer);
998 del_timer_sync(&priv->auto_deepsleep_timer);
999
1000 /* Flush pending command nodes */
1001 spin_lock_irqsave(&priv->driver_lock, flags);
1002 lbs_deb_main("clearing pending commands\n");
1003 list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
1004 cmdnode->result = -ENOENT;
1005 cmdnode->cmdwaitqwoken = 1;
1006 wake_up(&cmdnode->cmdwait_q);
1007 }
1008
1009 /* Flush the command the card is currently processing */
1010 if (priv->cur_cmd) {
1011 lbs_deb_main("clearing current command\n");
1012 priv->cur_cmd->result = -ENOENT;
1013 priv->cur_cmd->cmdwaitqwoken = 1;
1014 wake_up(&priv->cur_cmd->cmdwait_q);
1015 }
1016 lbs_deb_main("done clearing commands\n");
1017 spin_unlock_irqrestore(&priv->driver_lock, flags);
1018
1019 unregister_netdev(dev); 1071 unregister_netdev(dev);
1020 1072
1021out: 1073out:
@@ -1036,7 +1088,7 @@ void lbs_queue_event(struct lbs_private *priv, u32 event)
1036 1088
1037 kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32)); 1089 kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32));
1038 1090
1039 wake_up_interruptible(&priv->waitq); 1091 wake_up(&priv->waitq);
1040 1092
1041 spin_unlock_irqrestore(&priv->driver_lock, flags); 1093 spin_unlock_irqrestore(&priv->driver_lock, flags);
1042 lbs_deb_leave(LBS_DEB_THREAD); 1094 lbs_deb_leave(LBS_DEB_THREAD);
@@ -1054,7 +1106,7 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
1054 BUG_ON(resp_idx > 1); 1106 BUG_ON(resp_idx > 1);
1055 priv->resp_idx = resp_idx; 1107 priv->resp_idx = resp_idx;
1056 1108
1057 wake_up_interruptible(&priv->waitq); 1109 wake_up(&priv->waitq);
1058 1110
1059 lbs_deb_leave(LBS_DEB_THREAD); 1111 lbs_deb_leave(LBS_DEB_THREAD);
1060} 1112}
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index 8e3104d990fb..e87c031b298f 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -129,6 +129,19 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
129 return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); 129 return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
130} 130}
131 131
132int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
133{
134 return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
135}
136
137static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
138{
139 struct wireless_dev *mesh_wdev = priv->mesh_dev->ieee80211_ptr;
140 if (mesh_wdev->channel)
141 return mesh_wdev->channel->hw_value;
142 else
143 return 1;
144}
132 145
133/*************************************************************************** 146/***************************************************************************
134 * Mesh sysfs support 147 * Mesh sysfs support
@@ -812,7 +825,6 @@ static void lbs_persist_config_remove(struct net_device *dev)
812 */ 825 */
813int lbs_init_mesh(struct lbs_private *priv) 826int lbs_init_mesh(struct lbs_private *priv)
814{ 827{
815 struct net_device *dev = priv->dev;
816 int ret = 0; 828 int ret = 0;
817 829
818 lbs_deb_enter(LBS_DEB_MESH); 830 lbs_deb_enter(LBS_DEB_MESH);
@@ -837,11 +849,9 @@ int lbs_init_mesh(struct lbs_private *priv)
837 useful */ 849 useful */
838 850
839 priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID; 851 priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
840 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 852 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
841 priv->channel)) {
842 priv->mesh_tlv = TLV_TYPE_MESH_ID; 853 priv->mesh_tlv = TLV_TYPE_MESH_ID;
843 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 854 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
844 priv->channel))
845 priv->mesh_tlv = 0; 855 priv->mesh_tlv = 0;
846 } 856 }
847 } else 857 } else
@@ -851,23 +861,16 @@ int lbs_init_mesh(struct lbs_private *priv)
851 * 0x100+37; Do not invoke command with old TLV. 861 * 0x100+37; Do not invoke command with old TLV.
852 */ 862 */
853 priv->mesh_tlv = TLV_TYPE_MESH_ID; 863 priv->mesh_tlv = TLV_TYPE_MESH_ID;
854 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 864 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
855 priv->channel))
856 priv->mesh_tlv = 0; 865 priv->mesh_tlv = 0;
857 } 866 }
858 867
859 /* Stop meshing until interface is brought up */ 868 /* Stop meshing until interface is brought up */
860 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel); 869 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
861 870
862 if (priv->mesh_tlv) { 871 if (priv->mesh_tlv) {
863 sprintf(priv->mesh_ssid, "mesh"); 872 sprintf(priv->mesh_ssid, "mesh");
864 priv->mesh_ssid_len = 4; 873 priv->mesh_ssid_len = 4;
865
866 lbs_add_mesh(priv);
867
868 if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
869 netdev_err(dev, "cannot register lbs_mesh attribute\n");
870
871 ret = 1; 874 ret = 1;
872 } 875 }
873 876
@@ -875,6 +878,13 @@ int lbs_init_mesh(struct lbs_private *priv)
875 return ret; 878 return ret;
876} 879}
877 880
881void lbs_start_mesh(struct lbs_private *priv)
882{
883 lbs_add_mesh(priv);
884
885 if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
886 netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
887}
878 888
879int lbs_deinit_mesh(struct lbs_private *priv) 889int lbs_deinit_mesh(struct lbs_private *priv)
880{ 890{
@@ -904,7 +914,8 @@ static int lbs_mesh_stop(struct net_device *dev)
904 struct lbs_private *priv = dev->ml_priv; 914 struct lbs_private *priv = dev->ml_priv;
905 915
906 lbs_deb_enter(LBS_DEB_MESH); 916 lbs_deb_enter(LBS_DEB_MESH);
907 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel); 917 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
918 lbs_mesh_get_channel(priv));
908 919
909 spin_lock_irq(&priv->driver_lock); 920 spin_lock_irq(&priv->driver_lock);
910 921
@@ -913,7 +924,9 @@ static int lbs_mesh_stop(struct net_device *dev)
913 924
914 spin_unlock_irq(&priv->driver_lock); 925 spin_unlock_irq(&priv->driver_lock);
915 926
916 schedule_work(&priv->mcast_work); 927 lbs_update_mcast(priv);
928 if (!lbs_iface_active(priv))
929 lbs_stop_iface(priv);
917 930
918 lbs_deb_leave(LBS_DEB_MESH); 931 lbs_deb_leave(LBS_DEB_MESH);
919 return 0; 932 return 0;
@@ -931,6 +944,11 @@ static int lbs_mesh_dev_open(struct net_device *dev)
931 int ret = 0; 944 int ret = 0;
932 945
933 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 }
934 952
935 spin_lock_irq(&priv->driver_lock); 953 spin_lock_irq(&priv->driver_lock);
936 954
@@ -947,7 +965,8 @@ static int lbs_mesh_dev_open(struct net_device *dev)
947 965
948 spin_unlock_irq(&priv->driver_lock); 966 spin_unlock_irq(&priv->driver_lock);
949 967
950 ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->channel); 968 ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
969 lbs_mesh_get_channel(priv));
951 970
952out: 971out:
953 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); 972 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
@@ -971,18 +990,32 @@ static const struct net_device_ops mesh_netdev_ops = {
971static int lbs_add_mesh(struct lbs_private *priv) 990static int lbs_add_mesh(struct lbs_private *priv)
972{ 991{
973 struct net_device *mesh_dev = NULL; 992 struct net_device *mesh_dev = NULL;
993 struct wireless_dev *mesh_wdev;
974 int ret = 0; 994 int ret = 0;
975 995
976 lbs_deb_enter(LBS_DEB_MESH); 996 lbs_deb_enter(LBS_DEB_MESH);
977 997
978 /* Allocate a virtual mesh device */ 998 /* Allocate a virtual mesh device */
999 mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
1000 if (!mesh_wdev) {
1001 lbs_deb_mesh("init mshX wireless device failed\n");
1002 ret = -ENOMEM;
1003 goto done;
1004 }
1005
979 mesh_dev = alloc_netdev(0, "msh%d", ether_setup); 1006 mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
980 if (!mesh_dev) { 1007 if (!mesh_dev) {
981 lbs_deb_mesh("init mshX device failed\n"); 1008 lbs_deb_mesh("init mshX device failed\n");
982 ret = -ENOMEM; 1009 ret = -ENOMEM;
983 goto done; 1010 goto err_free_wdev;
984 } 1011 }
1012
1013 mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
1014 mesh_wdev->wiphy = priv->wdev->wiphy;
1015 mesh_wdev->netdev = mesh_dev;
1016
985 mesh_dev->ml_priv = priv; 1017 mesh_dev->ml_priv = priv;
1018 mesh_dev->ieee80211_ptr = mesh_wdev;
986 priv->mesh_dev = mesh_dev; 1019 priv->mesh_dev = mesh_dev;
987 1020
988 mesh_dev->netdev_ops = &mesh_netdev_ops; 1021 mesh_dev->netdev_ops = &mesh_netdev_ops;
@@ -996,7 +1029,7 @@ static int lbs_add_mesh(struct lbs_private *priv)
996 ret = register_netdev(mesh_dev); 1029 ret = register_netdev(mesh_dev);
997 if (ret) { 1030 if (ret) {
998 pr_err("cannot register mshX virtual interface\n"); 1031 pr_err("cannot register mshX virtual interface\n");
999 goto err_free; 1032 goto err_free_netdev;
1000 } 1033 }
1001 1034
1002 ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); 1035 ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
@@ -1012,9 +1045,12 @@ static int lbs_add_mesh(struct lbs_private *priv)
1012err_unregister: 1045err_unregister:
1013 unregister_netdev(mesh_dev); 1046 unregister_netdev(mesh_dev);
1014 1047
1015err_free: 1048err_free_netdev:
1016 free_netdev(mesh_dev); 1049 free_netdev(mesh_dev);
1017 1050
1051err_free_wdev:
1052 kfree(mesh_wdev);
1053
1018done: 1054done:
1019 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); 1055 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
1020 return ret; 1056 return ret;
@@ -1035,6 +1071,7 @@ void lbs_remove_mesh(struct lbs_private *priv)
1035 lbs_persist_config_remove(mesh_dev); 1071 lbs_persist_config_remove(mesh_dev);
1036 unregister_netdev(mesh_dev); 1072 unregister_netdev(mesh_dev);
1037 priv->mesh_dev = NULL; 1073 priv->mesh_dev = NULL;
1074 kfree(mesh_dev->ieee80211_ptr);
1038 free_netdev(mesh_dev); 1075 free_netdev(mesh_dev);
1039 lbs_deb_leave(LBS_DEB_MESH); 1076 lbs_deb_leave(LBS_DEB_MESH);
1040} 1077}
diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h
index 50144913f2ab..6603f341c874 100644
--- a/drivers/net/wireless/libertas/mesh.h
+++ b/drivers/net/wireless/libertas/mesh.h
@@ -9,30 +9,25 @@
9#include <net/lib80211.h> 9#include <net/lib80211.h>
10 10
11#include "host.h" 11#include "host.h"
12#include "dev.h"
12 13
13#ifdef CONFIG_LIBERTAS_MESH 14#ifdef CONFIG_LIBERTAS_MESH
14 15
15/* Mesh statistics */
16struct lbs_mesh_stats {
17 u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
18 u32 fwd_unicast_cnt; /* Fwd: Unicast counter */
19 u32 fwd_drop_ttl; /* Fwd: TTL zero */
20 u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */
21 u32 fwd_drop_noroute; /* Fwd: No route to Destination */
22 u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */
23 u32 drop_blind; /* Rx: Dropped by blinding table */
24 u32 tx_failed_cnt; /* Tx: Failed transmissions */
25};
26
27
28struct net_device; 16struct net_device;
29struct lbs_private;
30 17
31int lbs_init_mesh(struct lbs_private *priv); 18int lbs_init_mesh(struct lbs_private *priv);
19void lbs_start_mesh(struct lbs_private *priv);
32int lbs_deinit_mesh(struct lbs_private *priv); 20int lbs_deinit_mesh(struct lbs_private *priv);
33 21
34void lbs_remove_mesh(struct lbs_private *priv); 22void lbs_remove_mesh(struct lbs_private *priv);
35 23
24static inline bool lbs_mesh_activated(struct lbs_private *priv)
25{
26 /* Mesh SSID is only programmed after successful init */
27 return priv->mesh_ssid_len != 0;
28}
29
30int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel);
36 31
37/* Sending / Receiving */ 32/* Sending / Receiving */
38 33
@@ -67,11 +62,13 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev,
67 62
68#define lbs_init_mesh(priv) 63#define lbs_init_mesh(priv)
69#define lbs_deinit_mesh(priv) 64#define lbs_deinit_mesh(priv)
65#define lbs_start_mesh(priv)
70#define lbs_add_mesh(priv) 66#define lbs_add_mesh(priv)
71#define lbs_remove_mesh(priv) 67#define lbs_remove_mesh(priv)
72#define lbs_mesh_set_dev(priv, dev, rxpd) (dev) 68#define lbs_mesh_set_dev(priv, dev, rxpd) (dev)
73#define lbs_mesh_set_txpd(priv, dev, txpd) 69#define lbs_mesh_set_txpd(priv, dev, txpd)
74#define lbs_mesh_config(priv, enable, chan) 70#define lbs_mesh_set_channel(priv, channel) (0)
71#define lbs_mesh_activated(priv) (false)
75 72
76#endif 73#endif
77 74
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index bfb8898ae518..62e10eeadd7e 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -15,6 +15,7 @@
15#include "radiotap.h" 15#include "radiotap.h"
16#include "decl.h" 16#include "decl.h"
17#include "dev.h" 17#include "dev.h"
18#include "mesh.h"
18 19
19struct eth803hdr { 20struct eth803hdr {
20 u8 dest_addr[6]; 21 u8 dest_addr[6];
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index a6e85134cfe1..8f127520d786 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -12,6 +12,7 @@
12#include "decl.h" 12#include "decl.h"
13#include "defs.h" 13#include "defs.h"
14#include "dev.h" 14#include "dev.h"
15#include "mesh.h"
15 16
16/** 17/**
17 * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE 18 * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE