diff options
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r-- | drivers/net/wireless/libertas/cfg.c | 69 | ||||
-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 | 28 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/ethtool.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/if_sdio.c | 277 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/if_spi.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/if_usb.c | 13 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 180 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/mesh.c | 77 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/mesh.h | 27 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/rx.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/tx.c | 1 |
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 | ||
1405 | static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, | 1412 | int 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 | ||
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 | } | ||
1434 | 1451 | ||
1435 | static int lbs_cfg_set_default_key(struct wiphy *wiphy, | 1452 | static 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); | |||
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 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 */ | ||
25 | struct 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 */ |
27 | struct lbs_private { | 37 | struct 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 | ||
173 | extern struct cmd_confirm_sleep confirm_sleep; | 185 | extern struct cmd_confirm_sleep confirm_sleep; |
174 | 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 | |||
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 | ||
10 | static void lbs_ethtool_get_drvinfo(struct net_device *dev, | 11 | static 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 | ||
51 | static 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 | |||
767 | static 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 | |||
869 | release_irq: | ||
870 | sdio_release_irq(func); | ||
871 | disable: | ||
872 | sdio_disable_func(func); | ||
873 | release: | ||
874 | sdio_release_host(func); | ||
875 | return ret; | ||
876 | } | ||
877 | |||
878 | static 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 | ||
1059 | static 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 | |||
1074 | static 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 | |||
1156 | out: | 1231 | out: |
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: | |||
1161 | err_activate_card: | 1236 | err_activate_card: |
1162 | flush_workqueue(card->workqueue); | 1237 | flush_workqueue(card->workqueue); |
1163 | lbs_remove_card(priv); | 1238 | lbs_remove_card(priv); |
1164 | reclaim: | ||
1165 | sdio_claim_host(func); | ||
1166 | release_int: | ||
1167 | sdio_release_irq(func); | ||
1168 | disable: | ||
1169 | sdio_disable_func(func); | ||
1170 | release: | ||
1171 | sdio_release_host(func); | ||
1172 | free: | 1239 | free: |
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 | |||
538 | out: | 534 | out: |
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" |
28 | const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION | 29 | const 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 | ||
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 | } | ||
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 | |||
161 | out: | ||
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 | ||
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 | |||
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 | ||
207 | done: | ||
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 | ||
261 | static void lbs_set_mcast_worker(struct work_struct *work) | 336 | void 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 | ||
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 | |||
318 | void lbs_set_multicast_list(struct net_device *dev) | 399 | void 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); |
651 | out: | 732 | out: |
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); | |||
978 | void lbs_stop_card(struct lbs_private *priv) | 1056 | void 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 | ||
1021 | out: | 1073 | out: |
@@ -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 | ||
132 | int 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 | |||
137 | static 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 | */ |
813 | int lbs_init_mesh(struct lbs_private *priv) | 826 | int 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 | ||
881 | void 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 | ||
879 | int lbs_deinit_mesh(struct lbs_private *priv) | 889 | int 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 | ||
952 | out: | 971 | out: |
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 = { | |||
971 | static int lbs_add_mesh(struct lbs_private *priv) | 990 | static 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) | |||
1012 | err_unregister: | 1045 | err_unregister: |
1013 | unregister_netdev(mesh_dev); | 1046 | unregister_netdev(mesh_dev); |
1014 | 1047 | ||
1015 | err_free: | 1048 | err_free_netdev: |
1016 | free_netdev(mesh_dev); | 1049 | free_netdev(mesh_dev); |
1017 | 1050 | ||
1051 | err_free_wdev: | ||
1052 | kfree(mesh_wdev); | ||
1053 | |||
1018 | done: | 1054 | done: |
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 */ | ||
16 | struct 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 | |||
28 | struct net_device; | 16 | struct net_device; |
29 | struct lbs_private; | ||
30 | 17 | ||
31 | int lbs_init_mesh(struct lbs_private *priv); | 18 | int lbs_init_mesh(struct lbs_private *priv); |
19 | void lbs_start_mesh(struct lbs_private *priv); | ||
32 | int lbs_deinit_mesh(struct lbs_private *priv); | 20 | int lbs_deinit_mesh(struct lbs_private *priv); |
33 | 21 | ||
34 | void lbs_remove_mesh(struct lbs_private *priv); | 22 | void lbs_remove_mesh(struct lbs_private *priv); |
35 | 23 | ||
24 | static 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 | |||
30 | int 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 | ||
19 | struct eth803hdr { | 20 | struct 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 |