diff options
author | David Lin <dlin@marvell.com> | 2015-10-29 13:20:51 +0800 |
---|---|---|
committer | David Lin <dlin@marvell.com> | 2015-10-29 13:20:51 +0800 |
commit | 30e6b06de659f1d5e46d1dd3bf590caf3529bb65 (patch) | |
tree | 8c07d46accca9c8073882b7a31ce4209c3fb8f76 | |
parent | 7a6aff718d2de7dee6f9d82eae8af91667e8ee86 (diff) |
Commit mwlwifi driver 10.3.0.12.
1. Change FW_CHECK_MSECS from 1 to 3.
2. Modify the code to support client without AMSDU support.
Signed-off-by: David Lin <dlin@marvell.com>
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | Makefile.external | 7 | ||||
-rw-r--r-- | debugfs.c | 5 | ||||
-rw-r--r-- | dev.h | 17 | ||||
-rw-r--r-- | fwcmd.c | 111 | ||||
-rw-r--r-- | fwcmd.h | 2 | ||||
-rw-r--r-- | fwdl.c | 27 | ||||
-rw-r--r-- | mac80211.c | 9 | ||||
-rw-r--r-- | main.c | 47 | ||||
-rw-r--r-- | rx.c | 36 | ||||
-rw-r--r-- | tx.c | 2 |
11 files changed, 244 insertions, 26 deletions
@@ -8,6 +8,9 @@ mwlwifi-objs += tx.o mwlwifi-objs += rx.o mwlwifi-objs += isr.o mwlwifi-$(CONFIG_DEBUG_FS) += debugfs.o +ifeq (1, $(BUILD_MFG)) +mwlwifi-objs += mfg.o +endif AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld @@ -16,6 +19,10 @@ CC = $(CROSS_COMPILE)gcc EXTRA_CFLAGS+= -I${KDIR} EXTRA_CFLAGS+= -O2 -funroll-loops -D__CHECK_ENDIAN__ +ifeq (1, $(BUILD_MFG)) +EXTRA_CFLAGS+= -DCONFIG_SUPPORT_MFG +endif + EXTRA_CFLAGS+= -I${PWD} all: diff --git a/Makefile.external b/Makefile.external index ea3f265..e86508c 100644 --- a/Makefile.external +++ b/Makefile.external @@ -8,6 +8,9 @@ mwlwifi-objs += tx.o mwlwifi-objs += rx.o mwlwifi-objs += isr.o mwlwifi-$(CONFIG_DEBUG_FS) += debugfs.o +ifeq (1, $(BUILD_MFG)) +mwlwifi-objs += mfg.o +endif AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld @@ -16,6 +19,10 @@ CC = $(CROSS_COMPILE)gcc EXTRA_CFLAGS+= -I${KDIR} EXTRA_CFLAGS+= -O2 -funroll-loops -D__CHECK_ENDIAN__ +ifeq (1, $(BUILD_MFG)) +EXTRA_CFLAGS+= -DCONFIG_SUPPORT_MFG +endif + EXTRA_CFLAGS+= -I${PWD} all: @@ -121,6 +121,7 @@ static ssize_t mwl_debugfs_info_read(struct file *file, char __user *ubuf, p += sprintf(p, "sta macid support: %08x\n", priv->sta_macids_supported); p += sprintf(p, "macid used: %08x\n", priv->macids_used); + p += sprintf(p, "mfg mode: %s\n", priv->mfg_mode ? "true" : "false"); p += sprintf(p, "\n"); ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, @@ -159,6 +160,10 @@ static ssize_t mwl_debugfs_vif_read(struct file *file, char __user *ubuf, p += sprintf(p, "ssid: %s\n", ssid); p += print_mac_addr(p, mwl_vif->bssid); break; + case NL80211_IFTYPE_MESH_POINT: + p += sprintf(p, "type: mesh\n"); + p += print_mac_addr(p, mwl_vif->bssid); + break; case NL80211_IFTYPE_STATION: p += sprintf(p, "type: sta\n"); p += print_mac_addr(p, mwl_vif->sta_mac); @@ -27,7 +27,7 @@ #include <net/mac80211.h> #define MWL_DRV_NAME KBUILD_MODNAME -#define MWL_DRV_VERSION "10.3.0.10" +#define MWL_DRV_VERSION "10.3.0.12" /* Map to 0x80000000 (Bus control) on BAR0 */ #define MACREG_REG_H2A_INTERRUPT_EVENTS 0x00000C18 /* (From host to ARM) */ @@ -143,6 +143,7 @@ enum { struct mwl_chip_info { const char *part_name; const char *fw_image; + const char *mfg_fw_image; int antenna_tx; int antenna_rx; }; @@ -277,7 +278,7 @@ struct mwl_ampdu_stream { struct mwl_priv { struct ieee80211_hw *hw; - const struct firmware *fw_ucode; + struct firmware *fw_ucode; int chip_type; struct device_node *dt_node; @@ -354,6 +355,8 @@ struct mwl_priv { struct mwl_ampdu_stream ampdu[SYSADPT_TX_AMPDU_QUEUES]; struct work_struct watchdog_ba_handle; + bool mfg_mode; + #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_phy; u32 reg_type; @@ -374,11 +377,21 @@ struct beacon_info { u8 *ie_rsn48_ptr; u8 *ie_ht_ptr; u8 *ie_vht_ptr; +#ifdef CONFIG_MAC80211_MESH + u8 *ie_meshid_ptr; + u8 *ie_meshcfg_ptr; + u8 *ie_meshchsw_ptr; +#endif u8 ie_wmm_len; u8 ie_rsn_len; u8 ie_rsn48_len; u8 ie_ht_len; u8 ie_vht_len; +#ifdef CONFIG_MAC80211_MESH + u8 ie_meshid_len; + u8 ie_meshcfg_len; + u8 ie_meshchsw_len; +#endif }; struct mwl_vif { @@ -27,6 +27,11 @@ #define MAX_WAIT_FW_COMPLETE_ITERATIONS 2000 #define MAX_WAIT_GET_HW_SPECS_ITERATONS 3 +struct cmd_header { + __le16 command; + __le16 len; +} __packed; + static bool mwl_fwcmd_chk_adapter(struct mwl_priv *priv) { u32 regval; @@ -43,6 +48,16 @@ static bool mwl_fwcmd_chk_adapter(struct mwl_priv *priv) static void mwl_fwcmd_send_cmd(struct mwl_priv *priv) { + if (priv->mfg_mode) { + struct cmd_header *cmd_hdr = + (struct cmd_header *)&priv->pcmd_buf[2]; + u16 len = le16_to_cpu(cmd_hdr->len); + + writel(priv->pphys_cmd_buf, priv->iobase1 + 0xcd0); + writel(0x00, priv->iobase1 + 0xcd4); + writel(0x00, priv->iobase1 + MACREG_REG_INT_CODE); + writel(len + 4, priv->iobase1 + 0xc40); + } writel(priv->pphys_cmd_buf, priv->iobase1 + MACREG_REG_GEN_PTR); writel(MACREG_H2ARIC_BIT_DOOR_BELL, priv->iobase1 + MACREG_REG_H2A_INTERRUPT_EVENTS); @@ -109,7 +124,10 @@ static int mwl_fwcmd_wait_complete(struct mwl_priv *priv, unsigned short cmd) unsigned short int_code = 0; do { - int_code = le16_to_cpu(*((__le16 *)&priv->pcmd_buf[0])); + if (priv->mfg_mode) + int_code = le16_to_cpu(*((__le16 *)&priv->pcmd_buf[2])); + else + int_code = le16_to_cpu(*((__le16 *)&priv->pcmd_buf[0])); mdelay(1); } while ((int_code != cmd) && (--curr_iteration)); @@ -437,6 +455,20 @@ static void mwl_fwcmd_parse_beacon(struct mwl_priv *priv, beacon_info->ie_ht_ptr += elen; } break; +#ifdef CONFIG_MAC80211_MESH + case WLAN_EID_MESH_CONFIG: + beacon_info->ie_meshcfg_len = (elen + 2); + beacon_info->ie_meshcfg_ptr = (pos - 2); + break; + case WLAN_EID_MESH_ID: + beacon_info->ie_meshid_len = (elen + 2); + beacon_info->ie_meshid_ptr = (pos - 2); + break; + case WLAN_EID_CHAN_SWITCH_PARAM: + beacon_info->ie_meshchsw_len = (elen + 2); + beacon_info->ie_meshchsw_ptr = (pos - 2); + break; +#endif case WLAN_EID_VHT_CAPABILITY: case WLAN_EID_VHT_OPERATION: case WLAN_EID_OPMODE_NOTIF: @@ -483,14 +515,15 @@ static void mwl_fwcmd_parse_beacon(struct mwl_priv *priv, static int mwl_fwcmd_set_ies(struct mwl_priv *priv, struct mwl_vif *mwl_vif) { struct hostcmd_cmd_set_ies *pcmd; + struct beacon_info *beacon = &mwl_vif->beacon_info; - if (!mwl_vif->beacon_info.valid) + if (!beacon->valid) return -EINVAL; - if (mwl_vif->beacon_info.ie_ht_len > sizeof(pcmd->ie_list_ht)) + if (beacon->ie_ht_len > sizeof(pcmd->ie_list_ht)) goto einval; - if (mwl_vif->beacon_info.ie_vht_len > sizeof(pcmd->ie_list_vht)) + if (beacon->ie_vht_len > sizeof(pcmd->ie_list_vht)) goto einval; pcmd = (struct hostcmd_cmd_set_ies *)&priv->pcmd_buf[0]; @@ -504,20 +537,30 @@ static int mwl_fwcmd_set_ies(struct mwl_priv *priv, struct mwl_vif *mwl_vif) pcmd->action = cpu_to_le16(HOSTCMD_ACT_GEN_SET); - pcmd->ie_list_len_ht = cpu_to_le16(mwl_vif->beacon_info.ie_ht_len); - memcpy(pcmd->ie_list_ht, mwl_vif->beacon_info.ie_ht_ptr, - mwl_vif->beacon_info.ie_ht_len); + memcpy(pcmd->ie_list_ht, beacon->ie_ht_ptr, beacon->ie_ht_len); + pcmd->ie_list_len_ht = cpu_to_le16(beacon->ie_ht_len); - pcmd->ie_list_len_vht = cpu_to_le16(mwl_vif->beacon_info.ie_vht_len); - memcpy(pcmd->ie_list_vht, mwl_vif->beacon_info.ie_vht_ptr, - mwl_vif->beacon_info.ie_vht_len); + memcpy(pcmd->ie_list_vht, beacon->ie_vht_ptr, beacon->ie_vht_len); + pcmd->ie_list_len_vht = cpu_to_le16(beacon->ie_vht_len); + +#ifdef CONFIG_MAC80211_MESH + memcpy(pcmd->ie_list_proprietary, beacon->ie_meshid_ptr, + beacon->ie_meshid_len); + pcmd->ie_list_len_proprietary = cpu_to_le16(beacon->ie_meshid_len); + memcpy(pcmd->ie_list_proprietary + pcmd->ie_list_len_proprietary, + beacon->ie_meshcfg_ptr, beacon->ie_meshcfg_len); + pcmd->ie_list_len_proprietary += cpu_to_le16(beacon->ie_meshcfg_len); + memcpy(pcmd->ie_list_proprietary + pcmd->ie_list_len_proprietary, + beacon->ie_meshchsw_ptr, beacon->ie_meshchsw_len); + pcmd->ie_list_len_proprietary += cpu_to_le16(beacon->ie_meshchsw_len); +#endif if (priv->chip_type == MWL8897) { - pcmd->ie_list_len_proprietary = + memcpy(pcmd->ie_list_proprietary + + pcmd->ie_list_len_proprietary, + beacon->ie_wmm_ptr, beacon->ie_wmm_len); + pcmd->ie_list_len_proprietary += cpu_to_le16(mwl_vif->beacon_info.ie_wmm_len); - memcpy(pcmd->ie_list_proprietary, - mwl_vif->beacon_info.ie_wmm_ptr, - mwl_vif->beacon_info.ie_wmm_len); } if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_SET_IES)) { @@ -698,6 +741,9 @@ int mwl_fwcmd_get_hw_specs(struct ieee80211_hw *hw) int retry; int i; + if (priv->mfg_mode) + return 0; + pcmd = (struct hostcmd_cmd_get_hw_spec *)&priv->pcmd_buf[0]; spin_lock_bh(&priv->fwcmd_lock); @@ -751,6 +797,9 @@ int mwl_fwcmd_set_hw_specs(struct ieee80211_hw *hw) struct hostcmd_cmd_set_hw_spec *pcmd; int i; + if (priv->mfg_mode) + return 0; + pcmd = (struct hostcmd_cmd_set_hw_spec *)&priv->pcmd_buf[0]; spin_lock_bh(&priv->fwcmd_lock); @@ -886,6 +935,9 @@ int mwl_fwcmd_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) struct mwl_priv *priv = hw->priv; int rc; + if (priv->mfg_mode) + return 0; + priv->radio_short_preamble = short_preamble; rc = mwl_fwcmd_802_11_radio_control(priv, true, true); @@ -1146,6 +1198,9 @@ int mwl_fwcmd_rf_antenna(struct ieee80211_hw *hw, int dir, int antenna) struct mwl_priv *priv = hw->priv; struct hostcmd_cmd_802_11_rf_antenna *pcmd; + if (priv->mfg_mode) + return 0; + pcmd = (struct hostcmd_cmd_802_11_rf_antenna *)&priv->pcmd_buf[0]; spin_lock_bh(&priv->fwcmd_lock); @@ -2425,3 +2480,31 @@ int mwl_fwcmd_reg_cau(struct ieee80211_hw *hw, u8 flag, u32 reg, u32 *val) return 0; } + +int mwl_fwcmd_send_mfg_cmd(struct mwl_priv *priv, char *mfgcmd) +{ + struct hostcmd_header *pcmd; + struct cmd_header *cmd_hd = (struct cmd_header *)(mfgcmd+4); + u16 len; + u16 cmd; + + pcmd = (struct hostcmd_header *)&priv->pcmd_buf[0]; + + spin_lock_bh(&priv->fwcmd_lock); + + len = le16_to_cpu(cmd_hd->len); + memset(pcmd, 0x00, len+4); + memcpy((char *)pcmd, mfgcmd, len+4); + cmd = le16_to_cpu(cmd_hd->command); + if (mwl_fwcmd_exec_cmd(priv, cmd)) { + spin_unlock_bh(&priv->fwcmd_lock); + wiphy_err(priv->hw->wiphy, "failed execution"); + return -EIO; + } + cmd_hd = (struct cmd_header *)&priv->pcmd_buf[2]; + len = le16_to_cpu(cmd_hd->len); + memcpy(mfgcmd, (char *)&priv->pcmd_buf[2], len); + spin_unlock_bh(&priv->fwcmd_lock); + + return 0; +} @@ -199,4 +199,6 @@ int mwl_fwcmd_set_cdd(struct ieee80211_hw *hw); int mwl_fwcmd_reg_cau(struct ieee80211_hw *hw, u8 flag, u32 reg, u32 *val); +int mwl_fwcmd_send_mfg_cmd(struct mwl_priv *priv, char *mfgcmd); + #endif /* _fwcmd_h_ */ @@ -22,10 +22,13 @@ #include "sysadpt.h" #include "dev.h" #include "fwcmd.h" +#ifdef CONFIG_SUPPORT_MFG +#include "mfg.h" +#endif #include "fwdl.h" #define FW_DOWNLOAD_BLOCK_SIZE 256 -#define FW_CHECK_MSECS 1 +#define FW_CHECK_MSECS 3 #define FW_MAX_NUM_CHECKS 0xffff @@ -57,6 +60,12 @@ int mwl_fwdl_download_firmware(struct ieee80211_hw *hw) u32 size_fw_downloaded = 0; u32 int_code = 0; u32 len = 0; +#ifdef CONFIG_SUPPORT_MFG + u32 fwreadysignature = priv->mfg_mode ? + MFG_FW_READY_SIGNATURE : HOSTCMD_SOFTAP_FWRDY_SIGNATURE; +#else + u32 fwreadysignature = HOSTCMD_SOFTAP_FWRDY_SIGNATURE; +#endif fw = priv->fw_ucode; @@ -153,15 +162,23 @@ int mwl_fwdl_download_firmware(struct ieee80211_hw *hw) *((u32 *)&priv->pcmd_buf[1]) = 0; mwl_fwdl_trig_pcicmd(priv); curr_iteration = FW_MAX_NUM_CHECKS; + if (priv->mfg_mode) + writel(fwreadysignature, priv->iobase1 + 0xcf0); do { curr_iteration--; - writel(HOSTCMD_SOFTAP_MODE, priv->iobase1 + MACREG_REG_GEN_PTR); - mdelay(FW_CHECK_MSECS); - int_code = readl(priv->iobase1 + MACREG_REG_INT_CODE); + if (!priv->mfg_mode) { + writel(HOSTCMD_SOFTAP_MODE, + priv->iobase1 + MACREG_REG_GEN_PTR); + mdelay(FW_CHECK_MSECS); + int_code = readl(priv->iobase1 + MACREG_REG_INT_CODE); + } else { + mdelay(FW_CHECK_MSECS); + int_code = readl(priv->iobase1 + 0xc44); + } if (!(curr_iteration % 0xff)) wiphy_err(hw->wiphy, "%x;", int_code); } while ((curr_iteration) && - (int_code != HOSTCMD_SOFTAP_FWRDY_SIGNATURE)); + (int_code != fwreadysignature)); if (curr_iteration == 0) { wiphy_err(hw->wiphy, @@ -146,6 +146,7 @@ static int mwl_mac80211_add_interface(struct ieee80211_hw *hw, switch (vif->type) { case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: macids_supported = priv->ap_macids_supported; break; case NL80211_IFTYPE_STATION: @@ -179,6 +180,10 @@ static int mwl_mac80211_add_interface(struct ieee80211_hw *hw, ether_addr_copy(mwl_vif->bssid, vif->addr); mwl_fwcmd_set_new_stn_add_self(hw, vif); break; + case NL80211_IFTYPE_MESH_POINT: + ether_addr_copy(mwl_vif->bssid, vif->addr); + mwl_fwcmd_set_new_stn_add_self(hw, vif); + break; case NL80211_IFTYPE_STATION: ether_addr_copy(mwl_vif->sta_mac, vif->addr); mwl_fwcmd_bss_start(hw, vif, true); @@ -220,6 +225,7 @@ static void mwl_mac80211_remove_interface(struct ieee80211_hw *hw, switch (vif->type) { case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: mwl_fwcmd_set_new_stn_del(hw, vif, vif->addr); break; case NL80211_IFTYPE_STATION: @@ -355,6 +361,7 @@ static void mwl_mac80211_bss_info_changed(struct ieee80211_hw *hw, { switch (vif->type) { case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: mwl_mac80211_bss_info_changed_ap(hw, vif, info, changed); break; case NL80211_IFTYPE_STATION: @@ -458,7 +465,7 @@ static int mwl_mac80211_sta_add(struct ieee80211_hw *hw, memset(sta_info, 0, sizeof(*sta_info)); if (sta->ht_cap.ht_supported) { sta_info->is_ampdu_allowed = true; - sta_info->is_amsdu_allowed = true; + sta_info->is_amsdu_allowed = false; if (sta->ht_cap.cap & IEEE80211_HT_CAP_MAX_AMSDU) sta_info->amsdu_ctrl.cap = MWL_AMSDU_SIZE_8K; else @@ -27,6 +27,9 @@ #include "tx.h" #include "rx.h" #include "isr.h" +#ifdef CONFIG_SUPPORT_MFG +#include "mfg.h" +#endif #ifdef CONFIG_DEBUG_FS #include "debugfs.h" #endif @@ -47,12 +50,14 @@ static struct mwl_chip_info mwl_chip_tbl[] = { [MWL8864] = { .part_name = "88W8864", .fw_image = "mwlwifi/88W8864.bin", + .mfg_fw_image = "./88W8864-MFG.bin", .antenna_tx = ANTENNA_TX_4_AUTO, .antenna_rx = ANTENNA_RX_4_AUTO, }, [MWL8897] = { .part_name = "88W8897", .fw_image = "mwlwifi/88W8897.bin", + .mfg_fw_image = "./88W8897-MFG.bin", .antenna_tx = ANTENNA_TX_2, .antenna_rx = ANTENNA_RX_2, }, @@ -131,6 +136,9 @@ static const struct ieee80211_rate mwl_rates_50[] = { static const struct ieee80211_iface_limit ap_if_limits[] = { { .max = SYSADPT_NUM_OF_AP, .types = BIT(NL80211_IFTYPE_AP) }, +#ifdef CONFIG_MAC80211_MESH + { .max = 1, .types = BIT(NL80211_IFTYPE_MESH_POINT) }, +#endif { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) }, }; @@ -203,7 +211,14 @@ static int mwl_init_firmware(struct mwl_priv *priv, const char *fw_name) pdev = priv->pdev; - rc = request_firmware(&priv->fw_ucode, fw_name, &priv->pdev->dev); +#ifdef CONFIG_SUPPORT_MFG + if (priv->mfg_mode) + rc = mwl_mfg_request_firmware(priv, fw_name); + else +#endif + rc = request_firmware((const struct firmware **)&priv->fw_ucode, + fw_name, &priv->pdev->dev); + if (rc) { wiphy_err(priv->hw->wiphy, "%s: cannot load firmware image <%s>\n", @@ -223,7 +238,12 @@ static int mwl_init_firmware(struct mwl_priv *priv, const char *fw_name) err_download_fw: - release_firmware(priv->fw_ucode); +#ifdef CONFIG_SUPPORT_MFG + if (priv->mfg_mode) + mwl_mfg_release_firmware(priv); + else +#endif + release_firmware(priv->fw_ucode); err_load_fw: @@ -606,6 +626,9 @@ static int mwl_wl_init(struct mwl_priv *priv) hw->wiphy->interface_modes = 0; hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); +#ifdef CONFIG_MAC80211_MESH + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MESH_POINT); +#endif hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); hw->wiphy->iface_combinations = &ap_if_comb; hw->wiphy->n_iface_combinations = 1; @@ -674,6 +697,7 @@ static int mwl_probe(struct pci_dev *pdev, const struct pci_device_id *id) static bool printed_version; struct ieee80211_hw *hw; struct mwl_priv *priv; + const char *fw_name; int rc = 0; if (id->driver_data >= MWLUNKNOWN) @@ -728,7 +752,17 @@ static int mwl_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) goto err_alloc_pci_resource; - rc = mwl_init_firmware(priv, mwl_chip_tbl[priv->chip_type].fw_image); + fw_name = mwl_chip_tbl[priv->chip_type].fw_image; + +#ifdef CONFIG_SUPPORT_MFG + if (mfg_mode) { + mwl_mfg_handler_init(priv); + fw_name = mwl_chip_tbl[priv->chip_type].mfg_fw_image; + } +#endif + + rc = mwl_init_firmware(priv, fw_name); + if (rc) { wiphy_err(hw->wiphy, "%s: fail to initialize firmware\n", MWL_DRV_NAME); @@ -736,7 +770,12 @@ static int mwl_probe(struct pci_dev *pdev, const struct pci_device_id *id) } /* firmware is loaded to H/W, it can be released now */ - release_firmware(priv->fw_ucode); +#ifdef CONFIG_SUPPORT_MFG + if (priv->mfg_mode) + mwl_mfg_release_firmware(priv); + else +#endif + release_firmware(priv->fw_ucode); mwl_process_of_dts(priv); @@ -282,6 +282,24 @@ static inline void mwl_rx_prepare_status(struct mwl_rx_desc *pdesc, } } +static inline void mwl_rx_enable_sta_amsdu(struct mwl_priv *priv, + u8 *sta_addr) +{ + struct mwl_sta *sta_info; + struct ieee80211_sta *sta; + + spin_lock_bh(&priv->sta_lock); + list_for_each_entry(sta_info, &priv->sta_list, list) { + sta = container_of((char *)sta_info, struct ieee80211_sta, + drv_priv[0]); + if (ether_addr_equal(sta->addr, sta_addr)) { + sta_info->is_amsdu_allowed = true; + break; + } + } + spin_unlock_bh(&priv->sta_lock); +} + static inline struct mwl_vif *mwl_rx_find_vif_bss(struct mwl_priv *priv, u8 *bssid) { @@ -485,6 +503,24 @@ void mwl_rx_recv(unsigned long data) skb_put(prx_skb, pkt_len); mwl_rx_remove_dma_header(prx_skb, curr_hndl->pdesc->qos_ctrl); + + if (ieee80211_is_mgmt(wh->frame_control)) { + struct ieee80211_mgmt *mgmt; + __le16 capab; + + mgmt = (struct ieee80211_mgmt *)prx_skb->data; + + if (unlikely(ieee80211_is_action(wh->frame_control) && + mgmt->u.action.category == + WLAN_CATEGORY_BACK && + mgmt->u.action.u.addba_resp.action_code == + WLAN_ACTION_ADDBA_RESP)) { + capab = mgmt->u.action.u.addba_resp.capab; + if (le16_to_cpu(capab) & 1) + mwl_rx_enable_sta_amsdu(priv, mgmt->sa); + } + } + memcpy(IEEE80211_SKB_RXCB(prx_skb), &status, sizeof(status)); ieee80211_rx(hw, prx_skb); out: @@ -852,6 +852,8 @@ void mwl_tx_xmit(struct ieee80211_hw *hw, capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; index = mwl_tx_tid_queue_mapping(tid); + capab |= 1; + mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); } if (unlikely(ieee80211_is_action(wh->frame_control) && |