diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex')
39 files changed, 2457 insertions, 969 deletions
diff --git a/drivers/net/wireless/mwifiex/11ac.c b/drivers/net/wireless/mwifiex/11ac.c new file mode 100644 index 000000000000..cf43b3c29250 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11ac.c @@ -0,0 +1,261 @@ +/* + * Marvell Wireless LAN device driver: 802.11ac + * + * 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 "decl.h" +#include "ioctl.h" +#include "fw.h" +#include "main.h" +#include "11ac.h" + +/* This function converts the 2-bit MCS map to the highest long GI + * VHT data rate. + */ +static u16 +mwifiex_convert_mcsmap_to_maxrate(struct mwifiex_private *priv, + u8 bands, u16 mcs_map) +{ + u8 i, nss, max_mcs; + u16 max_rate = 0; + u32 usr_vht_cap_info = 0; + struct mwifiex_adapter *adapter = priv->adapter; + /* tables of the MCS map to the highest data rate (in Mbps) + * supported for long GI + */ + u16 max_rate_lgi_80MHZ[8][3] = { + {0x124, 0x15F, 0x186}, /* NSS = 1 */ + {0x249, 0x2BE, 0x30C}, /* NSS = 2 */ + {0x36D, 0x41D, 0x492}, /* NSS = 3 */ + {0x492, 0x57C, 0x618}, /* NSS = 4 */ + {0x5B6, 0x6DB, 0x79E}, /* NSS = 5 */ + {0x6DB, 0x83A, 0x0}, /* NSS = 6 */ + {0x7FF, 0x999, 0xAAA}, /* NSS = 7 */ + {0x924, 0xAF8, 0xC30} /* NSS = 8 */ + }; + u16 max_rate_lgi_160MHZ[8][3] = { + {0x249, 0x2BE, 0x30C}, /* NSS = 1 */ + {0x492, 0x57C, 0x618}, /* NSS = 2 */ + {0x6DB, 0x83A, 0x0}, /* NSS = 3 */ + {0x924, 0xAF8, 0xC30}, /* NSS = 4 */ + {0xB6D, 0xDB6, 0xF3C}, /* NSS = 5 */ + {0xDB6, 0x1074, 0x1248}, /* NSS = 6 */ + {0xFFF, 0x1332, 0x1554}, /* NSS = 7 */ + {0x1248, 0x15F0, 0x1860} /* NSS = 8 */ + }; + + if (bands & BAND_AAC) + usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a; + else + usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg; + + /* find the max NSS supported */ + nss = 0; + for (i = 0; i < 8; i++) { + max_mcs = (mcs_map >> (2 * i)) & 0x3; + if (max_mcs < 3) + nss = i; + } + max_mcs = (mcs_map >> (2 * nss)) & 0x3; + + /* if max_mcs is 3, nss must be 0 (SS = 1). Thus, max mcs is MCS 9 */ + if (max_mcs >= 3) + max_mcs = 2; + + if (GET_VHTCAP_CHWDSET(usr_vht_cap_info)) { + /* support 160 MHz */ + max_rate = max_rate_lgi_160MHZ[nss][max_mcs]; + if (!max_rate) + /* MCS9 is not supported in NSS6 */ + max_rate = max_rate_lgi_160MHZ[nss][max_mcs - 1]; + } else { + max_rate = max_rate_lgi_80MHZ[nss][max_mcs]; + if (!max_rate) + /* MCS9 is not supported in NSS3 */ + max_rate = max_rate_lgi_80MHZ[nss][max_mcs - 1]; + } + + return max_rate; +} + +static void +mwifiex_fill_vht_cap_info(struct mwifiex_private *priv, + struct mwifiex_ie_types_vhtcap *vht_cap, u8 bands) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + if (bands & BAND_A) + vht_cap->vht_cap.vht_cap_info = + cpu_to_le32(adapter->usr_dot_11ac_dev_cap_a); + else + vht_cap->vht_cap.vht_cap_info = + cpu_to_le32(adapter->usr_dot_11ac_dev_cap_bg); +} + +static void +mwifiex_fill_vht_cap_tlv(struct mwifiex_private *priv, + struct mwifiex_ie_types_vhtcap *vht_cap, u8 bands) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u16 mcs_map_user, mcs_map_resp, mcs_map_result; + u16 mcs_user, mcs_resp, nss, tmp; + + /* Fill VHT cap info */ + mwifiex_fill_vht_cap_info(priv, vht_cap, bands); + + /* rx MCS Set: find the minimum of the user rx mcs and ap rx mcs */ + mcs_map_user = GET_DEVRXMCSMAP(adapter->usr_dot_11ac_mcs_support); + mcs_map_resp = le16_to_cpu(vht_cap->vht_cap.supp_mcs.rx_mcs_map); + mcs_map_result = 0; + + for (nss = 1; nss <= 8; nss++) { + mcs_user = GET_VHTNSSMCS(mcs_map_user, nss); + mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss); + + if ((mcs_user == NO_NSS_SUPPORT) || + (mcs_resp == NO_NSS_SUPPORT)) + SET_VHTNSSMCS(mcs_map_result, nss, NO_NSS_SUPPORT); + else + SET_VHTNSSMCS(mcs_map_result, nss, + min(mcs_user, mcs_resp)); + } + + vht_cap->vht_cap.supp_mcs.rx_mcs_map = cpu_to_le16(mcs_map_result); + + tmp = mwifiex_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result); + vht_cap->vht_cap.supp_mcs.rx_highest = cpu_to_le16(tmp); + + /* tx MCS Set: find the minimum of the user tx mcs and ap tx mcs */ + mcs_map_user = GET_DEVTXMCSMAP(adapter->usr_dot_11ac_mcs_support); + mcs_map_resp = le16_to_cpu(vht_cap->vht_cap.supp_mcs.tx_mcs_map); + mcs_map_result = 0; + + for (nss = 1; nss <= 8; nss++) { + mcs_user = GET_VHTNSSMCS(mcs_map_user, nss); + mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss); + if ((mcs_user == NO_NSS_SUPPORT) || + (mcs_resp == NO_NSS_SUPPORT)) + SET_VHTNSSMCS(mcs_map_result, nss, NO_NSS_SUPPORT); + else + SET_VHTNSSMCS(mcs_map_result, nss, + min(mcs_user, mcs_resp)); + } + + vht_cap->vht_cap.supp_mcs.tx_mcs_map = cpu_to_le16(mcs_map_result); + + tmp = mwifiex_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result); + vht_cap->vht_cap.supp_mcs.tx_highest = cpu_to_le16(tmp); + + return; +} + +int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + u8 **buffer) +{ + struct mwifiex_ie_types_vhtcap *vht_cap; + struct mwifiex_ie_types_oper_mode_ntf *oper_ntf; + struct ieee_types_oper_mode_ntf *ieee_oper_ntf; + struct mwifiex_ie_types_vht_oper *vht_op; + struct mwifiex_adapter *adapter = priv->adapter; + u8 supp_chwd_set; + u32 usr_vht_cap_info; + int ret_len = 0; + + if (bss_desc->bss_band & BAND_A) + usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a; + else + usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg; + + /* VHT Capabilities IE */ + if (bss_desc->bcn_vht_cap) { + vht_cap = (struct mwifiex_ie_types_vhtcap *)*buffer; + memset(vht_cap, 0, sizeof(*vht_cap)); + vht_cap->header.type = cpu_to_le16(WLAN_EID_VHT_CAPABILITY); + vht_cap->header.len = + cpu_to_le16(sizeof(struct ieee80211_vht_cap)); + memcpy((u8 *)vht_cap + sizeof(struct mwifiex_ie_types_header), + (u8 *)bss_desc->bcn_vht_cap + + sizeof(struct ieee_types_header), + le16_to_cpu(vht_cap->header.len)); + + mwifiex_fill_vht_cap_tlv(priv, vht_cap, bss_desc->bss_band); + *buffer += sizeof(*vht_cap); + ret_len += sizeof(*vht_cap); + } + + /* VHT Operation IE */ + if (bss_desc->bcn_vht_oper) { + if (priv->bss_mode == HostCmd_BSS_MODE_IBSS) { + vht_op = (struct mwifiex_ie_types_vht_oper *)*buffer; + memset(vht_op, 0, sizeof(*vht_op)); + vht_op->header.type = + cpu_to_le16(WLAN_EID_VHT_OPERATION); + vht_op->header.len = cpu_to_le16(sizeof(*vht_op) - + sizeof(struct mwifiex_ie_types_header)); + memcpy((u8 *)vht_op + + sizeof(struct mwifiex_ie_types_header), + (u8 *)bss_desc->bcn_vht_oper + + sizeof(struct ieee_types_header), + le16_to_cpu(vht_op->header.len)); + + /* negotiate the channel width and central freq + * and keep the central freq as the peer suggests + */ + supp_chwd_set = GET_VHTCAP_CHWDSET(usr_vht_cap_info); + + switch (supp_chwd_set) { + case 0: + vht_op->chan_width = + min_t(u8, IEEE80211_VHT_CHANWIDTH_80MHZ, + bss_desc->bcn_vht_oper->chan_width); + break; + case 1: + vht_op->chan_width = + min_t(u8, IEEE80211_VHT_CHANWIDTH_160MHZ, + bss_desc->bcn_vht_oper->chan_width); + break; + case 2: + vht_op->chan_width = + min_t(u8, IEEE80211_VHT_CHANWIDTH_80P80MHZ, + bss_desc->bcn_vht_oper->chan_width); + break; + default: + vht_op->chan_width = + IEEE80211_VHT_CHANWIDTH_USE_HT; + break; + } + + *buffer += sizeof(*vht_op); + ret_len += sizeof(*vht_op); + } + } + + /* Operating Mode Notification IE */ + if (bss_desc->oper_mode) { + ieee_oper_ntf = bss_desc->oper_mode; + oper_ntf = (void *)*buffer; + memset(oper_ntf, 0, sizeof(*oper_ntf)); + oper_ntf->header.type = cpu_to_le16(WLAN_EID_OPMODE_NOTIF); + oper_ntf->header.len = cpu_to_le16(sizeof(u8)); + oper_ntf->oper_mode = ieee_oper_ntf->oper_mode; + *buffer += sizeof(*oper_ntf); + ret_len += sizeof(*oper_ntf); + } + + return ret_len; +} diff --git a/drivers/net/wireless/mwifiex/11ac.h b/drivers/net/wireless/mwifiex/11ac.h new file mode 100644 index 000000000000..80fd1ba46200 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11ac.h @@ -0,0 +1,26 @@ +/* + * Marvell Wireless LAN device driver: 802.11ac + * + * 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. + */ + +#ifndef _MWIFIEX_11AC_H_ +#define _MWIFIEX_11AC_H_ + +int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + u8 **buffer); +#endif /* _MWIFIEX_11AC_H_ */ diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 245a371f1a43..45f19716687e 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -53,7 +53,9 @@ mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type, sizeof(sband->ht_cap.mcs)); if (priv->bss_mode == NL80211_IFTYPE_STATION || - sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && + (priv->adapter->sec_chan_offset != + IEEE80211_HT_PARAM_CHA_SEC_NONE))) /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); @@ -248,7 +250,8 @@ int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, * - Setting HT Tx capability and HT Tx information fields * - Ensuring correct endian-ness */ -int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action, +int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, u16 cmd_action, struct mwifiex_ds_11n_tx_cfg *txcfg) { struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg; @@ -258,6 +261,10 @@ int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action, htcfg->action = cpu_to_le16(cmd_action); htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap); htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo); + + if (priv->adapter->is_hw_11ac_capable) + htcfg->misc_config = cpu_to_le16(txcfg->misc_config); + return 0; } @@ -398,45 +405,6 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, } /* - * This function reconfigures the Tx buffer size in firmware. - * - * This function prepares a firmware command and issues it, if - * the current Tx buffer size is different from the one requested. - * Maximum configurable Tx buffer size is limited by the HT capability - * field value. - */ -void -mwifiex_cfg_tx_buf(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *bss_desc) -{ - u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K; - u16 tx_buf, curr_tx_buf_size = 0; - - if (bss_desc->bcn_ht_cap) { - if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) & - IEEE80211_HT_CAP_MAX_AMSDU) - max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K; - else - max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K; - } - - tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu); - - dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n", - max_amsdu, priv->adapter->max_tx_buf_size); - - if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K) - curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; - else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K) - curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; - else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K) - curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K; - if (curr_tx_buf_size != tx_buf) - mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, - HostCmd_ACT_GEN_SET, 0, &tx_buf); -} - -/* * This function checks if the given pointer is valid entry of * Tx BA Stream table. */ @@ -531,11 +499,8 @@ void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid, if (!mwifiex_get_ba_tbl(priv, tid, ra)) { new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl), GFP_ATOMIC); - if (!new_node) { - dev_err(priv->adapter->dev, - "%s: failed to alloc new_node\n", __func__); + if (!new_node) return; - } INIT_LIST_HEAD(&new_node->list); diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index 46006a54a656..375db01442bf 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h @@ -28,14 +28,12 @@ int mwifiex_ret_11n_delba(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); -int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action, +int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, u16 cmd_action, struct mwifiex_ds_11n_tx_cfg *txcfg); - int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc, u8 **buffer); -void mwifiex_cfg_tx_buf(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *bss_desc); void mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type, struct mwifiex_ie_types_htcap *); int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv, diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 395f1bfd4102..af8fe6352eed 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -197,7 +197,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, ra_list_flags); mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad); - mwifiex_write_data_complete(adapter, skb_src, 0); + mwifiex_write_data_complete(adapter, skb_src, 0, 0); spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); @@ -256,7 +256,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); - mwifiex_write_data_complete(adapter, skb_aggr, -1); + mwifiex_write_data_complete(adapter, skb_aggr, 1, -1); return -1; } if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA && @@ -278,17 +278,19 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); break; case -1: - adapter->data_sent = false; + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; dev_err(adapter->dev, "%s: host_to_card failed: %#x\n", __func__, ret); adapter->dbg.num_tx_host_to_card_failure++; - mwifiex_write_data_complete(adapter, skb_aggr, ret); + mwifiex_write_data_complete(adapter, skb_aggr, 1, ret); return 0; case -EINPROGRESS: - adapter->data_sent = false; + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; break; case 0: - mwifiex_write_data_complete(adapter, skb_aggr, ret); + mwifiex_write_data_complete(adapter, skb_aggr, 1, ret); break; default: break; diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 9402b93b9a36..5e796f847088 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -58,8 +58,7 @@ mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr); else - mwifiex_process_rx_packet(priv->adapter, - rx_tmp_ptr); + mwifiex_process_rx_packet(priv, rx_tmp_ptr); } } @@ -106,7 +105,7 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv, if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr); else - mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr); + mwifiex_process_rx_packet(priv, rx_tmp_ptr); } spin_lock_irqsave(&priv->rx_pkt_lock, flags); @@ -273,11 +272,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, } /* if !tbl then create one */ new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL); - if (!new_node) { - dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n", - __func__); + if (!new_node) return; - } INIT_LIST_HEAD(&new_node->list); new_node->tid = tid; @@ -442,8 +438,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) mwifiex_handle_uap_rx_forward(priv, payload); else - mwifiex_process_rx_packet(priv->adapter, - payload); + mwifiex_process_rx_packet(priv, payload); } return 0; } diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig index 8e384fae3e68..4f614aad9ded 100644 --- a/drivers/net/wireless/mwifiex/Kconfig +++ b/drivers/net/wireless/mwifiex/Kconfig @@ -1,7 +1,6 @@ config MWIFIEX tristate "Marvell WiFi-Ex Driver" depends on CFG80211 - select LIB80211 ---help--- This adds support for wireless adapters based on Marvell 802.11n chipsets. @@ -21,12 +20,12 @@ config MWIFIEX_SDIO mwifiex_sdio. config MWIFIEX_PCIE - tristate "Marvell WiFi-Ex Driver for PCIE 8766" + tristate "Marvell WiFi-Ex Driver for PCIE 8766/8897" depends on MWIFIEX && PCI select FW_LOADER ---help--- This adds support for wireless adapters based on Marvell - 8766 chipset with PCIe interface. + 8766/8897 chipsets with PCIe interface. If you choose to build it as a module, it will be called mwifiex_pcie. diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile index dd0410d2d465..97b245cbafd8 100644 --- a/drivers/net/wireless/mwifiex/Makefile +++ b/drivers/net/wireless/mwifiex/Makefile @@ -23,6 +23,7 @@ mwifiex-y += util.o mwifiex-y += txrx.o mwifiex-y += wmm.o mwifiex-y += 11n.o +mwifiex-y += 11ac.o mwifiex-y += 11n_aggr.o mwifiex-y += 11n_rxreorder.o mwifiex-y += scan.o diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README index b55badef4660..3d64613ebb29 100644 --- a/drivers/net/wireless/mwifiex/README +++ b/drivers/net/wireless/mwifiex/README @@ -121,7 +121,6 @@ info wmm_ac_vi = <number of packets sent to device from WMM AcVi queue> wmm_ac_be = <number of packets sent to device from WMM AcBE queue> wmm_ac_bk = <number of packets sent to device from WMM AcBK queue> - max_tx_buf_size = <maximum Tx buffer size> tx_buf_size = <current Tx buffer size> curr_tx_buf_size = <current Tx buffer size> ps_mode = <0/1, CAM mode/PS mode> diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 780d3e168297..a44023a7bd57 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -180,10 +180,8 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len) static int mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, - enum nl80211_channel_type channel_type, - bool channel_type_valid, unsigned int wait, - const u8 *buf, size_t len, bool no_cck, - bool dont_wait_for_ack, u64 *cookie) + unsigned int wait, const u8 *buf, size_t len, + bool no_cck, bool dont_wait_for_ack, u64 *cookie) { struct sk_buff *skb; u16 pkt_len; @@ -253,7 +251,6 @@ static int mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); @@ -271,15 +268,14 @@ mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy, } ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_SET, chan, - &channel_type, duration); + duration); if (!ret) { *cookie = random32() | 1; priv->roc_cfg.cookie = *cookie; priv->roc_cfg.chan = *chan; - priv->roc_cfg.chan_type = channel_type; - cfg80211_ready_on_channel(wdev, *cookie, chan, channel_type, + cfg80211_ready_on_channel(wdev, *cookie, chan, duration, GFP_ATOMIC); wiphy_dbg(wiphy, "info: ROC, cookie = 0x%llx\n", *cookie); @@ -302,13 +298,11 @@ mwifiex_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, return -ENOENT; ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_REMOVE, - &priv->roc_cfg.chan, - &priv->roc_cfg.chan_type, 0); + &priv->roc_cfg.chan, 0); if (!ret) { cfg80211_remain_on_channel_expired(wdev, cookie, &priv->roc_cfg.chan, - priv->roc_cfg.chan_type, GFP_ATOMIC); memset(&priv->roc_cfg, 0, sizeof(struct mwifiex_roc_cfg)); @@ -324,6 +318,7 @@ mwifiex_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, */ static int mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, enum nl80211_tx_power_setting type, int mbm) { @@ -471,13 +466,13 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) flag = 1; first_chan = (u32) ch->hw_value; next_chan = first_chan; - max_pwr = ch->max_reg_power; + max_pwr = ch->max_power; no_of_parsed_chan = 1; continue; } if (ch->hw_value == next_chan + 1 && - ch->max_reg_power == max_pwr) { + ch->max_power == max_pwr) { next_chan++; no_of_parsed_chan++; } else { @@ -488,7 +483,7 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) no_of_triplet++; first_chan = (u32) ch->hw_value; next_chan = first_chan; - max_pwr = ch->max_reg_power; + max_pwr = ch->max_power; no_of_parsed_chan = 1; } } @@ -524,8 +519,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) * - Set by user * - Set bt Country IE */ -static int mwifiex_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) +static void mwifiex_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); @@ -545,8 +540,6 @@ static int mwifiex_reg_notifier(struct wiphy *wiphy, break; } mwifiex_send_domain_info_cmd_fw(wiphy); - - return 0; } /* @@ -841,6 +834,66 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, return ret; } +static void +mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo, + struct rate_info *rate) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + if (adapter->is_hw_11ac_capable) { + /* bit[1-0]: 00=LG 01=HT 10=VHT */ + if (tx_htinfo & BIT(0)) { + /* HT */ + rate->mcs = priv->tx_rate; + rate->flags |= RATE_INFO_FLAGS_MCS; + } + if (tx_htinfo & BIT(1)) { + /* VHT */ + rate->mcs = priv->tx_rate & 0x0F; + rate->flags |= RATE_INFO_FLAGS_VHT_MCS; + } + + if (tx_htinfo & (BIT(1) | BIT(0))) { + /* HT or VHT */ + switch (tx_htinfo & (BIT(3) | BIT(2))) { + case 0: + /* This will be 20MHz */ + break; + case (BIT(2)): + rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + break; + case (BIT(3)): + rate->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; + break; + case (BIT(3) | BIT(2)): + rate->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; + break; + } + + if (tx_htinfo & BIT(4)) + rate->flags |= RATE_INFO_FLAGS_SHORT_GI; + + if ((priv->tx_rate >> 4) == 1) + rate->nss = 2; + else + rate->nss = 1; + } + } else { + /* + * Bit 0 in tx_htinfo indicates that current Tx rate + * is 11n rate. Valid MCS index values for us are 0 to 15. + */ + if ((tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) { + rate->mcs = priv->tx_rate; + rate->flags |= RATE_INFO_FLAGS_MCS; + if (tx_htinfo & BIT(1)) + rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + if (tx_htinfo & BIT(2)) + rate->flags |= RATE_INFO_FLAGS_SHORT_GI; + } + } +} + /* * This function dumps the station information on a buffer. * @@ -880,20 +933,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, HostCmd_ACT_GEN_GET, DTIM_PERIOD_I, &priv->dtim_period); - /* - * Bit 0 in tx_htinfo indicates that current Tx rate is 11n rate. Valid - * MCS index values for us are 0 to 15. - */ - if ((priv->tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) { - sinfo->txrate.mcs = priv->tx_rate; - sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; - /* 40MHz rate */ - if (priv->tx_htinfo & BIT(1)) - sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; - /* SGI enabled */ - if (priv->tx_htinfo & BIT(2)) - sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; - } + mwifiex_parse_htinfo(priv, priv->tx_htinfo, &sinfo->txrate); sinfo->signal_avg = priv->bcn_rssi_avg; sinfo->rx_bytes = priv->stats.rx_bytes; @@ -1296,24 +1336,28 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, return -EINVAL; } - bss_cfg->channel = - (u8)ieee80211_frequency_to_channel(params->channel->center_freq); + bss_cfg->channel = ieee80211_frequency_to_channel( + params->chandef.chan->center_freq); /* Set appropriate bands */ - if (params->channel->band == IEEE80211_BAND_2GHZ) { + if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) { bss_cfg->band_cfg = BAND_CONFIG_BG; + config_bands = BAND_B | BAND_G; - if (params->channel_type == NL80211_CHAN_NO_HT) - config_bands = BAND_B | BAND_G; - else - config_bands = BAND_B | BAND_G | BAND_GN; + if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT) + config_bands |= BAND_GN; + + if (params->chandef.width > NL80211_CHAN_WIDTH_40) + config_bands |= BAND_GAC; } else { bss_cfg->band_cfg = BAND_CONFIG_A; + config_bands = BAND_A; - if (params->channel_type == NL80211_CHAN_NO_HT) - config_bands = BAND_A; - else - config_bands = BAND_AN | BAND_A; + if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT) + config_bands |= BAND_AN; + + if (params->chandef.width > NL80211_CHAN_WIDTH_40) + config_bands |= BAND_AAC; } if (!((config_bands | priv->adapter->fw_bands) & @@ -1330,6 +1374,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, } mwifiex_set_ht_params(priv, bss_cfg, params); + mwifiex_set_wmm_params(priv, bss_cfg, params); if (params->inactivity_timeout > 0) { /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */ @@ -1434,7 +1479,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) bss = cfg80211_inform_bss(priv->wdev->wiphy, chan, bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, 0, ie_buf, ie_len, 0, GFP_KERNEL); - cfg80211_put_bss(bss); + cfg80211_put_bss(priv->wdev->wiphy, bss); memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); return 0; @@ -1462,7 +1507,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, struct cfg80211_ssid req_ssid; int ret, auth_type = 0; struct cfg80211_bss *bss = NULL; - u8 is_scanning_required = 0, config_bands = 0; + u8 is_scanning_required = 0; memset(&req_ssid, 0, sizeof(struct cfg80211_ssid)); @@ -1481,19 +1526,6 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, /* disconnect before try to associate */ mwifiex_deauthenticate(priv, NULL); - if (channel) { - if (mode == NL80211_IFTYPE_STATION) { - if (channel->band == IEEE80211_BAND_2GHZ) - config_bands = BAND_B | BAND_G | BAND_GN; - else - config_bands = BAND_A | BAND_AN; - - if (!((config_bands | priv->adapter->fw_bands) & - ~priv->adapter->fw_bands)) - priv->adapter->config_bands = config_bands; - } - } - /* As this is new association, clear locally stored * keys and security related flags */ priv->sec_info.wpa_enabled = false; @@ -1683,7 +1715,7 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv, int index = 0, i; u8 config_bands = 0; - if (params->channel->band == IEEE80211_BAND_2GHZ) { + if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) { if (!params->basic_rates) { config_bands = BAND_B | BAND_G; } else { @@ -1708,10 +1740,12 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv, } } - if (params->channel_type != NL80211_CHAN_NO_HT) - config_bands |= BAND_GN; + if (cfg80211_get_chandef_type(¶ms->chandef) != + NL80211_CHAN_NO_HT) + config_bands |= BAND_G | BAND_GN; } else { - if (params->channel_type == NL80211_CHAN_NO_HT) + if (cfg80211_get_chandef_type(¶ms->chandef) == + NL80211_CHAN_NO_HT) config_bands = BAND_A; else config_bands = BAND_AN | BAND_A; @@ -1728,9 +1762,10 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv, } adapter->sec_chan_offset = - mwifiex_chan_type_to_sec_chan_offset(params->channel_type); - priv->adhoc_channel = - ieee80211_frequency_to_channel(params->channel->center_freq); + mwifiex_chan_type_to_sec_chan_offset( + cfg80211_get_chandef_type(¶ms->chandef)); + priv->adhoc_channel = ieee80211_frequency_to_channel( + params->chandef.chan->center_freq); wiphy_dbg(wiphy, "info: set ibss band %d, chan %d, chan offset %d\n", config_bands, priv->adhoc_channel, adapter->sec_chan_offset); @@ -1764,7 +1799,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid, params->bssid, priv->bss_mode, - params->channel, NULL, params->privacy); + params->chandef.chan, NULL, + params->privacy); done: if (!ret) { cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL); @@ -1819,18 +1855,22 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); - if (atomic_read(&priv->wmm.tx_pkts_queued) >= + if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && + atomic_read(&priv->wmm.tx_pkts_queued) >= MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN) { dev_dbg(priv->adapter->dev, "scan rejected due to traffic\n"); return -EBUSY; } + if (priv->user_scan_cfg) { + 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) { - dev_err(priv->adapter->dev, "failed to alloc scan_req\n"); + if (!priv->user_scan_cfg) return -ENOMEM; - } priv->scan_request = request; @@ -1888,6 +1928,79 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, return 0; } +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; + + /* Update MCS support for VHT */ + vht_info->vht_mcs.rx_mcs_map = cpu_to_le16( + adapter->hw_dot_11ac_mcs_support & 0xFFFF); + vht_info->vht_mcs.rx_highest = 0; + vht_info->vht_mcs.tx_mcs_map = cpu_to_le16( + adapter->hw_dot_11ac_mcs_support >> 16); + vht_info->vht_mcs.tx_highest = 0; +} + /* * This function sets up the CFG802.11 specific HT capability fields * with default values. @@ -1941,6 +2054,21 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, else ht_info->cap &= ~IEEE80211_HT_CAP_TX_STBC; + if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; + else + ht_info->cap &= ~IEEE80211_HT_CAP_GRN_FLD; + + if (ISENABLED_40MHZ_INTOLERANT(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_40MHZ_INTOLERANT; + else + ht_info->cap &= ~IEEE80211_HT_CAP_40MHZ_INTOLERANT; + + if (ISSUPP_RXLDPC(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; + else + ht_info->cap &= ~IEEE80211_HT_CAP_LDPC_CODING; + ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; ht_info->cap |= IEEE80211_HT_CAP_SM_PS; @@ -2074,8 +2202,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, return ERR_PTR(-EINVAL); } - dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), name, - ether_setup, 1); + dev = alloc_netdev_mqs(sizeof(struct mwifiex_private *), name, + ether_setup, IEEE80211_NUM_ACS, 1); if (!dev) { wiphy_err(wiphy, "no memory available for netdevice\n"); priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; @@ -2086,16 +2214,22 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, priv->netdev = dev; mwifiex_setup_ht_caps(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv); + if (adapter->is_hw_11ac_capable) + mwifiex_setup_vht_caps( + &wiphy->bands[IEEE80211_BAND_2GHZ]->vht_cap, priv); if (adapter->config_bands & BAND_A) mwifiex_setup_ht_caps( &wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv); + if ((adapter->config_bands & BAND_A) && adapter->is_hw_11ac_capable) + mwifiex_setup_vht_caps( + &wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap, priv); + dev_net_set(dev, wiphy_net(wiphy)); dev->ieee80211_ptr = priv->wdev; dev->ieee80211_ptr->iftype = priv->bss_mode; memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN); - memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN); SET_NETDEV_DEV(dev, wiphy_dev(wiphy)); dev->flags |= IFF_BROADCAST | IFF_MULTICAST; @@ -2116,7 +2250,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, } sema_init(&priv->async_sem, 1); - priv->scan_pending_on_block = false; dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); @@ -2138,8 +2271,7 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) mwifiex_dev_debugfs_remove(priv); #endif - if (!netif_queue_stopped(priv->netdev)) - netif_stop_queue(priv->netdev); + mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); @@ -2241,6 +2373,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | + WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; @@ -2253,8 +2386,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1; wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1; - wiphy->features = NL80211_FEATURE_HT_IBSS | - NL80211_FEATURE_INACTIVITY_TIMER; + wiphy->features |= NL80211_FEATURE_HT_IBSS | + NL80211_FEATURE_INACTIVITY_TIMER | + NL80211_FEATURE_LOW_PRIORITY_SCAN; /* Reserve space for mwifiex specific private data for BSS */ wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index f69300f93f42..988552dece75 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -106,8 +106,8 @@ u8 *mwifiex_11d_code_2_region(u8 code) * This function maps an index in supported rates table into * the corresponding data rate. */ -u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv, u8 index, - u8 ht_info) +u32 mwifiex_index_to_acs_data_rate(struct mwifiex_private *priv, + u8 index, u8 ht_info) { /* * For every mcs_rate line, the first 8 bytes are for stream 1x1, @@ -130,10 +130,155 @@ u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv, u8 index, { 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90, 0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 } }; + /* AC rates */ + u16 ac_mcs_rate_nss1[8][10] = { + /* LG 160M */ + { 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D, + 0x492, 0x57C, 0x618 }, + + /* SG 160M */ + { 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492, + 0x514, 0x618, 0x6C6 }, + + /* LG 80M */ + { 0x3B, 0x75, 0xB0, 0xEA, 0x15F, 0x1D4, 0x20F, + 0x249, 0x2BE, 0x30C }, + + /* SG 80M */ + { 0x41, 0x82, 0xC3, 0x104, 0x186, 0x208, 0x249, + 0x28A, 0x30C, 0x363 }, + + /* LG 40M */ + { 0x1B, 0x36, 0x51, 0x6C, 0xA2, 0xD8, 0xF3, + 0x10E, 0x144, 0x168 }, + + /* SG 40M */ + { 0x1E, 0x3C, 0x5A, 0x78, 0xB4, 0xF0, 0x10E, + 0x12C, 0x168, 0x190 }, + + /* LG 20M */ + { 0xD, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75, 0x82, 0x9C, 0x00 }, + + /* SG 20M */ + { 0xF, 0x1D, 0x2C, 0x3A, 0x57, 0x74, 0x82, 0x91, 0xAE, 0x00 }, + }; + /* NSS2 note: the value in the table is 2 multiplier of the actual + * rate + */ + u16 ac_mcs_rate_nss2[8][10] = { + /* LG 160M */ + { 0xEA, 0x1D4, 0x2BE, 0x3A8, 0x57C, 0x750, 0x83A, + 0x924, 0xAF8, 0xC30 }, + + /* SG 160M */ + { 0x104, 0x208, 0x30C, 0x410, 0x618, 0x820, 0x924, + 0xA28, 0xC30, 0xD8B }, + + /* LG 80M */ + { 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D, + 0x492, 0x57C, 0x618 }, + + /* SG 80M */ + { 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492, + 0x514, 0x618, 0x6C6 }, + + /* LG 40M */ + { 0x36, 0x6C, 0xA2, 0xD8, 0x144, 0x1B0, 0x1E6, + 0x21C, 0x288, 0x2D0 }, + + /* SG 40M */ + { 0x3C, 0x78, 0xB4, 0xF0, 0x168, 0x1E0, 0x21C, + 0x258, 0x2D0, 0x320 }, + + /* LG 20M */ + { 0x1A, 0x34, 0x4A, 0x68, 0x9C, 0xD0, 0xEA, 0x104, + 0x138, 0x00 }, + + /* SG 20M */ + { 0x1D, 0x3A, 0x57, 0x74, 0xAE, 0xE6, 0x104, 0x121, + 0x15B, 0x00 }, + }; + u32 rate = 0; + u8 mcs_index = 0; + u8 bw = 0; + u8 gi = 0; + + if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_VHT) { + mcs_index = min(index & 0xF, 9); + + /* 20M: bw=0, 40M: bw=1, 80M: bw=2, 160M: bw=3 */ + bw = (ht_info & 0xC) >> 2; + + /* LGI: gi =0, SGI: gi = 1 */ + gi = (ht_info & 0x10) >> 4; + + if ((index >> 4) == 1) /* NSS = 2 */ + rate = ac_mcs_rate_nss2[2 * (3 - bw) + gi][mcs_index]; + else /* NSS = 1 */ + rate = ac_mcs_rate_nss1[2 * (3 - bw) + gi][mcs_index]; + } else if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_HT) { + /* 20M: bw=0, 40M: bw=1 */ + bw = (ht_info & 0xC) >> 2; + + /* LGI: gi =0, SGI: gi = 1 */ + gi = (ht_info & 0x10) >> 4; + + if (index == MWIFIEX_RATE_BITMAP_MCS0) { + if (gi == 1) + rate = 0x0D; /* MCS 32 SGI rate */ + else + rate = 0x0C; /* MCS 32 LGI rate */ + } else if (index < 16) { + if ((bw == 1) || (bw == 0)) + rate = mcs_rate[2 * (1 - bw) + gi][index]; + else + rate = mwifiex_data_rates[0]; + } else { + rate = mwifiex_data_rates[0]; + } + } else { + /* 11n non-HT rates */ + if (index >= MWIFIEX_SUPPORTED_RATES_EXT) + index = 0; + rate = mwifiex_data_rates[index]; + } + + return rate; +} + +/* This function maps an index in supported rates table into + * the corresponding data rate. + */ +u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv, + u8 index, u8 ht_info) +{ + /* For every mcs_rate line, the first 8 bytes are for stream 1x1, + * and all 16 bytes are for stream 2x2. + */ + u16 mcs_rate[4][16] = { + /* LGI 40M */ + { 0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e, + 0x36, 0x6c, 0xa2, 0xd8, 0x144, 0x1b0, 0x1e6, 0x21c }, + + /* SGI 40M */ + { 0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c, + 0x3c, 0x78, 0xb4, 0xf0, 0x168, 0x1e0, 0x21c, 0x258 }, + + /* LGI 20M */ + { 0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82, + 0x1a, 0x34, 0x4e, 0x68, 0x9c, 0xd0, 0xea, 0x104 }, + + /* SGI 20M */ + { 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90, + 0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 } + }; u32 mcs_num_supp = (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) ? 16 : 8; u32 rate; + if (priv->adapter->is_hw_11ac_capable) + return mwifiex_index_to_acs_data_rate(priv, index, ht_info); + if (ht_info & BIT(0)) { if (index == MWIFIEX_RATE_BITMAP_MCS0) { if (ht_info & BIT(2)) @@ -269,6 +414,7 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) { u32 k = 0; struct mwifiex_adapter *adapter = priv->adapter; + if (priv->bss_mode == NL80211_IFTYPE_STATION) { switch (adapter->config_bands) { case BAND_B: @@ -279,6 +425,7 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) break; case BAND_G: case BAND_G | BAND_GN: + case BAND_G | BAND_GN | BAND_GAC: dev_dbg(adapter->dev, "info: infra band=%d " "supported_rates_g\n", adapter->config_bands); k = mwifiex_copy_rates(rates, k, supported_rates_g, @@ -288,7 +435,11 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) case BAND_A | BAND_B | BAND_G: case BAND_A | BAND_B: case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN: + case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN | BAND_AAC: + case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN | + BAND_AAC | BAND_GAC: case BAND_B | BAND_G | BAND_GN: + case BAND_B | BAND_G | BAND_GN | BAND_GAC: dev_dbg(adapter->dev, "info: infra band=%d " "supported_rates_bg\n", adapter->config_bands); k = mwifiex_copy_rates(rates, k, supported_rates_bg, @@ -301,14 +452,18 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) k = mwifiex_copy_rates(rates, k, supported_rates_a, sizeof(supported_rates_a)); break; + case BAND_AN: case BAND_A | BAND_AN: + case BAND_A | BAND_AN | BAND_AAC: case BAND_A | BAND_G | BAND_AN | BAND_GN: + case BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC: dev_dbg(adapter->dev, "info: infra band=%d " "supported_rates_a\n", adapter->config_bands); k = mwifiex_copy_rates(rates, k, supported_rates_a, sizeof(supported_rates_a)); break; case BAND_GN: + case BAND_GN | BAND_GAC: dev_dbg(adapter->dev, "info: infra band=%d " "supported_rates_n\n", adapter->config_bands); k = mwifiex_copy_rates(rates, k, supported_rates_n, diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 8d465107f52b..20a6c5555873 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -24,6 +24,7 @@ #include "main.h" #include "wmm.h" #include "11n.h" +#include "11ac.h" /* * This function initializes a command node. @@ -334,20 +335,15 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter) { struct cmd_ctrl_node *cmd_array; - u32 buf_size; u32 i; /* Allocate and initialize struct cmd_ctrl_node */ - buf_size = sizeof(struct cmd_ctrl_node) * MWIFIEX_NUM_OF_CMD_BUFFER; - cmd_array = kzalloc(buf_size, GFP_KERNEL); - if (!cmd_array) { - dev_err(adapter->dev, "%s: failed to alloc cmd_array\n", - __func__); + cmd_array = kcalloc(MWIFIEX_NUM_OF_CMD_BUFFER, + sizeof(struct cmd_ctrl_node), GFP_KERNEL); + if (!cmd_array) return -ENOMEM; - } adapter->cmd_pool = cmd_array; - memset(adapter->cmd_pool, 0, buf_size); /* Allocate and initialize command buffers */ for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) { @@ -890,9 +886,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context) return; } cmd_node = adapter->curr_cmd; - if (cmd_node->wait_q_enabled) - adapter->cmd_wait_q.status = -ETIMEDOUT; - if (cmd_node) { adapter->dbg.timeout_cmd_id = adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index]; @@ -917,30 +910,44 @@ mwifiex_cmd_timeout_func(unsigned long function_context) dev_err(adapter->dev, "last_cmd_index = %d\n", adapter->dbg.last_cmd_index); - print_hex_dump_bytes("last_cmd_id: ", DUMP_PREFIX_OFFSET, - adapter->dbg.last_cmd_id, DBG_CMD_NUM); - print_hex_dump_bytes("last_cmd_act: ", DUMP_PREFIX_OFFSET, - adapter->dbg.last_cmd_act, DBG_CMD_NUM); + dev_err(adapter->dev, "last_cmd_id: %*ph\n", + (int)sizeof(adapter->dbg.last_cmd_id), + adapter->dbg.last_cmd_id); + dev_err(adapter->dev, "last_cmd_act: %*ph\n", + (int)sizeof(adapter->dbg.last_cmd_act), + adapter->dbg.last_cmd_act); dev_err(adapter->dev, "last_cmd_resp_index = %d\n", adapter->dbg.last_cmd_resp_index); - print_hex_dump_bytes("last_cmd_resp_id: ", DUMP_PREFIX_OFFSET, - adapter->dbg.last_cmd_resp_id, - DBG_CMD_NUM); + dev_err(adapter->dev, "last_cmd_resp_id: %*ph\n", + (int)sizeof(adapter->dbg.last_cmd_resp_id), + adapter->dbg.last_cmd_resp_id); dev_err(adapter->dev, "last_event_index = %d\n", adapter->dbg.last_event_index); - print_hex_dump_bytes("last_event: ", DUMP_PREFIX_OFFSET, - adapter->dbg.last_event, DBG_CMD_NUM); + dev_err(adapter->dev, "last_event: %*ph\n", + (int)sizeof(adapter->dbg.last_event), + adapter->dbg.last_event); dev_err(adapter->dev, "data_sent=%d cmd_sent=%d\n", adapter->data_sent, adapter->cmd_sent); dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n", adapter->ps_mode, adapter->ps_state); + + if (cmd_node->wait_q_enabled) { + adapter->cmd_wait_q.status = -ETIMEDOUT; + wake_up_interruptible(&adapter->cmd_wait_q.wait); + mwifiex_cancel_pending_ioctl(adapter); + /* reset cmd_sent flag to unblock new commands */ + adapter->cmd_sent = false; + } } if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) mwifiex_init_fw_complete(adapter); + + if (adapter->if_ops.card_reset) + adapter->if_ops.card_reset(adapter); } /* @@ -1459,6 +1466,24 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number); adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna); + if (le32_to_cpu(hw_spec->dot_11ac_dev_cap)) { + adapter->is_hw_11ac_capable = true; + + /* Copy 11AC cap */ + adapter->hw_dot_11ac_dev_cap = + le32_to_cpu(hw_spec->dot_11ac_dev_cap); + adapter->usr_dot_11ac_dev_cap_bg = adapter->hw_dot_11ac_dev_cap; + adapter->usr_dot_11ac_dev_cap_a = adapter->hw_dot_11ac_dev_cap; + + /* Copy 11AC mcs */ + adapter->hw_dot_11ac_mcs_support = + le32_to_cpu(hw_spec->dot_11ac_mcs_support); + adapter->usr_dot_11ac_mcs_support = + adapter->hw_dot_11ac_mcs_support; + } else { + adapter->is_hw_11ac_capable = false; + } + dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n", adapter->fw_release_number); dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n", diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index a870b5885c09..753b5682d53f 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -58,8 +58,6 @@ static struct mwifiex_debug_data items[] = { item_addr(packets_out[WMM_AC_BE]), 1}, {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]), item_addr(packets_out[WMM_AC_BK]), 1}, - {"max_tx_buf_size", item_size(max_tx_buf_size), - item_addr(max_tx_buf_size), 1}, {"tx_buf_size", item_size(tx_buf_size), item_addr(tx_buf_size), 1}, {"curr_tx_buf_size", item_size(curr_tx_buf_size), @@ -178,6 +176,7 @@ mwifiex_info_read(struct file *file, char __user *ubuf, (struct mwifiex_private *) file->private_data; struct net_device *netdev = priv->netdev; struct netdev_hw_addr *ha; + struct netdev_queue *txq; unsigned long page = get_zeroed_page(GFP_KERNEL); char *p = (char *) page, fmt[64]; struct mwifiex_bss_info info; @@ -229,8 +228,13 @@ mwifiex_info_read(struct file *file, char __user *ubuf, p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors); p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev)) ? "on" : "off")); - p += sprintf(p, "tx queue %s\n", ((netif_queue_stopped(priv->netdev)) - ? "stopped" : "started")); + p += sprintf(p, "tx queue"); + for (i = 0; i < netdev->num_tx_queues; i++) { + txq = netdev_get_tx_queue(netdev, i); + p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ? + "stopped" : "started"); + } + p += sprintf(p, "\n"); ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, (unsigned long) p - page); diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index e9357d87d327..e8a569aaa2e8 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -26,6 +26,7 @@ #include <linux/wait.h> #include <linux/timer.h> #include <linux/ieee80211.h> +#include <net/mac80211.h> #define MWIFIEX_MAX_BSS_NUM (3) @@ -58,6 +59,8 @@ #define MWIFIEX_RTS_MAX_VALUE (2347) #define MWIFIEX_FRAG_MIN_VALUE (256) #define MWIFIEX_FRAG_MAX_VALUE (2346) +#define MWIFIEX_WMM_VERSION 0x01 +#define MWIFIEX_WMM_SUBTYPE 0x01 #define MWIFIEX_RETRY_LIMIT 14 #define MWIFIEX_SDIO_BLOCK_SIZE 256 @@ -126,4 +129,19 @@ enum mwifiex_wmm_ac_e { WMM_AC_VI, WMM_AC_VO } __packed; + +struct ieee_types_wmm_ac_parameters { + u8 aci_aifsn_bitmap; + u8 ecw_bitmap; + __le16 tx_op_limit; +} __packed; + +struct mwifiex_types_wmm_info { + u8 oui[4]; + u8 subtype; + u8 version; + u8 qos_info; + u8 reserved; + struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_NUM_ACS]; +} __packed; #endif /* !_MWIFIEX_DECL_H_ */ diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index dda588b35570..25acb0682c56 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -49,13 +49,23 @@ struct tx_packet_hdr { #define A_SUPPORTED_RATES 9 #define HOSTCMD_SUPPORTED_RATES 14 #define N_SUPPORTED_RATES 3 -#define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN) +#define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN | \ + BAND_AN | BAND_GAC | BAND_AAC) -#define FW_MULTI_BANDS_SUPPORT (BIT(8) | BIT(9) | BIT(10) | BIT(11)) +#define FW_MULTI_BANDS_SUPPORT (BIT(8) | BIT(9) | BIT(10) | BIT(11) | \ + BIT(12) | BIT(13)) #define IS_SUPPORT_MULTI_BANDS(adapter) \ (adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT) + +/* shift bit 12 and bit 13 in fw_cap_info from the firmware to bit 13 and 14 + * for 11ac so that bit 11 is for GN, bit 12 for AN, bit 13 for GAC, and bit + * bit 14 for AAC, in order to be compatible with the band capability + * defined in the driver after right shift of 8 bits. + */ #define GET_FW_DEFAULT_BANDS(adapter) \ - ((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS) + (((((adapter->fw_cap_info & 0x3000) << 1) | \ + (adapter->fw_cap_info & ~0xF000)) >> 8) & \ + ALL_802_11_BANDS) #define HostCmd_WEP_KEY_INDEX_MASK 0x3fff @@ -194,6 +204,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(25)) #define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26)) #define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29)) +#define ISENABLED_40MHZ_INTOLERANT(Dot11nDevCap) (Dot11nDevCap & BIT(8)) +#define ISSUPP_RXLDPC(Dot11nDevCap) (Dot11nDevCap & BIT(22)) /* httxcfg bitmap * 0 reserved @@ -214,6 +226,47 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define LLC_SNAP_LEN 8 +/* HW_SPEC fw_cap_info */ + +#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) + #define MOD_CLASS_HR_DSSS 0x03 #define MOD_CLASS_OFDM 0x07 #define MOD_CLASS_HT 0x08 @@ -328,6 +381,9 @@ enum P2P_MODES { #define HOST_SLEEP_CFG_GPIO_DEF 0xff #define HOST_SLEEP_CFG_GAP_DEF 0 +#define MWIFIEX_TIMEOUT_FOR_AP_RESP 0xfffc +#define MWIFIEX_STATUS_CODE_AUTH_TIMEOUT 2 + #define CMD_F_HOSTCMD (1 << 0) #define CMD_F_CANCELED (1 << 1) @@ -450,9 +506,22 @@ struct rxpd { u8 rx_rate; s8 snr; s8 nf; - /* Ht Info [Bit 0] RxRate format: LG=0, HT=1 + + /* For: Non-802.11 AC cards + * + * Ht Info [Bit 0] RxRate format: LG=0, HT=1 * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1 - * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */ + * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 + * + * For: 802.11 AC cards + * [Bit 1] [Bit 0] RxRate format: legacy rate = 00 HT = 01 VHT = 10 + * [Bit 3] [Bit 2] HT/VHT Bandwidth BW20 = 00 BW40 = 01 + * BW80 = 10 BW160 = 11 + * [Bit 4] HT/VHT Guard interval LGI = 0 SGI = 1 + * [Bit 5] STBC support Enabled = 1 + * [Bit 6] LDPC support Enabled = 1 + * [Bit 7] Reserved + */ u8 ht_info; u8 reserved; } __packed; @@ -675,7 +744,11 @@ struct host_cmd_ds_get_hw_spec { __le32 dot_11n_dev_cap; u8 dev_mcs_support; __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ - __le16 reserved_4; + __le16 mgmt_buf_count; /* mgmt IE buffer count */ + __le32 reserved_5; + __le32 reserved_6; + __le32 dot_11ac_dev_cap; + __le32 dot_11ac_mcs_support; } __packed; struct host_cmd_ds_802_11_rssi_info { @@ -781,6 +854,12 @@ union ieee_types_phy_param_set { struct ieee_types_ds_param_set ds_param_set; } __packed; +struct ieee_types_oper_mode_ntf { + u8 element_id; + u8 len; + u8 oper_mode; +} __packed; + struct host_cmd_ds_802_11_ad_hoc_start { u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 bss_mode; @@ -841,11 +920,27 @@ struct host_cmd_ds_802_11_get_log { __le32 wep_icv_err_cnt[4]; }; +/* Enumeration for rate format */ +enum _mwifiex_rate_format { + MWIFIEX_RATE_FORMAT_LG = 0, + MWIFIEX_RATE_FORMAT_HT, + MWIFIEX_RATE_FORMAT_VHT, + MWIFIEX_RATE_FORMAT_AUTO = 0xFF, +}; + struct host_cmd_ds_tx_rate_query { u8 tx_rate; - /* Ht Info [Bit 0] RxRate format: LG=0, HT=1 + /* Tx Rate Info: For 802.11 AC cards + * + * [Bit 0-1] tx rate formate: LG = 0, HT = 1, VHT = 2 + * [Bit 2-3] HT/VHT Bandwidth: BW20 = 0, BW40 = 1, BW80 = 2, BW160 = 3 + * [Bit 4] HT/VHT Guard Interval: LGI = 0, SGI = 1 + * + * For non-802.11 AC cards + * Ht Info [Bit 0] RxRate format: LG=0, HT=1 * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1 - * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */ + * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 + */ u8 ht_info; } __packed; @@ -1091,6 +1186,7 @@ struct host_cmd_ds_11n_cfg { __le16 action; __le16 ht_tx_cap; __le16 ht_tx_info; + __le16 misc_config; /* Needed for 802.11AC cards only */ } __packed; struct host_cmd_ds_txbuf_cfg { @@ -1129,12 +1225,6 @@ struct ieee_types_vendor_header { u8 version; } __packed; -struct ieee_types_wmm_ac_parameters { - u8 aci_aifsn_bitmap; - u8 ecw_bitmap; - __le16 tx_op_limit; -} __packed; - struct ieee_types_wmm_parameter { /* * WMM Parameter IE - Vendor Specific Header: @@ -1184,6 +1274,31 @@ struct mwifiex_ie_types_htcap { struct ieee80211_ht_cap ht_cap; } __packed; +struct mwifiex_ie_types_vhtcap { + struct mwifiex_ie_types_header header; + struct ieee80211_vht_cap vht_cap; +} __packed; + +struct mwifiex_ie_types_oper_mode_ntf { + struct mwifiex_ie_types_header header; + u8 oper_mode; +} __packed; + +/* VHT Operations IE */ +struct mwifiex_ie_types_vht_oper { + struct mwifiex_ie_types_header header; + u8 chan_width; + u8 chan_center_freq_1; + u8 chan_center_freq_2; + /* Basic MCS set map, each 2 bits stands for a NSS */ + u16 basic_mcs_map; +} __packed; + +struct mwifiex_ie_types_wmmcap { + struct mwifiex_ie_types_header header; + struct mwifiex_types_wmm_info wmm_info; +} __packed; + struct mwifiex_ie_types_htinfo { struct mwifiex_ie_types_header header; struct ieee80211_ht_operation ht_oper; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index b5d37a8caa09..e38aa9b3663d 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -39,11 +39,8 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv) unsigned long flags; bss_prio = kzalloc(sizeof(struct mwifiex_bss_prio_node), GFP_KERNEL); - if (!bss_prio) { - dev_err(adapter->dev, "%s: failed to alloc bss_prio\n", - __func__); + if (!bss_prio) return -ENOMEM; - } bss_prio->priv = priv; INIT_LIST_HEAD(&bss_prio->list); @@ -84,18 +81,19 @@ static void scan_delay_timer_fn(unsigned long data) spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); if (priv->user_scan_cfg) { - dev_dbg(priv->adapter->dev, - "info: %s: scan aborted\n", __func__); - cfg80211_scan_done(priv->scan_request, 1); - priv->scan_request = NULL; + 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; } - - if (priv->scan_pending_on_block) { - priv->scan_pending_on_block = false; - up(&priv->async_sem); - } goto done; } @@ -316,7 +314,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->pm_wakeup_fw_try = false; - adapter->max_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; @@ -387,9 +384,17 @@ void mwifiex_wake_up_net_dev_queue(struct net_device *netdev, struct mwifiex_adapter *adapter) { unsigned long dev_queue_flags; + unsigned int i; spin_lock_irqsave(&adapter->queue_lock, dev_queue_flags); - netif_tx_wake_all_queues(netdev); + + for (i = 0; i < netdev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(netdev, i); + + if (netif_tx_queue_stopped(txq)) + netif_tx_wake_queue(txq); + } + spin_unlock_irqrestore(&adapter->queue_lock, dev_queue_flags); } @@ -400,9 +405,17 @@ void mwifiex_stop_net_dev_queue(struct net_device *netdev, struct mwifiex_adapter *adapter) { unsigned long dev_queue_flags; + unsigned int i; spin_lock_irqsave(&adapter->queue_lock, dev_queue_flags); - netif_tx_stop_all_queues(netdev); + + for (i = 0; i < netdev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(netdev, i); + + if (!netif_tx_queue_stopped(txq)) + netif_tx_stop_queue(txq); + } + spin_unlock_irqrestore(&adapter->queue_lock, dev_queue_flags); } @@ -574,6 +587,12 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter) return -1; } } + + if (adapter->if_ops.init_fw_port) { + if (adapter->if_ops.init_fw_port(adapter)) + return -1; + } + for (i = 0; i < adapter->priv_num; i++) { if (adapter->priv[i]) { ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta); diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 4e31c6013ebe..d85e6eb1f58a 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -20,7 +20,6 @@ #ifndef _MWIFIEX_IOCTL_H_ #define _MWIFIEX_IOCTL_H_ -#include <net/mac80211.h> #include <net/lib80211.h> enum { @@ -61,6 +60,8 @@ enum { BAND_A = 4, BAND_GN = 8, BAND_AN = 16, + BAND_GAC = 32, + BAND_AAC = 64, }; #define MWIFIEX_WPA_PASSHPHRASE_LEN 64 @@ -104,9 +105,12 @@ struct mwifiex_uap_bss_param { struct wpa_param wpa_cfg; struct wep_key wep_cfg[NUM_WEP_KEYS]; struct ieee80211_ht_cap ht_cap; + struct ieee80211_vht_cap vht_cap; u8 rates[MWIFIEX_SUPPORTED_RATES]; u32 sta_ao_timer; u32 ps_sta_ao_timer; + u8 qos_info; + struct mwifiex_types_wmm_info wmm_info; }; enum { @@ -177,7 +181,6 @@ struct mwifiex_ds_tx_ba_stream_tbl { struct mwifiex_debug_info { u32 int_counter; u32 packets_out[MAX_NUM_TID]; - u32 max_tx_buf_size; u32 tx_buf_size; u32 curr_tx_buf_size; u32 tx_tbl_num; @@ -272,6 +275,7 @@ struct mwifiex_ds_pm_cfg { struct mwifiex_ds_11n_tx_cfg { u16 tx_htcap; u16 tx_htinfo; + u16 misc_config; /* Needed for 802.11AC cards only */ }; struct mwifiex_ds_11n_amsdu_aggr_ctrl { diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 7b0858af8f5d..246aa62a4817 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -24,6 +24,7 @@ #include "main.h" #include "wmm.h" #include "11n.h" +#include "11ac.h" #define CAPINFO_MASK (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9))) @@ -157,8 +158,8 @@ static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1, memset(rate1, 0, rate1_size); - for (i = 0; rate2[i] && i < rate2_size; i++) { - for (j = 0; tmp[j] && j < rate1_size; j++) { + for (i = 0; i < rate2_size && rate2[i]; i++) { + for (j = 0; j < rate1_size && tmp[j]; j++) { /* Check common rate, excluding the bit for basic rate */ if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) { @@ -398,8 +399,6 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, pos = (u8 *) assoc; - mwifiex_cfg_tx_buf(priv, bss_desc); - cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE); /* Save so we know which BSS Desc to use in the response handler */ @@ -514,6 +513,12 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, priv->adapter->config_bands & BAND_AN)) mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos); + if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && + !bss_desc->disable_11n && !bss_desc->disable_11ac && + (priv->adapter->config_bands & BAND_GAC || + priv->adapter->config_bands & BAND_AAC)) + mwifiex_cmd_append_11ac_tlv(priv, bss_desc, &pos); + /* Append vendor specific IE TLV */ mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos); @@ -615,23 +620,33 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, struct ieee_types_assoc_rsp *assoc_rsp; struct mwifiex_bssdescriptor *bss_desc; u8 enable_data = true; + u16 cap_info, status_code; assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params; + cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap); + status_code = le16_to_cpu(assoc_rsp->status_code); + priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN, sizeof(priv->assoc_rsp_buf)); memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size); - if (le16_to_cpu(assoc_rsp->status_code)) { + if (status_code) { priv->adapter->dbg.num_cmd_assoc_failure++; dev_err(priv->adapter->dev, "ASSOC_RESP: failed, status code=%d err=%#x a_id=%#x\n", - le16_to_cpu(assoc_rsp->status_code), - le16_to_cpu(assoc_rsp->cap_info_bitmap), - le16_to_cpu(assoc_rsp->a_id)); + status_code, cap_info, le16_to_cpu(assoc_rsp->a_id)); + + if (cap_info == MWIFIEX_TIMEOUT_FOR_AP_RESP) { + if (status_code == MWIFIEX_STATUS_CODE_AUTH_TIMEOUT) + ret = WLAN_STATUS_AUTH_TIMEOUT; + else + ret = WLAN_STATUS_UNSPECIFIED_FAILURE; + } else { + ret = status_code; + } - ret = le16_to_cpu(assoc_rsp->status_code); goto done; } @@ -721,8 +736,7 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, if (!netif_carrier_ok(priv->netdev)) netif_carrier_on(priv->netdev); - if (netif_queue_stopped(priv->netdev)) - netif_wake_queue(priv->netdev); + mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) priv->scan_block = true; @@ -970,6 +984,16 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, priv->adapter->config_bands); mwifiex_fill_cap_info(priv, radio_type, ht_cap); + if (adapter->sec_chan_offset == + IEEE80211_HT_PARAM_CHA_SEC_NONE) { + u16 tmp_ht_cap; + + tmp_ht_cap = le16_to_cpu(ht_cap->ht_cap.cap_info); + tmp_ht_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + tmp_ht_cap &= ~IEEE80211_HT_CAP_SGI_40; + ht_cap->ht_cap.cap_info = cpu_to_le16(tmp_ht_cap); + } + pos += sizeof(struct mwifiex_ie_types_htcap); cmd_append_size += sizeof(struct mwifiex_ie_types_htcap); @@ -1238,8 +1262,7 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, if (!netif_carrier_ok(priv->netdev)) netif_carrier_on(priv->netdev); - if (netif_queue_stopped(priv->netdev)) - netif_wake_queue(priv->netdev); + mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); mwifiex_save_curr_bcn(priv); @@ -1405,6 +1428,7 @@ mwifiex_band_to_radio_type(u8 band) case BAND_A: case BAND_AN: case BAND_A | BAND_AN: + case BAND_A | BAND_AN | BAND_AAC: return HostCmd_SCAN_RADIO_TYPE_A; case BAND_B: case BAND_G: diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index eb22dd248d54..9c802ede9c3b 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -282,6 +282,7 @@ exit_main_proc: mwifiex_shutdown_drv(adapter); return ret; } +EXPORT_SYMBOL_GPL(mwifiex_main_process); /* * This function frees the adapter structure. @@ -412,49 +413,6 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) } /* - * This function fills a driver buffer. - * - * The function associates a given SKB with the provided driver buffer - * and also updates some of the SKB parameters, including IP header, - * priority and timestamp. - */ -static void -mwifiex_fill_buffer(struct sk_buff *skb) -{ - struct ethhdr *eth; - struct iphdr *iph; - struct timeval tv; - u8 tid = 0; - - eth = (struct ethhdr *) skb->data; - switch (eth->h_proto) { - case __constant_htons(ETH_P_IP): - iph = ip_hdr(skb); - tid = IPTOS_PREC(iph->tos); - pr_debug("data: packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n", - eth->h_proto, tid, skb->priority); - break; - case __constant_htons(ETH_P_ARP): - pr_debug("data: ARP packet: %04x\n", eth->h_proto); - default: - break; - } -/* Offset for TOS field in the IP header */ -#define IPTOS_OFFSET 5 - tid = (tid >> IPTOS_OFFSET); - skb->priority = tid; - /* Record the current time the packet was queued; used to - determine the amount of time the packet was queued in - the driver before it was sent to the firmware. - The delay is then sent along with the packet to the - firmware for aggregate delay calculation for stats and - MSDU lifetime expiry. - */ - do_gettimeofday(&tv); - skb->tstamp = timeval_to_ktime(tv); -} - -/* * CFG802.11 network device handler for open. * * Starts the data queue. @@ -472,6 +430,14 @@ mwifiex_open(struct net_device *dev) static int mwifiex_close(struct net_device *dev) { + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + if (priv->scan_request) { + dev_dbg(priv->adapter->dev, "aborting scan on ndo_stop\n"); + cfg80211_scan_done(priv->scan_request, 1); + priv->scan_request = NULL; + } + return 0; } @@ -480,17 +446,23 @@ mwifiex_close(struct net_device *dev) */ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb) { - mwifiex_wmm_add_buf_txqueue(priv, skb); + struct netdev_queue *txq; + int index = mwifiex_1d_to_wmm_queue[skb->priority]; + + if (atomic_inc_return(&priv->wmm_tx_pending[index]) >= MAX_TX_PENDING) { + txq = netdev_get_tx_queue(priv->netdev, index); + if (!netif_tx_queue_stopped(txq)) { + netif_tx_stop_queue(txq); + dev_dbg(priv->adapter->dev, "stop queue: %d\n", index); + } + } + atomic_inc(&priv->adapter->tx_pending); + mwifiex_wmm_add_buf_txqueue(priv, skb); if (priv->adapter->scan_delay_cnt) atomic_set(&priv->adapter->is_tx_received, true); - if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) { - mwifiex_set_trans_start(priv->netdev); - mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); - } - queue_work(priv->adapter->workqueue, &priv->adapter->main_work); return 0; @@ -505,6 +477,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct sk_buff *new_skb; struct mwifiex_txinfo *tx_info; + struct timeval tv; dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n", jiffies, priv->bss_type, priv->bss_num); @@ -542,7 +515,16 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) tx_info = MWIFIEX_SKB_TXCB(skb); tx_info->bss_num = priv->bss_num; tx_info->bss_type = priv->bss_type; - mwifiex_fill_buffer(skb); + + /* Record the current time the packet was queued; used to + * determine the amount of time the packet was queued in + * the driver before it was sent to the firmware. + * The delay is then sent along with the packet to the + * firmware for aggregate delay calculation for stats and + * MSDU lifetime expiry. + */ + do_gettimeofday(&tv); + skb->tstamp = timeval_to_ktime(tv); mwifiex_queue_tx_pkt(priv, skb); @@ -622,6 +604,13 @@ static struct net_device_stats *mwifiex_get_stats(struct net_device *dev) return &priv->stats; } +static u16 +mwifiex_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb) +{ + skb->priority = cfg80211_classify8021d(skb); + return mwifiex_1d_to_wmm_queue[skb->priority]; +} + /* Network device handlers */ static const struct net_device_ops mwifiex_netdev_ops = { .ndo_open = mwifiex_open, @@ -631,6 +620,7 @@ static const struct net_device_ops mwifiex_netdev_ops = { .ndo_tx_timeout = mwifiex_tx_timeout, .ndo_get_stats = mwifiex_get_stats, .ndo_set_rx_mode = mwifiex_set_multicast_list, + .ndo_select_queue = mwifiex_netdev_select_wmm_queue, }; /* @@ -830,9 +820,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; if (priv && priv->netdev) { - if (!netif_queue_stopped(priv->netdev)) - mwifiex_stop_net_dev_queue(priv->netdev, - adapter); + mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index c2d0ab146af5..553adfb0aa81 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -115,8 +115,6 @@ enum { #define MWIFIEX_TYPE_DATA 0 #define MWIFIEX_TYPE_EVENT 3 -#define DBG_CMD_NUM 5 - #define MAX_BITMAP_RATES_SIZE 10 #define MAX_CHANNEL_BAND_BG 14 @@ -297,6 +295,13 @@ struct mwifiex_bssdescriptor { u16 bss_co_2040_offset; u8 *bcn_ext_cap; u16 ext_cap_offset; + struct ieee80211_vht_cap *bcn_vht_cap; + u16 vht_cap_offset; + struct ieee80211_vht_operation *bcn_vht_oper; + u16 vht_info_offset; + struct ieee_types_oper_mode_ntf *oper_mode; + u16 oper_mode_offset; + u8 disable_11ac; struct ieee_types_vendor_specific *bcn_wpa_ie; u16 wpa_offset; struct ieee_types_generic *bcn_rsn_ie; @@ -373,7 +378,6 @@ struct wps { struct mwifiex_roc_cfg { u64 cookie; struct ieee80211_channel chan; - enum nl80211_channel_type chan_type; }; struct mwifiex_adapter; @@ -442,6 +446,7 @@ struct mwifiex_private { u8 wmm_enabled; u8 wmm_qosinfo; struct mwifiex_wmm_desc wmm; + atomic_t wmm_tx_pending[IEEE80211_NUM_ACS]; struct list_head sta_list; /* spin lock for associated station list */ spinlock_t sta_list_spinlock; @@ -484,7 +489,6 @@ struct mwifiex_private { u8 nick_name[16]; u16 current_key_index; struct semaphore async_sem; - u8 scan_pending_on_block; u8 report_scan_result; struct cfg80211_scan_request *scan_request; struct mwifiex_user_scan_cfg *user_scan_cfg; @@ -502,6 +506,7 @@ struct mwifiex_private { u16 rsn_idx; struct timer_list scan_delay_timer; u8 ap_11n_enabled; + u8 ap_11ac_enabled; u32 mgmt_frame_mask; struct mwifiex_roc_cfg roc_cfg; }; @@ -602,7 +607,10 @@ struct mwifiex_if_ops { int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *); int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *); int (*data_complete) (struct mwifiex_adapter *, struct sk_buff *); + int (*init_fw_port) (struct mwifiex_adapter *); int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); + void (*card_reset) (struct mwifiex_adapter *); + int (*clean_pcie_ring) (struct mwifiex_adapter *adapter); }; struct mwifiex_adapter { @@ -631,7 +639,6 @@ struct mwifiex_adapter { /* spin lock for main process */ spinlock_t main_proc_lock; u32 mwifiex_processing; - u16 max_tx_buf_size; u16 tx_buf_size; u16 curr_tx_buf_size; u32 ioport; @@ -723,6 +730,15 @@ struct mwifiex_adapter { u16 max_mgmt_ie_index; u8 scan_delay_cnt; u8 empty_tx_q_cnt; + + /* 11AC */ + u32 is_hw_11ac_capable; + u32 hw_dot_11ac_dev_cap; + u32 hw_dot_11ac_mcs_support; + u32 usr_dot_11ac_dev_cap_bg; + u32 usr_dot_11ac_dev_cap_a; + u32 usr_dot_11ac_mcs_support; + atomic_t is_tx_received; atomic_t pending_bridged_pkts; }; @@ -750,9 +766,9 @@ int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter); int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *); -int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb); +int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb); -int mwifiex_process_mgmt_packet(struct mwifiex_adapter *adapter, +int mwifiex_process_mgmt_packet(struct mwifiex_private *priv, struct sk_buff *skb); int mwifiex_process_event(struct mwifiex_adapter *adapter); @@ -791,7 +807,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, struct mwifiex_tx_param *tx_param); int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags); int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, - struct sk_buff *skb, int status); + struct sk_buff *skb, int aggr, int status); void mwifiex_clean_txrx(struct mwifiex_private *priv); u8 mwifiex_check_last_packet_indication(struct mwifiex_private *priv); void mwifiex_check_ps_cond(struct mwifiex_adapter *adapter); @@ -809,7 +825,7 @@ void mwifiex_hs_activated_event(struct mwifiex_private *priv, u8 activated); int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); -int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, +int mwifiex_process_rx_packet(struct mwifiex_private *priv, struct sk_buff *skb); int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no, u16 cmd_action, u32 cmd_oid, @@ -819,9 +835,9 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, void *data_buf, void *cmd_buf); int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no, struct host_cmd_ds_command *resp); -int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *, +int mwifiex_process_sta_rx_packet(struct mwifiex_private *, struct sk_buff *skb); -int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter, +int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv, struct sk_buff *skb); int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv, struct sk_buff *skb); @@ -865,8 +881,10 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd); struct mwifiex_chan_freq_power *mwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq); -u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv, u8 index, - u8 ht_info); +u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv, + u8 index, u8 ht_info); +u32 mwifiex_index_to_acs_data_rate(struct mwifiex_private *priv, + u8 index, u8 ht_info); u32 mwifiex_find_freq_from_band_chan(u8, u8); int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask, u8 **buffer); @@ -892,6 +910,10 @@ void mwifiex_set_ht_params(struct mwifiex_private *priv, 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_wmm_params(struct mwifiex_private *priv, + struct mwifiex_uap_bss_param *bss_cfg, + struct cfg80211_ap_settings *params); /* * This function checks if the queuing is RA based or not. @@ -1019,7 +1041,6 @@ int mwifiex_get_ver_ext(struct mwifiex_private *priv); int mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action, struct ieee80211_channel *chan, - enum nl80211_channel_type *channel_type, unsigned int duration); int mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role); diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 13fbc4eb1595..5c395e2e6a2b 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -39,17 +39,20 @@ 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); -/* - * This function is called after skb allocation to update - * "skb->cb" with physical address of data pointer. - */ -static phys_addr_t *mwifiex_update_sk_buff_pa(struct sk_buff *skb) +static int +mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb, + int size, int flags) { - phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb); - - *buf_pa = (phys_addr_t)virt_to_phys(skb->data); + struct pcie_service_card *card = adapter->card; + dma_addr_t buf_pa; - return buf_pa; + buf_pa = pci_map_single(card->dev, skb->data, size, flags); + if (pci_dma_mapping_error(card->dev, buf_pa)) { + dev_err(adapter->dev, "failed to map pci memory!\n"); + return -1; + } + memcpy(skb->cb, &buf_pa, sizeof(dma_addr_t)); + return 0; } /* @@ -59,9 +62,13 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter) { u32 *cookie_addr; struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + + if (!reg->sleep_cookie) + return true; - if (card->sleep_cookie) { - cookie_addr = (u32 *)card->sleep_cookie->data; + if (card->sleep_cookie_vbase) { + cookie_addr = (u32 *)card->sleep_cookie_vbase; dev_dbg(adapter->dev, "info: ACCESS_HW: sleep cookie=0x%x\n", *cookie_addr); if (*cookie_addr == FW_AWAKE_COOKIE) @@ -91,6 +98,13 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, card->dev = pdev; + if (ent->driver_data) { + struct mwifiex_pcie_device *data = (void *)ent->driver_data; + card->pcie.firmware = data->firmware; + card->pcie.reg = data->reg; + card->pcie.blksz_fw_dl = data->blksz_fw_dl; + } + if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops, MWIFIEX_PCIE)) { pr_err("%s failed\n", __func__); @@ -157,11 +171,11 @@ 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, i; + int hs_actived; if (pdev) { card = (struct pcie_service_card *) pci_get_drvdata(pdev); - if (!card || card->adapter) { + if (!card || !card->adapter) { pr_err("Card or adapter structure is not valid\n"); return 0; } @@ -177,9 +191,6 @@ static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state) /* Indicate device suspended */ adapter->is_suspended = true; - for (i = 0; i < adapter->priv_num; i++) - netif_carrier_off(adapter->priv[i]->netdev); - return 0; } @@ -195,7 +206,6 @@ static int mwifiex_pcie_resume(struct pci_dev *pdev) { struct mwifiex_adapter *adapter; struct pcie_service_card *card; - int i; if (pdev) { card = (struct pcie_service_card *) pci_get_drvdata(pdev); @@ -217,23 +227,22 @@ static int mwifiex_pcie_resume(struct pci_dev *pdev) adapter->is_suspended = false; - for (i = 0; i < adapter->priv_num; i++) - if (adapter->priv[i]->media_connected) - netif_carrier_on(adapter->priv[i]->netdev); - mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), MWIFIEX_ASYNC_CMD); return 0; } -#define PCIE_VENDOR_ID_MARVELL (0x11ab) -#define PCIE_DEVICE_ID_MARVELL_88W8766P (0x2b30) - static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = { { PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + .driver_data = (unsigned long) &mwifiex_pcie8766, + }, + { + PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8897, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + .driver_data = (unsigned long) &mwifiex_pcie8897, }, {}, }; @@ -286,12 +295,14 @@ static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data) static int mwifiex_pm_wakeup_card(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 (mwifiex_pcie_ok_to_access_hw(adapter)) { + while (reg->sleep_cookie && mwifiex_pcie_ok_to_access_hw(adapter)) { i++; usleep_range(10, 20); /* 50ms max wait */ - if (i == 50000) + if (i == 5000) break; } @@ -361,14 +372,246 @@ static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter) } /* - * This function creates buffer descriptor ring for TX + * This function initializes TX buffer ring descriptors */ -static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) +static int mwifiex_init_txq_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + struct mwifiex_pcie_buf_desc *desc; + struct mwifiex_pfu_buf_desc *desc2; + int i; + + for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { + card->tx_buf_list[i] = NULL; + if (reg->pfu_enabled) { + card->txbd_ring[i] = (void *)card->txbd_ring_vbase + + (sizeof(*desc2) * i); + desc2 = card->txbd_ring[i]; + memset(desc2, 0, sizeof(*desc2)); + } else { + card->txbd_ring[i] = (void *)card->txbd_ring_vbase + + (sizeof(*desc) * i); + desc = card->txbd_ring[i]; + memset(desc, 0, sizeof(*desc)); + } + } + + return 0; +} + +/* This function initializes RX buffer ring descriptors. Each SKB is allocated + * here and after mapping PCI memory, its physical address is assigned to + * PCIE Rx buffer descriptor's physical address. + */ +static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; struct sk_buff *skb; + struct mwifiex_pcie_buf_desc *desc; + struct mwifiex_pfu_buf_desc *desc2; + dma_addr_t buf_pa; int i; - phys_addr_t *buf_pa; + + for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { + /* Allocate skb here so that firmware can DMA data from it */ + skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); + if (!skb) { + dev_err(adapter->dev, + "Unable to allocate skb for RX ring.\n"); + kfree(card->rxbd_ring_vbase); + return -ENOMEM; + } + + if (mwifiex_map_pci_memory(adapter, skb, + MWIFIEX_RX_DATA_BUF_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; + + MWIFIEX_SKB_PACB(skb, &buf_pa); + + dev_dbg(adapter->dev, + "info: RX ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n", + skb, skb->len, skb->data, (u32)buf_pa, + (u32)((u64)buf_pa >> 32)); + + card->rx_buf_list[i] = skb; + if (reg->pfu_enabled) { + card->rxbd_ring[i] = (void *)card->rxbd_ring_vbase + + (sizeof(*desc2) * i); + desc2 = card->rxbd_ring[i]; + desc2->paddr = buf_pa; + desc2->len = (u16)skb->len; + desc2->frag_len = (u16)skb->len; + desc2->flags = reg->ring_flag_eop | reg->ring_flag_sop; + desc2->offset = 0; + } else { + card->rxbd_ring[i] = (void *)(card->rxbd_ring_vbase + + (sizeof(*desc) * i)); + desc = card->rxbd_ring[i]; + desc->paddr = buf_pa; + desc->len = (u16)skb->len; + desc->flags = 0; + } + } + + return 0; +} + +/* This function initializes event buffer ring descriptors. Each SKB is + * allocated here and after mapping PCI memory, its physical address is assigned + * to PCIE Rx buffer descriptor's physical address + */ +static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + struct mwifiex_evt_buf_desc *desc; + struct sk_buff *skb; + dma_addr_t buf_pa; + int i; + + for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { + /* Allocate skb here so that firmware can DMA data from it */ + skb = dev_alloc_skb(MAX_EVENT_SIZE); + if (!skb) { + dev_err(adapter->dev, + "Unable to allocate skb for EVENT buf.\n"); + kfree(card->evtbd_ring_vbase); + return -ENOMEM; + } + skb_put(skb, MAX_EVENT_SIZE); + + if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; + + MWIFIEX_SKB_PACB(skb, &buf_pa); + + dev_dbg(adapter->dev, + "info: EVT ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n", + skb, skb->len, skb->data, (u32)buf_pa, + (u32)((u64)buf_pa >> 32)); + + card->evt_buf_list[i] = skb; + card->evtbd_ring[i] = (void *)(card->evtbd_ring_vbase + + (sizeof(*desc) * i)); + desc = card->evtbd_ring[i]; + desc->paddr = buf_pa; + desc->len = (u16)skb->len; + desc->flags = 0; + } + + return 0; +} + +/* This function cleans up TX buffer rings. If any of the buffer list has valid + * SKB address, associated SKB is freed. + */ +static void mwifiex_cleanup_txq_ring(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + struct sk_buff *skb; + struct mwifiex_pcie_buf_desc *desc; + struct mwifiex_pfu_buf_desc *desc2; + int i; + + for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { + if (reg->pfu_enabled) { + desc2 = card->txbd_ring[i]; + if (card->tx_buf_list[i]) { + skb = card->tx_buf_list[i]; + pci_unmap_single(card->dev, desc2->paddr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); + } + memset(desc2, 0, sizeof(*desc2)); + } else { + desc = card->txbd_ring[i]; + if (card->tx_buf_list[i]) { + skb = card->tx_buf_list[i]; + pci_unmap_single(card->dev, desc->paddr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); + } + memset(desc, 0, sizeof(*desc)); + } + card->tx_buf_list[i] = NULL; + } + + return; +} + +/* This function cleans up RX buffer rings. If any of the buffer list has valid + * SKB address, associated SKB is freed. + */ +static void mwifiex_cleanup_rxq_ring(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + struct mwifiex_pcie_buf_desc *desc; + struct mwifiex_pfu_buf_desc *desc2; + struct sk_buff *skb; + int i; + + for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { + if (reg->pfu_enabled) { + desc2 = card->rxbd_ring[i]; + if (card->rx_buf_list[i]) { + skb = card->rx_buf_list[i]; + pci_unmap_single(card->dev, desc2->paddr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); + } + memset(desc2, 0, sizeof(*desc2)); + } else { + desc = card->rxbd_ring[i]; + if (card->rx_buf_list[i]) { + skb = card->rx_buf_list[i]; + pci_unmap_single(card->dev, desc->paddr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); + } + memset(desc, 0, sizeof(*desc)); + } + card->rx_buf_list[i] = NULL; + } + + return; +} + +/* This function cleans up event buffer rings. If any of the buffer list has + * valid SKB address, associated SKB is freed. + */ +static void mwifiex_cleanup_evt_ring(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + struct mwifiex_evt_buf_desc *desc; + struct sk_buff *skb; + int i; + + for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { + desc = card->evtbd_ring[i]; + if (card->evt_buf_list[i]) { + skb = card->evt_buf_list[i]; + pci_unmap_single(card->dev, desc->paddr, MAX_EVENT_SIZE, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(skb); + } + card->evt_buf_list[i] = NULL; + memset(desc, 0, sizeof(*desc)); + } + + return; +} + +/* This function creates buffer descriptor ring for TX + */ +static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; /* * driver maintaines the write pointer and firmware maintaines the read @@ -376,76 +619,56 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) * starts at zero with rollover bit set */ card->txbd_wrptr = 0; - card->txbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND; + + if (reg->pfu_enabled) + card->txbd_rdptr = 0; + else + card->txbd_rdptr |= reg->tx_rollover_ind; /* allocate shared memory for the BD ring and divide the same in to several descriptors */ - card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * - MWIFIEX_MAX_TXRX_BD; + if (reg->pfu_enabled) + card->txbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) * + MWIFIEX_MAX_TXRX_BD; + else + card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * + MWIFIEX_MAX_TXRX_BD; + dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n", card->txbd_ring_size); - card->txbd_ring_vbase = kzalloc(card->txbd_ring_size, GFP_KERNEL); + card->txbd_ring_vbase = pci_alloc_consistent(card->dev, + card->txbd_ring_size, + &card->txbd_ring_pbase); if (!card->txbd_ring_vbase) { - dev_err(adapter->dev, "Unable to alloc buffer for txbd ring\n"); + dev_err(adapter->dev, + "allocate consistent memory (%d bytes) failed!\n", + card->txbd_ring_size); return -ENOMEM; } - card->txbd_ring_pbase = virt_to_phys(card->txbd_ring_vbase); - dev_dbg(adapter->dev, "info: txbd_ring - base: %p, pbase: %#x:%x, len: %x\n", - card->txbd_ring_vbase, (u32)card->txbd_ring_pbase, + card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase, (u32)((u64)card->txbd_ring_pbase >> 32), card->txbd_ring_size); - for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { - card->txbd_ring[i] = (struct mwifiex_pcie_buf_desc *) - (card->txbd_ring_vbase + - (sizeof(struct mwifiex_pcie_buf_desc) - * i)); - - /* Allocate buffer here so that firmware can DMA data from it */ - skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); - if (!skb) { - dev_err(adapter->dev, "Unable to allocate skb for TX ring.\n"); - kfree(card->txbd_ring_vbase); - return -ENOMEM; - } - buf_pa = mwifiex_update_sk_buff_pa(skb); - - skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE); - dev_dbg(adapter->dev, "info: TX ring: add new skb base: %p, " - "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n", - skb, skb->data, (u32)*buf_pa, - (u32)(((u64)*buf_pa >> 32)), skb->len); - - card->tx_buf_list[i] = skb; - card->txbd_ring[i]->paddr = *buf_pa; - card->txbd_ring[i]->len = (u16)skb->len; - card->txbd_ring[i]->flags = 0; - } - - return 0; + return mwifiex_init_txq_ring(adapter); } static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - int i; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { - if (card->tx_buf_list[i]) - dev_kfree_skb_any(card->tx_buf_list[i]); - card->tx_buf_list[i] = NULL; - card->txbd_ring[i]->paddr = 0; - card->txbd_ring[i]->len = 0; - card->txbd_ring[i]->flags = 0; - card->txbd_ring[i] = NULL; - } + mwifiex_cleanup_txq_ring(adapter); - kfree(card->txbd_ring_vbase); + if (card->txbd_ring_vbase) + pci_free_consistent(card->dev, card->txbd_ring_size, + card->txbd_ring_vbase, + card->txbd_ring_pbase); card->txbd_ring_size = 0; card->txbd_wrptr = 0; - card->txbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; + card->txbd_rdptr = 0 | reg->tx_rollover_ind; card->txbd_ring_vbase = NULL; + card->txbd_ring_pbase = 0; return 0; } @@ -456,9 +679,7 @@ static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter) static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - struct sk_buff *skb; - int i; - phys_addr_t *buf_pa; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; /* * driver maintaines the read pointer and firmware maintaines the write @@ -466,19 +687,26 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) * starts at zero with rollover bit set */ card->rxbd_wrptr = 0; - card->rxbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND; + card->rxbd_rdptr = reg->rx_rollover_ind; + + if (reg->pfu_enabled) + card->rxbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) * + MWIFIEX_MAX_TXRX_BD; + else + card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * + MWIFIEX_MAX_TXRX_BD; - card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * - MWIFIEX_MAX_TXRX_BD; dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n", card->rxbd_ring_size); - card->rxbd_ring_vbase = kzalloc(card->rxbd_ring_size, GFP_KERNEL); + card->rxbd_ring_vbase = pci_alloc_consistent(card->dev, + card->rxbd_ring_size, + &card->rxbd_ring_pbase); if (!card->rxbd_ring_vbase) { - dev_err(adapter->dev, "Unable to allocate buffer for " - "rxbd_ring.\n"); + dev_err(adapter->dev, + "allocate consistent memory (%d bytes) failed!\n", + card->rxbd_ring_size); return -ENOMEM; } - card->rxbd_ring_pbase = virt_to_phys(card->rxbd_ring_vbase); dev_dbg(adapter->dev, "info: rxbd_ring - base: %p, pbase: %#x:%x, len: %#x\n", @@ -486,35 +714,7 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) (u32)((u64)card->rxbd_ring_pbase >> 32), card->rxbd_ring_size); - for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { - card->rxbd_ring[i] = (struct mwifiex_pcie_buf_desc *) - (card->rxbd_ring_vbase + - (sizeof(struct mwifiex_pcie_buf_desc) - * i)); - - /* Allocate skb here so that firmware can DMA data from it */ - skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); - if (!skb) { - dev_err(adapter->dev, - "Unable to allocate skb for RX ring.\n"); - kfree(card->rxbd_ring_vbase); - return -ENOMEM; - } - buf_pa = mwifiex_update_sk_buff_pa(skb); - skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE); - - dev_dbg(adapter->dev, "info: RX ring: add new skb base: %p, " - "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n", - skb, skb->data, (u32)*buf_pa, (u32)((u64)*buf_pa >> 32), - skb->len); - - card->rx_buf_list[i] = skb; - card->rxbd_ring[i]->paddr = *buf_pa; - card->rxbd_ring[i]->len = (u16)skb->len; - card->rxbd_ring[i]->flags = 0; - } - - return 0; + return mwifiex_init_rxq_ring(adapter); } /* @@ -523,23 +723,19 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - int i; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { - if (card->rx_buf_list[i]) - dev_kfree_skb_any(card->rx_buf_list[i]); - card->rx_buf_list[i] = NULL; - card->rxbd_ring[i]->paddr = 0; - card->rxbd_ring[i]->len = 0; - card->rxbd_ring[i]->flags = 0; - card->rxbd_ring[i] = NULL; - } + mwifiex_cleanup_rxq_ring(adapter); - kfree(card->rxbd_ring_vbase); + if (card->rxbd_ring_vbase) + pci_free_consistent(card->dev, card->rxbd_ring_size, + card->rxbd_ring_vbase, + card->rxbd_ring_pbase); card->rxbd_ring_size = 0; card->rxbd_wrptr = 0; - card->rxbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; + card->rxbd_rdptr = 0 | reg->rx_rollover_ind; card->rxbd_ring_vbase = NULL; + card->rxbd_ring_pbase = 0; return 0; } @@ -550,9 +746,7 @@ static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter) static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - struct sk_buff *skb; - int i; - phys_addr_t *buf_pa; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; /* * driver maintaines the read pointer and firmware maintaines the write @@ -560,19 +754,22 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) * starts at zero with rollover bit set */ card->evtbd_wrptr = 0; - card->evtbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND; + card->evtbd_rdptr = reg->evt_rollover_ind; + + card->evtbd_ring_size = sizeof(struct mwifiex_evt_buf_desc) * + MWIFIEX_MAX_EVT_BD; - card->evtbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * - MWIFIEX_MAX_EVT_BD; dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n", card->evtbd_ring_size); - card->evtbd_ring_vbase = kzalloc(card->evtbd_ring_size, GFP_KERNEL); + card->evtbd_ring_vbase = pci_alloc_consistent(card->dev, + card->evtbd_ring_size, + &card->evtbd_ring_pbase); if (!card->evtbd_ring_vbase) { dev_err(adapter->dev, - "Unable to allocate buffer. Terminating download\n"); + "allocate consistent memory (%d bytes) failed!\n", + card->evtbd_ring_size); return -ENOMEM; } - card->evtbd_ring_pbase = virt_to_phys(card->evtbd_ring_vbase); dev_dbg(adapter->dev, "info: CMDRSP/EVT bd_ring - base: %p pbase: %#x:%x len: %#x\n", @@ -580,35 +777,7 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) (u32)((u64)card->evtbd_ring_pbase >> 32), card->evtbd_ring_size); - for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { - card->evtbd_ring[i] = (struct mwifiex_pcie_buf_desc *) - (card->evtbd_ring_vbase + - (sizeof(struct mwifiex_pcie_buf_desc) - * i)); - - /* Allocate skb here so that firmware can DMA data from it */ - skb = dev_alloc_skb(MAX_EVENT_SIZE); - if (!skb) { - dev_err(adapter->dev, - "Unable to allocate skb for EVENT buf.\n"); - kfree(card->evtbd_ring_vbase); - return -ENOMEM; - } - buf_pa = mwifiex_update_sk_buff_pa(skb); - skb_put(skb, MAX_EVENT_SIZE); - - dev_dbg(adapter->dev, "info: Evt ring: add new skb. base: %p, " - "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n", - skb, skb->data, (u32)*buf_pa, (u32)((u64)*buf_pa >> 32), - skb->len); - - card->evt_buf_list[i] = skb; - card->evtbd_ring[i]->paddr = *buf_pa; - card->evtbd_ring[i]->len = (u16)skb->len; - card->evtbd_ring[i]->flags = 0; - } - - return 0; + return mwifiex_pcie_init_evt_ring(adapter); } /* @@ -617,23 +786,19 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - int i; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { - if (card->evt_buf_list[i]) - dev_kfree_skb_any(card->evt_buf_list[i]); - card->evt_buf_list[i] = NULL; - card->evtbd_ring[i]->paddr = 0; - card->evtbd_ring[i]->len = 0; - card->evtbd_ring[i]->flags = 0; - card->evtbd_ring[i] = NULL; - } + mwifiex_cleanup_evt_ring(adapter); - kfree(card->evtbd_ring_vbase); + if (card->evtbd_ring_vbase) + pci_free_consistent(card->dev, card->evtbd_ring_size, + card->evtbd_ring_vbase, + card->evtbd_ring_pbase); card->evtbd_wrptr = 0; - card->evtbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; + card->evtbd_rdptr = 0 | reg->evt_rollover_ind; card->evtbd_ring_size = 0; card->evtbd_ring_vbase = NULL; + card->evtbd_ring_pbase = 0; return 0; } @@ -653,21 +818,12 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter) "Unable to allocate skb for command response data.\n"); return -ENOMEM; } - mwifiex_update_sk_buff_pa(skb); skb_put(skb, MWIFIEX_UPLD_SIZE); - card->cmdrsp_buf = skb; + if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; - skb = NULL; - /* Allocate memory for sending command to firmware */ - skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER); - if (!skb) { - dev_err(adapter->dev, - "Unable to allocate skb for command data.\n"); - return -ENOMEM; - } - mwifiex_update_sk_buff_pa(skb); - skb_put(skb, MWIFIEX_SIZE_OF_CMD_BUFFER); - card->cmd_buf = skb; + card->cmdrsp_buf = skb; return 0; } @@ -678,18 +834,26 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter) static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter) { struct pcie_service_card *card; + dma_addr_t buf_pa; if (!adapter) return 0; card = adapter->card; - if (card && card->cmdrsp_buf) + if (card && card->cmdrsp_buf) { + MWIFIEX_SKB_PACB(card->cmdrsp_buf, &buf_pa); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, + PCI_DMA_FROMDEVICE); dev_kfree_skb_any(card->cmdrsp_buf); + } - if (card && card->cmd_buf) + if (card && card->cmd_buf) { + MWIFIEX_SKB_PACB(card->cmd_buf, &buf_pa); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_SIZE_OF_CMD_BUFFER, + PCI_DMA_TODEVICE); dev_kfree_skb_any(card->cmd_buf); - + } return 0; } @@ -698,27 +862,19 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter) */ static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter) { - struct sk_buff *skb; struct pcie_service_card *card = adapter->card; - /* Allocate memory for sleep cookie */ - skb = dev_alloc_skb(sizeof(u32)); - if (!skb) { - dev_err(adapter->dev, - "Unable to allocate skb for sleep cookie!\n"); + card->sleep_cookie_vbase = pci_alloc_consistent(card->dev, sizeof(u32), + &card->sleep_cookie_pbase); + if (!card->sleep_cookie_vbase) { + dev_err(adapter->dev, "pci_alloc_consistent failed!\n"); return -ENOMEM; } - mwifiex_update_sk_buff_pa(skb); - skb_put(skb, sizeof(u32)); - /* Init val of Sleep Cookie */ - *(u32 *)skb->data = FW_AWAKE_COOKIE; + *(u32 *)card->sleep_cookie_vbase = FW_AWAKE_COOKIE; dev_dbg(adapter->dev, "alloc_scook: sleep cookie=0x%x\n", - *((u32 *)skb->data)); - - /* Save the sleep cookie */ - card->sleep_cookie = skb; + *((u32 *)card->sleep_cookie_vbase)); return 0; } @@ -735,86 +891,237 @@ static int mwifiex_pcie_delete_sleep_cookie_buf(struct mwifiex_adapter *adapter) card = adapter->card; - if (card && card->sleep_cookie) { - dev_kfree_skb_any(card->sleep_cookie); - card->sleep_cookie = NULL; + if (card && card->sleep_cookie_vbase) { + pci_free_consistent(card->dev, sizeof(u32), + card->sleep_cookie_vbase, + card->sleep_cookie_pbase); + card->sleep_cookie_vbase = NULL; } return 0; } +/* This function flushes the TX buffer descriptor ring + * This function defined as handler is also called while cleaning TXRX + * during disconnect/ bss stop. + */ +static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + + if (!mwifiex_pcie_txbd_empty(card, card->txbd_rdptr)) { + card->txbd_flush = 1; + /* write pointer already set at last send + * send dnld-rdy intr again, wait for completion. + */ + if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, + CPU_INTR_DNLD_RDY)) { + dev_err(adapter->dev, + "failed to assert dnld-rdy interrupt.\n"); + return -1; + } + } + return 0; +} + /* - * This function sends data buffer to device + * This function unmaps and frees downloaded data buffer */ -static int -mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb) +static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter) { + struct sk_buff *skb; + dma_addr_t buf_pa; + u32 wrdoneidx, rdptr, num_tx_buffs, unmap_count = 0; + struct mwifiex_pcie_buf_desc *desc; + struct mwifiex_pfu_buf_desc *desc2; struct pcie_service_card *card = adapter->card; - u32 wrindx, rdptr; - phys_addr_t *buf_pa; - __le16 *tmp; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; if (!mwifiex_pcie_ok_to_access_hw(adapter)) mwifiex_pm_wakeup_card(adapter); /* Read the TX ring read pointer set by firmware */ - if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) { + if (mwifiex_read_reg(adapter, reg->tx_rdptr, &rdptr)) { dev_err(adapter->dev, - "SEND DATA: failed to read REG_TXBD_RDPTR\n"); + "SEND COMP: failed to read reg->tx_rdptr\n"); return -1; } - wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK; + dev_dbg(adapter->dev, "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n", + card->txbd_rdptr, rdptr); - dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", rdptr, - card->txbd_wrptr); - if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) != - (rdptr & MWIFIEX_TXBD_MASK)) || - ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != - (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { - struct sk_buff *skb_data; + num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr; + /* free from previous txbd_rdptr to current txbd_rdptr */ + while (((card->txbd_rdptr & reg->tx_mask) != + (rdptr & reg->tx_mask)) || + ((card->txbd_rdptr & reg->tx_rollover_ind) != + (rdptr & reg->tx_rollover_ind))) { + wrdoneidx = (card->txbd_rdptr & reg->tx_mask) >> + reg->tx_start_ptr; + + skb = card->tx_buf_list[wrdoneidx]; + if (skb) { + dev_dbg(adapter->dev, + "SEND COMP: Detach skb %p at txbd_rdidx=%d\n", + skb, wrdoneidx); + MWIFIEX_SKB_PACB(skb, &buf_pa); + pci_unmap_single(card->dev, buf_pa, skb->len, + PCI_DMA_TODEVICE); + + unmap_count++; + + if (card->txbd_flush) + mwifiex_write_data_complete(adapter, skb, 0, + -1); + else + mwifiex_write_data_complete(adapter, skb, 0, 0); + } + + card->tx_buf_list[wrdoneidx] = NULL; + + if (reg->pfu_enabled) { + desc2 = (void *)card->txbd_ring[wrdoneidx]; + memset(desc2, 0, sizeof(*desc2)); + } else { + desc = card->txbd_ring[wrdoneidx]; + memset(desc, 0, sizeof(*desc)); + } + switch (card->dev->device) { + case PCIE_DEVICE_ID_MARVELL_88W8766P: + card->txbd_rdptr++; + break; + case PCIE_DEVICE_ID_MARVELL_88W8897: + card->txbd_rdptr += reg->ring_tx_start_ptr; + break; + } + + + if ((card->txbd_rdptr & reg->tx_mask) == num_tx_buffs) + card->txbd_rdptr = ((card->txbd_rdptr & + reg->tx_rollover_ind) ^ + reg->tx_rollover_ind); + } + + if (unmap_count) + adapter->data_sent = false; + + if (card->txbd_flush) { + if (mwifiex_pcie_txbd_empty(card, card->txbd_rdptr)) + card->txbd_flush = 0; + else + mwifiex_clean_pcie_ring_buf(adapter); + } + + return 0; +} + +/* This function sends data buffer to device. First 4 bytes of payload + * are filled with payload length and payload type. Then this payload + * is mapped to PCI device memory. Tx ring pointers are advanced accordingly. + * Download ready interrupt to FW is deffered if Tx ring is not full and + * additional payload can be accomodated. + */ +static int +mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb, + struct mwifiex_tx_param *tx_param) +{ + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + 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; + __le16 *tmp; + + if (!(skb->data && skb->len)) { + dev_err(adapter->dev, "%s(): invalid parameter <%p, %#x>\n", + __func__, skb->data, skb->len); + return -1; + } + + if (!mwifiex_pcie_ok_to_access_hw(adapter)) + mwifiex_pm_wakeup_card(adapter); + + num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr; + dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", + card->txbd_rdptr, card->txbd_wrptr); + if (mwifiex_pcie_txbd_not_full(card)) { u8 *payload; adapter->data_sent = true; - skb_data = card->tx_buf_list[wrindx]; - memcpy(skb_data->data, skb->data, skb->len); - payload = skb_data->data; + payload = skb->data; tmp = (__le16 *)&payload[0]; *tmp = cpu_to_le16((u16)skb->len); tmp = (__le16 *)&payload[2]; *tmp = cpu_to_le16(MWIFIEX_TYPE_DATA); - skb_put(skb_data, MWIFIEX_RX_DATA_BUF_SIZE - skb_data->len); - skb_trim(skb_data, skb->len); - buf_pa = MWIFIEX_SKB_PACB(skb_data); - card->txbd_ring[wrindx]->paddr = *buf_pa; - card->txbd_ring[wrindx]->len = (u16)skb_data->len; - card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC | - MWIFIEX_BD_FLAG_LAST_DESC; - - if ((++card->txbd_wrptr & MWIFIEX_TXBD_MASK) == - MWIFIEX_MAX_TXRX_BD) - card->txbd_wrptr = ((card->txbd_wrptr & - MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ - MWIFIEX_BD_FLAG_ROLLOVER_IND); - /* Write the TX ring write pointer in to REG_TXBD_WRPTR */ - if (mwifiex_write_reg(adapter, REG_TXBD_WRPTR, - card->txbd_wrptr)) { - dev_err(adapter->dev, - "SEND DATA: failed to write REG_TXBD_WRPTR\n"); - return 0; + if (mwifiex_map_pci_memory(adapter, skb, skb->len , + PCI_DMA_TODEVICE)) + return -1; + + wrindx = (card->txbd_wrptr & reg->tx_mask) >> reg->tx_start_ptr; + MWIFIEX_SKB_PACB(skb, &buf_pa); + card->tx_buf_list[wrindx] = skb; + + if (reg->pfu_enabled) { + desc2 = (void *)card->txbd_ring[wrindx]; + desc2->paddr = buf_pa; + desc2->len = (u16)skb->len; + desc2->frag_len = (u16)skb->len; + desc2->offset = 0; + desc2->flags = MWIFIEX_BD_FLAG_FIRST_DESC | + MWIFIEX_BD_FLAG_LAST_DESC; + } else { + desc = card->txbd_ring[wrindx]; + desc->paddr = buf_pa; + desc->len = (u16)skb->len; + desc->flags = MWIFIEX_BD_FLAG_FIRST_DESC | + MWIFIEX_BD_FLAG_LAST_DESC; } - /* Send the TX ready interrupt */ - if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, - CPU_INTR_DNLD_RDY)) { + switch (card->dev->device) { + case PCIE_DEVICE_ID_MARVELL_88W8766P: + card->txbd_wrptr++; + break; + case PCIE_DEVICE_ID_MARVELL_88W8897: + card->txbd_wrptr += reg->ring_tx_start_ptr; + break; + } + + if ((card->txbd_wrptr & reg->tx_mask) == num_tx_buffs) + card->txbd_wrptr = ((card->txbd_wrptr & + reg->tx_rollover_ind) ^ + reg->tx_rollover_ind); + + rx_val = card->rxbd_rdptr & reg->rx_wrap_mask; + /* Write the TX ring write pointer in to reg->tx_wrptr */ + if (mwifiex_write_reg(adapter, reg->tx_wrptr, + card->txbd_wrptr | rx_val)) { dev_err(adapter->dev, - "SEND DATA: failed to assert door-bell intr\n"); - return -1; + "SEND DATA: failed to write reg->tx_wrptr\n"); + ret = -1; + goto done_unmap; + } + if ((mwifiex_pcie_txbd_not_full(card)) && + tx_param->next_pkt_len) { + /* have more packets and TxBD still can hold more */ + dev_dbg(adapter->dev, + "SEND DATA: delay dnld-rdy interrupt.\n"); + adapter->data_sent = false; + } else { + /* Send the TX ready interrupt */ + if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, + CPU_INTR_DNLD_RDY)) { + dev_err(adapter->dev, + "SEND DATA: failed to assert dnld-rdy interrupt.\n"); + ret = -1; + goto done_unmap; + } } dev_dbg(adapter->dev, "info: SEND DATA: Updated <Rd: %#x, Wr: " "%#x> and sent packet to firmware successfully\n", - rdptr, card->txbd_wrptr); + card->txbd_rdptr, card->txbd_wrptr); } else { dev_dbg(adapter->dev, "info: TX Ring full, can't send packets to fw\n"); @@ -827,7 +1134,17 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb) return -EBUSY; } - return 0; + return -EINPROGRESS; +done_unmap: + MWIFIEX_SKB_PACB(skb, &buf_pa); + pci_unmap_single(card->dev, buf_pa, skb->len, PCI_DMA_TODEVICE); + card->tx_buf_list[wrindx] = NULL; + if (reg->pfu_enabled) + memset(desc2, 0, sizeof(*desc2)); + else + memset(desc, 0, sizeof(*desc)); + + return ret; } /* @@ -837,78 +1154,119 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb) static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - u32 wrptr, rd_index; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + u32 wrptr, rd_index, tx_val; + dma_addr_t buf_pa; int ret = 0; struct sk_buff *skb_tmp = NULL; + struct mwifiex_pcie_buf_desc *desc; + struct mwifiex_pfu_buf_desc *desc2; + + if (!mwifiex_pcie_ok_to_access_hw(adapter)) + mwifiex_pm_wakeup_card(adapter); /* Read the RX ring Write pointer set by firmware */ - if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) { + if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) { dev_err(adapter->dev, - "RECV DATA: failed to read REG_TXBD_RDPTR\n"); + "RECV DATA: failed to read reg->rx_wrptr\n"); ret = -1; goto done; } + card->rxbd_wrptr = wrptr; - while (((wrptr & MWIFIEX_RXBD_MASK) != - (card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) || - ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) == - (card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { + while (((wrptr & reg->rx_mask) != + (card->rxbd_rdptr & reg->rx_mask)) || + ((wrptr & reg->rx_rollover_ind) == + (card->rxbd_rdptr & reg->rx_rollover_ind))) { struct sk_buff *skb_data; u16 rx_len; + __le16 pkt_len; - rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK; + rd_index = card->rxbd_rdptr & reg->rx_mask; skb_data = card->rx_buf_list[rd_index]; + MWIFIEX_SKB_PACB(skb_data, &buf_pa); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_RX_DATA_BUF_SIZE, + PCI_DMA_FROMDEVICE); + card->rx_buf_list[rd_index] = NULL; + /* Get data length from interface header - - first byte is len, second byte is type */ - rx_len = *((u16 *)skb_data->data); + * first 2 bytes for len, next 2 bytes is for type + */ + pkt_len = *((__le16 *)skb_data->data); + rx_len = le16_to_cpu(pkt_len); + skb_put(skb_data, rx_len); dev_dbg(adapter->dev, "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n", card->rxbd_rdptr, wrptr, rx_len); - skb_tmp = dev_alloc_skb(rx_len); + skb_pull(skb_data, INTF_HEADER_LEN); + mwifiex_handle_rx_packet(adapter, skb_data); + + skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); if (!skb_tmp) { - dev_dbg(adapter->dev, - "info: Failed to alloc skb for RX\n"); - ret = -EBUSY; - goto done; + dev_err(adapter->dev, + "Unable to allocate skb.\n"); + return -ENOMEM; } - skb_put(skb_tmp, rx_len); + if (mwifiex_map_pci_memory(adapter, skb_tmp, + MWIFIEX_RX_DATA_BUF_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; + + MWIFIEX_SKB_PACB(skb_tmp, &buf_pa); + + dev_dbg(adapter->dev, + "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n", + skb_tmp, rd_index); + card->rx_buf_list[rd_index] = skb_tmp; + + if (reg->pfu_enabled) { + desc2 = (void *)card->rxbd_ring[rd_index]; + desc2->paddr = buf_pa; + desc2->len = skb_tmp->len; + desc2->frag_len = skb_tmp->len; + desc2->offset = 0; + desc2->flags = reg->ring_flag_sop | reg->ring_flag_eop; + } else { + desc = card->rxbd_ring[rd_index]; + desc->paddr = buf_pa; + desc->len = skb_tmp->len; + desc->flags = 0; + } - memcpy(skb_tmp->data, skb_data->data + INTF_HEADER_LEN, rx_len); - if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) == + if ((++card->rxbd_rdptr & reg->rx_mask) == MWIFIEX_MAX_TXRX_BD) { card->rxbd_rdptr = ((card->rxbd_rdptr & - MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ - MWIFIEX_BD_FLAG_ROLLOVER_IND); + reg->rx_rollover_ind) ^ + reg->rx_rollover_ind); } dev_dbg(adapter->dev, "info: RECV DATA: <Rd: %#x, Wr: %#x>\n", card->rxbd_rdptr, wrptr); - /* Write the RX ring read pointer in to REG_RXBD_RDPTR */ - if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR, - card->rxbd_rdptr)) { + tx_val = card->txbd_wrptr & reg->tx_wrap_mask; + /* Write the RX ring read pointer in to reg->rx_rdptr */ + if (mwifiex_write_reg(adapter, reg->rx_rdptr, + card->rxbd_rdptr | tx_val)) { dev_err(adapter->dev, - "RECV DATA: failed to write REG_RXBD_RDPTR\n"); + "RECV DATA: failed to write reg->rx_rdptr\n"); ret = -1; goto done; } /* Read the RX ring Write pointer set by firmware */ - if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) { + if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) { dev_err(adapter->dev, - "RECV DATA: failed to read REG_TXBD_RDPTR\n"); + "RECV DATA: failed to read reg->rx_wrptr\n"); ret = -1; goto done; } dev_dbg(adapter->dev, "info: RECV DATA: Rcvd packet from fw successfully\n"); - mwifiex_handle_rx_packet(adapter, skb_tmp); + card->rxbd_wrptr = wrptr; } done: - if (ret && skb_tmp) - dev_kfree_skb_any(skb_tmp); return ret; } @@ -918,40 +1276,54 @@ done: static int mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) { - phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb); + dma_addr_t buf_pa; + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - if (!(skb->data && skb->len && *buf_pa)) { + if (!(skb->data && skb->len)) { dev_err(adapter->dev, - "Invalid parameter in %s <%p, %#x:%x, %x>\n", - __func__, skb->data, skb->len, - (u32)*buf_pa, (u32)((u64)*buf_pa >> 32)); + "Invalid parameter in %s <%p. len %d>\n", + __func__, skb->data, skb->len); return -1; } - /* Write the lower 32bits of the physical address to scratch - * register 0 */ - if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)*buf_pa)) { + if (mwifiex_map_pci_memory(adapter, skb, skb->len , PCI_DMA_TODEVICE)) + return -1; + + MWIFIEX_SKB_PACB(skb, &buf_pa); + + /* Write the lower 32bits of the physical address to low command + * address scratch register + */ + if (mwifiex_write_reg(adapter, reg->cmd_addr_lo, (u32)buf_pa)) { dev_err(adapter->dev, "%s: failed to write download command to boot code.\n", __func__); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, + PCI_DMA_TODEVICE); return -1; } - /* Write the upper 32bits of the physical address to scratch - * register 1 */ - if (mwifiex_write_reg(adapter, PCIE_SCRATCH_1_REG, - (u32)((u64)*buf_pa >> 32))) { + /* Write the upper 32bits of the physical address to high command + * address scratch register + */ + if (mwifiex_write_reg(adapter, reg->cmd_addr_hi, + (u32)((u64)buf_pa >> 32))) { dev_err(adapter->dev, "%s: failed to write download command to boot code.\n", __func__); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, + PCI_DMA_TODEVICE); return -1; } - /* Write the command length to scratch register 2 */ - if (mwifiex_write_reg(adapter, PCIE_SCRATCH_2_REG, skb->len)) { + /* Write the command length to cmd_size scratch register */ + if (mwifiex_write_reg(adapter, reg->cmd_size, skb->len)) { dev_err(adapter->dev, - "%s: failed to write command len to scratch reg 2\n", + "%s: failed to write command len to cmd_size scratch reg\n", __func__); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, + PCI_DMA_TODEVICE); return -1; } @@ -960,22 +1332,43 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) CPU_INTR_DOOR_BELL)) { dev_err(adapter->dev, "%s: failed to assert door-bell intr\n", __func__); + pci_unmap_single(card->dev, buf_pa, + MWIFIEX_UPLD_SIZE, PCI_DMA_TODEVICE); return -1; } return 0; } -/* - * This function downloads commands to the device +/* This function init rx port in firmware which in turn enables to receive data + * from device before transmitting any packet. + */ +static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + + /* Write the RX ring read pointer in to reg->rx_rdptr */ + if (mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | + tx_wrap)) { + dev_err(adapter->dev, + "RECV DATA: failed to write reg->rx_rdptr\n"); + return -1; + } + return 0; +} + +/* This function downloads commands to the device */ static int mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) { struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; int ret = 0; - phys_addr_t *cmd_buf_pa; - phys_addr_t *cmdrsp_buf_pa; + dma_addr_t cmd_buf_pa, cmdrsp_buf_pa; + u8 *payload = (u8 *)skb->data; if (!(skb->data && skb->len)) { dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x>\n", @@ -990,21 +1383,22 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) return -EBUSY; } - /* Make sure a command buffer is available */ - if (!card->cmd_buf) { - dev_err(adapter->dev, "Command buffer not available\n"); - return -EBUSY; - } + if (!mwifiex_pcie_ok_to_access_hw(adapter)) + mwifiex_pm_wakeup_card(adapter); adapter->cmd_sent = true; - /* Copy the given skb in to DMA accessable shared buffer */ - skb_put(card->cmd_buf, MWIFIEX_SIZE_OF_CMD_BUFFER - card->cmd_buf->len); - skb_trim(card->cmd_buf, skb->len); - memcpy(card->cmd_buf->data, skb->data, skb->len); + + *(__le16 *)&payload[0] = cpu_to_le16((u16)skb->len); + *(__le16 *)&payload[2] = cpu_to_le16(MWIFIEX_TYPE_CMD); + + if (mwifiex_map_pci_memory(adapter, skb, skb->len, PCI_DMA_TODEVICE)) + return -1; + + card->cmd_buf = skb; /* To send a command, the driver will: 1. Write the 64bit physical address of the data buffer to - SCRATCH1 + SCRATCH0 + cmd response address low + cmd response address high 2. Ring the door bell (i.e. set the door bell interrupt) In response to door bell interrupt, the firmware will perform @@ -1013,11 +1407,11 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) */ if (card->cmdrsp_buf) { - cmdrsp_buf_pa = MWIFIEX_SKB_PACB(card->cmdrsp_buf); + MWIFIEX_SKB_PACB(card->cmdrsp_buf, &cmdrsp_buf_pa); /* Write the lower 32bits of the cmdrsp buffer physical address */ - if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, - (u32)*cmdrsp_buf_pa)) { + if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo, + (u32)cmdrsp_buf_pa)) { dev_err(adapter->dev, "Failed to write download cmd to boot code.\n"); ret = -1; @@ -1025,8 +1419,8 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) } /* Write the upper 32bits of the cmdrsp buffer physical address */ - if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, - (u32)((u64)*cmdrsp_buf_pa >> 32))) { + if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi, + (u32)((u64)cmdrsp_buf_pa >> 32))) { dev_err(adapter->dev, "Failed to write download cmd to boot code.\n"); ret = -1; @@ -1034,27 +1428,29 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) } } - cmd_buf_pa = MWIFIEX_SKB_PACB(card->cmd_buf); - /* Write the lower 32bits of the physical address to REG_CMD_ADDR_LO */ - if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO, (u32)*cmd_buf_pa)) { + MWIFIEX_SKB_PACB(card->cmd_buf, &cmd_buf_pa); + /* Write the lower 32bits of the physical address to reg->cmd_addr_lo */ + if (mwifiex_write_reg(adapter, reg->cmd_addr_lo, + (u32)cmd_buf_pa)) { dev_err(adapter->dev, "Failed to write download cmd to boot code.\n"); ret = -1; goto done; } - /* Write the upper 32bits of the physical address to REG_CMD_ADDR_HI */ - if (mwifiex_write_reg(adapter, REG_CMD_ADDR_HI, - (u32)((u64)*cmd_buf_pa >> 32))) { + /* Write the upper 32bits of the physical address to reg->cmd_addr_hi */ + if (mwifiex_write_reg(adapter, reg->cmd_addr_hi, + (u32)((u64)cmd_buf_pa >> 32))) { dev_err(adapter->dev, "Failed to write download cmd to boot code.\n"); ret = -1; goto done; } - /* Write the command length to REG_CMD_SIZE */ - if (mwifiex_write_reg(adapter, REG_CMD_SIZE, card->cmd_buf->len)) { + /* Write the command length to reg->cmd_size */ + if (mwifiex_write_reg(adapter, reg->cmd_size, + card->cmd_buf->len)) { dev_err(adapter->dev, - "Failed to write cmd len to REG_CMD_SIZE\n"); + "Failed to write cmd len to reg->cmd_size\n"); ret = -1; goto done; } @@ -1081,18 +1477,30 @@ done: static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; struct sk_buff *skb = card->cmdrsp_buf; int count = 0; + u16 rx_len; + __le16 pkt_len; + dma_addr_t buf_pa; dev_dbg(adapter->dev, "info: Rx CMD Response\n"); + MWIFIEX_SKB_PACB(skb, &buf_pa); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, + PCI_DMA_FROMDEVICE); + + pkt_len = *((__le16 *)skb->data); + rx_len = le16_to_cpu(pkt_len); + skb_trim(skb, rx_len); + skb_pull(skb, INTF_HEADER_LEN); + if (!adapter->curr_cmd) { - skb_pull(skb, INTF_HEADER_LEN); if (adapter->ps_state == PS_STATE_SLEEP_CFM) { mwifiex_process_sleep_confirm_resp(adapter, skb->data, skb->len); - while (mwifiex_pcie_ok_to_access_hw(adapter) && - (count++ < 10)) + while (reg->sleep_cookie && (count++ < 10) && + mwifiex_pcie_ok_to_access_hw(adapter)) usleep_range(50, 60); } else { dev_err(adapter->dev, @@ -1100,9 +1508,12 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) } memcpy(adapter->upld_buf, skb->data, min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len)); - skb_push(skb, INTF_HEADER_LEN); + if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; + + MWIFIEX_SKB_PACB(skb, &buf_pa); } else if (mwifiex_pcie_ok_to_access_hw(adapter)) { - skb_pull(skb, INTF_HEADER_LEN); adapter->curr_cmd->resp_skb = skb; adapter->cmd_resp_received = true; /* Take the pointer and set it to CMD node and will @@ -1112,14 +1523,14 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) /* Clear the cmd-rsp buffer address in scratch registers. This will prevent firmware from writing to the same response buffer again. */ - if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, 0)) { + if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo, 0)) { dev_err(adapter->dev, "cmd_done: failed to clear cmd_rsp_addr_lo\n"); return -1; } /* Write the upper 32bits of the cmdrsp buffer physical address */ - if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, 0)) { + if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi, 0)) { dev_err(adapter->dev, "cmd_done: failed to clear cmd_rsp_addr_hi\n"); return -1; @@ -1136,10 +1547,23 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter, struct sk_buff *skb) { struct pcie_service_card *card = adapter->card; + dma_addr_t buf_pa; + struct sk_buff *skb_tmp; if (skb) { card->cmdrsp_buf = skb; skb_push(card->cmdrsp_buf, INTF_HEADER_LEN); + if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; + } + + skb_tmp = card->cmd_buf; + if (skb_tmp) { + MWIFIEX_SKB_PACB(skb_tmp, &buf_pa); + pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE, + PCI_DMA_FROMDEVICE); + card->cmd_buf = NULL; } return 0; @@ -1151,8 +1575,14 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter, static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK; u32 wrptr, event; + dma_addr_t buf_pa; + struct mwifiex_evt_buf_desc *desc; + + if (!mwifiex_pcie_ok_to_access_hw(adapter)) + mwifiex_pm_wakeup_card(adapter); if (adapter->event_received) { dev_dbg(adapter->dev, "info: Event being processed, " @@ -1166,9 +1596,9 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) } /* Read the event ring write pointer set by firmware */ - if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) { + if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) { dev_err(adapter->dev, - "EventReady: failed to read REG_EVTBD_WRPTR\n"); + "EventReady: failed to read reg->evt_wrptr\n"); return -1; } @@ -1176,20 +1606,23 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) card->evtbd_rdptr, wrptr); if (((wrptr & MWIFIEX_EVTBD_MASK) != (card->evtbd_rdptr & MWIFIEX_EVTBD_MASK)) || - ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) == - (card->evtbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { + ((wrptr & reg->evt_rollover_ind) == + (card->evtbd_rdptr & reg->evt_rollover_ind))) { struct sk_buff *skb_cmd; __le16 data_len = 0; u16 evt_len; dev_dbg(adapter->dev, "info: Read Index: %d\n", rdptr); skb_cmd = card->evt_buf_list[rdptr]; + MWIFIEX_SKB_PACB(skb_cmd, &buf_pa); + pci_unmap_single(card->dev, buf_pa, MAX_EVENT_SIZE, + PCI_DMA_FROMDEVICE); + /* Take the pointer and set it to event pointer in adapter and will return back after event handling callback */ card->evt_buf_list[rdptr] = NULL; - card->evtbd_ring[rdptr]->paddr = 0; - card->evtbd_ring[rdptr]->len = 0; - card->evtbd_ring[rdptr]->flags = 0; + desc = card->evtbd_ring[rdptr]; + memset(desc, 0, sizeof(*desc)); event = *(u32 *) &skb_cmd->data[INTF_HEADER_LEN]; adapter->event_cause = event; @@ -1225,10 +1658,12 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, struct sk_buff *skb) { struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; int ret = 0; u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK; u32 wrptr; - phys_addr_t *buf_pa; + dma_addr_t buf_pa; + struct mwifiex_evt_buf_desc *desc; if (!skb) return 0; @@ -1240,19 +1675,25 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, } /* Read the event ring write pointer set by firmware */ - if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) { + if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) { dev_err(adapter->dev, - "event_complete: failed to read REG_EVTBD_WRPTR\n"); + "event_complete: failed to read reg->evt_wrptr\n"); return -1; } if (!card->evt_buf_list[rdptr]) { skb_push(skb, INTF_HEADER_LEN); + if (mwifiex_map_pci_memory(adapter, skb, + MAX_EVENT_SIZE, + PCI_DMA_FROMDEVICE)) + return -1; + MWIFIEX_SKB_PACB(skb, &buf_pa); card->evt_buf_list[rdptr] = skb; - buf_pa = MWIFIEX_SKB_PACB(skb); - card->evtbd_ring[rdptr]->paddr = *buf_pa; - card->evtbd_ring[rdptr]->len = (u16)skb->len; - card->evtbd_ring[rdptr]->flags = 0; + MWIFIEX_SKB_PACB(skb, &buf_pa); + desc = card->evtbd_ring[rdptr]; + desc->paddr = buf_pa; + desc->len = (u16)skb->len; + desc->flags = 0; skb = NULL; } else { dev_dbg(adapter->dev, @@ -1262,17 +1703,18 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) { card->evtbd_rdptr = ((card->evtbd_rdptr & - MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ - MWIFIEX_BD_FLAG_ROLLOVER_IND); + reg->evt_rollover_ind) ^ + reg->evt_rollover_ind); } dev_dbg(adapter->dev, "info: Updated <Rd: 0x%x, Wr: 0x%x>", card->evtbd_rdptr, wrptr); - /* Write the event ring read pointer in to REG_EVTBD_RDPTR */ - if (mwifiex_write_reg(adapter, REG_EVTBD_RDPTR, card->evtbd_rdptr)) { + /* Write the event ring read pointer in to reg->evt_rdptr */ + if (mwifiex_write_reg(adapter, reg->evt_rdptr, + card->evtbd_rdptr)) { dev_err(adapter->dev, - "event_complete: failed to read REG_EVTBD_RDPTR\n"); + "event_complete: failed to read reg->evt_rdptr\n"); return -1; } @@ -1299,11 +1741,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, struct sk_buff *skb; u32 txlen, tx_blocks = 0, tries, len; u32 block_retry_cnt = 0; - - if (!adapter) { - pr_err("adapter structure is not valid\n"); - return -1; - } + dma_addr_t buf_pa; + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; if (!firmware || !firmware_len) { dev_err(adapter->dev, @@ -1325,7 +1765,6 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, ret = -ENOMEM; goto done; } - mwifiex_update_sk_buff_pa(skb); /* Perform firmware data transfer */ do { @@ -1336,7 +1775,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, PCIE_SCRATCH_2_REG, + ret = mwifiex_read_reg(adapter, reg->cmd_size, &len); if (ret) { dev_warn(adapter->dev, @@ -1382,16 +1821,15 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, dev_dbg(adapter->dev, "."); - tx_blocks = (txlen + - MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD - 1) / - MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD; + tx_blocks = (txlen + card->pcie.blksz_fw_dl - 1) / + card->pcie.blksz_fw_dl; /* Copy payload to buffer */ memmove(skb->data, &firmware[offset], txlen); } skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len); - skb_trim(skb, tx_blocks * MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD); + skb_trim(skb, tx_blocks * card->pcie.blksz_fw_dl); /* Send the boot command to device */ if (mwifiex_pcie_send_boot_cmd(adapter, skb)) { @@ -1400,6 +1838,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, ret = -1; goto done; } + + MWIFIEX_SKB_PACB(skb, &buf_pa); + /* Wait for the command done interrupt */ do { if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS, @@ -1407,11 +1848,17 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, dev_err(adapter->dev, "%s: Failed to read " "interrupt status during fw dnld.\n", __func__); + pci_unmap_single(card->dev, buf_pa, skb->len, + PCI_DMA_TODEVICE); ret = -1; goto done; } } while ((ireg_intr & CPU_INTR_DOOR_BELL) == CPU_INTR_DOOR_BELL); + + pci_unmap_single(card->dev, buf_pa, skb->len, + PCI_DMA_TODEVICE); + offset += txlen; } while (true); @@ -1435,6 +1882,8 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) { int ret = 0; u32 firmware_stat, winner_status; + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; u32 tries; /* Mask spurios interrupts */ @@ -1445,7 +1894,8 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) } dev_dbg(adapter->dev, "Setting driver ready signature\n"); - if (mwifiex_write_reg(adapter, REG_DRV_READY, FIRMWARE_READY_PCIE)) { + if (mwifiex_write_reg(adapter, reg->drv_rdy, + FIRMWARE_READY_PCIE)) { dev_err(adapter->dev, "Failed to write driver ready signature\n"); return -1; @@ -1453,7 +1903,7 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) /* Wait for firmware initialization event */ for (tries = 0; tries < poll_num; tries++) { - if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG, + if (mwifiex_read_reg(adapter, reg->fw_status, &firmware_stat)) ret = -1; else @@ -1470,7 +1920,7 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) } if (ret) { - if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG, + if (mwifiex_read_reg(adapter, reg->fw_status, &winner_status)) ret = -1; else if (!winner_status) { @@ -1594,39 +2044,40 @@ exit: static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) { int ret; - u32 pcie_ireg = 0; + u32 pcie_ireg; unsigned long flags; spin_lock_irqsave(&adapter->int_lock, flags); /* Clear out unused interrupts */ - adapter->int_status &= HOST_INTR_MASK; + pcie_ireg = adapter->int_status; + adapter->int_status = 0; spin_unlock_irqrestore(&adapter->int_lock, flags); - while (adapter->int_status & HOST_INTR_MASK) { - if (adapter->int_status & HOST_INTR_DNLD_DONE) { - adapter->int_status &= ~HOST_INTR_DNLD_DONE; - if (adapter->data_sent) { - dev_dbg(adapter->dev, "info: DATA sent intr\n"); - adapter->data_sent = false; - } + while (pcie_ireg & HOST_INTR_MASK) { + if (pcie_ireg & HOST_INTR_DNLD_DONE) { + pcie_ireg &= ~HOST_INTR_DNLD_DONE; + dev_dbg(adapter->dev, "info: TX DNLD Done\n"); + ret = mwifiex_pcie_send_data_complete(adapter); + if (ret) + return ret; } - if (adapter->int_status & HOST_INTR_UPLD_RDY) { - adapter->int_status &= ~HOST_INTR_UPLD_RDY; + if (pcie_ireg & HOST_INTR_UPLD_RDY) { + pcie_ireg &= ~HOST_INTR_UPLD_RDY; dev_dbg(adapter->dev, "info: Rx DATA\n"); ret = mwifiex_pcie_process_recv_data(adapter); if (ret) return ret; } - if (adapter->int_status & HOST_INTR_EVENT_RDY) { - adapter->int_status &= ~HOST_INTR_EVENT_RDY; + if (pcie_ireg & HOST_INTR_EVENT_RDY) { + pcie_ireg &= ~HOST_INTR_EVENT_RDY; dev_dbg(adapter->dev, "info: Rx EVENT\n"); ret = mwifiex_pcie_process_event_ready(adapter); if (ret) return ret; } - if (adapter->int_status & HOST_INTR_CMD_DONE) { - adapter->int_status &= ~HOST_INTR_CMD_DONE; + if (pcie_ireg & HOST_INTR_CMD_DONE) { + pcie_ireg &= ~HOST_INTR_CMD_DONE; if (adapter->cmd_sent) { dev_dbg(adapter->dev, "info: CMD sent Interrupt\n"); @@ -1654,8 +2105,6 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) "Write register failed\n"); return -1; } - adapter->int_status |= pcie_ireg; - adapter->int_status &= HOST_INTR_MASK; } } @@ -1687,7 +2136,7 @@ static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type, } if (type == MWIFIEX_TYPE_DATA) - return mwifiex_pcie_send_data(adapter, skb); + return mwifiex_pcie_send_data(adapter, skb, tx_param); else if (type == MWIFIEX_TYPE_CMD) return mwifiex_pcie_send_cmd(adapter, skb); @@ -1709,6 +2158,7 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter) struct pcie_service_card *card = adapter->card; int ret; struct pci_dev *pdev = card->dev; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; pci_set_drvdata(pdev, card); @@ -1739,6 +2189,7 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter) card->pci_mmap = pci_iomap(pdev, 0, 0); if (!card->pci_mmap) { dev_err(adapter->dev, "iomap(0) error\n"); + ret = -EIO; goto err_iomap0; } ret = pci_request_region(pdev, 2, DRV_NAME); @@ -1749,6 +2200,7 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter) card->pci_mmap1 = pci_iomap(pdev, 2, 0); if (!card->pci_mmap1) { dev_err(adapter->dev, "iomap(2) error\n"); + ret = -EIO; goto err_iomap2; } @@ -1769,10 +2221,13 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter) ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter); if (ret) goto err_alloc_cmdbuf; - ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter); - if (ret) - goto err_alloc_cookie; - + if (reg->sleep_cookie) { + ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter); + if (ret) + goto err_alloc_cookie; + } else { + card->sleep_cookie_vbase = NULL; + } return ret; err_alloc_cookie: @@ -1813,17 +2268,11 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; struct pci_dev *pdev = card->dev; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - mwifiex_pcie_delete_sleep_cookie_buf(adapter); - mwifiex_pcie_delete_cmdrsp_buf(adapter); - mwifiex_pcie_delete_evtbd_ring(adapter); - mwifiex_pcie_delete_rxbd_ring(adapter); - mwifiex_pcie_delete_txbd_ring(adapter); - card->cmdrsp_buf = NULL; - - dev_dbg(adapter->dev, "Clearing driver ready signature\n"); if (user_rmmod) { - if (mwifiex_write_reg(adapter, REG_DRV_READY, 0x00000000)) + dev_dbg(adapter->dev, "Clearing driver ready signature\n"); + if (mwifiex_write_reg(adapter, reg->drv_rdy, 0x00000000)) dev_err(adapter->dev, "Failed to write driver not-ready signature\n"); } @@ -1861,7 +2310,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) } adapter->dev = &pdev->dev; - strcpy(adapter->fw_name, PCIE8766_DEFAULT_FW_NAME); + strcpy(adapter->fw_name, card->pcie.firmware); return 0; } @@ -1875,10 +2324,21 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg; if (card) { dev_dbg(adapter->dev, "%s(): calling free_irq()\n", __func__); free_irq(card->dev->irq, card->dev); + + reg = card->pcie.reg; + if (reg->sleep_cookie) + mwifiex_pcie_delete_sleep_cookie_buf(adapter); + + mwifiex_pcie_delete_cmdrsp_buf(adapter); + mwifiex_pcie_delete_evtbd_ring(adapter); + mwifiex_pcie_delete_rxbd_ring(adapter); + mwifiex_pcie_delete_txbd_ring(adapter); + card->cmdrsp_buf = NULL; } } @@ -1900,6 +2360,8 @@ static struct mwifiex_if_ops pcie_ops = { .event_complete = mwifiex_pcie_event_complete, .update_mp_end_port = NULL, .cleanup_mpa_buf = NULL, + .init_fw_port = mwifiex_pcie_init_fw_port, + .clean_pcie_ring = mwifiex_clean_pcie_ring_buf, }; /* @@ -1912,7 +2374,7 @@ static int mwifiex_pcie_init_module(void) { int ret; - pr_debug("Marvell 8766 PCIe Driver\n"); + pr_debug("Marvell PCIe Driver\n"); sema_init(&add_remove_card_sem, 1); @@ -1955,4 +2417,5 @@ MODULE_AUTHOR("Marvell International Ltd."); MODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION); MODULE_VERSION(PCIE_VERSION); MODULE_LICENSE("GPL v2"); -MODULE_FIRMWARE("mrvl/pcie8766_uapsta.bin"); +MODULE_FIRMWARE(PCIE8766_DEFAULT_FW_NAME); +MODULE_FIRMWARE(PCIE8897_DEFAULT_FW_NAME); diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h index 2f218f9a3fd3..d322ab8604ea 100644 --- a/drivers/net/wireless/mwifiex/pcie.h +++ b/drivers/net/wireless/mwifiex/pcie.h @@ -29,6 +29,11 @@ #include "main.h" #define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin" +#define PCIE8897_DEFAULT_FW_NAME "mrvl/pcie8897_uapsta.bin" + +#define PCIE_VENDOR_ID_MARVELL (0x11ab) +#define PCIE_DEVICE_ID_MARVELL_88W8766P (0x2b30) +#define PCIE_DEVICE_ID_MARVELL_88W8897 (0x2b38) /* Constants for Buffer Descriptor (BD) rings */ #define MWIFIEX_MAX_TXRX_BD 0x20 @@ -57,6 +62,8 @@ #define PCIE_SCRATCH_10_REG 0xCE8 #define PCIE_SCRATCH_11_REG 0xCEC #define PCIE_SCRATCH_12_REG 0xCF0 +#define PCIE_RD_DATA_PTR_Q0_Q1 0xC08C +#define PCIE_WR_DATA_PTR_Q0_Q1 0xC05C #define CPU_INTR_DNLD_RDY BIT(0) #define CPU_INTR_DOOR_BELL BIT(1) @@ -75,27 +82,14 @@ #define MWIFIEX_BD_FLAG_ROLLOVER_IND BIT(7) #define MWIFIEX_BD_FLAG_FIRST_DESC BIT(0) #define MWIFIEX_BD_FLAG_LAST_DESC BIT(1) -#define REG_CMD_ADDR_LO PCIE_SCRATCH_0_REG -#define REG_CMD_ADDR_HI PCIE_SCRATCH_1_REG -#define REG_CMD_SIZE PCIE_SCRATCH_2_REG - -#define REG_CMDRSP_ADDR_LO PCIE_SCRATCH_4_REG -#define REG_CMDRSP_ADDR_HI PCIE_SCRATCH_5_REG - -/* TX buffer description read pointer */ -#define REG_TXBD_RDPTR PCIE_SCRATCH_6_REG -/* TX buffer description write pointer */ -#define REG_TXBD_WRPTR PCIE_SCRATCH_7_REG -/* RX buffer description read pointer */ -#define REG_RXBD_RDPTR PCIE_SCRATCH_8_REG -/* RX buffer description write pointer */ -#define REG_RXBD_WRPTR PCIE_SCRATCH_9_REG -/* Event buffer description read pointer */ -#define REG_EVTBD_RDPTR PCIE_SCRATCH_10_REG -/* Event buffer description write pointer */ -#define REG_EVTBD_WRPTR PCIE_SCRATCH_11_REG -/* Driver ready signature write pointer */ -#define REG_DRV_READY PCIE_SCRATCH_12_REG +#define MWIFIEX_BD_FLAG_SOP BIT(0) +#define MWIFIEX_BD_FLAG_EOP BIT(1) +#define MWIFIEX_BD_FLAG_XS_SOP BIT(2) +#define MWIFIEX_BD_FLAG_XS_EOP BIT(3) +#define MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND BIT(7) +#define MWIFIEX_BD_FLAG_RX_ROLLOVER_IND BIT(10) +#define MWIFIEX_BD_FLAG_TX_START_PTR BIT(16) +#define MWIFIEX_BD_FLAG_TX_ROLLOVER_IND BIT(26) /* Max retry number of command write */ #define MAX_WRITE_IOMEM_RETRY 2 @@ -104,45 +98,223 @@ /* FW awake cookie after FW ready */ #define FW_AWAKE_COOKIE (0xAA55AA55) +struct mwifiex_pcie_card_reg { + u16 cmd_addr_lo; + u16 cmd_addr_hi; + u16 fw_status; + u16 cmd_size; + u16 cmdrsp_addr_lo; + u16 cmdrsp_addr_hi; + u16 tx_rdptr; + u16 tx_wrptr; + u16 rx_rdptr; + u16 rx_wrptr; + u16 evt_rdptr; + u16 evt_wrptr; + u16 drv_rdy; + u16 tx_start_ptr; + u32 tx_mask; + u32 tx_wrap_mask; + u32 rx_mask; + u32 rx_wrap_mask; + u32 tx_rollover_ind; + u32 rx_rollover_ind; + u32 evt_rollover_ind; + u8 ring_flag_sop; + u8 ring_flag_eop; + u8 ring_flag_xs_sop; + u8 ring_flag_xs_eop; + u32 ring_tx_start_ptr; + u8 pfu_enabled; + u8 sleep_cookie; +}; + +static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = { + .cmd_addr_lo = PCIE_SCRATCH_0_REG, + .cmd_addr_hi = PCIE_SCRATCH_1_REG, + .cmd_size = PCIE_SCRATCH_2_REG, + .fw_status = PCIE_SCRATCH_3_REG, + .cmdrsp_addr_lo = PCIE_SCRATCH_4_REG, + .cmdrsp_addr_hi = PCIE_SCRATCH_5_REG, + .tx_rdptr = PCIE_SCRATCH_6_REG, + .tx_wrptr = PCIE_SCRATCH_7_REG, + .rx_rdptr = PCIE_SCRATCH_8_REG, + .rx_wrptr = PCIE_SCRATCH_9_REG, + .evt_rdptr = PCIE_SCRATCH_10_REG, + .evt_wrptr = PCIE_SCRATCH_11_REG, + .drv_rdy = PCIE_SCRATCH_12_REG, + .tx_start_ptr = 0, + .tx_mask = MWIFIEX_TXBD_MASK, + .tx_wrap_mask = 0, + .rx_mask = MWIFIEX_RXBD_MASK, + .rx_wrap_mask = 0, + .tx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND, + .rx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND, + .evt_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND, + .ring_flag_sop = 0, + .ring_flag_eop = 0, + .ring_flag_xs_sop = 0, + .ring_flag_xs_eop = 0, + .ring_tx_start_ptr = 0, + .pfu_enabled = 0, + .sleep_cookie = 1, +}; + +static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = { + .cmd_addr_lo = PCIE_SCRATCH_0_REG, + .cmd_addr_hi = PCIE_SCRATCH_1_REG, + .cmd_size = PCIE_SCRATCH_2_REG, + .fw_status = PCIE_SCRATCH_3_REG, + .cmdrsp_addr_lo = PCIE_SCRATCH_4_REG, + .cmdrsp_addr_hi = PCIE_SCRATCH_5_REG, + .tx_rdptr = PCIE_RD_DATA_PTR_Q0_Q1, + .tx_wrptr = PCIE_WR_DATA_PTR_Q0_Q1, + .rx_rdptr = PCIE_WR_DATA_PTR_Q0_Q1, + .rx_wrptr = PCIE_RD_DATA_PTR_Q0_Q1, + .evt_rdptr = PCIE_SCRATCH_10_REG, + .evt_wrptr = PCIE_SCRATCH_11_REG, + .drv_rdy = PCIE_SCRATCH_12_REG, + .tx_start_ptr = 16, + .tx_mask = 0x03FF0000, + .tx_wrap_mask = 0x07FF0000, + .rx_mask = 0x000003FF, + .rx_wrap_mask = 0x000007FF, + .tx_rollover_ind = MWIFIEX_BD_FLAG_TX_ROLLOVER_IND, + .rx_rollover_ind = MWIFIEX_BD_FLAG_RX_ROLLOVER_IND, + .evt_rollover_ind = MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND, + .ring_flag_sop = MWIFIEX_BD_FLAG_SOP, + .ring_flag_eop = MWIFIEX_BD_FLAG_EOP, + .ring_flag_xs_sop = MWIFIEX_BD_FLAG_XS_SOP, + .ring_flag_xs_eop = MWIFIEX_BD_FLAG_XS_EOP, + .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR, + .pfu_enabled = 1, + .sleep_cookie = 0, +}; + +struct mwifiex_pcie_device { + const char *firmware; + const struct mwifiex_pcie_card_reg *reg; + u16 blksz_fw_dl; +}; + +static const struct mwifiex_pcie_device mwifiex_pcie8766 = { + .firmware = PCIE8766_DEFAULT_FW_NAME, + .reg = &mwifiex_reg_8766, + .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, +}; + +static const struct mwifiex_pcie_device mwifiex_pcie8897 = { + .firmware = PCIE8897_DEFAULT_FW_NAME, + .reg = &mwifiex_reg_8897, + .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, +}; + +struct mwifiex_evt_buf_desc { + u64 paddr; + u16 len; + u16 flags; +} __packed; + struct mwifiex_pcie_buf_desc { u64 paddr; u16 len; u16 flags; } __packed; +struct mwifiex_pfu_buf_desc { + u16 flags; + u16 offset; + u16 frag_len; + u16 len; + u64 paddr; + u32 reserved; +} __packed; + struct pcie_service_card { struct pci_dev *dev; struct mwifiex_adapter *adapter; + struct mwifiex_pcie_device pcie; + u8 txbd_flush; u32 txbd_wrptr; u32 txbd_rdptr; u32 txbd_ring_size; u8 *txbd_ring_vbase; - phys_addr_t txbd_ring_pbase; - struct mwifiex_pcie_buf_desc *txbd_ring[MWIFIEX_MAX_TXRX_BD]; + dma_addr_t txbd_ring_pbase; + void *txbd_ring[MWIFIEX_MAX_TXRX_BD]; struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD]; u32 rxbd_wrptr; u32 rxbd_rdptr; u32 rxbd_ring_size; u8 *rxbd_ring_vbase; - phys_addr_t rxbd_ring_pbase; - struct mwifiex_pcie_buf_desc *rxbd_ring[MWIFIEX_MAX_TXRX_BD]; + dma_addr_t rxbd_ring_pbase; + void *rxbd_ring[MWIFIEX_MAX_TXRX_BD]; struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD]; u32 evtbd_wrptr; u32 evtbd_rdptr; u32 evtbd_ring_size; u8 *evtbd_ring_vbase; - phys_addr_t evtbd_ring_pbase; - struct mwifiex_pcie_buf_desc *evtbd_ring[MWIFIEX_MAX_EVT_BD]; + dma_addr_t evtbd_ring_pbase; + void *evtbd_ring[MWIFIEX_MAX_EVT_BD]; struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD]; struct sk_buff *cmd_buf; struct sk_buff *cmdrsp_buf; - struct sk_buff *sleep_cookie; + u8 *sleep_cookie_vbase; + dma_addr_t sleep_cookie_pbase; void __iomem *pci_mmap; void __iomem *pci_mmap1; }; +static inline int +mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr) +{ + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + + switch (card->dev->device) { + case PCIE_DEVICE_ID_MARVELL_88W8766P: + if (((card->txbd_wrptr & reg->tx_mask) == + (rdptr & reg->tx_mask)) && + ((card->txbd_wrptr & reg->tx_rollover_ind) != + (rdptr & reg->tx_rollover_ind))) + return 1; + break; + case PCIE_DEVICE_ID_MARVELL_88W8897: + if (((card->txbd_wrptr & reg->tx_mask) == + (rdptr & reg->tx_mask)) && + ((card->txbd_wrptr & reg->tx_rollover_ind) == + (rdptr & reg->tx_rollover_ind))) + return 1; + break; + } + + return 0; +} + +static inline int +mwifiex_pcie_txbd_not_full(struct pcie_service_card *card) +{ + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + + switch (card->dev->device) { + case PCIE_DEVICE_ID_MARVELL_88W8766P: + if (((card->txbd_wrptr & reg->tx_mask) != + (card->txbd_rdptr & reg->tx_mask)) || + ((card->txbd_wrptr & reg->tx_rollover_ind) != + (card->txbd_rdptr & reg->tx_rollover_ind))) + return 1; + break; + case PCIE_DEVICE_ID_MARVELL_88W8897: + if (((card->txbd_wrptr & reg->tx_mask) != + (card->txbd_rdptr & reg->tx_mask)) || + ((card->txbd_wrptr & reg->tx_rollover_ind) == + (card->txbd_rdptr & reg->tx_rollover_ind))) + return 1; + break; + } + + return 0; +} #endif /* _MWIFIEX_PCIE_H */ diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 9171aaedbccd..bb60c2754a97 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -153,7 +153,7 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) if (((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id == - WLAN_EID_WPA))) { + WLAN_EID_VENDOR_SPECIFIC))) { iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data; oui = &mwifiex_wpa_oui[cipher][0]; ret = mwifiex_search_oui_in_ie(iebody, oui); @@ -202,7 +202,7 @@ mwifiex_is_bss_no_sec(struct mwifiex_private *priv, if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != - WLAN_EID_WPA)) && + WLAN_EID_VENDOR_SPECIFIC)) && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) && @@ -237,7 +237,8 @@ mwifiex_is_bss_wpa(struct mwifiex_private *priv, { if (!priv->sec_info.wep_enabled && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled && ((bss_desc->bcn_wpa_ie) && - ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id == WLAN_EID_WPA)) + ((*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC)) /* * Privacy bit may NOT be set in some APs like * LinkSys WRT54G && bss_desc->privacy @@ -309,7 +310,8 @@ mwifiex_is_bss_adhoc_aes(struct mwifiex_private *priv, if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) || - ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != WLAN_EID_WPA)) && + ((*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id != WLAN_EID_VENDOR_SPECIFIC)) && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) && !priv->sec_info.encryption_mode && bss_desc->privacy) { @@ -329,7 +331,8 @@ mwifiex_is_bss_dynamic_wep(struct mwifiex_private *priv, if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) || - ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != WLAN_EID_WPA)) && + ((*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id != WLAN_EID_VENDOR_SPECIFIC)) && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) && priv->sec_info.encryption_mode && bss_desc->privacy) { @@ -938,6 +941,11 @@ mwifiex_config_scan(struct mwifiex_private *priv, chan_idx)->chan_scan_mode_bitmap &= ~MWIFIEX_PASSIVE_SCAN; + if (*filtered_scan) + (scan_chan_list + + chan_idx)->chan_scan_mode_bitmap + |= MWIFIEX_DISABLE_CHAN_FILT; + if (user_scan_in->chan_list[chan_idx].scan_time) { scan_dur = (u16) user_scan_in-> chan_list[chan_idx].scan_time; @@ -1242,6 +1250,23 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, sizeof(struct ieee_types_header) - bss_entry->beacon_buf); break; + case WLAN_EID_VHT_CAPABILITY: + bss_entry->disable_11ac = false; + bss_entry->bcn_vht_cap = + (void *)(current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->vht_cap_offset = + (u16)((u8 *)bss_entry->bcn_vht_cap - + bss_entry->beacon_buf); + break; + case WLAN_EID_VHT_OPERATION: + bss_entry->bcn_vht_oper = + (void *)(current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->vht_info_offset = + (u16)((u8 *)bss_entry->bcn_vht_oper - + bss_entry->beacon_buf); + break; case WLAN_EID_BSS_COEX_2040: bss_entry->bcn_bss_co_2040 = current_ptr + sizeof(struct ieee_types_header); @@ -1256,6 +1281,14 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, sizeof(struct ieee_types_header) - bss_entry->beacon_buf); break; + case WLAN_EID_OPMODE_NOTIF: + bss_entry->oper_mode = + (void *)(current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->oper_mode_offset = + (u16)((u8 *)bss_entry->oper_mode - + bss_entry->beacon_buf); + break; default: break; } @@ -1301,7 +1334,6 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, struct cmd_ctrl_node *cmd_node; union mwifiex_scan_cmd_config_tlv *scan_cfg_out; struct mwifiex_ie_types_chan_list_param_set *chan_list_out; - u32 buf_size; struct mwifiex_chan_scan_param_set *scan_chan_list; u8 filtered_scan; u8 scan_current_chan_only; @@ -1324,18 +1356,16 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv), - GFP_KERNEL); + GFP_KERNEL); if (!scan_cfg_out) { - dev_err(adapter->dev, "failed to alloc scan_cfg_out\n"); ret = -ENOMEM; goto done; } - buf_size = sizeof(struct mwifiex_chan_scan_param_set) * - MWIFIEX_USER_SCAN_CHAN_MAX; - scan_chan_list = kzalloc(buf_size, GFP_KERNEL); + scan_chan_list = kcalloc(MWIFIEX_USER_SCAN_CHAN_MAX, + sizeof(struct mwifiex_chan_scan_param_set), + GFP_KERNEL); if (!scan_chan_list) { - dev_err(adapter->dev, "failed to alloc scan_chan_list\n"); kfree(scan_cfg_out); ret = -ENOMEM; goto done; @@ -1453,12 +1483,9 @@ static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv, unsigned long flags; /* Allocate and fill new bss descriptor */ - bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), - GFP_KERNEL); - if (!bss_desc) { - dev_err(priv->adapter->dev, " failed to alloc bss_desc\n"); + bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), GFP_KERNEL); + if (!bss_desc) return -ENOMEM; - } ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc); if (ret) @@ -1477,20 +1504,26 @@ static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv, priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL; priv->curr_bss_params.bss_descriptor.wapi_offset = 0; priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL; - priv->curr_bss_params.bss_descriptor.ht_cap_offset = - 0; + priv->curr_bss_params.bss_descriptor.ht_cap_offset = 0; priv->curr_bss_params.bss_descriptor.bcn_ht_oper = NULL; - priv->curr_bss_params.bss_descriptor.ht_info_offset = - 0; - priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = - NULL; - priv->curr_bss_params.bss_descriptor. - bss_co_2040_offset = 0; + priv->curr_bss_params.bss_descriptor.ht_info_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = NULL; + priv->curr_bss_params.bss_descriptor.bss_co_2040_offset = 0; priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL; priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0; priv->curr_bss_params.bss_descriptor.beacon_buf = NULL; - priv->curr_bss_params.bss_descriptor.beacon_buf_size = - 0; + priv->curr_bss_params.bss_descriptor.beacon_buf_size = 0; + priv->curr_bss_params.bss_descriptor.bcn_vht_cap = NULL; + priv->curr_bss_params.bss_descriptor.vht_cap_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_vht_oper = NULL; + priv->curr_bss_params.bss_descriptor.vht_info_offset = 0; + priv->curr_bss_params.bss_descriptor.oper_mode = NULL; + priv->curr_bss_params.bss_descriptor.oper_mode_offset = 0; + + /* Disable 11ac by default. Enable it only where there + * exist VHT_CAP IE in AP beacon + */ + priv->curr_bss_params.bss_descriptor.disable_11ac = true; /* Make a copy of current BSSID descriptor */ memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc, @@ -1555,7 +1588,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n", scan_rsp->number_of_sets); ret = -1; - goto done; + goto check_next_scan; } bytes_left = le16_to_cpu(scan_rsp->bss_descript_size); @@ -1626,7 +1659,8 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, if (!beacon_size || beacon_size > bytes_left) { bss_info += bytes_left; bytes_left = 0; - return -1; + ret = -1; + goto check_next_scan; } /* Initialize the current working beacon pointer for this BSS @@ -1682,7 +1716,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, dev_err(priv->adapter->dev, "%s: bytes left < IE length\n", __func__); - goto done; + goto check_next_scan; } if (element_id == WLAN_EID_DS_PARAMS) { channel = *(current_ptr + sizeof(struct ieee_types_header)); @@ -1738,13 +1772,14 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, .mac_address, ETH_ALEN)) mwifiex_update_curr_bss_params(priv, bss); - cfg80211_put_bss(bss); + cfg80211_put_bss(priv->wdev->wiphy, bss); } } else { dev_dbg(adapter->dev, "missing BSS channel IE\n"); } } +check_next_scan: spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); if (list_empty(&adapter->scan_pending_q)) { spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); @@ -1759,26 +1794,39 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, } if (priv->report_scan_result) priv->report_scan_result = false; - if (priv->scan_pending_on_block) { - priv->scan_pending_on_block = false; - up(&priv->async_sem); - } if (priv->user_scan_cfg) { - dev_dbg(priv->adapter->dev, - "info: %s: sending scan results\n", __func__); - cfg80211_scan_done(priv->scan_request, 0); - priv->scan_request = NULL; + 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; } } else { - if (!mwifiex_wmm_lists_empty(adapter)) { + if (priv->user_scan_cfg && !priv->scan_request) { + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + flags); + adapter->scan_delay_cnt = MWIFIEX_MAX_SCAN_DELAY_CNT; + mod_timer(&priv->scan_delay_timer, jiffies); + dev_dbg(priv->adapter->dev, + "info: %s: triggerring scan abort\n", __func__); + } else if (!mwifiex_wmm_lists_empty(adapter) && + (priv->scan_request && (priv->scan_request->flags & + NL80211_SCAN_FLAG_LOW_PRIORITY))) { spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); adapter->scan_delay_cnt = 1; mod_timer(&priv->scan_delay_timer, jiffies + msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC)); + dev_dbg(priv->adapter->dev, + "info: %s: deferring scan\n", __func__); } else { /* Get scan command from scan_pending_q and put to cmd_pending_q */ @@ -1792,7 +1840,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, } } -done: return ret; } @@ -1858,10 +1905,8 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, } scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); - if (!scan_cfg) { - dev_err(adapter->dev, "failed to alloc scan_cfg\n"); + if (!scan_cfg) return -ENOMEM; - } scan_cfg->ssid_list = req_ssid; scan_cfg->num_ssids = 1; @@ -1891,7 +1936,6 @@ int mwifiex_request_scan(struct mwifiex_private *priv, __func__); return -1; } - priv->scan_pending_on_block = true; priv->adapter->scan_wait_q_woken = false; @@ -1905,10 +1949,7 @@ int mwifiex_request_scan(struct mwifiex_private *priv, if (!ret) ret = mwifiex_wait_queue_complete(priv->adapter); - if (ret == -1) { - priv->scan_pending_on_block = false; - up(&priv->async_sem); - } + up(&priv->async_sem); return ret; } @@ -1979,11 +2020,8 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv) kfree(priv->curr_bcn_buf); priv->curr_bcn_buf = kmalloc(curr_bss->beacon_buf_size, GFP_ATOMIC); - if (!priv->curr_bcn_buf) { - dev_err(priv->adapter->dev, - "failed to alloc curr_bcn_buf\n"); + if (!priv->curr_bcn_buf) return; - } } memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf, @@ -2015,6 +2053,14 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv) (curr_bss->beacon_buf + curr_bss->ht_info_offset); + if (curr_bss->bcn_vht_cap) + curr_bss->bcn_ht_cap = (void *)(curr_bss->beacon_buf + + curr_bss->vht_cap_offset); + + if (curr_bss->bcn_vht_oper) + curr_bss->bcn_ht_oper = (void *)(curr_bss->beacon_buf + + curr_bss->vht_info_offset); + if (curr_bss->bcn_bss_co_2040) curr_bss->bcn_bss_co_2040 = (curr_bss->beacon_buf + curr_bss->bss_co_2040_offset); @@ -2022,6 +2068,10 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv) if (curr_bss->bcn_ext_cap) curr_bss->bcn_ext_cap = curr_bss->beacon_buf + curr_bss->ext_cap_offset; + + if (curr_bss->oper_mode) + curr_bss->oper_mode = (void *)(curr_bss->beacon_buf + + curr_bss->oper_mode_offset); } /* diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index fc8a9bfa1248..363ba31b58bf 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -161,8 +161,6 @@ static int mwifiex_sdio_suspend(struct device *dev) struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; mmc_pm_flag_t pm_flag = 0; - int hs_actived = 0; - int i; int ret = 0; if (func) { @@ -188,18 +186,17 @@ static int mwifiex_sdio_suspend(struct device *dev) adapter = card->adapter; /* Enable the Host Sleep */ - hs_actived = mwifiex_enable_hs(adapter); - if (hs_actived) { - pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n"); - ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (!mwifiex_enable_hs(adapter)) { + dev_err(adapter->dev, "cmd: failed to suspend\n"); + return -EFAULT; } + dev_dbg(adapter->dev, "cmd: suspend with MMC_PM_KEEP_POWER\n"); + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + /* Indicate device suspended */ adapter->is_suspended = true; - for (i = 0; i < adapter->priv_num; i++) - netif_carrier_off(adapter->priv[i]->netdev); - return ret; } @@ -219,7 +216,6 @@ static int mwifiex_sdio_resume(struct device *dev) struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; mmc_pm_flag_t pm_flag = 0; - int i; if (func) { pm_flag = sdio_get_host_pm_caps(func); @@ -242,10 +238,6 @@ static int mwifiex_sdio_resume(struct device *dev) adapter->is_suspended = false; - for (i = 0; i < adapter->priv_num; i++) - if (adapter->priv[i]->media_connected) - netif_carrier_on(adapter->priv[i]->netdev); - /* Disable Host Sleep */ mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), MWIFIEX_ASYNC_CMD); @@ -331,7 +323,7 @@ mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, u32 pkt_len, u32 port) { struct sdio_mmc_card *card = adapter->card; - int ret = -1; + int ret; u8 blk_mode = (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; @@ -349,8 +341,7 @@ mwifiex_write_data_sync(struct mwifiex_adapter *adapter, sdio_claim_host(card->func); - if (!sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size)) - ret = 0; + ret = sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size); sdio_release_host(card->func); @@ -364,7 +355,7 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, u32 len, u32 port, u8 claim) { struct sdio_mmc_card *card = adapter->card; - int ret = -1; + int ret; u8 blk_mode = (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; @@ -375,8 +366,7 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, if (claim) sdio_claim_host(card->func); - if (!sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size)) - ret = 0; + ret = sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size); if (claim) sdio_release_host(card->func); @@ -717,11 +707,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, /* Assume that the allocated buffer is 8-byte aligned */ fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL); - if (!fwbuf) { - dev_err(adapter->dev, - "unable to alloc buffer for FW. Terminating dnld\n"); + if (!fwbuf) return -ENOMEM; - } /* Perform firmware data transfer */ do { @@ -905,8 +892,8 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) /* * SDIO interrupt handler. * - * This function reads the interrupt status from firmware and assigns - * the main process in workqueue which will handle the interrupt. + * This function reads the interrupt status from firmware and handles + * the interrupt in current thread (ksdioirqd) right away. */ static void mwifiex_sdio_interrupt(struct sdio_func *func) @@ -929,7 +916,7 @@ mwifiex_sdio_interrupt(struct sdio_func *func) adapter->ps_state = PS_STATE_AWAKE; mwifiex_interrupt_status(adapter); - queue_work(adapter->workqueue, &adapter->main_work); + mwifiex_main_process(adapter); } /* @@ -1519,7 +1506,6 @@ static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter, card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL); if (!card->mpa_tx.buf) { - dev_err(adapter->dev, "could not alloc buffer for MP-A TX\n"); ret = -1; goto error; } @@ -1528,7 +1514,6 @@ static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter, card->mpa_rx.buf = kzalloc(mpa_rx_buf_size, GFP_KERNEL); if (!card->mpa_rx.buf) { - dev_err(adapter->dev, "could not alloc buffer for MP-A RX\n"); ret = -1; goto error; } @@ -1681,10 +1666,8 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) /* Allocate buffers for SDIO MP-A */ card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL); - if (!card->mp_regs) { - dev_err(adapter->dev, "failed to alloc mp_regs\n"); + if (!card->mp_regs) return -ENOMEM; - } ret = mwifiex_alloc_sdio_mpa_buffers(adapter, SDIO_MP_TX_AGGR_DEF_BUF_SIZE, @@ -1748,6 +1731,36 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) port, card->mp_data_port_mask); } +static struct mmc_host *reset_host; +static void sdio_card_reset_worker(struct work_struct *work) +{ + struct mmc_host *target = reset_host; + + /* The actual reset operation must be run outside of driver thread. + * This is because mmc_remove_host() will cause the device to be + * instantly destroyed, and the driver then needs to end its thread, + * leading to a deadlock. + * + * We run it in a totally independent workqueue. + */ + + pr_err("Resetting card...\n"); + mmc_remove_host(target); + /* 20ms delay is based on experiment with sdhci controller */ + mdelay(20); + mmc_add_host(target); +} +static DECLARE_WORK(card_reset_work, sdio_card_reset_worker); + +/* This function resets the card */ +static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + reset_host = card->func->card->host; + schedule_work(&card_reset_work); +} + static struct mwifiex_if_ops sdio_ops = { .init_if = mwifiex_init_sdio, .cleanup_if = mwifiex_cleanup_sdio, @@ -1766,6 +1779,7 @@ static struct mwifiex_if_ops sdio_ops = { .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf, .cmdrsp_complete = mwifiex_sdio_cmdrsp_complete, .event_complete = mwifiex_sdio_event_complete, + .card_reset = mwifiex_sdio_card_reset, }; /* @@ -1803,6 +1817,7 @@ mwifiex_sdio_cleanup_module(void) /* Set the flag as user is removing this module. */ user_rmmod = 1; + cancel_work_sync(&card_reset_work); sdio_unregister_driver(&mwifiex_sdio); } diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 21033738ef0c..8cc5468654b4 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -25,6 +25,7 @@ #include <linux/mmc/sdio_ids.h> #include <linux/mmc/sdio_func.h> #include <linux/mmc/card.h> +#include <linux/mmc/host.h> #include "main.h" diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 5d87195390f8..c55c5bb93134 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -931,7 +931,6 @@ mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv, struct host_cmd_ds_pcie_details *host_spec = &cmd->params.pcie_host_spec; struct pcie_service_card *card = priv->adapter->card; - phys_addr_t *buf_pa; cmd->command = cpu_to_le16(HostCmd_CMD_PCIE_DESC_DETAILS); cmd->size = cpu_to_le16(sizeof(struct @@ -953,10 +952,11 @@ mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv, host_spec->evtbd_addr_lo = (u32)(card->evtbd_ring_pbase); host_spec->evtbd_addr_hi = (u32)(((u64)card->evtbd_ring_pbase)>>32); host_spec->evtbd_count = MWIFIEX_MAX_EVT_BD; - if (card->sleep_cookie) { - buf_pa = MWIFIEX_SKB_PACB(card->sleep_cookie); - host_spec->sleep_cookie_addr_lo = (u32) *buf_pa; - host_spec->sleep_cookie_addr_hi = (u32) (((u64)*buf_pa) >> 32); + if (card->sleep_cookie_vbase) { + host_spec->sleep_cookie_addr_lo = + (u32)(card->sleep_cookie_pbase); + host_spec->sleep_cookie_addr_hi = + (u32)(((u64)(card->sleep_cookie_pbase)) >> 32); dev_dbg(priv->adapter->dev, "sleep_cook_lo phy addr: 0x%x\n", host_spec->sleep_cookie_addr_lo); } @@ -1230,7 +1230,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, data_buf); break; case HostCmd_CMD_11N_CFG: - ret = mwifiex_cmd_11n_cfg(cmd_ptr, cmd_action, data_buf); + ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action, data_buf); break; case HostCmd_CMD_WMM_GET_STATUS: dev_dbg(priv->adapter->dev, diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 09e6a267f566..4669f8d9389f 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -24,6 +24,7 @@ #include "main.h" #include "wmm.h" #include "11n.h" +#include "11ac.h" /* @@ -85,10 +86,6 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv, spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); if (priv->report_scan_result) priv->report_scan_result = false; - if (priv->scan_pending_on_block) { - priv->scan_pending_on_block = false; - up(&priv->async_sem); - } break; case HostCmd_CMD_MAC_CONTROL: @@ -939,9 +936,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, / MWIFIEX_SDIO_BLOCK_SIZE) * MWIFIEX_SDIO_BLOCK_SIZE; adapter->curr_tx_buf_size = adapter->tx_buf_size; - dev_dbg(adapter->dev, - "cmd: max_tx_buf_size=%d, tx_buf_size=%d\n", - adapter->max_tx_buf_size, adapter->tx_buf_size); + dev_dbg(adapter->dev, "cmd: curr_tx_buf_size=%d\n", + adapter->curr_tx_buf_size); if (adapter->if_ops.update_mp_end_port) adapter->if_ops.update_mp_end_port(adapter, diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 8132119e1a21..41aafc7454ed 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -124,8 +124,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) } memset(priv->cfg_bssid, 0, ETH_ALEN); - if (!netif_queue_stopped(priv->netdev)) - mwifiex_stop_net_dev_queue(priv->netdev, adapter); + mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); } @@ -197,8 +196,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) dev_dbg(adapter->dev, "event: LINK_SENSED\n"); if (!netif_carrier_ok(priv->netdev)) netif_carrier_on(priv->netdev); - if (netif_queue_stopped(priv->netdev)) - mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); + mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); break; case EVENT_DEAUTHENTICATED: @@ -306,8 +304,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n"); priv->adhoc_is_link_sensed = false; mwifiex_clean_txrx(priv); - if (!netif_queue_stopped(priv->netdev)) - mwifiex_stop_net_dev_queue(priv->netdev, adapter); + mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); break; @@ -424,7 +421,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) cfg80211_remain_on_channel_expired(priv->wdev, priv->roc_cfg.cookie, &priv->roc_cfg.chan, - priv->roc_cfg.chan_type, GFP_ATOMIC); memset(&priv->roc_cfg, 0x00, sizeof(struct mwifiex_roc_cfg)); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 0c9f70b2cbe6..9f33c92c90f5 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -56,7 +56,6 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, */ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) { - bool cancel_flag = false; int status; struct cmd_ctrl_node *cmd_queued; @@ -70,14 +69,11 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) atomic_inc(&adapter->cmd_pending); /* Wait for completion */ - wait_event_interruptible(adapter->cmd_wait_q.wait, - *(cmd_queued->condition)); - if (!*(cmd_queued->condition)) - cancel_flag = true; - - if (cancel_flag) { - mwifiex_cancel_pending_ioctl(adapter); - dev_dbg(adapter->dev, "cmd cancel\n"); + status = wait_event_interruptible(adapter->cmd_wait_q.wait, + *(cmd_queued->condition)); + if (status) { + dev_err(adapter->dev, "cmd_wait_q terminated: %d\n", status); + return status; } status = adapter->cmd_wait_q.status; @@ -160,10 +156,17 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, { int ret; u8 *beacon_ie; + size_t beacon_ie_len; struct mwifiex_bss_priv *bss_priv = (void *)bss->priv; + const struct cfg80211_bss_ies *ies; + + rcu_read_lock(); + ies = rcu_dereference(bss->ies); + beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC); + beacon_ie_len = ies->len; + bss_desc->timestamp = ies->tsf; + rcu_read_unlock(); - beacon_ie = kmemdup(bss->information_elements, bss->len_beacon_ies, - GFP_KERNEL); if (!beacon_ie) { dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); return -ENOMEM; @@ -172,12 +175,11 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN); bss_desc->rssi = bss->signal; bss_desc->beacon_buf = beacon_ie; - bss_desc->beacon_buf_size = bss->len_beacon_ies; + bss_desc->beacon_buf_size = beacon_ie_len; bss_desc->beacon_period = bss->beacon_interval; bss_desc->cap_info_bitmap = bss->capability; bss_desc->bss_band = bss_priv->band; bss_desc->fw_tsf = bss_priv->fw_tsf; - bss_desc->timestamp = bss->tsf; if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n"); bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; @@ -198,18 +200,23 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, static int mwifiex_process_country_ie(struct mwifiex_private *priv, struct cfg80211_bss *bss) { - u8 *country_ie, country_ie_len; + const u8 *country_ie; + u8 country_ie_len; struct mwifiex_802_11d_domain_reg *domain_info = &priv->adapter->domain_reg; - country_ie = (u8 *)ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); - - if (!country_ie) + rcu_read_lock(); + country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); + if (!country_ie) { + rcu_read_unlock(); return 0; + } country_ie_len = country_ie[1]; - if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) + if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) { + rcu_read_unlock(); return 0; + } domain_info->country_code[0] = country_ie[2]; domain_info->country_code[1] = country_ie[3]; @@ -223,6 +230,8 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv, memcpy((u8 *)domain_info->triplet, &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len); + rcu_read_unlock(); + if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, HostCmd_ACT_GEN_SET, 0, NULL)) { wiphy_err(priv->adapter->wiphy, @@ -252,11 +261,9 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, /* Allocate and fill new bss descriptor */ bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), - GFP_KERNEL); - if (!bss_desc) { - dev_err(priv->adapter->dev, " failed to alloc bss_desc\n"); + GFP_KERNEL); + if (!bss_desc) return -ENOMEM; - } ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc); if (ret) @@ -269,6 +276,21 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, if (ret) goto done; + if (bss_desc) { + u8 config_bands = 0; + + 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 (!((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; @@ -276,8 +298,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, dev_dbg(adapter->dev, "info: SSID found in scan list ... " "associating...\n"); - if (!netif_queue_stopped(priv->netdev)) - mwifiex_stop_net_dev_queue(priv->netdev, adapter); + mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); @@ -297,7 +318,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, } if (bss) - cfg80211_put_bss(bss); + cfg80211_put_bss(priv->adapter->wiphy, bss); } else { /* Adhoc mode */ /* If the requested SSID matches current SSID, return */ @@ -318,8 +339,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, ret = mwifiex_check_network_compatibility(priv, bss_desc); - if (!netif_queue_stopped(priv->netdev)) - mwifiex_stop_net_dev_queue(priv->netdev, adapter); + mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); @@ -328,7 +348,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, " list. Joining...\n"); ret = mwifiex_adhoc_join(priv, bss_desc); if (bss) - cfg80211_put_bss(bss); + cfg80211_put_bss(priv->adapter->wiphy, bss); } else { dev_dbg(adapter->dev, "info: Network not found in " "the list, creating adhoc with ssid = %s\n", @@ -463,7 +483,7 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) } if (adapter->hs_activated) { - dev_dbg(adapter->dev, "cmd: HS Already actived\n"); + dev_dbg(adapter->dev, "cmd: HS Already activated\n"); return true; } @@ -480,8 +500,11 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) return false; } - wait_event_interruptible(adapter->hs_activate_wait_q, - adapter->hs_activate_wait_q_woken); + if (wait_event_interruptible(adapter->hs_activate_wait_q, + adapter->hs_activate_wait_q_woken)) { + dev_err(adapter->dev, "hs_activate_wait_q terminated\n"); + return false; + } return true; } @@ -607,11 +630,8 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv, } } buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL); - if (!buf) { - dev_err(priv->adapter->dev, "%s: failed to alloc cmd buffer\n", - __func__); + if (!buf) return -ENOMEM; - } txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf; txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET); @@ -713,7 +733,7 @@ static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv, dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n", priv->wpa_ie_len, priv->wpa_ie[0]); - if (priv->wpa_ie[0] == WLAN_EID_WPA) { + if (priv->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) { priv->sec_info.wpa_enabled = true; } else if (priv->wpa_ie[0] == WLAN_EID_RSN) { priv->sec_info.wpa2_enabled = true; @@ -1046,7 +1066,6 @@ mwifiex_get_ver_ext(struct mwifiex_private *priv) int mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action, struct ieee80211_channel *chan, - enum nl80211_channel_type *ct, unsigned int duration) { struct host_cmd_ds_remain_on_chan roc_cfg; @@ -1056,7 +1075,7 @@ mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action, roc_cfg.action = cpu_to_le16(action); if (action == HostCmd_ACT_GEN_SET) { roc_cfg.band_cfg = chan->band; - sc = mwifiex_chan_type_to_sec_chan_offset(*ct); + sc = mwifiex_chan_type_to_sec_chan_offset(NL80211_CHAN_NO_HT); roc_cfg.band_cfg |= (sc << 2); roc_cfg.channel = @@ -1253,7 +1272,7 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr, } pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; /* Test to see if it is a WPA IE, if not, then it is a gen IE */ - if (((pvendor_ie->element_id == WLAN_EID_WPA) && + if (((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui)))) || (pvendor_ie->element_id == WLAN_EID_RSN)) { diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index 07d32b73783e..b5c109504393 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -38,14 +38,10 @@ * * The completion callback is called after processing in complete. */ -int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, +int mwifiex_process_rx_packet(struct mwifiex_private *priv, struct sk_buff *skb) { int ret; - struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); - struct mwifiex_private *priv = - mwifiex_get_priv_by_id(adapter, rx_info->bss_num, - rx_info->bss_type); struct rx_packet_hdr *rx_pkt_hdr; struct rxpd *local_rx_pd; int hdr_chop; @@ -98,9 +94,9 @@ int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, priv->rxpd_htinfo = local_rx_pd->ht_info; - ret = mwifiex_recv_packet(adapter, skb); + ret = mwifiex_recv_packet(priv, skb); if (ret == -1) - dev_err(adapter->dev, "recv packet failed\n"); + dev_err(priv->adapter->dev, "recv packet failed\n"); return ret; } @@ -117,21 +113,15 @@ int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, * * The completion callback is called after processing in complete. */ -int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, +int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv, struct sk_buff *skb) { + struct mwifiex_adapter *adapter = priv->adapter; int ret = 0; struct rxpd *local_rx_pd; - struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); struct rx_packet_hdr *rx_pkt_hdr; u8 ta[ETH_ALEN]; u16 rx_pkt_type, rx_pkt_offset, rx_pkt_length, seq_num; - struct mwifiex_private *priv = - mwifiex_get_priv_by_id(adapter, rx_info->bss_num, - rx_info->bss_type); - - if (!priv) - return -1; local_rx_pd = (struct rxpd *) (skb->data); rx_pkt_type = le16_to_cpu(local_rx_pd->rx_pkt_type); @@ -169,13 +159,13 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, while (!skb_queue_empty(&list)) { rx_skb = __skb_dequeue(&list); - ret = mwifiex_recv_packet(adapter, rx_skb); + ret = mwifiex_recv_packet(priv, rx_skb); if (ret == -1) dev_err(adapter->dev, "Rx of A-MSDU failed"); } return 0; } else if (rx_pkt_type == PKT_TYPE_MGMT) { - ret = mwifiex_process_mgmt_packet(adapter, skb); + ret = mwifiex_process_mgmt_packet(priv, skb); if (ret) dev_err(adapter->dev, "Rx of mgmt packet failed"); dev_kfree_skb_any(skb); @@ -188,7 +178,7 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, */ if (!IS_11N_ENABLED(priv) || memcmp(priv->curr_addr, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN)) { - mwifiex_process_rx_packet(adapter, skb); + mwifiex_process_rx_packet(priv, skb); return ret; } diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 2af263992e83..296faec14365 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -48,13 +48,19 @@ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, if (!priv) priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + if (!priv) { + dev_err(adapter->dev, "data: priv not found. Drop RX packet\n"); + dev_kfree_skb_any(skb); + return -1; + } + rx_info->bss_num = priv->bss_num; rx_info->bss_type = priv->bss_type; if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) - return mwifiex_process_uap_rx_packet(adapter, skb); + return mwifiex_process_uap_rx_packet(priv, skb); - return mwifiex_process_sta_rx_packet(adapter, skb); + return mwifiex_process_sta_rx_packet(priv, skb); } EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); @@ -111,17 +117,19 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); break; case -1: - adapter->data_sent = false; + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n", ret); adapter->dbg.num_tx_host_to_card_failure++; - mwifiex_write_data_complete(adapter, skb, ret); + mwifiex_write_data_complete(adapter, skb, 0, ret); break; case -EINPROGRESS: - adapter->data_sent = false; + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; break; case 0: - mwifiex_write_data_complete(adapter, skb, ret); + mwifiex_write_data_complete(adapter, skb, 0, ret); break; default: break; @@ -138,11 +146,12 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, * wakes up stalled traffic queue if required, and then frees the buffer. */ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, - struct sk_buff *skb, int status) + struct sk_buff *skb, int aggr, int status) { - struct mwifiex_private *priv, *tpriv; + struct mwifiex_private *priv; struct mwifiex_txinfo *tx_info; - int i; + struct netdev_queue *txq; + int index; if (!skb) return 0; @@ -166,15 +175,20 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) atomic_dec_return(&adapter->pending_bridged_pkts); - if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING) + + if (aggr) + /* For skb_aggr, do not wake up tx queue */ goto done; - for (i = 0; i < adapter->priv_num; i++) { - tpriv = adapter->priv[i]; + atomic_dec(&adapter->tx_pending); - if (tpriv->media_connected && - netif_queue_stopped(tpriv->netdev)) - mwifiex_wake_up_net_dev_queue(tpriv->netdev, adapter); + index = mwifiex_1d_to_wmm_queue[skb->priority]; + if (atomic_dec_return(&priv->wmm_tx_pending[index]) < LOW_TX_PENDING) { + txq = netdev_get_tx_queue(priv->netdev, index); + if (netif_tx_queue_stopped(txq)) { + netif_tx_wake_queue(txq); + dev_dbg(adapter->dev, "wake queue: %d\n", index); + } } done: dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index d95a2d558fcf..6e76a15a8950 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -188,10 +188,19 @@ mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg, int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable); const u8 *var_pos = params->beacon.head + var_offset; int len = params->beacon.head_len - var_offset; + u8 rate_len = 0; rate_ie = (void *)cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len); - if (rate_ie) + if (rate_ie) { memcpy(bss_cfg->rates, rate_ie + 1, rate_ie->len); + rate_len = rate_ie->len; + } + + rate_ie = (void *)cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, + params->beacon.tail, + params->beacon.tail_len); + if (rate_ie) + memcpy(bss_cfg->rates + rate_len, rate_ie + 1, rate_ie->len); return; } @@ -210,6 +219,7 @@ void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config) config->rts_threshold = 0x7FFF; config->frag_threshold = 0x7FFF; config->retry_limit = 0x7F; + config->qos_info = 0xFF; } /* This function parses BSS related parameters from structure @@ -288,6 +298,38 @@ mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size) return; } +/* This function parses WMM related parameters from cfg80211_ap_settings + * structure and updates bss_config structure. + */ +void +mwifiex_set_wmm_params(struct mwifiex_private *priv, + struct mwifiex_uap_bss_param *bss_cfg, + struct cfg80211_ap_settings *params) +{ + const u8 *vendor_ie; + struct ieee_types_header *wmm_ie; + u8 wmm_oui[] = {0x00, 0x50, 0xf2, 0x02}; + + vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WMM, + params->beacon.tail, + params->beacon.tail_len); + if (vendor_ie) { + wmm_ie = (struct ieee_types_header *)vendor_ie; + memcpy(&bss_cfg->wmm_info, wmm_ie + 1, + sizeof(bss_cfg->wmm_info)); + priv->wmm_enabled = 1; + } else { + memset(&bss_cfg->wmm_info, 0, sizeof(bss_cfg->wmm_info)); + memcpy(&bss_cfg->wmm_info.oui, wmm_oui, sizeof(wmm_oui)); + bss_cfg->wmm_info.subtype = MWIFIEX_WMM_SUBTYPE; + bss_cfg->wmm_info.version = MWIFIEX_WMM_VERSION; + priv->wmm_enabled = 0; + } + + bss_cfg->qos_info = 0x00; + return; +} /* This function parses BSS related parameters from structure * and prepares TLVs specific to WEP encryption. * These TLVs are appended to command buffer. @@ -345,6 +387,7 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) struct host_cmd_tlv_rates *tlv_rates; struct host_cmd_tlv_ageout_timer *ao_timer, *ps_ao_timer; struct mwifiex_ie_types_htcap *htcap; + struct mwifiex_ie_types_wmmcap *wmm_cap; struct mwifiex_uap_bss_param *bss_cfg = cmd_buf; int i; u16 cmd_size = *param_size; @@ -498,6 +541,16 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) tlv += sizeof(struct mwifiex_ie_types_htcap); } + if (bss_cfg->wmm_info.qos_info != 0xFF) { + wmm_cap = (struct mwifiex_ie_types_wmmcap *)tlv; + wmm_cap->header.type = cpu_to_le16(WLAN_EID_VENDOR_SPECIFIC); + wmm_cap->header.len = cpu_to_le16(sizeof(wmm_cap->wmm_info)); + memcpy(&wmm_cap->wmm_info, &bss_cfg->wmm_info, + sizeof(wmm_cap->wmm_info)); + cmd_size += sizeof(struct mwifiex_ie_types_wmmcap); + tlv += sizeof(struct mwifiex_ie_types_wmmcap); + } + if (bss_cfg->sta_ao_timer) { ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv; ao_timer->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER); diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index a33fa394e349..21c640d3b579 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -235,11 +235,18 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) break; case EVENT_UAP_BSS_IDLE: priv->media_connected = false; + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + mwifiex_stop_net_dev_queue(priv->netdev, adapter); + mwifiex_clean_txrx(priv); mwifiex_del_all_sta_list(priv); break; case EVENT_UAP_BSS_ACTIVE: priv->media_connected = true; + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); break; case EVENT_UAP_BSS_START: dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause); diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index 0966ac24b3b4..a018e42d117e 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -146,7 +146,7 @@ int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv, } /* Forward unicat/Inter-BSS packets to kernel. */ - return mwifiex_process_rx_packet(adapter, skb); + return mwifiex_process_rx_packet(priv, skb); } /* @@ -159,24 +159,17 @@ int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv, * * The completion callback is called after processing is complete. */ -int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter, +int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv, struct sk_buff *skb) { + struct mwifiex_adapter *adapter = priv->adapter; int ret; struct uap_rxpd *uap_rx_pd; - struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); struct rx_packet_hdr *rx_pkt_hdr; u16 rx_pkt_type; u8 ta[ETH_ALEN], pkt_type; struct mwifiex_sta_node *node; - struct mwifiex_private *priv = - mwifiex_get_priv_by_id(adapter, rx_info->bss_num, - rx_info->bss_type); - - if (!priv) - return -1; - uap_rx_pd = (struct uap_rxpd *)(skb->data); rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type); rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset); @@ -210,7 +203,7 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter, while (!skb_queue_empty(&list)) { rx_skb = __skb_dequeue(&list); - ret = mwifiex_recv_packet(adapter, rx_skb); + ret = mwifiex_recv_packet(priv, rx_skb); if (ret) dev_err(adapter->dev, "AP:Rx A-MSDU failed"); @@ -218,7 +211,7 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter, return 0; } else if (rx_pkt_type == PKT_TYPE_MGMT) { - ret = mwifiex_process_mgmt_packet(adapter, skb); + ret = mwifiex_process_mgmt_packet(priv, skb); if (ret) dev_err(adapter->dev, "Rx of mgmt packet failed"); dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 22a5916564b8..f90fe21e5bfd 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -238,7 +238,7 @@ static void mwifiex_usb_tx_complete(struct urb *urb) } else { dev_dbg(adapter->dev, "%s: DATA\n", __func__); atomic_dec(&card->tx_data_urb_pending); - mwifiex_write_data_complete(adapter, context->skb, + mwifiex_write_data_complete(adapter, context->skb, 0, urb->status ? -1 : 0); } @@ -351,7 +351,7 @@ static int mwifiex_usb_probe(struct usb_interface *intf, card->udev = udev; card->intf = intf; - pr_debug("info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocl=%#x\n", + pr_debug("info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocol=%#x\n", udev->descriptor.bcdUSB, udev->descriptor.bDeviceClass, udev->descriptor.bDeviceSubClass, udev->descriptor.bDeviceProtocol); @@ -672,7 +672,7 @@ static int mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf, *len, &actual_length, timeout); if (ret) { dev_err(adapter->dev, "usb_bulk_msg for tx failed: %d\n", ret); - ret = -1; + return ret; } *len = actual_length; @@ -691,7 +691,7 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf, *len, &actual_length, timeout); if (ret) { dev_err(adapter->dev, "usb_bulk_msg for rx failed: %d\n", ret); - ret = -1; + return ret; } *len = actual_length; @@ -786,21 +786,6 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) return 0; } -/* This function reads one block of firmware data. */ -static int mwifiex_get_fw_data(struct mwifiex_adapter *adapter, - u32 offset, u32 len, u8 *buf) -{ - if (!buf || !len) - return -1; - - if (offset + len > adapter->firmware->size) - return -1; - - memcpy(buf, adapter->firmware->data + offset, len); - - return 0; -} - static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, struct mwifiex_fw_image *fw) { @@ -836,23 +821,14 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, dlen = 0; } else { /* copy the header of the fw_data to get the length */ - if (firmware) - memcpy(&fwdata->fw_hdr, &firmware[tlen], - sizeof(struct fw_header)); - else - mwifiex_get_fw_data(adapter, tlen, - sizeof(struct fw_header), - (u8 *)&fwdata->fw_hdr); + memcpy(&fwdata->fw_hdr, &firmware[tlen], + sizeof(struct fw_header)); dlen = le32_to_cpu(fwdata->fw_hdr.data_len); dnld_cmd = le32_to_cpu(fwdata->fw_hdr.dnld_cmd); tlen += sizeof(struct fw_header); - if (firmware) - memcpy(fwdata->data, &firmware[tlen], dlen); - else - mwifiex_get_fw_data(adapter, tlen, dlen, - (u8 *)fwdata->data); + memcpy(fwdata->data, &firmware[tlen], dlen); fwdata->seq_num = cpu_to_le32(fw_seqnum); tlen += dlen; diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index ae88f80cf86b..21553976b550 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -91,7 +91,7 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv, memcpy(info->packets_out, priv->wmm.packets_out, sizeof(priv->wmm.packets_out)); - info->max_tx_buf_size = (u32) adapter->max_tx_buf_size; + info->curr_tx_buf_size = (u32) adapter->curr_tx_buf_size; info->tx_buf_size = (u32) adapter->tx_buf_size; info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(priv, info->rx_tbl); @@ -146,20 +146,16 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv, * to the kernel. */ int -mwifiex_process_mgmt_packet(struct mwifiex_adapter *adapter, +mwifiex_process_mgmt_packet(struct mwifiex_private *priv, struct sk_buff *skb) { struct rxpd *rx_pd; - struct mwifiex_private *priv; u16 pkt_len; if (!skb) return -1; rx_pd = (struct rxpd *)skb->data; - priv = mwifiex_get_priv_by_id(adapter, rx_pd->bss_num, rx_pd->bss_type); - if (!priv) - return -1; skb_pull(skb, le16_to_cpu(rx_pd->rx_pkt_offset)); skb_pull(skb, sizeof(pkt_len)); @@ -190,20 +186,11 @@ mwifiex_process_mgmt_packet(struct mwifiex_adapter *adapter, * the function creates a blank SKB, fills it with the data from the * received buffer and then sends this new SKB to the kernel. */ -int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) +int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb) { - struct mwifiex_rxinfo *rx_info; - struct mwifiex_private *priv; - if (!skb) return -1; - rx_info = MWIFIEX_SKB_RXCB(skb); - priv = mwifiex_get_priv_by_id(adapter, rx_info->bss_num, - rx_info->bss_type); - if (!priv) - return -1; - skb->dev = priv->netdev; skb->protocol = eth_type_trans(skb, priv->netdev); skb->ip_summed = CHECKSUM_NONE; @@ -225,7 +212,7 @@ int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) * fragments. Currently we fail the Filesndl-ht.scr script * for UDP, hence this fix */ - if ((adapter->iface_type == MWIFIEX_USB) && + if ((priv->adapter->iface_type == MWIFIEX_USB) && (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE)) skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE); diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h index f6d36b9654a0..cb2d0582bd36 100644 --- a/drivers/net/wireless/mwifiex/util.h +++ b/drivers/net/wireless/mwifiex/util.h @@ -22,16 +22,16 @@ static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb) { - return (struct mwifiex_rxinfo *)(skb->cb + sizeof(phys_addr_t)); + return (struct mwifiex_rxinfo *)(skb->cb + sizeof(dma_addr_t)); } static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb) { - return (struct mwifiex_txinfo *)(skb->cb + sizeof(phys_addr_t)); + return (struct mwifiex_txinfo *)(skb->cb + sizeof(dma_addr_t)); } -static inline phys_addr_t *MWIFIEX_SKB_PACB(struct sk_buff *skb) +static inline void MWIFIEX_SKB_PACB(struct sk_buff *skb, dma_addr_t *buf_pa) { - return (phys_addr_t *)skb->cb; + memcpy(buf_pa, skb->cb, sizeof(dma_addr_t)); } #endif /* !_MWIFIEX_UTIL_H_ */ diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 600d8194610e..32adc878041d 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -109,12 +109,9 @@ mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra) struct mwifiex_ra_list_tbl *ra_list; ra_list = kzalloc(sizeof(struct mwifiex_ra_list_tbl), GFP_ATOMIC); - - if (!ra_list) { - dev_err(adapter->dev, "%s: failed to alloc ra_list\n", - __func__); + if (!ra_list) return NULL; - } + INIT_LIST_HEAD(&ra_list->list); skb_queue_head_init(&ra_list->skb_head); @@ -483,7 +480,7 @@ mwifiex_wmm_del_pkts_in_ralist_node(struct mwifiex_private *priv, struct sk_buff *skb, *tmp; skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) - mwifiex_write_data_complete(adapter, skb, -1); + mwifiex_write_data_complete(adapter, skb, 0, -1); } /* @@ -568,6 +565,8 @@ mwifiex_clean_txrx(struct mwifiex_private *priv) mwifiex_wmm_delete_all_ralist(priv); memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid)); + if (priv->adapter->if_ops.clean_pcie_ring) + priv->adapter->if_ops.clean_pcie_ring(priv->adapter); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); } @@ -650,7 +649,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, if (!priv->media_connected && !mwifiex_is_skb_mgmt_frame(skb)) { dev_dbg(adapter->dev, "data: drop packet in disconnect\n"); - mwifiex_write_data_complete(adapter, skb, -1); + mwifiex_write_data_complete(adapter, skb, 0, -1); return; } @@ -680,7 +679,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, if (!ra_list) { spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); - mwifiex_write_data_complete(adapter, skb, -1); + mwifiex_write_data_complete(adapter, skb, 0, -1); return; } @@ -1090,7 +1089,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv, if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); - mwifiex_write_data_complete(adapter, skb, -1); + mwifiex_write_data_complete(adapter, skb, 0, -1); return; } @@ -1195,7 +1194,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv, if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); - mwifiex_write_data_complete(adapter, skb, -1); + mwifiex_write_data_complete(adapter, skb, 0, -1); return; } @@ -1206,13 +1205,15 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv, ra_list_flags); break; case -1: - adapter->data_sent = false; + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; dev_err(adapter->dev, "host_to_card failed: %#x\n", ret); adapter->dbg.num_tx_host_to_card_failure++; - mwifiex_write_data_complete(adapter, skb, ret); + mwifiex_write_data_complete(adapter, skb, 0, ret); break; case -EINPROGRESS: - adapter->data_sent = false; + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; default: break; } diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index ec839952d2e7..b92f39d8963b 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -31,6 +31,8 @@ enum ieee_types_wmm_ecw_bitmasks { MWIFIEX_ECW_MAX = (BIT(4) | BIT(5) | BIT(6) | BIT(7)), }; +static const u16 mwifiex_1d_to_wmm_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; + /* * This function retrieves the TID of the given RA list. */ |