summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/mwifiex
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/mwifiex')
-rw-r--r--drivers/net/wireless/mwifiex/11ac.c19
-rw-r--r--drivers/net/wireless/mwifiex/11ac.h17
-rw-r--r--drivers/net/wireless/mwifiex/Makefile1
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c225
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c2
-rw-r--r--drivers/net/wireless/mwifiex/ethtool.c70
-rw-r--r--drivers/net/wireless/mwifiex/fw.h83
-rw-r--r--drivers/net/wireless/mwifiex/init.c6
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h31
-rw-r--r--drivers/net/wireless/mwifiex/main.c15
-rw-r--r--drivers/net/wireless/mwifiex/main.h15
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c203
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c83
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c4
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c10
-rw-r--r--drivers/net/wireless/mwifiex/txrx.c2
-rw-r--r--drivers/net/wireless/mwifiex/uap_cmd.c55
-rw-r--r--drivers/net/wireless/mwifiex/util.c5
18 files changed, 647 insertions, 199 deletions
diff --git a/drivers/net/wireless/mwifiex/11ac.c b/drivers/net/wireless/mwifiex/11ac.c
index cf43b3c29250..de0a63469cb1 100644
--- a/drivers/net/wireless/mwifiex/11ac.c
+++ b/drivers/net/wireless/mwifiex/11ac.c
@@ -259,3 +259,22 @@ int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
return ret_len;
}
+
+int mwifiex_cmd_11ac_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, u16 cmd_action,
+ struct mwifiex_11ac_vht_cfg *cfg)
+{
+ struct host_cmd_11ac_vht_cfg *vhtcfg = &cmd->params.vht_cfg;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_11AC_CFG);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_11ac_vht_cfg) +
+ S_DS_GEN);
+ vhtcfg->action = cpu_to_le16(cmd_action);
+ vhtcfg->band_config = cfg->band_config;
+ vhtcfg->misc_config = cfg->misc_config;
+ vhtcfg->cap_info = cpu_to_le32(cfg->cap_info);
+ vhtcfg->mcs_tx_set = cpu_to_le32(cfg->mcs_tx_set);
+ vhtcfg->mcs_rx_set = cpu_to_le32(cfg->mcs_rx_set);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mwifiex/11ac.h b/drivers/net/wireless/mwifiex/11ac.h
index 80fd1ba46200..7c2c69b5b3eb 100644
--- a/drivers/net/wireless/mwifiex/11ac.h
+++ b/drivers/net/wireless/mwifiex/11ac.h
@@ -20,7 +20,24 @@
#ifndef _MWIFIEX_11AC_H_
#define _MWIFIEX_11AC_H_
+#define VHT_CFG_2GHZ BIT(0)
+#define VHT_CFG_5GHZ BIT(1)
+
+enum vht_cfg_misc_config {
+ VHT_CAP_TX_OPERATION = 1,
+ VHT_CAP_ASSOCIATION,
+ VHT_CAP_UAP_ONLY
+};
+
+#define DEFAULT_VHT_MCS_SET 0xfffa
+#define DISABLE_VHT_MCS_SET 0xffff
+
+#define VHT_BW_80_160_80P80 BIT(2)
+
int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc,
u8 **buffer);
+int mwifiex_cmd_11ac_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, u16 cmd_action,
+ struct mwifiex_11ac_vht_cfg *cfg);
#endif /* _MWIFIEX_11AC_H_ */
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
index 97b245cbafd8..ecf28464367f 100644
--- a/drivers/net/wireless/mwifiex/Makefile
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -39,6 +39,7 @@ mwifiex-y += sta_tx.o
mwifiex-y += sta_rx.o
mwifiex-y += uap_txrx.o
mwifiex-y += cfg80211.o
+mwifiex-y += ethtool.o
mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
obj-$(CONFIG_MWIFIEX) += mwifiex.o
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index a44023a7bd57..95f3306e2836 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -1374,6 +1374,13 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
}
mwifiex_set_ht_params(priv, bss_cfg, params);
+
+ if (priv->adapter->is_hw_11ac_capable) {
+ mwifiex_set_vht_params(priv, bss_cfg, params);
+ mwifiex_set_vht_width(priv, params->chandef.width,
+ priv->ap_11ac_enabled);
+ }
+
mwifiex_set_wmm_params(priv, bss_cfg, params);
if (params->inactivity_timeout > 0) {
@@ -1932,66 +1939,10 @@ static void mwifiex_setup_vht_caps(struct ieee80211_sta_vht_cap *vht_info,
struct mwifiex_private *priv)
{
struct mwifiex_adapter *adapter = priv->adapter;
- u32 vht_cap = 0, cap = adapter->hw_dot_11ac_dev_cap;
vht_info->vht_supported = true;
- switch (GET_VHTCAP_MAXMPDULEN(cap)) {
- case 0x00:
- vht_cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
- break;
- case 0x01:
- vht_cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
- break;
- case 0x10:
- vht_cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
- break;
- default:
- dev_err(adapter->dev, "unsupported MAX MPDU len\n");
- break;
- }
-
- if (ISSUPP_11ACVHTHTCVHT(cap))
- vht_cap |= IEEE80211_VHT_CAP_HTC_VHT;
-
- if (ISSUPP_11ACVHTTXOPPS(cap))
- vht_cap |= IEEE80211_VHT_CAP_VHT_TXOP_PS;
-
- if (ISSUPP_11ACMURXBEAMFORMEE(cap))
- vht_cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
-
- if (ISSUPP_11ACMUTXBEAMFORMEE(cap))
- vht_cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
-
- if (ISSUPP_11ACSUBEAMFORMER(cap))
- vht_cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
-
- if (ISSUPP_11ACSUBEAMFORMEE(cap))
- vht_cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
-
- if (ISSUPP_11ACRXSTBC(cap))
- vht_cap |= IEEE80211_VHT_CAP_RXSTBC_1;
-
- if (ISSUPP_11ACTXSTBC(cap))
- vht_cap |= IEEE80211_VHT_CAP_TXSTBC;
-
- if (ISSUPP_11ACSGI160(cap))
- vht_cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
-
- if (ISSUPP_11ACSGI80(cap))
- vht_cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
-
- if (ISSUPP_11ACLDPC(cap))
- vht_cap |= IEEE80211_VHT_CAP_RXLDPC;
-
- if (ISSUPP_11ACBW8080(cap))
- vht_cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
-
- if (ISSUPP_11ACBW160(cap))
- vht_cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
-
- vht_info->cap = vht_cap;
-
+ vht_info->cap = adapter->hw_dot_11ac_dev_cap;
/* Update MCS support for VHT */
vht_info->vht_mcs.rx_mcs_map = cpu_to_le16(
adapter->hw_dot_11ac_mcs_support & 0xFFFF);
@@ -2235,6 +2186,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT;
dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN;
+ dev->ethtool_ops = &mwifiex_ethtool_ops;
mdev_priv = netdev_priv(dev);
*((unsigned long *) mdev_priv) = (unsigned long) priv;
@@ -2293,6 +2245,152 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
}
EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf);
+#ifdef CONFIG_PM
+static bool
+mwifiex_is_pattern_supported(struct cfg80211_wowlan_trig_pkt_pattern *pat,
+ s8 *byte_seq)
+{
+ int j, k, valid_byte_cnt = 0;
+ bool dont_care_byte = false;
+
+ for (j = 0; j < DIV_ROUND_UP(pat->pattern_len, 8); j++) {
+ for (k = 0; k < 8; k++) {
+ if (pat->mask[j] & 1 << k) {
+ memcpy(byte_seq + valid_byte_cnt,
+ &pat->pattern[j * 8 + k], 1);
+ valid_byte_cnt++;
+ if (dont_care_byte)
+ return false;
+ } else {
+ if (valid_byte_cnt)
+ dont_care_byte = true;
+ }
+
+ if (valid_byte_cnt > MAX_BYTESEQ)
+ return false;
+ }
+ }
+
+ byte_seq[MAX_BYTESEQ] = valid_byte_cnt;
+
+ return true;
+}
+
+static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
+ struct cfg80211_wowlan *wowlan)
+{
+ struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
+ struct mwifiex_ds_mef_cfg mef_cfg;
+ struct mwifiex_mef_entry *mef_entry;
+ int i, filt_num = 0, ret;
+ bool first_pat = true;
+ u8 byte_seq[MAX_BYTESEQ + 1];
+ const u8 ipv4_mc_mac[] = {0x33, 0x33};
+ const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e};
+ struct mwifiex_private *priv =
+ mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
+
+ if (!wowlan) {
+ dev_warn(adapter->dev, "None of the WOWLAN triggers enabled\n");
+ return 0;
+ }
+
+ if (!priv->media_connected) {
+ dev_warn(adapter->dev,
+ "Can not configure WOWLAN in disconnected state\n");
+ return 0;
+ }
+
+ mef_entry = kzalloc(sizeof(*mef_entry), GFP_KERNEL);
+ if (!mef_entry)
+ return -ENOMEM;
+
+ memset(&mef_cfg, 0, sizeof(mef_cfg));
+ mef_cfg.num_entries = 1;
+ mef_cfg.mef_entry = mef_entry;
+ mef_entry->mode = MEF_MODE_HOST_SLEEP;
+ mef_entry->action = MEF_ACTION_ALLOW_AND_WAKEUP_HOST;
+
+ for (i = 0; i < wowlan->n_patterns; i++) {
+ memset(byte_seq, 0, sizeof(byte_seq));
+ if (!mwifiex_is_pattern_supported(&wowlan->patterns[i],
+ byte_seq)) {
+ wiphy_err(wiphy, "Pattern not supported\n");
+ kfree(mef_entry);
+ return -EOPNOTSUPP;
+ }
+
+ if (!wowlan->patterns[i].pkt_offset) {
+ if (!(byte_seq[0] & 0x01) &&
+ (byte_seq[MAX_BYTESEQ] == 1)) {
+ mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST;
+ continue;
+ } else if (is_broadcast_ether_addr(byte_seq)) {
+ mef_cfg.criteria |= MWIFIEX_CRITERIA_BROADCAST;
+ continue;
+ } else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) &&
+ (byte_seq[MAX_BYTESEQ] == 2)) ||
+ (!memcmp(byte_seq, ipv6_mc_mac, 3) &&
+ (byte_seq[MAX_BYTESEQ] == 3))) {
+ mef_cfg.criteria |= MWIFIEX_CRITERIA_MULTICAST;
+ continue;
+ }
+ }
+
+ mef_entry->filter[filt_num].repeat = 1;
+ mef_entry->filter[filt_num].offset =
+ wowlan->patterns[i].pkt_offset;
+ memcpy(mef_entry->filter[filt_num].byte_seq, byte_seq,
+ sizeof(byte_seq));
+ mef_entry->filter[filt_num].filt_type = TYPE_EQ;
+
+ if (first_pat)
+ first_pat = false;
+ else
+ mef_entry->filter[filt_num].filt_action = TYPE_AND;
+
+ filt_num++;
+ }
+
+ if (wowlan->magic_pkt) {
+ mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST;
+ mef_entry->filter[filt_num].repeat = 16;
+ memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr,
+ ETH_ALEN);
+ mef_entry->filter[filt_num].byte_seq[MAX_BYTESEQ] = ETH_ALEN;
+ mef_entry->filter[filt_num].offset = 14;
+ mef_entry->filter[filt_num].filt_type = TYPE_EQ;
+ if (filt_num)
+ mef_entry->filter[filt_num].filt_action = TYPE_OR;
+ }
+
+ if (!mef_cfg.criteria)
+ mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST |
+ MWIFIEX_CRITERIA_UNICAST |
+ MWIFIEX_CRITERIA_MULTICAST;
+
+ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MEF_CFG,
+ HostCmd_ACT_GEN_SET, 0,
+ &mef_cfg);
+
+ kfree(mef_entry);
+ return ret;
+}
+
+static int mwifiex_cfg80211_resume(struct wiphy *wiphy)
+{
+ return 0;
+}
+
+static void mwifiex_cfg80211_set_wakeup(struct wiphy *wiphy,
+ bool enabled)
+{
+ struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
+
+ device_set_wakeup_enable(adapter->dev, enabled);
+}
+#endif
+
/* station cfg80211 operations */
static struct cfg80211_ops mwifiex_cfg80211_ops = {
.add_virtual_intf = mwifiex_add_virtual_intf,
@@ -2321,6 +2419,11 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.change_beacon = mwifiex_cfg80211_change_beacon,
.set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config,
.set_antenna = mwifiex_cfg80211_set_antenna,
+#ifdef CONFIG_PM
+ .suspend = mwifiex_cfg80211_suspend,
+ .resume = mwifiex_cfg80211_resume,
+ .set_wakeup = mwifiex_cfg80211_set_wakeup,
+#endif
};
/*
@@ -2379,6 +2482,14 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom);
+#ifdef CONFIG_PM
+ wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT;
+ wiphy->wowlan.n_patterns = MWIFIEX_MAX_FILTERS;
+ wiphy->wowlan.pattern_min_len = 1;
+ wiphy->wowlan.pattern_max_len = MWIFIEX_MAX_PATTERN_LEN;
+ wiphy->wowlan.max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN;
+#endif
+
wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index b5c8b962ce12..9a1302bd4c03 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -1149,7 +1149,7 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
phs_cfg->params.hs_config.gpio,
phs_cfg->params.hs_config.gap);
}
- if (conditions != HOST_SLEEP_CFG_CANCEL) {
+ if (conditions != HS_CFG_CANCEL) {
adapter->is_hs_configured = true;
if (adapter->iface_type == MWIFIEX_USB ||
adapter->iface_type == MWIFIEX_PCIE)
diff --git a/drivers/net/wireless/mwifiex/ethtool.c b/drivers/net/wireless/mwifiex/ethtool.c
new file mode 100644
index 000000000000..bfb39908b2c6
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/ethtool.c
@@ -0,0 +1,70 @@
+/*
+ * Marvell Wireless LAN device driver: ethtool
+ *
+ * Copyright (C) 2013, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * 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 by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "main.h"
+
+static void mwifiex_ethtool_get_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wol)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ u32 conditions = le32_to_cpu(priv->adapter->hs_cfg.conditions);
+
+ wol->supported = WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY;
+
+ if (conditions == HS_CFG_COND_DEF)
+ return;
+
+ if (conditions & HS_CFG_COND_UNICAST_DATA)
+ wol->wolopts |= WAKE_UCAST;
+ if (conditions & HS_CFG_COND_MULTICAST_DATA)
+ wol->wolopts |= WAKE_MCAST;
+ if (conditions & HS_CFG_COND_BROADCAST_DATA)
+ wol->wolopts |= WAKE_BCAST;
+ if (conditions & HS_CFG_COND_MAC_EVENT)
+ wol->wolopts |= WAKE_PHY;
+}
+
+static int mwifiex_ethtool_set_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wol)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ u32 conditions = 0;
+
+ if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY))
+ return -EOPNOTSUPP;
+
+ if (wol->wolopts & WAKE_UCAST)
+ conditions |= HS_CFG_COND_UNICAST_DATA;
+ if (wol->wolopts & WAKE_MCAST)
+ conditions |= HS_CFG_COND_MULTICAST_DATA;
+ if (wol->wolopts & WAKE_BCAST)
+ conditions |= HS_CFG_COND_BROADCAST_DATA;
+ if (wol->wolopts & WAKE_PHY)
+ conditions |= HS_CFG_COND_MAC_EVENT;
+ if (wol->wolopts == 0)
+ conditions |= HS_CFG_COND_DEF;
+ priv->adapter->hs_cfg.conditions = cpu_to_le32(conditions);
+
+ return 0;
+}
+
+const struct ethtool_ops mwifiex_ethtool_ops = {
+ .get_wol = mwifiex_ethtool_get_wol,
+ .set_wol = mwifiex_ethtool_set_wol,
+};
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 25acb0682c56..1f7578d553ec 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -230,40 +230,12 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define ISSUPP_11ACENABLED(fw_cap_info) (fw_cap_info & (BIT(13)|BIT(14)))
-#define GET_VHTCAP_MAXMPDULEN(vht_cap_info) (vht_cap_info & 0x3)
#define GET_VHTCAP_CHWDSET(vht_cap_info) ((vht_cap_info >> 2) & 0x3)
#define GET_VHTNSSMCS(mcs_mapset, nss) ((mcs_mapset >> (2 * (nss - 1))) & 0x3)
#define SET_VHTNSSMCS(mcs_mapset, nss, value) (mcs_mapset |= (value & 0x3) << \
(2 * (nss - 1)))
#define NO_NSS_SUPPORT 0x3
-/* HW_SPEC: HTC-VHT supported */
-#define ISSUPP_11ACVHTHTCVHT(Dot11acDevCap) (Dot11acDevCap & BIT(22))
-/* HW_SPEC: VHT TXOP PS support */
-#define ISSUPP_11ACVHTTXOPPS(Dot11acDevCap) (Dot11acDevCap & BIT(21))
-/* HW_SPEC: MU RX beamformee support */
-#define ISSUPP_11ACMURXBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & BIT(20))
-/* HW_SPEC: MU TX beamformee support */
-#define ISSUPP_11ACMUTXBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & BIT(19))
-/* HW_SPEC: SU Beamformee support */
-#define ISSUPP_11ACSUBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & BIT(10))
-/* HW_SPEC: SU Beamformer support */
-#define ISSUPP_11ACSUBEAMFORMER(Dot11acDevCap) (Dot11acDevCap & BIT(9))
-/* HW_SPEC: Rx STBC support */
-#define ISSUPP_11ACRXSTBC(Dot11acDevCap) (Dot11acDevCap & BIT(8))
-/* HW_SPEC: Tx STBC support */
-#define ISSUPP_11ACTXSTBC(Dot11acDevCap) (Dot11acDevCap & BIT(7))
-/* HW_SPEC: Short GI support for 160MHz BW */
-#define ISSUPP_11ACSGI160(Dot11acDevCap) (Dot11acDevCap & BIT(6))
-/* HW_SPEC: Short GI support for 80MHz BW */
-#define ISSUPP_11ACSGI80(Dot11acDevCap) (Dot11acDevCap & BIT(5))
-/* HW_SPEC: LDPC coding support */
-#define ISSUPP_11ACLDPC(Dot11acDevCap) (Dot11acDevCap & BIT(4))
-/* HW_SPEC: Channel BW 20/40/80/160/80+80 MHz support */
-#define ISSUPP_11ACBW8080(Dot11acDevCap) (Dot11acDevCap & BIT(3))
-/* HW_SPEC: Channel BW 20/40/80/160 MHz support */
-#define ISSUPP_11ACBW160(Dot11acDevCap) (Dot11acDevCap & BIT(2))
-
#define GET_DEVTXMCSMAP(dev_mcs_map) (dev_mcs_map >> 16)
#define GET_DEVRXMCSMAP(dev_mcs_map) (dev_mcs_map & 0xFFFF)
@@ -300,6 +272,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f
#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083
#define HostCmd_CMD_VERSION_EXT 0x0097
+#define HostCmd_CMD_MEF_CFG 0x009a
#define HostCmd_CMD_RSSI_INFO 0x00a4
#define HostCmd_CMD_FUNC_INIT 0x00a9
#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
@@ -322,6 +295,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa
#define HostCmd_CMD_MGMT_FRAME_REG 0x010c
#define HostCmd_CMD_REMAIN_ON_CHAN 0x010d
+#define HostCmd_CMD_11AC_CFG 0x0112
#define PROTOCOL_NO_SECURITY 0x01
#define PROTOCOL_STATIC_WEP 0x02
@@ -376,10 +350,14 @@ enum P2P_MODES {
#define HostCmd_SCAN_RADIO_TYPE_BG 0
#define HostCmd_SCAN_RADIO_TYPE_A 1
-#define HOST_SLEEP_CFG_CANCEL 0xffffffff
-#define HOST_SLEEP_CFG_COND_DEF 0x00000000
-#define HOST_SLEEP_CFG_GPIO_DEF 0xff
-#define HOST_SLEEP_CFG_GAP_DEF 0
+#define HS_CFG_CANCEL 0xffffffff
+#define HS_CFG_COND_DEF 0x00000000
+#define HS_CFG_GPIO_DEF 0xff
+#define HS_CFG_GAP_DEF 0
+#define HS_CFG_COND_BROADCAST_DATA 0x00000001
+#define HS_CFG_COND_UNICAST_DATA 0x00000002
+#define HS_CFG_COND_MAC_EVENT 0x00000004
+#define HS_CFG_COND_MULTICAST_DATA 0x00000008
#define MWIFIEX_TIMEOUT_FOR_AP_RESP 0xfffc
#define MWIFIEX_STATUS_CODE_AUTH_TIMEOUT 2
@@ -469,6 +447,23 @@ enum P2P_MODES {
#define EVENT_GET_BSS_TYPE(event_cause) \
(((event_cause) >> 24) & 0x00ff)
+#define MWIFIEX_MAX_PATTERN_LEN 20
+#define MWIFIEX_MAX_OFFSET_LEN 50
+#define STACK_NBYTES 100
+#define TYPE_DNUM 1
+#define TYPE_BYTESEQ 2
+#define MAX_OPERAND 0x40
+#define TYPE_EQ (MAX_OPERAND+1)
+#define TYPE_EQ_DNUM (MAX_OPERAND+2)
+#define TYPE_EQ_BIT (MAX_OPERAND+3)
+#define TYPE_AND (MAX_OPERAND+4)
+#define TYPE_OR (MAX_OPERAND+5)
+#define MEF_MODE_HOST_SLEEP 1
+#define MEF_ACTION_ALLOW_AND_WAKEUP_HOST 3
+#define MWIFIEX_CRITERIA_BROADCAST BIT(0)
+#define MWIFIEX_CRITERIA_UNICAST BIT(1)
+#define MWIFIEX_CRITERIA_MULTICAST BIT(3)
+
struct mwifiex_ie_types_header {
__le16 type;
__le16 len;
@@ -1369,6 +1364,15 @@ struct host_cmd_ds_sys_config {
u8 tlv[0];
};
+struct host_cmd_11ac_vht_cfg {
+ __le16 action;
+ u8 band_config;
+ u8 misc_config;
+ __le32 cap_info;
+ __le32 mcs_tx_set;
+ __le32 mcs_rx_set;
+} __packed;
+
struct host_cmd_tlv_akmp {
struct host_cmd_tlv tlv;
__le16 key_mgmt;
@@ -1499,6 +1503,19 @@ struct host_cmd_ds_802_11_ibss_status {
__le16 use_g_rate_protect;
} __packed;
+struct mwifiex_fw_mef_entry {
+ u8 mode;
+ u8 action;
+ __le16 exprsize;
+ u8 expr[0];
+} __packed;
+
+struct host_cmd_ds_mef_cfg {
+ __le32 criteria;
+ __le16 num_entries;
+ struct mwifiex_fw_mef_entry mef_entry[0];
+} __packed;
+
#define CONNECTION_TYPE_INFRA 0
#define CONNECTION_TYPE_ADHOC 1
#define CONNECTION_TYPE_AP 2
@@ -1603,6 +1620,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_remain_on_chan roc_cfg;
struct host_cmd_ds_p2p_mode_cfg mode_cfg;
struct host_cmd_ds_802_11_ibss_status ibss_coalescing;
+ struct host_cmd_ds_mef_cfg mef_cfg;
struct host_cmd_ds_mac_reg_access mac_reg;
struct host_cmd_ds_bbp_reg_access bbp_reg;
struct host_cmd_ds_rf_reg_access rf_reg;
@@ -1612,6 +1630,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_802_11_eeprom_access eeprom;
struct host_cmd_ds_802_11_subsc_evt subsc_evt;
struct host_cmd_ds_sys_config uap_sys_config;
+ struct host_cmd_11ac_vht_cfg vht_cfg;
} params;
} __packed;
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 0ff4c37ab42a..daf8801cecd2 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -318,9 +318,9 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
adapter->is_hs_configured = false;
- adapter->hs_cfg.conditions = cpu_to_le32(HOST_SLEEP_CFG_COND_DEF);
- adapter->hs_cfg.gpio = HOST_SLEEP_CFG_GPIO_DEF;
- adapter->hs_cfg.gap = HOST_SLEEP_CFG_GAP_DEF;
+ adapter->hs_cfg.conditions = cpu_to_le32(HS_CFG_COND_DEF);
+ adapter->hs_cfg.gpio = HS_CFG_GPIO_DEF;
+ adapter->hs_cfg.gap = HS_CFG_GAP_DEF;
adapter->hs_activated = false;
memset(adapter->event_body, 0, sizeof(adapter->event_body));
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index d85e6eb1f58a..7f27e45680b5 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -272,6 +272,14 @@ struct mwifiex_ds_pm_cfg {
} param;
};
+struct mwifiex_11ac_vht_cfg {
+ u8 band_config;
+ u8 misc_config;
+ u32 cap_info;
+ u32 mcs_tx_set;
+ u32 mcs_rx_set;
+};
+
struct mwifiex_ds_11n_tx_cfg {
u16 tx_htcap;
u16 tx_htinfo;
@@ -354,6 +362,29 @@ struct mwifiex_ds_misc_subsc_evt {
struct subsc_evt_cfg bcn_h_rssi_cfg;
};
+#define MAX_BYTESEQ 6 /* non-adjustable */
+#define MWIFIEX_MAX_FILTERS 10
+
+struct mwifiex_mef_filter {
+ u16 repeat;
+ u16 offset;
+ s8 byte_seq[MAX_BYTESEQ + 1];
+ u8 filt_type;
+ u8 filt_action;
+};
+
+struct mwifiex_mef_entry {
+ u8 mode;
+ u8 action;
+ struct mwifiex_mef_filter filter[MWIFIEX_MAX_FILTERS];
+};
+
+struct mwifiex_ds_mef_cfg {
+ u32 criteria;
+ u16 num_entries;
+ struct mwifiex_mef_entry *mef_entry;
+};
+
#define MWIFIEX_MAX_VSIE_LEN (256)
#define MWIFIEX_MAX_VSIE_NUM (8)
#define MWIFIEX_VSIE_MASK_CLEAR 0x00
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 9c802ede9c3b..121443a0f2a1 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -588,10 +588,19 @@ mwifiex_tx_timeout(struct net_device *dev)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- dev_err(priv->adapter->dev, "%lu : Tx timeout, bss_type-num = %d-%d\n",
- jiffies, priv->bss_type, priv->bss_num);
- mwifiex_set_trans_start(dev);
priv->num_tx_timeout++;
+ priv->tx_timeout_cnt++;
+ dev_err(priv->adapter->dev,
+ "%lu : Tx timeout(#%d), bss_type-num = %d-%d\n",
+ jiffies, priv->tx_timeout_cnt, priv->bss_type, priv->bss_num);
+ mwifiex_set_trans_start(dev);
+
+ if (priv->tx_timeout_cnt > TX_TIMEOUT_THRESHOLD &&
+ priv->adapter->if_ops.card_reset) {
+ dev_err(priv->adapter->dev,
+ "tx_timeout_cnt exceeds threshold. Triggering card reset!\n");
+ priv->adapter->if_ops.card_reset(priv->adapter);
+ }
}
/*
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 7035ade9af74..535595eeb5c5 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -130,6 +130,9 @@ enum {
#define MWIFIEX_USB_TYPE_DATA 0xBEADC0DE
#define MWIFIEX_USB_TYPE_EVENT 0xBEEFFACE
+/* Threshold for tx_timeout_cnt before we trigger a card reset */
+#define TX_TIMEOUT_THRESHOLD 6
+
struct mwifiex_dbg {
u32 num_cmd_host_to_card_failure;
u32 num_cmd_sleep_cfm_host_to_card_failure;
@@ -394,6 +397,8 @@ struct mwifiex_private {
u8 curr_addr[ETH_ALEN];
u8 media_connected;
u32 num_tx_timeout;
+ /* track consecutive timeout */
+ u8 tx_timeout_cnt;
struct net_device *netdev;
struct net_device_stats stats;
u16 curr_pkt_filter;
@@ -907,8 +912,14 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
void mwifiex_set_ht_params(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
+void mwifiex_set_vht_params(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_ap_settings *params);
void mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
+void mwifiex_set_vht_width(struct mwifiex_private *priv,
+ enum nl80211_chan_width width,
+ bool ap_11ac_disable);
void
mwifiex_set_wmm_params(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_cfg,
@@ -1098,11 +1109,15 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev);
void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config);
+int mwifiex_add_wowlan_magic_pkt_filter(struct mwifiex_adapter *adapter);
+
int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
struct cfg80211_beacon_data *data);
int mwifiex_del_mgmt_ies(struct mwifiex_private *priv);
u8 *mwifiex_11d_code_2_region(u8 code);
+extern const struct ethtool_ops mwifiex_ethtool_ops;
+
#ifdef CONFIG_DEBUG_FS
void mwifiex_debugfs_init(void);
void mwifiex_debugfs_remove(void);
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index feb204613397..856959b64bc7 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -36,8 +36,6 @@ static u8 user_rmmod;
static struct mwifiex_if_ops pcie_ops;
static struct semaphore add_remove_card_sem;
-static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter);
-static int mwifiex_pcie_resume(struct pci_dev *pdev);
static int
mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
@@ -78,6 +76,82 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter)
return false;
}
+#ifdef CONFIG_PM
+/*
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not suspended, this function allocates and sends a host
+ * sleep activate request to the firmware and turns off the traffic.
+ */
+static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct mwifiex_adapter *adapter;
+ struct pcie_service_card *card;
+ int hs_actived;
+
+ if (pdev) {
+ card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+ if (!card || !card->adapter) {
+ pr_err("Card or adapter structure is not valid\n");
+ return 0;
+ }
+ } else {
+ pr_err("PCIE device is not specified\n");
+ return 0;
+ }
+
+ adapter = card->adapter;
+
+ hs_actived = mwifiex_enable_hs(adapter);
+
+ /* Indicate device suspended */
+ adapter->is_suspended = true;
+
+ return 0;
+}
+
+/*
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not resumed, this function turns on the traffic and
+ * sends a host sleep cancel request to the firmware.
+ */
+static int mwifiex_pcie_resume(struct pci_dev *pdev)
+{
+ struct mwifiex_adapter *adapter;
+ struct pcie_service_card *card;
+
+ if (pdev) {
+ card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+ if (!card || !card->adapter) {
+ pr_err("Card or adapter structure is not valid\n");
+ return 0;
+ }
+ } else {
+ pr_err("PCIE device is not specified\n");
+ return 0;
+ }
+
+ adapter = card->adapter;
+
+ if (!adapter->is_suspended) {
+ dev_warn(adapter->dev, "Device already resumed\n");
+ return 0;
+ }
+
+ adapter->is_suspended = false;
+
+ mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
+ MWIFIEX_ASYNC_CMD);
+
+ return 0;
+}
+#endif
+
/*
* This function probes an mwifiex device and registers it. It allocates
* the card structure, enables PCIE function number and initiates the
@@ -159,80 +233,6 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
kfree(card);
}
-/*
- * Kernel needs to suspend all functions separately. Therefore all
- * registered functions must have drivers with suspend and resume
- * methods. Failing that the kernel simply removes the whole card.
- *
- * If already not suspended, this function allocates and sends a host
- * sleep activate request to the firmware and turns off the traffic.
- */
-static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct mwifiex_adapter *adapter;
- struct pcie_service_card *card;
- int hs_actived;
-
- if (pdev) {
- card = (struct pcie_service_card *) pci_get_drvdata(pdev);
- if (!card || !card->adapter) {
- pr_err("Card or adapter structure is not valid\n");
- return 0;
- }
- } else {
- pr_err("PCIE device is not specified\n");
- return 0;
- }
-
- adapter = card->adapter;
-
- hs_actived = mwifiex_enable_hs(adapter);
-
- /* Indicate device suspended */
- adapter->is_suspended = true;
-
- return 0;
-}
-
-/*
- * Kernel needs to suspend all functions separately. Therefore all
- * registered functions must have drivers with suspend and resume
- * methods. Failing that the kernel simply removes the whole card.
- *
- * If already not resumed, this function turns on the traffic and
- * sends a host sleep cancel request to the firmware.
- */
-static int mwifiex_pcie_resume(struct pci_dev *pdev)
-{
- struct mwifiex_adapter *adapter;
- struct pcie_service_card *card;
-
- if (pdev) {
- card = (struct pcie_service_card *) pci_get_drvdata(pdev);
- if (!card || !card->adapter) {
- pr_err("Card or adapter structure is not valid\n");
- return 0;
- }
- } else {
- pr_err("PCIE device is not specified\n");
- return 0;
- }
-
- adapter = card->adapter;
-
- if (!adapter->is_suspended) {
- dev_warn(adapter->dev, "Device already resumed\n");
- return 0;
- }
-
- adapter->is_suspended = false;
-
- mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
- MWIFIEX_ASYNC_CMD);
-
- return 0;
-}
-
static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = {
{
PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P,
@@ -287,18 +287,13 @@ static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data)
}
/*
- * This function wakes up the card.
- *
- * A host power up command is written to the card configuration
- * register to wake up the card.
+ * This function adds delay loop to ensure FW is awake before proceeding.
*/
-static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
+static void mwifiex_pcie_dev_wakeup_delay(struct mwifiex_adapter *adapter)
{
int i = 0;
- struct pcie_service_card *card = adapter->card;
- const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
- while (reg->sleep_cookie && mwifiex_pcie_ok_to_access_hw(adapter)) {
+ while (mwifiex_pcie_ok_to_access_hw(adapter)) {
i++;
usleep_range(10, 20);
/* 50ms max wait */
@@ -306,16 +301,32 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
break;
}
+ return;
+}
+
+/* This function wakes up the card by reading fw_status register. */
+static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
+{
+ u32 fw_status;
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
dev_dbg(adapter->dev, "event: Wakeup device...\n");
- /* Enable interrupts or any chip access will wakeup device */
- if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK, HOST_INTR_MASK)) {
- dev_warn(adapter->dev, "Enable host interrupt failed\n");
+ if (reg->sleep_cookie)
+ mwifiex_pcie_dev_wakeup_delay(adapter);
+
+ /* Reading fw_status register will wakeup device */
+ if (mwifiex_read_reg(adapter, reg->fw_status, &fw_status)) {
+ dev_warn(adapter->dev, "Reading fw_status register failed\n");
return -1;
}
- dev_dbg(adapter->dev, "PCIE wakeup: Setting PS_STATE_AWAKE\n");
- adapter->ps_state = PS_STATE_AWAKE;
+ if (reg->sleep_cookie) {
+ mwifiex_pcie_dev_wakeup_delay(adapter);
+ dev_dbg(adapter->dev, "PCIE wakeup: Setting PS_STATE_AWAKE\n");
+ adapter->ps_state = PS_STATE_AWAKE;
+ }
return 0;
}
@@ -1030,8 +1041,8 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
u32 wrindx, num_tx_buffs, rx_val;
int ret;
dma_addr_t buf_pa;
- struct mwifiex_pcie_buf_desc *desc;
- struct mwifiex_pfu_buf_desc *desc2;
+ struct mwifiex_pcie_buf_desc *desc = NULL;
+ struct mwifiex_pfu_buf_desc *desc2 = NULL;
__le16 *tmp;
if (!(skb->data && skb->len)) {
@@ -1984,12 +1995,13 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
}
}
} else if (!adapter->pps_uapsd_mode &&
- adapter->ps_state == PS_STATE_SLEEP) {
+ adapter->ps_state == PS_STATE_SLEEP &&
+ mwifiex_pcie_ok_to_access_hw(adapter)) {
/* Potentially for PCIe we could get other
* interrupts like shared. Don't change power
* state until cookie is set */
- if (mwifiex_pcie_ok_to_access_hw(adapter))
- adapter->ps_state = PS_STATE_AWAKE;
+ adapter->ps_state = PS_STATE_AWAKE;
+ adapter->pm_wakeup_fw_try = false;
}
}
}
@@ -2112,7 +2124,8 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
}
dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n",
adapter->cmd_sent, adapter->data_sent);
- mwifiex_pcie_enable_host_int(adapter);
+ if (adapter->ps_state != PS_STATE_SLEEP)
+ mwifiex_pcie_enable_host_int(adapter);
return 0;
}
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index c55c5bb93134..b193e25977d2 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -24,6 +24,7 @@
#include "main.h"
#include "wmm.h"
#include "11n.h"
+#include "11ac.h"
/*
* This function prepares command to set/get RSSI information.
@@ -334,7 +335,7 @@ mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv,
cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
if (!hs_activate &&
- (hscfg_param->conditions != cpu_to_le32(HOST_SLEEP_CFG_CANCEL)) &&
+ (hscfg_param->conditions != cpu_to_le32(HS_CFG_CANCEL)) &&
((adapter->arp_filter_size > 0) &&
(adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) {
dev_dbg(adapter->dev,
@@ -1059,6 +1060,80 @@ mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv,
return 0;
}
+static int
+mwifiex_cmd_append_rpn_expression(struct mwifiex_private *priv,
+ struct mwifiex_mef_entry *mef_entry,
+ u8 **buffer)
+{
+ struct mwifiex_mef_filter *filter = mef_entry->filter;
+ int i, byte_len;
+ u8 *stack_ptr = *buffer;
+
+ for (i = 0; i < MWIFIEX_MAX_FILTERS; i++) {
+ filter = &mef_entry->filter[i];
+ if (!filter->filt_type)
+ break;
+ *(__le32 *)stack_ptr = cpu_to_le32((u32)filter->repeat);
+ stack_ptr += 4;
+ *stack_ptr = TYPE_DNUM;
+ stack_ptr += 1;
+
+ byte_len = filter->byte_seq[MAX_BYTESEQ];
+ memcpy(stack_ptr, filter->byte_seq, byte_len);
+ stack_ptr += byte_len;
+ *stack_ptr = byte_len;
+ stack_ptr += 1;
+ *stack_ptr = TYPE_BYTESEQ;
+ stack_ptr += 1;
+
+ *(__le32 *)stack_ptr = cpu_to_le32((u32)filter->offset);
+ stack_ptr += 4;
+ *stack_ptr = TYPE_DNUM;
+ stack_ptr += 1;
+
+ *stack_ptr = filter->filt_type;
+ stack_ptr += 1;
+
+ if (filter->filt_action) {
+ *stack_ptr = filter->filt_action;
+ stack_ptr += 1;
+ }
+
+ if (stack_ptr - *buffer > STACK_NBYTES)
+ return -1;
+ }
+
+ *buffer = stack_ptr;
+ return 0;
+}
+
+static int
+mwifiex_cmd_mef_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ struct mwifiex_ds_mef_cfg *mef)
+{
+ struct host_cmd_ds_mef_cfg *mef_cfg = &cmd->params.mef_cfg;
+ u8 *pos = (u8 *)mef_cfg;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_MEF_CFG);
+
+ mef_cfg->criteria = cpu_to_le32(mef->criteria);
+ mef_cfg->num_entries = cpu_to_le16(mef->num_entries);
+ pos += sizeof(*mef_cfg);
+ mef_cfg->mef_entry->mode = mef->mef_entry->mode;
+ mef_cfg->mef_entry->action = mef->mef_entry->action;
+ pos += sizeof(*(mef_cfg->mef_entry));
+
+ if (mwifiex_cmd_append_rpn_expression(priv, mef->mef_entry, &pos))
+ return -1;
+
+ mef_cfg->mef_entry->exprsize =
+ cpu_to_le16(pos - mef_cfg->mef_entry->expr);
+ cmd->size = cpu_to_le16((u16) (pos - (u8 *)mef_cfg) + S_DS_GEN);
+
+ return 0;
+}
+
/*
* This function prepares the commands before sending them to the firmware.
*
@@ -1184,6 +1259,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
cpu_to_le16(sizeof(struct host_cmd_ds_remain_on_chan) +
S_DS_GEN);
break;
+ case HostCmd_CMD_11AC_CFG:
+ ret = mwifiex_cmd_11ac_cfg(priv, cmd_ptr, cmd_action, data_buf);
+ break;
case HostCmd_CMD_P2P_MODE_CFG:
cmd_ptr->command = cpu_to_le16(cmd_no);
cmd_ptr->params.mode_cfg.action = cpu_to_le16(cmd_action);
@@ -1273,6 +1351,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
ret = mwifiex_cmd_802_11_subsc_evt(priv, cmd_ptr, data_buf);
break;
+ case HostCmd_CMD_MEF_CFG:
+ ret = mwifiex_cmd_mef_cfg(priv, cmd_ptr, data_buf);
+ break;
default:
dev_err(priv->adapter->dev,
"PREP_CMD: unknown cmd- %#x\n", cmd_no);
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 4669f8d9389f..c7dc450f0bf3 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -907,6 +907,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_REMAIN_ON_CHAN:
ret = mwifiex_ret_remain_on_chan(priv, resp, data_buf);
break;
+ case HostCmd_CMD_11AC_CFG:
+ break;
case HostCmd_CMD_P2P_MODE_CFG:
ret = mwifiex_ret_p2p_mode_cfg(priv, resp, data_buf);
break;
@@ -976,6 +978,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_UAP_BSS_STOP:
priv->bss_started = 0;
break;
+ case HostCmd_CMD_MEF_CFG:
+ break;
default:
dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
resp->command);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 13100f8de3db..8c943b6ebf45 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -382,7 +382,7 @@ static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
break;
}
if (hs_cfg->is_invoke_hostcmd) {
- if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) {
+ if (hs_cfg->conditions == HS_CFG_CANCEL) {
if (!adapter->is_hs_configured)
/* Already cancelled */
break;
@@ -397,8 +397,8 @@ static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
if (hs_cfg->gap)
adapter->hs_cfg.gap = (u8)hs_cfg->gap;
- } else if (adapter->hs_cfg.conditions
- == cpu_to_le32(HOST_SLEEP_CFG_CANCEL)) {
+ } else if (adapter->hs_cfg.conditions ==
+ cpu_to_le32(HS_CFG_CANCEL)) {
/* Return failure if no parameters for HS
enable */
status = -1;
@@ -414,7 +414,7 @@ static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
HostCmd_CMD_802_11_HS_CFG_ENH,
HostCmd_ACT_GEN_SET, 0,
&adapter->hs_cfg);
- if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL)
+ if (hs_cfg->conditions == HS_CFG_CANCEL)
/* Restore previous condition */
adapter->hs_cfg.conditions =
cpu_to_le32(prev_cond);
@@ -448,7 +448,7 @@ int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type)
{
struct mwifiex_ds_hs_cfg hscfg;
- hscfg.conditions = HOST_SLEEP_CFG_CANCEL;
+ hscfg.conditions = HS_CFG_CANCEL;
hscfg.is_invoke_hostcmd = true;
return mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index 296faec14365..8f923d0d2ba6 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -169,6 +169,8 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
if (!status) {
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
+ if (priv->tx_timeout_cnt)
+ priv->tx_timeout_cnt = 0;
} else {
priv->stats.tx_errors++;
}
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c
index 6e76a15a8950..b04b1db29100 100644
--- a/drivers/net/wireless/mwifiex/uap_cmd.c
+++ b/drivers/net/wireless/mwifiex/uap_cmd.c
@@ -18,6 +18,7 @@
*/
#include "main.h"
+#include "11ac.h"
/* This function parses security related parameters from cfg80211_ap_settings
* and sets into FW understandable bss_config structure.
@@ -177,6 +178,60 @@ mwifiex_set_ht_params(struct mwifiex_private *priv,
return;
}
+/* This function updates 11ac related parameters from IE
+ * and sets them into bss_config structure.
+ */
+void mwifiex_set_vht_params(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_ap_settings *params)
+{
+ const u8 *vht_ie;
+
+ vht_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, params->beacon.tail,
+ params->beacon.tail_len);
+ if (vht_ie) {
+ memcpy(&bss_cfg->vht_cap, vht_ie + 2,
+ sizeof(struct ieee80211_vht_cap));
+ priv->ap_11ac_enabled = 1;
+ } else {
+ priv->ap_11ac_enabled = 0;
+ }
+
+ return;
+}
+
+/* Enable VHT only when cfg80211_ap_settings has VHT IE.
+ * Otherwise disable VHT.
+ */
+void mwifiex_set_vht_width(struct mwifiex_private *priv,
+ enum nl80211_chan_width width,
+ bool ap_11ac_enable)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_11ac_vht_cfg vht_cfg;
+
+ vht_cfg.band_config = VHT_CFG_5GHZ;
+ vht_cfg.cap_info = adapter->hw_dot_11ac_dev_cap;
+
+ if (!ap_11ac_enable) {
+ vht_cfg.mcs_tx_set = DISABLE_VHT_MCS_SET;
+ vht_cfg.mcs_rx_set = DISABLE_VHT_MCS_SET;
+ } else {
+ vht_cfg.mcs_tx_set = DEFAULT_VHT_MCS_SET;
+ vht_cfg.mcs_rx_set = DEFAULT_VHT_MCS_SET;
+ }
+
+ vht_cfg.misc_config = VHT_CAP_UAP_ONLY;
+
+ if (ap_11ac_enable && width >= NL80211_CHAN_WIDTH_80)
+ vht_cfg.misc_config |= VHT_BW_80_160_80P80;
+
+ mwifiex_send_cmd_sync(priv, HostCmd_CMD_11AC_CFG,
+ HostCmd_ACT_GEN_SET, 0, &vht_cfg);
+
+ return;
+}
+
/* This function finds supported rates IE from beacon parameter and sets
* these rates into bss_config structure.
*/
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index 21553976b550..54667e65ca47 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -195,7 +195,7 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
skb->protocol = eth_type_trans(skb, priv->netdev);
skb->ip_summed = CHECKSUM_NONE;
- /* This is required only in case of 11n and USB as we alloc
+ /* This is required only in case of 11n and USB/PCIE as we alloc
* a buffer of 4K only if its 11N (to be able to receive 4K
* AMSDU packets). In case of SD we allocate buffers based
* on the size of packet and hence this is not needed.
@@ -212,7 +212,8 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
* fragments. Currently we fail the Filesndl-ht.scr script
* for UDP, hence this fix
*/
- if ((priv->adapter->iface_type == MWIFIEX_USB) &&
+ if ((priv->adapter->iface_type == MWIFIEX_USB ||
+ priv->adapter->iface_type == MWIFIEX_PCIE) &&
(skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE))
skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE);