aboutsummaryrefslogtreecommitdiffstats
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/11h.c101
-rw-r--r--drivers/net/wireless/mwifiex/Kconfig4
-rw-r--r--drivers/net/wireless/mwifiex/Makefile1
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c122
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c1
-rw-r--r--drivers/net/wireless/mwifiex/fw.h33
-rw-r--r--drivers/net/wireless/mwifiex/init.c115
-rw-r--r--drivers/net/wireless/mwifiex/join.c7
-rw-r--r--drivers/net/wireless/mwifiex/main.c101
-rw-r--r--drivers/net/wireless/mwifiex/main.h32
-rw-r--r--drivers/net/wireless/mwifiex/scan.c60
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c463
-rw-r--r--drivers/net/wireless/mwifiex/sdio.h340
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c62
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c17
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c11
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c52
-rw-r--r--drivers/net/wireless/mwifiex/uap_cmd.c21
-rw-r--r--drivers/net/wireless/mwifiex/uap_event.c25
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c5
20 files changed, 1151 insertions, 422 deletions
diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c
new file mode 100644
index 000000000000..8d683070bdb3
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11h.c
@@ -0,0 +1,101 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11h
+ *
+ * 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"
+#include "fw.h"
+
+
+/* This function appends 11h info to a buffer while joining an
+ * infrastructure BSS
+ */
+static void
+mwifiex_11h_process_infra_join(struct mwifiex_private *priv, u8 **buffer,
+ struct mwifiex_bssdescriptor *bss_desc)
+{
+ struct mwifiex_ie_types_header *ie_header;
+ struct mwifiex_ie_types_pwr_capability *cap;
+ struct mwifiex_ie_types_local_pwr_constraint *constraint;
+ struct ieee80211_supported_band *sband;
+ u8 radio_type;
+ int i;
+
+ if (!buffer || !(*buffer))
+ return;
+
+ radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
+ sband = priv->wdev->wiphy->bands[radio_type];
+
+ cap = (struct mwifiex_ie_types_pwr_capability *)*buffer;
+ cap->header.type = cpu_to_le16(WLAN_EID_PWR_CAPABILITY);
+ cap->header.len = cpu_to_le16(2);
+ cap->min_pwr = 0;
+ cap->max_pwr = 0;
+ *buffer += sizeof(*cap);
+
+ constraint = (struct mwifiex_ie_types_local_pwr_constraint *)*buffer;
+ constraint->header.type = cpu_to_le16(WLAN_EID_PWR_CONSTRAINT);
+ constraint->header.len = cpu_to_le16(2);
+ constraint->chan = bss_desc->channel;
+ constraint->constraint = bss_desc->local_constraint;
+ *buffer += sizeof(*constraint);
+
+ ie_header = (struct mwifiex_ie_types_header *)*buffer;
+ ie_header->type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+ ie_header->len = cpu_to_le16(2 * sband->n_channels + 2);
+ *buffer += sizeof(*ie_header);
+ *(*buffer)++ = WLAN_EID_SUPPORTED_CHANNELS;
+ *(*buffer)++ = 2 * sband->n_channels;
+ for (i = 0; i < sband->n_channels; i++) {
+ *(*buffer)++ = ieee80211_frequency_to_channel(
+ sband->channels[i].center_freq);
+ *(*buffer)++ = 1; /* one channel in the subband */
+ }
+}
+
+/* Enable or disable the 11h extensions in the firmware */
+static int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag)
+{
+ u32 enable = flag;
+
+ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, DOT11H_I, &enable);
+}
+
+/* This functions processes TLV buffer for a pending BSS Join command.
+ *
+ * Activate 11h functionality in the firmware if the spectrum management
+ * capability bit is found in the network we are joining. Also, necessary
+ * TLVs are set based on requested network's 11h capability.
+ */
+void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
+ struct mwifiex_bssdescriptor *bss_desc)
+{
+ if (bss_desc->sensed_11h) {
+ /* Activate 11h functions in firmware, turns on capability
+ * bit
+ */
+ mwifiex_11h_activate(priv, true);
+ bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_SPECTRUM_MGMT;
+ mwifiex_11h_process_infra_join(priv, buffer, bss_desc);
+ } else {
+ /* Deactivate 11h functions in the firmware */
+ mwifiex_11h_activate(priv, false);
+ bss_desc->cap_info_bitmap &= ~WLAN_CAPABILITY_SPECTRUM_MGMT;
+ }
+}
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig
index 4f614aad9ded..f7ff4725506a 100644
--- a/drivers/net/wireless/mwifiex/Kconfig
+++ b/drivers/net/wireless/mwifiex/Kconfig
@@ -3,13 +3,13 @@ config MWIFIEX
depends on CFG80211
---help---
This adds support for wireless adapters based on Marvell
- 802.11n chipsets.
+ 802.11n/ac chipsets.
If you choose to build it as a module, it will be called
mwifiex.
config MWIFIEX_SDIO
- tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797"
+ tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797/SD8897"
depends on MWIFIEX && MMC
select FW_LOADER
---help---
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
index ecf28464367f..a42a506fd32b 100644
--- a/drivers/net/wireless/mwifiex/Makefile
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -40,6 +40,7 @@ mwifiex-y += sta_rx.o
mwifiex-y += uap_txrx.o
mwifiex-y += cfg80211.o
mwifiex-y += ethtool.o
+mwifiex-y += 11h.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 e42b266a023a..ef5fa890a286 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -20,6 +20,9 @@
#include "cfg80211.h"
#include "main.h"
+static char *reg_alpha2;
+module_param(reg_alpha2, charp, 0);
+
static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = {
{
.max = 2, .types = BIT(NL80211_IFTYPE_STATION),
@@ -1231,6 +1234,51 @@ static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy,
return 0;
}
+/* cfg80211 operation handler for del_station.
+ * Function deauthenticates station which value is provided in mac parameter.
+ * If mac is NULL/broadcast, all stations in associated station list are
+ * deauthenticated. If bss is not started or there are no stations in
+ * associated stations list, no action is taken.
+ */
+static int
+mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ struct mwifiex_sta_node *sta_node;
+ unsigned long flags;
+
+ if (list_empty(&priv->sta_list) || !priv->bss_started)
+ return 0;
+
+ if (!mac || is_broadcast_ether_addr(mac)) {
+ wiphy_dbg(wiphy, "%s: NULL/broadcast mac address\n", __func__);
+ list_for_each_entry(sta_node, &priv->sta_list, list) {
+ if (mwifiex_send_cmd_sync(priv,
+ HostCmd_CMD_UAP_STA_DEAUTH,
+ HostCmd_ACT_GEN_SET, 0,
+ sta_node->mac_addr))
+ return -1;
+ mwifiex_uap_del_sta_data(priv, sta_node);
+ }
+ } else {
+ wiphy_dbg(wiphy, "%s: mac address %pM\n", __func__, mac);
+ spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ sta_node = mwifiex_get_sta_entry(priv, mac);
+ spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ if (sta_node) {
+ if (mwifiex_send_cmd_sync(priv,
+ HostCmd_CMD_UAP_STA_DEAUTH,
+ HostCmd_ACT_GEN_SET, 0,
+ sta_node->mac_addr))
+ return -1;
+ mwifiex_uap_del_sta_data(priv, sta_node);
+ }
+ }
+
+ return 0;
+}
+
static int
mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant)
{
@@ -1859,6 +1907,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
int i, offset, ret;
struct ieee80211_channel *chan;
struct ieee_types_header *ie;
+ struct mwifiex_user_scan_cfg *user_scan_cfg;
wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name);
@@ -1869,20 +1918,22 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
return -EBUSY;
}
- if (priv->user_scan_cfg) {
+ /* Block scan request if scan operation or scan cleanup when interface
+ * is disabled is in process
+ */
+ if (priv->scan_request || priv->scan_aborting) {
dev_err(priv->adapter->dev, "cmd: Scan already in process..\n");
return -EBUSY;
}
- priv->user_scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg),
- GFP_KERNEL);
- if (!priv->user_scan_cfg)
+ user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL);
+ if (!user_scan_cfg)
return -ENOMEM;
priv->scan_request = request;
- priv->user_scan_cfg->num_ssids = request->n_ssids;
- priv->user_scan_cfg->ssid_list = request->ssids;
+ user_scan_cfg->num_ssids = request->n_ssids;
+ user_scan_cfg->ssid_list = request->ssids;
if (request->ie && request->ie_len) {
offset = 0;
@@ -1902,25 +1953,25 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
for (i = 0; i < min_t(u32, request->n_channels,
MWIFIEX_USER_SCAN_CHAN_MAX); i++) {
chan = request->channels[i];
- priv->user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
- priv->user_scan_cfg->chan_list[i].radio_type = chan->band;
+ user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
+ user_scan_cfg->chan_list[i].radio_type = chan->band;
if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
- priv->user_scan_cfg->chan_list[i].scan_type =
+ user_scan_cfg->chan_list[i].scan_type =
MWIFIEX_SCAN_TYPE_PASSIVE;
else
- priv->user_scan_cfg->chan_list[i].scan_type =
+ user_scan_cfg->chan_list[i].scan_type =
MWIFIEX_SCAN_TYPE_ACTIVE;
- priv->user_scan_cfg->chan_list[i].scan_time = 0;
+ user_scan_cfg->chan_list[i].scan_time = 0;
}
- ret = mwifiex_scan_networks(priv, priv->user_scan_cfg);
+ ret = mwifiex_scan_networks(priv, user_scan_cfg);
+ kfree(user_scan_cfg);
if (ret) {
dev_err(priv->adapter->dev, "scan failed: %d\n", ret);
+ priv->scan_aborting = false;
priv->scan_request = NULL;
- kfree(priv->user_scan_cfg);
- priv->user_scan_cfg = NULL;
return ret;
}
@@ -2419,6 +2470,7 @@ 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,
+ .del_station = mwifiex_cfg80211_del_station,
#ifdef CONFIG_PM
.suspend = mwifiex_cfg80211_suspend,
.resume = mwifiex_cfg80211_resume,
@@ -2426,6 +2478,27 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
#endif
};
+#ifdef CONFIG_PM
+static const struct wiphy_wowlan_support mwifiex_wowlan_support = {
+ .flags = WIPHY_WOWLAN_MAGIC_PKT,
+ .n_patterns = MWIFIEX_MAX_FILTERS,
+ .pattern_min_len = 1,
+ .pattern_max_len = MWIFIEX_MAX_PATTERN_LEN,
+ .max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN,
+};
+#endif
+
+static bool mwifiex_is_valid_alpha2(const char *alpha2)
+{
+ if (!alpha2 || strlen(alpha2) != 2)
+ return false;
+
+ if (isalpha(alpha2[0]) && isalpha(alpha2[1]))
+ return true;
+
+ return false;
+}
+
/*
* This function registers the device with CFG802.11 subsystem.
*
@@ -2478,16 +2551,13 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_CUSTOM_REGULATORY |
+ WIPHY_FLAG_STRICT_REGULATORY |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
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;
+ wiphy->wowlan = &mwifiex_wowlan_support;
#endif
wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
@@ -2519,10 +2589,16 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy_free(wiphy);
return ret;
}
- country_code = mwifiex_11d_code_2_region(priv->adapter->region_code);
- if (country_code)
- dev_info(adapter->dev,
- "ignoring F/W country code %2.2s\n", country_code);
+
+ if (reg_alpha2 && mwifiex_is_valid_alpha2(reg_alpha2)) {
+ wiphy_info(wiphy, "driver hint alpha2: %2.2s\n", reg_alpha2);
+ regulatory_hint(wiphy, reg_alpha2);
+ } else {
+ country_code = mwifiex_11d_code_2_region(adapter->region_code);
+ if (country_code)
+ wiphy_info(wiphy, "ignoring F/W country code %2.2s\n",
+ country_code);
+ }
adapter->wiphy = wiphy;
return ret;
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index 26755d9acb55..2d761477d15e 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -570,6 +570,7 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
case HostCmd_CMD_UAP_SYS_CONFIG:
case HostCmd_CMD_UAP_BSS_START:
case HostCmd_CMD_UAP_BSS_STOP:
+ case HostCmd_CMD_UAP_STA_DEAUTH:
ret = mwifiex_uap_prepare_cmd(priv, cmd_no, cmd_action,
cmd_oid, data_buf,
cmd_ptr);
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 1f7578d553ec..1b45aa533300 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -245,6 +245,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HT_BW_20 0
#define HT_BW_40 1
+#define DFS_CHAN_MOVE_TIME 10000
+
#define HostCmd_CMD_GET_HW_SPEC 0x0003
#define HostCmd_CMD_802_11_SCAN 0x0006
#define HostCmd_CMD_802_11_GET_LOG 0x000b
@@ -271,6 +273,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075
#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f
#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083
+#define HostCmd_CMD_CFG_DATA 0x008f
#define HostCmd_CMD_VERSION_EXT 0x0097
#define HostCmd_CMD_MEF_CFG 0x009a
#define HostCmd_CMD_RSSI_INFO 0x00a4
@@ -279,6 +282,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_UAP_SYS_CONFIG 0x00b0
#define HostCmd_CMD_UAP_BSS_START 0x00b1
#define HostCmd_CMD_UAP_BSS_STOP 0x00b2
+#define HostCmd_CMD_UAP_STA_DEAUTH 0x00b5
#define HostCmd_CMD_11N_CFG 0x00cd
#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce
#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf
@@ -436,6 +440,7 @@ enum P2P_MODES {
#define EVENT_BW_CHANGE 0x00000048
#define EVENT_UAP_MIC_COUNTERMEASURES 0x0000004c
#define EVENT_HOSTWAKE_STAIE 0x0000004d
+#define EVENT_CHANNEL_SWITCH_ANN 0x00000050
#define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f
#define EVENT_ID_MASK 0xffff
@@ -464,6 +469,8 @@ enum P2P_MODES {
#define MWIFIEX_CRITERIA_UNICAST BIT(1)
#define MWIFIEX_CRITERIA_MULTICAST BIT(3)
+#define CFG_DATA_TYPE_CAL 2
+
struct mwifiex_ie_types_header {
__le16 type;
__le16 len;
@@ -971,6 +978,7 @@ enum SNMP_MIB_INDEX {
LONG_RETRY_LIM_I = 7,
FRAG_THRESH_I = 8,
DOT11D_I = 9,
+ DOT11H_I = 10,
};
#define MAX_SNMP_BUF_SIZE 128
@@ -1197,6 +1205,23 @@ struct host_cmd_ds_amsdu_aggr_ctrl {
__le16 curr_buf_size;
} __packed;
+struct host_cmd_ds_sta_deauth {
+ u8 mac[ETH_ALEN];
+ __le16 reason;
+} __packed;
+
+struct mwifiex_ie_types_pwr_capability {
+ struct mwifiex_ie_types_header header;
+ s8 min_pwr;
+ s8 max_pwr;
+};
+
+struct mwifiex_ie_types_local_pwr_constraint {
+ struct mwifiex_ie_types_header header;
+ u8 chan;
+ u8 constraint;
+};
+
struct mwifiex_ie_types_wmm_param_set {
struct mwifiex_ie_types_header header;
u8 wmm_ie[1];
@@ -1573,6 +1598,12 @@ struct mwifiex_ie_list {
struct mwifiex_ie ie_list[MAX_MGMT_IE_INDEX];
} __packed;
+struct host_cmd_ds_802_11_cfg_data {
+ __le16 action;
+ __le16 type;
+ __le16 data_len;
+} __packed;
+
struct host_cmd_ds_command {
__le16 command;
__le16 size;
@@ -1630,7 +1661,9 @@ 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_ds_sta_deauth sta_deauth;
struct host_cmd_11ac_vht_cfg vht_cfg;
+ struct host_cmd_ds_802_11_cfg_data cfg_data;
} params;
} __packed;
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 9f44fda19db9..caaf4bd56b30 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -52,87 +52,6 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv)
return 0;
}
-static void scan_delay_timer_fn(unsigned long data)
-{
- struct mwifiex_private *priv = (struct mwifiex_private *)data;
- struct mwifiex_adapter *adapter = priv->adapter;
- struct cmd_ctrl_node *cmd_node, *tmp_node;
- unsigned long flags;
-
- if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
- /*
- * Abort scan operation by cancelling all pending scan
- * commands
- */
- spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
- list_for_each_entry_safe(cmd_node, tmp_node,
- &adapter->scan_pending_q, list) {
- list_del(&cmd_node->list);
- mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
- }
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
-
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
- adapter->scan_processing = false;
- adapter->scan_delay_cnt = 0;
- adapter->empty_tx_q_cnt = 0;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
-
- if (priv->user_scan_cfg) {
- if (priv->scan_request) {
- dev_dbg(priv->adapter->dev,
- "info: aborting scan\n");
- cfg80211_scan_done(priv->scan_request, 1);
- priv->scan_request = NULL;
- } else {
- dev_dbg(priv->adapter->dev,
- "info: scan already aborted\n");
- }
-
- kfree(priv->user_scan_cfg);
- priv->user_scan_cfg = NULL;
- }
- goto done;
- }
-
- if (!atomic_read(&priv->adapter->is_tx_received)) {
- adapter->empty_tx_q_cnt++;
- if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) {
- /*
- * No Tx traffic for 200msec. Get scan command from
- * scan pending queue and put to cmd pending queue to
- * resume scan operation
- */
- adapter->scan_delay_cnt = 0;
- adapter->empty_tx_q_cnt = 0;
- spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
- cmd_node = list_first_entry(&adapter->scan_pending_q,
- struct cmd_ctrl_node, list);
- list_del(&cmd_node->list);
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
- flags);
-
- mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
- true);
- queue_work(adapter->workqueue, &adapter->main_work);
- goto done;
- }
- } else {
- adapter->empty_tx_q_cnt = 0;
- }
-
- /* Delay scan operation further by 20msec */
- mod_timer(&priv->scan_delay_timer, jiffies +
- msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
- adapter->scan_delay_cnt++;
-
-done:
- if (atomic_read(&priv->adapter->is_tx_received))
- atomic_set(&priv->adapter->is_tx_received, false);
-
- return;
-}
-
/*
* This function initializes the private structure and sets default
* values to the members.
@@ -214,8 +133,8 @@ int mwifiex_init_priv(struct mwifiex_private *priv)
priv->scan_block = false;
- setup_timer(&priv->scan_delay_timer, scan_delay_timer_fn,
- (unsigned long)priv);
+ priv->csa_chan = 0;
+ priv->csa_expire_time = 0;
return mwifiex_add_bss_prio_tbl(priv);
}
@@ -447,23 +366,29 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
}
/*
- * This function frees the adapter structure.
+ * This function performs cleanup for adapter structure.
*
- * The freeing operation is done recursively, by canceling all
- * pending commands, freeing the member buffers previously
- * allocated (command buffers, scan table buffer, sleep confirm
- * command buffer), stopping the timers and calling the cleanup
- * routines for every interface, before the actual adapter
- * structure is freed.
+ * The cleanup is done recursively, by canceling all pending
+ * commands, freeing the member buffers previously allocated
+ * (command buffers, scan table buffer, sleep confirm command
+ * buffer), stopping the timers and calling the cleanup routines
+ * for every interface.
*/
static void
-mwifiex_free_adapter(struct mwifiex_adapter *adapter)
+mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
{
+ int i;
+
if (!adapter) {
pr_err("%s: adapter is NULL\n", __func__);
return;
}
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i])
+ del_timer_sync(&adapter->priv[i]->scan_delay_timer);
+ }
+
mwifiex_cancel_all_pending_cmd(adapter);
/* Free lock variables */
@@ -684,7 +609,6 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
int ret = -EINPROGRESS;
struct mwifiex_private *priv;
s32 i;
- unsigned long flags;
struct sk_buff *skb;
/* mwifiex already shutdown */
@@ -719,7 +643,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
}
}
- spin_lock_irqsave(&adapter->mwifiex_lock, flags);
+ spin_lock(&adapter->mwifiex_lock);
if (adapter->if_ops.data_complete) {
while ((skb = skb_dequeue(&adapter->usb_rx_data_q))) {
@@ -733,10 +657,9 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
}
}
- /* Free adapter structure */
- mwifiex_free_adapter(adapter);
+ mwifiex_adapter_cleanup(adapter);
- spin_unlock_irqrestore(&adapter->mwifiex_lock, flags);
+ spin_unlock(&adapter->mwifiex_lock);
/* Notify completion */
ret = mwifiex_shutdown_fw_complete(adapter);
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 6bcb66e6e97c..1c8a771e8e81 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -534,6 +534,8 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc);
+ mwifiex_11h_process_join(priv, &pos, bss_desc);
+
cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN);
/* Set the Capability info at last */
@@ -919,9 +921,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
memcpy(&priv->curr_bss_params.data_rates,
&adhoc_start->data_rate, priv->curr_bss_params.num_of_rates);
- dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n",
- adhoc_start->data_rate[0], adhoc_start->data_rate[1],
- adhoc_start->data_rate[2], adhoc_start->data_rate[3]);
+ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%4ph\n",
+ adhoc_start->data_rate);
dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n");
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 2eb88ea9acf7..e15ab72fb03d 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -25,6 +25,86 @@
#define VERSION "1.0"
const char driver_version[] = "mwifiex " VERSION " (%s) ";
+static char *cal_data_cfg;
+module_param(cal_data_cfg, charp, 0);
+
+static void scan_delay_timer_fn(unsigned long data)
+{
+ struct mwifiex_private *priv = (struct mwifiex_private *)data;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *cmd_node, *tmp_node;
+ unsigned long flags;
+
+ if (adapter->surprise_removed)
+ return;
+
+ if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
+ /*
+ * Abort scan operation by cancelling all pending scan
+ * commands
+ */
+ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ list_for_each_entry_safe(cmd_node, tmp_node,
+ &adapter->scan_pending_q, list) {
+ list_del(&cmd_node->list);
+ mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ }
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->scan_processing = false;
+ adapter->scan_delay_cnt = 0;
+ adapter->empty_tx_q_cnt = 0;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
+ if (priv->scan_request) {
+ dev_dbg(adapter->dev, "info: aborting scan\n");
+ cfg80211_scan_done(priv->scan_request, 1);
+ priv->scan_request = NULL;
+ } else {
+ priv->scan_aborting = false;
+ dev_dbg(adapter->dev, "info: scan already aborted\n");
+ }
+ goto done;
+ }
+
+ if (!atomic_read(&priv->adapter->is_tx_received)) {
+ adapter->empty_tx_q_cnt++;
+ if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) {
+ /*
+ * No Tx traffic for 200msec. Get scan command from
+ * scan pending queue and put to cmd pending queue to
+ * resume scan operation
+ */
+ adapter->scan_delay_cnt = 0;
+ adapter->empty_tx_q_cnt = 0;
+ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ cmd_node = list_first_entry(&adapter->scan_pending_q,
+ struct cmd_ctrl_node, list);
+ list_del(&cmd_node->list);
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+ flags);
+
+ mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
+ true);
+ queue_work(adapter->workqueue, &adapter->main_work);
+ goto done;
+ }
+ } else {
+ adapter->empty_tx_q_cnt = 0;
+ }
+
+ /* Delay scan operation further by 20msec */
+ mod_timer(&priv->scan_delay_timer, jiffies +
+ msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
+ adapter->scan_delay_cnt++;
+
+done:
+ if (atomic_read(&priv->adapter->is_tx_received))
+ atomic_set(&priv->adapter->is_tx_received, false);
+
+ return;
+}
/*
* This function registers the device and performs all the necessary
@@ -73,6 +153,10 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
adapter->priv[i]->adapter = adapter;
adapter->priv_num++;
+
+ setup_timer(&adapter->priv[i]->scan_delay_timer,
+ scan_delay_timer_fn,
+ (unsigned long)adapter->priv[i]);
}
mwifiex_init_lock_list(adapter);
@@ -336,6 +420,13 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
dev_notice(adapter->dev, "WLAN FW is active\n");
+ if (cal_data_cfg) {
+ if ((request_firmware(&adapter->cal_data, cal_data_cfg,
+ adapter->dev)) < 0)
+ dev_err(adapter->dev,
+ "Cal data request_firmware() failed\n");
+ }
+
adapter->init_wait_q_woken = false;
ret = mwifiex_init_fw(adapter);
if (ret == -1) {
@@ -390,6 +481,10 @@ err_init_fw:
pr_debug("info: %s: unregister device\n", __func__);
adapter->if_ops.unregister_dev(adapter);
done:
+ if (adapter->cal_data) {
+ release_firmware(adapter->cal_data);
+ adapter->cal_data = NULL;
+ }
release_firmware(adapter->firmware);
complete(&adapter->fw_load);
return;
@@ -436,6 +531,7 @@ mwifiex_close(struct net_device *dev)
dev_dbg(priv->adapter->dev, "aborting scan on ndo_stop\n");
cfg80211_scan_done(priv->scan_request, 1);
priv->scan_request = NULL;
+ priv->scan_aborting = true;
}
return 0;
@@ -573,9 +669,8 @@ static void mwifiex_set_multicast_list(struct net_device *dev)
mcast_list.mode = MWIFIEX_ALL_MULTI_MODE;
} else {
mcast_list.mode = MWIFIEX_MULTICAST_MODE;
- if (netdev_mc_count(dev))
- mcast_list.num_multicast_addr =
- mwifiex_copy_mcast_addr(&mcast_list, dev);
+ mcast_list.num_multicast_addr =
+ mwifiex_copy_mcast_addr(&mcast_list, dev);
}
mwifiex_request_set_multicast_list(priv, &mcast_list);
}
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 4ef67fca06d3..3da73d36acdf 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -309,6 +309,9 @@ struct mwifiex_bssdescriptor {
u16 wapi_offset;
u8 *beacon_buf;
u32 beacon_buf_size;
+ u8 sensed_11h;
+ u8 local_constraint;
+ u8 chan_sw_ie_present;
};
struct mwifiex_current_bss_params {
@@ -492,7 +495,6 @@ struct mwifiex_private {
struct semaphore async_sem;
u8 report_scan_result;
struct cfg80211_scan_request *scan_request;
- struct mwifiex_user_scan_cfg *user_scan_cfg;
u8 cfg_bssid[6];
struct wps wps;
u8 scan_block;
@@ -510,6 +512,9 @@ struct mwifiex_private {
u8 ap_11ac_enabled;
u32 mgmt_frame_mask;
struct mwifiex_roc_cfg roc_cfg;
+ bool scan_aborting;
+ u8 csa_chan;
+ unsigned long csa_expire_time;
};
enum mwifiex_ba_status {
@@ -730,6 +735,7 @@ struct mwifiex_adapter {
u16 max_mgmt_ie_index;
u8 scan_delay_cnt;
u8 empty_tx_q_cnt;
+ const struct firmware *cal_data;
/* 11AC */
u32 is_hw_11ac_capable;
@@ -1017,6 +1023,24 @@ static inline bool mwifiex_is_skb_mgmt_frame(struct sk_buff *skb)
return (*(u32 *)skb->data == PKT_TYPE_MGMT);
}
+/* This function retrieves channel closed for operation by Channel
+ * Switch Announcement.
+ */
+static inline u8
+mwifiex_11h_get_csa_closed_channel(struct mwifiex_private *priv)
+{
+ if (!priv->csa_chan)
+ return 0;
+
+ /* Clear csa channel, if DFS channel move time has passed */
+ if (jiffies > priv->csa_expire_time) {
+ priv->csa_chan = 0;
+ priv->csa_expire_time = 0;
+ }
+
+ return priv->csa_chan;
+}
+
int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
u32 func_init_shutdown);
int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8);
@@ -1115,6 +1139,12 @@ 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);
+void mwifiex_uap_del_sta_data(struct mwifiex_private *priv,
+ struct mwifiex_sta_node *node);
+
+void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
+ struct mwifiex_bssdescriptor *bss_desc);
+int mwifiex_11h_handle_event_chanswann(struct mwifiex_private *priv);
extern const struct ethtool_ops mwifiex_ethtool_ops;
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 9cf5d8f07df8..c447d9bd1aa9 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -391,6 +391,12 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
return 0;
}
+ if (bss_desc->chan_sw_ie_present) {
+ dev_err(adapter->dev,
+ "Don't connect to AP with WLAN_EID_CHANNEL_SWITCH\n");
+ return -1;
+ }
+
if (mwifiex_is_bss_wapi(priv, bss_desc)) {
dev_dbg(adapter->dev, "info: return success for WAPI AP\n");
return 0;
@@ -569,6 +575,9 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
return -1;
}
+ /* Check csa channel expiry before preparing scan list */
+ mwifiex_11h_get_csa_closed_channel(priv);
+
chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
/* Set the temp channel struct pointer to the start of the desired
@@ -598,6 +607,11 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
while (tlv_idx < max_chan_per_scan &&
tmp_chan_list->chan_number && !done_early) {
+ if (tmp_chan_list->chan_number == priv->csa_chan) {
+ tmp_chan_list++;
+ continue;
+ }
+
dev_dbg(priv->adapter->dev,
"info: Scan: Chan(%3d), Radio(%d),"
" Mode(%d, %d), Dur(%d)\n",
@@ -1169,6 +1183,19 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
bss_entry->erp_flags = *(current_ptr + 2);
break;
+ case WLAN_EID_PWR_CONSTRAINT:
+ bss_entry->local_constraint = *(current_ptr + 2);
+ bss_entry->sensed_11h = true;
+ break;
+
+ case WLAN_EID_CHANNEL_SWITCH:
+ bss_entry->chan_sw_ie_present = true;
+ case WLAN_EID_PWR_CAPABILITY:
+ case WLAN_EID_TPC_REPORT:
+ case WLAN_EID_QUIET:
+ bss_entry->sensed_11h = true;
+ break;
+
case WLAN_EID_EXT_SUPP_RATES:
/*
* Only process extended supported rate
@@ -1575,6 +1602,9 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
goto check_next_scan;
}
+ /* Check csa channel expiry before parsing scan response */
+ mwifiex_11h_get_csa_closed_channel(priv);
+
bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n",
bytes_left);
@@ -1727,6 +1757,13 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
struct ieee80211_channel *chan;
u8 band;
+ /* Skip entry if on csa closed channel */
+ if (channel == priv->csa_chan) {
+ dev_dbg(adapter->dev,
+ "Dropping entry on csa closed channel\n");
+ continue;
+ }
+
band = BAND_G;
if (chan_band_tlv) {
chan_band =
@@ -1784,22 +1821,17 @@ check_next_scan:
if (priv->report_scan_result)
priv->report_scan_result = false;
- if (priv->user_scan_cfg) {
- if (priv->scan_request) {
- dev_dbg(priv->adapter->dev,
- "info: notifying scan done\n");
- cfg80211_scan_done(priv->scan_request, 0);
- priv->scan_request = NULL;
- } else {
- dev_dbg(priv->adapter->dev,
- "info: scan already aborted\n");
- }
-
- kfree(priv->user_scan_cfg);
- priv->user_scan_cfg = NULL;
+ if (priv->scan_request) {
+ dev_dbg(adapter->dev, "info: notifying scan done\n");
+ cfg80211_scan_done(priv->scan_request, 0);
+ priv->scan_request = NULL;
+ } else {
+ priv->scan_aborting = false;
+ dev_dbg(adapter->dev, "info: scan already aborted\n");
}
} else {
- if (priv->user_scan_cfg && !priv->scan_request) {
+ if ((priv->scan_aborting && !priv->scan_request) ||
+ priv->scan_block) {
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
flags);
adapter->scan_delay_cnt = MWIFIEX_MAX_SCAN_DELAY_CNT;
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index 363ba31b58bf..5ee5ed02eccd 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -77,6 +77,17 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
+ if (id->driver_data) {
+ struct mwifiex_sdio_device *data = (void *)id->driver_data;
+
+ card->firmware = data->firmware;
+ card->reg = data->reg;
+ card->max_ports = data->max_ports;
+ card->mp_agg_pkt_limit = data->mp_agg_pkt_limit;
+ card->supports_sdio_new_mode = data->supports_sdio_new_mode;
+ card->has_control_mask = data->has_control_mask;
+ }
+
sdio_claim_host(func);
ret = sdio_enable_func(func);
sdio_release_host(func);
@@ -251,12 +262,19 @@ static int mwifiex_sdio_resume(struct device *dev)
#define SDIO_DEVICE_ID_MARVELL_8787 (0x9119)
/* Device ID for SD8797 */
#define SDIO_DEVICE_ID_MARVELL_8797 (0x9129)
+/* Device ID for SD8897 */
+#define SDIO_DEVICE_ID_MARVELL_8897 (0x912d)
/* WLAN IDs */
static const struct sdio_device_id mwifiex_ids[] = {
- {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8786)},
- {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)},
- {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797)},
+ {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8786),
+ .driver_data = (unsigned long) &mwifiex_sdio_sd8786},
+ {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787),
+ .driver_data = (unsigned long) &mwifiex_sdio_sd8787},
+ {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797),
+ .driver_data = (unsigned long) &mwifiex_sdio_sd8797},
+ {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8897),
+ .driver_data = (unsigned long) &mwifiex_sdio_sd8897},
{},
};
@@ -282,13 +300,13 @@ static struct sdio_driver mwifiex_sdio = {
* This function writes data into SDIO card register.
*/
static int
-mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u32 data)
+mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u8 data)
{
struct sdio_mmc_card *card = adapter->card;
int ret = -1;
sdio_claim_host(card->func);
- sdio_writeb(card->func, (u8) data, reg, &ret);
+ sdio_writeb(card->func, data, reg, &ret);
sdio_release_host(card->func);
return ret;
@@ -298,7 +316,7 @@ mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u32 data)
* This function reads data from SDIO card register.
*/
static int
-mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u32 *data)
+mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u8 *data)
{
struct sdio_mmc_card *card = adapter->card;
int ret = -1;
@@ -400,7 +418,40 @@ static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
}
/*
- * This function initializes the IO ports.
+ * This function is used to initialize IO ports for the
+ * chipsets supporting SDIO new mode eg SD8897.
+ */
+static int mwifiex_init_sdio_new_mode(struct mwifiex_adapter *adapter)
+{
+ u8 reg;
+
+ adapter->ioport = MEM_PORT;
+
+ /* enable sdio new mode */
+ if (mwifiex_read_reg(adapter, CARD_CONFIG_2_1_REG, &reg))
+ return -1;
+ if (mwifiex_write_reg(adapter, CARD_CONFIG_2_1_REG,
+ reg | CMD53_NEW_MODE))
+ return -1;
+
+ /* Configure cmd port and enable reading rx length from the register */
+ if (mwifiex_read_reg(adapter, CMD_CONFIG_0, &reg))
+ return -1;
+ if (mwifiex_write_reg(adapter, CMD_CONFIG_0, reg | CMD_PORT_RD_LEN_EN))
+ return -1;
+
+ /* Enable Dnld/Upld ready auto reset for cmd port after cmd53 is
+ * completed
+ */
+ if (mwifiex_read_reg(adapter, CMD_CONFIG_1, &reg))
+ return -1;
+ if (mwifiex_write_reg(adapter, CMD_CONFIG_1, reg | CMD_PORT_AUTO_EN))
+ return -1;
+
+ return 0;
+}
+
+/* This function initializes the IO ports.
*
* The following operations are performed -
* - Read the IO ports (0, 1 and 2)
@@ -409,10 +460,17 @@ static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
*/
static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter)
{
- u32 reg;
+ u8 reg;
+ struct sdio_mmc_card *card = adapter->card;
adapter->ioport = 0;
+ if (card->supports_sdio_new_mode) {
+ if (mwifiex_init_sdio_new_mode(adapter))
+ return -1;
+ goto cont;
+ }
+
/* Read the IO port */
if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, &reg))
adapter->ioport |= (reg & 0xff);
@@ -428,19 +486,19 @@ static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter)
adapter->ioport |= ((reg & 0xff) << 16);
else
return -1;
-
+cont:
pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport);
/* Set Host interrupt reset to read to clear */
if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, &reg))
mwifiex_write_reg(adapter, HOST_INT_RSR_REG,
- reg | SDIO_INT_MASK);
+ reg | card->reg->sdio_int_mask);
else
return -1;
/* Dnld/Upld ready set to auto reset */
- if (!mwifiex_read_reg(adapter, CARD_MISC_CFG_REG, &reg))
- mwifiex_write_reg(adapter, CARD_MISC_CFG_REG,
+ if (!mwifiex_read_reg(adapter, card->reg->card_misc_cfg_reg, &reg))
+ mwifiex_write_reg(adapter, card->reg->card_misc_cfg_reg,
reg | AUTO_RE_ENABLE_INT);
else
return -1;
@@ -486,34 +544,42 @@ static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter,
static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port)
{
struct sdio_mmc_card *card = adapter->card;
- u16 rd_bitmap = card->mp_rd_bitmap;
+ const struct mwifiex_sdio_card_reg *reg = card->reg;
+ u32 rd_bitmap = card->mp_rd_bitmap;
- dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%04x\n", rd_bitmap);
+ dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%08x\n", rd_bitmap);
- if (!(rd_bitmap & (CTRL_PORT_MASK | DATA_PORT_MASK)))
- return -1;
+ if (card->supports_sdio_new_mode) {
+ if (!(rd_bitmap & reg->data_port_mask))
+ return -1;
+ } else {
+ if (!(rd_bitmap & (CTRL_PORT_MASK | reg->data_port_mask)))
+ return -1;
+ }
- if (card->mp_rd_bitmap & CTRL_PORT_MASK) {
- card->mp_rd_bitmap &= (u16) (~CTRL_PORT_MASK);
+ if ((card->has_control_mask) &&
+ (card->mp_rd_bitmap & CTRL_PORT_MASK)) {
+ card->mp_rd_bitmap &= (u32) (~CTRL_PORT_MASK);
*port = CTRL_PORT;
- dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%04x\n",
+ dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%08x\n",
*port, card->mp_rd_bitmap);
- } else {
- if (card->mp_rd_bitmap & (1 << card->curr_rd_port)) {
- card->mp_rd_bitmap &= (u16)
- (~(1 << card->curr_rd_port));
- *port = card->curr_rd_port;
+ return 0;
+ }
- if (++card->curr_rd_port == MAX_PORT)
- card->curr_rd_port = 1;
- } else {
- return -1;
- }
+ if (!(card->mp_rd_bitmap & (1 << card->curr_rd_port)))
+ return -1;
+
+ /* We are now handling the SDIO data ports */
+ card->mp_rd_bitmap &= (u32)(~(1 << card->curr_rd_port));
+ *port = card->curr_rd_port;
+
+ if (++card->curr_rd_port == card->max_ports)
+ card->curr_rd_port = reg->start_rd_port;
+
+ dev_dbg(adapter->dev,
+ "data: port=%d mp_rd_bitmap=0x%08x -> 0x%08x\n",
+ *port, rd_bitmap, card->mp_rd_bitmap);
- dev_dbg(adapter->dev,
- "data: port=%d mp_rd_bitmap=0x%04x -> 0x%04x\n",
- *port, rd_bitmap, card->mp_rd_bitmap);
- }
return 0;
}
@@ -524,35 +590,45 @@ static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port)
* increased (provided it does not reach the maximum limit, in which
* case it is reset to 1)
*/
-static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u8 *port)
+static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u32 *port)
{
struct sdio_mmc_card *card = adapter->card;
- u16 wr_bitmap = card->mp_wr_bitmap;
+ const struct mwifiex_sdio_card_reg *reg = card->reg;
+ u32 wr_bitmap = card->mp_wr_bitmap;
- dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%04x\n", wr_bitmap);
+ dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%08x\n", wr_bitmap);
- if (!(wr_bitmap & card->mp_data_port_mask))
+ if (card->supports_sdio_new_mode &&
+ !(wr_bitmap & reg->data_port_mask)) {
+ adapter->data_sent = true;
+ return -EBUSY;
+ } else if (!card->supports_sdio_new_mode &&
+ !(wr_bitmap & card->mp_data_port_mask)) {
return -1;
+ }
if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) {
- card->mp_wr_bitmap &= (u16) (~(1 << card->curr_wr_port));
+ card->mp_wr_bitmap &= (u32) (~(1 << card->curr_wr_port));
*port = card->curr_wr_port;
- if (++card->curr_wr_port == card->mp_end_port)
- card->curr_wr_port = 1;
+ if (((card->supports_sdio_new_mode) &&
+ (++card->curr_wr_port == card->max_ports)) ||
+ ((!card->supports_sdio_new_mode) &&
+ (++card->curr_wr_port == card->mp_end_port)))
+ card->curr_wr_port = reg->start_wr_port;
} else {
adapter->data_sent = true;
return -EBUSY;
}
- if (*port == CTRL_PORT) {
- dev_err(adapter->dev, "invalid data port=%d cur port=%d"
- " mp_wr_bitmap=0x%04x -> 0x%04x\n",
+ if ((card->has_control_mask) && (*port == CTRL_PORT)) {
+ dev_err(adapter->dev,
+ "invalid data port=%d cur port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
*port, card->curr_wr_port, wr_bitmap,
card->mp_wr_bitmap);
return -1;
}
- dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%04x -> 0x%04x\n",
+ dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
*port, wr_bitmap, card->mp_wr_bitmap);
return 0;
@@ -564,11 +640,12 @@ static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u8 *port)
static int
mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits)
{
+ struct sdio_mmc_card *card = adapter->card;
u32 tries;
- u32 cs;
+ u8 cs;
for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
- if (mwifiex_read_reg(adapter, CARD_STATUS_REG, &cs))
+ if (mwifiex_read_reg(adapter, card->reg->poll_reg, &cs))
break;
else if ((cs & bits) == bits)
return 0;
@@ -587,12 +664,14 @@ mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits)
static int
mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat)
{
- u32 fws0, fws1;
+ struct sdio_mmc_card *card = adapter->card;
+ const struct mwifiex_sdio_card_reg *reg = card->reg;
+ u8 fws0, fws1;
- if (mwifiex_read_reg(adapter, CARD_FW_STATUS0_REG, &fws0))
+ if (mwifiex_read_reg(adapter, reg->status_reg_0, &fws0))
return -1;
- if (mwifiex_read_reg(adapter, CARD_FW_STATUS1_REG, &fws1))
+ if (mwifiex_read_reg(adapter, reg->status_reg_1, &fws1))
return -1;
*dat = (u16) ((fws1 << 8) | fws0);
@@ -608,14 +687,14 @@ mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat)
*/
static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
{
- u32 host_int_mask;
+ u8 host_int_mask, host_int_disable = HOST_INT_DISABLE;
/* Read back the host_int_mask register */
if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask))
return -1;
/* Update with the mask and write back to the register */
- host_int_mask &= ~HOST_INT_DISABLE;
+ host_int_mask &= ~host_int_disable;
if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) {
dev_err(adapter->dev, "disable host interrupt failed\n");
@@ -633,8 +712,11 @@ static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
*/
static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter)
{
+ struct sdio_mmc_card *card = adapter->card;
+
/* Simply write the mask to the register */
- if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, HOST_INT_ENABLE)) {
+ if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG,
+ card->reg->host_int_enable)) {
dev_err(adapter->dev, "enable host interrupt failed\n");
return -1;
}
@@ -686,11 +768,13 @@ static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter,
static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
struct mwifiex_fw_image *fw)
{
+ struct sdio_mmc_card *card = adapter->card;
+ const struct mwifiex_sdio_card_reg *reg = card->reg;
int ret;
u8 *firmware = fw->fw_buf;
u32 firmware_len = fw->fw_len;
u32 offset = 0;
- u32 base0, base1;
+ u8 base0, base1;
u8 *fwbuf;
u16 len = 0;
u32 txlen, tx_blocks = 0, tries;
@@ -727,7 +811,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
break;
for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
- ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_0,
+ ret = mwifiex_read_reg(adapter, reg->base_0_reg,
&base0);
if (ret) {
dev_err(adapter->dev,
@@ -736,7 +820,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
base0, base0);
goto done;
}
- ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_1,
+ ret = mwifiex_read_reg(adapter, reg->base_1_reg,
&base1);
if (ret) {
dev_err(adapter->dev,
@@ -828,10 +912,11 @@ done:
static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
u32 poll_num)
{
+ struct sdio_mmc_card *card = adapter->card;
int ret = 0;
u16 firmware_stat;
u32 tries;
- u32 winner_status;
+ u8 winner_status;
/* Wait for firmware initialization event */
for (tries = 0; tries < poll_num; tries++) {
@@ -849,7 +934,7 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
if (ret) {
if (mwifiex_read_reg
- (adapter, CARD_FW_STATUS0_REG, &winner_status))
+ (adapter, card->reg->status_reg_0, &winner_status))
winner_status = 0;
if (winner_status)
@@ -866,12 +951,12 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
{
struct sdio_mmc_card *card = adapter->card;
- u32 sdio_ireg;
+ u8 sdio_ireg;
unsigned long flags;
- if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS,
- REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK,
- 0)) {
+ if (mwifiex_read_data_sync(adapter, card->mp_regs,
+ card->reg->max_mp_regs,
+ REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0)) {
dev_err(adapter->dev, "read mp_regs failed\n");
return;
}
@@ -880,6 +965,9 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
if (sdio_ireg) {
/*
* DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+ * For SDIO new mode CMD port interrupts
+ * DN_LD_CMD_PORT_HOST_INT_STATUS and/or
+ * UP_LD_CMD_PORT_HOST_INT_STATUS
* Clear the interrupt status register
*/
dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg);
@@ -1003,11 +1091,11 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
s32 f_aggr_cur = 0;
struct sk_buff *skb_deaggr;
u32 pind;
- u32 pkt_len, pkt_type = 0;
+ u32 pkt_len, pkt_type, mport;
u8 *curr_ptr;
u32 rx_len = skb->len;
- if (port == CTRL_PORT) {
+ if ((card->has_control_mask) && (port == CTRL_PORT)) {
/* Read the command Resp without aggr */
dev_dbg(adapter->dev, "info: %s: no aggregation for cmd "
"response\n", __func__);
@@ -1024,7 +1112,10 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
goto rx_curr_single;
}
- if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) {
+ if ((!card->has_control_mask && (card->mp_rd_bitmap &
+ card->reg->data_port_mask)) ||
+ (card->has_control_mask && (card->mp_rd_bitmap &
+ (~((u32) CTRL_PORT_MASK))))) {
/* Some more data RX pending */
dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__);
@@ -1060,10 +1151,10 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
if (f_aggr_cur) {
dev_dbg(adapter->dev, "info: current packet aggregation\n");
/* Curr pkt can be aggregated */
- MP_RX_AGGR_SETUP(card, skb, port);
+ mp_rx_aggr_setup(card, skb, port);
if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) ||
- MP_RX_AGGR_PORT_LIMIT_REACHED(card)) {
+ mp_rx_aggr_port_limit_reached(card)) {
dev_dbg(adapter->dev, "info: %s: aggregated packet "
"limit reached\n", __func__);
/* No more pkts allowed in Aggr buf, rx it */
@@ -1076,11 +1167,28 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n",
card->mpa_rx.pkt_cnt);
+ if (card->supports_sdio_new_mode) {
+ int i;
+ u32 port_count;
+
+ for (i = 0, port_count = 0; i < card->max_ports; i++)
+ if (card->mpa_rx.ports & BIT(i))
+ port_count++;
+
+ /* Reading data from "start_port + 0" to "start_port +
+ * port_count -1", so decrease the count by 1
+ */
+ port_count--;
+ mport = (adapter->ioport | SDIO_MPA_ADDR_BASE |
+ (port_count << 8)) + card->mpa_rx.start_port;
+ } else {
+ mport = (adapter->ioport | SDIO_MPA_ADDR_BASE |
+ (card->mpa_rx.ports << 4)) +
+ card->mpa_rx.start_port;
+ }
+
if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf,
- card->mpa_rx.buf_len,
- (adapter->ioport | 0x1000 |
- (card->mpa_rx.ports << 4)) +
- card->mpa_rx.start_port, 1))
+ card->mpa_rx.buf_len, mport, 1))
goto error;
curr_ptr = card->mpa_rx.buf;
@@ -1167,6 +1275,7 @@ error:
static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
{
struct sdio_mmc_card *card = adapter->card;
+ const struct mwifiex_sdio_card_reg *reg = card->reg;
int ret = 0;
u8 sdio_ireg;
struct sk_buff *skb;
@@ -1175,6 +1284,8 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
u32 rx_blocks;
u16 rx_len;
unsigned long flags;
+ u32 bitmap;
+ u8 cr;
spin_lock_irqsave(&adapter->int_lock, flags);
sdio_ireg = adapter->int_status;
@@ -1184,10 +1295,60 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
if (!sdio_ireg)
return ret;
+ /* Following interrupt is only for SDIO new mode */
+ if (sdio_ireg & DN_LD_CMD_PORT_HOST_INT_STATUS && adapter->cmd_sent)
+ adapter->cmd_sent = false;
+
+ /* Following interrupt is only for SDIO new mode */
+ if (sdio_ireg & UP_LD_CMD_PORT_HOST_INT_STATUS) {
+ u32 pkt_type;
+
+ /* read the len of control packet */
+ rx_len = card->mp_regs[CMD_RD_LEN_1] << 8;
+ rx_len |= (u16) card->mp_regs[CMD_RD_LEN_0];
+ rx_blocks = DIV_ROUND_UP(rx_len, MWIFIEX_SDIO_BLOCK_SIZE);
+ if (rx_len <= INTF_HEADER_LEN ||
+ (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) >
+ MWIFIEX_RX_DATA_BUF_SIZE)
+ return -1;
+ rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE);
+
+ skb = dev_alloc_skb(rx_len);
+ if (!skb)
+ return -1;
+
+ skb_put(skb, rx_len);
+
+ if (mwifiex_sdio_card_to_host(adapter, &pkt_type, skb->data,
+ skb->len, adapter->ioport |
+ CMD_PORT_SLCT)) {
+ dev_err(adapter->dev,
+ "%s: failed to card_to_host", __func__);
+ dev_kfree_skb_any(skb);
+ goto term_cmd;
+ }
+
+ if ((pkt_type != MWIFIEX_TYPE_CMD) &&
+ (pkt_type != MWIFIEX_TYPE_EVENT))
+ dev_err(adapter->dev,
+ "%s:Received wrong packet on cmd port",
+ __func__);
+
+ mwifiex_decode_rx_packet(adapter, skb, pkt_type);
+ }
+
if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
- card->mp_wr_bitmap = ((u16) card->mp_regs[WR_BITMAP_U]) << 8;
- card->mp_wr_bitmap |= (u16) card->mp_regs[WR_BITMAP_L];
- dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%04x\n",
+ bitmap = (u32) card->mp_regs[reg->wr_bitmap_l];
+ bitmap |= ((u32) card->mp_regs[reg->wr_bitmap_u]) << 8;
+ if (card->supports_sdio_new_mode) {
+ bitmap |=
+ ((u32) card->mp_regs[reg->wr_bitmap_1l]) << 16;
+ bitmap |=
+ ((u32) card->mp_regs[reg->wr_bitmap_1u]) << 24;
+ }
+ card->mp_wr_bitmap = bitmap;
+
+ dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%x\n",
card->mp_wr_bitmap);
if (adapter->data_sent &&
(card->mp_wr_bitmap & card->mp_data_port_mask)) {
@@ -1200,11 +1361,11 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
/* As firmware will not generate download ready interrupt if the port
updated is command port only, cmd_sent should be done for any SDIO
interrupt. */
- if (adapter->cmd_sent) {
+ if (card->has_control_mask && adapter->cmd_sent) {
/* Check if firmware has attach buffer at command port and
update just that in wr_bit_map. */
card->mp_wr_bitmap |=
- (u16) card->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK;
+ (u32) card->mp_regs[reg->wr_bitmap_l] & CTRL_PORT_MASK;
if (card->mp_wr_bitmap & CTRL_PORT_MASK)
adapter->cmd_sent = false;
}
@@ -1212,9 +1373,16 @@ 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);
if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
- card->mp_rd_bitmap = ((u16) card->mp_regs[RD_BITMAP_U]) << 8;
- card->mp_rd_bitmap |= (u16) card->mp_regs[RD_BITMAP_L];
- dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%04x\n",
+ bitmap = (u32) card->mp_regs[reg->rd_bitmap_l];
+ bitmap |= ((u32) card->mp_regs[reg->rd_bitmap_u]) << 8;
+ if (card->supports_sdio_new_mode) {
+ bitmap |=
+ ((u32) card->mp_regs[reg->rd_bitmap_1l]) << 16;
+ bitmap |=
+ ((u32) card->mp_regs[reg->rd_bitmap_1u]) << 24;
+ }
+ card->mp_rd_bitmap = bitmap;
+ dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%x\n",
card->mp_rd_bitmap);
while (true) {
@@ -1224,8 +1392,8 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
"info: no more rd_port available\n");
break;
}
- len_reg_l = RD_LEN_P0_L + (port << 1);
- len_reg_u = RD_LEN_P0_U + (port << 1);
+ len_reg_l = reg->rd_len_p0_l + (port << 1);
+ len_reg_u = reg->rd_len_p0_u + (port << 1);
rx_len = ((u16) card->mp_regs[len_reg_u]) << 8;
rx_len |= (u16) card->mp_regs[len_reg_l];
dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n",
@@ -1257,37 +1425,33 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb,
port)) {
- u32 cr = 0;
-
dev_err(adapter->dev, "card_to_host_mpa failed:"
" int status=%#x\n", sdio_ireg);
- if (mwifiex_read_reg(adapter,
- CONFIGURATION_REG, &cr))
- dev_err(adapter->dev,
- "read CFG reg failed\n");
-
- dev_dbg(adapter->dev,
- "info: CFG reg val = %d\n", cr);
- if (mwifiex_write_reg(adapter,
- CONFIGURATION_REG,
- (cr | 0x04)))
- dev_err(adapter->dev,
- "write CFG reg failed\n");
-
- dev_dbg(adapter->dev, "info: write success\n");
- if (mwifiex_read_reg(adapter,
- CONFIGURATION_REG, &cr))
- dev_err(adapter->dev,
- "read CFG reg failed\n");
-
- dev_dbg(adapter->dev,
- "info: CFG reg val =%x\n", cr);
- return -1;
+ goto term_cmd;
}
}
}
return 0;
+
+term_cmd:
+ /* terminate cmd */
+ if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr))
+ dev_err(adapter->dev, "read CFG reg failed\n");
+ else
+ dev_dbg(adapter->dev, "info: CFG reg val = %d\n", cr);
+
+ if (mwifiex_write_reg(adapter, CONFIGURATION_REG, (cr | 0x04)))
+ dev_err(adapter->dev, "write CFG reg failed\n");
+ else
+ dev_dbg(adapter->dev, "info: write success\n");
+
+ if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr))
+ dev_err(adapter->dev, "read CFG reg failed\n");
+ else
+ dev_dbg(adapter->dev, "info: CFG reg val =%x\n", cr);
+
+ return -1;
}
/*
@@ -1305,7 +1469,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
* and return.
*/
static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
- u8 *payload, u32 pkt_len, u8 port,
+ u8 *payload, u32 pkt_len, u32 port,
u32 next_pkt_len)
{
struct sdio_mmc_card *card = adapter->card;
@@ -1314,8 +1478,11 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
s32 f_send_cur_buf = 0;
s32 f_precopy_cur_buf = 0;
s32 f_postcopy_cur_buf = 0;
+ u32 mport;
- if ((!card->mpa_tx.enabled) || (port == CTRL_PORT)) {
+ if (!card->mpa_tx.enabled ||
+ (card->has_control_mask && (port == CTRL_PORT)) ||
+ (card->supports_sdio_new_mode && (port == CMD_PORT_SLCT))) {
dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n",
__func__);
@@ -1329,7 +1496,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
__func__);
if (MP_TX_AGGR_IN_PROGRESS(card)) {
- if (!MP_TX_AGGR_PORT_LIMIT_REACHED(card) &&
+ if (!mp_tx_aggr_port_limit_reached(card) &&
MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) {
f_precopy_cur_buf = 1;
@@ -1342,7 +1509,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
/* No room in Aggr buf, send it */
f_send_aggr_buf = 1;
- if (MP_TX_AGGR_PORT_LIMIT_REACHED(card) ||
+ if (mp_tx_aggr_port_limit_reached(card) ||
!(card->mp_wr_bitmap &
(1 << card->curr_wr_port)))
f_send_cur_buf = 1;
@@ -1381,7 +1548,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port);
if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) ||
- MP_TX_AGGR_PORT_LIMIT_REACHED(card))
+ mp_tx_aggr_port_limit_reached(card))
/* No more pkts allowed in Aggr buf, send it */
f_send_aggr_buf = 1;
}
@@ -1390,11 +1557,28 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n",
__func__,
card->mpa_tx.start_port, card->mpa_tx.ports);
+ if (card->supports_sdio_new_mode) {
+ u32 port_count;
+ int i;
+
+ for (i = 0, port_count = 0; i < card->max_ports; i++)
+ if (card->mpa_tx.ports & BIT(i))
+ port_count++;
+
+ /* Writing data from "start_port + 0" to "start_port +
+ * port_count -1", so decrease the count by 1
+ */
+ port_count--;
+ mport = (adapter->ioport | SDIO_MPA_ADDR_BASE |
+ (port_count << 8)) + card->mpa_tx.start_port;
+ } else {
+ mport = (adapter->ioport | SDIO_MPA_ADDR_BASE |
+ (card->mpa_tx.ports << 4)) +
+ card->mpa_tx.start_port;
+ }
+
ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf,
- card->mpa_tx.buf_len,
- (adapter->ioport | 0x1000 |
- (card->mpa_tx.ports << 4)) +
- card->mpa_tx.start_port);
+ card->mpa_tx.buf_len, mport);
MP_TX_AGGR_BUF_RESET(card);
}
@@ -1434,7 +1618,7 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
int ret;
u32 buf_block_len;
u32 blk_size;
- u8 port = CTRL_PORT;
+ u32 port = CTRL_PORT;
u8 *payload = (u8 *)skb->data;
u32 pkt_len = skb->len;
@@ -1465,6 +1649,9 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
pkt_len > MWIFIEX_UPLD_SIZE)
dev_err(adapter->dev, "%s: payload=%p, nb=%d\n",
__func__, payload, pkt_len);
+
+ if (card->supports_sdio_new_mode)
+ port = CMD_PORT_SLCT;
}
/* Transfer data to card */
@@ -1586,18 +1773,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
adapter->dev = &func->dev;
- switch (func->device) {
- case SDIO_DEVICE_ID_MARVELL_8786:
- strcpy(adapter->fw_name, SD8786_DEFAULT_FW_NAME);
- break;
- case SDIO_DEVICE_ID_MARVELL_8797:
- strcpy(adapter->fw_name, SD8797_DEFAULT_FW_NAME);
- break;
- case SDIO_DEVICE_ID_MARVELL_8787:
- default:
- strcpy(adapter->fw_name, SD8787_DEFAULT_FW_NAME);
- break;
- }
+ strcpy(adapter->fw_name, card->firmware);
return 0;
@@ -1626,8 +1802,9 @@ disable_func:
static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
{
struct sdio_mmc_card *card = adapter->card;
+ const struct mwifiex_sdio_card_reg *reg = card->reg;
int ret;
- u32 sdio_ireg;
+ u8 sdio_ireg;
/*
* Read the HOST_INT_STATUS_REG for ACK the first interrupt got
@@ -1645,30 +1822,35 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
/* Initialize SDIO variables in card */
card->mp_rd_bitmap = 0;
card->mp_wr_bitmap = 0;
- card->curr_rd_port = 1;
- card->curr_wr_port = 1;
+ card->curr_rd_port = reg->start_rd_port;
+ card->curr_wr_port = reg->start_wr_port;
- card->mp_data_port_mask = DATA_PORT_MASK;
+ card->mp_data_port_mask = reg->data_port_mask;
card->mpa_tx.buf_len = 0;
card->mpa_tx.pkt_cnt = 0;
card->mpa_tx.start_port = 0;
card->mpa_tx.enabled = 1;
- card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+ card->mpa_tx.pkt_aggr_limit = card->mp_agg_pkt_limit;
card->mpa_rx.buf_len = 0;
card->mpa_rx.pkt_cnt = 0;
card->mpa_rx.start_port = 0;
card->mpa_rx.enabled = 1;
- card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+ card->mpa_rx.pkt_aggr_limit = card->mp_agg_pkt_limit;
/* Allocate buffers for SDIO MP-A */
- card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL);
+ card->mp_regs = kzalloc(reg->max_mp_regs, GFP_KERNEL);
if (!card->mp_regs)
return -ENOMEM;
+ /* Allocate skb pointer buffers */
+ card->mpa_rx.skb_arr = kzalloc((sizeof(void *)) *
+ card->mp_agg_pkt_limit, GFP_KERNEL);
+ card->mpa_rx.len_arr = kzalloc(sizeof(*card->mpa_rx.len_arr) *
+ card->mp_agg_pkt_limit, GFP_KERNEL);
ret = mwifiex_alloc_sdio_mpa_buffers(adapter,
SDIO_MP_TX_AGGR_DEF_BUF_SIZE,
SDIO_MP_RX_AGGR_DEF_BUF_SIZE);
@@ -1705,6 +1887,8 @@ static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter)
struct sdio_mmc_card *card = adapter->card;
kfree(card->mp_regs);
+ kfree(card->mpa_rx.skb_arr);
+ kfree(card->mpa_rx.len_arr);
kfree(card->mpa_tx.buf);
kfree(card->mpa_rx.buf);
}
@@ -1716,16 +1900,20 @@ static void
mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port)
{
struct sdio_mmc_card *card = adapter->card;
+ const struct mwifiex_sdio_card_reg *reg = card->reg;
int i;
card->mp_end_port = port;
- card->mp_data_port_mask = DATA_PORT_MASK;
+ card->mp_data_port_mask = reg->data_port_mask;
- for (i = 1; i <= MAX_PORT - card->mp_end_port; i++)
- card->mp_data_port_mask &= ~(1 << (MAX_PORT - i));
+ if (reg->start_wr_port) {
+ for (i = 1; i <= card->max_ports - card->mp_end_port; i++)
+ card->mp_data_port_mask &=
+ ~(1 << (card->max_ports - i));
+ }
- card->curr_wr_port = 1;
+ card->curr_wr_port = reg->start_wr_port;
dev_dbg(adapter->dev, "cmd: mp_end_port %d, data port mask 0x%x\n",
port, card->mp_data_port_mask);
@@ -1831,3 +2019,4 @@ MODULE_LICENSE("GPL v2");
MODULE_FIRMWARE(SD8786_DEFAULT_FW_NAME);
MODULE_FIRMWARE(SD8787_DEFAULT_FW_NAME);
MODULE_FIRMWARE(SD8797_DEFAULT_FW_NAME);
+MODULE_FIRMWARE(SD8897_DEFAULT_FW_NAME);
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h
index 8cc5468654b4..6d51dfdd8251 100644
--- a/drivers/net/wireless/mwifiex/sdio.h
+++ b/drivers/net/wireless/mwifiex/sdio.h
@@ -32,30 +32,37 @@
#define SD8786_DEFAULT_FW_NAME "mrvl/sd8786_uapsta.bin"
#define SD8787_DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin"
#define SD8797_DEFAULT_FW_NAME "mrvl/sd8797_uapsta.bin"
+#define SD8897_DEFAULT_FW_NAME "mrvl/sd8897_uapsta.bin"
#define BLOCK_MODE 1
#define BYTE_MODE 0
#define REG_PORT 0
-#define RD_BITMAP_L 0x04
-#define RD_BITMAP_U 0x05
-#define WR_BITMAP_L 0x06
-#define WR_BITMAP_U 0x07
-#define RD_LEN_P0_L 0x08
-#define RD_LEN_P0_U 0x09
#define MWIFIEX_SDIO_IO_PORT_MASK 0xfffff
#define MWIFIEX_SDIO_BYTE_MODE_MASK 0x80000000
+#define SDIO_MPA_ADDR_BASE 0x1000
#define CTRL_PORT 0
#define CTRL_PORT_MASK 0x0001
-#define DATA_PORT_MASK 0xfffe
-#define MAX_MP_REGS 64
-#define MAX_PORT 16
-
-#define SDIO_MP_AGGR_DEF_PKT_LIMIT 8
+#define CMD_PORT_UPLD_INT_MASK (0x1U<<6)
+#define CMD_PORT_DNLD_INT_MASK (0x1U<<7)
+#define HOST_TERM_CMD53 (0x1U << 2)
+#define REG_PORT 0
+#define MEM_PORT 0x10000
+#define CMD_RD_LEN_0 0xB4
+#define CMD_RD_LEN_1 0xB5
+#define CARD_CONFIG_2_1_REG 0xCD
+#define CMD53_NEW_MODE (0x1U << 0)
+#define CMD_CONFIG_0 0xB8
+#define CMD_PORT_RD_LEN_EN (0x1U << 2)
+#define CMD_CONFIG_1 0xB9
+#define CMD_PORT_AUTO_EN (0x1U << 0)
+#define CMD_PORT_SLCT 0x8000
+#define UP_LD_CMD_PORT_HOST_INT_STATUS (0x40U)
+#define DN_LD_CMD_PORT_HOST_INT_STATUS (0x80U)
#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (8192) /* 8K */
@@ -75,14 +82,8 @@
/* Host Control Registers : Configuration */
#define CONFIGURATION_REG 0x00
-/* Host Control Registers : Host without Command 53 finish host*/
-#define HOST_TO_CARD_EVENT (0x1U << 3)
-/* Host Control Registers : Host without Command 53 finish host */
-#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2)
/* Host Control Registers : Host power up */
#define HOST_POWER_UP (0x1U << 1)
-/* Host Control Registers : Host power down */
-#define HOST_POWER_DOWN (0x1U << 0)
/* Host Control Registers : Host interrupt mask */
#define HOST_INT_MASK_REG 0x02
@@ -90,8 +91,7 @@
#define UP_LD_HOST_INT_MASK (0x1U)
/* Host Control Registers : Download host interrupt mask */
#define DN_LD_HOST_INT_MASK (0x2U)
-/* Enable Host interrupt mask */
-#define HOST_INT_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK)
+
/* Disable Host interrupt mask */
#define HOST_INT_DISABLE 0xff
@@ -104,74 +104,15 @@
/* Host Control Registers : Host interrupt RSR */
#define HOST_INT_RSR_REG 0x01
-/* Host Control Registers : Upload host interrupt RSR */
-#define UP_LD_HOST_INT_RSR (0x1U)
-#define SDIO_INT_MASK 0x3F
/* Host Control Registers : Host interrupt status */
#define HOST_INT_STATUS_REG 0x28
-/* Host Control Registers : Upload CRC error */
-#define UP_LD_CRC_ERR (0x1U << 2)
-/* Host Control Registers : Upload restart */
-#define UP_LD_RESTART (0x1U << 1)
-/* Host Control Registers : Download restart */
-#define DN_LD_RESTART (0x1U << 0)
-
-/* Card Control Registers : Card status register */
-#define CARD_STATUS_REG 0x30
+
/* Card Control Registers : Card I/O ready */
#define CARD_IO_READY (0x1U << 3)
-/* Card Control Registers : CIS card ready */
-#define CIS_CARD_RDY (0x1U << 2)
-/* Card Control Registers : Upload card ready */
-#define UP_LD_CARD_RDY (0x1U << 1)
/* Card Control Registers : Download card ready */
#define DN_LD_CARD_RDY (0x1U << 0)
-/* Card Control Registers : Host interrupt mask register */
-#define HOST_INTERRUPT_MASK_REG 0x34
-/* Card Control Registers : Host power interrupt mask */
-#define HOST_POWER_INT_MASK (0x1U << 3)
-/* Card Control Registers : Abort card interrupt mask */
-#define ABORT_CARD_INT_MASK (0x1U << 2)
-/* Card Control Registers : Upload card interrupt mask */
-#define UP_LD_CARD_INT_MASK (0x1U << 1)
-/* Card Control Registers : Download card interrupt mask */
-#define DN_LD_CARD_INT_MASK (0x1U << 0)
-
-/* Card Control Registers : Card interrupt status register */
-#define CARD_INTERRUPT_STATUS_REG 0x38
-/* Card Control Registers : Power up interrupt */
-#define POWER_UP_INT (0x1U << 4)
-/* Card Control Registers : Power down interrupt */
-#define POWER_DOWN_INT (0x1U << 3)
-
-/* Card Control Registers : Card interrupt RSR register */
-#define CARD_INTERRUPT_RSR_REG 0x3c
-/* Card Control Registers : Power up RSR */
-#define POWER_UP_RSR (0x1U << 4)
-/* Card Control Registers : Power down RSR */
-#define POWER_DOWN_RSR (0x1U << 3)
-
-/* Card Control Registers : Miscellaneous Configuration Register */
-#define CARD_MISC_CFG_REG 0x6C
-
-/* Host F1 read base 0 */
-#define HOST_F1_RD_BASE_0 0x0040
-/* Host F1 read base 1 */
-#define HOST_F1_RD_BASE_1 0x0041
-/* Host F1 card ready */
-#define HOST_F1_CARD_RDY 0x0020
-
-/* Firmware status 0 register */
-#define CARD_FW_STATUS0_REG 0x60
-/* Firmware status 1 register */
-#define CARD_FW_STATUS1_REG 0x61
-/* Rx length register */
-#define CARD_RX_LEN_REG 0x62
-/* Rx unit register */
-#define CARD_RX_UNIT_REG 0x63
-
/* Max retry number of CMD53 write */
#define MAX_WRITE_IOMEM_RETRY 2
@@ -192,7 +133,8 @@
if (a->mpa_tx.start_port <= port) \
a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt)); \
else \
- a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT - \
+ a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+ \
+ (a->max_ports - \
a->mp_end_port))); \
a->mpa_tx.pkt_cnt++; \
} while (0)
@@ -201,12 +143,6 @@
#define MP_TX_AGGR_PKT_LIMIT_REACHED(a) \
(a->mpa_tx.pkt_cnt == a->mpa_tx.pkt_aggr_limit)
-/* SDIO Tx aggregation port limit ? */
-#define MP_TX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_wr_port < \
- a->mpa_tx.start_port) && (((MAX_PORT - \
- a->mpa_tx.start_port) + a->curr_wr_port) >= \
- SDIO_MP_AGGR_DEF_PKT_LIMIT))
-
/* Reset SDIO Tx aggregation buffer parameters */
#define MP_TX_AGGR_BUF_RESET(a) do { \
a->mpa_tx.pkt_cnt = 0; \
@@ -219,12 +155,6 @@
#define MP_RX_AGGR_PKT_LIMIT_REACHED(a) \
(a->mpa_rx.pkt_cnt == a->mpa_rx.pkt_aggr_limit)
-/* SDIO Tx aggregation port limit ? */
-#define MP_RX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_rd_port < \
- a->mpa_rx.start_port) && (((MAX_PORT - \
- a->mpa_rx.start_port) + a->curr_rd_port) >= \
- SDIO_MP_AGGR_DEF_PKT_LIMIT))
-
/* SDIO Rx aggregation in progress ? */
#define MP_RX_AGGR_IN_PROGRESS(a) (a->mpa_rx.pkt_cnt > 0)
@@ -232,20 +162,6 @@
#define MP_RX_AGGR_BUF_HAS_ROOM(a, rx_len) \
((a->mpa_rx.buf_len+rx_len) <= a->mpa_rx.buf_size)
-/* Prepare to copy current packet from card to SDIO Rx aggregation buffer */
-#define MP_RX_AGGR_SETUP(a, skb, port) do { \
- a->mpa_rx.buf_len += skb->len; \
- if (!a->mpa_rx.pkt_cnt) \
- a->mpa_rx.start_port = port; \
- if (a->mpa_rx.start_port <= port) \
- a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt)); \
- else \
- a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt+1)); \
- a->mpa_rx.skb_arr[a->mpa_rx.pkt_cnt] = skb; \
- a->mpa_rx.len_arr[a->mpa_rx.pkt_cnt] = skb->len; \
- a->mpa_rx.pkt_cnt++; \
-} while (0)
-
/* Reset SDIO Rx aggregation buffer parameters */
#define MP_RX_AGGR_BUF_RESET(a) do { \
a->mpa_rx.pkt_cnt = 0; \
@@ -254,14 +170,13 @@
a->mpa_rx.start_port = 0; \
} while (0)
-
/* data structure for SDIO MPA TX */
struct mwifiex_sdio_mpa_tx {
/* multiport tx aggregation buffer pointer */
u8 *buf;
u32 buf_len;
u32 pkt_cnt;
- u16 ports;
+ u32 ports;
u16 start_port;
u8 enabled;
u32 buf_size;
@@ -272,11 +187,11 @@ struct mwifiex_sdio_mpa_rx {
u8 *buf;
u32 buf_len;
u32 pkt_cnt;
- u16 ports;
+ u32 ports;
u16 start_port;
- struct sk_buff *skb_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
- u32 len_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
+ struct sk_buff **skb_arr;
+ u32 *len_arr;
u8 enabled;
u32 buf_size;
@@ -286,15 +201,47 @@ struct mwifiex_sdio_mpa_rx {
int mwifiex_bus_register(void);
void mwifiex_bus_unregister(void);
+struct mwifiex_sdio_card_reg {
+ u8 start_rd_port;
+ u8 start_wr_port;
+ u8 base_0_reg;
+ u8 base_1_reg;
+ u8 poll_reg;
+ u8 host_int_enable;
+ u8 status_reg_0;
+ u8 status_reg_1;
+ u8 sdio_int_mask;
+ u32 data_port_mask;
+ u8 max_mp_regs;
+ u8 rd_bitmap_l;
+ u8 rd_bitmap_u;
+ u8 rd_bitmap_1l;
+ u8 rd_bitmap_1u;
+ u8 wr_bitmap_l;
+ u8 wr_bitmap_u;
+ u8 wr_bitmap_1l;
+ u8 wr_bitmap_1u;
+ u8 rd_len_p0_l;
+ u8 rd_len_p0_u;
+ u8 card_misc_cfg_reg;
+};
+
struct sdio_mmc_card {
struct sdio_func *func;
struct mwifiex_adapter *adapter;
- u16 mp_rd_bitmap;
- u16 mp_wr_bitmap;
+ const char *firmware;
+ const struct mwifiex_sdio_card_reg *reg;
+ u8 max_ports;
+ u8 mp_agg_pkt_limit;
+ bool supports_sdio_new_mode;
+ bool has_control_mask;
+
+ u32 mp_rd_bitmap;
+ u32 mp_wr_bitmap;
u16 mp_end_port;
- u16 mp_data_port_mask;
+ u32 mp_data_port_mask;
u8 curr_rd_port;
u8 curr_wr_port;
@@ -305,6 +252,98 @@ struct sdio_mmc_card {
struct mwifiex_sdio_mpa_rx mpa_rx;
};
+struct mwifiex_sdio_device {
+ const char *firmware;
+ const struct mwifiex_sdio_card_reg *reg;
+ u8 max_ports;
+ u8 mp_agg_pkt_limit;
+ bool supports_sdio_new_mode;
+ bool has_control_mask;
+};
+
+static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = {
+ .start_rd_port = 1,
+ .start_wr_port = 1,
+ .base_0_reg = 0x0040,
+ .base_1_reg = 0x0041,
+ .poll_reg = 0x30,
+ .host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK,
+ .status_reg_0 = 0x60,
+ .status_reg_1 = 0x61,
+ .sdio_int_mask = 0x3f,
+ .data_port_mask = 0x0000fffe,
+ .max_mp_regs = 64,
+ .rd_bitmap_l = 0x04,
+ .rd_bitmap_u = 0x05,
+ .wr_bitmap_l = 0x06,
+ .wr_bitmap_u = 0x07,
+ .rd_len_p0_l = 0x08,
+ .rd_len_p0_u = 0x09,
+ .card_misc_cfg_reg = 0x6c,
+};
+
+static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = {
+ .start_rd_port = 0,
+ .start_wr_port = 0,
+ .base_0_reg = 0x60,
+ .base_1_reg = 0x61,
+ .poll_reg = 0x50,
+ .host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK |
+ CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK,
+ .status_reg_0 = 0xc0,
+ .status_reg_1 = 0xc1,
+ .sdio_int_mask = 0xff,
+ .data_port_mask = 0xffffffff,
+ .max_mp_regs = 184,
+ .rd_bitmap_l = 0x04,
+ .rd_bitmap_u = 0x05,
+ .rd_bitmap_1l = 0x06,
+ .rd_bitmap_1u = 0x07,
+ .wr_bitmap_l = 0x08,
+ .wr_bitmap_u = 0x09,
+ .wr_bitmap_1l = 0x0a,
+ .wr_bitmap_1u = 0x0b,
+ .rd_len_p0_l = 0x0c,
+ .rd_len_p0_u = 0x0d,
+ .card_misc_cfg_reg = 0xcc,
+};
+
+static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = {
+ .firmware = SD8786_DEFAULT_FW_NAME,
+ .reg = &mwifiex_reg_sd87xx,
+ .max_ports = 16,
+ .mp_agg_pkt_limit = 8,
+ .supports_sdio_new_mode = false,
+ .has_control_mask = true,
+};
+
+static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = {
+ .firmware = SD8787_DEFAULT_FW_NAME,
+ .reg = &mwifiex_reg_sd87xx,
+ .max_ports = 16,
+ .mp_agg_pkt_limit = 8,
+ .supports_sdio_new_mode = false,
+ .has_control_mask = true,
+};
+
+static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = {
+ .firmware = SD8797_DEFAULT_FW_NAME,
+ .reg = &mwifiex_reg_sd87xx,
+ .max_ports = 16,
+ .mp_agg_pkt_limit = 8,
+ .supports_sdio_new_mode = false,
+ .has_control_mask = true,
+};
+
+static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {
+ .firmware = SD8897_DEFAULT_FW_NAME,
+ .reg = &mwifiex_reg_sd8897,
+ .max_ports = 32,
+ .mp_agg_pkt_limit = 16,
+ .supports_sdio_new_mode = true,
+ .has_control_mask = false,
+};
+
/*
* .cmdrsp_complete handler
*/
@@ -325,4 +364,77 @@ static inline int mwifiex_sdio_event_complete(struct mwifiex_adapter *adapter,
return 0;
}
+static inline bool
+mp_rx_aggr_port_limit_reached(struct sdio_mmc_card *card)
+{
+ u8 tmp;
+
+ if (card->curr_rd_port < card->mpa_rx.start_port) {
+ if (card->supports_sdio_new_mode)
+ tmp = card->mp_end_port >> 1;
+ else
+ tmp = card->mp_agg_pkt_limit;
+
+ if (((card->max_ports - card->mpa_rx.start_port) +
+ card->curr_rd_port) >= tmp)
+ return true;
+ }
+
+ if (!card->supports_sdio_new_mode)
+ return false;
+
+ if ((card->curr_rd_port - card->mpa_rx.start_port) >=
+ (card->mp_end_port >> 1))
+ return true;
+
+ return false;
+}
+
+static inline bool
+mp_tx_aggr_port_limit_reached(struct sdio_mmc_card *card)
+{
+ u16 tmp;
+
+ if (card->curr_wr_port < card->mpa_tx.start_port) {
+ if (card->supports_sdio_new_mode)
+ tmp = card->mp_end_port >> 1;
+ else
+ tmp = card->mp_agg_pkt_limit;
+
+ if (((card->max_ports - card->mpa_tx.start_port) +
+ card->curr_wr_port) >= tmp)
+ return true;
+ }
+
+ if (!card->supports_sdio_new_mode)
+ return false;
+
+ if ((card->curr_wr_port - card->mpa_tx.start_port) >=
+ (card->mp_end_port >> 1))
+ return true;
+
+ return false;
+}
+
+/* Prepare to copy current packet from card to SDIO Rx aggregation buffer */
+static inline void mp_rx_aggr_setup(struct sdio_mmc_card *card,
+ struct sk_buff *skb, u8 port)
+{
+ card->mpa_rx.buf_len += skb->len;
+
+ if (!card->mpa_rx.pkt_cnt)
+ card->mpa_rx.start_port = port;
+
+ if (card->supports_sdio_new_mode) {
+ card->mpa_rx.ports |= (1 << port);
+ } else {
+ if (card->mpa_rx.start_port <= port)
+ card->mpa_rx.ports |= 1 << (card->mpa_rx.pkt_cnt);
+ else
+ card->mpa_rx.ports |= 1 << (card->mpa_rx.pkt_cnt + 1);
+ }
+ card->mpa_rx.skb_arr[card->mpa_rx.pkt_cnt] = skb;
+ card->mpa_rx.len_arr[card->mpa_rx.pkt_cnt] = skb->len;
+ card->mpa_rx.pkt_cnt++;
+}
#endif /* _MWIFIEX_SDIO_H */
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index b193e25977d2..8ece48580642 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -1134,6 +1134,55 @@ mwifiex_cmd_mef_cfg(struct mwifiex_private *priv,
return 0;
}
+/* This function parse cal data from ASCII to hex */
+static u32 mwifiex_parse_cal_cfg(u8 *src, size_t len, u8 *dst)
+{
+ u8 *s = src, *d = dst;
+
+ while (s - src < len) {
+ if (*s && (isspace(*s) || *s == '\t')) {
+ s++;
+ continue;
+ }
+ if (isxdigit(*s)) {
+ *d++ = simple_strtol(s, NULL, 16);
+ s += 2;
+ } else {
+ s++;
+ }
+ }
+
+ return d - dst;
+}
+
+/* This function prepares command of set_cfg_data. */
+static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct host_cmd_ds_802_11_cfg_data *cfg_data = &cmd->params.cfg_data;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u32 len, cal_data_offset;
+ u8 *tmp_cmd = (u8 *)cmd;
+
+ cal_data_offset = S_DS_GEN + sizeof(*cfg_data);
+ if ((adapter->cal_data->data) && (adapter->cal_data->size > 0))
+ len = mwifiex_parse_cal_cfg((u8 *)adapter->cal_data->data,
+ adapter->cal_data->size,
+ (u8 *)(tmp_cmd + cal_data_offset));
+ else
+ return -1;
+
+ cfg_data->action = cpu_to_le16(cmd_action);
+ cfg_data->type = cpu_to_le16(CFG_DATA_TYPE_CAL);
+ cfg_data->data_len = cpu_to_le16(len);
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_CFG_DATA);
+ cmd->size = cpu_to_le16(S_DS_GEN + sizeof(*cfg_data) + len);
+
+ return 0;
+}
+
/*
* This function prepares the commands before sending them to the firmware.
*
@@ -1152,6 +1201,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
case HostCmd_CMD_GET_HW_SPEC:
ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr);
break;
+ case HostCmd_CMD_CFG_DATA:
+ ret = mwifiex_cmd_cfg_data(priv, cmd_ptr, cmd_action);
+ break;
case HostCmd_CMD_MAC_CONTROL:
ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action,
data_buf);
@@ -1384,6 +1436,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
*/
int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
{
+ struct mwifiex_adapter *adapter = priv->adapter;
int ret;
u16 enable = true;
struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
@@ -1404,6 +1457,15 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
HostCmd_ACT_GEN_SET, 0, NULL);
if (ret)
return -1;
+
+ /* Download calibration data to firmware */
+ if (adapter->cal_data) {
+ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_CFG_DATA,
+ HostCmd_ACT_GEN_SET, 0, NULL);
+ if (ret)
+ return -1;
+ }
+
/* Read MAC address from HW */
ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_GET_HW_SPEC,
HostCmd_ACT_GEN_GET, 0, NULL);
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 9f990e14966e..d85df158cc6c 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -818,6 +818,18 @@ static int mwifiex_ret_subsc_evt(struct mwifiex_private *priv,
return 0;
}
+/* This function handles the command response of set_cfg_data */
+static int mwifiex_ret_cfg_data(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ if (resp->result != HostCmd_RESULT_OK) {
+ dev_err(priv->adapter->dev, "Cal data cmd resp failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* This function handles the command responses.
*
@@ -841,6 +853,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_GET_HW_SPEC:
ret = mwifiex_ret_get_hw_spec(priv, resp);
break;
+ case HostCmd_CMD_CFG_DATA:
+ ret = mwifiex_ret_cfg_data(priv, resp);
+ break;
case HostCmd_CMD_MAC_CONTROL:
break;
case HostCmd_CMD_802_11_MAC_ADDRESS:
@@ -978,6 +993,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_UAP_STA_DEAUTH:
+ break;
case HostCmd_CMD_MEF_CFG:
break;
default:
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index 41aafc7454ed..ea265ec0e522 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -427,6 +427,17 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
+ case EVENT_CHANNEL_SWITCH_ANN:
+ dev_dbg(adapter->dev, "event: Channel Switch Announcement\n");
+ priv->csa_expire_time =
+ jiffies + msecs_to_jiffies(DFS_CHAN_MOVE_TIME);
+ priv->csa_chan = priv->curr_bss_params.bss_descriptor.channel;
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_802_11_DEAUTHENTICATE,
+ HostCmd_ACT_GEN_SET, 0,
+ priv->curr_bss_params.bss_descriptor.mac_address);
+ break;
+
default:
dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
eventcause);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 1a8a19dbd635..206c3e038072 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -104,16 +104,14 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
} else {
priv->curr_pkt_filter &=
~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
- if (mcast_list->num_multicast_addr) {
- dev_dbg(priv->adapter->dev,
- "info: Set multicast list=%d\n",
- mcast_list->num_multicast_addr);
- /* Send multicast addresses to firmware */
- ret = mwifiex_send_cmd_async(priv,
- HostCmd_CMD_MAC_MULTICAST_ADR,
- HostCmd_ACT_GEN_SET, 0,
- mcast_list);
- }
+ dev_dbg(priv->adapter->dev,
+ "info: Set multicast list=%d\n",
+ mcast_list->num_multicast_addr);
+ /* Send multicast addresses to firmware */
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_MAC_MULTICAST_ADR,
+ HostCmd_ACT_GEN_SET, 0,
+ mcast_list);
}
}
dev_dbg(priv->adapter->dev,
@@ -180,6 +178,9 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
*/
bss_desc->disable_11ac = true;
+ if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT)
+ bss_desc->sensed_11h = true;
+
return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
}
@@ -257,30 +258,37 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
}
if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+ u8 config_bands;
+
/* Infra mode */
ret = mwifiex_deauthenticate(priv, NULL);
if (ret)
goto done;
- if (bss_desc) {
- u8 config_bands = 0;
+ if (!bss_desc)
+ return -1;
- if (mwifiex_band_to_radio_type((u8) bss_desc->bss_band)
- == HostCmd_SCAN_RADIO_TYPE_BG)
- config_bands = BAND_B | BAND_G | BAND_GN |
- BAND_GAC;
- else
- config_bands = BAND_A | BAND_AN | BAND_AAC;
+ if (mwifiex_band_to_radio_type(bss_desc->bss_band) ==
+ HostCmd_SCAN_RADIO_TYPE_BG)
+ config_bands = BAND_B | BAND_G | BAND_GN | BAND_GAC;
+ else
+ config_bands = BAND_A | BAND_AN | BAND_AAC;
- if (!((config_bands | adapter->fw_bands) &
- ~adapter->fw_bands))
- adapter->config_bands = config_bands;
- }
+ if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands))
+ adapter->config_bands = config_bands;
ret = mwifiex_check_network_compatibility(priv, bss_desc);
if (ret)
goto done;
+ if (mwifiex_11h_get_csa_closed_channel(priv) ==
+ (u8)bss_desc->channel) {
+ dev_err(adapter->dev,
+ "Attempt to reconnect on csa closed chan(%d)\n",
+ bss_desc->channel);
+ goto done;
+ }
+
dev_dbg(adapter->dev, "info: SSID found in scan list ... "
"associating...\n");
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c
index b04b1db29100..2de882dead0f 100644
--- a/drivers/net/wireless/mwifiex/uap_cmd.c
+++ b/drivers/net/wireless/mwifiex/uap_cmd.c
@@ -689,6 +689,23 @@ mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd, u16 cmd_action,
return 0;
}
+/* This function prepares AP specific deauth command with mac supplied in
+ * function parameter.
+ */
+static int mwifiex_cmd_uap_sta_deauth(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, u8 *mac)
+{
+ struct host_cmd_ds_sta_deauth *sta_deauth = &cmd->params.sta_deauth;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_UAP_STA_DEAUTH);
+ memcpy(sta_deauth->mac, mac, ETH_ALEN);
+ sta_deauth->reason = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING);
+
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_sta_deauth) +
+ S_DS_GEN);
+ return 0;
+}
+
/* This function prepares the AP specific commands before sending them
* to the firmware.
* This is a generic function which calls specific command preparation
@@ -710,6 +727,10 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
cmd->command = cpu_to_le16(cmd_no);
cmd->size = cpu_to_le16(S_DS_GEN);
break;
+ case HostCmd_CMD_UAP_STA_DEAUTH:
+ if (mwifiex_cmd_uap_sta_deauth(priv, cmd, data_buf))
+ return -1;
+ break;
default:
dev_err(priv->adapter->dev,
"PREP_CMD: unknown cmd %#x\n", cmd_no);
diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c
index 21c640d3b579..718066577c6c 100644
--- a/drivers/net/wireless/mwifiex/uap_event.c
+++ b/drivers/net/wireless/mwifiex/uap_event.c
@@ -107,18 +107,15 @@ mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
*/
static void mwifiex_del_sta_entry(struct mwifiex_private *priv, u8 *mac)
{
- struct mwifiex_sta_node *node, *tmp;
+ struct mwifiex_sta_node *node;
unsigned long flags;
spin_lock_irqsave(&priv->sta_list_spinlock, flags);
node = mwifiex_get_sta_entry(priv, mac);
if (node) {
- list_for_each_entry_safe(node, tmp, &priv->sta_list,
- list) {
- list_del(&node->list);
- kfree(node);
- }
+ list_del(&node->list);
+ kfree(node);
}
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
@@ -295,3 +292,19 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
return 0;
}
+
+/* This function deletes station entry from associated station list.
+ * Also if both AP and STA are 11n enabled, RxReorder tables and TxBA stream
+ * tables created for this station are deleted.
+ */
+void mwifiex_uap_del_sta_data(struct mwifiex_private *priv,
+ struct mwifiex_sta_node *node)
+{
+ if (priv->ap_11n_enabled && node->is_11n_enabled) {
+ mwifiex_11n_del_rx_reorder_tbl_by_ta(priv, node->mac_addr);
+ mwifiex_del_tx_ba_stream_tbl_by_ra(priv, node->mac_addr);
+ }
+ mwifiex_del_sta_entry(priv, node->mac_addr);
+
+ return;
+}
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index 4be3d33ceae8..944e8846f6fc 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -37,6 +37,9 @@
/* Offset for TOS field in the IP header */
#define IPTOS_OFFSET 5
+static bool enable_tx_amsdu;
+module_param(enable_tx_amsdu, bool, 0644);
+
/* WMM information IE */
static const u8 wmm_info_ie[] = { WLAN_EID_VENDOR_SPECIFIC, 0x07,
0x00, 0x50, 0xf2, 0x02,
@@ -1233,7 +1236,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
mwifiex_send_delba(priv, tid_del, ra, 1);
}
}
- if (mwifiex_is_amsdu_allowed(priv, tid) &&
+ if (enable_tx_amsdu && mwifiex_is_amsdu_allowed(priv, tid) &&
mwifiex_is_11n_aggragation_possible(priv, ptr,
adapter->tx_buf_size))
mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN,