aboutsummaryrefslogtreecommitdiff
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/Makefile1
-rw-r--r--drivers/net/wireless/libertas/README34
-rw-r--r--drivers/net/wireless/libertas/cfg.c397
-rw-r--r--drivers/net/wireless/libertas/cfg.h5
-rw-r--r--drivers/net/wireless/libertas/cmd.c400
-rw-r--r--drivers/net/wireless/libertas/cmd.h7
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c55
-rw-r--r--drivers/net/wireless/libertas/debugfs.c65
-rw-r--r--drivers/net/wireless/libertas/decl.h25
-rw-r--r--drivers/net/wireless/libertas/defs.h123
-rw-r--r--drivers/net/wireless/libertas/dev.h67
-rw-r--r--drivers/net/wireless/libertas/ethtool.c12
-rw-r--r--drivers/net/wireless/libertas/firmware.c227
-rw-r--r--drivers/net/wireless/libertas/host.h36
-rw-r--r--drivers/net/wireless/libertas/if_cs.c199
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c497
-rw-r--r--drivers/net/wireless/libertas/if_spi.c640
-rw-r--r--drivers/net/wireless/libertas/if_spi.h70
-rw-r--r--drivers/net/wireless/libertas/if_usb.c411
-rw-r--r--drivers/net/wireless/libertas/if_usb.h14
-rw-r--r--drivers/net/wireless/libertas/main.c591
-rw-r--r--drivers/net/wireless/libertas/mesh.c1140
-rw-r--r--drivers/net/wireless/libertas/mesh.h64
-rw-r--r--drivers/net/wireless/libertas/rx.c56
-rw-r--r--drivers/net/wireless/libertas/tx.c39
-rw-r--r--drivers/net/wireless/libertas/types.h18
26 files changed, 2861 insertions, 2332 deletions
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
index f7d01bfa2e4..eac72f7bd34 100644
--- a/drivers/net/wireless/libertas/Makefile
+++ b/drivers/net/wireless/libertas/Makefile
@@ -6,6 +6,7 @@ libertas-y += ethtool.o
libertas-y += main.o
libertas-y += rx.o
libertas-y += tx.o
+libertas-y += firmware.o
libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o
usb8xxx-objs += if_usb.o
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
index 60fd1afe89a..1a554a685e9 100644
--- a/drivers/net/wireless/libertas/README
+++ b/drivers/net/wireless/libertas/README
@@ -8,9 +8,8 @@
Ltd. under the terms of the GNU General Public License Version 2, June 1991
(the "License"). You may use, redistribute and/or modify this File in
accordance with the terms and conditions of the License, a copy of which
- is available along with the File in the license.txt file or by writing to
- the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ is available along with the File in the license.txt file or on the worldwide
+ web at http://www.gnu.org/licenses/gpl.txt.
THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
@@ -70,7 +69,7 @@ rdrf
These commands are used to read the MAC, BBP and RF registers from the
card. These commands take one parameter that specifies the offset
location that is to be read. This parameter must be specified in
- hexadecimal (its possible to preceed preceding the number with a "0x").
+ hexadecimal (its possible to precede preceding the number with a "0x").
Path: /sys/kernel/debug/libertas_wireless/ethX/registers/
@@ -84,7 +83,7 @@ wrrf
These commands are used to write the MAC, BBP and RF registers in the
card. These commands take two parameters that specify the offset
location and the value that is to be written. This parameters must
- be specified in hexadecimal (its possible to preceed the number
+ be specified in hexadecimal (its possible to precede the number
with a "0x").
Usage:
@@ -238,28 +237,3 @@ hostsleep
echo "1" > hostsleep : enable host sleep.
echo "0" > hostsleep : disable host sleep
-========================
-IWCONFIG COMMANDS
-========================
-power period
-
- This command is used to configure the station in deep sleep mode /
- auto deep sleep mode.
-
- The timer is implemented to monitor the activities (command, event,
- etc.). When an activity is detected station will exit from deep
- sleep mode automatically and restart the timer. At timer expiry
- (no activity for defined time period) the deep sleep mode is entered
- automatically.
-
- Note: this command is for SDIO interface only.
-
- Usage:
- To enable deep sleep mode do:
- iwconfig wlan0 power period 0
- To enable auto deep sleep mode with idle time period 5 seconds do:
- iwconfig wlan0 power period 5
- To disable deep sleep/auto deep sleep mode do:
- iwconfig wlan0 power period -1
-
-==============================================================================
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 373930afc26..47a998d8f99 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -6,11 +6,12 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/hardirq.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
#include <asm/unaligned.h>
@@ -18,6 +19,7 @@
#include "decl.h"
#include "cfg.h"
#include "cmd.h"
+#include "mesh.h"
#define CHAN2G(_channel, _freq, _flags) { \
@@ -101,7 +103,7 @@ static const u32 cipher_suites[] = {
* Convert NL80211's auth_type to the one from Libertas, see chapter 5.9.1
* in the firmware spec
*/
-static u8 lbs_auth_to_authtype(enum nl80211_auth_type auth_type)
+static int lbs_auth_to_authtype(enum nl80211_auth_type auth_type)
{
int ret = -ENOTSUPP;
@@ -124,8 +126,10 @@ static u8 lbs_auth_to_authtype(enum nl80211_auth_type auth_type)
}
-/* Various firmware commands need the list of supported rates, but with
- the hight-bit set for basic rates */
+/*
+ * Various firmware commands need the list of supported rates, but with
+ * the hight-bit set for basic rates
+ */
static int lbs_add_rates(u8 *rates)
{
size_t i;
@@ -294,6 +298,7 @@ static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
const u8 *rates_eid, *ext_rates_eid;
int n = 0;
+ rcu_read_lock();
rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
ext_rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
@@ -321,6 +326,7 @@ static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
*tlv++ = 0x96;
n = 4;
}
+ rcu_read_unlock();
rate_tlv->header.len = cpu_to_le16(n);
return sizeof(rate_tlv->header) + n;
@@ -427,34 +433,53 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
return ie_len + 2;
}
-/***************************************************************************
+/*
* Set Channel
*/
-static int lbs_cfg_set_channel(struct wiphy *wiphy,
- struct net_device *netdev,
- struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type)
+static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef)
{
struct lbs_private *priv = wiphy_priv(wiphy);
int ret = -ENOTSUPP;
lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
- channel->center_freq, channel_type);
+ chandef->chan->center_freq,
+ cfg80211_get_chandef_type(chandef));
- if (channel_type != NL80211_CHAN_NO_HT)
+ if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT)
goto out;
- ret = lbs_set_channel(priv, channel->hw_value);
+ ret = lbs_set_channel(priv, chandef->chan->hw_value);
out:
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
return ret;
}
+static int lbs_cfg_set_mesh_channel(struct wiphy *wiphy,
+ struct net_device *netdev,
+ struct ieee80211_channel *channel)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ int ret = -ENOTSUPP;
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d",
+ netdev_name(netdev), channel->center_freq);
+ if (netdev != priv->mesh_dev)
+ goto out;
-/***************************************************************************
+ ret = lbs_mesh_set_channel(priv, channel->hw_value);
+
+ out:
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+
+/*
* Scanning
*/
@@ -478,6 +503,7 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy,
static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
struct cmd_header *resp)
{
+ struct cfg80211_bss *bss;
struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
int bsssize;
const u8 *pos;
@@ -540,8 +566,10 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
goto done;
}
- /* Validity check: the TLV holds TSF values with 8 bytes each, so
- * the size in the TLV must match the nr_sets value */
+ /*
+ * Validity check: the TLV holds TSF values with 8 bytes each, so
+ * the size in the TLV must match the nr_sets value
+ */
i = get_unaligned_le16(tsfdesc);
tsfdesc += 2;
if (i / 8 != scanresp->nr_sets) {
@@ -583,15 +611,17 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
/* To find out the channel, we must parse the IEs */
ie = pos;
- /* 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon
- interval, capabilities */
+ /*
+ * 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon
+ * interval, capabilities
+ */
ielen = left = len - (6 + 1 + 8 + 2 + 2);
while (left >= 2) {
u8 id, elen;
id = *pos++;
elen = *pos++;
left -= 2;
- if (elen > left || elen == 0) {
+ if (elen > left) {
lbs_deb_scan("scan response: invalid IE fmt\n");
goto done;
}
@@ -609,7 +639,8 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
/* No channel, no luck */
if (chan_no != -1) {
struct wiphy *wiphy = priv->wdev->wiphy;
- int freq = ieee80211_channel_to_frequency(chan_no);
+ int freq = ieee80211_channel_to_frequency(chan_no,
+ IEEE80211_BAND_2GHZ);
struct ieee80211_channel *channel =
ieee80211_get_channel(wiphy, freq);
@@ -619,13 +650,15 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
print_ssid(ssid_buf, ssid, ssid_len),
LBS_SCAN_RSSI_TO_MBM(rssi)/100);
- if (channel ||
- !(channel->flags & IEEE80211_CHAN_DISABLED))
- cfg80211_inform_bss(wiphy, channel,
- bssid, le64_to_cpu(*(__le64 *)tsfdesc),
+ if (channel &&
+ !(channel->flags & IEEE80211_CHAN_DISABLED)) {
+ bss = cfg80211_inform_bss(wiphy, channel,
+ bssid, get_unaligned_le64(tsfdesc),
capa, intvl, ie, ielen,
LBS_SCAN_RSSI_TO_MBM(rssi),
GFP_KERNEL);
+ cfg80211_put_bss(wiphy, bss);
+ }
} else
lbs_deb_scan("scan response: missing BSS channel IE\n");
@@ -683,7 +716,7 @@ static void lbs_scan_worker(struct work_struct *work)
tlv = scan_cmd->tlvbuffer;
/* add SSID TLV */
- if (priv->scan_req->n_ssids)
+ if (priv->scan_req->n_ssids && priv->scan_req->ssids[0].ssid_len > 0)
tlv += lbs_add_ssid_tlv(tlv,
priv->scan_req->ssids[0].ssid,
priv->scan_req->ssids[0].ssid_len);
@@ -700,7 +733,7 @@ static void lbs_scan_worker(struct work_struct *work)
if (priv->scan_channel < priv->scan_req->n_channels) {
cancel_delayed_work(&priv->scan_work);
- if (!priv->stopping)
+ if (netif_running(priv->dev))
queue_delayed_work(priv->work_thread, &priv->scan_work,
msecs_to_jiffies(300));
}
@@ -718,13 +751,8 @@ static void lbs_scan_worker(struct work_struct *work)
if (priv->scan_channel >= priv->scan_req->n_channels) {
/* Mark scan done */
- if (priv->internal_scan)
- kfree(priv->scan_req);
- else
- cfg80211_scan_done(priv->scan_req, false);
-
- priv->scan_req = NULL;
- priv->last_scan = jiffies;
+ cancel_delayed_work(&priv->scan_work);
+ lbs_scan_done(priv);
}
/* Restart network */
@@ -754,17 +782,31 @@ static void _internal_start_scan(struct lbs_private *priv, bool internal,
request->n_ssids, request->n_channels, request->ie_len);
priv->scan_channel = 0;
- queue_delayed_work(priv->work_thread, &priv->scan_work,
- msecs_to_jiffies(50));
-
priv->scan_req = request;
priv->internal_scan = internal;
+ queue_delayed_work(priv->work_thread, &priv->scan_work,
+ msecs_to_jiffies(50));
+
lbs_deb_leave(LBS_DEB_CFG80211);
}
+/*
+ * Clean up priv->scan_req. Should be used to handle the allocation details.
+ */
+void lbs_scan_done(struct lbs_private *priv)
+{
+ WARN_ON(!priv->scan_req);
+
+ if (priv->internal_scan)
+ kfree(priv->scan_req);
+ else
+ cfg80211_scan_done(priv->scan_req, false);
+
+ priv->scan_req = NULL;
+}
+
static int lbs_cfg_scan(struct wiphy *wiphy,
- struct net_device *dev,
struct cfg80211_scan_request *request)
{
struct lbs_private *priv = wiphy_priv(wiphy);
@@ -791,7 +833,7 @@ static int lbs_cfg_scan(struct wiphy *wiphy,
-/***************************************************************************
+/*
* Events
*/
@@ -826,7 +868,7 @@ void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
-/***************************************************************************
+/*
* Connect/disconnect
*/
@@ -951,8 +993,10 @@ static int lbs_enable_rsn(struct lbs_private *priv, int enable)
* Set WPA/WPA key material
*/
-/* like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we
- * get rid of WEXT, this should go into host.h */
+/*
+ * like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we
+ * get rid of WEXT, this should go into host.h
+ */
struct cmd_key_material {
struct cmd_header hdr;
@@ -962,9 +1006,8 @@ struct cmd_key_material {
} __packed;
static int lbs_set_key_material(struct lbs_private *priv,
- int key_type,
- int key_info,
- u8 *key, u16 key_len)
+ int key_type, int key_info,
+ const u8 *key, u16 key_len)
{
struct cmd_key_material cmd;
int ret;
@@ -1098,11 +1141,13 @@ static int lbs_associate(struct lbs_private *priv,
cmd->capability = cpu_to_le16(bss->capability);
/* add SSID TLV */
+ rcu_read_lock();
ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
if (ssid_eid)
pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]);
else
lbs_deb_assoc("no SSID\n");
+ rcu_read_unlock();
/* add DS param TLV */
if (bss->channel)
@@ -1212,6 +1257,7 @@ static int lbs_associate(struct lbs_private *priv,
netif_tx_wake_all_queues(priv->dev);
}
+ kfree(cmd);
done:
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
return ret;
@@ -1221,14 +1267,9 @@ static struct cfg80211_scan_request *
_new_connect_scan_req(struct wiphy *wiphy, struct cfg80211_connect_params *sme)
{
struct cfg80211_scan_request *creq = NULL;
- int i, n_channels = 0;
+ int i, n_channels = ieee80211_get_num_supported_channels(wiphy);
enum ieee80211_band band;
- for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
- if (wiphy->bands[band])
- n_channels += wiphy->bands[band]->n_channels;
- }
-
creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
n_channels * sizeof(void *),
GFP_ATOMIC);
@@ -1282,27 +1323,32 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
int ret = 0;
u8 preamble = RADIO_PREAMBLE_SHORT;
+ if (dev == priv->mesh_dev)
+ return -EOPNOTSUPP;
+
lbs_deb_enter(LBS_DEB_CFG80211);
if (!sme->bssid) {
- /* Run a scan if one isn't in-progress already and if the last
- * scan was done more than 2 seconds ago.
- */
- if (priv->scan_req == NULL &&
- time_after(jiffies, priv->last_scan + (2 * HZ))) {
- struct cfg80211_scan_request *creq;
+ struct cfg80211_scan_request *creq;
- creq = _new_connect_scan_req(wiphy, sme);
- if (!creq) {
- ret = -EINVAL;
- goto done;
- }
+ /*
+ * Scan for the requested network after waiting for existing
+ * scans to finish.
+ */
+ lbs_deb_assoc("assoc: waiting for existing scans\n");
+ wait_event_interruptible_timeout(priv->scan_q,
+ (priv->scan_req == NULL),
+ (15 * HZ));
- lbs_deb_assoc("assoc: scanning for compatible AP\n");
- _internal_start_scan(priv, true, creq);
+ creq = _new_connect_scan_req(wiphy, sme);
+ if (!creq) {
+ ret = -EINVAL;
+ goto done;
}
- /* Wait for any in-progress scan to complete */
+ lbs_deb_assoc("assoc: scanning for compatible AP\n");
+ _internal_start_scan(priv, true, creq);
+
lbs_deb_assoc("assoc: waiting for scan to complete\n");
wait_event_interruptible_timeout(priv->scan_q,
(priv->scan_req == NULL),
@@ -1315,8 +1361,8 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
sme->ssid, sme->ssid_len,
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
if (!bss) {
- lbs_pr_err("assoc: bss %pM not in scan results\n",
- sme->bssid);
+ wiphy_err(wiphy, "assoc: bss %pM not in scan results\n",
+ sme->bssid);
ret = -ENOENT;
goto done;
}
@@ -1351,7 +1397,7 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
* we remove all keys like in the WPA/WPA2 setup,
* we just don't set RSN.
*
- * Therefore: fall-throught
+ * Therefore: fall-through
*/
case WLAN_CIPHER_SUITE_TKIP:
case WLAN_CIPHER_SUITE_CCMP:
@@ -1373,13 +1419,18 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
lbs_enable_rsn(priv, sme->crypto.cipher_group != 0);
break;
default:
- lbs_pr_err("unsupported cipher group 0x%x\n",
- sme->crypto.cipher_group);
+ wiphy_err(wiphy, "unsupported cipher group 0x%x\n",
+ sme->crypto.cipher_group);
ret = -ENOTSUPP;
goto done;
}
- lbs_set_authtype(priv, sme);
+ ret = lbs_set_authtype(priv, sme);
+ if (ret == -ENOTSUPP) {
+ wiphy_err(wiphy, "unsupported authtype 0x%x\n", sme->auth_type);
+ goto done;
+ }
+
lbs_set_radio(priv, preamble, 1);
/* Do the actual association */
@@ -1387,33 +1438,28 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
done:
if (bss)
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(wiphy, bss);
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
return ret;
}
-static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
- u16 reason_code)
+int lbs_disconnect(struct lbs_private *priv, u16 reason)
{
- struct lbs_private *priv = wiphy_priv(wiphy);
struct cmd_ds_802_11_deauthenticate cmd;
-
- lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
-
- /* store for lbs_cfg_ret_disconnect() */
- priv->disassoc_reason = reason_code;
+ int ret;
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
/* Mildly ugly to use a locally store my own BSSID ... */
memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN);
- cmd.reasoncode = cpu_to_le16(reason_code);
+ cmd.reasoncode = cpu_to_le16(reason);
- if (lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd))
- return -EFAULT;
+ ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd);
+ if (ret)
+ return ret;
cfg80211_disconnected(priv->dev,
- priv->disassoc_reason,
+ reason,
NULL, 0,
GFP_KERNEL);
priv->connect_status = LBS_DISCONNECTED;
@@ -1421,13 +1467,32 @@ static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
+static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+
+ if (dev == priv->mesh_dev)
+ return -EOPNOTSUPP;
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
+
+ /* store for lbs_cfg_ret_disconnect() */
+ priv->disassoc_reason = reason_code;
+
+ return lbs_disconnect(priv, reason_code);
+}
static int lbs_cfg_set_default_key(struct wiphy *wiphy,
struct net_device *netdev,
- u8 key_index)
+ u8 key_index, bool unicast,
+ bool multicast)
{
struct lbs_private *priv = wiphy_priv(wiphy);
+ if (netdev == priv->mesh_dev)
+ return -EOPNOTSUPP;
+
lbs_deb_enter(LBS_DEB_CFG80211);
if (key_index != priv->wep_tx_key) {
@@ -1449,6 +1514,9 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
u16 key_type;
int ret = 0;
+ if (netdev == priv->mesh_dev)
+ return -EOPNOTSUPP;
+
lbs_deb_enter(LBS_DEB_CFG80211);
lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n",
@@ -1491,7 +1559,7 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
params->key, params->key_len);
break;
default:
- lbs_pr_err("unhandled cipher 0x%x\n", params->cipher);
+ wiphy_err(wiphy, "unhandled cipher 0x%x\n", params->cipher);
ret = -ENOTSUPP;
break;
}
@@ -1536,12 +1604,12 @@ static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev,
}
-/***************************************************************************
+/*
* Get station
*/
static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
- u8 *mac, struct station_info *sinfo)
+ const u8 *mac, struct station_info *sinfo)
{
struct lbs_private *priv = wiphy_priv(wiphy);
s8 signal, noise;
@@ -1581,39 +1649,7 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
-/***************************************************************************
- * "Site survey", here just current channel and noise level
- */
-
-static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev,
- int idx, struct survey_info *survey)
-{
- struct lbs_private *priv = wiphy_priv(wiphy);
- s8 signal, noise;
- int ret;
-
- if (idx != 0)
- ret = -ENOENT;
-
- lbs_deb_enter(LBS_DEB_CFG80211);
-
- survey->channel = ieee80211_get_channel(wiphy,
- ieee80211_channel_to_frequency(priv->channel));
-
- ret = lbs_get_rssi(priv, &signal, &noise);
- if (ret == 0) {
- survey->filled = SURVEY_INFO_NOISE_DBM;
- survey->noise = noise;
- }
-
- lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
- return ret;
-}
-
-
-
-
-/***************************************************************************
+/*
* Change interface
*/
@@ -1624,28 +1660,23 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
struct lbs_private *priv = wiphy_priv(wiphy);
int ret = 0;
- lbs_deb_enter(LBS_DEB_CFG80211);
+ if (dev == priv->mesh_dev)
+ return -EOPNOTSUPP;
switch (type) {
case NL80211_IFTYPE_MONITOR:
- ret = lbs_set_monitor_mode(priv, 1);
- break;
case NL80211_IFTYPE_STATION:
- if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
- ret = lbs_set_monitor_mode(priv, 0);
- if (!ret)
- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1);
- break;
case NL80211_IFTYPE_ADHOC:
- if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
- ret = lbs_set_monitor_mode(priv, 0);
- if (!ret)
- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2);
break;
default:
- ret = -ENOTSUPP;
+ return -EOPNOTSUPP;
}
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ if (priv->iface_running)
+ ret = lbs_set_iface_type(priv, type);
+
if (!ret)
priv->wdev->iftype = type;
@@ -1655,11 +1686,12 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
-/***************************************************************************
+/*
* IBSS (Ad-Hoc)
*/
-/* The firmware needs the following bits masked out of the beacon-derived
+/*
+ * The firmware needs the following bits masked out of the beacon-derived
* capability field when associating/joining to a BSS:
* 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
*/
@@ -1676,6 +1708,7 @@ static void lbs_join_post(struct lbs_private *priv,
2 + 2 + /* atim */
2 + 8]; /* extended rates */
u8 *fake = fake_ie;
+ struct cfg80211_bss *bss;
lbs_deb_enter(LBS_DEB_CFG80211);
@@ -1699,7 +1732,7 @@ static void lbs_join_post(struct lbs_private *priv,
/* Fake DS channel IE */
*fake++ = WLAN_EID_DS_PARAMS;
*fake++ = 1;
- *fake++ = params->channel->hw_value;
+ *fake++ = params->chandef.chan->hw_value;
/* Fake IBSS params IE */
*fake++ = WLAN_EID_IBSS_PARAMS;
*fake++ = 2;
@@ -1719,19 +1752,21 @@ static void lbs_join_post(struct lbs_private *priv,
*fake++ = 0x6c;
lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie);
- cfg80211_inform_bss(priv->wdev->wiphy,
- params->channel,
- bssid,
- 0,
- capability,
- params->beacon_interval,
- fake_ie, fake - fake_ie,
- 0, GFP_KERNEL);
+ bss = cfg80211_inform_bss(priv->wdev->wiphy,
+ params->chandef.chan,
+ bssid,
+ 0,
+ capability,
+ params->beacon_interval,
+ fake_ie, fake - fake_ie,
+ 0, GFP_KERNEL);
+ cfg80211_put_bss(priv->wdev->wiphy, bss);
memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
priv->wdev->ssid_len = params->ssid_len;
- cfg80211_ibss_joined(priv->dev, bssid, GFP_KERNEL);
+ cfg80211_ibss_joined(priv->dev, bssid, params->chandef.chan,
+ GFP_KERNEL);
/* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */
priv->connect_status = LBS_CONNECTED;
@@ -1746,7 +1781,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv,
struct cfg80211_ibss_params *params,
struct cfg80211_bss *bss)
{
- const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
+ const u8 *rates_eid;
struct cmd_ds_802_11_ad_hoc_join cmd;
u8 preamble = RADIO_PREAMBLE_SHORT;
int ret = 0;
@@ -1797,7 +1832,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv,
cmd.bss.beaconperiod = cpu_to_le16(params->beacon_interval);
cmd.bss.ds.header.id = WLAN_EID_DS_PARAMS;
cmd.bss.ds.header.len = 1;
- cmd.bss.ds.channel = params->channel->hw_value;
+ cmd.bss.ds.channel = params->chandef.chan->hw_value;
cmd.bss.ibss.header.id = WLAN_EID_IBSS_PARAMS;
cmd.bss.ibss.header.len = 2;
cmd.bss.ibss.atimwindow = 0;
@@ -1805,6 +1840,8 @@ static int lbs_ibss_join_existing(struct lbs_private *priv,
/* set rates to the intersection of our rates and the rates in the
bss */
+ rcu_read_lock();
+ rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
if (!rates_eid) {
lbs_add_rates(cmd.bss.rates);
} else {
@@ -1824,6 +1861,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv,
}
}
}
+ rcu_read_unlock();
/* Only v8 and below support setting this */
if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) {
@@ -1906,7 +1944,7 @@ static int lbs_ibss_start_new(struct lbs_private *priv,
cmd.ibss.atimwindow = 0;
cmd.ds.header.id = WLAN_EID_DS_PARAMS;
cmd.ds.header.len = 1;
- cmd.ds.channel = params->channel->hw_value;
+ cmd.ds.channel = params->chandef.chan->hw_value;
/* Only v8 and below support setting probe delay */
if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8)
cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
@@ -1946,26 +1984,29 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_bss *bss;
DECLARE_SSID_BUF(ssid_buf);
+ if (dev == priv->mesh_dev)
+ return -EOPNOTSUPP;
+
lbs_deb_enter(LBS_DEB_CFG80211);
- if (!params->channel) {
+ if (!params->chandef.chan) {
ret = -ENOTSUPP;
goto out;
}
- ret = lbs_set_channel(priv, params->channel->hw_value);
+ ret = lbs_set_channel(priv, params->chandef.chan->hw_value);
if (ret)
goto out;
/* Search if someone is beaconing. This assumes that the
* bss list is populated already */
- bss = cfg80211_get_bss(wiphy, params->channel, params->bssid,
+ bss = cfg80211_get_bss(wiphy, params->chandef.chan, params->bssid,
params->ssid, params->ssid_len,
WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
if (bss) {
ret = lbs_ibss_join_existing(priv, params, bss);
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(wiphy, bss);
} else
ret = lbs_ibss_start_new(priv, params);
@@ -1982,6 +2023,9 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
struct cmd_ds_802_11_ad_hoc_stop cmd;
int ret = 0;
+ if (dev == priv->mesh_dev)
+ return -EOPNOTSUPP;
+
lbs_deb_enter(LBS_DEB_CFG80211);
memset(&cmd, 0, sizeof(cmd));
@@ -1998,12 +2042,13 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
-/***************************************************************************
+/*
* Initialization
*/
static struct cfg80211_ops lbs_cfg80211_ops = {
- .set_channel = lbs_cfg_set_channel,
+ .set_monitor_channel = lbs_cfg_set_monitor_channel,
+ .libertas_set_mesh_channel = lbs_cfg_set_mesh_channel,
.scan = lbs_cfg_scan,
.connect = lbs_cfg_connect,
.disconnect = lbs_cfg_disconnect,
@@ -2011,7 +2056,6 @@ static struct cfg80211_ops lbs_cfg80211_ops = {
.del_key = lbs_cfg_del_key,
.set_default_key = lbs_cfg_set_default_key,
.get_station = lbs_cfg_get_station,
- .dump_survey = lbs_get_survey,
.change_virtual_intf = lbs_change_intf,
.join_ibss = lbs_join_ibss,
.leave_ibss = lbs_leave_ibss,
@@ -2032,10 +2076,8 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev)
lbs_deb_enter(LBS_DEB_CFG80211);
wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
- if (!wdev) {
- dev_err(dev, "cannot allocate wireless device\n");
+ if (!wdev)
return ERR_PTR(-ENOMEM);
- }
wdev->wiphy = wiphy_new(&lbs_cfg80211_ops, sizeof(struct lbs_private));
if (!wdev->wiphy) {
@@ -2062,7 +2104,7 @@ static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv)
};
/* Section 5.17.2 */
- static struct region_code_mapping regmap[] = {
+ static const struct region_code_mapping regmap[] = {
{"US ", 0x10}, /* US FCC */
{"CA ", 0x20}, /* Canada */
{"EU ", 0x30}, /* ETSI */
@@ -2083,6 +2125,21 @@ static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv)
lbs_deb_leave(LBS_DEB_CFG80211);
}
+static void lbs_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
+ "callback for domain %c%c\n", request->alpha2[0],
+ request->alpha2[1]);
+
+ memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
+ if (lbs_iface_active(priv))
+ lbs_set_11d_domain_info(priv);
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+}
/*
* This function get's called after lbs_setup_firmware() determined the
@@ -2104,6 +2161,8 @@ int lbs_cfg_register(struct lbs_private *priv)
BIT(NL80211_IFTYPE_ADHOC);
if (lbs_rtap_supported(priv))
wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+ if (lbs_mesh_activated(priv))
+ wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MESH_POINT);
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
@@ -2117,13 +2176,13 @@ int lbs_cfg_register(struct lbs_private *priv)
ret = wiphy_register(wdev->wiphy);
if (ret < 0)
- lbs_pr_err("cannot register wiphy device\n");
+ pr_err("cannot register wiphy device\n");
priv->wiphy_registered = true;
ret = register_netdev(priv->dev);
if (ret)
- lbs_pr_err("cannot register network device\n");
+ pr_err("cannot register network device\n");
INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
@@ -2133,22 +2192,6 @@ int lbs_cfg_register(struct lbs_private *priv)
return ret;
}
-int lbs_reg_notifier(struct wiphy *wiphy,
- struct regulatory_request *request)
-{
- struct lbs_private *priv = wiphy_priv(wiphy);
- int ret;
-
- lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
- "callback for domain %c%c\n", request->alpha2[0],
- request->alpha2[1]);
-
- ret = lbs_set_11d_domain_info(priv, request, wiphy->bands);
-
- lbs_deb_leave(LBS_DEB_CFG80211);
- return ret;
-}
-
void lbs_scan_deinit(struct lbs_private *priv)
{
lbs_deb_enter(LBS_DEB_CFG80211);
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
index 4f46bb744be..10995f59fe3 100644
--- a/drivers/net/wireless/libertas/cfg.h
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -10,12 +10,11 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev);
int lbs_cfg_register(struct lbs_private *priv);
void lbs_cfg_free(struct lbs_private *priv);
-int lbs_reg_notifier(struct wiphy *wiphy,
- struct regulatory_request *request);
-
void lbs_send_disconnect_notification(struct lbs_private *priv);
void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
+void lbs_scan_done(struct lbs_private *priv);
void lbs_scan_deinit(struct lbs_private *priv);
+int lbs_disconnect(struct lbs_private *priv, u16 reason);
#endif
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 70745928f3f..aaa297315c4 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -1,12 +1,14 @@
-/**
- * This file contains the handling of command.
- * It prepares command and sends it to firmware when it is ready.
- */
+/*
+ * This file contains the handling of command.
+ * It prepares command and sends it to firmware when it is ready.
+ */
+#include <linux/hardirq.h>
#include <linux/kfifo.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/if_arp.h>
+#include <linux/export.h>
#include "decl.h"
#include "cfg.h"
@@ -16,14 +18,14 @@
#define CAL_RSSI(snr, nf) ((s32)((s32)(snr) + CAL_NF(nf)))
/**
- * @brief Simple callback that copies response back into command
+ * lbs_cmd_copyback - Simple callback that copies response back into command
*
- * @param priv A pointer to struct lbs_private structure
- * @param extra A pointer to the original command structure for which
- * 'resp' is a response
- * @param resp A pointer to the command response
+ * @priv: A pointer to &struct lbs_private structure
+ * @extra: A pointer to the original command structure for which
+ * 'resp' is a response
+ * @resp: A pointer to the command response
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
struct cmd_header *resp)
@@ -38,15 +40,15 @@ int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
EXPORT_SYMBOL_GPL(lbs_cmd_copyback);
/**
- * @brief Simple callback that ignores the result. Use this if
- * you just want to send a command to the hardware, but don't
+ * lbs_cmd_async_callback - Simple callback that ignores the result.
+ * Use this if you just want to send a command to the hardware, but don't
* care for the result.
*
- * @param priv ignored
- * @param extra ignored
- * @param resp ignored
+ * @priv: ignored
+ * @extra: ignored
+ * @resp: ignored
*
- * @return 0 for success
+ * returns: 0 for success
*/
static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,
struct cmd_header *resp)
@@ -56,10 +58,11 @@ static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,
/**
- * @brief Checks whether a command is allowed in Power Save mode
+ * is_command_allowed_in_ps - tests if a command is allowed in Power Save mode
*
- * @param command the command ID
- * @return 1 if allowed, 0 if not allowed
+ * @cmd: the command ID
+ *
+ * returns: 1 if allowed, 0 if not allowed
*/
static u8 is_command_allowed_in_ps(u16 cmd)
{
@@ -75,11 +78,12 @@ static u8 is_command_allowed_in_ps(u16 cmd)
}
/**
- * @brief Updates the hardware details like MAC address and regulatory region
+ * lbs_update_hw_spec - Updates the hardware details like MAC address
+ * and regulatory region
*
- * @param priv A pointer to struct lbs_private structure
+ * @priv: A pointer to &struct lbs_private structure
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_update_hw_spec(struct lbs_private *priv)
{
@@ -108,7 +112,7 @@ int lbs_update_hw_spec(struct lbs_private *priv)
* CF card firmware 5.0.16p0: cap 0x00000303
* USB dongle firmware 5.110.17p2: cap 0x00000303
*/
- lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n",
+ netdev_info(priv->dev, "%pM, fw %u.%u.%up%u, cap 0x%08x\n",
cmd.permanentaddr,
priv->fwrelease >> 24 & 0xff,
priv->fwrelease >> 16 & 0xff,
@@ -139,15 +143,20 @@ int lbs_update_hw_spec(struct lbs_private *priv)
/* if it's unidentified region code, use the default (USA) */
if (i >= MRVDRV_MAX_REGION_CODE) {
priv->regioncode = 0x10;
- lbs_pr_info("unidentified region code; using the default (USA)\n");
+ netdev_info(priv->dev,
+ "unidentified region code; using the default (USA)\n");
}
if (priv->current_addr[0] == 0xff)
memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
- memcpy(priv->dev->dev_addr, priv->current_addr, ETH_ALEN);
- if (priv->mesh_dev)
- memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);
+ if (!priv->copied_hwaddr) {
+ memcpy(priv->dev->dev_addr, priv->current_addr, ETH_ALEN);
+ if (priv->mesh_dev)
+ memcpy(priv->mesh_dev->dev_addr,
+ priv->current_addr, ETH_ALEN);
+ priv->copied_hwaddr = 1;
+ }
out:
lbs_deb_leave(LBS_DEB_CMD);
@@ -177,6 +186,14 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
struct cmd_ds_host_sleep cmd_config;
int ret;
+ /*
+ * Certain firmware versions do not support EHS_REMOVE_WAKEUP command
+ * and the card will return a failure. Since we need to be
+ * able to reset the mask, in those cases we set a 0 mask instead.
+ */
+ if (criteria == EHS_REMOVE_WAKEUP && !priv->ehs_remove_supported)
+ criteria = 0;
+
cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config));
cmd_config.criteria = cpu_to_le32(criteria);
cmd_config.gpio = priv->wol_gpio;
@@ -197,7 +214,7 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
(uint8_t *)&cmd_config.wol_conf,
sizeof(struct wol_config));
} else {
- lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
+ netdev_info(priv->dev, "HOST_SLEEP_CFG failed %d\n", ret);
}
return ret;
@@ -205,14 +222,14 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
/**
- * @brief Sets the Power Save mode
+ * lbs_set_ps_mode - Sets the Power Save mode
*
- * @param priv A pointer to struct lbs_private structure
- * @param cmd_action The Power Save operation (PS_MODE_ACTION_ENTER_PS or
+ * @priv: A pointer to &struct lbs_private structure
+ * @cmd_action: The Power Save operation (PS_MODE_ACTION_ENTER_PS or
* PS_MODE_ACTION_EXIT_PS)
- * @param block Whether to block on a response or not
+ * @block: Whether to block on a response or not
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block)
{
@@ -300,7 +317,7 @@ static int lbs_wait_for_ds_awake(struct lbs_private *priv)
if (priv->is_deep_sleep) {
if (!wait_event_interruptible_timeout(priv->ds_awake_q,
!priv->is_deep_sleep, (10 * HZ))) {
- lbs_pr_err("ds_awake_q: timer expired\n");
+ netdev_err(priv->dev, "ds_awake_q: timer expired\n");
ret = -1;
}
}
@@ -325,7 +342,7 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
netif_carrier_off(priv->dev);
}
} else {
- lbs_pr_err("deep sleep: already enabled\n");
+ netdev_err(priv->dev, "deep sleep: already enabled\n");
}
} else {
if (priv->is_deep_sleep) {
@@ -335,8 +352,8 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
if (!ret) {
ret = lbs_wait_for_ds_awake(priv);
if (ret)
- lbs_pr_err("deep sleep: wakeup"
- "failed\n");
+ netdev_err(priv->dev,
+ "deep sleep: wakeup failed\n");
}
}
}
@@ -370,8 +387,9 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
(struct wol_config *)NULL);
if (ret) {
- lbs_pr_info("Host sleep configuration failed: "
- "%d\n", ret);
+ netdev_info(priv->dev,
+ "Host sleep configuration failed: %d\n",
+ ret);
return ret;
}
if (priv->psstate == PS_STATE_FULL_POWER) {
@@ -381,19 +399,21 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
sizeof(cmd),
lbs_ret_host_sleep_activate, 0);
if (ret)
- lbs_pr_info("HOST_SLEEP_ACTIVATE "
- "failed: %d\n", ret);
+ netdev_info(priv->dev,
+ "HOST_SLEEP_ACTIVATE failed: %d\n",
+ ret);
}
if (!wait_event_interruptible_timeout(
priv->host_sleep_q,
priv->is_host_sleep_activated,
(10 * HZ))) {
- lbs_pr_err("host_sleep_q: timer expired\n");
+ netdev_err(priv->dev,
+ "host_sleep_q: timer expired\n");
ret = -1;
}
} else {
- lbs_pr_err("host sleep: already enabled\n");
+ netdev_err(priv->dev, "host sleep: already enabled\n");
}
} else {
if (priv->is_host_sleep_activated)
@@ -405,13 +425,13 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
}
/**
- * @brief Set an SNMP MIB value
+ * lbs_set_snmp_mib - Set an SNMP MIB value
*
- * @param priv A pointer to struct lbs_private structure
- * @param oid The OID to set in the firmware
- * @param val Value to set the OID to
+ * @priv: A pointer to &struct lbs_private structure
+ * @oid: The OID to set in the firmware
+ * @val: Value to set the OID to
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
{
@@ -455,13 +475,13 @@ out:
}
/**
- * @brief Get an SNMP MIB value
+ * lbs_get_snmp_mib - Get an SNMP MIB value
*
- * @param priv A pointer to struct lbs_private structure
- * @param oid The OID to retrieve from the firmware
- * @param out_val Location for the returned value
+ * @priv: A pointer to &struct lbs_private structure
+ * @oid: The OID to retrieve from the firmware
+ * @out_val: Location for the returned value
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
{
@@ -498,14 +518,14 @@ out:
}
/**
- * @brief Get the min, max, and current TX power
+ * lbs_get_tx_power - Get the min, max, and current TX power
*
- * @param priv A pointer to struct lbs_private structure
- * @param curlevel Current power level in dBm
- * @param minlevel Minimum supported power level in dBm (optional)
- * @param maxlevel Maximum supported power level in dBm (optional)
+ * @priv: A pointer to &struct lbs_private structure
+ * @curlevel: Current power level in dBm
+ * @minlevel: Minimum supported power level in dBm (optional)
+ * @maxlevel: Maximum supported power level in dBm (optional)
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
s16 *maxlevel)
@@ -533,12 +553,12 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
}
/**
- * @brief Set the TX power
+ * lbs_set_tx_power - Set the TX power
*
- * @param priv A pointer to struct lbs_private structure
- * @param dbm The desired power level in dBm
+ * @priv: A pointer to &struct lbs_private structure
+ * @dbm: The desired power level in dBm
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
{
@@ -561,12 +581,13 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
}
/**
- * @brief Enable or disable monitor mode (only implemented on OLPC usb8388 FW)
+ * lbs_set_monitor_mode - Enable or disable monitor mode
+ * (only implemented on OLPC usb8388 FW)
*
- * @param priv A pointer to struct lbs_private structure
- * @param enable 1 to enable monitor mode, 0 to disable
+ * @priv: A pointer to &struct lbs_private structure
+ * @enable: 1 to enable monitor mode, 0 to disable
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_set_monitor_mode(struct lbs_private *priv, int enable)
{
@@ -592,11 +613,11 @@ int lbs_set_monitor_mode(struct lbs_private *priv, int enable)
}
/**
- * @brief Get the radio channel
+ * lbs_get_channel - Get the radio channel
*
- * @param priv A pointer to struct lbs_private structure
+ * @priv: A pointer to &struct lbs_private structure
*
- * @return The channel on success, error on failure
+ * returns: The channel on success, error on failure
*/
static int lbs_get_channel(struct lbs_private *priv)
{
@@ -638,12 +659,12 @@ int lbs_update_channel(struct lbs_private *priv)
}
/**
- * @brief Set the radio channel
+ * lbs_set_channel - Set the radio channel
*
- * @param priv A pointer to struct lbs_private structure
- * @param channel The desired channel, or 0 to clear a locked channel
+ * @priv: A pointer to &struct lbs_private structure
+ * @channel: The desired channel, or 0 to clear a locked channel
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_set_channel(struct lbs_private *priv, u8 channel)
{
@@ -674,12 +695,13 @@ out:
}
/**
- * @brief Get current RSSI and noise floor
+ * lbs_get_rssi - Get current RSSI and noise floor
*
- * @param priv A pointer to struct lbs_private structure
- * @param rssi On successful return, signal level in mBm
+ * @priv: A pointer to &struct lbs_private structure
+ * @rssi: On successful return, signal level in mBm
+ * @nf: On successful return, Noise floor
*
- * @return The channel on success, error on failure
+ * returns: The channel on success, error on failure
*/
int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
{
@@ -707,18 +729,17 @@ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
}
/**
- * @brief Send regulatory and 802.11d domain information to the firmware
+ * lbs_set_11d_domain_info - Send regulatory and 802.11d domain information
+ * to the firmware
*
- * @param priv pointer to struct lbs_private
- * @param request cfg80211 regulatory request structure
- * @param bands the device's supported bands and channels
+ * @priv: pointer to &struct lbs_private
*
- * @return 0 on success, error code on failure
+ * returns: 0 on success, error code on failure
*/
-int lbs_set_11d_domain_info(struct lbs_private *priv,
- struct regulatory_request *request,
- struct ieee80211_supported_band **bands)
+int lbs_set_11d_domain_info(struct lbs_private *priv)
{
+ struct wiphy *wiphy = priv->wdev->wiphy;
+ struct ieee80211_supported_band **bands = wiphy->bands;
struct cmd_ds_802_11d_domain_info cmd;
struct mrvl_ie_domain_param_set *domain = &cmd.domain;
struct ieee80211_country_ie_triplet *t;
@@ -729,21 +750,23 @@ int lbs_set_11d_domain_info(struct lbs_private *priv,
u8 first_channel = 0, next_chan = 0, max_pwr = 0;
u8 i, flag = 0;
size_t triplet_size;
- int ret;
+ int ret = 0;
lbs_deb_enter(LBS_DEB_11D);
+ if (!priv->country_code[0])
+ goto out;
memset(&cmd, 0, sizeof(cmd));
cmd.action = cpu_to_le16(CMD_ACT_SET);
lbs_deb_11d("Setting country code '%c%c'\n",
- request->alpha2[0], request->alpha2[1]);
+ priv->country_code[0], priv->country_code[1]);
domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
/* Set country code */
- domain->country_code[0] = request->alpha2[0];
- domain->country_code[1] = request->alpha2[1];
+ domain->country_code[0] = priv->country_code[0];
+ domain->country_code[1] = priv->country_code[1];
domain->country_code[2] = ' ';
/* Now set up the channel triplets; firmware is somewhat picky here
@@ -825,20 +848,21 @@ int lbs_set_11d_domain_info(struct lbs_private *priv,
ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd);
+out:
lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
return ret;
}
/**
- * @brief Read a MAC, Baseband, or RF register
+ * lbs_get_reg - Read a MAC, Baseband, or RF register
*
- * @param priv pointer to struct lbs_private
- * @param cmd register command, one of CMD_MAC_REG_ACCESS,
- * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
- * @param offset byte offset of the register to get
- * @param value on success, the value of the register at 'offset'
+ * @priv: pointer to &struct lbs_private
+ * @reg: register command, one of CMD_MAC_REG_ACCESS,
+ * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
+ * @offset: byte offset of the register to get
+ * @value: on success, the value of the register at 'offset'
*
- * @return 0 on success, error code on failure
+ * returns: 0 on success, error code on failure
*/
int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
{
@@ -852,6 +876,7 @@ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(CMD_ACT_GET);
+ cmd.offset = cpu_to_le16(offset);
if (reg != CMD_MAC_REG_ACCESS &&
reg != CMD_BBP_REG_ACCESS &&
@@ -861,7 +886,7 @@ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
}
ret = lbs_cmd_with_response(priv, reg, &cmd);
- if (ret) {
+ if (!ret) {
if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
*value = cmd.value.bbp_rf;
else if (reg == CMD_MAC_REG_ACCESS)
@@ -874,15 +899,15 @@ out:
}
/**
- * @brief Write a MAC, Baseband, or RF register
+ * lbs_set_reg - Write a MAC, Baseband, or RF register
*
- * @param priv pointer to struct lbs_private
- * @param cmd register command, one of CMD_MAC_REG_ACCESS,
- * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
- * @param offset byte offset of the register to set
- * @param value the value to write to the register at 'offset'
+ * @priv: pointer to &struct lbs_private
+ * @reg: register command, one of CMD_MAC_REG_ACCESS,
+ * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
+ * @offset: byte offset of the register to set
+ * @value: the value to write to the register at 'offset'
*
- * @return 0 on success, error code on failure
+ * returns: 0 on success, error code on failure
*/
int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)
{
@@ -894,6 +919,7 @@ int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(CMD_ACT_SET);
+ cmd.offset = cpu_to_le16(offset);
if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
cmd.value.bbp_rf = (u8) (value & 0xFF);
@@ -973,6 +999,8 @@ static void lbs_submit_command(struct lbs_private *priv,
cmd = cmdnode->cmdbuf;
spin_lock_irqsave(&priv->driver_lock, flags);
+ priv->seqnum++;
+ cmd->seqnum = cpu_to_le16(priv->seqnum);
priv->cur_cmd = cmdnode;
spin_unlock_irqrestore(&priv->driver_lock, flags);
@@ -990,10 +1018,11 @@ static void lbs_submit_command(struct lbs_private *priv,
ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
if (ret) {
- lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
- /* Let the timer kick in and retry, and potentially reset
- the whole thing if the condition persists */
- timeo = HZ/4;
+ netdev_info(priv->dev, "DNLD_CMD: hw_host_to_card failed: %d\n",
+ ret);
+ /* Reset dnld state machine, report failure */
+ priv->dnld_sent = DNLD_RES_RECEIVED;
+ lbs_complete_command(priv, cmdnode, ret);
}
if (command == CMD_802_11_DEEP_SLEEP) {
@@ -1011,7 +1040,7 @@ static void lbs_submit_command(struct lbs_private *priv,
lbs_deb_leave(LBS_DEB_HOST);
}
-/**
+/*
* This function inserts command node to cmdfreeq
* after cleans it. Requires priv->driver_lock held.
*/
@@ -1043,16 +1072,34 @@ static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
spin_unlock_irqrestore(&priv->driver_lock, flags);
}
-void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
- int result)
+void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+ int result)
{
+ /*
+ * Normally, commands are removed from cmdpendingq before being
+ * submitted. However, we can arrive here on alternative codepaths
+ * where the command is still pending. Make sure the command really
+ * isn't part of a list at this point.
+ */
+ list_del_init(&cmd->list);
+
cmd->result = result;
cmd->cmdwaitqwoken = 1;
- wake_up_interruptible(&cmd->cmdwait_q);
+ wake_up(&cmd->cmdwait_q);
if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
__lbs_cleanup_and_insert_cmd(priv, cmd);
priv->cur_cmd = NULL;
+ wake_up(&priv->waitq);
+}
+
+void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+ int result)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&priv->driver_lock, flags);
+ __lbs_complete_command(priv, cmd, result);
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
}
int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
@@ -1112,12 +1159,29 @@ void lbs_set_mac_control(struct lbs_private *priv)
lbs_deb_leave(LBS_DEB_CMD);
}
+int lbs_set_mac_control_sync(struct lbs_private *priv)
+{
+ struct cmd_ds_mac_control cmd;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(priv->mac_control);
+ cmd.reserved = 0;
+ ret = lbs_cmd_with_response(priv, CMD_MAC_CONTROL, &cmd);
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return ret;
+}
+
/**
- * @brief This function allocates the command buffer and link
- * it to command free queue.
+ * lbs_allocate_cmd_buffer - allocates the command buffer and links
+ * it to command free queue
*
- * @param priv A pointer to struct lbs_private structure
- * @return 0 or -1
+ * @priv: A pointer to &struct lbs_private structure
+ *
+ * returns: 0 for success or -1 on error
*/
int lbs_allocate_cmd_buffer(struct lbs_private *priv)
{
@@ -1159,10 +1223,11 @@ done:
}
/**
- * @brief This function frees the command buffer.
+ * lbs_free_cmd_buffer - free the command buffer
+ *
+ * @priv: A pointer to &struct lbs_private structure
*
- * @param priv A pointer to struct lbs_private structure
- * @return 0 or -1
+ * returns: 0 for success
*/
int lbs_free_cmd_buffer(struct lbs_private *priv)
{
@@ -1199,11 +1264,13 @@ done:
}
/**
- * @brief This function gets a free command node if available in
- * command free queue.
+ * lbs_get_free_cmd_node - gets a free command node if available in
+ * command free queue
+ *
+ * @priv: A pointer to &struct lbs_private structure
*
- * @param priv A pointer to struct lbs_private structure
- * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
+ * returns: A pointer to &cmd_ctrl_node structure on success
+ * or %NULL on error
*/
static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
{
@@ -1220,7 +1287,7 @@ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
if (!list_empty(&priv->cmdfreeq)) {
tempnode = list_first_entry(&priv->cmdfreeq,
struct cmd_ctrl_node, list);
- list_del(&tempnode->list);
+ list_del_init(&tempnode->list);
} else {
lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
tempnode = NULL;
@@ -1233,12 +1300,12 @@ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
}
/**
- * @brief This function executes next command in command
- * pending queue. It will put firmware back to PS mode
- * if applicable.
+ * lbs_execute_next_command - execute next command in command
+ * pending queue. Will put firmware back to PS mode if applicable.
*
- * @param priv A pointer to struct lbs_private structure
- * @return 0 or -1
+ * @priv: A pointer to &struct lbs_private structure
+ *
+ * returns: 0 on success or -1 on error
*/
int lbs_execute_next_command(struct lbs_private *priv)
{
@@ -1255,7 +1322,8 @@ int lbs_execute_next_command(struct lbs_private *priv)
spin_lock_irqsave(&priv->driver_lock, flags);
if (priv->cur_cmd) {
- lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
+ netdev_alert(priv->dev,
+ "EXEC_NEXT_CMD: already processing command!\n");
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
goto done;
@@ -1327,10 +1395,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
lbs_deb_host(
"EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
- list_del(&cmdnode->list);
- spin_lock_irqsave(&priv->driver_lock, flags);
lbs_complete_command(priv, cmdnode, 0);
- spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = 0;
goto done;
@@ -1340,10 +1405,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
(priv->psstate == PS_STATE_PRE_SLEEP)) {
lbs_deb_host(
"EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
- list_del(&cmdnode->list);
- spin_lock_irqsave(&priv->driver_lock, flags);
lbs_complete_command(priv, cmdnode, 0);
- spin_unlock_irqrestore(&priv->driver_lock, flags);
priv->needtowakeup = 1;
ret = 0;
@@ -1354,7 +1416,9 @@ int lbs_execute_next_command(struct lbs_private *priv)
"EXEC_NEXT_CMD: sending EXIT_PS\n");
}
}
- list_del(&cmdnode->list);
+ spin_lock_irqsave(&priv->driver_lock, flags);
+ list_del_init(&cmdnode->list);
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
le16_to_cpu(cmd->command));
lbs_submit_command(priv, cmdnode);
@@ -1417,7 +1481,7 @@ static void lbs_send_confirmsleep(struct lbs_private *priv)
ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
sizeof(confirm_sleep));
if (ret) {
- lbs_pr_alert("confirm_sleep failed\n");
+ netdev_alert(priv->dev, "confirm_sleep failed\n");
goto out;
}
@@ -1442,12 +1506,12 @@ out:
}
/**
- * @brief This function checks condition and prepares to
- * send sleep confirm command to firmware if ok.
+ * lbs_ps_confirm_sleep - checks condition and prepares to
+ * send sleep confirm command to firmware if ok
+ *
+ * @priv: A pointer to &struct lbs_private structure
*
- * @param priv A pointer to struct lbs_private structure
- * @param psmode Power Saving mode
- * @return n/a
+ * returns: n/a
*/
void lbs_ps_confirm_sleep(struct lbs_private *priv)
{
@@ -1487,16 +1551,16 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv)
/**
- * @brief Configures the transmission power control functionality.
+ * lbs_set_tpc_cfg - Configures the transmission power control functionality
*
- * @param priv A pointer to struct lbs_private structure
- * @param enable Transmission power control enable
- * @param p0 Power level when link quality is good (dBm).
- * @param p1 Power level when link quality is fair (dBm).
- * @param p2 Power level when link quality is poor (dBm).
- * @param usesnr Use Signal to Noise Ratio in TPC
+ * @priv: A pointer to &struct lbs_private structure
+ * @enable: Transmission power control enable
+ * @p0: Power level when link quality is good (dBm).
+ * @p1: Power level when link quality is fair (dBm).
+ * @p2: Power level when link quality is poor (dBm).
+ * @usesnr: Use Signal to Noise Ratio in TPC
*
- * @return 0 on success
+ * returns: 0 on success
*/
int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
int8_t p2, int usesnr)
@@ -1519,15 +1583,15 @@ int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
}
/**
- * @brief Configures the power adaptation settings.
+ * lbs_set_power_adapt_cfg - Configures the power adaptation settings
*
- * @param priv A pointer to struct lbs_private structure
- * @param enable Power adaptation enable
- * @param p0 Power level for 1, 2, 5.5 and 11 Mbps (dBm).
- * @param p1 Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm).
- * @param p2 Power level for 48 and 54 Mbps (dBm).
+ * @priv: A pointer to &struct lbs_private structure
+ * @enable: Power adaptation enable
+ * @p0: Power level for 1, 2, 5.5 and 11 Mbps (dBm).
+ * @p1: Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm).
+ * @p2: Power level for 48 and 54 Mbps (dBm).
*
- * @return 0 on Success
+ * returns: 0 on Success
*/
int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
@@ -1581,7 +1645,7 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
/* Wake up main thread to execute next command */
- wake_up_interruptible(&priv->waitq);
+ wake_up(&priv->waitq);
cmdnode = ERR_PTR(-ENOBUFS);
goto done;
}
@@ -1592,18 +1656,16 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
/* Copy the incoming command to the buffer */
memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
- /* Set sequence number, clean result, move to buffer */
- priv->seqnum++;
+ /* Set command, clean result, move to buffer */
cmdnode->cmdbuf->command = cpu_to_le16(command);
cmdnode->cmdbuf->size = cpu_to_le16(in_cmd_size);
- cmdnode->cmdbuf->seqnum = cpu_to_le16(priv->seqnum);
cmdnode->cmdbuf->result = 0;
lbs_deb_host("PREP_CMD: command 0x%04x\n", command);
cmdnode->cmdwaitqwoken = 0;
lbs_queue_cmd(priv, cmdnode);
- wake_up_interruptible(&priv->waitq);
+ wake_up(&priv->waitq);
done:
lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
@@ -1638,12 +1700,18 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command,
}
might_sleep();
- wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
+
+ /*
+ * Be careful with signals here. A signal may be received as the system
+ * goes into suspend or resume. We do not want this to interrupt the
+ * command, so we perform an uninterruptible sleep.
+ */
+ wait_event(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
spin_lock_irqsave(&priv->driver_lock, flags);
ret = cmdnode->result;
if (ret)
- lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n",
+ netdev_info(priv->dev, "PREP_CMD: command 0x%04x failed: %d\n",
command, ret);
__lbs_cleanup_and_insert_cmd(priv, cmdnode);
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index 7109d6b717e..4279e8ab95f 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -59,6 +59,8 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv);
int lbs_free_cmd_buffer(struct lbs_private *priv);
int lbs_execute_next_command(struct lbs_private *priv);
+void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+ int result);
void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
int result);
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
@@ -94,6 +96,7 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv);
int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on);
void lbs_set_mac_control(struct lbs_private *priv);
+int lbs_set_mac_control_sync(struct lbs_private *priv);
int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
s16 *maxlevel);
@@ -126,9 +129,7 @@ int lbs_set_monitor_mode(struct lbs_private *priv, int enable);
int lbs_get_rssi(struct lbs_private *priv, s8 *snr, s8 *nf);
-int lbs_set_11d_domain_info(struct lbs_private *priv,
- struct regulatory_request *request,
- struct ieee80211_supported_band **bands);
+int lbs_set_11d_domain_info(struct lbs_private *priv);
int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value);
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 5e95da9dcc2..65f18f1e869 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -1,7 +1,9 @@
-/**
- * This file contains the handling of command
- * responses as well as events generated by firmware.
- */
+/*
+ * This file contains the handling of command
+ * responses as well as events generated by firmware.
+ */
+
+#include <linux/hardirq.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/sched.h>
@@ -12,12 +14,13 @@
#include "cmd.h"
/**
- * @brief This function handles disconnect event. it
- * reports disconnect to upper layer, clean tx/rx packets,
- * reset link state etc.
+ * lbs_mac_event_disconnected - handles disconnect event. It
+ * reports disconnect to upper layer, clean tx/rx packets,
+ * reset link state etc.
+ *
+ * @priv: A pointer to struct lbs_private structure
*
- * @param priv A pointer to struct lbs_private structure
- * @return n/a
+ * returns: n/a
*/
void lbs_mac_event_disconnected(struct lbs_private *priv)
{
@@ -84,15 +87,18 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
- lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
- le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
+ netdev_info(priv->dev,
+ "Received CMD_RESP with invalid sequence %d (expected %d)\n",
+ le16_to_cpu(resp->seqnum),
+ le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
goto done;
}
if (respcmd != CMD_RET(curcmd) &&
respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
- lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
+ netdev_info(priv->dev, "Invalid CMD_RESP %x to command %x!\n",
+ respcmd, curcmd);
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
goto done;
@@ -101,7 +107,8 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
if (resp->result == cpu_to_le16(0x0004)) {
/* 0x0004 means -EAGAIN. Drop the response, let it time out
and be resubmitted */
- lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n",
+ netdev_info(priv->dev,
+ "Firmware returns DEFER to command %x. Will let it time out...\n",
le16_to_cpu(resp->command));
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
@@ -159,7 +166,7 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
}
- lbs_complete_command(priv, priv->cur_cmd, result);
+ __lbs_complete_command(priv, priv->cur_cmd, result);
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = 0;
@@ -180,7 +187,7 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
break;
}
- lbs_complete_command(priv, priv->cur_cmd, result);
+ __lbs_complete_command(priv, priv->cur_cmd, result);
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
@@ -198,7 +205,7 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
if (priv->cur_cmd) {
/* Clean up and Put current command back to cmdfreeq */
- lbs_complete_command(priv, priv->cur_cmd, result);
+ __lbs_complete_command(priv, priv->cur_cmd, result);
}
spin_unlock_irqrestore(&priv->driver_lock, flags);
@@ -241,7 +248,7 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
/* handle unexpected PS SLEEP event */
if (priv->psstate == PS_STATE_FULL_POWER) {
lbs_deb_cmd(
- "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
+ "EVENT: in FULL POWER mode, ignoring PS_SLEEP\n");
break;
}
priv->psstate = PS_STATE_PRE_SLEEP;
@@ -313,28 +320,28 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
break;
case MACREG_INT_CODE_RSSI_LOW:
- lbs_pr_alert("EVENT: rssi low\n");
+ netdev_alert(priv->dev, "EVENT: rssi low\n");
break;
case MACREG_INT_CODE_SNR_LOW:
- lbs_pr_alert("EVENT: snr low\n");
+ netdev_alert(priv->dev, "EVENT: snr low\n");
break;
case MACREG_INT_CODE_MAX_FAIL:
- lbs_pr_alert("EVENT: max fail\n");
+ netdev_alert(priv->dev, "EVENT: max fail\n");
break;
case MACREG_INT_CODE_RSSI_HIGH:
- lbs_pr_alert("EVENT: rssi high\n");
+ netdev_alert(priv->dev, "EVENT: rssi high\n");
break;
case MACREG_INT_CODE_SNR_HIGH:
- lbs_pr_alert("EVENT: snr high\n");
+ netdev_alert(priv->dev, "EVENT: snr high\n");
break;
case MACREG_INT_CODE_MESH_AUTO_STARTED:
/* Ignore spurious autostart events */
- lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
+ netdev_info(priv->dev, "EVENT: MESH_AUTO_STARTED (ignoring)\n");
break;
default:
- lbs_pr_alert("EVENT: unknown event id %d\n", event);
+ netdev_alert(priv->dev, "EVENT: unknown event id %d\n", event);
break;
}
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index fbf3b0332bb..cc6a0a586f0 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -1,9 +1,11 @@
#include <linux/dcache.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
+#include <linux/hardirq.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/slab.h>
+#include <linux/export.h>
#include "decl.h"
#include "cmd.h"
@@ -19,12 +21,6 @@ static char *szStates[] = {
static void lbs_debug_init(struct lbs_private *priv);
#endif
-static int open_file_generic(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
static ssize_t write_file_dummy(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
@@ -151,13 +147,14 @@ static ssize_t lbs_host_sleep_write(struct file *file,
ret = lbs_set_host_sleep(priv, 0);
else if (host_sleep == 1) {
if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
- lbs_pr_info("wake parameters not configured");
+ netdev_info(priv->dev,
+ "wake parameters not configured\n");
ret = -EINVAL;
goto out_unlock;
}
ret = lbs_set_host_sleep(priv, 1);
} else {
- lbs_pr_err("invalid option\n");
+ netdev_err(priv->dev, "invalid option\n");
ret = -EINVAL;
}
@@ -486,7 +483,7 @@ static ssize_t lbs_rdmac_write(struct file *file,
res = -EFAULT;
goto out_unlock;
}
- priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
+ priv->mac_offset = simple_strtoul(buf, NULL, 16);
res = count;
out_unlock:
free_page(addr);
@@ -568,7 +565,7 @@ static ssize_t lbs_rdbbp_write(struct file *file,
res = -EFAULT;
goto out_unlock;
}
- priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
+ priv->bbp_offset = simple_strtoul(buf, NULL, 16);
res = count;
out_unlock:
free_page(addr);
@@ -693,7 +690,7 @@ out_unlock:
#define FOPS(fread, fwrite) { \
.owner = THIS_MODULE, \
- .open = open_file_generic, \
+ .open = simple_open, \
.read = (fread), \
.write = (fwrite), \
.llseek = generic_file_llseek, \
@@ -701,7 +698,7 @@ out_unlock:
struct lbs_debugfs_files {
const char *name;
- int perm;
+ umode_t perm;
struct file_operations fops;
};
@@ -849,15 +846,14 @@ static struct debug_data items[] = {
static int num_of_items = ARRAY_SIZE(items);
/**
- * @brief proc read function
+ * lbs_debugfs_read - proc read function
+ *
+ * @file: file to read
+ * @userbuf: pointer to buffer
+ * @count: number of bytes to read
+ * @ppos: read data starting position
*
- * @param page pointer to buffer
- * @param s read data starting position
- * @param off offset
- * @param cnt counter
- * @param eof end of file flag
- * @param data data to output
- * @return number of output data
+ * returns: amount of data read or negative error code
*/
static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
@@ -897,13 +893,14 @@ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
}
/**
- * @brief proc write function
+ * lbs_debugfs_write - proc write function
*
- * @param f file pointer
- * @param buf pointer to data buffer
- * @param cnt data number to write
- * @param data data to write
- * @return number of data
+ * @f: file pointer
+ * @buf: pointer to data buffer
+ * @cnt: data number to write
+ * @ppos: file position
+ *
+ * returns: amount of data written
*/
static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
size_t cnt, loff_t *ppos)
@@ -916,7 +913,10 @@ static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
char *p2;
struct debug_data *d = f->private_data;
- pdata = kmalloc(cnt, GFP_KERNEL);
+ if (cnt == 0)
+ return 0;
+
+ pdata = kmalloc(cnt + 1, GFP_KERNEL);
if (pdata == NULL)
return 0;
@@ -925,6 +925,7 @@ static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
kfree(pdata);
return 0;
}
+ pdata[cnt] = '\0';
p0 = pdata;
for (i = 0; i < num_of_items; i++) {
@@ -959,18 +960,18 @@ static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
static const struct file_operations lbs_debug_fops = {
.owner = THIS_MODULE,
- .open = open_file_generic,
+ .open = simple_open,
.write = lbs_debugfs_write,
.read = lbs_debugfs_read,
.llseek = default_llseek,
};
/**
- * @brief create debug proc file
+ * lbs_debug_init - create debug proc file
+ *
+ * @priv: pointer to &struct lbs_private
*
- * @param priv pointer struct lbs_private
- * @param dev pointer net_device
- * @return N/A
+ * returns: N/A
*/
static void lbs_debug_init(struct lbs_private *priv)
{
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 2ae752d1006..84a3aa7ac57 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -1,14 +1,15 @@
-/**
- * This file contains declaration referring to
- * functions defined in other source files
- */
+/*
+ * This file contains declaration referring to
+ * functions defined in other source files
+ */
#ifndef _LBS_DECL_H_
#define _LBS_DECL_H_
#include <linux/netdevice.h>
#include <linux/firmware.h>
+#include <linux/nl80211.h>
/* Should be terminated by a NULL entry */
struct lbs_fw_table {
@@ -18,6 +19,10 @@ struct lbs_fw_table {
};
struct lbs_private;
+typedef void (*lbs_fw_cb)(struct lbs_private *priv, int ret,
+ const struct firmware *helper, const struct firmware *mainfw);
+
+struct lbs_private;
struct sk_buff;
struct net_device;
struct cmd_ds_command;
@@ -43,10 +48,15 @@ int lbs_start_card(struct lbs_private *priv);
void lbs_stop_card(struct lbs_private *priv);
void lbs_host_to_card_done(struct lbs_private *priv);
+int lbs_start_iface(struct lbs_private *priv);
+int lbs_stop_iface(struct lbs_private *priv);
+int lbs_set_iface_type(struct lbs_private *priv, enum nl80211_iftype type);
+
int lbs_rtap_supported(struct lbs_private *priv);
int lbs_set_mac_address(struct net_device *dev, void *addr);
void lbs_set_multicast_list(struct net_device *dev);
+void lbs_update_mcast(struct lbs_private *priv);
int lbs_suspend(struct lbs_private *priv);
int lbs_resume(struct lbs_private *priv);
@@ -60,10 +70,13 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
u32 lbs_fw_index_to_data_rate(u8 index);
u8 lbs_data_rate_to_fw_index(u32 rate);
-int lbs_get_firmware(struct device *dev, const char *user_helper,
- const char *user_mainfw, u32 card_model,
+int lbs_get_firmware(struct device *dev, u32 card_model,
const struct lbs_fw_table *fw_table,
const struct firmware **helper,
const struct firmware **mainfw);
+int lbs_get_firmware_async(struct lbs_private *priv, struct device *device,
+ u32 card_model, const struct lbs_fw_table *fw_table,
+ lbs_fw_cb callback);
+void lbs_wait_for_firmware_load(struct lbs_private *priv);
#endif
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index d00c728cec4..407784aca62 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -1,7 +1,7 @@
-/**
- * This header file contains global constant/enum definitions,
- * global variable declaration.
- */
+/*
+ * This header file contains global constant/enum definitions,
+ * global variable declaration.
+ */
#ifndef _LBS_DEFS_H_
#define _LBS_DEFS_H_
@@ -89,15 +89,9 @@ do { if ((lbs_debug & (grp)) == (grp)) \
#define lbs_deb_spi(fmt, args...) LBS_DEB_LL(LBS_DEB_SPI, " spi", fmt, ##args)
#define lbs_deb_cfg80211(fmt, args...) LBS_DEB_LL(LBS_DEB_CFG80211, " cfg80211", fmt, ##args)
-#define lbs_pr_info(format, args...) \
- printk(KERN_INFO DRV_NAME": " format, ## args)
-#define lbs_pr_err(format, args...) \
- printk(KERN_ERR DRV_NAME": " format, ## args)
-#define lbs_pr_alert(format, args...) \
- printk(KERN_ALERT DRV_NAME": " format, ## args)
-
#ifdef DEBUG
-static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len)
+static inline void lbs_deb_hex(unsigned int grp, const char *prompt,
+ const u8 *buf, int len)
{
int i = 0;
@@ -123,19 +117,19 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
-/** Buffer Constants */
+/* Buffer Constants */
/* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
-* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
-* driver has more local TxPDs. Each TxPD on the host memory is associated
-* with a Tx control node. The driver maintains 8 RxPD descriptors for
-* station firmware to store Rx packet information.
-*
-* Current version of MAC has a 32x6 multicast address buffer.
-*
-* 802.11b can have up to 14 channels, the driver keeps the
-* BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
-*/
+ * addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
+ * driver has more local TxPDs. Each TxPD on the host memory is associated
+ * with a Tx control node. The driver maintains 8 RxPD descriptors for
+ * station firmware to store Rx packet information.
+ *
+ * Current version of MAC has a 32x6 multicast address buffer.
+ *
+ * 802.11b can have up to 14 channels, the driver keeps the
+ * BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
+ */
#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
#define LBS_NUM_CMD_BUFFERS 10
@@ -166,7 +160,7 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define WOL_RESULT_NOSPC_ERR 1
#define WOL_RESULT_EEXIST_ERR 2
-/** Misc constants */
+/* Misc constants */
/* This section defines 802.11 specific contants */
#define MRVDRV_MAX_BSS_DESCRIPTS 16
@@ -183,7 +177,8 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define MARVELL_MESH_IE_LENGTH 9
-/* Values used to populate the struct mrvl_mesh_ie. The only time you need this
+/*
+ * Values used to populate the struct mrvl_mesh_ie. The only time you need this
* is when enabling the mesh using CMD_MESH_CONFIG.
*/
#define MARVELL_MESH_IE_TYPE 4
@@ -193,7 +188,7 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define MARVELL_MESH_METRIC_ID 0
#define MARVELL_MESH_CAPABILITY 0
-/** INT status Bit Definition*/
+/* INT status Bit Definition */
#define MRVDRV_TX_DNLD_RDY 0x0001
#define MRVDRV_RX_UPLD_RDY 0x0002
#define MRVDRV_CMD_DNLD_RDY 0x0004
@@ -208,59 +203,63 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define TPC_DEFAULT_P1 10
#define TPC_DEFAULT_P2 13
-/** TxPD status */
+/* TxPD status */
-/* Station firmware use TxPD status field to report final Tx transmit
-* result, Bit masks are used to present combined situations.
-*/
+/*
+ * Station firmware use TxPD status field to report final Tx transmit
+ * result, Bit masks are used to present combined situations.
+ */
#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
-/** Tx mesh flag */
-/* Currently we are using normal WDS flag as mesh flag.
+/* Tx mesh flag */
+/*
+ * Currently we are using normal WDS flag as mesh flag.
* TODO: change to proper mesh flag when MAC understands it.
*/
#define TxPD_CONTROL_WDS_FRAME (1<<17)
#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME
-/** Mesh interface ID */
+/* Mesh interface ID */
#define MESH_IFACE_ID 0x0001
-/** Mesh id should be in bits 14-13-12 */
+/* Mesh id should be in bits 14-13-12 */
#define MESH_IFACE_BIT_OFFSET 0x000c
-/** Mesh enable bit in FW capability */
+/* Mesh enable bit in FW capability */
#define MESH_CAPINFO_ENABLE_MASK (1<<16)
-/** FW definition from Marvell v4 */
+/* FW definition from Marvell v4 */
#define MRVL_FW_V4 (0x04)
-/** FW definition from Marvell v5 */
+/* FW definition from Marvell v5 */
#define MRVL_FW_V5 (0x05)
-/** FW definition from Marvell v10 */
+/* FW definition from Marvell v10 */
#define MRVL_FW_V10 (0x0a)
-/** FW major revision definition */
+/* FW major revision definition */
#define MRVL_FW_MAJOR_REV(x) ((x)>>24)
-/** RxPD status */
+/* RxPD status */
#define MRVDRV_RXPD_STATUS_OK 0x0001
-/** RxPD status - Received packet types */
-/** Rx mesh flag */
-/* Currently we are using normal WDS flag as mesh flag.
+/* RxPD status - Received packet types */
+/* Rx mesh flag */
+/*
+ * Currently we are using normal WDS flag as mesh flag.
* TODO: change to proper mesh flag when MAC understands it.
*/
#define RxPD_CONTROL_WDS_FRAME (0x40)
#define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME
-/** RSSI-related defines */
-/* RSSI constants are used to implement 802.11 RSSI threshold
-* indication. if the Rx packet signal got too weak for 5 consecutive
-* times, miniport driver (driver) will report this event to wrapper
-*/
+/* RSSI-related defines */
+/*
+ * RSSI constants are used to implement 802.11 RSSI threshold
+ * indication. if the Rx packet signal got too weak for 5 consecutive
+ * times, miniport driver (driver) will report this event to wrapper
+ */
#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96)
-/** RTS/FRAG related defines */
+/* RTS/FRAG related defines */
#define MRVDRV_RTS_MIN_VALUE 0
#define MRVDRV_RTS_MAX_VALUE 2347
#define MRVDRV_FRAG_MIN_VALUE 256
@@ -300,36 +299,36 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define MAX_LEDS 8
-/** Global Variable Declaration */
+/* Global Variable Declaration */
extern const char lbs_driver_version[];
extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE];
-/** ENUM definition*/
-/** SNRNF_TYPE */
+/* ENUM definition */
+/* SNRNF_TYPE */
enum SNRNF_TYPE {
TYPE_BEACON = 0,
TYPE_RXPD,
MAX_TYPE_B
};
-/** SNRNF_DATA*/
+/* SNRNF_DATA */
enum SNRNF_DATA {
TYPE_NOAVG = 0,
TYPE_AVG,
MAX_TYPE_AVG
};
-/** LBS_802_11_POWER_MODE */
+/* LBS_802_11_POWER_MODE */
enum LBS_802_11_POWER_MODE {
LBS802_11POWERMODECAM,
LBS802_11POWERMODEMAX_PSP,
LBS802_11POWERMODEFAST_PSP,
- /*not a real mode, defined as an upper bound */
+ /* not a real mode, defined as an upper bound */
LBS802_11POWEMODEMAX
};
-/** PS_STATE */
+/* PS_STATE */
enum PS_STATE {
PS_STATE_FULL_POWER,
PS_STATE_AWAKE,
@@ -337,7 +336,7 @@ enum PS_STATE {
PS_STATE_SLEEP
};
-/** DNLD_STATE */
+/* DNLD_STATE */
enum DNLD_STATE {
DNLD_RES_RECEIVED,
DNLD_DATA_SENT,
@@ -345,19 +344,19 @@ enum DNLD_STATE {
DNLD_BOOTCMD_SENT,
};
-/** LBS_MEDIA_STATE */
+/* LBS_MEDIA_STATE */
enum LBS_MEDIA_STATE {
LBS_CONNECTED,
LBS_DISCONNECTED
};
-/** LBS_802_11_PRIVACY_FILTER */
+/* LBS_802_11_PRIVACY_FILTER */
enum LBS_802_11_PRIVACY_FILTER {
LBS802_11PRIVFILTERACCEPTALL,
LBS802_11PRIVFILTER8021XWEP
};
-/** mv_ms_type */
+/* mv_ms_type */
enum mv_ms_type {
MVMS_DAT = 0,
MVMS_CMD = 1,
@@ -365,14 +364,14 @@ enum mv_ms_type {
MVMS_EVENT
};
-/** KEY_TYPE_ID */
+/* KEY_TYPE_ID */
enum KEY_TYPE_ID {
KEY_TYPE_ID_WEP = 0,
KEY_TYPE_ID_TKIP,
KEY_TYPE_ID_AES
};
-/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
+/* KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
enum KEY_INFO_WPA {
KEY_INFO_WPA_MCAST = 0x01,
KEY_INFO_WPA_UNICAST = 0x02,
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index cb14c38caf3..6bd1608992b 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -1,18 +1,18 @@
-/**
- * This file contains definitions and data structures specific
- * to Marvell 802.11 NIC. It contains the Device Information
- * structure struct lbs_private..
- */
+/*
+ * This file contains definitions and data structures specific
+ * to Marvell 802.11 NIC. It contains the Device Information
+ * structure struct lbs_private..
+ */
#ifndef _LBS_DEV_H_
#define _LBS_DEV_H_
-#include "mesh.h"
#include "defs.h"
+#include "decl.h"
#include "host.h"
#include <linux/kfifo.h>
-/** sleep_params */
+/* sleep_params */
struct sleep_params {
uint16_t sp_error;
uint16_t sp_offset;
@@ -22,8 +22,19 @@ struct sleep_params {
uint16_t sp_reserved;
};
+/* Mesh statistics */
+struct lbs_mesh_stats {
+ u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
+ u32 fwd_unicast_cnt; /* Fwd: Unicast counter */
+ u32 fwd_drop_ttl; /* Fwd: TTL zero */
+ u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */
+ u32 fwd_drop_noroute; /* Fwd: No route to Destination */
+ u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */
+ u32 drop_blind; /* Rx: Dropped by blinding table */
+ u32 tx_failed_cnt; /* Tx: Failed transmissions */
+};
-/** Private structure for the MV device */
+/* Private structure for the MV device */
struct lbs_private {
/* Basic networking */
@@ -36,20 +47,19 @@ struct lbs_private {
/* CFG80211 */
struct wireless_dev *wdev;
bool wiphy_registered;
- bool stopping;
struct cfg80211_scan_request *scan_req;
u8 assoc_bss[ETH_ALEN];
+ u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
u8 disassoc_reason;
/* Mesh */
struct net_device *mesh_dev; /* Virtual device */
#ifdef CONFIG_LIBERTAS_MESH
- u32 mesh_connect_status;
struct lbs_mesh_stats mstats;
- int mesh_open;
uint16_t mesh_tlv;
u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
u8 mesh_ssid_len;
+ u8 mesh_channel;
#endif
/* Debugfs */
@@ -88,10 +98,14 @@ struct lbs_private {
/* Hardware access */
void *card;
+ bool iface_running;
u8 fw_ready;
u8 surpriseremoved;
+ u8 setup_fw_on_resume;
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
void (*reset_card) (struct lbs_private *priv);
+ int (*power_save) (struct lbs_private *priv);
+ int (*power_restore) (struct lbs_private *priv);
int (*enter_deep_sleep) (struct lbs_private *priv);
int (*exit_deep_sleep) (struct lbs_private *priv);
int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
@@ -101,6 +115,7 @@ struct lbs_private {
u32 fwcapinfo;
u16 regioncode;
u8 current_addr[ETH_ALEN];
+ u8 copied_hwaddr;
/* Command download */
u8 dnld_sent;
@@ -123,12 +138,12 @@ struct lbs_private {
/* Events sent from hardware to driver */
struct kfifo event_fifo;
- /** thread to service interrupts */
+ /* thread to service interrupts */
struct task_struct *main_thread;
wait_queue_head_t waitq;
struct workqueue_struct *work_thread;
- /** Encryption stuff */
+ /* Encryption stuff */
u8 authtype_auto;
u8 wep_tx_key;
u8 wep_key[4][WLAN_KEY_LEN_WEP104];
@@ -138,6 +153,7 @@ struct lbs_private {
uint32_t wol_criteria;
uint8_t wol_gpio;
uint8_t wol_gap;
+ bool ehs_remove_supported;
/* Transmitting */
int tx_pending_len; /* -1 while building packet */
@@ -145,6 +161,7 @@ struct lbs_private {
/* protected by hard_start_xmit serialization */
u8 txretrycount;
struct sk_buff *currenttxskb;
+ struct timer_list tx_lockup_timer;
/* Locks */
struct mutex lock;
@@ -159,16 +176,36 @@ struct lbs_private {
s16 txpower_min;
s16 txpower_max;
- /** Scanning */
+ /* Scanning */
struct delayed_work scan_work;
int scan_channel;
/* Queue of things waiting for scan completion */
wait_queue_head_t scan_q;
/* Whether the scan was initiated internally and not by cfg80211 */
bool internal_scan;
- unsigned long last_scan;
+
+ /* Firmware load */
+ u32 fw_model;
+ wait_queue_head_t fw_waitq;
+ struct device *fw_device;
+ const struct firmware *helper_fw;
+ const struct lbs_fw_table *fw_table;
+ const struct lbs_fw_table *fw_iter;
+ lbs_fw_cb fw_callback;
};
extern struct cmd_confirm_sleep confirm_sleep;
+/* Check if there is an interface active. */
+static inline int lbs_iface_active(struct lbs_private *priv)
+{
+ int r;
+
+ r = netif_running(priv->dev);
+ if (priv->mesh_dev)
+ r |= netif_running(priv->mesh_dev);
+
+ return r;
+}
+
#endif
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 50193aac679..f955b2d66ed 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -1,9 +1,11 @@
+#include <linux/hardirq.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/delay.h>
#include "decl.h"
#include "cmd.h"
+#include "mesh.h"
static void lbs_ethtool_get_drvinfo(struct net_device *dev,
@@ -11,16 +13,18 @@ static void lbs_ethtool_get_drvinfo(struct net_device *dev,
{
struct lbs_private *priv = dev->ml_priv;
- snprintf(info->fw_version, 32, "%u.%u.%u.p%u",
+ snprintf(info->fw_version, sizeof(info->fw_version),
+ "%u.%u.%u.p%u",
priv->fwrelease >> 24 & 0xff,
priv->fwrelease >> 16 & 0xff,
priv->fwrelease >> 8 & 0xff,
priv->fwrelease & 0xff);
- strcpy(info->driver, "libertas");
- strcpy(info->version, lbs_driver_version);
+ strlcpy(info->driver, "libertas", sizeof(info->driver));
+ strlcpy(info->version, lbs_driver_version, sizeof(info->version));
}
-/* All 8388 parts have 16KiB EEPROM size at the time of writing.
+/*
+ * All 8388 parts have 16KiB EEPROM size at the time of writing.
* In case that changes this needs fixing.
*/
#define LBS_EEPROM_LEN 16384
diff --git a/drivers/net/wireless/libertas/firmware.c b/drivers/net/wireless/libertas/firmware.c
new file mode 100644
index 00000000000..51b92b5df11
--- /dev/null
+++ b/drivers/net/wireless/libertas/firmware.c
@@ -0,0 +1,227 @@
+/*
+ * Firmware loading and handling functions.
+ */
+
+#include <linux/sched.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+
+#include "dev.h"
+#include "decl.h"
+
+static void load_next_firmware_from_table(struct lbs_private *private);
+
+static void lbs_fw_loaded(struct lbs_private *priv, int ret,
+ const struct firmware *helper, const struct firmware *mainfw)
+{
+ unsigned long flags;
+
+ lbs_deb_fw("firmware load complete, code %d\n", ret);
+
+ /* User must free helper/mainfw */
+ priv->fw_callback(priv, ret, helper, mainfw);
+
+ spin_lock_irqsave(&priv->driver_lock, flags);
+ priv->fw_callback = NULL;
+ wake_up(&priv->fw_waitq);
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+}
+
+static void do_load_firmware(struct lbs_private *priv, const char *name,
+ void (*cb)(const struct firmware *fw, void *context))
+{
+ int ret;
+
+ lbs_deb_fw("Requesting %s\n", name);
+ ret = request_firmware_nowait(THIS_MODULE, true, name,
+ priv->fw_device, GFP_KERNEL, priv, cb);
+ if (ret) {
+ lbs_deb_fw("request_firmware_nowait error %d\n", ret);
+ lbs_fw_loaded(priv, ret, NULL, NULL);
+ }
+}
+
+static void main_firmware_cb(const struct firmware *firmware, void *context)
+{
+ struct lbs_private *priv = context;
+
+ if (!firmware) {
+ /* Failed to find firmware: try next table entry */
+ load_next_firmware_from_table(priv);
+ return;
+ }
+
+ /* Firmware found! */
+ lbs_fw_loaded(priv, 0, priv->helper_fw, firmware);
+ if (priv->helper_fw) {
+ release_firmware (priv->helper_fw);
+ priv->helper_fw = NULL;
+ }
+ release_firmware (firmware);
+}
+
+static void helper_firmware_cb(const struct firmware *firmware, void *context)
+{
+ struct lbs_private *priv = context;
+
+ if (!firmware) {
+ /* Failed to find firmware: try next table entry */
+ load_next_firmware_from_table(priv);
+ return;
+ }
+
+ /* Firmware found! */
+ if (priv->fw_iter->fwname) {
+ priv->helper_fw = firmware;
+ do_load_firmware(priv, priv->fw_iter->fwname, main_firmware_cb);
+ } else {
+ /* No main firmware needed for this helper --> success! */
+ lbs_fw_loaded(priv, 0, firmware, NULL);
+ }
+}
+
+static void load_next_firmware_from_table(struct lbs_private *priv)
+{
+ const struct lbs_fw_table *iter;
+
+ if (!priv->fw_iter)
+ iter = priv->fw_table;
+ else
+ iter = ++priv->fw_iter;
+
+ if (priv->helper_fw) {
+ release_firmware(priv->helper_fw);
+ priv->helper_fw = NULL;
+ }
+
+next:
+ if (!iter->helper) {
+ /* End of table hit. */
+ lbs_fw_loaded(priv, -ENOENT, NULL, NULL);
+ return;
+ }
+
+ if (iter->model != priv->fw_model) {
+ iter++;
+ goto next;
+ }
+
+ priv->fw_iter = iter;
+ do_load_firmware(priv, iter->helper, helper_firmware_cb);
+}
+
+void lbs_wait_for_firmware_load(struct lbs_private *priv)
+{
+ wait_event(priv->fw_waitq, priv->fw_callback == NULL);
+}
+
+/**
+ * lbs_get_firmware_async - Retrieves firmware asynchronously. Can load
+ * either a helper firmware and a main firmware (2-stage), or just the helper.
+ *
+ * @priv: Pointer to lbs_private instance
+ * @dev: A pointer to &device structure
+ * @card_model: Bus-specific card model ID used to filter firmware table
+ * elements
+ * @fw_table: Table of firmware file names and device model numbers
+ * terminated by an entry with a NULL helper name
+ * @callback: User callback to invoke when firmware load succeeds or fails.
+ */
+int lbs_get_firmware_async(struct lbs_private *priv, struct device *device,
+ u32 card_model, const struct lbs_fw_table *fw_table,
+ lbs_fw_cb callback)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->driver_lock, flags);
+ if (priv->fw_callback) {
+ lbs_deb_fw("firmware load already in progress\n");
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ return -EBUSY;
+ }
+
+ priv->fw_device = device;
+ priv->fw_callback = callback;
+ priv->fw_table = fw_table;
+ priv->fw_iter = NULL;
+ priv->fw_model = card_model;
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ lbs_deb_fw("Starting async firmware load\n");
+ load_next_firmware_from_table(priv);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(lbs_get_firmware_async);
+
+/**
+ * lbs_get_firmware - Retrieves two-stage firmware
+ *
+ * @dev: A pointer to &device structure
+ * @card_model: Bus-specific card model ID used to filter firmware table
+ * elements
+ * @fw_table: Table of firmware file names and device model numbers
+ * terminated by an entry with a NULL helper name
+ * @helper: On success, the helper firmware; caller must free
+ * @mainfw: On success, the main firmware; caller must free
+ *
+ * Deprecated: use lbs_get_firmware_async() instead.
+ *
+ * returns: 0 on success, non-zero on failure
+ */
+int lbs_get_firmware(struct device *dev, u32 card_model,
+ const struct lbs_fw_table *fw_table,
+ const struct firmware **helper,
+ const struct firmware **mainfw)
+{
+ const struct lbs_fw_table *iter;
+ int ret;
+
+ BUG_ON(helper == NULL);
+ BUG_ON(mainfw == NULL);
+
+ /* Search for firmware to use from the table. */
+ iter = fw_table;
+ while (iter && iter->helper) {
+ if (iter->model != card_model)
+ goto next;
+
+ if (*helper == NULL) {
+ ret = request_firmware(helper, iter->helper, dev);
+ if (ret)
+ goto next;
+
+ /* If the device has one-stage firmware (ie cf8305) and
+ * we've got it then we don't need to bother with the
+ * main firmware.
+ */
+ if (iter->fwname == NULL)
+ return 0;
+ }
+
+ if (*mainfw == NULL) {
+ ret = request_firmware(mainfw, iter->fwname, dev);
+ if (ret) {
+ /* Clear the helper to ensure we don't have
+ * mismatched firmware pairs.
+ */
+ release_firmware(*helper);
+ *helper = NULL;
+ }
+ }
+
+ if (*helper && *mainfw)
+ return 0;
+
+ next:
+ iter++;
+ }
+
+ /* Failed */
+ release_firmware(*helper);
+ *helper = NULL;
+ release_firmware(*mainfw);
+ *mainfw = NULL;
+
+ return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(lbs_get_firmware);
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 5eac1351a02..96726f79a1d 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -1,7 +1,7 @@
-/**
- * This file function prototypes, data structure
- * and definitions for all the host/station commands
- */
+/*
+ * This file function prototypes, data structure
+ * and definitions for all the host/station commands
+ */
#ifndef _LBS_HOST_H_
#define _LBS_HOST_H_
@@ -13,9 +13,10 @@
#define CMD_OPTION_WAITFORRSP 0x0002
-/** Host command IDs */
+/* Host command IDs */
-/* Return command are almost always the same as the host command, but with
+/*
+ * Return command are almost always the same as the host command, but with
* bit 15 set high. There are a few exceptions, though...
*/
#define CMD_RET(cmd) (0x8000 | cmd)
@@ -67,7 +68,6 @@
#define CMD_802_11_BEACON_STOP 0x0049
#define CMD_802_11_MAC_ADDRESS 0x004d
#define CMD_802_11_LED_GPIO_CTRL 0x004e
-#define CMD_802_11_EEPROM_ACCESS 0x0059
#define CMD_802_11_BAND_CONFIG 0x0058
#define CMD_GSPI_BUS_CONFIG 0x005a
#define CMD_802_11D_DOMAIN_INFO 0x005b
@@ -251,7 +251,7 @@ enum cmd_mesh_config_types {
CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */
};
-/** Card Event definition */
+/* Card Event definition */
#define MACREG_INT_CODE_TX_PPA_FREE 0
#define MACREG_INT_CODE_TX_DMA_DONE 1
#define MACREG_INT_CODE_LINK_LOST_W_SCAN 2
@@ -387,7 +387,7 @@ struct lbs_offset_value {
struct mrvl_ie_domain_param_set {
struct mrvl_ie_header header;
- u8 country_code[3];
+ u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
struct ieee80211_country_ie_triplet triplet[MAX_11D_TRIPLETS];
} __packed;
@@ -624,12 +624,14 @@ struct cmd_ds_802_11_rf_channel {
struct cmd_ds_802_11_rssi {
struct cmd_header hdr;
- /* request: number of beacons (N) to average the SNR and NF over
+ /*
+ * request: number of beacons (N) to average the SNR and NF over
* response: SNR of most recent beacon
*/
__le16 n_or_snr;
- /* The following fields are only set in the response.
+ /*
+ * The following fields are only set in the response.
* In the request these are reserved and should be set to 0.
*/
__le16 nf; /* most recent beacon noise floor */
@@ -680,14 +682,16 @@ struct cmd_ds_802_11_ps_mode {
__le16 action;
- /* Interval for keepalive in PS mode:
+ /*
+ * Interval for keepalive in PS mode:
* 0x0000 = don't change
* 0x001E = firmware default
* 0xFFFF = disable
*/
__le16 nullpktinterval;
- /* Number of DTIM intervals to wake up for:
+ /*
+ * Number of DTIM intervals to wake up for:
* 0 = don't change
* 1 = firmware default
* 5 = max
@@ -697,7 +701,8 @@ struct cmd_ds_802_11_ps_mode {
__le16 reserved;
__le16 locallisteninterval;
- /* AdHoc awake period (FW v9+ only):
+ /*
+ * AdHoc awake period (FW v9+ only):
* 0 = don't change
* 1 = always awake (IEEE standard behavior)
* 2 - 31 = sleep for (n - 1) periods and awake for 1 period
@@ -771,7 +776,8 @@ struct adhoc_bssdesc {
__le16 capability;
u8 rates[MAX_RATES];
- /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
+ /*
+ * DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
* Adhoc join command and will cause a binary layout mismatch with
* the firmware
*/
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index fc8121190d3..f499efc6abc 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -21,6 +21,8 @@
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -312,7 +314,8 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
#define CF8385_MANFID 0x02df
#define CF8385_CARDID 0x8103
-/* FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when
+/*
+ * FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when
* that gets fixed. Currently there's no way to access it from the probe hook.
*/
static inline u32 get_model(u16 manf_id, u16 card_id)
@@ -361,7 +364,7 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
if (status & IF_CS_BIT_COMMAND)
break;
if (++loops > 100) {
- lbs_pr_err("card not ready for commands\n");
+ netdev_err(priv->dev, "card not ready for commands\n");
goto done;
}
mdelay(1);
@@ -431,14 +434,16 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
/* is hardware ready? */
status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
if ((status & IF_CS_BIT_RESP) == 0) {
- lbs_pr_err("no cmd response in card\n");
+ netdev_err(priv->dev, "no cmd response in card\n");
*len = 0;
goto out;
}
*len = if_cs_read16(priv->card, IF_CS_RESP_LEN);
if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) {
- lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len);
+ netdev_err(priv->dev,
+ "card cmd buffer has invalid # of bytes (%d)\n",
+ *len);
goto out;
}
@@ -472,7 +477,9 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
len = if_cs_read16(priv->card, IF_CS_READ_LEN);
if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
- lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
+ netdev_err(priv->dev,
+ "card data buffer has invalid # of bytes (%d)\n",
+ len);
priv->dev->stats.rx_dropped++;
goto dat_err;
}
@@ -621,8 +628,10 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
if (remain < count)
count = remain;
- /* "write the number of bytes to be sent to the I/O Command
- * write length register" */
+ /*
+ * "write the number of bytes to be sent to the I/O Command
+ * write length register"
+ */
if_cs_write16(card, IF_CS_CMD_LEN, count);
/* "write this to I/O Command port register as 16 bit writes */
@@ -631,21 +640,27 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
&fw->data[sent],
count >> 1);
- /* "Assert the download over interrupt command in the Host
- * status register" */
+ /*
+ * "Assert the download over interrupt command in the Host
+ * status register"
+ */
if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
- /* "Assert the download over interrupt command in the Card
- * interrupt case register" */
+ /*
+ * "Assert the download over interrupt command in the Card
+ * interrupt case register"
+ */
if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
- /* "The host polls the Card Status register ... for 50 ms before
- declaring a failure */
+ /*
+ * "The host polls the Card Status register ... for 50 ms before
+ * declaring a failure"
+ */
ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
IF_CS_BIT_COMMAND);
if (ret < 0) {
- lbs_pr_err("can't download helper at 0x%x, ret %d\n",
- sent, ret);
+ pr_err("can't download helper at 0x%x, ret %d\n",
+ sent, ret);
goto done;
}
@@ -675,7 +690,7 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW,
IF_CS_SQ_HELPER_OK);
if (ret < 0) {
- lbs_pr_err("helper firmware doesn't answer\n");
+ pr_err("helper firmware doesn't answer\n");
goto done;
}
@@ -683,13 +698,13 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
len = if_cs_read16(card, IF_CS_SQ_READ_LOW);
if (len & 1) {
retry++;
- lbs_pr_info("odd, need to retry this firmware block\n");
+ pr_info("odd, need to retry this firmware block\n");
} else {
retry = 0;
}
if (retry > 20) {
- lbs_pr_err("could not download firmware\n");
+ pr_err("could not download firmware\n");
ret = -ENODEV;
goto done;
}
@@ -709,20 +724,60 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
IF_CS_BIT_COMMAND);
if (ret < 0) {
- lbs_pr_err("can't download firmware at 0x%x\n", sent);
+ pr_err("can't download firmware at 0x%x\n", sent);
goto done;
}
}
ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
if (ret < 0)
- lbs_pr_err("firmware download failed\n");
+ pr_err("firmware download failed\n");
done:
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
return ret;
}
+static void if_cs_prog_firmware(struct lbs_private *priv, int ret,
+ const struct firmware *helper,
+ const struct firmware *mainfw)
+{
+ struct if_cs_card *card = priv->card;
+
+ if (ret) {
+ pr_err("failed to find firmware (%d)\n", ret);
+ return;
+ }
+
+ /* Load the firmware */
+ ret = if_cs_prog_helper(card, helper);
+ if (ret == 0 && (card->model != MODEL_8305))
+ ret = if_cs_prog_real(card, mainfw);
+ if (ret)
+ return;
+
+ /* Now actually get the IRQ */
+ ret = request_irq(card->p_dev->irq, if_cs_interrupt,
+ IRQF_SHARED, DRV_NAME, card);
+ if (ret) {
+ pr_err("error in request_irq\n");
+ return;
+ }
+
+ /*
+ * Clear any interrupt cause that happened while sending
+ * firmware/initializing card
+ */
+ if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK);
+ if_cs_enable_ints(card);
+
+ /* And finally bring the card up */
+ priv->fw_ready = 1;
+ if (lbs_start_card(priv) != 0) {
+ pr_err("could not activate card\n");
+ free_irq(card->p_dev->irq, card);
+ }
+}
/********************************************************************/
@@ -750,7 +805,8 @@ static int if_cs_host_to_card(struct lbs_private *priv,
ret = if_cs_send_cmd(priv, buf, nb);
break;
default:
- lbs_pr_err("%s: unsupported type %d\n", __func__, type);
+ netdev_err(priv->dev, "%s: unsupported type %d\n",
+ __func__, type);
}
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
@@ -779,7 +835,7 @@ static int if_cs_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
if (p_dev->resource[1]->end) {
- lbs_pr_err("wrong CIS (check number of IO windows)\n");
+ pr_err("wrong CIS (check number of IO windows)\n");
return -ENODEV;
}
@@ -793,23 +849,20 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
unsigned int prod_id;
struct lbs_private *priv;
struct if_cs_card *card;
- const struct firmware *helper = NULL;
- const struct firmware *mainfw = NULL;
lbs_deb_enter(LBS_DEB_CS);
card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
- if (!card) {
- lbs_pr_err("error in kzalloc\n");
+ if (!card)
goto out;
- }
+
card->p_dev = p_dev;
p_dev->priv = card;
p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) {
- lbs_pr_err("error in pcmcia_loop_config\n");
+ pr_err("error in pcmcia_loop_config\n");
goto out1;
}
@@ -825,14 +878,14 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
card->iobase = ioport_map(p_dev->resource[0]->start,
resource_size(p_dev->resource[0]));
if (!card->iobase) {
- lbs_pr_err("error in ioport_map\n");
+ pr_err("error in ioport_map\n");
ret = -EIO;
goto out1;
}
ret = pcmcia_enable_device(p_dev);
if (ret) {
- lbs_pr_err("error in pcmcia_enable_device\n");
+ pr_err("error in pcmcia_enable_device\n");
goto out2;
}
@@ -841,54 +894,41 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
/*
* Most of the libertas cards can do unaligned register access, but some
- * weird ones can not. That's especially true for the CF8305 card.
+ * weird ones cannot. That's especially true for the CF8305 card.
*/
- card->align_regs = 0;
+ card->align_regs = false;
card->model = get_model(p_dev->manf_id, p_dev->card_id);
if (card->model == MODEL_UNKNOWN) {
- lbs_pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
- p_dev->manf_id, p_dev->card_id);
+ pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
+ p_dev->manf_id, p_dev->card_id);
+ ret = -ENODEV;
goto out2;
}
/* Check if we have a current silicon */
prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID);
if (card->model == MODEL_8305) {
- card->align_regs = 1;
+ card->align_regs = true;
if (prod_id < IF_CS_CF8305_B1_REV) {
- lbs_pr_err("8305 rev B0 and older are not supported\n");
+ pr_err("8305 rev B0 and older are not supported\n");
ret = -ENODEV;
goto out2;
}
}
if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) {
- lbs_pr_err("8381 rev B2 and older are not supported\n");
+ pr_err("8381 rev B2 and older are not supported\n");
ret = -ENODEV;
goto out2;
}
if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) {
- lbs_pr_err("8385 rev B0 and older are not supported\n");
+ pr_err("8385 rev B0 and older are not supported\n");
ret = -ENODEV;
goto out2;
}
- ret = lbs_get_firmware(&p_dev->dev, NULL, NULL, card->model,
- &fw_table[0], &helper, &mainfw);
- if (ret) {
- lbs_pr_err("failed to find firmware (%d)\n", ret);
- goto out2;
- }
-
- /* Load the firmware early, before calling into libertas.ko */
- ret = if_cs_prog_helper(card, helper);
- if (ret == 0 && (card->model != MODEL_8305))
- ret = if_cs_prog_real(card, mainfw);
- if (ret)
- goto out2;
-
/* Make this card known to the libertas driver */
priv = lbs_add_card(card, &p_dev->dev);
if (!priv) {
@@ -896,35 +936,22 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
goto out2;
}
- /* Finish setting up fields in lbs_private */
+ /* Set up fields in lbs_private */
card->priv = priv;
priv->card = card;
priv->hw_host_to_card = if_cs_host_to_card;
priv->enter_deep_sleep = NULL;
priv->exit_deep_sleep = NULL;
priv->reset_deep_sleep_wakeup = NULL;
- priv->fw_ready = 1;
- /* Now actually get the IRQ */
- ret = request_irq(p_dev->irq, if_cs_interrupt,
- IRQF_SHARED, DRV_NAME, card);
+ /* Get firmware */
+ ret = lbs_get_firmware_async(priv, &p_dev->dev, card->model, fw_table,
+ if_cs_prog_firmware);
if (ret) {
- lbs_pr_err("error in request_irq\n");
- goto out3;
- }
-
- /* Clear any interrupt cause that happend while sending
- * firmware/initializing card */
- if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK);
- if_cs_enable_ints(card);
-
- /* And finally bring the card up */
- if (lbs_start_card(priv) != 0) {
- lbs_pr_err("could not activate card\n");
+ pr_err("failed to find firmware (%d)\n", ret);
goto out3;
}
- ret = 0;
goto out;
out3:
@@ -934,11 +961,6 @@ out2:
out1:
pcmcia_disable_device(p_dev);
out:
- if (helper)
- release_firmware(helper);
- if (mainfw)
- release_firmware(mainfw);
-
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
return ret;
}
@@ -965,7 +987,7 @@ static void if_cs_detach(struct pcmcia_device *p_dev)
/* Module initialization */
/********************************************************************/
-static struct pcmcia_device_id if_cs_ids[] = {
+static const struct pcmcia_device_id if_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
@@ -974,7 +996,6 @@ static struct pcmcia_device_id if_cs_ids[] = {
};
MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
-
static struct pcmcia_driver lbs_driver = {
.owner = THIS_MODULE,
.name = DRV_NAME,
@@ -982,26 +1003,4 @@ static struct pcmcia_driver lbs_driver = {
.remove = if_cs_detach,
.id_table = if_cs_ids,
};
-
-
-static int __init if_cs_init(void)
-{
- int ret;
-
- lbs_deb_enter(LBS_DEB_CS);
- ret = pcmcia_register_driver(&lbs_driver);
- lbs_deb_leave(LBS_DEB_CS);
- return ret;
-}
-
-
-static void __exit if_cs_exit(void)
-{
- lbs_deb_enter(LBS_DEB_CS);
- pcmcia_unregister_driver(&lbs_driver);
- lbs_deb_leave(LBS_DEB_CS);
-}
-
-
-module_init(if_cs_init);
-module_exit(if_cs_exit);
+module_pcmcia_driver(lbs_driver);
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index b4de0ca10fe..33ceda296c9 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -26,8 +26,10 @@
* if_sdio_card_to_host() to pad the data.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <linux/firmware.h>
#include <linux/netdevice.h>
@@ -37,6 +39,7 @@
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/host.h>
+#include <linux/pm_runtime.h>
#include "host.h"
#include "decl.h"
@@ -45,6 +48,8 @@
#include "cmd.h"
#include "if_sdio.h"
+static void if_sdio_interrupt(struct sdio_func *func);
+
/* The if_sdio_remove() callback function is called when
* user removes this module from kernel space or ejects
* the card from the slot. The driver handles these 2 cases
@@ -60,12 +65,6 @@
*/
static u8 user_rmmod;
-static char *lbs_helper_name = NULL;
-module_param_named(helper_name, lbs_helper_name, charp, 0644);
-
-static char *lbs_fw_name = NULL;
-module_param_named(fw_name, lbs_fw_name, charp, 0644);
-
static const struct sdio_device_id if_sdio_ids[] = {
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL,
SDIO_DEVICE_ID_MARVELL_LIBERTAS) },
@@ -118,11 +117,8 @@ struct if_sdio_card {
int model;
unsigned long ioport;
unsigned int scratch_reg;
-
- const char *helper;
- const char *firmware;
- bool helper_allocated;
- bool firmware_allocated;
+ bool started;
+ wait_queue_head_t pwron_waitq;
u8 buffer[65536] __attribute__((aligned(4)));
@@ -135,6 +131,9 @@ struct if_sdio_card {
u8 rx_unit;
};
+static void if_sdio_finish_power_on(struct if_sdio_card *card);
+static int if_sdio_power_off(struct if_sdio_card *card);
+
/********************************************************************/
/* I/O */
/********************************************************************/
@@ -409,7 +408,7 @@ static int if_sdio_card_to_host(struct if_sdio_card *card)
out:
if (ret)
- lbs_pr_err("problem fetching packet from firmware\n");
+ pr_err("problem fetching packet from firmware\n");
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
@@ -446,7 +445,7 @@ static void if_sdio_host_to_card_worker(struct work_struct *work)
}
if (ret)
- lbs_pr_err("error %d sending packet to firmware\n", ret);
+ pr_err("error %d sending packet to firmware\n", ret);
sdio_release_host(card->func);
@@ -499,7 +498,7 @@ static int if_sdio_prog_helper(struct if_sdio_card *card,
*/
mdelay(2);
- chunk_size = min(size, (size_t)60);
+ chunk_size = min_t(size_t, size, 60);
*((__le32*)chunk_buffer) = cpu_to_le32(chunk_size);
memcpy(chunk_buffer + 4, firmware, chunk_size);
@@ -555,7 +554,7 @@ release:
out:
if (ret)
- lbs_pr_err("failed to load helper firmware\n");
+ pr_err("failed to load helper firmware\n");
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
return ret;
@@ -589,17 +588,38 @@ static int if_sdio_prog_real(struct if_sdio_card *card,
size = fw->size;
while (size) {
- ret = if_sdio_wait_status(card, FW_DL_READY_STATUS);
- if (ret)
- goto release;
+ timeout = jiffies + HZ;
+ while (1) {
+ ret = if_sdio_wait_status(card, FW_DL_READY_STATUS);
+ if (ret)
+ goto release;
- req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
- if (ret)
- goto release;
+ req_size = sdio_readb(card->func, IF_SDIO_RD_BASE,
+ &ret);
+ if (ret)
+ goto release;
+
+ req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1,
+ &ret) << 8;
+ if (ret)
+ goto release;
+
+ /*
+ * For SD8688 wait until the length is not 0, 1 or 2
+ * before downloading the first FW block,
+ * since BOOT code writes the register to indicate the
+ * helper/FW download winner,
+ * the value could be 1 or 2 (Func1 or Func2).
+ */
+ if ((size != fw->size) || (req_size > 2))
+ break;
+ if (time_after(jiffies, timeout)) {
+ ret = -ETIMEDOUT;
+ goto release;
+ }
+ mdelay(1);
+ }
- req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
- if (ret)
- goto release;
/*
lbs_deb_sdio("firmware wants %d bytes\n", (int)req_size);
*/
@@ -619,7 +639,7 @@ static int if_sdio_prog_real(struct if_sdio_card *card,
req_size = size;
while (req_size) {
- chunk_size = min(req_size, (size_t)512);
+ chunk_size = min_t(size_t, req_size, 512);
memcpy(chunk_buffer, firmware, chunk_size);
/*
@@ -669,18 +689,41 @@ release:
out:
if (ret)
- lbs_pr_err("failed to load firmware\n");
+ pr_err("failed to load firmware\n");
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
return ret;
}
+static void if_sdio_do_prog_firmware(struct lbs_private *priv, int ret,
+ const struct firmware *helper,
+ const struct firmware *mainfw)
+{
+ struct if_sdio_card *card = priv->card;
+
+ if (ret) {
+ pr_err("failed to find firmware (%d)\n", ret);
+ return;
+ }
+
+ ret = if_sdio_prog_helper(card, helper);
+ if (ret)
+ return;
+
+ lbs_deb_sdio("Helper firmware loaded\n");
+
+ ret = if_sdio_prog_real(card, mainfw);
+ if (ret)
+ return;
+
+ lbs_deb_sdio("Firmware loaded\n");
+ if_sdio_finish_power_on(card);
+}
+
static int if_sdio_prog_firmware(struct if_sdio_card *card)
{
int ret;
u16 scratch;
- const struct firmware *helper = NULL;
- const struct firmware *mainfw = NULL;
lbs_deb_enter(LBS_DEB_SDIO);
@@ -714,47 +757,184 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
*/
if (scratch == IF_SDIO_FIRMWARE_OK) {
lbs_deb_sdio("firmware already loaded\n");
- goto success;
+ if_sdio_finish_power_on(card);
+ return 0;
} else if ((card->model == MODEL_8686) && (scratch & 0x7fff)) {
lbs_deb_sdio("firmware may be running\n");
- goto success;
+ if_sdio_finish_power_on(card);
+ return 0;
}
- ret = lbs_get_firmware(&card->func->dev, lbs_helper_name, lbs_fw_name,
- card->model, &fw_table[0], &helper, &mainfw);
- if (ret) {
- lbs_pr_err("failed to find firmware (%d)\n", ret);
- goto out;
+ ret = lbs_get_firmware_async(card->priv, &card->func->dev, card->model,
+ fw_table, if_sdio_do_prog_firmware);
+
+out:
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+ return ret;
+}
+
+/********************************************************************/
+/* Power management */
+/********************************************************************/
+
+/* Finish power on sequence (after firmware is loaded) */
+static void if_sdio_finish_power_on(struct if_sdio_card *card)
+{
+ struct sdio_func *func = card->func;
+ struct lbs_private *priv = card->priv;
+ int ret;
+
+ sdio_claim_host(func);
+ sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
+
+ /*
+ * Get rx_unit if the chip is SD8688 or newer.
+ * SD8385 & SD8686 do not have rx_unit.
+ */
+ if ((card->model != MODEL_8385)
+ && (card->model != MODEL_8686))
+ card->rx_unit = if_sdio_read_rx_unit(card);
+ else
+ card->rx_unit = 0;
+
+ /*
+ * Set up the interrupt handler late.
+ *
+ * If we set it up earlier, the (buggy) hardware generates a spurious
+ * interrupt, even before the interrupt has been enabled, with
+ * CCCR_INTx = 0.
+ *
+ * We register the interrupt handler late so that we can handle any
+ * spurious interrupts, and also to avoid generation of that known
+ * spurious interrupt in the first place.
+ */
+ ret = sdio_claim_irq(func, if_sdio_interrupt);
+ if (ret)
+ goto release;
+
+ /*
+ * Enable interrupts now that everything is set up
+ */
+ sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
+ if (ret)
+ goto release_irq;
+
+ sdio_release_host(func);
+
+ /* Set fw_ready before queuing any commands so that
+ * lbs_thread won't block from sending them to firmware.
+ */
+ priv->fw_ready = 1;
+
+ /*
+ * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
+ */
+ if (card->model == MODEL_8688) {
+ struct cmd_header cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ lbs_deb_sdio("send function INIT command\n");
+ if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
+ lbs_cmd_copyback, (unsigned long) &cmd))
+ netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");
}
- ret = if_sdio_prog_helper(card, helper);
+ wake_up(&card->pwron_waitq);
+
+ if (!card->started) {
+ ret = lbs_start_card(priv);
+ if_sdio_power_off(card);
+ if (ret == 0) {
+ card->started = true;
+ /* Tell PM core that we don't need the card to be
+ * powered now */
+ pm_runtime_put(&func->dev);
+ }
+ }
+
+ return;
+
+release_irq:
+ sdio_release_irq(func);
+release:
+ sdio_release_host(func);
+}
+
+static int if_sdio_power_on(struct if_sdio_card *card)
+{
+ struct sdio_func *func = card->func;
+ struct mmc_host *host = func->card->host;
+ int ret;
+
+ sdio_claim_host(func);
+
+ ret = sdio_enable_func(func);
if (ret)
- goto out;
+ goto release;
- lbs_deb_sdio("Helper firmware loaded\n");
+ /* For 1-bit transfers to the 8686 model, we need to enable the
+ * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
+ * bit to allow access to non-vendor registers. */
+ if ((card->model == MODEL_8686) &&
+ (host->caps & MMC_CAP_SDIO_IRQ) &&
+ (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
+ u8 reg;
- ret = if_sdio_prog_real(card, mainfw);
+ func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+ reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
+ if (ret)
+ goto disable;
+
+ reg |= SDIO_BUS_ECSI;
+ sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
+ if (ret)
+ goto disable;
+ }
+
+ card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
if (ret)
- goto out;
+ goto disable;
- lbs_deb_sdio("Firmware loaded\n");
+ card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
+ if (ret)
+ goto disable;
-success:
- sdio_claim_host(card->func);
- sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
- sdio_release_host(card->func);
- ret = 0;
+ card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
+ if (ret)
+ goto disable;
-out:
- if (helper)
- release_firmware(helper);
- if (mainfw)
- release_firmware(mainfw);
+ sdio_release_host(func);
+ ret = if_sdio_prog_firmware(card);
+ if (ret) {
+ sdio_claim_host(func);
+ goto disable;
+ }
- lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+ return 0;
+
+disable:
+ sdio_disable_func(func);
+release:
+ sdio_release_host(func);
return ret;
}
+static int if_sdio_power_off(struct if_sdio_card *card)
+{
+ struct sdio_func *func = card->func;
+ struct lbs_private *priv = card->priv;
+
+ priv->fw_ready = 0;
+
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+ return 0;
+}
+
+
/*******************************************************************/
/* Libertas callbacks */
/*******************************************************************/
@@ -849,7 +1029,7 @@ static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
lbs_cmd_copyback, (unsigned long) &cmd);
if (ret)
- lbs_pr_err("DEEP_SLEEP cmd failed\n");
+ netdev_err(priv->dev, "DEEP_SLEEP cmd failed\n");
mdelay(200);
return ret;
@@ -865,7 +1045,7 @@ static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
if (ret)
- lbs_pr_err("sdio_writeb failed!\n");
+ netdev_err(priv->dev, "sdio_writeb failed!\n");
sdio_release_host(card->func);
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
@@ -882,7 +1062,7 @@ static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
if (ret)
- lbs_pr_err("sdio_writeb failed!\n");
+ netdev_err(priv->dev, "sdio_writeb failed!\n");
sdio_release_host(card->func);
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
@@ -890,6 +1070,69 @@ static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
}
+static struct mmc_host *reset_host;
+
+static void if_sdio_reset_card_worker(struct work_struct *work)
+{
+ /*
+ * The actual reset operation must be run outside of lbs_thread. This
+ * is because mmc_remove_host() will cause the device to be instantly
+ * destroyed, and the libertas driver then needs to end lbs_thread,
+ * leading to a deadlock.
+ *
+ * We run it in a workqueue totally independent from the if_sdio_card
+ * instance for that reason.
+ */
+
+ pr_info("Resetting card...");
+ mmc_remove_host(reset_host);
+ mmc_add_host(reset_host);
+}
+static DECLARE_WORK(card_reset_work, if_sdio_reset_card_worker);
+
+static void if_sdio_reset_card(struct lbs_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+
+ if (work_pending(&card_reset_work))
+ return;
+
+ reset_host = card->func->card->host;
+ schedule_work(&card_reset_work);
+}
+
+static int if_sdio_power_save(struct lbs_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret;
+
+ flush_workqueue(card->workqueue);
+
+ ret = if_sdio_power_off(card);
+
+ /* Let runtime PM know the card is powered off */
+ pm_runtime_put_sync(&card->func->dev);
+
+ return ret;
+}
+
+static int if_sdio_power_restore(struct lbs_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int r;
+
+ /* Make sure the card will not be powered off by runtime PM */
+ pm_runtime_get_sync(&card->func->dev);
+
+ r = if_sdio_power_on(card);
+ if (r)
+ return r;
+
+ wait_event(card->pwron_waitq, priv->fw_ready);
+ return 0;
+}
+
+
/*******************************************************************/
/* SDIO callbacks */
/*******************************************************************/
@@ -905,7 +1148,7 @@ static void if_sdio_interrupt(struct sdio_func *func)
card = sdio_get_drvdata(func);
cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);
- if (ret)
+ if (ret || !cause)
goto out;
lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
@@ -943,7 +1186,6 @@ static int if_sdio_probe(struct sdio_func *func,
int ret, i;
unsigned int model;
struct if_sdio_packet *packet;
- struct mmc_host *host = func->card->host;
lbs_deb_enter(LBS_DEB_SDIO);
@@ -961,7 +1203,7 @@ static int if_sdio_probe(struct sdio_func *func,
}
if (i == func->card->num_info) {
- lbs_pr_err("unable to identify card model\n");
+ pr_err("unable to identify card model\n");
return -ENODEV;
}
@@ -988,6 +1230,7 @@ static int if_sdio_probe(struct sdio_func *func,
spin_lock_init(&card->lock);
card->workqueue = create_workqueue("libertas_sdio");
INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
+ init_waitqueue_head(&card->pwron_waitq);
/* Check if we support this card */
for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
@@ -995,54 +1238,11 @@ static int if_sdio_probe(struct sdio_func *func,
break;
}
if (i == ARRAY_SIZE(fw_table)) {
- lbs_pr_err("unknown card model 0x%x\n", card->model);
+ pr_err("unknown card model 0x%x\n", card->model);
ret = -ENODEV;
goto free;
}
- sdio_claim_host(func);
-
- ret = sdio_enable_func(func);
- if (ret)
- goto release;
-
- ret = sdio_claim_irq(func, if_sdio_interrupt);
- if (ret)
- goto disable;
-
- /* For 1-bit transfers to the 8686 model, we need to enable the
- * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
- * bit to allow access to non-vendor registers. */
- if ((card->model == MODEL_8686) &&
- (host->caps & MMC_CAP_SDIO_IRQ) &&
- (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
- u8 reg;
-
- func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
- reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
- if (ret)
- goto release_int;
-
- reg |= SDIO_BUS_ECSI;
- sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
- if (ret)
- goto release_int;
- }
-
- card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
- if (ret)
- goto release_int;
-
- card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
- if (ret)
- goto release_int;
-
- card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
- if (ret)
- goto release_int;
-
- sdio_release_host(func);
-
sdio_set_drvdata(func, card);
lbs_deb_sdio("class = 0x%X, vendor = 0x%X, "
@@ -1050,14 +1250,11 @@ static int if_sdio_probe(struct sdio_func *func,
func->class, func->vendor, func->device,
model, (unsigned)card->ioport);
- ret = if_sdio_prog_firmware(card);
- if (ret)
- goto reclaim;
priv = lbs_add_card(card, &func->dev);
if (!priv) {
ret = -ENOMEM;
- goto reclaim;
+ goto free;
}
card->priv = priv;
@@ -1067,44 +1264,11 @@ static int if_sdio_probe(struct sdio_func *func,
priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
+ priv->reset_card = if_sdio_reset_card;
+ priv->power_save = if_sdio_power_save;
+ priv->power_restore = if_sdio_power_restore;
- sdio_claim_host(func);
-
- /*
- * Get rx_unit if the chip is SD8688 or newer.
- * SD8385 & SD8686 do not have rx_unit.
- */
- if ((card->model != MODEL_8385)
- && (card->model != MODEL_8686))
- card->rx_unit = if_sdio_read_rx_unit(card);
- else
- card->rx_unit = 0;
-
- /*
- * Enable interrupts now that everything is set up
- */
- sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
- sdio_release_host(func);
- if (ret)
- goto reclaim;
-
- priv->fw_ready = 1;
-
- /*
- * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
- */
- if (card->model == MODEL_8688) {
- struct cmd_header cmd;
-
- memset(&cmd, 0, sizeof(cmd));
-
- lbs_deb_sdio("send function INIT command\n");
- if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
- lbs_cmd_copyback, (unsigned long) &cmd))
- lbs_pr_alert("CMD_FUNC_INIT cmd failed\n");
- }
-
- ret = lbs_start_card(priv);
+ ret = if_sdio_power_on(card);
if (ret)
goto err_activate_card;
@@ -1116,14 +1280,6 @@ out:
err_activate_card:
flush_workqueue(card->workqueue);
lbs_remove_card(priv);
-reclaim:
- sdio_claim_host(func);
-release_int:
- sdio_release_irq(func);
-disable:
- sdio_disable_func(func);
-release:
- sdio_release_host(func);
free:
destroy_workqueue(card->workqueue);
while (card->packets) {
@@ -1132,10 +1288,6 @@ free:
kfree(packet);
}
- if (card->helper_allocated)
- kfree(card->helper);
- if (card->firmware_allocated)
- kfree(card->firmware);
kfree(card);
goto out;
@@ -1150,6 +1302,9 @@ static void if_sdio_remove(struct sdio_func *func)
card = sdio_get_drvdata(func);
+ /* Undo decrement done above in if_sdio_probe */
+ pm_runtime_get_noresume(&func->dev);
+
if (user_rmmod && (card->model == MODEL_8688)) {
/*
* FUNC_SHUTDOWN is required for SD8688 WLAN/BT
@@ -1163,7 +1318,7 @@ static void if_sdio_remove(struct sdio_func *func)
if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN,
&cmd, sizeof(cmd), lbs_cmd_copyback,
(unsigned long) &cmd))
- lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
+ pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
}
@@ -1174,23 +1329,13 @@ static void if_sdio_remove(struct sdio_func *func)
flush_workqueue(card->workqueue);
destroy_workqueue(card->workqueue);
- sdio_claim_host(func);
- sdio_release_irq(func);
- sdio_disable_func(func);
- sdio_release_host(func);
-
while (card->packets) {
packet = card->packets;
card->packets = card->packets->next;
kfree(packet);
}
- if (card->helper_allocated)
- kfree(card->helper);
- if (card->firmware_allocated)
- kfree(card->firmware);
kfree(card);
-
lbs_deb_leave(LBS_DEB_SDIO);
}
@@ -1202,20 +1347,24 @@ static int if_sdio_suspend(struct device *dev)
mmc_pm_flag_t flags = sdio_get_host_pm_caps(func);
- lbs_pr_info("%s: suspend: PM flags = 0x%x\n",
- sdio_func_id(func), flags);
+ /* If we're powered off anyway, just let the mmc layer remove the
+ * card. */
+ if (!lbs_iface_active(card->priv))
+ return -ENOSYS;
+
+ dev_info(dev, "%s: suspend: PM flags = 0x%x\n",
+ sdio_func_id(func), flags);
/* If we aren't being asked to wake on anything, we should bail out
* and let the SD stack power down the card.
*/
if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) {
- lbs_pr_info("Suspend without wake params -- "
- "powering down card.");
+ dev_info(dev, "Suspend without wake params -- powering down card\n");
return -ENOSYS;
}
if (!(flags & MMC_PM_KEEP_POWER)) {
- lbs_pr_err("%s: cannot remain alive while host is suspended\n",
+ dev_err(dev, "%s: cannot remain alive while host is suspended\n",
sdio_func_id(func));
return -ENOSYS;
}
@@ -1237,7 +1386,7 @@ static int if_sdio_resume(struct device *dev)
struct if_sdio_card *card = sdio_get_drvdata(func);
int ret;
- lbs_pr_info("%s: resume: we're back\n", sdio_func_id(func));
+ dev_info(dev, "%s: resume: we're back\n", sdio_func_id(func));
ret = lbs_resume(card->priv);
@@ -1289,6 +1438,8 @@ static void __exit if_sdio_exit_module(void)
/* Set the flag as user is removing this module. */
user_rmmod = 1;
+ cancel_work_sync(&card_reset_work);
+
sdio_unregister_driver(&if_sdio_driver);
lbs_deb_leave(LBS_DEB_SDIO);
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index ecd4d04b2c3..f11728a866f 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -17,13 +17,15 @@
* (at your option) any later version.
*/
-#include <linux/moduleparam.h>
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/hardirq.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/jiffies.h>
-#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/netdevice.h>
-#include <linux/semaphore.h>
#include <linux/slab.h>
#include <linux/spi/libertas_spi.h>
#include <linux/spi/spi.h>
@@ -34,6 +36,12 @@
#include "dev.h"
#include "if_spi.h"
+struct if_spi_packet {
+ struct list_head list;
+ u16 blen;
+ u8 buffer[0] __attribute__((aligned(4)));
+};
+
struct if_spi_card {
struct spi_device *spi;
struct lbs_private *priv;
@@ -51,19 +59,40 @@ struct if_spi_card {
unsigned long spu_reg_delay;
/* Handles all SPI communication (except for FW load) */
- struct task_struct *spi_thread;
- int run_thread;
-
- /* Used to wake up the spi_thread */
- struct semaphore spi_ready;
- struct semaphore spi_thread_terminated;
+ struct workqueue_struct *workqueue;
+ struct work_struct packet_work;
+ struct work_struct resume_work;
u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE];
+
+ /* A buffer of incoming packets from libertas core.
+ * Since we can't sleep in hw_host_to_card, we have to buffer
+ * them. */
+ struct list_head cmd_packet_list;
+ struct list_head data_packet_list;
+
+ /* Protects cmd_packet_list and data_packet_list */
+ spinlock_t buffer_lock;
+
+ /* True is card suspended */
+ u8 suspended;
};
static void free_if_spi_card(struct if_spi_card *card)
{
- spi_set_drvdata(card->spi, NULL);
+ struct list_head *cursor, *next;
+ struct if_spi_packet *packet;
+
+ list_for_each_safe(cursor, next, &card->cmd_packet_list) {
+ packet = container_of(cursor, struct if_spi_packet, list);
+ list_del(&packet->list);
+ kfree(packet);
+ }
+ list_for_each_safe(cursor, next, &card->data_packet_list) {
+ packet = container_of(cursor, struct if_spi_packet, list);
+ list_del(&packet->list);
+ kfree(packet);
+ }
kfree(card);
}
@@ -117,8 +146,10 @@ static void spu_transaction_finish(struct if_spi_card *card)
card->prev_xfer_time = jiffies;
}
-/* Write out a byte buffer to an SPI register,
- * using a series of 16-bit transfers. */
+/*
+ * Write out a byte buffer to an SPI register,
+ * using a series of 16-bit transfers.
+ */
static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len)
{
int err = 0;
@@ -182,8 +213,10 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len)
struct spi_transfer dummy_trans;
struct spi_transfer data_trans;
- /* You must take an even number of bytes from the SPU, even if you
- * don't care about the last one. */
+ /*
+ * You must take an even number of bytes from the SPU, even if you
+ * don't care about the last one.
+ */
BUG_ON(len & 0x1);
spu_transaction_init(card);
@@ -232,8 +265,10 @@ static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val)
return ret;
}
-/* Read 32 bits from an SPI register.
- * The low 16 bits are read first. */
+/*
+ * Read 32 bits from an SPI register.
+ * The low 16 bits are read first.
+ */
static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val)
{
__le32 buf;
@@ -245,13 +280,15 @@ static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val)
return err;
}
-/* Keep reading 16 bits from an SPI register until you get the correct result.
+/*
+ * Keep reading 16 bits from an SPI register until you get the correct result.
*
* If mask = 0, the correct result is any non-zero number.
* If mask != 0, the correct result is any number where
* number & target_mask == target
*
- * Returns -ETIMEDOUT if a second passes without the correct result. */
+ * Returns -ETIMEDOUT if a second passes without the correct result.
+ */
static int spu_wait_for_u16(struct if_spi_card *card, u16 reg,
u16 target_mask, u16 target)
{
@@ -271,16 +308,17 @@ static int spu_wait_for_u16(struct if_spi_card *card, u16 reg,
}
udelay(100);
if (time_after(jiffies, timeout)) {
- lbs_pr_err("%s: timeout with val=%02x, "
- "target_mask=%02x, target=%02x\n",
+ pr_err("%s: timeout with val=%02x, target_mask=%02x, target=%02x\n",
__func__, val, target_mask, target);
return -ETIMEDOUT;
}
}
}
-/* Read 16 bits from an SPI register until you receive a specific value.
- * Returns -ETIMEDOUT if a 4 tries pass without success. */
+/*
+ * Read 16 bits from an SPI register until you receive a specific value.
+ * Returns -ETIMEDOUT if a 4 tries pass without success.
+ */
static int spu_wait_for_u32(struct if_spi_card *card, u32 reg, u32 target)
{
int err, try;
@@ -302,8 +340,10 @@ static int spu_set_interrupt_mode(struct if_spi_card *card,
{
int err = 0;
- /* We can suppress a host interrupt by clearing the appropriate
- * bit in the "host interrupt status mask" register */
+ /*
+ * We can suppress a host interrupt by clearing the appropriate
+ * bit in the "host interrupt status mask" register
+ */
if (suppress_host_int) {
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG, 0);
if (err)
@@ -319,10 +359,12 @@ static int spu_set_interrupt_mode(struct if_spi_card *card,
return err;
}
- /* If auto-interrupts are on, the completion of certain transactions
+ /*
+ * If auto-interrupts are on, the completion of certain transactions
* will trigger an interrupt automatically. If auto-interrupts
* are off, we need to set the "Card Interrupt Cause" register to
- * trigger a card interrupt. */
+ * trigger a card interrupt.
+ */
if (auto_int) {
err = spu_write_u16(card, IF_SPI_HOST_INT_CTRL_REG,
IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO |
@@ -365,7 +407,7 @@ static int spu_set_bus_mode(struct if_spi_card *card, u16 mode)
if (err)
return err;
if ((rval & 0xF) != mode) {
- lbs_pr_err("Can't read bus mode register.\n");
+ pr_err("Can't read bus mode register\n");
return -EIO;
}
return 0;
@@ -376,8 +418,10 @@ static int spu_init(struct if_spi_card *card, int use_dummy_writes)
int err = 0;
u32 delay;
- /* We have to start up in timed delay mode so that we can safely
- * read the Delay Read Register. */
+ /*
+ * We have to start up in timed delay mode so that we can safely
+ * read the Delay Read Register.
+ */
card->use_dummy_writes = 0;
err = spu_set_bus_mode(card,
IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING |
@@ -433,8 +477,10 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
/* Load helper firmware image */
while (bytes_remaining > 0) {
- /* Scratch pad 1 should contain the number of bytes we
- * want to download to the firmware */
+ /*
+ * Scratch pad 1 should contain the number of bytes we
+ * want to download to the firmware
+ */
err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG,
HELPER_FW_LOAD_CHUNK_SZ);
if (err)
@@ -446,8 +492,10 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
if (err)
goto out;
- /* Feed the data into the command read/write port reg
- * in chunks of 64 bytes */
+ /*
+ * Feed the data into the command read/write port reg
+ * in chunks of 64 bytes
+ */
memset(temp, 0, sizeof(temp));
memcpy(temp, fw,
min(bytes_remaining, HELPER_FW_LOAD_CHUNK_SZ));
@@ -469,9 +517,11 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
fw += HELPER_FW_LOAD_CHUNK_SZ;
}
- /* Once the helper / single stage firmware download is complete,
+ /*
+ * Once the helper / single stage firmware download is complete,
* write 0 to scratch pad 1 and interrupt the
- * bootloader. This completes the helper download. */
+ * bootloader. This completes the helper download.
+ */
err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK);
if (err)
goto out;
@@ -480,32 +530,32 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
goto out;
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
IF_SPI_CIC_CMD_DOWNLOAD_OVER);
- goto out;
-
- lbs_deb_spi("waiting for helper to boot...\n");
-
out:
if (err)
- lbs_pr_err("failed to load helper firmware (err=%d)\n", err);
+ pr_err("failed to load helper firmware (err=%d)\n", err);
lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err);
return err;
}
-/* Returns the length of the next packet the firmware expects us to send
- * Sets crc_err if the previous transfer had a CRC error. */
+/*
+ * Returns the length of the next packet the firmware expects us to send.
+ * Sets crc_err if the previous transfer had a CRC error.
+ */
static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
int *crc_err)
{
u16 len;
int err = 0;
- /* wait until the host interrupt status register indicates
- * that we are ready to download */
+ /*
+ * wait until the host interrupt status register indicates
+ * that we are ready to download
+ */
err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
IF_SPI_HIST_CMD_DOWNLOAD_RDY,
IF_SPI_HIST_CMD_DOWNLOAD_RDY);
if (err) {
- lbs_pr_err("timed out waiting for host_int_status\n");
+ pr_err("timed out waiting for host_int_status\n");
return err;
}
@@ -515,9 +565,8 @@ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
return err;
if (len > IF_SPI_CMD_BUF_SIZE) {
- lbs_pr_err("firmware load device requested a larger "
- "tranfer than we are prepared to "
- "handle. (len = %d)\n", len);
+ pr_err("firmware load device requested a larger transfer than we are prepared to handle (len = %d)\n",
+ len);
return -EIO;
}
if (len & 0x1) {
@@ -533,6 +582,7 @@ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
static int if_spi_prog_main_firmware(struct if_spi_card *card,
const struct firmware *firmware)
{
+ struct lbs_private *priv = card->priv;
int len, prev_len;
int bytes, crc_err = 0, err = 0;
const u8 *fw;
@@ -546,8 +596,9 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card,
err = spu_wait_for_u16(card, IF_SPI_SCRATCH_1_REG, 0, 0);
if (err) {
- lbs_pr_err("%s: timed out waiting for initial "
- "scratch reg = 0\n", __func__);
+ netdev_err(priv->dev,
+ "%s: timed out waiting for initial scratch reg = 0\n",
+ __func__);
goto out;
}
@@ -561,17 +612,18 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card,
goto out;
}
if (bytes < 0) {
- /* If there are no more bytes left, we would normally
- * expect to have terminated with len = 0 */
- lbs_pr_err("Firmware load wants more bytes "
- "than we have to offer.\n");
+ /*
+ * If there are no more bytes left, we would normally
+ * expect to have terminated with len = 0
+ */
+ netdev_err(priv->dev,
+ "Firmware load wants more bytes than we have to offer.\n");
break;
}
if (crc_err) {
/* Previous transfer failed. */
if (++num_crc_errs > MAX_MAIN_FW_LOAD_CRC_ERR) {
- lbs_pr_err("Too many CRC errors encountered "
- "in firmware load.\n");
+ pr_err("Too many CRC errors encountered in firmware load.\n");
err = -EIO;
goto out;
}
@@ -600,21 +652,20 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card,
prev_len = len;
}
if (bytes > prev_len) {
- lbs_pr_err("firmware load wants fewer bytes than "
- "we have to offer.\n");
+ pr_err("firmware load wants fewer bytes than we have to offer\n");
}
/* Confirm firmware download */
err = spu_wait_for_u32(card, IF_SPI_SCRATCH_4_REG,
SUCCESSFUL_FW_DOWNLOAD_MAGIC);
if (err) {
- lbs_pr_err("failed to confirm the firmware download\n");
+ pr_err("failed to confirm the firmware download\n");
goto out;
}
out:
if (err)
- lbs_pr_err("failed to load firmware (err=%d)\n", err);
+ pr_err("failed to load firmware (err=%d)\n", err);
lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err);
return err;
}
@@ -622,7 +673,7 @@ out:
/*
* SPI Transfer Thread
*
- * The SPI thread handles all SPI transfers, so there is no need for a lock.
+ * The SPI worker handles all SPI transfers, so there is no need for a lock.
*/
/* Move a command from the card to the host */
@@ -634,14 +685,18 @@ static int if_spi_c2h_cmd(struct if_spi_card *card)
u16 len;
u8 i;
- /* We need a buffer big enough to handle whatever people send to
- * hw_host_to_card */
+ /*
+ * We need a buffer big enough to handle whatever people send to
+ * hw_host_to_card
+ */
BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_CMD_BUFFER_SIZE);
BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_UPLD_SIZE);
- /* It's just annoying if the buffer size isn't a multiple of 4, because
- * then we might have len < IF_SPI_CMD_BUF_SIZE but
- * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE */
+ /*
+ * It's just annoying if the buffer size isn't a multiple of 4, because
+ * then we might have len < IF_SPI_CMD_BUF_SIZE but
+ * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE
+ */
BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE % 4 != 0);
lbs_deb_enter(LBS_DEB_SPI);
@@ -651,13 +706,13 @@ static int if_spi_c2h_cmd(struct if_spi_card *card)
if (err)
goto out;
if (!len) {
- lbs_pr_err("%s: error: card has no data for host\n",
+ netdev_err(priv->dev, "%s: error: card has no data for host\n",
__func__);
err = -EINVAL;
goto out;
} else if (len > IF_SPI_CMD_BUF_SIZE) {
- lbs_pr_err("%s: error: response packet too large: "
- "%d bytes, but maximum is %d\n",
+ netdev_err(priv->dev,
+ "%s: error: response packet too large: %d bytes, but maximum is %d\n",
__func__, len, IF_SPI_CMD_BUF_SIZE);
err = -EINVAL;
goto out;
@@ -679,7 +734,7 @@ static int if_spi_c2h_cmd(struct if_spi_card *card)
out:
if (err)
- lbs_pr_err("%s: err=%d\n", __func__, err);
+ netdev_err(priv->dev, "%s: err=%d\n", __func__, err);
lbs_deb_leave(LBS_DEB_SPI);
return err;
}
@@ -687,6 +742,7 @@ out:
/* Move data from the card to the host */
static int if_spi_c2h_data(struct if_spi_card *card)
{
+ struct lbs_private *priv = card->priv;
struct sk_buff *skb;
char *data;
u16 len;
@@ -699,13 +755,13 @@ static int if_spi_c2h_data(struct if_spi_card *card)
if (err)
goto out;
if (!len) {
- lbs_pr_err("%s: error: card has no data for host\n",
+ netdev_err(priv->dev, "%s: error: card has no data for host\n",
__func__);
err = -EINVAL;
goto out;
} else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
- lbs_pr_err("%s: error: card has %d bytes of data, but "
- "our maximum skb size is %zu\n",
+ netdev_err(priv->dev,
+ "%s: error: card has %d bytes of data, but our maximum skb size is %zu\n",
__func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
err = -EINVAL;
goto out;
@@ -737,11 +793,47 @@ free_skb:
dev_kfree_skb(skb);
out:
if (err)
- lbs_pr_err("%s: err=%d\n", __func__, err);
+ netdev_err(priv->dev, "%s: err=%d\n", __func__, err);
lbs_deb_leave(LBS_DEB_SPI);
return err;
}
+/* Move data or a command from the host to the card. */
+static void if_spi_h2c(struct if_spi_card *card,
+ struct if_spi_packet *packet, int type)
+{
+ struct lbs_private *priv = card->priv;
+ int err = 0;
+ u16 int_type, port_reg;
+
+ switch (type) {
+ case MVMS_DAT:
+ int_type = IF_SPI_CIC_TX_DOWNLOAD_OVER;
+ port_reg = IF_SPI_DATA_RDWRPORT_REG;
+ break;
+ case MVMS_CMD:
+ int_type = IF_SPI_CIC_CMD_DOWNLOAD_OVER;
+ port_reg = IF_SPI_CMD_RDWRPORT_REG;
+ break;
+ default:
+ netdev_err(priv->dev, "can't transfer buffer of type %d\n",
+ type);
+ err = -EINVAL;
+ goto out;
+ }
+
+ /* Write the data to the card */
+ err = spu_write(card, port_reg, packet->buffer, packet->blen);
+ if (err)
+ goto out;
+
+out:
+ kfree(packet);
+
+ if (err)
+ netdev_err(priv->dev, "%s: error %d\n", __func__, err);
+}
+
/* Inform the host about a card event */
static void if_spi_e2h(struct if_spi_card *card)
{
@@ -763,104 +855,155 @@ static void if_spi_e2h(struct if_spi_card *card)
lbs_queue_event(priv, cause & 0xff);
out:
if (err)
- lbs_pr_err("%s: error %d\n", __func__, err);
+ netdev_err(priv->dev, "%s: error %d\n", __func__, err);
}
-static int lbs_spi_thread(void *data)
+static void if_spi_host_to_card_worker(struct work_struct *work)
{
int err;
- struct if_spi_card *card = data;
+ struct if_spi_card *card;
u16 hiStatus;
+ unsigned long flags;
+ struct if_spi_packet *packet;
+ struct lbs_private *priv;
- while (1) {
- /* Wait to be woken up by one of two things. First, our ISR
- * could tell us that something happened on the WLAN.
- * Secondly, libertas could call hw_host_to_card with more
- * data, which we might be able to send.
- */
- do {
- err = down_interruptible(&card->spi_ready);
- if (!card->run_thread) {
- up(&card->spi_thread_terminated);
- do_exit(0);
- }
- } while (err == EINTR);
+ card = container_of(work, struct if_spi_card, packet_work);
+ priv = card->priv;
- /* Read the host interrupt status register to see what we
- * can do. */
- err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG,
- &hiStatus);
- if (err) {
- lbs_pr_err("I/O error\n");
+ lbs_deb_enter(LBS_DEB_SPI);
+
+ /*
+ * Read the host interrupt status register to see what we
+ * can do.
+ */
+ err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG,
+ &hiStatus);
+ if (err) {
+ netdev_err(priv->dev, "I/O error\n");
+ goto err;
+ }
+
+ if (hiStatus & IF_SPI_HIST_CMD_UPLOAD_RDY) {
+ err = if_spi_c2h_cmd(card);
+ if (err)
goto err;
- }
+ }
+ if (hiStatus & IF_SPI_HIST_RX_UPLOAD_RDY) {
+ err = if_spi_c2h_data(card);
+ if (err)
+ goto err;
+ }
- if (hiStatus & IF_SPI_HIST_CMD_UPLOAD_RDY) {
- err = if_spi_c2h_cmd(card);
- if (err)
- goto err;
- }
- if (hiStatus & IF_SPI_HIST_RX_UPLOAD_RDY) {
- err = if_spi_c2h_data(card);
- if (err)
- goto err;
+ /*
+ * workaround: in PS mode, the card does not set the Command
+ * Download Ready bit, but it sets TX Download Ready.
+ */
+ if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY ||
+ (card->priv->psstate != PS_STATE_FULL_POWER &&
+ (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) {
+ /*
+ * This means two things. First of all,
+ * if there was a previous command sent, the card has
+ * successfully received it.
+ * Secondly, it is now ready to download another
+ * command.
+ */
+ lbs_host_to_card_done(card->priv);
+
+ /* Do we have any command packets from the host to send? */
+ packet = NULL;
+ spin_lock_irqsave(&card->buffer_lock, flags);
+ if (!list_empty(&card->cmd_packet_list)) {
+ packet = (struct if_spi_packet *)(card->
+ cmd_packet_list.next);
+ list_del(&packet->list);
}
+ spin_unlock_irqrestore(&card->buffer_lock, flags);
- /* workaround: in PS mode, the card does not set the Command
- * Download Ready bit, but it sets TX Download Ready. */
- if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY ||
- (card->priv->psstate != PS_STATE_FULL_POWER &&
- (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) {
- lbs_host_to_card_done(card->priv);
+ if (packet)
+ if_spi_h2c(card, packet, MVMS_CMD);
+ }
+ if (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY) {
+ /* Do we have any data packets from the host to send? */
+ packet = NULL;
+ spin_lock_irqsave(&card->buffer_lock, flags);
+ if (!list_empty(&card->data_packet_list)) {
+ packet = (struct if_spi_packet *)(card->
+ data_packet_list.next);
+ list_del(&packet->list);
}
+ spin_unlock_irqrestore(&card->buffer_lock, flags);
- if (hiStatus & IF_SPI_HIST_CARD_EVENT)
- if_spi_e2h(card);
+ if (packet)
+ if_spi_h2c(card, packet, MVMS_DAT);
+ }
+ if (hiStatus & IF_SPI_HIST_CARD_EVENT)
+ if_spi_e2h(card);
err:
- if (err)
- lbs_pr_err("%s: got error %d\n", __func__, err);
- }
-}
+ if (err)
+ netdev_err(priv->dev, "%s: got error %d\n", __func__, err);
-/* Block until lbs_spi_thread thread has terminated */
-static void if_spi_terminate_spi_thread(struct if_spi_card *card)
-{
- /* It would be nice to use kthread_stop here, but that function
- * can't wake threads waiting for a semaphore. */
- card->run_thread = 0;
- up(&card->spi_ready);
- down(&card->spi_thread_terminated);
+ lbs_deb_leave(LBS_DEB_SPI);
}
/*
* Host to Card
*
* Called from Libertas to transfer some data to the WLAN device
- * We can't sleep here. */
+ * We can't sleep here.
+ */
static int if_spi_host_to_card(struct lbs_private *priv,
u8 type, u8 *buf, u16 nb)
{
int err = 0;
+ unsigned long flags;
struct if_spi_card *card = priv->card;
+ struct if_spi_packet *packet;
+ u16 blen;
lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb);
- nb = ALIGN(nb, 4);
+ if (nb == 0) {
+ netdev_err(priv->dev, "%s: invalid size requested: %d\n",
+ __func__, nb);
+ err = -EINVAL;
+ goto out;
+ }
+ blen = ALIGN(nb, 4);
+ packet = kzalloc(sizeof(struct if_spi_packet) + blen, GFP_ATOMIC);
+ if (!packet) {
+ err = -ENOMEM;
+ goto out;
+ }
+ packet->blen = blen;
+ memcpy(packet->buffer, buf, nb);
+ memset(packet->buffer + nb, 0, blen - nb);
switch (type) {
case MVMS_CMD:
- err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG, buf, nb);
+ priv->dnld_sent = DNLD_CMD_SENT;
+ spin_lock_irqsave(&card->buffer_lock, flags);
+ list_add_tail(&packet->list, &card->cmd_packet_list);
+ spin_unlock_irqrestore(&card->buffer_lock, flags);
break;
case MVMS_DAT:
- err = spu_write(card, IF_SPI_DATA_RDWRPORT_REG, buf, nb);
+ priv->dnld_sent = DNLD_DATA_SENT;
+ spin_lock_irqsave(&card->buffer_lock, flags);
+ list_add_tail(&packet->list, &card->data_packet_list);
+ spin_unlock_irqrestore(&card->buffer_lock, flags);
break;
default:
- lbs_pr_err("can't transfer buffer of type %d", type);
+ kfree(packet);
+ netdev_err(priv->dev, "can't transfer buffer of type %d\n",
+ type);
err = -EINVAL;
break;
}
+ /* Queue spi xfer work */
+ queue_work(card->workqueue, &card->packet_work);
+out:
lbs_deb_leave_args(LBS_DEB_SPI, "err=%d", err);
return err;
}
@@ -869,13 +1012,14 @@ static int if_spi_host_to_card(struct lbs_private *priv,
* Host Interrupts
*
* Service incoming interrupts from the WLAN device. We can't sleep here, so
- * don't try to talk on the SPI bus, just wake up the SPI thread.
+ * don't try to talk on the SPI bus, just queue the SPI xfer work.
*/
static irqreturn_t if_spi_host_interrupt(int irq, void *dev_id)
{
struct if_spi_card *card = dev_id;
- up(&card->spi_ready);
+ queue_work(card->workqueue, &card->packet_work);
+
return IRQ_HANDLED;
}
@@ -883,56 +1027,26 @@ static irqreturn_t if_spi_host_interrupt(int irq, void *dev_id)
* SPI callbacks
*/
-static int __devinit if_spi_probe(struct spi_device *spi)
+static int if_spi_init_card(struct if_spi_card *card)
{
- struct if_spi_card *card;
- struct lbs_private *priv = NULL;
- struct libertas_spi_platform_data *pdata = spi->dev.platform_data;
- int err = 0, i;
+ struct lbs_private *priv = card->priv;
+ int err, i;
u32 scratch;
- struct sched_param param = { .sched_priority = 1 };
const struct firmware *helper = NULL;
const struct firmware *mainfw = NULL;
lbs_deb_enter(LBS_DEB_SPI);
- if (!pdata) {
- err = -EINVAL;
- goto out;
- }
-
- if (pdata->setup) {
- err = pdata->setup(spi);
- if (err)
- goto out;
- }
-
- /* Allocate card structure to represent this specific device */
- card = kzalloc(sizeof(struct if_spi_card), GFP_KERNEL);
- if (!card) {
- err = -ENOMEM;
- goto out;
- }
- spi_set_drvdata(spi, card);
- card->pdata = pdata;
- card->spi = spi;
- card->prev_xfer_time = jiffies;
-
- sema_init(&card->spi_ready, 0);
- sema_init(&card->spi_thread_terminated, 0);
-
- /* Initialize the SPI Interface Unit */
- err = spu_init(card, pdata->use_dummy_writes);
+ err = spu_init(card, card->pdata->use_dummy_writes);
if (err)
- goto free_card;
+ goto out;
err = spu_get_chip_revision(card, &card->card_id, &card->card_rev);
if (err)
- goto free_card;
+ goto out;
- /* Firmware load */
err = spu_read_u32(card, IF_SPI_SCRATCH_4_REG, &scratch);
if (err)
- goto free_card;
+ goto out;
if (scratch == SUCCESSFUL_FW_DOWNLOAD_MAGIC)
lbs_deb_spi("Firmware is already loaded for "
"Marvell WLAN 802.11 adapter\n");
@@ -943,18 +1057,18 @@ static int __devinit if_spi_probe(struct spi_device *spi)
break;
}
if (i == ARRAY_SIZE(fw_table)) {
- lbs_pr_err("Unsupported chip_id: 0x%02x\n",
- card->card_id);
+ netdev_err(priv->dev, "Unsupported chip_id: 0x%02x\n",
+ card->card_id);
err = -ENODEV;
- goto free_card;
+ goto out;
}
- err = lbs_get_firmware(&card->spi->dev, NULL, NULL,
- card->card_id, &fw_table[0], &helper,
- &mainfw);
+ err = lbs_get_firmware(&card->spi->dev, card->card_id,
+ &fw_table[0], &helper, &mainfw);
if (err) {
- lbs_pr_err("failed to find firmware (%d)\n", err);
- goto free_card;
+ netdev_err(priv->dev, "failed to find firmware (%d)\n",
+ err);
+ goto out;
}
lbs_deb_spi("Initializing FW for Marvell WLAN 802.11 adapter "
@@ -962,29 +1076,102 @@ static int __devinit if_spi_probe(struct spi_device *spi)
"attached to SPI bus_num %d, chip_select %d. "
"spi->max_speed_hz=%d\n",
card->card_id, card->card_rev,
- spi->master->bus_num, spi->chip_select,
- spi->max_speed_hz);
+ card->spi->master->bus_num,
+ card->spi->chip_select,
+ card->spi->max_speed_hz);
err = if_spi_prog_helper_firmware(card, helper);
if (err)
- goto free_card;
+ goto out;
err = if_spi_prog_main_firmware(card, mainfw);
if (err)
- goto free_card;
+ goto out;
lbs_deb_spi("loaded FW for Marvell WLAN 802.11 adapter\n");
}
err = spu_set_interrupt_mode(card, 0, 1);
if (err)
+ goto out;
+
+out:
+ lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err);
+ return err;
+}
+
+static void if_spi_resume_worker(struct work_struct *work)
+{
+ struct if_spi_card *card;
+
+ card = container_of(work, struct if_spi_card, resume_work);
+
+ if (card->suspended) {
+ if (card->pdata->setup)
+ card->pdata->setup(card->spi);
+
+ /* Init card ... */
+ if_spi_init_card(card);
+
+ enable_irq(card->spi->irq);
+
+ /* And resume it ... */
+ lbs_resume(card->priv);
+
+ card->suspended = 0;
+ }
+}
+
+static int if_spi_probe(struct spi_device *spi)
+{
+ struct if_spi_card *card;
+ struct lbs_private *priv = NULL;
+ struct libertas_spi_platform_data *pdata = dev_get_platdata(&spi->dev);
+ int err = 0;
+
+ lbs_deb_enter(LBS_DEB_SPI);
+
+ if (!pdata) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (pdata->setup) {
+ err = pdata->setup(spi);
+ if (err)
+ goto out;
+ }
+
+ /* Allocate card structure to represent this specific device */
+ card = kzalloc(sizeof(struct if_spi_card), GFP_KERNEL);
+ if (!card) {
+ err = -ENOMEM;
+ goto teardown;
+ }
+ spi_set_drvdata(spi, card);
+ card->pdata = pdata;
+ card->spi = spi;
+ card->prev_xfer_time = jiffies;
+
+ INIT_LIST_HEAD(&card->cmd_packet_list);
+ INIT_LIST_HEAD(&card->data_packet_list);
+ spin_lock_init(&card->buffer_lock);
+
+ /* Initialize the SPI Interface Unit */
+
+ /* Firmware load */
+ err = if_spi_init_card(card);
+ if (err)
goto free_card;
- /* Register our card with libertas.
- * This will call alloc_etherdev */
+ /*
+ * Register our card with libertas.
+ * This will call alloc_etherdev.
+ */
priv = lbs_add_card(card, &spi->dev);
if (!priv) {
err = -ENOMEM;
goto free_card;
}
card->priv = priv;
+ priv->setup_fw_on_resume = 1;
priv->card = card;
priv->hw_host_to_card = if_spi_host_to_card;
priv->enter_deep_sleep = NULL;
@@ -993,30 +1180,22 @@ static int __devinit if_spi_probe(struct spi_device *spi)
priv->fw_ready = 1;
/* Initialize interrupt handling stuff. */
- card->run_thread = 1;
- card->spi_thread = kthread_run(lbs_spi_thread, card, "lbs_spi_thread");
- if (IS_ERR(card->spi_thread)) {
- card->run_thread = 0;
- err = PTR_ERR(card->spi_thread);
- lbs_pr_err("error creating SPI thread: err=%d\n", err);
- goto remove_card;
- }
- if (sched_setscheduler(card->spi_thread, SCHED_FIFO, &param))
- lbs_pr_err("Error setting scheduler, using default.\n");
+ card->workqueue = create_workqueue("libertas_spi");
+ INIT_WORK(&card->packet_work, if_spi_host_to_card_worker);
+ INIT_WORK(&card->resume_work, if_spi_resume_worker);
err = request_irq(spi->irq, if_spi_host_interrupt,
IRQF_TRIGGER_FALLING, "libertas_spi", card);
if (err) {
- lbs_pr_err("can't get host irq line-- request_irq failed\n");
- goto terminate_thread;
+ pr_err("can't get host irq line-- request_irq failed\n");
+ goto terminate_workqueue;
}
- /* poke the IRQ handler so that we don't miss the first interrupt */
- up(&card->spi_ready);
-
- /* Start the card.
+ /*
+ * Start the card.
* This will call register_netdev, and we'll start
- * getting interrupts... */
+ * getting interrupts...
+ */
err = lbs_start_card(priv);
if (err)
goto release_irq;
@@ -1028,23 +1207,21 @@ static int __devinit if_spi_probe(struct spi_device *spi)
release_irq:
free_irq(spi->irq, card);
-terminate_thread:
- if_spi_terminate_spi_thread(card);
-remove_card:
+terminate_workqueue:
+ flush_workqueue(card->workqueue);
+ destroy_workqueue(card->workqueue);
lbs_remove_card(priv); /* will call free_netdev */
free_card:
free_if_spi_card(card);
+teardown:
+ if (pdata->teardown)
+ pdata->teardown(spi);
out:
- if (helper)
- release_firmware(helper);
- if (mainfw)
- release_firmware(mainfw);
-
lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err);
return err;
}
-static int __devexit libertas_spi_remove(struct spi_device *spi)
+static int libertas_spi_remove(struct spi_device *spi)
{
struct if_spi_card *card = spi_get_drvdata(spi);
struct lbs_private *priv = card->priv;
@@ -1052,11 +1229,14 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
lbs_deb_spi("libertas_spi_remove\n");
lbs_deb_enter(LBS_DEB_SPI);
+ cancel_work_sync(&card->resume_work);
+
lbs_stop_card(priv);
lbs_remove_card(priv); /* will call free_netdev */
free_irq(spi->irq, card);
- if_spi_terminate_spi_thread(card);
+ flush_workqueue(card->workqueue);
+ destroy_workqueue(card->workqueue);
if (card->pdata->teardown)
card->pdata->teardown(spi);
free_if_spi_card(card);
@@ -1064,13 +1244,47 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
return 0;
}
+static int if_spi_suspend(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct if_spi_card *card = spi_get_drvdata(spi);
+
+ if (!card->suspended) {
+ lbs_suspend(card->priv);
+ flush_workqueue(card->workqueue);
+ disable_irq(spi->irq);
+
+ if (card->pdata->teardown)
+ card->pdata->teardown(spi);
+ card->suspended = 1;
+ }
+
+ return 0;
+}
+
+static int if_spi_resume(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct if_spi_card *card = spi_get_drvdata(spi);
+
+ /* Schedule delayed work */
+ schedule_work(&card->resume_work);
+
+ return 0;
+}
+
+static const struct dev_pm_ops if_spi_pm_ops = {
+ .suspend = if_spi_suspend,
+ .resume = if_spi_resume,
+};
+
static struct spi_driver libertas_spi_driver = {
.probe = if_spi_probe,
- .remove = __devexit_p(libertas_spi_remove),
+ .remove = libertas_spi_remove,
.driver = {
.name = "libertas_spi",
- .bus = &spi_bus_type,
.owner = THIS_MODULE,
+ .pm = &if_spi_pm_ops,
},
};
diff --git a/drivers/net/wireless/libertas/if_spi.h b/drivers/net/wireless/libertas/if_spi.h
index 8b1417d3b71..e450e31fd11 100644
--- a/drivers/net/wireless/libertas/if_spi.h
+++ b/drivers/net/wireless/libertas/if_spi.h
@@ -66,7 +66,7 @@
#define IF_SPI_HOST_INT_CTRL_REG 0x40 /* Host interrupt controller reg */
#define IF_SPI_CARD_INT_CAUSE_REG 0x44 /* Card interrupt cause reg */
-#define IF_SPI_CARD_INT_STATUS_REG 0x48 /* Card interupt status reg */
+#define IF_SPI_CARD_INT_STATUS_REG 0x48 /* Card interrupt status reg */
#define IF_SPI_CARD_INT_EVENT_MASK_REG 0x4C /* Card interrupt event mask */
#define IF_SPI_CARD_INT_STATUS_MASK_REG 0x50 /* Card interrupt status mask */
@@ -86,34 +86,34 @@
#define IF_SPI_DEVICEID_CTRL_REG_TO_CARD_REV(dc) (dc & 0x000000ff)
/***************** IF_SPI_HOST_INT_CTRL_REG *****************/
-/** Host Interrupt Control bit : Wake up */
+/* Host Interrupt Control bit : Wake up */
#define IF_SPI_HICT_WAKE_UP (1<<0)
-/** Host Interrupt Control bit : WLAN ready */
+/* Host Interrupt Control bit : WLAN ready */
#define IF_SPI_HICT_WLAN_READY (1<<1)
/*#define IF_SPI_HICT_FIFO_FIRST_HALF_EMPTY (1<<2) */
/*#define IF_SPI_HICT_FIFO_SECOND_HALF_EMPTY (1<<3) */
/*#define IF_SPI_HICT_IRQSRC_WLAN (1<<4) */
-/** Host Interrupt Control bit : Tx auto download */
+/* Host Interrupt Control bit : Tx auto download */
#define IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO (1<<5)
-/** Host Interrupt Control bit : Rx auto upload */
+/* Host Interrupt Control bit : Rx auto upload */
#define IF_SPI_HICT_RX_UPLOAD_OVER_AUTO (1<<6)
-/** Host Interrupt Control bit : Command auto download */
+/* Host Interrupt Control bit : Command auto download */
#define IF_SPI_HICT_CMD_DOWNLOAD_OVER_AUTO (1<<7)
-/** Host Interrupt Control bit : Command auto upload */
+/* Host Interrupt Control bit : Command auto upload */
#define IF_SPI_HICT_CMD_UPLOAD_OVER_AUTO (1<<8)
/***************** IF_SPI_CARD_INT_CAUSE_REG *****************/
-/** Card Interrupt Case bit : Tx download over */
+/* Card Interrupt Case bit : Tx download over */
#define IF_SPI_CIC_TX_DOWNLOAD_OVER (1<<0)
-/** Card Interrupt Case bit : Rx upload over */
+/* Card Interrupt Case bit : Rx upload over */
#define IF_SPI_CIC_RX_UPLOAD_OVER (1<<1)
-/** Card Interrupt Case bit : Command download over */
+/* Card Interrupt Case bit : Command download over */
#define IF_SPI_CIC_CMD_DOWNLOAD_OVER (1<<2)
-/** Card Interrupt Case bit : Host event */
+/* Card Interrupt Case bit : Host event */
#define IF_SPI_CIC_HOST_EVENT (1<<3)
-/** Card Interrupt Case bit : Command upload over */
+/* Card Interrupt Case bit : Command upload over */
#define IF_SPI_CIC_CMD_UPLOAD_OVER (1<<4)
-/** Card Interrupt Case bit : Power down */
+/* Card Interrupt Case bit : Power down */
#define IF_SPI_CIC_POWER_DOWN (1<<5)
/***************** IF_SPI_CARD_INT_STATUS_REG *****************/
@@ -138,51 +138,51 @@
#define IF_SPI_HICU_CMD_RD_FIFO_UNDERFLOW (1<<10)
/***************** IF_SPI_HOST_INT_STATUS_REG *****************/
-/** Host Interrupt Status bit : Tx download ready */
+/* Host Interrupt Status bit : Tx download ready */
#define IF_SPI_HIST_TX_DOWNLOAD_RDY (1<<0)
-/** Host Interrupt Status bit : Rx upload ready */
+/* Host Interrupt Status bit : Rx upload ready */
#define IF_SPI_HIST_RX_UPLOAD_RDY (1<<1)
-/** Host Interrupt Status bit : Command download ready */
+/* Host Interrupt Status bit : Command download ready */
#define IF_SPI_HIST_CMD_DOWNLOAD_RDY (1<<2)
-/** Host Interrupt Status bit : Card event */
+/* Host Interrupt Status bit : Card event */
#define IF_SPI_HIST_CARD_EVENT (1<<3)
-/** Host Interrupt Status bit : Command upload ready */
+/* Host Interrupt Status bit : Command upload ready */
#define IF_SPI_HIST_CMD_UPLOAD_RDY (1<<4)
-/** Host Interrupt Status bit : I/O write FIFO overflow */
+/* Host Interrupt Status bit : I/O write FIFO overflow */
#define IF_SPI_HIST_IO_WR_FIFO_OVERFLOW (1<<5)
-/** Host Interrupt Status bit : I/O read FIFO underflow */
+/* Host Interrupt Status bit : I/O read FIFO underflow */
#define IF_SPI_HIST_IO_RD_FIFO_UNDRFLOW (1<<6)
-/** Host Interrupt Status bit : Data write FIFO overflow */
+/* Host Interrupt Status bit : Data write FIFO overflow */
#define IF_SPI_HIST_DATA_WR_FIFO_OVERFLOW (1<<7)
-/** Host Interrupt Status bit : Data read FIFO underflow */
+/* Host Interrupt Status bit : Data read FIFO underflow */
#define IF_SPI_HIST_DATA_RD_FIFO_UNDERFLOW (1<<8)
-/** Host Interrupt Status bit : Command write FIFO overflow */
+/* Host Interrupt Status bit : Command write FIFO overflow */
#define IF_SPI_HIST_CMD_WR_FIFO_OVERFLOW (1<<9)
-/** Host Interrupt Status bit : Command read FIFO underflow */
+/* Host Interrupt Status bit : Command read FIFO underflow */
#define IF_SPI_HIST_CMD_RD_FIFO_UNDERFLOW (1<<10)
/***************** IF_SPI_HOST_INT_STATUS_MASK_REG *****************/
-/** Host Interrupt Status Mask bit : Tx download ready */
+/* Host Interrupt Status Mask bit : Tx download ready */
#define IF_SPI_HISM_TX_DOWNLOAD_RDY (1<<0)
-/** Host Interrupt Status Mask bit : Rx upload ready */
+/* Host Interrupt Status Mask bit : Rx upload ready */
#define IF_SPI_HISM_RX_UPLOAD_RDY (1<<1)
-/** Host Interrupt Status Mask bit : Command download ready */
+/* Host Interrupt Status Mask bit : Command download ready */
#define IF_SPI_HISM_CMD_DOWNLOAD_RDY (1<<2)
-/** Host Interrupt Status Mask bit : Card event */
+/* Host Interrupt Status Mask bit : Card event */
#define IF_SPI_HISM_CARDEVENT (1<<3)
-/** Host Interrupt Status Mask bit : Command upload ready */
+/* Host Interrupt Status Mask bit : Command upload ready */
#define IF_SPI_HISM_CMD_UPLOAD_RDY (1<<4)
-/** Host Interrupt Status Mask bit : I/O write FIFO overflow */
+/* Host Interrupt Status Mask bit : I/O write FIFO overflow */
#define IF_SPI_HISM_IO_WR_FIFO_OVERFLOW (1<<5)
-/** Host Interrupt Status Mask bit : I/O read FIFO underflow */
+/* Host Interrupt Status Mask bit : I/O read FIFO underflow */
#define IF_SPI_HISM_IO_RD_FIFO_UNDERFLOW (1<<6)
-/** Host Interrupt Status Mask bit : Data write FIFO overflow */
+/* Host Interrupt Status Mask bit : Data write FIFO overflow */
#define IF_SPI_HISM_DATA_WR_FIFO_OVERFLOW (1<<7)
-/** Host Interrupt Status Mask bit : Data write FIFO underflow */
+/* Host Interrupt Status Mask bit : Data write FIFO underflow */
#define IF_SPI_HISM_DATA_RD_FIFO_UNDERFLOW (1<<8)
-/** Host Interrupt Status Mask bit : Command write FIFO overflow */
+/* Host Interrupt Status Mask bit : Command write FIFO overflow */
#define IF_SPI_HISM_CMD_WR_FIFO_OVERFLOW (1<<9)
-/** Host Interrupt Status Mask bit : Command write FIFO underflow */
+/* Host Interrupt Status Mask bit : Command write FIFO underflow */
#define IF_SPI_HISM_CMD_RD_FIFO_UNDERFLOW (1<<10)
/***************** IF_SPI_SPU_BUS_MODE_REG *****************/
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index efaf8503220..dff08a2896a 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -1,12 +1,16 @@
-/**
- * This file contains functions used in USB interface module.
- */
+/*
+ * This file contains functions used in USB interface module.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/delay.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/netdevice.h>
#include <linux/slab.h>
#include <linux/usb.h>
+#include <linux/olpc-ec.h>
#ifdef CONFIG_OLPC
#include <asm/olpc.h>
@@ -26,9 +30,6 @@
#define MESSAGE_HEADER_LEN 4
-static char *lbs_fw_name = NULL;
-module_param_named(fw_name, lbs_fw_name, charp, 0644);
-
MODULE_FIRMWARE("libertas/usb8388_v9.bin");
MODULE_FIRMWARE("libertas/usb8388_v5.bin");
MODULE_FIRMWARE("libertas/usb8388.bin");
@@ -41,6 +42,16 @@ enum {
MODEL_8682 = 0x2
};
+/* table of firmware file names */
+static const struct lbs_fw_table fw_table[] = {
+ { MODEL_8388, "libertas/usb8388_olpc.bin", NULL },
+ { MODEL_8388, "libertas/usb8388_v9.bin", NULL },
+ { MODEL_8388, "libertas/usb8388_v5.bin", NULL },
+ { MODEL_8388, "libertas/usb8388.bin", NULL },
+ { MODEL_8388, "usb8388.bin", NULL },
+ { MODEL_8682, "libertas/usb8682.bin", NULL }
+};
+
static struct usb_device_id if_usb_table[] = {
/* Enter the device signature inside */
{ USB_DEVICE(0x1286, 0x2001), .driver_info = MODEL_8388 },
@@ -52,10 +63,9 @@ MODULE_DEVICE_TABLE(usb, if_usb_table);
static void if_usb_receive(struct urb *urb);
static void if_usb_receive_fwload(struct urb *urb);
-static int __if_usb_prog_firmware(struct if_usb_card *cardp,
- const char *fwname, int cmd);
-static int if_usb_prog_firmware(struct if_usb_card *cardp,
- const char *fwname, int cmd);
+static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
+ const struct firmware *fw,
+ const struct firmware *unused);
static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
uint8_t *payload, uint16_t nb);
static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
@@ -64,66 +74,11 @@ static void if_usb_free(struct if_usb_card *cardp);
static int if_usb_submit_rx_urb(struct if_usb_card *cardp);
static int if_usb_reset_device(struct if_usb_card *cardp);
-/* sysfs hooks */
-
/**
- * Set function to write firmware to device's persistent memory
- */
-static ssize_t if_usb_firmware_set(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- struct if_usb_card *cardp = priv->card;
- int ret;
-
- BUG_ON(buf == NULL);
-
- ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_FW);
- if (ret == 0)
- return count;
-
- return ret;
-}
-
-/**
- * lbs_flash_fw attribute to be exported per ethX interface through sysfs
- * (/sys/class/net/ethX/lbs_flash_fw). Use this like so to write firmware to
- * the device's persistent memory:
- * echo usb8388-5.126.0.p5.bin > /sys/class/net/ethX/lbs_flash_fw
- */
-static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set);
-
-/**
- * Set function to write firmware to device's persistent memory
- */
-static ssize_t if_usb_boot2_set(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- struct if_usb_card *cardp = priv->card;
- int ret;
-
- BUG_ON(buf == NULL);
-
- ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_BOOT2);
- if (ret == 0)
- return count;
-
- return ret;
-}
-
-/**
- * lbs_flash_boot2 attribute to be exported per ethX interface through sysfs
- * (/sys/class/net/ethX/lbs_flash_boot2). Use this like so to write firmware
- * to the device's persistent memory:
- * echo usb8388-5.126.0.p5.bin > /sys/class/net/ethX/lbs_flash_boot2
- */
-static DEVICE_ATTR(lbs_flash_boot2, 0200, NULL, if_usb_boot2_set);
-
-/**
- * @brief call back function to handle the status of the URB
- * @param urb pointer to urb structure
- * @return N/A
+ * if_usb_write_bulk_callback - callback function to handle the status
+ * of the URB
+ * @urb: pointer to &urb structure
+ * returns: N/A
*/
static void if_usb_write_bulk_callback(struct urb *urb)
{
@@ -145,14 +100,14 @@ static void if_usb_write_bulk_callback(struct urb *urb)
lbs_host_to_card_done(priv);
} else {
/* print the failure status number for debug */
- lbs_pr_info("URB in failure status: %d\n", urb->status);
+ pr_info("URB in failure status: %d\n", urb->status);
}
}
/**
- * @brief free tx/rx urb, skb and rx buffer
- * @param cardp pointer if_usb_card
- * @return N/A
+ * if_usb_free - free tx/rx urb, skb and rx buffer
+ * @cardp: pointer to &if_usb_card
+ * returns: N/A
*/
static void if_usb_free(struct if_usb_card *cardp)
{
@@ -195,7 +150,7 @@ static void if_usb_setup_firmware(struct lbs_private *priv)
wake_method.hdr.size = cpu_to_le16(sizeof(wake_method));
wake_method.action = cpu_to_le16(CMD_ACT_GET);
if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
- lbs_pr_info("Firmware does not seem to support PS mode\n");
+ netdev_info(priv->dev, "Firmware does not seem to support PS mode\n");
priv->fwcapinfo &= ~FW_CAPINFO_PS;
} else {
if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
@@ -204,7 +159,8 @@ static void if_usb_setup_firmware(struct lbs_private *priv)
/* The versions which boot up this way don't seem to
work even if we set it to the command interrupt */
priv->fwcapinfo &= ~FW_CAPINFO_PS;
- lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n");
+ netdev_info(priv->dev,
+ "Firmware doesn't wake via command interrupt; disabling PS mode\n");
}
}
}
@@ -216,7 +172,7 @@ static void if_usb_fw_timeo(unsigned long priv)
if (cardp->fwdnldover) {
lbs_deb_usb("Download complete, no event. Assuming success\n");
} else {
- lbs_pr_err("Download timed out\n");
+ pr_err("Download timed out\n");
cardp->surprise_removed = 1;
}
wake_up(&cardp->fw_wq);
@@ -231,10 +187,10 @@ static void if_usb_reset_olpc_card(struct lbs_private *priv)
#endif
/**
- * @brief sets the configuration values
- * @param ifnum interface number
- * @param id pointer to usb_device_id
- * @return 0 on success, error code on failure
+ * if_usb_probe - sets the configuration values
+ * @intf: &usb_interface pointer
+ * @id: pointer to usb_device_id
+ * returns: 0 on success, error code on failure
*/
static int if_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -244,15 +200,14 @@ static int if_usb_probe(struct usb_interface *intf,
struct usb_endpoint_descriptor *endpoint;
struct lbs_private *priv;
struct if_usb_card *cardp;
+ int r = -ENOMEM;
int i;
udev = interface_to_usbdev(intf);
cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
- if (!cardp) {
- lbs_pr_err("Out of memory allocating private data.\n");
+ if (!cardp)
goto error;
- }
setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp);
init_waitqueue_head(&cardp->fw_wq);
@@ -303,20 +258,10 @@ static int if_usb_probe(struct usb_interface *intf,
goto dealloc;
}
- /* Upload firmware */
- kparam_block_sysfs_write(fw_name);
- if (__if_usb_prog_firmware(cardp, lbs_fw_name, BOOT_CMD_FW_BY_USB)) {
- kparam_unblock_sysfs_write(fw_name);
- lbs_deb_usbd(&udev->dev, "FW upload failed\n");
- goto err_prog_firmware;
- }
- kparam_unblock_sysfs_write(fw_name);
-
- if (!(priv = lbs_add_card(cardp, &udev->dev)))
- goto err_prog_firmware;
+ if (!(priv = lbs_add_card(cardp, &intf->dev)))
+ goto err_add_card;
cardp->priv = priv;
- cardp->priv->fw_ready = 1;
priv->hw_host_to_card = if_usb_host_to_card;
priv->enter_deep_sleep = NULL;
@@ -329,54 +274,42 @@ static int if_usb_probe(struct usb_interface *intf,
cardp->boot2_version = udev->descriptor.bcdDevice;
- if_usb_submit_rx_urb(cardp);
-
- if (lbs_start_card(priv))
- goto err_start_card;
-
- if_usb_setup_firmware(priv);
-
usb_get_dev(udev);
usb_set_intfdata(intf, cardp);
- if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_fw))
- lbs_pr_err("cannot register lbs_flash_fw attribute\n");
-
- if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2))
- lbs_pr_err("cannot register lbs_flash_boot2 attribute\n");
+ r = lbs_get_firmware_async(priv, &udev->dev, cardp->model,
+ fw_table, if_usb_prog_firmware);
+ if (r)
+ goto err_get_fw;
return 0;
-err_start_card:
+err_get_fw:
lbs_remove_card(priv);
-err_prog_firmware:
+err_add_card:
if_usb_reset_device(cardp);
dealloc:
if_usb_free(cardp);
error:
- return -ENOMEM;
+ return r;
}
/**
- * @brief free resource and cleanup
- * @param intf USB interface structure
- * @return N/A
+ * if_usb_disconnect - free resource and cleanup
+ * @intf: USB interface structure
+ * returns: N/A
*/
static void if_usb_disconnect(struct usb_interface *intf)
{
struct if_usb_card *cardp = usb_get_intfdata(intf);
- struct lbs_private *priv = (struct lbs_private *) cardp->priv;
+ struct lbs_private *priv = cardp->priv;
lbs_deb_enter(LBS_DEB_MAIN);
- device_remove_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2);
- device_remove_file(&priv->dev->dev, &dev_attr_lbs_flash_fw);
-
cardp->surprise_removed = 1;
if (priv) {
- priv->surpriseremoved = 1;
lbs_stop_card(priv);
lbs_remove_card(priv);
}
@@ -391,9 +324,9 @@ static void if_usb_disconnect(struct usb_interface *intf)
}
/**
- * @brief This function download FW
- * @param priv pointer to struct lbs_private
- * @return 0
+ * if_usb_send_fw_pkt - download FW
+ * @cardp: pointer to &struct if_usb_card
+ * returns: 0
*/
static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
{
@@ -479,11 +412,11 @@ static int if_usb_reset_device(struct if_usb_card *cardp)
}
/**
- * @brief This function transfer the data to the device.
- * @param priv pointer to struct lbs_private
- * @param payload pointer to payload data
- * @param nb data length
- * @return 0 or -1
+ * usb_tx_block - transfer the data to the device
+ * @cardp: pointer to &struct if_usb_card
+ * @payload: pointer to payload data
+ * @nb: data length
+ * returns: 0 for success or negative error code
*/
static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb)
{
@@ -521,7 +454,7 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
int ret = -1;
if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
- lbs_pr_err("No free skb\n");
+ pr_err("No free skb\n");
goto rx_ret;
}
@@ -580,7 +513,7 @@ static void if_usb_receive_fwload(struct urb *urb)
if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) &&
tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) {
- lbs_pr_info("Firmware ready event received\n");
+ pr_info("Firmware ready event received\n");
wake_up(&cardp->fw_wq);
} else {
lbs_deb_usb("Waiting for confirmation; got %x %x\n",
@@ -607,20 +540,20 @@ static void if_usb_receive_fwload(struct urb *urb)
bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) {
if (!cardp->bootcmdresp)
- lbs_pr_info("Firmware already seems alive; resetting\n");
+ pr_info("Firmware already seems alive; resetting\n");
cardp->bootcmdresp = -1;
} else {
- lbs_pr_info("boot cmd response wrong magic number (0x%x)\n",
+ pr_info("boot cmd response wrong magic number (0x%x)\n",
le32_to_cpu(bootcmdresp.magic));
}
} else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) &&
(bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) &&
(bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) {
- lbs_pr_info("boot cmd response cmd_tag error (%d)\n",
- bootcmdresp.cmd);
+ pr_info("boot cmd response cmd_tag error (%d)\n",
+ bootcmdresp.cmd);
} else if (bootcmdresp.result != BOOT_CMD_RESP_OK) {
- lbs_pr_info("boot cmd response result error (%d)\n",
- bootcmdresp.result);
+ pr_info("boot cmd response result error (%d)\n",
+ bootcmdresp.result);
} else {
cardp->bootcmdresp = 1;
lbs_deb_usbd(&cardp->udev->dev,
@@ -720,11 +653,11 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
}
/**
- * @brief This function reads of the packet into the upload buff,
- * wake up the main thread and initialise the Rx callack.
+ * if_usb_receive - read the packet into the upload buffer,
+ * wake up the main thread and initialise the Rx callack
*
- * @param urb pointer to struct urb
- * @return N/A
+ * @urb: pointer to &struct urb
+ * returns: N/A
*/
static void if_usb_receive(struct urb *urb)
{
@@ -795,12 +728,12 @@ rx_exit:
}
/**
- * @brief This function downloads data to FW
- * @param priv pointer to struct lbs_private structure
- * @param type type of data
- * @param buf pointer to data buffer
- * @param len number of bytes
- * @return 0 or -1
+ * if_usb_host_to_card - downloads data to FW
+ * @priv: pointer to &struct lbs_private structure
+ * @type: type of data
+ * @payload: pointer to data buffer
+ * @nb: number of bytes
+ * returns: 0 for success or negative error code
*/
static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
uint8_t *payload, uint16_t nb)
@@ -824,10 +757,11 @@ static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
}
/**
- * @brief This function issues Boot command to the Boot2 code
- * @param ivalue 1:Boot from FW by USB-Download
- * 2:Boot from FW in EEPROM
- * @return 0
+ * if_usb_issue_boot_command - issues Boot command to the Boot2 code
+ * @cardp: pointer to &if_usb_card
+ * @ivalue: 1:Boot from FW by USB-Download
+ * 2:Boot from FW in EEPROM
+ * returns: 0 for success or negative error code
*/
static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
{
@@ -846,11 +780,11 @@ static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
/**
- * @brief This function checks the validity of Boot2/FW image.
+ * check_fwfile_format - check the validity of Boot2/FW image
*
- * @param data pointer to image
- * len image length
- * @return 0 or -1
+ * @data: pointer to image
+ * @totlen: image length
+ * returns: 0 (good) or 1 (failure)
*/
static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
{
@@ -885,110 +819,32 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
} while (!exit);
if (ret)
- lbs_pr_err("firmware file format check FAIL\n");
+ pr_err("firmware file format check FAIL\n");
else
lbs_deb_fw("firmware file format check PASS\n");
return ret;
}
-
-/**
-* @brief This function programs the firmware subject to cmd
-*
-* @param cardp the if_usb_card descriptor
-* fwname firmware or boot2 image file name
-* cmd either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW,
-* or BOOT_CMD_UPDATE_BOOT2.
-* @return 0 or error code
-*/
-static int if_usb_prog_firmware(struct if_usb_card *cardp,
- const char *fwname, int cmd)
-{
- struct lbs_private *priv = cardp->priv;
- unsigned long flags, caps;
- int ret;
-
- caps = priv->fwcapinfo;
- if (((cmd == BOOT_CMD_UPDATE_FW) && !(caps & FW_CAPINFO_FIRMWARE_UPGRADE)) ||
- ((cmd == BOOT_CMD_UPDATE_BOOT2) && !(caps & FW_CAPINFO_BOOT2_UPGRADE)))
- return -EOPNOTSUPP;
-
- /* Ensure main thread is idle. */
- spin_lock_irqsave(&priv->driver_lock, flags);
- while (priv->cur_cmd != NULL || priv->dnld_sent != DNLD_RES_RECEIVED) {
- spin_unlock_irqrestore(&priv->driver_lock, flags);
- if (wait_event_interruptible(priv->waitq,
- (priv->cur_cmd == NULL &&
- priv->dnld_sent == DNLD_RES_RECEIVED))) {
- return -ERESTARTSYS;
- }
- spin_lock_irqsave(&priv->driver_lock, flags);
- }
- priv->dnld_sent = DNLD_BOOTCMD_SENT;
- spin_unlock_irqrestore(&priv->driver_lock, flags);
-
- ret = __if_usb_prog_firmware(cardp, fwname, cmd);
-
- spin_lock_irqsave(&priv->driver_lock, flags);
- priv->dnld_sent = DNLD_RES_RECEIVED;
- spin_unlock_irqrestore(&priv->driver_lock, flags);
-
- wake_up_interruptible(&priv->waitq);
-
- return ret;
-}
-
-/* table of firmware file names */
-static const struct {
- u32 model;
- const char *fwname;
-} fw_table[] = {
- { MODEL_8388, "libertas/usb8388_v9.bin" },
- { MODEL_8388, "libertas/usb8388_v5.bin" },
- { MODEL_8388, "libertas/usb8388.bin" },
- { MODEL_8388, "usb8388.bin" },
- { MODEL_8682, "libertas/usb8682.bin" }
-};
-
-static int get_fw(struct if_usb_card *cardp, const char *fwname)
-{
- int i;
-
- /* Try user-specified firmware first */
- if (fwname)
- return request_firmware(&cardp->fw, fwname, &cardp->udev->dev);
-
- /* Otherwise search for firmware to use */
- for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
- if (fw_table[i].model != cardp->model)
- continue;
- if (request_firmware(&cardp->fw, fw_table[i].fwname,
- &cardp->udev->dev) == 0)
- return 0;
- }
-
- return -ENOENT;
-}
-
-static int __if_usb_prog_firmware(struct if_usb_card *cardp,
- const char *fwname, int cmd)
+static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
+ const struct firmware *fw,
+ const struct firmware *unused)
{
+ struct if_usb_card *cardp = priv->card;
int i = 0;
static int reset_count = 10;
- int ret = 0;
lbs_deb_enter(LBS_DEB_USB);
- ret = get_fw(cardp, fwname);
if (ret) {
- lbs_pr_err("failed to find firmware (%d)\n", ret);
+ pr_err("failed to find firmware (%d)\n", ret);
goto done;
}
+ cardp->fw = fw;
if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) {
ret = -EINVAL;
- goto release_fw;
+ goto done;
}
/* Cancel any pending usb business */
@@ -1005,14 +861,14 @@ restart:
if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
ret = -EIO;
- goto release_fw;
+ goto done;
}
cardp->bootcmdresp = 0;
do {
int j = 0;
i++;
- if_usb_issue_boot_command(cardp, cmd);
+ if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB);
/* wait for command response */
do {
j++;
@@ -1027,14 +883,14 @@ restart:
usb_kill_urb(cardp->tx_urb);
if (if_usb_submit_rx_urb(cardp) < 0)
ret = -EIO;
- goto release_fw;
+ goto done;
} else if (cardp->bootcmdresp <= 0) {
if (--reset_count >= 0) {
if_usb_reset_device(cardp);
goto restart;
}
ret = -EIO;
- goto release_fw;
+ goto done;
}
i = 0;
@@ -1057,24 +913,35 @@ restart:
usb_kill_urb(cardp->rx_urb);
if (!cardp->fwdnldover) {
- lbs_pr_info("failed to load fw, resetting device!\n");
+ pr_info("failed to load fw, resetting device!\n");
if (--reset_count >= 0) {
if_usb_reset_device(cardp);
goto restart;
}
- lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
+ pr_info("FW download failure, time = %d ms\n", i * 100);
ret = -EIO;
- goto release_fw;
+ goto done;
}
- release_fw:
- release_firmware(cardp->fw);
- cardp->fw = NULL;
+ cardp->priv->fw_ready = 1;
+ if_usb_submit_rx_urb(cardp);
+
+ if (lbs_start_card(priv))
+ goto done;
+
+ if_usb_setup_firmware(priv);
+
+ /*
+ * EHS_REMOVE_WAKEUP is not supported on all versions of the firmware.
+ */
+ priv->wol_criteria = EHS_REMOVE_WAKEUP;
+ if (lbs_host_sleep_cfg(priv, priv->wol_criteria, NULL))
+ priv->ehs_remove_supported = false;
done:
- lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
- return ret;
+ cardp->fw = NULL;
+ lbs_deb_leave(LBS_DEB_USB);
}
@@ -1087,14 +954,19 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
lbs_deb_enter(LBS_DEB_USB);
- if (priv->psstate != PS_STATE_FULL_POWER)
- return -1;
+ if (priv->psstate != PS_STATE_FULL_POWER) {
+ ret = -1;
+ goto out;
+ }
- if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
- lbs_pr_info("Suspend attempt without "
- "configuring wake params!\n");
- return -ENOSYS;
+#ifdef CONFIG_OLPC
+ if (machine_is_olpc()) {
+ if (priv->wol_criteria == EHS_REMOVE_WAKEUP)
+ olpc_ec_wakeup_clear(EC_SCI_SRC_WLAN);
+ else
+ olpc_ec_wakeup_set(EC_SCI_SRC_WLAN);
}
+#endif
ret = lbs_suspend(priv);
if (ret)
@@ -1136,31 +1008,10 @@ static struct usb_driver if_usb_driver = {
.suspend = if_usb_suspend,
.resume = if_usb_resume,
.reset_resume = if_usb_resume,
+ .disable_hub_initiated_lpm = 1,
};
-static int __init if_usb_init_module(void)
-{
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_MAIN);
-
- ret = usb_register(&if_usb_driver);
-
- lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
- return ret;
-}
-
-static void __exit if_usb_exit_module(void)
-{
- lbs_deb_enter(LBS_DEB_MAIN);
-
- usb_deregister(&if_usb_driver);
-
- lbs_deb_leave(LBS_DEB_MAIN);
-}
-
-module_init(if_usb_init_module);
-module_exit(if_usb_exit_module);
+module_usb_driver(if_usb_driver);
MODULE_DESCRIPTION("8388 USB WLAN Driver");
MODULE_AUTHOR("Marvell International Ltd. and Red Hat, Inc.");
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
index d819e7e3c9a..6e42eac331d 100644
--- a/drivers/net/wireless/libertas/if_usb.h
+++ b/drivers/net/wireless/libertas/if_usb.h
@@ -6,9 +6,9 @@
struct lbs_private;
-/**
- * This file contains definition for USB interface.
- */
+/*
+ * This file contains definition for USB interface.
+ */
#define CMD_TYPE_REQUEST 0xF00DFACE
#define CMD_TYPE_DATA 0xBEADC0DE
#define CMD_TYPE_INDICATION 0xBEEFFACE
@@ -40,7 +40,7 @@ struct bootcmdresp
uint8_t pad[2];
};
-/** USB card description structure*/
+/* USB card description structure*/
struct if_usb_card {
struct usb_device *udev;
uint32_t model; /* MODEL_* */
@@ -77,7 +77,7 @@ struct if_usb_card {
__le16 boot2_version;
};
-/** fwheader */
+/* fwheader */
struct fwheader {
__le32 dnldcmd;
__le32 baseaddr;
@@ -86,14 +86,14 @@ struct fwheader {
};
#define FW_MAX_DATA_BLK_SIZE 600
-/** FWData */
+/* FWData */
struct fwdata {
struct fwheader hdr;
__le32 seqnum;
uint8_t data[0];
};
-/** fwsyncheader */
+/* fwsyncheader */
struct fwsyncheader {
__le32 cmd;
__le32 seqnum;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index fcd1bbfc632..0c02f0483d1 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -1,12 +1,15 @@
-/**
- * This file contains the major functions in WLAN
- * driver. It includes init, exit, open, close and main
- * thread etc..
- */
+/*
+ * This file contains the major functions in WLAN
+ * driver. It includes init, exit, open, close and main
+ * thread etc..
+ */
-#include <linux/moduleparam.h>
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
+#include <linux/hardirq.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/kthread.h>
@@ -20,6 +23,7 @@
#include "cfg.h"
#include "debugfs.h"
#include "cmd.h"
+#include "mesh.h"
#define DRIVER_RELEASE_VERSION "323.p0"
const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
@@ -34,19 +38,25 @@ unsigned int lbs_debug;
EXPORT_SYMBOL_GPL(lbs_debug);
module_param_named(libertas_debug, lbs_debug, int, 0644);
+unsigned int lbs_disablemesh;
+EXPORT_SYMBOL_GPL(lbs_disablemesh);
+module_param_named(libertas_disablemesh, lbs_disablemesh, int, 0644);
+
-/* This global structure is used to send the confirm_sleep command as
- * fast as possible down to the firmware. */
+/*
+ * This global structure is used to send the confirm_sleep command as
+ * fast as possible down to the firmware.
+ */
struct cmd_confirm_sleep confirm_sleep;
-/**
+/*
* the table to keep region code
*/
u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
{ 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
-/**
+/*
* FW rate table. FW refers to rates by their index in this table, not by the
* rate value itself. Values of 0x00 are
* reserved positions.
@@ -57,10 +67,10 @@ static u8 fw_data_rates[MAX_RATES] =
};
/**
- * @brief use index to get the data rate
+ * lbs_fw_index_to_data_rate - use index to get the data rate
*
- * @param idx The index of data rate
- * @return data rate or 0
+ * @idx: The index of data rate
+ * returns: data rate or 0
*/
u32 lbs_fw_index_to_data_rate(u8 idx)
{
@@ -70,10 +80,10 @@ u32 lbs_fw_index_to_data_rate(u8 idx)
}
/**
- * @brief use rate to get the index
+ * lbs_data_rate_to_fw_index - use rate to get the index
*
- * @param rate data rate
- * @return index or 0
+ * @rate: data rate
+ * returns: index or 0
*/
u8 lbs_data_rate_to_fw_index(u32 rate)
{
@@ -89,12 +99,81 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
return 0;
}
+int lbs_set_iface_type(struct lbs_private *priv, enum nl80211_iftype type)
+{
+ int ret = 0;
+
+ switch (type) {
+ case NL80211_IFTYPE_MONITOR:
+ ret = lbs_set_monitor_mode(priv, 1);
+ break;
+ case NL80211_IFTYPE_STATION:
+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
+ ret = lbs_set_monitor_mode(priv, 0);
+ if (!ret)
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1);
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
+ ret = lbs_set_monitor_mode(priv, 0);
+ if (!ret)
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2);
+ break;
+ default:
+ ret = -ENOTSUPP;
+ }
+ return ret;
+}
+
+int lbs_start_iface(struct lbs_private *priv)
+{
+ struct cmd_ds_802_11_mac_address cmd;
+ int ret;
+
+ if (priv->power_restore) {
+ ret = priv->power_restore(priv);
+ if (ret)
+ return ret;
+ }
+
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_SET);
+ memcpy(cmd.macadd, priv->current_addr, ETH_ALEN);
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd);
+ if (ret) {
+ lbs_deb_net("set MAC address failed\n");
+ goto err;
+ }
+
+ ret = lbs_set_iface_type(priv, priv->wdev->iftype);
+ if (ret) {
+ lbs_deb_net("set iface type failed\n");
+ goto err;
+ }
+
+ ret = lbs_set_11d_domain_info(priv);
+ if (ret) {
+ lbs_deb_net("set 11d domain info failed\n");
+ goto err;
+ }
+
+ lbs_update_channel(priv);
+
+ priv->iface_running = true;
+ return 0;
+
+err:
+ if (priv->power_save)
+ priv->power_save(priv);
+ return ret;
+}
/**
- * @brief This function opens the ethX interface
+ * lbs_dev_open - open the ethX interface
*
- * @param dev A pointer to net_device structure
- * @return 0 or -EBUSY if monitor mode active
+ * @dev: A pointer to &net_device structure
+ * returns: 0 or -EBUSY if monitor mode active
*/
static int lbs_dev_open(struct net_device *dev)
{
@@ -102,28 +181,70 @@ static int lbs_dev_open(struct net_device *dev)
int ret = 0;
lbs_deb_enter(LBS_DEB_NET);
+ if (!priv->iface_running) {
+ ret = lbs_start_iface(priv);
+ if (ret)
+ goto out;
+ }
spin_lock_irq(&priv->driver_lock);
- priv->stopping = false;
- if (priv->connect_status == LBS_CONNECTED)
- netif_carrier_on(dev);
- else
- netif_carrier_off(dev);
+ netif_carrier_off(dev);
if (!priv->tx_pending_len)
netif_wake_queue(dev);
spin_unlock_irq(&priv->driver_lock);
+
+out:
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
return ret;
}
+static bool lbs_command_queue_empty(struct lbs_private *priv)
+{
+ unsigned long flags;
+ bool ret;
+ spin_lock_irqsave(&priv->driver_lock, flags);
+ ret = priv->cur_cmd == NULL && list_empty(&priv->cmdpendingq);
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ return ret;
+}
+
+int lbs_stop_iface(struct lbs_private *priv)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+ spin_lock_irqsave(&priv->driver_lock, flags);
+ priv->iface_running = false;
+ kfree_skb(priv->currenttxskb);
+ priv->currenttxskb = NULL;
+ priv->tx_pending_len = 0;
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ cancel_work_sync(&priv->mcast_work);
+ del_timer_sync(&priv->tx_lockup_timer);
+
+ /* Disable command processing, and wait for all commands to complete */
+ lbs_deb_main("waiting for commands to complete\n");
+ wait_event(priv->waitq, lbs_command_queue_empty(priv));
+ lbs_deb_main("all commands completed\n");
+
+ if (priv->power_save)
+ ret = priv->power_save(priv);
+
+ lbs_deb_leave(LBS_DEB_MAIN);
+ return ret;
+}
+
/**
- * @brief This function closes the ethX interface
+ * lbs_eth_stop - close the ethX interface
*
- * @param dev A pointer to net_device structure
- * @return 0
+ * @dev: A pointer to &net_device structure
+ * returns: 0
*/
static int lbs_eth_stop(struct net_device *dev)
{
@@ -131,42 +252,25 @@ static int lbs_eth_stop(struct net_device *dev)
lbs_deb_enter(LBS_DEB_NET);
+ if (priv->connect_status == LBS_CONNECTED)
+ lbs_disconnect(priv, WLAN_REASON_DEAUTH_LEAVING);
+
spin_lock_irq(&priv->driver_lock);
- priv->stopping = true;
netif_stop_queue(dev);
spin_unlock_irq(&priv->driver_lock);
- schedule_work(&priv->mcast_work);
+ lbs_update_mcast(priv);
cancel_delayed_work_sync(&priv->scan_work);
- if (priv->scan_req) {
- cfg80211_scan_done(priv->scan_req, false);
- priv->scan_req = NULL;
- }
+ if (priv->scan_req)
+ lbs_scan_done(priv);
- lbs_deb_leave(LBS_DEB_NET);
- return 0;
-}
-
-static void lbs_tx_timeout(struct net_device *dev)
-{
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_TX);
-
- lbs_pr_err("tx watch dog timeout\n");
-
- dev->trans_start = jiffies; /* prevent tx timeout */
+ netif_carrier_off(priv->dev);
- if (priv->currenttxskb)
- lbs_send_tx_feedback(priv, 0);
+ if (!lbs_iface_active(priv))
+ lbs_stop_iface(priv);
- /* XX: Shouldn't we also call into the hw-specific driver
- to kick it somehow? */
- lbs_host_to_card_done(priv);
-
- /* FIXME: reset the card */
-
- lbs_deb_leave(LBS_DEB_TX);
+ lbs_deb_leave(LBS_DEB_NET);
+ return 0;
}
void lbs_host_to_card_done(struct lbs_private *priv)
@@ -176,13 +280,14 @@ void lbs_host_to_card_done(struct lbs_private *priv)
lbs_deb_enter(LBS_DEB_THREAD);
spin_lock_irqsave(&priv->driver_lock, flags);
+ del_timer(&priv->tx_lockup_timer);
priv->dnld_sent = DNLD_RES_RECEIVED;
/* Wake main thread if commands are pending */
if (!priv->cur_cmd || priv->tx_pending_len > 0) {
if (!priv->wakeup_dev_required)
- wake_up_interruptible(&priv->waitq);
+ wake_up(&priv->waitq);
}
spin_unlock_irqrestore(&priv->driver_lock, flags);
@@ -195,29 +300,24 @@ int lbs_set_mac_address(struct net_device *dev, void *addr)
int ret = 0;
struct lbs_private *priv = dev->ml_priv;
struct sockaddr *phwaddr = addr;
- struct cmd_ds_802_11_mac_address cmd;
lbs_deb_enter(LBS_DEB_NET);
+ /*
+ * Can only set MAC address when all interfaces are down, to be written
+ * to the hardware when one of them is brought up.
+ */
+ if (lbs_iface_active(priv))
+ return -EBUSY;
+
/* In case it was called from the mesh device */
dev = priv->dev;
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
- cmd.action = cpu_to_le16(CMD_ACT_SET);
- memcpy(cmd.macadd, phwaddr->sa_data, ETH_ALEN);
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd);
- if (ret) {
- lbs_deb_net("set MAC address failed\n");
- goto done;
- }
-
memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN);
memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
if (priv->mesh_dev)
memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
-done:
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
return ret;
}
@@ -271,18 +371,18 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
return i;
}
-static void lbs_set_mcast_worker(struct work_struct *work)
+void lbs_update_mcast(struct lbs_private *priv)
{
- struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
struct cmd_ds_mac_multicast_adr mcast_cmd;
- int dev_flags;
+ int dev_flags = 0;
int nr_addrs;
int old_mac_control = priv->mac_control;
lbs_deb_enter(LBS_DEB_NET);
- dev_flags = priv->dev->flags;
- if (priv->mesh_dev)
+ if (netif_running(priv->dev))
+ dev_flags |= priv->dev->flags;
+ if (priv->mesh_dev && netif_running(priv->mesh_dev))
dev_flags |= priv->mesh_dev->flags;
if (dev_flags & IFF_PROMISC) {
@@ -328,6 +428,12 @@ static void lbs_set_mcast_worker(struct work_struct *work)
lbs_deb_leave(LBS_DEB_NET);
}
+static void lbs_set_mcast_worker(struct work_struct *work)
+{
+ struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
+ lbs_update_mcast(priv);
+}
+
void lbs_set_multicast_list(struct net_device *dev)
{
struct lbs_private *priv = dev->ml_priv;
@@ -336,12 +442,12 @@ void lbs_set_multicast_list(struct net_device *dev)
}
/**
- * @brief This function handles the major jobs in the LBS driver.
+ * lbs_thread - handles the major jobs in the LBS driver.
* It handles all events generated by firmware, RX data received
* from firmware and TX data sent from kernel.
*
- * @param data A pointer to lbs_thread structure
- * @return 0
+ * @data: A pointer to &lbs_thread structure
+ * returns: 0
*/
static int lbs_thread(void *data)
{
@@ -462,10 +568,13 @@ static int lbs_thread(void *data)
if (priv->cmd_timed_out && priv->cur_cmd) {
struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
- lbs_pr_info("Timeout submitting command 0x%04x\n",
- le16_to_cpu(cmdnode->cmdbuf->command));
+ netdev_info(dev, "Timeout submitting command 0x%04x\n",
+ le16_to_cpu(cmdnode->cmdbuf->command));
lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
- if (priv->reset_card)
+
+ /* Reset card, but only when it isn't in the process
+ * of being shutdown anyway. */
+ if (!dev->dismantle && priv->reset_card)
priv->reset_card(priv);
}
priv->cmd_timed_out = 0;
@@ -490,8 +599,8 @@ static int lbs_thread(void *data)
* after firmware fixes it
*/
priv->psstate = PS_STATE_AWAKE;
- lbs_pr_alert("ignore PS_SleepConfirm in "
- "non-connected state\n");
+ netdev_alert(dev,
+ "ignore PS_SleepConfirm in non-connected state\n");
}
}
@@ -517,6 +626,9 @@ static int lbs_thread(void *data)
if (ret) {
lbs_deb_tx("host_to_card failed %d\n", ret);
priv->dnld_sent = DNLD_RES_RECEIVED;
+ } else {
+ mod_timer(&priv->tx_lockup_timer,
+ jiffies + (HZ * 5));
}
priv->tx_pending_len = 0;
if (!priv->currenttxskb) {
@@ -525,7 +637,7 @@ static int lbs_thread(void *data)
if (priv->connect_status == LBS_CONNECTED)
netif_wake_queue(priv->dev);
if (priv->mesh_dev &&
- lbs_mesh_connected(priv))
+ netif_running(priv->mesh_dev))
netif_wake_queue(priv->mesh_dev);
}
}
@@ -533,12 +645,52 @@ static int lbs_thread(void *data)
}
del_timer(&priv->command_timer);
+ del_timer(&priv->tx_lockup_timer);
del_timer(&priv->auto_deepsleep_timer);
lbs_deb_leave(LBS_DEB_THREAD);
return 0;
}
+/**
+ * lbs_setup_firmware - gets the HW spec from the firmware and sets
+ * some basic parameters
+ *
+ * @priv: A pointer to &struct lbs_private structure
+ * returns: 0 or -1
+ */
+static int lbs_setup_firmware(struct lbs_private *priv)
+{
+ int ret = -1;
+ s16 curlevel = 0, minlevel = 0, maxlevel = 0;
+
+ lbs_deb_enter(LBS_DEB_FW);
+
+ /* Read MAC address from firmware */
+ memset(priv->current_addr, 0xff, ETH_ALEN);
+ ret = lbs_update_hw_spec(priv);
+ if (ret)
+ goto done;
+
+ /* Read power levels if available */
+ ret = lbs_get_tx_power(priv, &curlevel, &minlevel, &maxlevel);
+ if (ret == 0) {
+ priv->txpower_cur = curlevel;
+ priv->txpower_min = minlevel;
+ priv->txpower_max = maxlevel;
+ }
+
+ /* Send cmd to FW to enable 11D function */
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1);
+ if (ret)
+ goto done;
+
+ ret = lbs_set_mac_control_sync(priv);
+done:
+ lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+ return ret;
+}
+
int lbs_suspend(struct lbs_private *priv)
{
int ret;
@@ -548,7 +700,8 @@ int lbs_suspend(struct lbs_private *priv)
if (priv->is_deep_sleep) {
ret = lbs_set_deep_sleep(priv, 0);
if (ret) {
- lbs_pr_err("deep sleep cancellation failed: %d\n", ret);
+ netdev_err(priv->dev,
+ "deep sleep cancellation failed: %d\n", ret);
return ret;
}
priv->deep_sleep_required = 1;
@@ -581,79 +734,84 @@ int lbs_resume(struct lbs_private *priv)
priv->deep_sleep_required = 0;
ret = lbs_set_deep_sleep(priv, 1);
if (ret)
- lbs_pr_err("deep sleep activation failed: %d\n", ret);
+ netdev_err(priv->dev,
+ "deep sleep activation failed: %d\n", ret);
}
+ if (priv->setup_fw_on_resume)
+ ret = lbs_setup_firmware(priv);
+
lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
return ret;
}
EXPORT_SYMBOL_GPL(lbs_resume);
/**
- * @brief This function gets the HW spec from the firmware and sets
- * some basic parameters.
+ * lbs_cmd_timeout_handler - handles the timeout of command sending.
+ * It will re-send the same command again.
*
- * @param priv A pointer to struct lbs_private structure
- * @return 0 or -1
+ * @data: &struct lbs_private pointer
*/
-static int lbs_setup_firmware(struct lbs_private *priv)
+static void lbs_cmd_timeout_handler(unsigned long data)
{
- int ret = -1;
- s16 curlevel = 0, minlevel = 0, maxlevel = 0;
+ struct lbs_private *priv = (struct lbs_private *)data;
+ unsigned long flags;
- lbs_deb_enter(LBS_DEB_FW);
+ lbs_deb_enter(LBS_DEB_CMD);
+ spin_lock_irqsave(&priv->driver_lock, flags);
- /* Read MAC address from firmware */
- memset(priv->current_addr, 0xff, ETH_ALEN);
- ret = lbs_update_hw_spec(priv);
- if (ret)
- goto done;
+ if (!priv->cur_cmd)
+ goto out;
- /* Read power levels if available */
- ret = lbs_get_tx_power(priv, &curlevel, &minlevel, &maxlevel);
- if (ret == 0) {
- priv->txpower_cur = curlevel;
- priv->txpower_min = minlevel;
- priv->txpower_max = maxlevel;
- }
+ netdev_info(priv->dev, "command 0x%04x timed out\n",
+ le16_to_cpu(priv->cur_cmd->cmdbuf->command));
- /* Send cmd to FW to enable 11D function */
- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1);
+ priv->cmd_timed_out = 1;
- lbs_set_mac_control(priv);
-done:
- lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
- return ret;
+ /*
+ * If the device didn't even acknowledge the command, reset the state
+ * so that we don't block all future commands due to this one timeout.
+ */
+ if (priv->dnld_sent == DNLD_CMD_SENT)
+ priv->dnld_sent = DNLD_RES_RECEIVED;
+
+ wake_up(&priv->waitq);
+out:
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ lbs_deb_leave(LBS_DEB_CMD);
}
/**
- * This function handles the timeout of command sending.
- * It will re-send the same command again.
+ * lbs_tx_lockup_handler - handles the timeout of the passing of TX frames
+ * to the hardware. This is known to frequently happen with SD8686 when
+ * waking up after a Wake-on-WLAN-triggered resume.
+ *
+ * @data: &struct lbs_private pointer
*/
-static void lbs_cmd_timeout_handler(unsigned long data)
+static void lbs_tx_lockup_handler(unsigned long data)
{
struct lbs_private *priv = (struct lbs_private *)data;
unsigned long flags;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_TX);
spin_lock_irqsave(&priv->driver_lock, flags);
- if (!priv->cur_cmd)
- goto out;
-
- lbs_pr_info("command 0x%04x timed out\n",
- le16_to_cpu(priv->cur_cmd->cmdbuf->command));
+ netdev_info(priv->dev, "TX lockup detected\n");
+ if (priv->reset_card)
+ priv->reset_card(priv);
- priv->cmd_timed_out = 1;
+ priv->dnld_sent = DNLD_RES_RECEIVED;
wake_up_interruptible(&priv->waitq);
-out:
+
spin_unlock_irqrestore(&priv->driver_lock, flags);
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_TX);
}
/**
- * This function put the device back to deep sleep mode when timer expires
- * and no activity (command, event, data etc.) is detected.
+ * auto_deepsleep_timer_fn - put the device back to deep sleep mode when
+ * timer expires and no activity (command, event, data etc.) is detected.
+ * @data: &struct lbs_private pointer
+ * returns: N/A
*/
static void auto_deepsleep_timer_fn(unsigned long data)
{
@@ -731,10 +889,13 @@ static int lbs_init_adapter(struct lbs_private *priv)
priv->is_host_sleep_configured = 0;
priv->is_host_sleep_activated = 0;
init_waitqueue_head(&priv->host_sleep_q);
+ init_waitqueue_head(&priv->fw_waitq);
mutex_init(&priv->lock);
setup_timer(&priv->command_timer, lbs_cmd_timeout_handler,
(unsigned long)priv);
+ setup_timer(&priv->tx_lockup_timer, lbs_tx_lockup_handler,
+ (unsigned long)priv);
setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
(unsigned long)priv);
@@ -745,7 +906,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
/* Allocate the command buffers */
if (lbs_allocate_cmd_buffer(priv)) {
- lbs_pr_err("Out of memory allocating command buffers\n");
+ pr_err("Out of memory allocating command buffers\n");
ret = -ENOMEM;
goto out;
}
@@ -755,7 +916,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
/* Create the event FIFO */
ret = kfifo_alloc(&priv->event_fifo, sizeof(u32) * 16, GFP_KERNEL);
if (ret) {
- lbs_pr_err("Out of memory allocating event FIFO buffer\n");
+ pr_err("Out of memory allocating event FIFO buffer\n");
goto out;
}
@@ -772,6 +933,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
lbs_free_cmd_buffer(priv);
kfifo_free(&priv->event_fifo);
del_timer(&priv->command_timer);
+ del_timer(&priv->tx_lockup_timer);
del_timer(&priv->auto_deepsleep_timer);
lbs_deb_leave(LBS_DEB_MAIN);
@@ -782,18 +944,18 @@ static const struct net_device_ops lbs_netdev_ops = {
.ndo_stop = lbs_eth_stop,
.ndo_start_xmit = lbs_hard_start_xmit,
.ndo_set_mac_address = lbs_set_mac_address,
- .ndo_tx_timeout = lbs_tx_timeout,
- .ndo_set_multicast_list = lbs_set_multicast_list,
+ .ndo_set_rx_mode = lbs_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
};
/**
- * @brief This function adds the card. it will probe the
+ * lbs_add_card - adds the card. It will probe the
* card, allocate the lbs_priv and initialize the device.
*
- * @param card A pointer to card
- * @return A pointer to struct lbs_private structure
+ * @card: A pointer to card
+ * @dmdev: A pointer to &struct device
+ * returns: A pointer to &struct lbs_private structure
*/
struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
{
@@ -806,7 +968,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
/* Allocate an Ethernet device and register it */
wdev = lbs_cfg_alloc(dmdev);
if (IS_ERR(wdev)) {
- lbs_pr_err("cfg80211 init failed\n");
+ pr_err("cfg80211 init failed\n");
goto done;
}
@@ -815,7 +977,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
priv->wdev = wdev;
if (lbs_init_adapter(priv)) {
- lbs_pr_err("failed to initialize adapter structure.\n");
+ pr_err("failed to initialize adapter structure\n");
goto err_wdev;
}
@@ -851,9 +1013,10 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
priv->work_thread = create_singlethread_workqueue("lbs_worker");
INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
- priv->wol_criteria = 0xffffffff;
+ priv->wol_criteria = EHS_REMOVE_WAKEUP;
priv->wol_gpio = 0xff;
priv->wol_gap = 20;
+ priv->ehs_remove_supported = true;
goto done;
@@ -882,11 +1045,11 @@ void lbs_remove_card(struct lbs_private *priv)
lbs_deb_enter(LBS_DEB_MAIN);
lbs_remove_mesh(priv);
- lbs_scan_deinit(priv);
- dev = priv->dev;
+ if (priv->wiphy_registered)
+ lbs_scan_deinit(priv);
- cancel_work_sync(&priv->mcast_work);
+ lbs_wait_for_firmware_load(priv);
/* worker thread destruction blocks on the in-flight command which
* should have been cleared already in lbs_stop_card().
@@ -945,18 +1108,22 @@ int lbs_start_card(struct lbs_private *priv)
if (ret)
goto done;
+ if (!lbs_disablemesh)
+ lbs_init_mesh(priv);
+ else
+ pr_info("%s: mesh disabled\n", dev->name);
+
if (lbs_cfg_register(priv)) {
- lbs_pr_err("cannot register device\n");
+ pr_err("cannot register device\n");
goto done;
}
- lbs_update_channel(priv);
-
- lbs_init_mesh(priv);
+ if (lbs_mesh_activated(priv))
+ lbs_start_mesh(priv);
lbs_debugfs_init_one(priv, dev);
- lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
+ netdev_info(dev, "Marvell WLAN 802.11 adapter\n");
ret = 0;
@@ -970,8 +1137,6 @@ EXPORT_SYMBOL_GPL(lbs_start_card);
void lbs_stop_card(struct lbs_private *priv)
{
struct net_device *dev;
- struct cmd_ctrl_node *cmdnode;
- unsigned long flags;
lbs_deb_enter(LBS_DEB_MAIN);
@@ -979,35 +1144,16 @@ void lbs_stop_card(struct lbs_private *priv)
goto out;
dev = priv->dev;
+ /* If the netdev isn't registered, it means that lbs_start_card() was
+ * never called so we have nothing to do here. */
+ if (dev->reg_state != NETREG_REGISTERED)
+ goto out;
+
netif_stop_queue(dev);
netif_carrier_off(dev);
lbs_debugfs_remove_one(priv);
lbs_deinit_mesh(priv);
-
- /* Delete the timeout of the currently processing command */
- del_timer_sync(&priv->command_timer);
- del_timer_sync(&priv->auto_deepsleep_timer);
-
- /* Flush pending command nodes */
- spin_lock_irqsave(&priv->driver_lock, flags);
- lbs_deb_main("clearing pending commands\n");
- list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
- cmdnode->result = -ENOENT;
- cmdnode->cmdwaitqwoken = 1;
- wake_up_interruptible(&cmdnode->cmdwait_q);
- }
-
- /* Flush the command the card is currently processing */
- if (priv->cur_cmd) {
- lbs_deb_main("clearing current command\n");
- priv->cur_cmd->result = -ENOENT;
- priv->cur_cmd->cmdwaitqwoken = 1;
- wake_up_interruptible(&priv->cur_cmd->cmdwait_q);
- }
- lbs_deb_main("done clearing commands\n");
- spin_unlock_irqrestore(&priv->driver_lock, flags);
-
unregister_netdev(dev);
out:
@@ -1028,7 +1174,7 @@ void lbs_queue_event(struct lbs_private *priv, u32 event)
kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32));
- wake_up_interruptible(&priv->waitq);
+ wake_up(&priv->waitq);
spin_unlock_irqrestore(&priv->driver_lock, flags);
lbs_deb_leave(LBS_DEB_THREAD);
@@ -1046,117 +1192,12 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
BUG_ON(resp_idx > 1);
priv->resp_idx = resp_idx;
- wake_up_interruptible(&priv->waitq);
+ wake_up(&priv->waitq);
lbs_deb_leave(LBS_DEB_THREAD);
}
EXPORT_SYMBOL_GPL(lbs_notify_command_response);
-/**
- * @brief Retrieves two-stage firmware
- *
- * @param dev A pointer to device structure
- * @param user_helper User-defined helper firmware file
- * @param user_mainfw User-defined main firmware file
- * @param card_model Bus-specific card model ID used to filter firmware table
- * elements
- * @param fw_table Table of firmware file names and device model numbers
- * terminated by an entry with a NULL helper name
- * @param helper On success, the helper firmware; caller must free
- * @param mainfw On success, the main firmware; caller must free
- *
- * @return 0 on success, non-zero on failure
- */
-int lbs_get_firmware(struct device *dev, const char *user_helper,
- const char *user_mainfw, u32 card_model,
- const struct lbs_fw_table *fw_table,
- const struct firmware **helper,
- const struct firmware **mainfw)
-{
- const struct lbs_fw_table *iter;
- int ret;
-
- BUG_ON(helper == NULL);
- BUG_ON(mainfw == NULL);
-
- /* Try user-specified firmware first */
- if (user_helper) {
- ret = request_firmware(helper, user_helper, dev);
- if (ret) {
- lbs_pr_err("couldn't find helper firmware %s",
- user_helper);
- goto fail;
- }
- }
- if (user_mainfw) {
- ret = request_firmware(mainfw, user_mainfw, dev);
- if (ret) {
- lbs_pr_err("couldn't find main firmware %s",
- user_mainfw);
- goto fail;
- }
- }
-
- if (*helper && *mainfw)
- return 0;
-
- /* Otherwise search for firmware to use. If neither the helper or
- * the main firmware were specified by the user, then we need to
- * make sure that found helper & main are from the same entry in
- * fw_table.
- */
- iter = fw_table;
- while (iter && iter->helper) {
- if (iter->model != card_model)
- goto next;
-
- if (*helper == NULL) {
- ret = request_firmware(helper, iter->helper, dev);
- if (ret)
- goto next;
-
- /* If the device has one-stage firmware (ie cf8305) and
- * we've got it then we don't need to bother with the
- * main firmware.
- */
- if (iter->fwname == NULL)
- return 0;
- }
-
- if (*mainfw == NULL) {
- ret = request_firmware(mainfw, iter->fwname, dev);
- if (ret && !user_helper) {
- /* Clear the helper if it wasn't user-specified
- * and the main firmware load failed, to ensure
- * we don't have mismatched firmware pairs.
- */
- release_firmware(*helper);
- *helper = NULL;
- }
- }
-
- if (*helper && *mainfw)
- return 0;
-
- next:
- iter++;
- }
-
- fail:
- /* Failed */
- if (*helper) {
- release_firmware(*helper);
- *helper = NULL;
- }
- if (*mainfw) {
- release_firmware(*mainfw);
- *mainfw = NULL;
- }
-
- return -ENOENT;
-}
-EXPORT_SYMBOL_GPL(lbs_get_firmware);
-
static int __init lbs_init_module(void)
{
lbs_deb_enter(LBS_DEB_MAIN);
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index acf3bf63ee3..6fef746345b 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -1,5 +1,8 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/delay.h>
#include <linux/etherdevice.h>
+#include <linux/hardirq.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
@@ -12,16 +15,144 @@
#include "cmd.h"
+static int lbs_add_mesh(struct lbs_private *priv);
+
+/***************************************************************************
+ * Mesh command handling
+ */
+
+static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
+ struct cmd_ds_mesh_access *cmd)
+{
+ int ret;
+
+ lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
+
+ cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
+ cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
+ cmd->hdr.result = 0;
+
+ cmd->action = cpu_to_le16(cmd_action);
+
+ ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return ret;
+}
+
+static int __lbs_mesh_config_send(struct lbs_private *priv,
+ struct cmd_ds_mesh_config *cmd,
+ uint16_t action, uint16_t type)
+{
+ int ret;
+ u16 command = CMD_MESH_CONFIG_OLD;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ /*
+ * Command id is 0xac for v10 FW along with mesh interface
+ * id in bits 14-13-12.
+ */
+ if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
+ command = CMD_MESH_CONFIG |
+ (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
+
+ cmd->hdr.command = cpu_to_le16(command);
+ cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
+ cmd->hdr.result = 0;
+
+ cmd->type = cpu_to_le16(type);
+ cmd->action = cpu_to_le16(action);
+
+ ret = lbs_cmd_with_response(priv, command, cmd);
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return ret;
+}
+
+static int lbs_mesh_config_send(struct lbs_private *priv,
+ struct cmd_ds_mesh_config *cmd,
+ uint16_t action, uint16_t type)
+{
+ int ret;
+
+ if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
+ return -EOPNOTSUPP;
+
+ ret = __lbs_mesh_config_send(priv, cmd, action, type);
+ return ret;
+}
+
+/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
+ * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
+ * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
+ * lbs_mesh_config_send.
+ */
+static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
+ uint16_t chan)
+{
+ struct cmd_ds_mesh_config cmd;
+ struct mrvl_meshie *ie;
+ DECLARE_SSID_BUF(ssid);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.channel = cpu_to_le16(chan);
+ ie = (struct mrvl_meshie *)cmd.data;
+
+ switch (action) {
+ case CMD_ACT_MESH_CONFIG_START:
+ ie->id = WLAN_EID_VENDOR_SPECIFIC;
+ ie->val.oui[0] = 0x00;
+ ie->val.oui[1] = 0x50;
+ ie->val.oui[2] = 0x43;
+ ie->val.type = MARVELL_MESH_IE_TYPE;
+ ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
+ ie->val.version = MARVELL_MESH_IE_VERSION;
+ ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
+ ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
+ ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
+ ie->val.mesh_id_len = priv->mesh_ssid_len;
+ memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
+ ie->len = sizeof(struct mrvl_meshie_val) -
+ IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
+ cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
+ break;
+ case CMD_ACT_MESH_CONFIG_STOP:
+ break;
+ default:
+ return -1;
+ }
+ lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
+ action, priv->mesh_tlv, chan,
+ print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
+
+ return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
+}
+
+int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
+{
+ priv->mesh_channel = channel;
+ return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
+}
+
+static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
+{
+ return priv->mesh_channel ?: 1;
+}
+
/***************************************************************************
* Mesh sysfs support
*/
-/**
+/*
* Attributes exported through sysfs
*/
/**
- * @brief Get function for sysfs attribute anycast_mask
+ * lbs_anycast_get - Get function for sysfs attribute anycast_mask
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t lbs_anycast_get(struct device *dev,
struct device_attribute *attr, char * buf)
@@ -40,7 +171,11 @@ static ssize_t lbs_anycast_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute anycast_mask
+ * lbs_anycast_set - Set function for sysfs attribute anycast_mask
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t lbs_anycast_set(struct device *dev,
struct device_attribute *attr, const char * buf, size_t count)
@@ -62,7 +197,10 @@ static ssize_t lbs_anycast_set(struct device *dev,
}
/**
- * @brief Get function for sysfs attribute prb_rsp_limit
+ * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -85,7 +223,11 @@ static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute prb_rsp_limit
+ * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
@@ -98,7 +240,7 @@ static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
memset(&mesh_access, 0, sizeof(mesh_access));
mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
- if (!strict_strtoul(buf, 10, &retry_limit))
+ if (!kstrtoul(buf, 10, &retry_limit))
return -ENOTSUPP;
if (retry_limit > 15)
return -ENOTSUPP;
@@ -114,7 +256,10 @@ static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
}
/**
- * Get function for sysfs attribute mesh
+ * lbs_mesh_get - Get function for sysfs attribute mesh
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t lbs_mesh_get(struct device *dev,
struct device_attribute *attr, char * buf)
@@ -124,24 +269,22 @@ static ssize_t lbs_mesh_get(struct device *dev,
}
/**
- * Set function for sysfs attribute mesh
+ * lbs_mesh_set - Set function for sysfs attribute mesh
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t lbs_mesh_set(struct device *dev,
struct device_attribute *attr, const char * buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
int enable;
- int ret, action = CMD_ACT_MESH_CONFIG_STOP;
sscanf(buf, "%x", &enable);
enable = !!enable;
if (enable == !!priv->mesh_dev)
return count;
- if (enable)
- action = CMD_ACT_MESH_CONFIG_START;
- ret = lbs_mesh_config(priv, action, priv->channel);
- if (ret)
- return ret;
if (enable)
lbs_add_mesh(priv);
@@ -151,19 +294,19 @@ static ssize_t lbs_mesh_set(struct device *dev,
return count;
}
-/**
+/*
* lbs_mesh attribute to be exported per ethX interface
* through sysfs (/sys/class/net/ethX/lbs_mesh)
*/
static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
-/**
+/*
* anycast_mask attribute to be exported per mshX interface
* through sysfs (/sys/class/net/mshX/anycast_mask)
*/
static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
-/**
+/*
* prb_rsp_limit attribute to be exported per mshX interface
* through sysfs (/sys/class/net/mshX/prb_rsp_limit)
*/
@@ -176,580 +319,11 @@ static struct attribute *lbs_mesh_sysfs_entries[] = {
NULL,
};
-static struct attribute_group lbs_mesh_attr_group = {
+static const struct attribute_group lbs_mesh_attr_group = {
.attrs = lbs_mesh_sysfs_entries,
};
-
-/***************************************************************************
- * Initializing and starting, stopping mesh
- */
-
-/*
- * Check mesh FW version and appropriately send the mesh start
- * command
- */
-int lbs_init_mesh(struct lbs_private *priv)
-{
- struct net_device *dev = priv->dev;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_MESH);
-
- priv->mesh_connect_status = LBS_DISCONNECTED;
-
- /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
- /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
- /* 5.110.22 have mesh command with 0xa3 command id */
- /* 10.0.0.p0 FW brings in mesh config command with different id */
- /* Check FW version MSB and initialize mesh_fw_ver */
- if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
- /* Enable mesh, if supported, and work out which TLV it uses.
- 0x100 + 291 is an unofficial value used in 5.110.20.pXX
- 0x100 + 37 is the official value used in 5.110.21.pXX
- but we check them in that order because 20.pXX doesn't
- give an error -- it just silently fails. */
-
- /* 5.110.20.pXX firmware will fail the command if the channel
- doesn't match the existing channel. But only if the TLV
- is correct. If the channel is wrong, _BOTH_ versions will
- give an error to 0x100+291, and allow 0x100+37 to succeed.
- It's just that 5.110.20.pXX will not have done anything
- useful */
-
- priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
- if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->channel)) {
- priv->mesh_tlv = TLV_TYPE_MESH_ID;
- if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->channel))
- priv->mesh_tlv = 0;
- }
- } else
- if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
- (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
- /* 10.0.0.pXX new firmwares should succeed with TLV
- * 0x100+37; Do not invoke command with old TLV.
- */
- priv->mesh_tlv = TLV_TYPE_MESH_ID;
- if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->channel))
- priv->mesh_tlv = 0;
- }
-
-
- if (priv->mesh_tlv) {
- sprintf(priv->mesh_ssid, "mesh");
- priv->mesh_ssid_len = 4;
-
- lbs_add_mesh(priv);
-
- if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
- lbs_pr_err("cannot register lbs_mesh attribute\n");
-
- ret = 1;
- }
-
- lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
- return ret;
-}
-
-
-int lbs_deinit_mesh(struct lbs_private *priv)
-{
- struct net_device *dev = priv->dev;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_MESH);
-
- if (priv->mesh_tlv) {
- device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
- ret = 1;
- }
-
- lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
- return ret;
-}
-
-
-/**
- * @brief This function closes the mshX interface
- *
- * @param dev A pointer to net_device structure
- * @return 0
- */
-static int lbs_mesh_stop(struct net_device *dev)
-{
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_MESH);
- spin_lock_irq(&priv->driver_lock);
-
- priv->mesh_open = 0;
- priv->mesh_connect_status = LBS_DISCONNECTED;
-
- netif_stop_queue(dev);
- netif_carrier_off(dev);
-
- spin_unlock_irq(&priv->driver_lock);
-
- schedule_work(&priv->mcast_work);
-
- lbs_deb_leave(LBS_DEB_MESH);
- return 0;
-}
-
-/**
- * @brief This function opens the mshX interface
- *
- * @param dev A pointer to net_device structure
- * @return 0 or -EBUSY if monitor mode active
- */
-static int lbs_mesh_dev_open(struct net_device *dev)
-{
- struct lbs_private *priv = dev->ml_priv;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_NET);
-
- spin_lock_irq(&priv->driver_lock);
-
- if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
- ret = -EBUSY;
- goto out;
- }
-
- priv->mesh_open = 1;
- priv->mesh_connect_status = LBS_CONNECTED;
- netif_carrier_on(dev);
-
- if (!priv->tx_pending_len)
- netif_wake_queue(dev);
- out:
-
- spin_unlock_irq(&priv->driver_lock);
- lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
- return ret;
-}
-
-static const struct net_device_ops mesh_netdev_ops = {
- .ndo_open = lbs_mesh_dev_open,
- .ndo_stop = lbs_mesh_stop,
- .ndo_start_xmit = lbs_hard_start_xmit,
- .ndo_set_mac_address = lbs_set_mac_address,
- .ndo_set_multicast_list = lbs_set_multicast_list,
-};
-
-/**
- * @brief This function adds mshX interface
- *
- * @param priv A pointer to the struct lbs_private structure
- * @return 0 if successful, -X otherwise
- */
-int lbs_add_mesh(struct lbs_private *priv)
-{
- struct net_device *mesh_dev = NULL;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_MESH);
-
- /* Allocate a virtual mesh device */
- mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
- if (!mesh_dev) {
- lbs_deb_mesh("init mshX device failed\n");
- ret = -ENOMEM;
- goto done;
- }
- mesh_dev->ml_priv = priv;
- priv->mesh_dev = mesh_dev;
-
- mesh_dev->netdev_ops = &mesh_netdev_ops;
- mesh_dev->ethtool_ops = &lbs_ethtool_ops;
- memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, ETH_ALEN);
-
- SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
-
- mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
- /* Register virtual mesh interface */
- ret = register_netdev(mesh_dev);
- if (ret) {
- lbs_pr_err("cannot register mshX virtual interface\n");
- goto err_free;
- }
-
- ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
- if (ret)
- goto err_unregister;
-
- lbs_persist_config_init(mesh_dev);
-
- /* Everything successful */
- ret = 0;
- goto done;
-
-err_unregister:
- unregister_netdev(mesh_dev);
-
-err_free:
- free_netdev(mesh_dev);
-
-done:
- lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
- return ret;
-}
-
-void lbs_remove_mesh(struct lbs_private *priv)
-{
- struct net_device *mesh_dev;
-
- mesh_dev = priv->mesh_dev;
- if (!mesh_dev)
- return;
-
- lbs_deb_enter(LBS_DEB_MESH);
- netif_stop_queue(mesh_dev);
- netif_carrier_off(mesh_dev);
- sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
- lbs_persist_config_remove(mesh_dev);
- unregister_netdev(mesh_dev);
- priv->mesh_dev = NULL;
- free_netdev(mesh_dev);
- lbs_deb_leave(LBS_DEB_MESH);
-}
-
-
-
-/***************************************************************************
- * Sending and receiving
- */
-struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
- struct net_device *dev, struct rxpd *rxpd)
-{
- if (priv->mesh_dev) {
- if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
- if (rxpd->rx_control & RxPD_MESH_FRAME)
- dev = priv->mesh_dev;
- } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
- if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
- dev = priv->mesh_dev;
- }
- }
- return dev;
-}
-
-
-void lbs_mesh_set_txpd(struct lbs_private *priv,
- struct net_device *dev, struct txpd *txpd)
-{
- if (dev == priv->mesh_dev) {
- if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
- txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
- else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
- txpd->u.bss.bss_num = MESH_IFACE_ID;
- }
-}
-
-
-/***************************************************************************
- * Mesh command handling
- */
-
-/**
- * @brief Add or delete Mesh Blinding Table entries
- *
- * @param priv A pointer to struct lbs_private structure
- * @param add TRUE to add the entry, FALSE to delete it
- * @param addr1 Destination address to blind or unblind
- *
- * @return 0 on success, error on failure
- */
-int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1)
-{
- struct cmd_ds_bt_access cmd;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- BUG_ON(addr1 == NULL);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
- memcpy(cmd.addr1, addr1, ETH_ALEN);
- if (add) {
- cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_ADD);
- lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr",
- addr1, ETH_ALEN);
- } else {
- cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_DEL);
- lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr",
- addr1, ETH_ALEN);
- }
-
- ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief Reset/clear the mesh blinding table
- *
- * @param priv A pointer to struct lbs_private structure
- *
- * @return 0 on success, error on failure
- */
-int lbs_mesh_bt_reset(struct lbs_private *priv)
-{
- struct cmd_ds_bt_access cmd;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
- cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_RESET);
-
- ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief Gets the inverted status of the mesh blinding table
- *
- * Normally the firmware "blinds" or ignores traffic from mesh nodes in the
- * table, but an inverted table allows *only* traffic from nodes listed in
- * the table.
- *
- * @param priv A pointer to struct lbs_private structure
- * @param invert On success, TRUE if the blinding table is inverted,
- * FALSE if it is not inverted
- *
- * @return 0 on success, error on failure
- */
-int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted)
-{
- struct cmd_ds_bt_access cmd;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- BUG_ON(inverted == NULL);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
- cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_GET_INVERT);
-
- ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
- if (ret == 0)
- *inverted = !!cmd.id;
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief Sets the inverted status of the mesh blinding table
- *
- * Normally the firmware "blinds" or ignores traffic from mesh nodes in the
- * table, but an inverted table allows *only* traffic from nodes listed in
- * the table.
- *
- * @param priv A pointer to struct lbs_private structure
- * @param invert TRUE to invert the blinding table (only traffic from
- * listed nodes allowed), FALSE to return it
- * to normal state (listed nodes ignored)
- *
- * @return 0 on success, error on failure
- */
-int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted)
-{
- struct cmd_ds_bt_access cmd;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
- cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_SET_INVERT);
- cmd.id = cpu_to_le32(!!inverted);
-
- ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief List an entry in the mesh blinding table
- *
- * @param priv A pointer to struct lbs_private structure
- * @param id The ID of the entry to list
- * @param addr1 MAC address associated with the table entry
- *
- * @return 0 on success, error on failure
- */
-int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1)
-{
- struct cmd_ds_bt_access cmd;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- BUG_ON(addr1 == NULL);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
- cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_SET_INVERT);
- cmd.id = cpu_to_le32(id);
-
- ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
- if (ret == 0)
- memcpy(addr1, cmd.addr1, sizeof(cmd.addr1));
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief Access the mesh forwarding table
- *
- * @param priv A pointer to struct lbs_private structure
- * @param cmd_action The forwarding table action to perform
- * @param cmd The pre-filled FWT_ACCESS command
- *
- * @return 0 on success and 'cmd' will be filled with the
- * firmware's response
- */
-int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action,
- struct cmd_ds_fwt_access *cmd)
-{
- int ret;
-
- lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
-
- cmd->hdr.command = cpu_to_le16(CMD_FWT_ACCESS);
- cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access));
- cmd->hdr.result = 0;
- cmd->action = cpu_to_le16(cmd_action);
-
- ret = lbs_cmd_with_response(priv, CMD_FWT_ACCESS, cmd);
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return 0;
-}
-
-int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
- struct cmd_ds_mesh_access *cmd)
-{
- int ret;
-
- lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
-
- cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
- cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
- cmd->hdr.result = 0;
-
- cmd->action = cpu_to_le16(cmd_action);
-
- ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return ret;
-}
-
-static int __lbs_mesh_config_send(struct lbs_private *priv,
- struct cmd_ds_mesh_config *cmd,
- uint16_t action, uint16_t type)
-{
- int ret;
- u16 command = CMD_MESH_CONFIG_OLD;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- /*
- * Command id is 0xac for v10 FW along with mesh interface
- * id in bits 14-13-12.
- */
- if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
- command = CMD_MESH_CONFIG |
- (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
-
- cmd->hdr.command = cpu_to_le16(command);
- cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
- cmd->hdr.result = 0;
-
- cmd->type = cpu_to_le16(type);
- cmd->action = cpu_to_le16(action);
-
- ret = lbs_cmd_with_response(priv, command, cmd);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return ret;
-}
-
-int lbs_mesh_config_send(struct lbs_private *priv,
- struct cmd_ds_mesh_config *cmd,
- uint16_t action, uint16_t type)
-{
- int ret;
-
- if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
- return -EOPNOTSUPP;
-
- ret = __lbs_mesh_config_send(priv, cmd, action, type);
- return ret;
-}
-
-/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
- * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
- * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
- * lbs_mesh_config_send.
- */
-int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
-{
- struct cmd_ds_mesh_config cmd;
- struct mrvl_meshie *ie;
- DECLARE_SSID_BUF(ssid);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.channel = cpu_to_le16(chan);
- ie = (struct mrvl_meshie *)cmd.data;
-
- switch (action) {
- case CMD_ACT_MESH_CONFIG_START:
- ie->id = WLAN_EID_GENERIC;
- ie->val.oui[0] = 0x00;
- ie->val.oui[1] = 0x50;
- ie->val.oui[2] = 0x43;
- ie->val.type = MARVELL_MESH_IE_TYPE;
- ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
- ie->val.version = MARVELL_MESH_IE_VERSION;
- ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
- ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
- ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
- ie->val.mesh_id_len = priv->mesh_ssid_len;
- memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
- ie->len = sizeof(struct mrvl_meshie_val) -
- IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
- cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
- break;
- case CMD_ACT_MESH_CONFIG_STOP:
- break;
- default:
- return -1;
- }
- lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
- action, priv->mesh_tlv, chan,
- print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
-
- return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
-}
-
-
-
/***************************************************************************
* Persistent configuration support
*/
@@ -774,7 +348,10 @@ static int mesh_get_default_parameters(struct device *dev,
}
/**
- * @brief Get function for sysfs attribute bootflag
+ * bootflag_get - Get function for sysfs attribute bootflag
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t bootflag_get(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -791,7 +368,11 @@ static ssize_t bootflag_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute bootflag
+ * bootflag_set - Set function for sysfs attribute bootflag
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -817,7 +398,10 @@ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
}
/**
- * @brief Get function for sysfs attribute boottime
+ * boottime_get - Get function for sysfs attribute boottime
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t boottime_get(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -834,7 +418,11 @@ static ssize_t boottime_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute boottime
+ * boottime_set - Set function for sysfs attribute boottime
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t boottime_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
@@ -869,7 +457,10 @@ static ssize_t boottime_set(struct device *dev,
}
/**
- * @brief Get function for sysfs attribute channel
+ * channel_get - Get function for sysfs attribute channel
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t channel_get(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -886,7 +477,11 @@ static ssize_t channel_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute channel
+ * channel_set - Set function for sysfs attribute channel
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -912,13 +507,15 @@ static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
}
/**
- * @brief Get function for sysfs attribute mesh_id
+ * mesh_id_get - Get function for sysfs attribute mesh_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct mrvl_mesh_defaults defs;
- int maxlen;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
@@ -927,21 +524,23 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
return ret;
if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
- lbs_pr_err("inconsistent mesh ID length");
+ dev_err(dev, "inconsistent mesh ID length\n");
defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
}
- /* SSID not null terminated: reserve room for \0 + \n */
- maxlen = defs.meshie.val.mesh_id_len + 2;
- maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE;
-
- defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0';
+ memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len);
+ buf[defs.meshie.val.mesh_id_len] = '\n';
+ buf[defs.meshie.val.mesh_id_len + 1] = '\0';
- return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id);
+ return defs.meshie.val.mesh_id_len + 1;
}
/**
- * @brief Set function for sysfs attribute mesh_id
+ * mesh_id_set - Set function for sysfs attribute mesh_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -983,7 +582,10 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
}
/**
- * @brief Get function for sysfs attribute protocol_id
+ * protocol_id_get - Get function for sysfs attribute protocol_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t protocol_id_get(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1000,7 +602,11 @@ static ssize_t protocol_id_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute protocol_id
+ * protocol_id_set - Set function for sysfs attribute protocol_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t protocol_id_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
@@ -1037,7 +643,10 @@ static ssize_t protocol_id_set(struct device *dev,
}
/**
- * @brief Get function for sysfs attribute metric_id
+ * metric_id_get - Get function for sysfs attribute metric_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t metric_id_get(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1054,7 +663,11 @@ static ssize_t metric_id_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute metric_id
+ * metric_id_set - Set function for sysfs attribute metric_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -1091,7 +704,10 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
}
/**
- * @brief Get function for sysfs attribute capability
+ * capability_get - Get function for sysfs attribute capability
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t capability_get(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1108,7 +724,11 @@ static ssize_t capability_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute capability
+ * capability_set - Set function for sysfs attribute capability
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -1160,7 +780,7 @@ static struct attribute *boot_opts_attrs[] = {
NULL
};
-static struct attribute_group boot_opts_group = {
+static const struct attribute_group boot_opts_group = {
.name = "boot_options",
.attrs = boot_opts_attrs,
};
@@ -1173,31 +793,323 @@ static struct attribute *mesh_ie_attrs[] = {
NULL
};
-static struct attribute_group mesh_ie_group = {
+static const struct attribute_group mesh_ie_group = {
.name = "mesh_ie",
.attrs = mesh_ie_attrs,
};
-void lbs_persist_config_init(struct net_device *dev)
+static void lbs_persist_config_init(struct net_device *dev)
{
int ret;
ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
}
-void lbs_persist_config_remove(struct net_device *dev)
+static void lbs_persist_config_remove(struct net_device *dev)
{
sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
}
+/***************************************************************************
+ * Initializing and starting, stopping mesh
+ */
+
+/*
+ * Check mesh FW version and appropriately send the mesh start
+ * command
+ */
+int lbs_init_mesh(struct lbs_private *priv)
+{
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_MESH);
+
+ /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
+ /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
+ /* 5.110.22 have mesh command with 0xa3 command id */
+ /* 10.0.0.p0 FW brings in mesh config command with different id */
+ /* Check FW version MSB and initialize mesh_fw_ver */
+ if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
+ /* Enable mesh, if supported, and work out which TLV it uses.
+ 0x100 + 291 is an unofficial value used in 5.110.20.pXX
+ 0x100 + 37 is the official value used in 5.110.21.pXX
+ but we check them in that order because 20.pXX doesn't
+ give an error -- it just silently fails. */
+
+ /* 5.110.20.pXX firmware will fail the command if the channel
+ doesn't match the existing channel. But only if the TLV
+ is correct. If the channel is wrong, _BOTH_ versions will
+ give an error to 0x100+291, and allow 0x100+37 to succeed.
+ It's just that 5.110.20.pXX will not have done anything
+ useful */
+
+ priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
+ if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
+ priv->mesh_tlv = TLV_TYPE_MESH_ID;
+ if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
+ priv->mesh_tlv = 0;
+ }
+ } else
+ if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
+ (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
+ /* 10.0.0.pXX new firmwares should succeed with TLV
+ * 0x100+37; Do not invoke command with old TLV.
+ */
+ priv->mesh_tlv = TLV_TYPE_MESH_ID;
+ if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
+ priv->mesh_tlv = 0;
+ }
+
+ /* Stop meshing until interface is brought up */
+ lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
+
+ if (priv->mesh_tlv) {
+ sprintf(priv->mesh_ssid, "mesh");
+ priv->mesh_ssid_len = 4;
+ ret = 1;
+ }
+
+ lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
+ return ret;
+}
+
+void lbs_start_mesh(struct lbs_private *priv)
+{
+ lbs_add_mesh(priv);
+
+ if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
+ netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
+}
+
+int lbs_deinit_mesh(struct lbs_private *priv)
+{
+ struct net_device *dev = priv->dev;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_MESH);
+
+ if (priv->mesh_tlv) {
+ device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
+ ret = 1;
+ }
+
+ lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
+ return ret;
+}
+
+
+/**
+ * lbs_mesh_stop - close the mshX interface
+ *
+ * @dev: A pointer to &net_device structure
+ * returns: 0
+ */
+static int lbs_mesh_stop(struct net_device *dev)
+{
+ struct lbs_private *priv = dev->ml_priv;
+
+ lbs_deb_enter(LBS_DEB_MESH);
+ lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
+ lbs_mesh_get_channel(priv));
+
+ spin_lock_irq(&priv->driver_lock);
+
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+
+ spin_unlock_irq(&priv->driver_lock);
+
+ lbs_update_mcast(priv);
+ if (!lbs_iface_active(priv))
+ lbs_stop_iface(priv);
+
+ lbs_deb_leave(LBS_DEB_MESH);
+ return 0;
+}
+
+/**
+ * lbs_mesh_dev_open - open the mshX interface
+ *
+ * @dev: A pointer to &net_device structure
+ * returns: 0 or -EBUSY if monitor mode active
+ */
+static int lbs_mesh_dev_open(struct net_device *dev)
+{
+ struct lbs_private *priv = dev->ml_priv;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_NET);
+ if (!priv->iface_running) {
+ ret = lbs_start_iface(priv);
+ if (ret)
+ goto out;
+ }
+
+ spin_lock_irq(&priv->driver_lock);
+
+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
+ ret = -EBUSY;
+ spin_unlock_irq(&priv->driver_lock);
+ goto out;
+ }
+
+ netif_carrier_on(dev);
+
+ if (!priv->tx_pending_len)
+ netif_wake_queue(dev);
+
+ spin_unlock_irq(&priv->driver_lock);
+
+ ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+ lbs_mesh_get_channel(priv));
+
+out:
+ lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
+ return ret;
+}
+
+static const struct net_device_ops mesh_netdev_ops = {
+ .ndo_open = lbs_mesh_dev_open,
+ .ndo_stop = lbs_mesh_stop,
+ .ndo_start_xmit = lbs_hard_start_xmit,
+ .ndo_set_mac_address = lbs_set_mac_address,
+ .ndo_set_rx_mode = lbs_set_multicast_list,
+};
+
+/**
+ * lbs_add_mesh - add mshX interface
+ *
+ * @priv: A pointer to the &struct lbs_private structure
+ * returns: 0 if successful, -X otherwise
+ */
+static int lbs_add_mesh(struct lbs_private *priv)
+{
+ struct net_device *mesh_dev = NULL;
+ struct wireless_dev *mesh_wdev;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_MESH);
+
+ /* Allocate a virtual mesh device */
+ mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ if (!mesh_wdev) {
+ lbs_deb_mesh("init mshX wireless device failed\n");
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
+ if (!mesh_dev) {
+ lbs_deb_mesh("init mshX device failed\n");
+ ret = -ENOMEM;
+ goto err_free_wdev;
+ }
+
+ mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
+ mesh_wdev->wiphy = priv->wdev->wiphy;
+ mesh_wdev->netdev = mesh_dev;
+
+ mesh_dev->ml_priv = priv;
+ mesh_dev->ieee80211_ptr = mesh_wdev;
+ priv->mesh_dev = mesh_dev;
+
+ mesh_dev->netdev_ops = &mesh_netdev_ops;
+ mesh_dev->ethtool_ops = &lbs_ethtool_ops;
+ eth_hw_addr_inherit(mesh_dev, priv->dev);
+
+ SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
+
+ mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+ /* Register virtual mesh interface */
+ ret = register_netdev(mesh_dev);
+ if (ret) {
+ pr_err("cannot register mshX virtual interface\n");
+ goto err_free_netdev;
+ }
+
+ ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
+ if (ret)
+ goto err_unregister;
+
+ lbs_persist_config_init(mesh_dev);
+
+ /* Everything successful */
+ ret = 0;
+ goto done;
+
+err_unregister:
+ unregister_netdev(mesh_dev);
+
+err_free_netdev:
+ free_netdev(mesh_dev);
+
+err_free_wdev:
+ kfree(mesh_wdev);
+
+done:
+ lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
+ return ret;
+}
+
+void lbs_remove_mesh(struct lbs_private *priv)
+{
+ struct net_device *mesh_dev;
+
+ mesh_dev = priv->mesh_dev;
+ if (!mesh_dev)
+ return;
+
+ lbs_deb_enter(LBS_DEB_MESH);
+ netif_stop_queue(mesh_dev);
+ netif_carrier_off(mesh_dev);
+ sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
+ lbs_persist_config_remove(mesh_dev);
+ unregister_netdev(mesh_dev);
+ priv->mesh_dev = NULL;
+ kfree(mesh_dev->ieee80211_ptr);
+ free_netdev(mesh_dev);
+ lbs_deb_leave(LBS_DEB_MESH);
+}
+
+
+/***************************************************************************
+ * Sending and receiving
+ */
+struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
+ struct net_device *dev, struct rxpd *rxpd)
+{
+ if (priv->mesh_dev) {
+ if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
+ if (rxpd->rx_control & RxPD_MESH_FRAME)
+ dev = priv->mesh_dev;
+ } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
+ if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
+ dev = priv->mesh_dev;
+ }
+ }
+ return dev;
+}
+
+
+void lbs_mesh_set_txpd(struct lbs_private *priv,
+ struct net_device *dev, struct txpd *txpd)
+{
+ if (dev == priv->mesh_dev) {
+ if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
+ txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
+ else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
+ txpd->u.bss.bss_num = MESH_IFACE_ID;
+ }
+}
+
/***************************************************************************
* Ethtool related
*/
-static const char *mesh_stat_strings[] = {
+static const char * const mesh_stat_strings[] = {
"drop_duplicate_bcast",
"drop_ttl_zero",
"drop_no_fwd_route",
diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h
index afb2e8dead3..6603f341c87 100644
--- a/drivers/net/wireless/libertas/mesh.h
+++ b/drivers/net/wireless/libertas/mesh.h
@@ -1,6 +1,6 @@
-/**
- * Contains all definitions needed for the Libertas' MESH implementation.
- */
+/*
+ * Contains all definitions needed for the Libertas' MESH implementation.
+ */
#ifndef _LBS_MESH_H_
#define _LBS_MESH_H_
@@ -9,31 +9,25 @@
#include <net/lib80211.h>
#include "host.h"
+#include "dev.h"
#ifdef CONFIG_LIBERTAS_MESH
-/* Mesh statistics */
-struct lbs_mesh_stats {
- u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
- u32 fwd_unicast_cnt; /* Fwd: Unicast counter */
- u32 fwd_drop_ttl; /* Fwd: TTL zero */
- u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */
- u32 fwd_drop_noroute; /* Fwd: No route to Destination */
- u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */
- u32 drop_blind; /* Rx: Dropped by blinding table */
- u32 tx_failed_cnt; /* Tx: Failed transmissions */
-};
-
-
struct net_device;
-struct lbs_private;
int lbs_init_mesh(struct lbs_private *priv);
+void lbs_start_mesh(struct lbs_private *priv);
int lbs_deinit_mesh(struct lbs_private *priv);
-int lbs_add_mesh(struct lbs_private *priv);
void lbs_remove_mesh(struct lbs_private *priv);
+static inline bool lbs_mesh_activated(struct lbs_private *priv)
+{
+ /* Mesh SSID is only programmed after successful init */
+ return priv->mesh_ssid_len != 0;
+}
+
+int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel);
/* Sending / Receiving */
@@ -52,29 +46,6 @@ struct cmd_ds_command;
struct cmd_ds_mesh_access;
struct cmd_ds_mesh_config;
-int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1);
-int lbs_mesh_bt_reset(struct lbs_private *priv);
-int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted);
-int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted);
-int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1);
-
-int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action,
- struct cmd_ds_fwt_access *cmd);
-
-int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
- struct cmd_ds_mesh_access *cmd);
-int lbs_mesh_config_send(struct lbs_private *priv,
- struct cmd_ds_mesh_config *cmd,
- uint16_t action, uint16_t type);
-int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
-
-
-
-/* Persistent configuration */
-
-void lbs_persist_config_init(struct net_device *net);
-void lbs_persist_config_remove(struct net_device *net);
-
/* Ethtool statistics */
@@ -87,22 +58,17 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev,
uint32_t stringset, uint8_t *s);
-/* Accessors */
-
-#define lbs_mesh_open(priv) (priv->mesh_open)
-#define lbs_mesh_connected(priv) (priv->mesh_connect_status == LBS_CONNECTED)
-
#else
#define lbs_init_mesh(priv)
#define lbs_deinit_mesh(priv)
+#define lbs_start_mesh(priv)
#define lbs_add_mesh(priv)
#define lbs_remove_mesh(priv)
#define lbs_mesh_set_dev(priv, dev, rxpd) (dev)
#define lbs_mesh_set_txpd(priv, dev, txpd)
-#define lbs_mesh_config(priv, enable, chan)
-#define lbs_mesh_open(priv) (0)
-#define lbs_mesh_connected(priv) (0)
+#define lbs_mesh_set_channel(priv, channel) (0)
+#define lbs_mesh_activated(priv) (false)
#endif
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index a4d0bca9ef2..e446fed7b34 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -1,9 +1,14 @@
-/**
- * This file contains the handling of RX in wlan driver.
- */
+/*
+ * This file contains the handling of RX in wlan driver.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/etherdevice.h>
+#include <linux/hardirq.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/export.h>
#include <net/cfg80211.h>
#include "defs.h"
@@ -11,6 +16,7 @@
#include "radiotap.h"
#include "decl.h"
#include "dev.h"
+#include "mesh.h"
struct eth803hdr {
u8 dest_addr[6];
@@ -40,12 +46,12 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
struct sk_buff *skb);
/**
- * @brief This function processes received packet and forwards it
- * to kernel/upper layer
+ * lbs_process_rxed_packet - processes received packet and forwards it
+ * to kernel/upper layer
*
- * @param priv A pointer to struct lbs_private
- * @param skb A pointer to skb which includes the received packet
- * @return 0 or -1
+ * @priv: A pointer to &struct lbs_private
+ * @skb: A pointer to skb which includes the received packet
+ * returns: 0 or -1
*/
int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
{
@@ -55,7 +61,9 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
struct rxpd *p_rx_pd;
int hdrchop;
struct ethhdr *p_ethhdr;
- const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+ static const u8 rfc1042_eth_hdr[] = {
+ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00
+ };
lbs_deb_enter(LBS_DEB_RX);
@@ -63,8 +71,10 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
skb->ip_summed = CHECKSUM_NONE;
- if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
- return process_rxed_802_11_packet(priv, skb);
+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
+ ret = process_rxed_802_11_packet(priv, skb);
+ goto done;
+ }
p_rx_pd = (struct rxpd *) skb->data;
p_rx_pkt = (struct rxpackethdr *) ((u8 *)p_rx_pd +
@@ -78,7 +88,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
lbs_deb_rx("rx err: frame received with bad length\n");
dev->stats.rx_length_errors++;
- ret = 0;
+ ret = -EINVAL;
dev_kfree_skb(skb);
goto done;
}
@@ -154,11 +164,11 @@ done:
EXPORT_SYMBOL_GPL(lbs_process_rxed_packet);
/**
- * @brief This function converts Tx/Rx rates from the Marvell WLAN format
- * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
+ * convert_mv_rate_to_radiotap - converts Tx/Rx rates from Marvell WLAN format
+ * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
*
- * @param rate Input rate
- * @return Output Rate (0 if invalid)
+ * @rate: Input rate
+ * returns: Output Rate (0 if invalid)
*/
static u8 convert_mv_rate_to_radiotap(u8 rate)
{
@@ -189,17 +199,17 @@ static u8 convert_mv_rate_to_radiotap(u8 rate)
case 12: /* 54 Mbps */
return 108;
}
- lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate);
+ pr_alert("Invalid Marvell WLAN rate %i\n", rate);
return 0;
}
/**
- * @brief This function processes a received 802.11 packet and forwards it
- * to kernel/upper layer
+ * process_rxed_802_11_packet - processes a received 802.11 packet and forwards
+ * it to kernel/upper layer
*
- * @param priv A pointer to struct lbs_private
- * @param skb A pointer to skb which includes the received packet
- * @return 0 or -1
+ * @priv: A pointer to &struct lbs_private
+ * @skb: A pointer to skb which includes the received packet
+ * returns: 0 or -1
*/
static int process_rxed_802_11_packet(struct lbs_private *priv,
struct sk_buff *skb)
@@ -246,7 +256,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
/* add space for the new radio header */
if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) {
- lbs_pr_alert("%s: couldn't pskb_expand_head\n", __func__);
+ netdev_alert(dev, "%s: couldn't pskb_expand_head\n", __func__);
ret = -ENOMEM;
kfree_skb(skb);
goto done;
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index 8000ca6165d..c025f9c1828 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -1,9 +1,11 @@
-/**
- * This file contains the handling of TX in wlan driver.
- */
+/*
+ * This file contains the handling of TX in wlan driver.
+ */
+#include <linux/hardirq.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/sched.h>
+#include <linux/export.h>
#include <net/cfg80211.h>
#include "host.h"
@@ -11,13 +13,14 @@
#include "decl.h"
#include "defs.h"
#include "dev.h"
+#include "mesh.h"
/**
- * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
- * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
+ * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
+ * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
*
- * @param rate Input rate
- * @return Output Rate (0 if invalid)
+ * @rate: Input rate
+ * returns: Output Rate (0 if invalid)
*/
static u32 convert_radiotap_rate_to_mv(u8 rate)
{
@@ -51,12 +54,12 @@ static u32 convert_radiotap_rate_to_mv(u8 rate)
}
/**
- * @brief This function checks the conditions and sends packet to IF
- * layer if everything is ok.
+ * lbs_hard_start_xmit - checks the conditions and sends packet to IF
+ * layer if everything is ok
*
- * @param priv A pointer to struct lbs_private structure
- * @param skb A pointer to skb which includes TX packet
- * @return 0 or -1
+ * @skb: A pointer to skb which includes TX packet
+ * @dev: A pointer to the &struct net_device
+ * returns: 0 or -1
*/
netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -168,13 +171,13 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
/**
- * @brief This function sends to the host the last transmitted packet,
- * filling the radiotap headers with transmission information.
+ * lbs_send_tx_feedback - sends to the host the last transmitted packet,
+ * filling the radiotap headers with transmission information.
*
- * @param priv A pointer to struct lbs_private structure
- * @param status A 32 bit value containing transmission status.
+ * @priv: A pointer to &struct lbs_private structure
+ * @try_count: A 32-bit value containing transmission retry status.
*
- * @returns void
+ * returns: void
*/
void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
{
@@ -198,7 +201,7 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
if (priv->connect_status == LBS_CONNECTED)
netif_wake_queue(priv->dev);
- if (priv->mesh_dev && lbs_mesh_connected(priv))
+ if (priv->mesh_dev && netif_running(priv->mesh_dev))
netif_wake_queue(priv->mesh_dev);
}
EXPORT_SYMBOL_GPL(lbs_send_tx_feedback);
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index 462fbb4cb74..cf1d9b047ee 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -1,6 +1,6 @@
-/**
- * This header file contains definition for global types
- */
+/*
+ * This header file contains definition for global types
+ */
#ifndef _LBS_TYPES_H_
#define _LBS_TYPES_H_
@@ -54,7 +54,7 @@ union ieee_phy_param_set {
struct ieee_ie_ds_param_set ds;
} __packed;
-/** TLV type ID definition */
+/* TLV type ID definition */
#define PROPRIETARY_TLV_BASE_ID 0x0100
/* Terminating TLV type */
@@ -96,7 +96,7 @@ union ieee_phy_param_set {
#define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37)
#define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291)
-/** TLV related data structures*/
+/* TLV related data structures */
struct mrvl_ie_header {
__le16 type;
__le16 len;
@@ -177,7 +177,7 @@ struct mrvl_ie_auth_type {
__le16 auth;
} __packed;
-/** Local Power capability */
+/* Local Power capability */
struct mrvl_ie_power_capability {
struct mrvl_ie_header header;
s8 minpower;
@@ -235,9 +235,11 @@ struct mrvl_ie_ledbhv {
struct led_bhv ledbhv[1];
} __packed;
-/* Meant to be packed as the value member of a struct ieee80211_info_element.
+/*
+ * Meant to be packed as the value member of a struct ieee80211_info_element.
* Note that the len member of the ieee80211_info_element varies depending on
- * the mesh_id_len */
+ * the mesh_id_len
+ */
struct mrvl_meshie_val {
uint8_t oui[3];
uint8_t type;