summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Lin <dlin@marvell.com>2015-10-16 12:52:21 +0800
committerDavid Lin <dlin@marvell.com>2015-10-16 12:52:21 +0800
commit7a6aff718d2de7dee6f9d82eae8af91667e8ee86 (patch)
treef814ad67ecaccb2f005ba5f739632f8a398f629a
parent59e0d3d167a5bc2c03010df4ed54cc0653b5ae58 (diff)
Commit mwlwifi driver 10.3.0.10.
1. Enhance Tx throughput. 2. Add the mechanism to stop and wake up sub Tx queue via ieee80211_stop_queue() and ieee80211_wake_queue(). 3. Refine code related to BA. 4. Replace BUG_ON() with WARN_ON() as suggested by LWN. 5. Acknowledge all packets in AMSDU to mac80211 after transmission is done. 6. Merge patch from community: fix a problem where the resources are left claimed if the firmware fails to load. 7. Replace dma_alloc_coherent() with dmam_alloc_coherent(). 8. Add debugfs. 9. Add linux version check to apply new API ieee80211_hw_set() existed after kernel 4.2. 10. Rearrange spin lock sequences in flushing AMSDU function to avoid dead lock on OpenWrt platform. Signed-off-by: David Lin <dlin@marvell.com>
-rw-r--r--Makefile1
-rw-r--r--Makefile.external1
-rw-r--r--Makefile.kernel1
-rw-r--r--debugfs.c441
-rw-r--r--debugfs.h24
-rw-r--r--dev.h32
-rw-r--r--fwcmd.c264
-rw-r--r--fwcmd.h31
-rw-r--r--hostcmd.h60
-rw-r--r--isr.c16
-rw-r--r--mac80211.c102
-rw-r--r--main.c138
-rw-r--r--rx.c8
-rw-r--r--sysadpt.h4
-rw-r--r--tx.c398
-rw-r--r--tx.h7
16 files changed, 1231 insertions, 297 deletions
diff --git a/Makefile b/Makefile
index 43c8632..ea3f265 100644
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,7 @@ mwlwifi-objs += fwcmd.o
mwlwifi-objs += tx.o
mwlwifi-objs += rx.o
mwlwifi-objs += isr.o
+mwlwifi-$(CONFIG_DEBUG_FS) += debugfs.o
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
diff --git a/Makefile.external b/Makefile.external
index 43c8632..ea3f265 100644
--- a/Makefile.external
+++ b/Makefile.external
@@ -7,6 +7,7 @@ mwlwifi-objs += fwcmd.o
mwlwifi-objs += tx.o
mwlwifi-objs += rx.o
mwlwifi-objs += isr.o
+mwlwifi-$(CONFIG_DEBUG_FS) += debugfs.o
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
diff --git a/Makefile.kernel b/Makefile.kernel
index 49bd311..88f7efd 100644
--- a/Makefile.kernel
+++ b/Makefile.kernel
@@ -7,5 +7,6 @@ mwlwifi-objs += fwcmd.o
mwlwifi-objs += tx.o
mwlwifi-objs += rx.o
mwlwifi-objs += isr.o
+mwlwifi-$(CONFIG_DEBUG_FS) += debugfs.o
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/debugfs.c b/debugfs.c
new file mode 100644
index 0000000..00aa12d
--- /dev/null
+++ b/debugfs.c
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2006-2015, 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.
+ *
+ * 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.
+ */
+
+/* Description: This file implements debug fs related functions. */
+
+#include <linux/debugfs.h>
+
+#include "sysadpt.h"
+#include "dev.h"
+#include "hostcmd.h"
+#include "fwcmd.h"
+#include "debugfs.h"
+
+#define MWLWIFI_DEBUGFS_ADD_FILE(name) do { \
+ if (!debugfs_create_file(#name, 0644, priv->debugfs_phy, \
+ priv, &mwl_debugfs_##name##_fops)) \
+ return; \
+} while (0)
+
+#define MWLWIFI_DEBUGFS_FILE_OPS(name) \
+static const struct file_operations mwl_debugfs_##name##_fops = { \
+ .read = mwl_debugfs_##name##_read, \
+ .write = mwl_debugfs_##name##_write, \
+ .open = simple_open, \
+}
+
+#define MWLWIFI_DEBUGFS_FILE_READ_OPS(name) \
+static const struct file_operations mwl_debugfs_##name##_fops = { \
+ .read = mwl_debugfs_##name##_read, \
+ .open = simple_open, \
+}
+
+#define MWLWIFI_DEBUGFS_FILE_WRITE_OPS(name) \
+static const struct file_operations mwl_debugfs_##name##_fops = { \
+ .write = mwl_debugfs_##name##_write, \
+ .open = simple_open, \
+}
+
+static int print_mac_addr(char *p, u8 *mac_addr)
+{
+ int i;
+ char *str = p;
+
+ str += sprintf(str, "mac address: %02x", mac_addr[0]);
+ for (i = 1; i < ETH_ALEN; i++)
+ str += sprintf(str, ":%02x", mac_addr[i]);
+ str += sprintf(str, "\n");
+
+ return str-p;
+}
+
+static int dump_data(char *p, u8 *data, int len, char *title)
+{
+ char *str = p;
+ int cur_byte = 0;
+ int i;
+
+ str += sprintf(str, "%s\n", title);
+ for (cur_byte = 0; cur_byte < len; cur_byte += 8) {
+ if ((cur_byte + 8) < len) {
+ for (i = 0; i < 8; i++)
+ str += sprintf(str, "0x%02x ",
+ *(data+cur_byte+i));
+ str += sprintf(str, "\n");
+ } else {
+ for (i = 0; i < (len - cur_byte); i++)
+ str += sprintf(str, "0x%02x ",
+ *(data+cur_byte+i));
+ str += sprintf(str, "\n");
+ break;
+ }
+ }
+
+ return str-p;
+}
+
+static ssize_t mwl_debugfs_info_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ char *p = (char *)page;
+ ssize_t ret;
+
+ if (!p)
+ return -ENOMEM;
+
+ p += sprintf(p, "\n");
+ p += sprintf(p, "driver name: %s\n", MWL_DRV_NAME);
+ p += sprintf(p, "chip type: %s\n",
+ (priv->chip_type == MWL8864) ? "88W8864" : "88W8897");
+ p += sprintf(p, "hw version: %X\n", priv->hw_data.hw_version);
+ p += sprintf(p, "driver version: %s\n", MWL_DRV_VERSION);
+ p += sprintf(p, "firmware version: 0x%08x\n",
+ priv->hw_data.fw_release_num);
+ p += print_mac_addr(p, priv->hw_data.mac_addr);
+ p += sprintf(p, "2g: %s\n", priv->disable_2g ? "disable" : "enable");
+ p += sprintf(p, "5g: %s\n", priv->disable_5g ? "disable" : "enable");
+ p += sprintf(p, "antenna: %d %d\n",
+ (priv->antenna_tx == ANTENNA_TX_4_AUTO) ? 4 : 2,
+ (priv->antenna_rx == ANTENNA_TX_4_AUTO) ? 4 : 2);
+ p += sprintf(p, "irq number: %d\n", priv->irq);
+ p += sprintf(p, "iobase0: %p\n", priv->iobase0);
+ p += sprintf(p, "iobase1: %p\n", priv->iobase1);
+ p += sprintf(p, "tx limit: %d\n", priv->txq_limit);
+ p += sprintf(p, "rx limit: %d\n", priv->recv_limit);
+ p += sprintf(p, "ap macid support: %08x\n",
+ priv->ap_macids_supported);
+ 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, "\n");
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
+ (unsigned long) p - page);
+ free_page(page);
+
+ return ret;
+}
+
+static ssize_t mwl_debugfs_vif_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ char *p = (char *)page;
+ struct mwl_vif *mwl_vif;
+ struct ieee80211_vif *vif;
+ char ssid[IEEE80211_MAX_SSID_LEN+1];
+ ssize_t ret;
+
+ if (!p)
+ return -ENOMEM;
+
+ p += sprintf(p, "\n");
+ spin_lock_bh(&priv->vif_lock);
+ list_for_each_entry(mwl_vif, &priv->vif_list, list) {
+ vif = container_of((char *)mwl_vif, struct ieee80211_vif,
+ drv_priv[0]);
+ p += sprintf(p, "macid: %d\n", mwl_vif->macid);
+ switch (vif->type) {
+ case NL80211_IFTYPE_AP:
+ p += sprintf(p, "type: ap\n");
+ memcpy(ssid, vif->bss_conf.ssid,
+ vif->bss_conf.ssid_len);
+ ssid[vif->bss_conf.ssid_len] = 0;
+ p += sprintf(p, "ssid: %s\n", ssid);
+ 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);
+ break;
+ default:
+ p += sprintf(p, "type: unknown\n");
+ break;
+ }
+ p += sprintf(p, "hw_crypto_enabled: %s\n",
+ mwl_vif->is_hw_crypto_enabled ? "true" : "false");
+ p += sprintf(p, "key idx: %d\n", mwl_vif->keyidx);
+ p += sprintf(p, "IV: %08x%04x\n", mwl_vif->iv32, mwl_vif->iv16);
+ p += dump_data(p, mwl_vif->beacon_info.ie_wmm_ptr,
+ mwl_vif->beacon_info.ie_wmm_len, "WMM:");
+ p += dump_data(p, mwl_vif->beacon_info.ie_rsn_ptr,
+ mwl_vif->beacon_info.ie_rsn_len, "RSN:");
+ p += dump_data(p, mwl_vif->beacon_info.ie_rsn48_ptr,
+ mwl_vif->beacon_info.ie_rsn48_len, "RSN48:");
+ p += dump_data(p, mwl_vif->beacon_info.ie_ht_ptr,
+ mwl_vif->beacon_info.ie_ht_len, "HT:");
+ p += dump_data(p, mwl_vif->beacon_info.ie_vht_ptr,
+ mwl_vif->beacon_info.ie_vht_len, "VHT:");
+ p += sprintf(p, "\n");
+ }
+ spin_unlock_bh(&priv->vif_lock);
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
+ (unsigned long) p - page);
+ free_page(page);
+
+ return ret;
+}
+
+static ssize_t mwl_debugfs_sta_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ char *p = (char *)page;
+ struct mwl_sta *sta_info;
+ struct ieee80211_sta *sta;
+ ssize_t ret;
+
+ if (!p)
+ return -ENOMEM;
+
+ p += sprintf(p, "\n");
+ 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]);
+ p += print_mac_addr(p, sta->addr);
+ p += sprintf(p, "aid: %u\n", sta->aid);
+ p += sprintf(p, "ampdu: %s\n",
+ sta_info->is_ampdu_allowed ? "true" : "false");
+ p += sprintf(p, "amsdu: %s\n",
+ sta_info->is_amsdu_allowed ? "true" : "false");
+ if (sta_info->is_amsdu_allowed) {
+ p += sprintf(p, "amsdu cap: 0x%02x\n",
+ sta_info->amsdu_ctrl.cap);
+ }
+ p += sprintf(p, "IV: %08x%04x\n",
+ sta_info->iv32, sta_info->iv16);
+ p += sprintf(p, "\n");
+ }
+ spin_unlock_bh(&priv->sta_lock);
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
+ (unsigned long) p - page);
+ free_page(page);
+
+ return ret;
+}
+
+static ssize_t mwl_debugfs_ampdu_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ char *p = (char *)page;
+ struct mwl_ampdu_stream *stream;
+ int i;
+ ssize_t ret;
+
+ if (!p)
+ return -ENOMEM;
+
+ p += sprintf(p, "\n");
+ spin_lock_bh(&priv->stream_lock);
+ for (i = 0; i < SYSADPT_TX_AMPDU_QUEUES; i++) {
+ stream = &priv->ampdu[i];
+ p += sprintf(p, "stream: %d\n", i);
+ p += sprintf(p, "idx: %u\n", stream->idx);
+ p += sprintf(p, "state: %u\n", stream->state);
+ if (stream->sta) {
+ p += print_mac_addr(p, stream->sta->addr);
+ p += sprintf(p, "tid: %u\n", stream->tid);
+ }
+ }
+ spin_unlock_bh(&priv->stream_lock);
+ p += sprintf(p, "\n");
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
+ (unsigned long) p - page);
+ free_page(page);
+
+ return ret;
+}
+
+static int mwl_debugfs_reg_access(struct mwl_priv *priv, bool write)
+{
+ struct ieee80211_hw *hw = priv->hw;
+ u8 set;
+ u32 *addr_val;
+ int ret = 0;
+
+ set = write ? WL_SET : WL_GET;
+
+ switch (priv->reg_type) {
+ case MWL_ACCESS_MAC:
+ if (set == WL_GET)
+ priv->reg_value =
+ le32_to_cpu(MAC_REG_ADDR_PCI(priv->reg_offset));
+ else
+ writel(cpu_to_le32(priv->reg_value),
+ MAC_REG_ADDR_PCI(priv->reg_offset));
+ break;
+ case MWL_ACCESS_RF:
+ ret = mwl_fwcmd_reg_rf(hw, set, priv->reg_offset,
+ &priv->reg_value);
+ break;
+ case MWL_ACCESS_BBP:
+ ret = mwl_fwcmd_reg_bb(hw, set, priv->reg_offset,
+ &priv->reg_value);
+ break;
+ case MWL_ACCESS_CAU:
+ ret = mwl_fwcmd_reg_cau(hw, set, priv->reg_offset,
+ &priv->reg_value);
+ break;
+ case MWL_ACCESS_ADDR0:
+ if (set == WL_GET)
+ priv->reg_value =
+ readl(priv->iobase0 + priv->reg_offset);
+ else
+ writel(priv->reg_value,
+ priv->iobase0 + priv->reg_offset);
+ break;
+ case MWL_ACCESS_ADDR1:
+ if (set == WL_GET)
+ priv->reg_value =
+ readl(priv->iobase1 + priv->reg_offset);
+ else
+ writel(priv->reg_value,
+ priv->iobase1 + priv->reg_offset);
+ break;
+ case MWL_ACCESS_ADDR:
+ addr_val = kmalloc(64 * sizeof(u32), GFP_KERNEL);
+ if (addr_val) {
+ memset(addr_val, 0, 64 * sizeof(u32));
+ addr_val[0] = priv->reg_value;
+ ret = mwl_fwcmd_get_addr_value(hw, priv->reg_offset,
+ 4, addr_val, set);
+ if ((!ret) && (set == WL_GET))
+ priv->reg_value = addr_val[0];
+ kfree(addr_val);
+ } else
+ ret = -ENOMEM;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static ssize_t mwl_debugfs_regrdwr_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *) addr;
+ int pos = 0, ret = 0;
+
+ if (!buf)
+ return -ENOMEM;
+
+ if (!priv->reg_type) {
+ /* No command has been given */
+ pos += snprintf(buf, PAGE_SIZE, "0");
+ goto none;
+ }
+
+ /* Set command has been given */
+ if (priv->reg_value != UINT_MAX) {
+ ret = mwl_debugfs_reg_access(priv, true);
+ goto done;
+ }
+ /* Get command has been given */
+ ret = mwl_debugfs_reg_access(priv, false);
+
+done:
+ pos += snprintf(buf, PAGE_SIZE, "%u 0x%08x 0x%08x\n",
+ priv->reg_type, priv->reg_offset,
+ priv->reg_value);
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
+
+none:
+
+ free_page(addr);
+ return ret;
+}
+
+static ssize_t mwl_debugfs_regrdwr_write(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *) addr;
+ size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+ int ret;
+ u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
+
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, ubuf, buf_size)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value);
+
+ if (!reg_type) {
+ ret = -EINVAL;
+ goto done;
+ } else {
+ priv->reg_type = reg_type;
+ priv->reg_offset = reg_offset;
+ priv->reg_value = reg_value;
+ ret = count;
+ }
+done:
+
+ free_page(addr);
+ return ret;
+}
+
+MWLWIFI_DEBUGFS_FILE_READ_OPS(info);
+MWLWIFI_DEBUGFS_FILE_READ_OPS(vif);
+MWLWIFI_DEBUGFS_FILE_READ_OPS(sta);
+MWLWIFI_DEBUGFS_FILE_READ_OPS(ampdu);
+MWLWIFI_DEBUGFS_FILE_OPS(regrdwr);
+
+void mwl_debugfs_init(struct ieee80211_hw *hw)
+{
+ struct mwl_priv *priv = hw->priv;
+
+ if (!priv->debugfs_phy)
+ priv->debugfs_phy = debugfs_create_dir("mwlwifi",
+ hw->wiphy->debugfsdir);
+
+ if (!priv->debugfs_phy)
+ return;
+
+ MWLWIFI_DEBUGFS_ADD_FILE(info);
+ MWLWIFI_DEBUGFS_ADD_FILE(vif);
+ MWLWIFI_DEBUGFS_ADD_FILE(sta);
+ MWLWIFI_DEBUGFS_ADD_FILE(ampdu);
+ MWLWIFI_DEBUGFS_ADD_FILE(regrdwr);
+}
+
+void mwl_debugfs_remove(struct ieee80211_hw *hw)
+{
+ struct mwl_priv *priv = hw->priv;
+
+ debugfs_remove(priv->debugfs_phy);
+ priv->debugfs_phy = NULL;
+}
diff --git a/debugfs.h b/debugfs.h
new file mode 100644
index 0000000..dfc2a3c
--- /dev/null
+++ b/debugfs.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2006-2015, 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.
+ *
+ * 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.
+ */
+
+/* Description: This file defines debug fs related functions. */
+
+#ifndef _debugfs_h_
+#define _debugfs_h_
+
+void mwl_debugfs_init(struct ieee80211_hw *hw);
+void mwl_debugfs_remove(struct ieee80211_hw *hw);
+
+#endif /* _debugfs_h_ */
diff --git a/dev.h b/dev.h
index 243af72..b488977 100644
--- a/dev.h
+++ b/dev.h
@@ -26,6 +26,9 @@
#include <linux/bitops.h>
#include <net/mac80211.h>
+#define MWL_DRV_NAME KBUILD_MODNAME
+#define MWL_DRV_VERSION "10.3.0.10"
+
/* Map to 0x80000000 (Bus control) on BAR0 */
#define MACREG_REG_H2A_INTERRUPT_EVENTS 0x00000C18 /* (From host to ARM) */
#define MACREG_REG_H2A_INTERRUPT_CAUSE 0x00000C1C /* (From host to ARM) */
@@ -54,8 +57,8 @@
#define MACREG_A2HRIC_BIT_RADAR_DETECT BIT(7)
#define MACREG_A2HRIC_BIT_ICV_ERROR BIT(8)
#define MACREG_A2HRIC_BIT_WEAKIV_ERROR BIT(9)
-#define MACREG_A2HRIC_BIT_QUEUE_EMPTY BIT(10)
-#define MACREG_A2HRIC_BIT_QUEUE_FULL BIT(11)
+#define MACREG_A2HRIC_BIT_QUE_EMPTY BIT(10)
+#define MACREG_A2HRIC_BIT_QUE_FULL BIT(11)
#define MACREG_A2HRIC_BIT_CHAN_SWITCH BIT(12)
#define MACREG_A2HRIC_BIT_TX_WATCHDOG BIT(13)
#define MACREG_A2HRIC_BA_WATCHDOG BIT(14)
@@ -73,7 +76,7 @@
MACREG_A2HRIC_BIT_RADAR_DETECT | \
MACREG_A2HRIC_BIT_CHAN_SWITCH | \
MACREG_A2HRIC_BIT_TX_WATCHDOG | \
- MACREG_A2HRIC_BIT_QUEUE_EMPTY | \
+ MACREG_A2HRIC_BIT_QUE_EMPTY | \
MACREG_A2HRIC_BA_WATCHDOG | \
MACREG_A2HRIC_CONSEC_TXFAIL)
@@ -260,6 +263,18 @@ struct mwl_ampdu_stream {
u8 idx;
};
+#ifdef CONFIG_DEBUG_FS
+#define MAC_REG_ADDR_PCI(offset) ((priv->iobase1+0xA000) + offset)
+
+#define MWL_ACCESS_MAC 1
+#define MWL_ACCESS_RF 2
+#define MWL_ACCESS_BBP 3
+#define MWL_ACCESS_CAU 4
+#define MWL_ACCESS_ADDR0 5
+#define MWL_ACCESS_ADDR1 6
+#define MWL_ACCESS_ADDR 7
+#endif
+
struct mwl_priv {
struct ieee80211_hw *hw;
const struct firmware *fw_ucode;
@@ -295,6 +310,7 @@ struct mwl_priv {
/* various descriptor data */
spinlock_t tx_desc_lock; /* for tx descriptor data */
+ spinlock_t rx_desc_lock; /* for rx descriptor data */
struct mwl_desc_data desc_data[SYSADPT_NUM_OF_DESC_DATA];
struct sk_buff_head txq[SYSADPT_NUM_OF_DESC_DATA];
struct sk_buff_head delay_q;
@@ -337,6 +353,13 @@ struct mwl_priv {
spinlock_t stream_lock; /* for ampdu stream */
struct mwl_ampdu_stream ampdu[SYSADPT_TX_AMPDU_QUEUES];
struct work_struct watchdog_ba_handle;
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_phy;
+ u32 reg_type;
+ u32 reg_offset;
+ u32 reg_value;
+#endif
};
struct beacon_info {
@@ -415,9 +438,10 @@ struct mwl_dma_data {
/* Transmission information to transmit a socket buffer. */
struct mwl_tx_ctrl {
- void *sta;
void *vif;
+ void *sta;
void *k_conf;
+ void *amsdu_pkts;
u8 tx_priority;
u8 type;
u16 qos_ctrl;
diff --git a/fwcmd.c b/fwcmd.c
index 35da765..62ed88a 100644
--- a/fwcmd.c
+++ b/fwcmd.c
@@ -24,7 +24,7 @@
#include "fwcmd.h"
#include "hostcmd.h"
-#define MAX_WAIT_FW_COMPLETE_ITERATIONS 500
+#define MAX_WAIT_FW_COMPLETE_ITERATIONS 2000
#define MAX_WAIT_GET_HW_SPECS_ITERATONS 3
static bool mwl_fwcmd_chk_adapter(struct mwl_priv *priv)
@@ -60,7 +60,10 @@ static char *mwl_fwcmd_get_cmd_string(unsigned short cmd)
{ HOSTCMD_CMD_GET_HW_SPEC, "GetHwSpecifications" },
{ HOSTCMD_CMD_SET_HW_SPEC, "SetHwSepcifications" },
{ HOSTCMD_CMD_802_11_GET_STAT, "80211GetStat" },
+ { HOSTCMD_CMD_BBP_REG_ACCESS, "BBPRegAccess" },
+ { HOSTCMD_CMD_RF_REG_ACCESS, "RFRegAccess" },
{ HOSTCMD_CMD_802_11_RADIO_CONTROL, "80211RadioControl" },
+ { HOSTCMD_CMD_MEM_ADDR_ACCESS, "MEMAddrAccess" },
{ HOSTCMD_CMD_802_11_TX_POWER, "80211TxPower" },
{ HOSTCMD_CMD_802_11_RF_ANTENNA, "80211RfAntenna" },
{ HOSTCMD_CMD_BROADCAST_SSID_ENABLE, "broadcast_ssid_enable" },
@@ -70,10 +73,12 @@ static char *mwl_fwcmd_get_cmd_string(unsigned short cmd)
{ HOSTCMD_CMD_802_11_RTS_THSD, "80211RtsThreshold" },
{ HOSTCMD_CMD_SET_EDCA_PARAMS, "SetEDCAParams" },
{ HOSTCMD_CMD_SET_WMM_MODE, "SetWMMMode" },
+ { HOSTCMD_CMD_HT_GUARD_INTERVAL, "HtGuardInterval" },
{ HOSTCMD_CMD_SET_FIXED_RATE, "SetFixedRate" },
{ HOSTCMD_CMD_SET_IES, "SetInformationElements" },
- { HOSTCMD_CMD_SET_RATE_ADAPT_MODE, "SetRateAdaptationMode" },
+ { HOSTCMD_CMD_SET_LINKADAPT_CS_MODE, "LinkAdaptCsMode" },
{ HOSTCMD_CMD_SET_MAC_ADDR, "SetMacAddr" },
+ { HOSTCMD_CMD_SET_RATE_ADAPT_MODE, "SetRateAdaptationMode" },
{ HOSTCMD_CMD_GET_WATCHDOG_BITMAP, "GetWatchdogBitMap" },
{ HOSTCMD_CMD_DEL_MAC_ADDR, "DelMacAddr" },
{ HOSTCMD_CMD_BSS_START, "BssStart" },
@@ -82,12 +87,14 @@ static char *mwl_fwcmd_get_cmd_string(unsigned short cmd)
{ HOSTCMD_CMD_SET_APMODE, "SetApMode" },
{ HOSTCMD_CMD_UPDATE_ENCRYPTION, "UpdateEncryption" },
{ HOSTCMD_CMD_BASTREAM, "BAStream" },
+ { HOSTCMD_CMD_SET_OPTIMIZATION_LEVEL, "SetOptimizationLevel"},
{ HOSTCMD_CMD_DWDS_ENABLE, "DwdsEnable" },
{ HOSTCMD_CMD_FW_FLUSH_TIMER, "FwFlushTimer" },
{ HOSTCMD_CMD_SET_CDD, "SetCDD" },
+ { HOSTCMD_CMD_CAU_REG_ACCESS, "CAURegAccess" },
};
- max_entries = sizeof(cmds) / sizeof(cmds[0]);
+ max_entries = ARRAY_SIZE(cmds);
for (curr_cmd = 0; curr_cmd < max_entries; curr_cmd++)
if ((cmd & 0x7fff) == cmds[curr_cmd].cmd)
@@ -99,7 +106,6 @@ static char *mwl_fwcmd_get_cmd_string(unsigned short cmd)
static int mwl_fwcmd_wait_complete(struct mwl_priv *priv, unsigned short cmd)
{
unsigned int curr_iteration = MAX_WAIT_FW_COMPLETE_ITERATIONS;
-
unsigned short int_code = 0;
do {
@@ -110,6 +116,7 @@ static int mwl_fwcmd_wait_complete(struct mwl_priv *priv, unsigned short cmd)
if (curr_iteration == 0) {
wiphy_err(priv->hw->wiphy, "cmd 0x%04x=%s timed out\n",
cmd, mwl_fwcmd_get_cmd_string(cmd));
+ wiphy_err(priv->hw->wiphy, "return code: 0x%04x\n", int_code);
return -EIO;
}
@@ -132,7 +139,7 @@ static int mwl_fwcmd_exec_cmd(struct mwl_priv *priv, unsigned short cmd)
priv->in_send_cmd = true;
mwl_fwcmd_send_cmd(priv);
if (mwl_fwcmd_wait_complete(priv, 0x8000 | cmd)) {
- wiphy_err(priv->hw->wiphy, "timeout\n");
+ wiphy_err(priv->hw->wiphy, "timeout: 0x%04x\n", cmd);
priv->in_send_cmd = false;
return -EIO;
}
@@ -697,7 +704,7 @@ int mwl_fwcmd_get_hw_specs(struct ieee80211_hw *hw)
wiphy_debug(hw->wiphy, "pcmd = %p\n", pcmd);
memset(pcmd, 0x00, sizeof(*pcmd));
- memset(&pcmd->permanent_addr[0], 0xff, ETH_ALEN);
+ eth_broadcast_addr(pcmd->permanent_addr);
pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_GET_HW_SPEC);
pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
pcmd->fw_awake_cookie = cpu_to_le32(priv->pphys_cmd_buf + 2048);
@@ -806,6 +813,64 @@ int mwl_fwcmd_get_stat(struct ieee80211_hw *hw,
return 0;
}
+int mwl_fwcmd_reg_bb(struct ieee80211_hw *hw, u8 flag, u32 reg, u32 *val)
+{
+ struct mwl_priv *priv = hw->priv;
+ struct hostcmd_cmd_bbp_reg_access *pcmd;
+
+ pcmd = (struct hostcmd_cmd_bbp_reg_access *)&priv->pcmd_buf[0];
+
+ spin_lock_bh(&priv->fwcmd_lock);
+
+ memset(pcmd, 0x00, sizeof(*pcmd));
+ pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_BBP_REG_ACCESS);
+ pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
+ pcmd->offset = cpu_to_le16(reg);
+ pcmd->action = cpu_to_le16(flag);
+ pcmd->value = *val;
+
+ if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_BBP_REG_ACCESS)) {
+ spin_unlock_bh(&priv->fwcmd_lock);
+ wiphy_err(hw->wiphy, "failed execution\n");
+ return -EIO;
+ }
+
+ *val = pcmd->value;
+
+ spin_unlock_bh(&priv->fwcmd_lock);
+
+ return 0;
+}
+
+int mwl_fwcmd_reg_rf(struct ieee80211_hw *hw, u8 flag, u32 reg, u32 *val)
+{
+ struct mwl_priv *priv = hw->priv;
+ struct hostcmd_cmd_rf_reg_access *pcmd;
+
+ pcmd = (struct hostcmd_cmd_rf_reg_access *)&priv->pcmd_buf[0];
+
+ spin_lock_bh(&priv->fwcmd_lock);
+
+ memset(pcmd, 0x00, sizeof(*pcmd));
+ pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_RF_REG_ACCESS);
+ pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
+ pcmd->offset = cpu_to_le16(reg);
+ pcmd->action = cpu_to_le16(flag);
+ pcmd->value = *val;
+
+ if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_RF_REG_ACCESS)) {
+ spin_unlock_bh(&priv->fwcmd_lock);
+ wiphy_err(hw->wiphy, "failed execution\n");
+ return -EIO;
+ }
+
+ *val = pcmd->value;
+
+ spin_unlock_bh(&priv->fwcmd_lock);
+
+ return 0;
+}
+
int mwl_fwcmd_radio_enable(struct ieee80211_hw *hw)
{
return mwl_fwcmd_802_11_radio_control(hw->priv, true, false);
@@ -827,6 +892,39 @@ int mwl_fwcmd_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble)
return rc;
}
+int mwl_fwcmd_get_addr_value(struct ieee80211_hw *hw, u32 addr, u32 len,
+ u32 *val, u16 set)
+{
+ struct mwl_priv *priv = hw->priv;
+ struct hostcmd_cmd_mem_addr_access *pcmd;
+ int i;
+
+ pcmd = (struct hostcmd_cmd_mem_addr_access *)&priv->pcmd_buf[0];
+
+ spin_lock_bh(&priv->fwcmd_lock);
+
+ memset(pcmd, 0x00, sizeof(*pcmd));
+ pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_MEM_ADDR_ACCESS);
+ pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
+ pcmd->address = cpu_to_le32(addr);
+ pcmd->length = cpu_to_le16(len);
+ pcmd->value[0] = cpu_to_le32(*val);
+ pcmd->reserved = cpu_to_le16(set);
+
+ if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_MEM_ADDR_ACCESS)) {
+ spin_unlock_bh(&priv->fwcmd_lock);
+ wiphy_err(hw->wiphy, "failed execution\n");
+ return -EIO;
+ }
+
+ for (i = 0; i < len; i++)
+ val[i] = le32_to_cpu(pcmd->value[i]);
+
+ spin_unlock_bh(&priv->fwcmd_lock);
+
+ return 0;
+}
+
int mwl_fwcmd_max_tx_power(struct ieee80211_hw *hw,
struct ieee80211_conf *conf, u8 fraction)
{
@@ -1334,6 +1432,32 @@ int mwl_fwcmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable)
return 0;
}
+int mwl_fwcmd_ht_guard_interval(struct ieee80211_hw *hw, u32 gi_type)
+{
+ struct mwl_priv *priv = hw->priv;
+ struct hostcmd_cmd_ht_guard_interval *pcmd;
+
+ pcmd = (struct hostcmd_cmd_ht_guard_interval *)&priv->pcmd_buf[0];
+
+ spin_lock_bh(&priv->fwcmd_lock);
+
+ memset(pcmd, 0x00, sizeof(*pcmd));
+ pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_HT_GUARD_INTERVAL);
+ pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
+ pcmd->action = cpu_to_le32(WL_SET);
+ pcmd->gi_type = cpu_to_le32(gi_type);
+
+ if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_HT_GUARD_INTERVAL)) {
+ spin_unlock_bh(&priv->fwcmd_lock);
+ wiphy_err(hw->wiphy, "failed execution\n");
+ return -EIO;
+ }
+
+ spin_unlock_bh(&priv->fwcmd_lock);
+
+ return 0;
+}
+
int mwl_fwcmd_use_fixed_rate(struct ieee80211_hw *hw, int mcast, int mgmt)
{
struct mwl_priv *priv = hw->priv;
@@ -1362,6 +1486,32 @@ int mwl_fwcmd_use_fixed_rate(struct ieee80211_hw *hw, int mcast, int mgmt)
return 0;
}
+int mwl_fwcmd_set_linkadapt_cs_mode(struct ieee80211_hw *hw, u16 cs_mode)
+{
+ struct mwl_priv *priv = hw->priv;
+ struct hostcmd_cmd_set_linkadapt_cs_mode *pcmd;
+
+ pcmd = (struct hostcmd_cmd_set_linkadapt_cs_mode *)&priv->pcmd_buf[0];
+
+ spin_lock_bh(&priv->fwcmd_lock);
+
+ memset(pcmd, 0x00, sizeof(*pcmd));
+ pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_LINKADAPT_CS_MODE);
+ pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
+ pcmd->action = cpu_to_le16(HOSTCMD_ACT_GEN_SET);
+ pcmd->cs_mode = cpu_to_le16(cs_mode);
+
+ if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_SET_LINKADAPT_CS_MODE)) {
+ spin_unlock_bh(&priv->fwcmd_lock);
+ wiphy_err(hw->wiphy, "failed execution\n");
+ return -EIO;
+ }
+
+ spin_unlock_bh(&priv->fwcmd_lock);
+
+ return 0;
+}
+
int mwl_fwcmd_set_rate_adapt_mode(struct ieee80211_hw *hw, u16 mode)
{
struct mwl_priv *priv = hw->priv;
@@ -1759,7 +1909,7 @@ int mwl_fwcmd_update_encryption_enable(struct ieee80211_hw *hw,
}
if (vif->type == NL80211_IFTYPE_STATION) {
- if (memcmp(mwl_vif->bssid, addr, ETH_ALEN) == 0)
+ if (ether_addr_equal(mwl_vif->bssid, addr))
ether_addr_copy(pcmd->mac_addr, mwl_vif->sta_mac);
else
ether_addr_copy(pcmd->mac_addr, mwl_vif->bssid);
@@ -1847,7 +1997,7 @@ int mwl_fwcmd_encryption_set_key(struct ieee80211_hw *hw,
}
if (vif->type == NL80211_IFTYPE_STATION) {
- if (memcmp(mwl_vif->bssid, addr, ETH_ALEN) == 0)
+ if (ether_addr_equal(mwl_vif->bssid, addr))
ether_addr_copy(pcmd->key_param.mac_addr,
mwl_vif->sta_mac);
else
@@ -1932,8 +2082,8 @@ int mwl_fwcmd_check_ba(struct ieee80211_hw *hw,
pcmd->cmd_hdr.result = cpu_to_le16(0xffff);
pcmd->action_type = cpu_to_le32(BA_CHECK_STREAM);
- memcpy(&pcmd->ba_info.create_params.peer_mac_addr[0],
- stream->sta->addr, ETH_ALEN);
+ ether_addr_copy(&pcmd->ba_info.create_params.peer_mac_addr[0],
+ stream->sta->addr);
pcmd->ba_info.create_params.tid = stream->tid;
ba_type = BASTREAM_FLAG_IMMEDIATE_TYPE;
ba_direction = BASTREAM_FLAG_DIRECTION_UPSTREAM;
@@ -1944,13 +2094,14 @@ int mwl_fwcmd_check_ba(struct ieee80211_hw *hw,
if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_BASTREAM)) {
spin_unlock_bh(&priv->fwcmd_lock);
- wiphy_err(hw->wiphy, "failed execution\n");
+ wiphy_err(hw->wiphy, "check ba failed execution\n");
return -EIO;
}
if (pcmd->cmd_hdr.result != 0) {
spin_unlock_bh(&priv->fwcmd_lock);
- wiphy_err(hw->wiphy, "check ba result error\n");
+ wiphy_err(hw->wiphy, "check ba result error %d\n",
+ le16_to_cpu(pcmd->cmd_hdr.result));
return -EINVAL;
}
@@ -1983,8 +2134,8 @@ int mwl_fwcmd_create_ba(struct ieee80211_hw *hw,
pcmd->action_type = cpu_to_le32(BA_CREATE_STREAM);
pcmd->ba_info.create_params.bar_thrs = cpu_to_le32(buf_size);
pcmd->ba_info.create_params.window_size = cpu_to_le32(buf_size);
- memcpy(&pcmd->ba_info.create_params.peer_mac_addr[0],
- stream->sta->addr, ETH_ALEN);
+ ether_addr_copy(&pcmd->ba_info.create_params.peer_mac_addr[0],
+ stream->sta->addr);
pcmd->ba_info.create_params.tid = stream->tid;
ba_type = BASTREAM_FLAG_IMMEDIATE_TYPE;
ba_direction = BASTREAM_FLAG_DIRECTION_UPSTREAM;
@@ -2002,13 +2153,14 @@ int mwl_fwcmd_create_ba(struct ieee80211_hw *hw,
if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_BASTREAM)) {
spin_unlock_bh(&priv->fwcmd_lock);
- wiphy_err(hw->wiphy, "failed execution\n");
+ wiphy_err(hw->wiphy, "create ba failed execution\n");
return -EIO;
}
if (pcmd->cmd_hdr.result != 0) {
spin_unlock_bh(&priv->fwcmd_lock);
- wiphy_err(hw->wiphy, "create ba result error\n");
+ wiphy_err(hw->wiphy, "create ba result error %d\n",
+ le16_to_cpu(pcmd->cmd_hdr.result));
return -EINVAL;
}
@@ -2042,7 +2194,7 @@ int mwl_fwcmd_destroy_ba(struct ieee80211_hw *hw,
if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_BASTREAM)) {
spin_unlock_bh(&priv->fwcmd_lock);
- wiphy_err(hw->wiphy, "failed execution\n");
+ wiphy_err(hw->wiphy, "destroy ba failed execution\n");
return -EIO;
}
@@ -2075,6 +2227,23 @@ struct mwl_ampdu_stream *mwl_fwcmd_add_stream(struct ieee80211_hw *hw,
return NULL;
}
+void mwl_fwcmd_del_sta_streams(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta)
+{
+ struct mwl_priv *priv = hw->priv;
+ struct mwl_ampdu_stream *stream;
+ int i;
+
+ for (i = 0; i < SYSADPT_TX_AMPDU_QUEUES; i++) {
+ stream = &priv->ampdu[i];
+
+ if (stream->sta == sta) {
+ mwl_fwcmd_destroy_ba(hw, stream->idx);
+ mwl_fwcmd_remove_stream(hw, stream);
+ }
+ }
+}
+
int mwl_fwcmd_start_stream(struct ieee80211_hw *hw,
struct mwl_ampdu_stream *stream)
{
@@ -2104,7 +2273,7 @@ struct mwl_ampdu_stream *mwl_fwcmd_lookup_stream(struct ieee80211_hw *hw,
if (stream->state == AMPDU_NO_STREAM)
continue;
- if (!memcmp(stream->sta->addr, addr, ETH_ALEN) &&
+ if (ether_addr_equal(stream->sta->addr, addr) &&
stream->tid == tid)
return stream;
}
@@ -2117,9 +2286,10 @@ bool mwl_fwcmd_ampdu_allowed(struct ieee80211_sta *sta, u8 tid)
struct mwl_sta *sta_info;
struct mwl_tx_info *tx_stats;
- sta_info = mwl_dev_get_sta(sta);
+ if (WARN_ON(tid >= SYSADPT_MAX_TID))
+ return false;
- BUG_ON(tid >= SYSADPT_MAX_TID);
+ sta_info = mwl_dev_get_sta(sta);
tx_stats = &sta_info->tx_stats[tid];
@@ -2127,6 +2297,31 @@ bool mwl_fwcmd_ampdu_allowed(struct ieee80211_sta *sta, u8 tid)
tx_stats->pkts > SYSADPT_AMPDU_PACKET_THRESHOLD);
}
+int mwl_fwcmd_set_optimization_level(struct ieee80211_hw *hw, u8 opt_level)
+{
+ struct mwl_priv *priv = hw->priv;
+ struct hostcmd_cmd_set_optimization_level *pcmd;
+
+ pcmd = (struct hostcmd_cmd_set_optimization_level *)&priv->pcmd_buf[0];
+
+ spin_lock_bh(&priv->fwcmd_lock);
+
+ memset(pcmd, 0x00, sizeof(*pcmd));
+ pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_OPTIMIZATION_LEVEL);
+ pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
+ pcmd->opt_level = opt_level;
+
+ if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_SET_OPTIMIZATION_LEVEL)) {
+ spin_unlock_bh(&priv->fwcmd_lock);
+ wiphy_err(hw->wiphy, "failed execution\n");
+ return -EIO;
+ }
+
+ spin_unlock_bh(&priv->fwcmd_lock);
+
+ return 0;
+}
+
int mwl_fwcmd_set_dwds_stamode(struct ieee80211_hw *hw, bool enable)
{
struct mwl_priv *priv = hw->priv;
@@ -2201,3 +2396,32 @@ int mwl_fwcmd_set_cdd(struct ieee80211_hw *hw)
return 0;
}
+
+int mwl_fwcmd_reg_cau(struct ieee80211_hw *hw, u8 flag, u32 reg, u32 *val)
+{
+ struct mwl_priv *priv = hw->priv;
+ struct hostcmd_cmd_bbp_reg_access *pcmd;
+
+ pcmd = (struct hostcmd_cmd_bbp_reg_access *)&priv->pcmd_buf[0];
+
+ spin_lock_bh(&priv->fwcmd_lock);
+
+ memset(pcmd, 0x00, sizeof(*pcmd));
+ pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_CAU_REG_ACCESS);
+ pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
+ pcmd->offset = cpu_to_le16(reg);
+ pcmd->action = cpu_to_le16(flag);
+ pcmd->value = *val;
+
+ if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_CAU_REG_ACCESS)) {
+ spin_unlock_bh(&priv->fwcmd_lock);
+ wiphy_err(hw->wiphy, "failed execution\n");
+ return -EIO;
+ }
+
+ *val = pcmd->value;
+
+ spin_unlock_bh(&priv->fwcmd_lock);
+
+ return 0;
+}
diff --git a/fwcmd.h b/fwcmd.h
index 6b8ec74..6775c98 100644
--- a/fwcmd.h
+++ b/fwcmd.h
@@ -33,6 +33,15 @@
#define HOSTCMD_STA_FWRDY_SIGNATURE 0xF0F1F2F4
#define HOSTCMD_SOFTAP_FWRDY_SIGNATURE 0xF1F2F4A5
+#define GUARD_INTERVAL_STANDARD 1
+#define GUARD_INTERVAL_SHORT 2
+#define GUARD_INTERVAL_AUTO 3
+
+#define LINK_CS_STATE_CONSERV 0
+#define LINK_CS_STATE_AGGR 1
+#define LINK_CS_STATE_AUTO 2
+#define LINK_CS_STATE_AUTO_DISABLED 3
+
enum {
WL_ANTENNATYPE_RX = 1,
WL_ANTENNATYPE_TX = 2,
@@ -59,6 +68,10 @@ int mwl_fwcmd_set_hw_specs(struct ieee80211_hw *hw);
int mwl_fwcmd_get_stat(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats);
+int mwl_fwcmd_reg_bb(struct ieee80211_hw *hw, u8 flag, u32 reg, u32 *val);
+
+int mwl_fwcmd_reg_rf(struct ieee80211_hw *hw, u8 flag, u32 reg, u32 *val);
+
int mwl_fwcmd_radio_enable(struct ieee80211_hw *hw);
int mwl_fwcmd_radio_disable(struct ieee80211_hw *hw);
@@ -66,6 +79,9 @@ int mwl_fwcmd_radio_disable(struct ieee80211_hw *hw);
int mwl_fwcmd_set_radio_preamble(struct ieee80211_hw *hw,
bool short_preamble);
+int mwl_fwcmd_get_addr_value(struct ieee80211_hw *hw, u32 addr, u32 len,
+ u32 *val, u16 set);
+
int mwl_fwcmd_max_tx_power(struct ieee80211_hw *hw,
struct ieee80211_conf *conf, u8 fraction);
@@ -92,12 +108,16 @@ int mwl_fwcmd_set_rts_threshold(struct ieee80211_hw *hw,
int mwl_fwcmd_set_edca_params(struct ieee80211_hw *hw, u8 index,
u16 cw_min, u16 cw_max, u8 aifs, u16 txop);
-int mwl_fwcmd_set_wmm_mode(struct ieee80211_hw *hw,
- bool enable);
+int mwl_fwcmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable);
+
+int mwl_fwcmd_ht_guard_interval(struct ieee80211_hw *hw, u32 gi_type);
int mwl_fwcmd_use_fixed_rate(struct ieee80211_hw *hw,
int mcast, int mgmt);
+int mwl_fwcmd_set_linkadapt_cs_mode(struct ieee80211_hw *hw,
+ u16 cs_mode);
+
int mwl_fwcmd_set_rate_adapt_mode(struct ieee80211_hw *hw,
u16 mode);
@@ -155,6 +175,9 @@ struct mwl_ampdu_stream *mwl_fwcmd_add_stream(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u8 tid);
+void mwl_fwcmd_del_sta_streams(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta);
+
int mwl_fwcmd_start_stream(struct ieee80211_hw *hw,
struct mwl_ampdu_stream *stream);
@@ -166,10 +189,14 @@ struct mwl_ampdu_stream *mwl_fwcmd_lookup_stream(struct ieee80211_hw *hw,
bool mwl_fwcmd_ampdu_allowed(struct ieee80211_sta *sta, u8 tid);
+int mwl_fwcmd_set_optimization_level(struct ieee80211_hw *hw, u8 opt_level);
+
int mwl_fwcmd_set_dwds_stamode(struct ieee80211_hw *hw, bool enable);
int mwl_fwcmd_set_fw_flush_timer(struct ieee80211_hw *hw, u32 value);
int mwl_fwcmd_set_cdd(struct ieee80211_hw *hw);
+int mwl_fwcmd_reg_cau(struct ieee80211_hw *hw, u8 flag, u32 reg, u32 *val);
+
#endif /* _fwcmd_h_ */
diff --git a/hostcmd.h b/hostcmd.h
index d9db0ee..8c03626 100644
--- a/hostcmd.h
+++ b/hostcmd.h
@@ -24,7 +24,10 @@
#define HOSTCMD_CMD_GET_HW_SPEC 0x0003
#define HOSTCMD_CMD_SET_HW_SPEC 0x0004
#define HOSTCMD_CMD_802_11_GET_STAT 0x0014
+#define HOSTCMD_CMD_BBP_REG_ACCESS 0x001a
+#define HOSTCMD_CMD_RF_REG_ACCESS 0x001b
#define HOSTCMD_CMD_802_11_RADIO_CONTROL 0x001c
+#define HOSTCMD_CMD_MEM_ADDR_ACCESS 0x001d
#define HOSTCMD_CMD_802_11_TX_POWER 0x001f
#define HOSTCMD_CMD_802_11_RF_ANTENNA 0x0020
#define HOSTCMD_CMD_BROADCAST_SSID_ENABLE 0x0050 /* per-vif */
@@ -34,8 +37,10 @@
#define HOSTCMD_CMD_802_11_RTS_THSD 0x0113
#define HOSTCMD_CMD_SET_EDCA_PARAMS 0x0115
#define HOSTCMD_CMD_SET_WMM_MODE 0x0123
+#define HOSTCMD_CMD_HT_GUARD_INTERVAL 0x0124
#define HOSTCMD_CMD_SET_FIXED_RATE 0x0126
#define HOSTCMD_CMD_SET_IES 0x0127
+#define HOSTCMD_CMD_SET_LINKADAPT_CS_MODE 0x0129
#define HOSTCMD_CMD_SET_MAC_ADDR 0x0202 /* per-vif */
#define HOSTCMD_CMD_SET_RATE_ADAPT_MODE 0x0203
#define HOSTCMD_CMD_GET_WATCHDOG_BITMAP 0x0205
@@ -46,9 +51,11 @@
#define HOSTCMD_CMD_SET_APMODE 0x1114
#define HOSTCMD_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */
#define HOSTCMD_CMD_BASTREAM 0x1125
+#define HOSTCMD_CMD_SET_OPTIMIZATION_LEVEL 0x1133
#define HOSTCMD_CMD_DWDS_ENABLE 0x1144
#define HOSTCMD_CMD_FW_FLUSH_TIMER 0x1148
#define HOSTCMD_CMD_SET_CDD 0x1150
+#define HOSTCMD_CMD_CAU_REG_ACCESS 0x1157
/* Define general result code for each command */
#define HOSTCMD_RESULT_OK 0x0000
@@ -261,6 +268,24 @@ struct hostcmd_cmd_802_11_get_stat {
__le32 tx_cts_count;
} __packed;
+/* HOSTCMD_CMD_BBP_REG_ACCESS */
+struct hostcmd_cmd_bbp_reg_access {
+ struct hostcmd_header cmd_hdr;
+ __le16 action;
+ __le16 offset;
+ u8 value;
+ u8 reserverd[3];
+} __packed;
+
+/* HOSTCMD_CMD_RF_REG_ACCESS */
+struct hostcmd_cmd_rf_reg_access {
+ struct hostcmd_header cmd_hdr;
+ __le16 action;
+ __le16 offset;
+ u8 value;
+ u8 reserverd[3];
+} __packed;
+
/* HOSTCMD_CMD_802_11_RADIO_CONTROL */
struct hostcmd_cmd_802_11_radio_control {
struct hostcmd_header cmd_hdr;
@@ -270,6 +295,15 @@ struct hostcmd_cmd_802_11_radio_control {
__le16 radio_on;
} __packed;
+/* HOSTCMD_CMD_MEM_ADDR_ACCESS */
+struct hostcmd_cmd_mem_addr_access {
+ struct hostcmd_header cmd_hdr;
+ __le32 address;
+ __le16 length;
+ __le16 reserved;
+ __le32 value[64];
+} __packed;
+
/* HOSTCMD_CMD_802_11_TX_POWER */
struct hostcmd_cmd_802_11_tx_power {
struct hostcmd_header cmd_hdr;
@@ -347,6 +381,13 @@ struct hostcmd_cmd_set_wmm_mode {
__le16 action; /* 0->unset, 1->set */
} __packed;
+/* HOSTCMD_CMD_HT_GUARD_INTERVAL */
+struct hostcmd_cmd_ht_guard_interval {
+ struct hostcmd_header cmd_hdr;
+ __le32 action;
+ __le32 gi_type;
+} __packed;
+
/* HOSTCMD_CMD_SET_FIXED_RATE */
struct fix_rate_flag { /* lower rate after the retry count */
/* 0: legacy, 1: HT */
@@ -390,11 +431,11 @@ struct hostcmd_cmd_set_ies {
u8 ie_list_proprietary[112];
} __packed;
-/* HOSTCMD_CMD_SET_RATE_ADAPT_MODE */
-struct hostcmd_cmd_set_rate_adapt_mode {
+/* HOSTCMD_CMD_SET_LINKADAPT_CS_MODE */
+struct hostcmd_cmd_set_linkadapt_cs_mode {
struct hostcmd_header cmd_hdr;
__le16 action;
- __le16 rate_adapt_mode; /* 0:Indoor, 1:Outdoor */
+ __le16 cs_mode;
} __packed;
/* HOSTCMD_CMD_SET_MAC_ADDR, HOSTCMD_CMD_DEL_MAC_ADDR */
@@ -404,6 +445,13 @@ struct hostcmd_cmd_set_mac_addr {
u8 mac_addr[ETH_ALEN];
} __packed;
+/* HOSTCMD_CMD_SET_RATE_ADAPT_MODE */
+struct hostcmd_cmd_set_rate_adapt_mode {
+ struct hostcmd_header cmd_hdr;
+ __le16 action;
+ __le16 rate_adapt_mode; /* 0:Indoor, 1:Outdoor */
+} __packed;
+
/* HOSTCMD_CMD_GET_WATCHDOG_BITMAP */
struct hostcmd_cmd_get_watchdog_bitmap {
struct hostcmd_header cmd_hdr;
@@ -731,6 +779,12 @@ struct hostcmd_cmd_bastream {
union ba_info ba_info;
} __packed;
+/* HOSTCMD_CMD_SET_OPTIMIZATION_LEVEL */
+struct hostcmd_cmd_set_optimization_level {
+ struct hostcmd_header cmd_hdr;
+ u8 opt_level;
+} __packed;
+
/* HOSTCMD_CMD_DWDS_ENABLE */
struct hostcmd_cmd_dwds_enable {
struct hostcmd_header cmd_hdr;
diff --git a/isr.c b/isr.c
index 9e7d473..20b6088 100644
--- a/isr.c
+++ b/isr.c
@@ -66,12 +66,12 @@ irqreturn_t mwl_isr(int irq, void *dev_id)
}
}
- if (int_status & MACREG_A2HRIC_BIT_QUEUE_EMPTY) {
- int_status &= ~MACREG_A2HRIC_BIT_QUEUE_EMPTY;
+ if (int_status & MACREG_A2HRIC_BIT_QUE_EMPTY) {
+ int_status &= ~MACREG_A2HRIC_BIT_QUE_EMPTY;
if (!priv->is_qe_schedule) {
status = readl(int_status_mask);
- writel((status & ~MACREG_A2HRIC_BIT_QUEUE_EMPTY),
+ writel((status & ~MACREG_A2HRIC_BIT_QUE_EMPTY),
int_status_mask);
tasklet_schedule(&priv->qe_task);
priv->is_qe_schedule = true;
@@ -100,7 +100,6 @@ void mwl_watchdog_ba_events(struct work_struct *work)
struct mwl_ampdu_stream *streams;
struct mwl_priv *priv =
container_of(work, struct mwl_priv, watchdog_ba_handle);
- struct ieee80211_hw *hw = priv->hw;
u32 status;
rc = mwl_fwcmd_get_watchdog_bitmap(priv->hw, &bitmap);
@@ -123,13 +122,9 @@ void mwl_watchdog_ba_events(struct work_struct *work)
/* Check if the stream is in use before disabling it */
streams = &priv->ampdu[stream_index];
- if (streams->state == AMPDU_STREAM_ACTIVE) {
+ if (streams->state == AMPDU_STREAM_ACTIVE)
ieee80211_stop_tx_ba_session(streams->sta,
streams->tid);
- spin_unlock_bh(&priv->stream_lock);
- mwl_fwcmd_destroy_ba(hw, stream_index);
- spin_lock_bh(&priv->stream_lock);
- }
} else {
for (stream_index = 0;
stream_index < SYSADPT_TX_AMPDU_QUEUES;
@@ -141,9 +136,6 @@ void mwl_watchdog_ba_events(struct work_struct *work)
ieee80211_stop_tx_ba_session(streams->sta,
streams->tid);
- spin_unlock_bh(&priv->stream_lock);
- mwl_fwcmd_destroy_ba(hw, stream_index);
- spin_lock_bh(&priv->stream_lock);
}
}
}
diff --git a/mac80211.c b/mac80211.c
index a4242e0..ec96f25 100644
--- a/mac80211.c
+++ b/mac80211.c
@@ -91,12 +91,18 @@ static int mwl_mac80211_start(struct ieee80211_hw *hw)
rc = mwl_fwcmd_set_wmm_mode(hw, true);
if (rc)
goto fwcmd_fail;
+ rc = mwl_fwcmd_ht_guard_interval(hw, GUARD_INTERVAL_AUTO);
+ if (rc)
+ goto fwcmd_fail;
rc = mwl_fwcmd_set_dwds_stamode(hw, true);
if (rc)
goto fwcmd_fail;
rc = mwl_fwcmd_set_fw_flush_timer(hw, SYSADPT_AMSDU_FLUSH_TIME);
if (rc)
goto fwcmd_fail;
+ rc = mwl_fwcmd_set_optimization_level(hw, 1);
+ if (rc)
+ goto fwcmd_fail;
ieee80211_wake_queues(hw);
return 0;
@@ -194,27 +200,12 @@ static int mwl_mac80211_add_interface(struct ieee80211_hw *hw,
static void mwl_mac80211_remove_vif(struct mwl_priv *priv,
struct ieee80211_vif *vif)
{
- int num;
- struct sk_buff *skb, *tmp;
- struct ieee80211_tx_info *tx_info;
- struct mwl_tx_ctrl *tx_ctrl;
struct mwl_vif *mwl_vif = mwl_dev_get_vif(vif);
if (!priv->macids_used)
return;
- for (num = 1; num < SYSADPT_NUM_OF_DESC_DATA; num++) {
- spin_lock_bh(&priv->txq[num].lock);
- skb_queue_walk_safe(&priv->txq[num], skb, tmp) {
- tx_info = IEEE80211_SKB_CB(skb);
- tx_ctrl = (struct mwl_tx_ctrl *)&tx_info->status;
- if (tx_ctrl->vif == vif) {
- __skb_unlink(skb, &priv->txq[num]);
- dev_kfree_skb_any(skb);
- }
- }
- spin_unlock_bh(&priv->txq[num].lock);
- }
+ mwl_tx_del_pkts_via_vif(priv->hw, vif);
priv->macids_used &= ~(1 << mwl_vif->macid);
spin_lock_bh(&priv->vif_lock);
@@ -262,9 +253,13 @@ static int mwl_mac80211_config(struct ieee80211_hw *hw,
if (conf->chandef.chan->band == IEEE80211_BAND_2GHZ) {
mwl_fwcmd_set_apmode(hw, AP_MODE_2_4GHZ_11AC_MIXED);
+ mwl_fwcmd_set_linkadapt_cs_mode(hw,
+ LINK_CS_STATE_CONSERV);
rate = mwl_rates_24[0].hw_value;
} else if (conf->chandef.chan->band == IEEE80211_BAND_5GHZ) {
mwl_fwcmd_set_apmode(hw, AP_MODE_11AC);
+ mwl_fwcmd_set_linkadapt_cs_mode(hw,
+ LINK_CS_STATE_AUTO);
rate = mwl_rates_50[0].hw_value;
}
@@ -496,34 +491,16 @@ static int mwl_mac80211_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_sta *sta)
{
struct mwl_priv *priv = hw->priv;
- struct mwl_sta *sta_info;
- int num;
- struct sk_buff *skb, *tmp;
- struct ieee80211_tx_info *tx_info;
- struct mwl_tx_ctrl *tx_ctrl;
int rc;
+ struct mwl_sta *sta_info = mwl_dev_get_sta(sta);
- sta_info = mwl_dev_get_sta(sta);
+ mwl_tx_del_sta_amsdu_pkts(sta);
- for (num = 1; num < SYSADPT_NUM_OF_DESC_DATA; num++) {
- spin_lock_bh(&priv->txq[num].lock);
- skb_queue_walk_safe(&priv->txq[num], skb, tmp) {
- tx_info = IEEE80211_SKB_CB(skb);
- tx_ctrl = (struct mwl_tx_ctrl *)&tx_info->status;
- if (tx_ctrl->sta == sta) {
- __skb_unlink(skb, &priv->txq[num]);
- dev_kfree_skb_any(skb);
- }
- }
- spin_unlock_bh(&priv->txq[num].lock);
- }
+ spin_lock_bh(&priv->stream_lock);
+ mwl_fwcmd_del_sta_streams(hw, sta);
+ spin_unlock_bh(&priv->stream_lock);
- spin_lock_bh(&sta_info->amsdu_lock);
- for (num = 0; num < SYSADPT_TX_WMM_QUEUES; num++) {
- if (!sta_info->amsdu_ctrl.frag[num].skb)
- dev_kfree_skb_any(sta_info->amsdu_ctrl.frag[num].skb);
- }
- spin_unlock_bh(&sta_info->amsdu_lock);
+ mwl_tx_del_pkts_via_sta(hw, sta);
rc = mwl_fwcmd_set_new_stn_del(hw, vif, sta->addr);
@@ -542,7 +519,8 @@ static int mwl_mac80211_conf_tx(struct ieee80211_hw *hw,
struct mwl_priv *priv = hw->priv;
int rc = 0;
- BUG_ON(queue > SYSADPT_TX_WMM_QUEUES - 1);
+ if (WARN_ON(queue > SYSADPT_TX_WMM_QUEUES - 1))
+ return -EINVAL;
memcpy(&priv->wmm_params[queue], params, sizeof(*params));
@@ -570,7 +548,7 @@ static int mwl_mac80211_get_stats(struct ieee80211_hw *hw,
static int mwl_mac80211_get_survey(struct ieee80211_hw *hw,
int idx,
- struct survey_info *survey)
+ struct survey_info *survey)
{
struct mwl_priv *priv = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
@@ -591,7 +569,7 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u16 tid, u16 *ssn, u8 buf_size)
{
- int i, rc = 0;
+ int rc = 0;
struct mwl_priv *priv = hw->priv;
struct mwl_ampdu_stream *stream;
u8 *addr = sta->addr, idx;
@@ -639,30 +617,23 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
/* Release the lock before we do the time consuming stuff */
spin_unlock_bh(&priv->stream_lock);
- for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) {
- /* Check if link is still valid */
- if (!sta_info->is_ampdu_allowed) {
- spin_lock_bh(&priv->stream_lock);
- mwl_fwcmd_remove_stream(hw, stream);
- spin_unlock_bh(&priv->stream_lock);
- wiphy_warn(hw->wiphy,
- "link is no valid now\n");
- return -EBUSY;
- }
-
- rc = mwl_fwcmd_check_ba(hw, stream, vif);
-
- if (!rc)
- break;
-
- mdelay(1000);
+ /* Check if link is still valid */
+ if (!sta_info->is_ampdu_allowed) {
+ spin_lock_bh(&priv->stream_lock);
+ mwl_fwcmd_remove_stream(hw, stream);
+ spin_unlock_bh(&priv->stream_lock);
+ wiphy_warn(hw->wiphy,
+ "link is not valid now\n");
+ return -EBUSY;
}
+ rc = mwl_fwcmd_check_ba(hw, stream, vif);
spin_lock_bh(&priv->stream_lock);
if (rc) {
mwl_fwcmd_remove_stream(hw, stream);
- wiphy_err(hw->wiphy, "error code: %d\n", rc);
+ wiphy_err(hw->wiphy,
+ "ampdu start error code: %d\n", rc);
rc = -EBUSY;
break;
}
@@ -674,6 +645,7 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
if (stream) {
if (stream->state == AMPDU_STREAM_ACTIVE) {
+ mwl_tx_del_ampdu_pkts(hw, sta, tid);
idx = stream->idx;
spin_unlock_bh(&priv->stream_lock);
mwl_fwcmd_destroy_ba(hw, idx);
@@ -686,7 +658,10 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
- BUG_ON(stream->state != AMPDU_STREAM_IN_PROGRESS);
+ if (WARN_ON(stream->state != AMPDU_STREAM_IN_PROGRESS)) {
+ rc = -EPERM;
+ break;
+ }
spin_unlock_bh(&priv->stream_lock);
rc = mwl_fwcmd_create_ba(hw, stream, buf_size, vif);
spin_lock_bh(&priv->stream_lock);
@@ -699,10 +674,13 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
mwl_fwcmd_destroy_ba(hw, idx);
spin_lock_bh(&priv->stream_lock);
mwl_fwcmd_remove_stream(hw, stream);
+ wiphy_err(hw->wiphy,
+ "ampdu operation error code: %d\n", rc);
}
break;
default:
rc = -ENOTSUPP;
+ break;
}
spin_unlock_bh(&priv->stream_lock);
diff --git a/main.c b/main.c
index 667c231..5a000c0 100644
--- a/main.c
+++ b/main.c
@@ -27,11 +27,12 @@
#include "tx.h"
#include "rx.h"
#include "isr.h"
+#ifdef CONFIG_DEBUG_FS
+#include "debugfs.h"
+#endif
#define MWL_DESC "Marvell 802.11ac Wireless Network Driver"
#define MWL_DEV_NAME "Marvell 802.11ac Adapter"
-#define MWL_DRV_NAME KBUILD_MODNAME
-#define MWL_DRV_VERSION "10.3.0.8"
#define FILE_PATH_LEN 64
#define CMD_BUF_SIZE 0x4000
@@ -142,131 +143,59 @@ static const struct ieee80211_iface_combination ap_if_comb = {
static int mwl_alloc_pci_resource(struct mwl_priv *priv)
{
- struct pci_dev *pdev;
- u32 phys_addr = 0;
- u32 flags;
- void __iomem *phys_addr1[2];
- void __iomem *phys_addr2[2];
-
- pdev = priv->pdev;
-
- phys_addr = pci_resource_start(pdev, 0);
- flags = pci_resource_flags(pdev, 0);
+ struct pci_dev *pdev = priv->pdev;
+ void __iomem *addr;
priv->next_bar_num = 1; /* 32-bit */
-
- if (flags & 0x04)
+ if (pci_resource_flags(pdev, 0) & 0x04)
priv->next_bar_num = 2; /* 64-bit */
- if (!request_mem_region(phys_addr, pci_resource_len(pdev, 0),
- MWL_DRV_NAME)) {
+ addr = devm_ioremap_resource(&pdev->dev, &pdev->resource[0]);
+ if (IS_ERR(addr)) {
wiphy_err(priv->hw->wiphy,
"%s: cannot reserve PCI memory region 0\n",
MWL_DRV_NAME);
- goto err_reserve_mem_region_bar0;
+ goto err;
}
-
- phys_addr1[0] = ioremap(phys_addr, pci_resource_len(pdev, 0));
- phys_addr1[1] = NULL;
-
- priv->iobase0 = phys_addr1[0];
- if (!priv->iobase0) {
- wiphy_err(priv->hw->wiphy,
- "%s: cannot remap PCI memory region 0\n",
- MWL_DRV_NAME);
- goto err_release_mem_region_bar0;
- }
-
+ priv->iobase0 = addr;
wiphy_debug(priv->hw->wiphy, "priv->iobase0 = %p\n", priv->iobase0);
- phys_addr = pci_resource_start(pdev, priv->next_bar_num);
-
- if (!request_mem_region(phys_addr,
- pci_resource_len(pdev, priv->next_bar_num),
- MWL_DRV_NAME)) {
+ addr = devm_ioremap_resource(&pdev->dev,
+ &pdev->resource[priv->next_bar_num]);
+ if (IS_ERR(addr)) {
wiphy_err(priv->hw->wiphy,
"%s: cannot reserve PCI memory region 1\n",
MWL_DRV_NAME);
- goto err_iounmap_iobase0;
- }
-
- phys_addr2[0] = ioremap(phys_addr,
- pci_resource_len(pdev, priv->next_bar_num));
- phys_addr2[1] = NULL;
- priv->iobase1 = phys_addr2[0];
-
- if (!priv->iobase1) {
- wiphy_err(priv->hw->wiphy,
- "%s: cannot remap PCI memory region 1\n",
- MWL_DRV_NAME);
- goto err_release_mem_region_bar1;
+ goto err;
}
-
+ priv->iobase1 = addr;
wiphy_debug(priv->hw->wiphy, "priv->iobase1 = %p\n", priv->iobase1);
priv->pcmd_buf =
- (unsigned short *)dma_alloc_coherent(&priv->pdev->dev,
- CMD_BUF_SIZE,
- &priv->pphys_cmd_buf,
- GFP_KERNEL);
-
+ (unsigned short *)dmam_alloc_coherent(&priv->pdev->dev,
+ CMD_BUF_SIZE,
+ &priv->pphys_cmd_buf,
+ GFP_KERNEL);
if (!priv->pcmd_buf) {
wiphy_err(priv->hw->wiphy,
"%s: cannot alloc memory for command buffer\n",
MWL_DRV_NAME);
- goto err_iounmap_iobase1;
+ goto err;
}
-
wiphy_debug(priv->hw->wiphy,
"priv->pcmd_buf = %p priv->pphys_cmd_buf = %p\n",
priv->pcmd_buf,
(void *)priv->pphys_cmd_buf);
-
memset(priv->pcmd_buf, 0x00, CMD_BUF_SIZE);
return 0;
-err_iounmap_iobase1:
-
- iounmap(priv->iobase1);
-
-err_release_mem_region_bar1:
-
- release_mem_region(pci_resource_start(pdev, 1),
- pci_resource_len(pdev, 1));
-
-err_iounmap_iobase0:
-
- iounmap(priv->iobase0);
-
-err_release_mem_region_bar0:
-
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
-
-err_reserve_mem_region_bar0:
-
+err:
wiphy_err(priv->hw->wiphy, "pci alloc fail\n");
return -EIO;
}
-static void mwl_free_pci_resource(struct mwl_priv *priv)
-{
- struct pci_dev *pdev;
-
- pdev = priv->pdev;
-
- iounmap(priv->iobase0);
- iounmap(priv->iobase1);
- release_mem_region(pci_resource_start(pdev, priv->next_bar_num),
- pci_resource_len(pdev, priv->next_bar_num));
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- dma_free_coherent(&priv->pdev->dev, CMD_BUF_SIZE,
- priv->pcmd_buf, priv->pphys_cmd_buf);
-}
-
static int mwl_init_firmware(struct mwl_priv *priv, const char *fw_name)
{
struct pci_dev *pdev;
@@ -465,7 +394,11 @@ static void mwl_set_ht_caps(struct mwl_priv *priv,
band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+#else
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+#endif
band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
@@ -567,12 +500,21 @@ static int mwl_wl_init(struct mwl_priv *priv)
hw->queues = SYSADPT_TX_WMM_QUEUES;
/* Set rssi values to dBm */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL;
+#else
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+#endif
- /* Ask mac80211 to not to trigger PS mode
+ /* Ask mac80211 not to trigger PS mode
* based on PM bit of incoming frames.
*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
hw->flags |= IEEE80211_HW_AP_LINK_PS;
+#else
+ ieee80211_hw_set(hw, AP_LINK_PS);
+#endif
hw->vif_data_size = sizeof(struct mwl_vif);
hw->sta_data_size = sizeof(struct mwl_sta);
@@ -607,6 +549,7 @@ static int mwl_wl_init(struct mwl_priv *priv)
priv->is_qe_schedule = false;
spin_lock_init(&priv->tx_desc_lock);
+ spin_lock_init(&priv->rx_desc_lock);
spin_lock_init(&priv->fwcmd_lock);
spin_lock_init(&priv->vif_lock);
spin_lock_init(&priv->sta_lock);
@@ -822,6 +765,10 @@ static int mwl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
else
wiphy_info(priv->hw->wiphy, "RX: unknown\n");
+#ifdef CONFIG_DEBUG_FS
+ mwl_debugfs_init(hw);
+#endif
+
return rc;
err_wl_init:
@@ -852,10 +799,13 @@ static void mwl_remove(struct pci_dev *pdev)
priv = hw->priv;
mwl_wl_deinit(priv);
- mwl_free_pci_resource(priv);
pci_set_drvdata(pdev, NULL);
ieee80211_free_hw(hw);
pci_disable_device(pdev);
+
+#ifdef CONFIG_DEBUG_FS
+ mwl_debugfs_remove(hw);
+#endif
}
static struct pci_driver mwl_pci_driver = {
diff --git a/rx.c b/rx.c
index 3390c5d..210269b 100644
--- a/rx.c
+++ b/rx.c
@@ -15,6 +15,7 @@
/* Description: This file implements receive related functions. */
+#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include "sysadpt.h"
@@ -288,7 +289,7 @@ static inline struct mwl_vif *mwl_rx_find_vif_bss(struct mwl_priv *priv,
spin_lock_bh(&priv->vif_lock);
list_for_each_entry(mwl_vif, &priv->vif_list, list) {
- if (memcmp(bssid, mwl_vif->bssid, ETH_ALEN) == 0) {
+ if (ether_addr_equal(bssid, mwl_vif->bssid)) {
spin_unlock_bh(&priv->vif_lock);
return mwl_vif;
}
@@ -399,6 +400,7 @@ void mwl_rx_recv(unsigned long data)
struct ieee80211_hdr *wh;
u32 status_mask;
+ spin_lock(&priv->rx_desc_lock);
desc = &priv->desc_data[0];
curr_hndl = desc->pnext_rx_hndl;
@@ -409,8 +411,8 @@ void mwl_rx_recv(unsigned long data)
priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK);
priv->is_rx_schedule = false;
-
wiphy_warn(hw->wiphy, "busy or no receiving packets\n");
+ spin_unlock(&priv->rx_desc_lock);
return;
}
@@ -501,4 +503,6 @@ out:
priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK);
priv->is_rx_schedule = false;
+
+ spin_unlock(&priv->rx_desc_lock);
}
diff --git a/sysadpt.h b/sysadpt.h
index bf8f3bd..0f6ab4f 100644
--- a/sysadpt.h
+++ b/sysadpt.h
@@ -40,7 +40,9 @@
#define SYSADPT_MAX_NUM_TX_DESC 256
-#define SYSADPT_TX_QUEUE_LIMIT 1024
+#define SYSADPT_TX_QUEUE_LIMIT (3 * SYSADPT_MAX_NUM_TX_DESC)
+
+#define SYSADPT_TX_WAKE_Q_THRESHOLD (2 * SYSADPT_MAX_NUM_TX_DESC)
#define SYSADPT_DELAY_FREE_Q_LIMIT SYSADPT_MAX_NUM_TX_DESC
diff --git a/tx.c b/tx.c
index 7687e38..1db6b71 100644
--- a/tx.c
+++ b/tx.c
@@ -324,8 +324,6 @@ static inline void mwl_tx_insert_ccmp_hdr(u8 *pccmp_hdr,
static inline int mwl_tx_tid_queue_mapping(u8 tid)
{
- BUG_ON(tid > 7);
-
switch (tid) {
case 0:
case 3:
@@ -351,7 +349,8 @@ static inline void mwl_tx_count_packet(struct ieee80211_sta *sta, u8 tid)
struct mwl_sta *sta_info;
struct mwl_tx_info *tx_stats;
- BUG_ON(tid >= SYSADPT_MAX_TID);
+ if (WARN_ON(tid >= SYSADPT_MAX_TID))
+ return;
sta_info = mwl_dev_get_sta(sta);
@@ -410,7 +409,8 @@ static inline void mwl_tx_skb(struct mwl_priv *priv, int desc_num,
struct ieee80211_hdr *wh;
dma_addr_t dma;
- BUG_ON(!tx_skb);
+ if (WARN_ON(!tx_skb))
+ return;
tx_info = IEEE80211_SKB_CB(tx_skb);
tx_ctrl = (struct mwl_tx_ctrl *)&tx_info->status;
@@ -490,10 +490,13 @@ static inline void mwl_tx_skb(struct mwl_priv *priv, int desc_num,
static inline struct sk_buff *mwl_tx_do_amsdu(struct mwl_priv *priv,
int desc_num,
struct sk_buff *tx_skb,
- struct mwl_tx_ctrl *tx_ctrl)
+ struct ieee80211_tx_info *tx_info)
{
struct ieee80211_sta *sta;
struct mwl_sta *sta_info;
+ struct mwl_tx_ctrl *tx_ctrl = (struct mwl_tx_ctrl *)&tx_info->status;
+ struct ieee80211_tx_info *amsdu_info;
+ struct sk_buff_head *amsdu_pkts;
struct mwl_amsdu_frag *amsdu;
int amsdu_allow_size;
struct ieee80211_hdr *wh;
@@ -553,18 +556,22 @@ static inline struct sk_buff *mwl_tx_do_amsdu(struct mwl_priv *priv,
if (amsdu->num == 0) {
struct sk_buff *newskb;
- struct ieee80211_tx_info *tx_info;
+ amsdu_pkts = (struct sk_buff_head *)
+ kmalloc(sizeof(*amsdu_pkts), GFP_KERNEL);
+ if (!amsdu_pkts) {
+ spin_unlock_bh(&sta_info->amsdu_lock);
+ return tx_skb;
+ }
newskb = dev_alloc_skb(amsdu_allow_size +
SYSADPT_MIN_BYTES_HEADROOM);
-
- if (newskb == NULL) {
+ if (!newskb) {
spin_unlock_bh(&sta_info->amsdu_lock);
+ kfree(amsdu_pkts);
return tx_skb;
}
data = newskb->data;
-
memcpy(data, tx_skb->data, wh_len);
ether_addr_copy(data + wh_len, ieee80211_get_DA(wh));
ether_addr_copy(data + wh_len + ETH_ALEN, ieee80211_get_SA(wh));
@@ -574,8 +581,11 @@ static inline struct sk_buff *mwl_tx_do_amsdu(struct mwl_priv *priv,
skb_put(newskb, tx_skb->len + ETH_HLEN);
tx_ctrl->qos_ctrl |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
- tx_info = IEEE80211_SKB_CB(newskb);
- memcpy(&tx_info->status, tx_ctrl, sizeof(*tx_ctrl));
+ amsdu_info = IEEE80211_SKB_CB(newskb);
+ memcpy(amsdu_info, tx_info, sizeof(*tx_info));
+ skb_queue_head_init(amsdu_pkts);
+ ((struct mwl_tx_ctrl *)&amsdu_info->status)->amsdu_pkts =
+ (void *)amsdu_pkts;
amsdu->skb = newskb;
} else {
amsdu->cur_pos += amsdu->pad;
@@ -588,12 +598,15 @@ static inline struct sk_buff *mwl_tx_do_amsdu(struct mwl_priv *priv,
memcpy(data + ETH_HLEN, tx_skb->data + wh_len, len);
skb_put(amsdu->skb, len + ETH_HLEN + amsdu->pad);
+ amsdu_info = IEEE80211_SKB_CB(amsdu->skb);
+ amsdu_pkts = (struct sk_buff_head *)
+ ((struct mwl_tx_ctrl *)&amsdu_info->status)->amsdu_pkts;
}
amsdu->num++;
amsdu->pad = ((len + ETH_HLEN) % 4) ? (4 - (len + ETH_HLEN) % 4) : 0;
amsdu->cur_pos = amsdu->skb->data + amsdu->skb->len;
- dev_kfree_skb_any(tx_skb);
+ skb_queue_tail(amsdu_pkts, tx_skb);
if (amsdu->num > SYSADPT_AMSDU_PACKET_THRESHOLD) {
amsdu->num = 0;
@@ -609,7 +622,7 @@ static inline struct sk_buff *mwl_tx_do_amsdu(struct mwl_priv *priv,
static inline void mwl_tx_skbs(struct ieee80211_hw *hw)
{
struct mwl_priv *priv = hw->priv;
- int num = SYSADPT_NUM_OF_DESC_DATA;
+ int num = SYSADPT_TX_WMM_QUEUES;
struct sk_buff *tx_skb;
spin_lock_bh(&priv->tx_desc_lock);
@@ -628,16 +641,92 @@ static inline void mwl_tx_skbs(struct ieee80211_hw *hw)
if ((tx_skb->protocol != cpu_to_be16(ETH_P_PAE)) &&
(tx_ctrl->tx_priority >= SYSADPT_TX_WMM_QUEUES)) {
tx_skb = mwl_tx_do_amsdu(priv, num,
- tx_skb, tx_ctrl);
+ tx_skb, tx_info);
}
if (tx_skb)
mwl_tx_skb(priv, num, tx_skb);
}
+
+ if (skb_queue_len(&priv->txq[num]) <
+ SYSADPT_TX_WAKE_Q_THRESHOLD) {
+ int queue;
+
+ queue = SYSADPT_TX_WMM_QUEUES - num - 1;
+ if (ieee80211_queue_stopped(hw, queue))
+ ieee80211_wake_queue(hw, queue);
+ }
}
spin_unlock_bh(&priv->tx_desc_lock);
}
+static inline void mwl_tx_prepare_info(struct ieee80211_hw *hw, u32 rate,
+ struct ieee80211_tx_info *info)
+{
+ u32 format, bandwidth, short_gi, rate_id;
+
+ ieee80211_tx_info_clear_status(info);
+
+ info->status.rates[0].idx = -1;
+ info->status.rates[0].count = 0;
+ info->status.rates[0].flags = 0;
+
+ if (rate) {
+ /* Prepare rate information */
+ format = rate & MWL_TX_RATE_FORMAT_MASK;
+ bandwidth =
+ (rate & MWL_TX_RATE_BANDWIDTH_MASK) >>
+ MWL_TX_RATE_BANDWIDTH_SHIFT;
+ short_gi = (rate & MWL_TX_RATE_SHORTGI_MASK) >>
+ MWL_TX_RATE_SHORTGI_SHIFT;
+ rate_id = (rate & MWL_TX_RATE_RATEIDMCS_MASK) >>
+ MWL_TX_RATE_RATEIDMCS_SHIFT;
+
+ info->status.rates[0].idx = rate_id;
+ if (format == TX_RATE_FORMAT_LEGACY) {
+ if (hw->conf.chandef.chan->hw_value >
+ BAND_24_CHANNEL_NUM) {
+ info->status.rates[0].idx -= 5;
+ }
+ }
+ if (format == TX_RATE_FORMAT_11N)
+ info->status.rates[0].flags |=
+ IEEE80211_TX_RC_MCS;
+ if (format == TX_RATE_FORMAT_11AC)
+ info->status.rates[0].flags |=
+ IEEE80211_TX_RC_VHT_MCS;
+ if (bandwidth == TX_RATE_BANDWIDTH_40)
+ info->status.rates[0].flags |=
+ IEEE80211_TX_RC_40_MHZ_WIDTH;
+ if (bandwidth == TX_RATE_BANDWIDTH_80)
+ info->status.rates[0].flags |=
+ IEEE80211_TX_RC_80_MHZ_WIDTH;
+ if (short_gi == TX_RATE_INFO_SHORT_GI)
+ info->status.rates[0].flags |=
+ IEEE80211_TX_RC_SHORT_GI;
+ info->status.rates[0].count = 1;
+ info->status.rates[1].idx = -1;
+ }
+}
+
+static inline void mwl_tx_ack_amsdu_pkts(struct ieee80211_hw *hw, u32 rate,
+ struct sk_buff_head *amsdu_pkts)
+{
+ struct sk_buff *amsdu_pkt;
+ struct ieee80211_tx_info *info;
+
+ while (skb_queue_len(amsdu_pkts) > 0) {
+ amsdu_pkt = skb_dequeue(amsdu_pkts);
+ info = IEEE80211_SKB_CB(amsdu_pkt);
+ mwl_tx_prepare_info(hw, rate, info);
+ info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ ieee80211_tx_status(hw, amsdu_pkt);
+ }
+
+ kfree(amsdu_pkts);
+}
+
int mwl_tx_init(struct ieee80211_hw *hw)
{
struct mwl_priv *priv = hw->priv;
@@ -755,7 +844,7 @@ void mwl_tx_xmit(struct ieee80211_hw *hw,
*/
if (mgmtframe) {
u16 capab;
-
+
if (unlikely(ieee80211_is_action(wh->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
mgmt->u.action.u.addba_req.action_code ==
@@ -788,7 +877,12 @@ void mwl_tx_xmit(struct ieee80211_hw *hw,
if (stream) {
if (stream->state == AMPDU_STREAM_ACTIVE) {
- WARN_ON(!(qos & MWL_QOS_ACK_POLICY_BLOCKACK));
+ if (WARN_ON(!(qos &
+ MWL_QOS_ACK_POLICY_BLOCKACK))) {
+ spin_unlock_bh(&priv->stream_lock);
+ dev_kfree_skb_any(skb);
+ return;
+ }
txpriority =
(SYSADPT_TX_WMM_QUEUES + stream->idx) %
@@ -821,11 +915,6 @@ void mwl_tx_xmit(struct ieee80211_hw *hw,
return;
}
} else {
- /* Defer calling mwl_fwcmd_start_stream so that the current
- * skb can go out before the ADDBA request. This
- * prevents sequence number mismatch at the recipient
- * as described above.
- */
if (mwl_fwcmd_ampdu_allowed(sta, tid)) {
stream = mwl_fwcmd_add_stream(hw, sta, tid);
@@ -841,18 +930,19 @@ void mwl_tx_xmit(struct ieee80211_hw *hw,
}
tx_ctrl = (struct mwl_tx_ctrl *)&tx_info->status;
+ tx_ctrl->vif = (void *)tx_info->control.vif;
+ tx_ctrl->sta = (void *)sta;
+ tx_ctrl->k_conf = (void *)k_conf;
+ tx_ctrl->amsdu_pkts = NULL;
tx_ctrl->tx_priority = txpriority;
- tx_ctrl->qos_ctrl = qos;
tx_ctrl->type = (mgmtframe ? IEEE_TYPE_MANAGEMENT : IEEE_TYPE_DATA);
+ tx_ctrl->qos_ctrl = qos;
tx_ctrl->xmit_control = xmitcontrol;
- tx_ctrl->sta = (void *)sta;
- tx_ctrl->vif = (void *)tx_info->control.vif;
- tx_ctrl->k_conf = (void *)k_conf;
if (skb_queue_len(&priv->txq[index]) > priv->txq_limit)
- dev_kfree_skb_any(skb);
- else
- skb_queue_tail(&priv->txq[index], skb);
+ ieee80211_stop_queue(hw, SYSADPT_TX_WMM_QUEUES - index - 1);
+
+ skb_queue_tail(&priv->txq[index], skb);
mwl_tx_skbs(hw);
@@ -865,6 +955,115 @@ void mwl_tx_xmit(struct ieee80211_hw *hw,
}
}
+void mwl_tx_del_pkts_via_vif(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct mwl_priv *priv = hw->priv;
+ int num;
+ struct sk_buff *skb, *tmp;
+ struct ieee80211_tx_info *tx_info;
+ struct mwl_tx_ctrl *tx_ctrl;
+ struct sk_buff_head *amsdu_pkts;
+
+ for (num = 1; num < SYSADPT_NUM_OF_DESC_DATA; num++) {
+ spin_lock_bh(&priv->txq[num].lock);
+ skb_queue_walk_safe(&priv->txq[num], skb, tmp) {
+ tx_info = IEEE80211_SKB_CB(skb);
+ tx_ctrl = (struct mwl_tx_ctrl *)&tx_info->status;
+ if (tx_ctrl->vif == vif) {
+ amsdu_pkts = (struct sk_buff_head *)
+ tx_ctrl->amsdu_pkts;
+ if (amsdu_pkts) {
+ skb_queue_purge(amsdu_pkts);
+ kfree(amsdu_pkts);
+ }
+ __skb_unlink(skb, &priv->txq[num]);
+ dev_kfree_skb_any(skb);
+ }
+ }
+ spin_unlock_bh(&priv->txq[num].lock);
+ }
+}
+
+void mwl_tx_del_pkts_via_sta(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta)
+{
+ struct mwl_priv *priv = hw->priv;
+ int num;
+ struct sk_buff *skb, *tmp;
+ struct ieee80211_tx_info *tx_info;
+ struct mwl_tx_ctrl *tx_ctrl;
+ struct sk_buff_head *amsdu_pkts;
+
+ for (num = 1; num < SYSADPT_NUM_OF_DESC_DATA; num++) {
+ spin_lock_bh(&priv->txq[num].lock);
+ skb_queue_walk_safe(&priv->txq[num], skb, tmp) {
+ tx_info = IEEE80211_SKB_CB(skb);
+ tx_ctrl = (struct mwl_tx_ctrl *)&tx_info->status;
+ if (tx_ctrl->sta == sta) {
+ amsdu_pkts = (struct sk_buff_head *)
+ tx_ctrl->amsdu_pkts;
+ if (amsdu_pkts) {
+ skb_queue_purge(amsdu_pkts);
+ kfree(amsdu_pkts);
+ }
+ __skb_unlink(skb, &priv->txq[num]);
+ dev_kfree_skb_any(skb);
+ }
+ }
+ spin_unlock_bh(&priv->txq[num].lock);
+ }
+}
+
+void mwl_tx_del_ampdu_pkts(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 tid)
+{
+ struct mwl_priv *priv = hw->priv;
+ struct mwl_sta *sta_info = mwl_dev_get_sta(sta);
+ int desc_num = SYSADPT_TX_WMM_QUEUES - tid - 1;
+ struct mwl_amsdu_frag *amsdu_frag;
+ struct sk_buff *skb, *tmp;
+ struct ieee80211_tx_info *tx_info;
+ struct mwl_tx_ctrl *tx_ctrl;
+ struct sk_buff_head *amsdu_pkts;
+
+ spin_lock_bh(&priv->txq[desc_num].lock);
+ skb_queue_walk_safe(&priv->txq[desc_num], skb, tmp) {
+ tx_info = IEEE80211_SKB_CB(skb);
+ tx_ctrl = (struct mwl_tx_ctrl *)&tx_info->status;
+ if (tx_ctrl->sta == sta) {
+ amsdu_pkts = (struct sk_buff_head *)
+ tx_ctrl->amsdu_pkts;
+ if (amsdu_pkts) {
+ skb_queue_purge(amsdu_pkts);
+ kfree(amsdu_pkts);
+ }
+ __skb_unlink(skb, &priv->txq[desc_num]);
+ dev_kfree_skb_any(skb);
+ }
+ }
+ spin_unlock_bh(&priv->txq[desc_num].lock);
+
+ spin_lock_bh(&sta_info->amsdu_lock);
+ amsdu_frag = &sta_info->amsdu_ctrl.frag[desc_num];
+ if (amsdu_frag->num) {
+ amsdu_frag->num = 0;
+ amsdu_frag->cur_pos = NULL;
+ if (amsdu_frag->skb) {
+ tx_info = IEEE80211_SKB_CB(amsdu_frag->skb);
+ tx_ctrl = (struct mwl_tx_ctrl *)&tx_info->status;
+ amsdu_pkts = (struct sk_buff_head *)
+ tx_ctrl->amsdu_pkts;
+ if (amsdu_pkts) {
+ skb_queue_purge(amsdu_pkts);
+ kfree(amsdu_pkts);
+ }
+ dev_kfree_skb_any(amsdu_frag->skb);
+ }
+ }
+ spin_unlock_bh(&sta_info->amsdu_lock);
+}
+
void mwl_tx_done(unsigned long data)
{
struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
@@ -874,13 +1073,15 @@ void mwl_tx_done(unsigned long data)
struct mwl_tx_hndl *tx_hndl;
struct mwl_tx_desc *tx_desc;
struct sk_buff *done_skb;
- u32 rate, format, bandwidth, short_gi, rate_id;
+ u32 rate;
struct mwl_dma_data *tr;
struct ieee80211_tx_info *info;
+ struct mwl_tx_ctrl *tx_ctrl;
+ struct sk_buff_head *amsdu_pkts;
int hdrlen;
spin_lock_bh(&priv->tx_desc_lock);
- for (num = 0; num < SYSADPT_NUM_OF_DESC_DATA; num++) {
+ for (num = 0; num < SYSADPT_TX_WMM_QUEUES; num++) {
desc = &priv->desc_data[num];
tx_hndl = desc->pstale_tx_hndl;
tx_desc = tx_hndl->pdesc;
@@ -901,69 +1102,40 @@ void mwl_tx_done(unsigned long data)
tx_hndl->psk_buff = NULL;
wmb(); /* memory barrier */
+ skb_get(done_skb);
+ skb_queue_tail(&priv->delay_q, done_skb);
+ if (skb_queue_len(&priv->delay_q) >
+ SYSADPT_DELAY_FREE_Q_LIMIT)
+ dev_kfree_skb_any(skb_dequeue(&priv->delay_q));
+
tr = (struct mwl_dma_data *)done_skb->data;
info = IEEE80211_SKB_CB(done_skb);
- ieee80211_tx_info_clear_status(info);
-
- info->status.rates[0].idx = -1;
- info->status.rates[0].count = 0;
- info->status.rates[0].flags = 0;
if (ieee80211_is_data(tr->wh.frame_control) ||
ieee80211_is_data_qos(tr->wh.frame_control)) {
- skb_get(done_skb);
- skb_queue_tail(&priv->delay_q, done_skb);
-
- if (skb_queue_len(&priv->delay_q) >
- SYSADPT_DELAY_FREE_Q_LIMIT)
- dev_kfree_skb_any(
- skb_dequeue(&priv->delay_q));
-
- /* Prepare rate information */
- format = rate & MWL_TX_RATE_FORMAT_MASK;
- bandwidth =
- (rate & MWL_TX_RATE_BANDWIDTH_MASK) >>
- MWL_TX_RATE_BANDWIDTH_SHIFT;
- short_gi = (rate & MWL_TX_RATE_SHORTGI_MASK) >>
- MWL_TX_RATE_SHORTGI_SHIFT;
- rate_id = (rate & MWL_TX_RATE_RATEIDMCS_MASK) >>
- MWL_TX_RATE_RATEIDMCS_SHIFT;
-
- info->status.rates[0].idx = rate_id;
- if (format == TX_RATE_FORMAT_LEGACY) {
- if (hw->conf.chandef.chan->hw_value >
- BAND_24_CHANNEL_NUM) {
- info->status.rates[0].idx -= 5;
- }
- }
- if (format == TX_RATE_FORMAT_11N)
- info->status.rates[0].flags |=
- IEEE80211_TX_RC_MCS;
- if (format == TX_RATE_FORMAT_11AC)
- info->status.rates[0].flags |=
- IEEE80211_TX_RC_VHT_MCS;
- if (bandwidth == TX_RATE_BANDWIDTH_40)
- info->status.rates[0].flags |=
- IEEE80211_TX_RC_40_MHZ_WIDTH;
- if (bandwidth == TX_RATE_BANDWIDTH_80)
- info->status.rates[0].flags |=
- IEEE80211_TX_RC_80_MHZ_WIDTH;
- if (short_gi == TX_RATE_INFO_SHORT_GI)
- info->status.rates[0].flags |=
- IEEE80211_TX_RC_SHORT_GI;
- info->status.rates[0].count = 1;
-
- info->status.rates[1].idx = -1;
+ tx_ctrl = (struct mwl_tx_ctrl *)&info->status;
+ amsdu_pkts = (struct sk_buff_head *)
+ tx_ctrl->amsdu_pkts;
+ if (amsdu_pkts) {
+ mwl_tx_ack_amsdu_pkts(hw, rate,
+ amsdu_pkts);
+ dev_kfree_skb_any(done_skb);
+ done_skb = NULL;
+ } else
+ mwl_tx_prepare_info(hw, rate, info);
+ } else
+ mwl_tx_prepare_info(hw, 0, info);
+
+ if (done_skb) {
+ /* Remove H/W dma header */
+ hdrlen = ieee80211_hdrlen(tr->wh.frame_control);
+ memmove(tr->data - hdrlen, &tr->wh, hdrlen);
+ skb_pull(done_skb, sizeof(*tr) - hdrlen);
+ info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ ieee80211_tx_status(hw, done_skb);
}
- /* Remove H/W dma header */
- hdrlen = ieee80211_hdrlen(tr->wh.frame_control);
- memmove(tr->data - hdrlen, &tr->wh, hdrlen);
- skb_pull(done_skb, sizeof(*tr) - hdrlen);
-
- info->flags |= IEEE80211_TX_STAT_ACK;
- ieee80211_tx_status(hw, done_skb);
-
tx_hndl = tx_hndl->pnext;
tx_desc = tx_hndl->pdesc;
priv->fw_desc_cnt[num]--;
@@ -996,33 +1168,65 @@ void mwl_tx_flush_amsdu(unsigned long data)
int i;
struct mwl_amsdu_frag *amsdu_frag;
- spin_lock_bh(&priv->sta_lock);
-
+ spin_lock(&priv->sta_lock);
list_for_each_entry(sta_info, &priv->sta_list, list) {
- spin_lock_bh(&sta_info->amsdu_lock);
+ spin_lock(&priv->tx_desc_lock);
+ spin_lock(&sta_info->amsdu_lock);
for (i = 0; i < SYSADPT_TX_WMM_QUEUES; i++) {
amsdu_frag = &sta_info->amsdu_ctrl.frag[i];
if (amsdu_frag->num) {
- if (jiffies > (amsdu_frag->jiffies + 1)) {
- spin_lock_bh(&priv->tx_desc_lock);
+ if (time_after(jiffies,
+ (amsdu_frag->jiffies + 1))) {
if (mwl_tx_available(priv, i)) {
- mwl_tx_skb(priv, i, amsdu_frag->skb);
+ mwl_tx_skb(priv, i,
+ amsdu_frag->skb);
amsdu_frag->num = 0;
amsdu_frag->cur_pos = NULL;
}
- spin_unlock_bh(&priv->tx_desc_lock);
}
}
}
- spin_unlock_bh(&sta_info->amsdu_lock);
+ spin_unlock(&sta_info->amsdu_lock);
+ spin_unlock(&priv->tx_desc_lock);
}
-
- spin_unlock_bh(&priv->sta_lock);
+ spin_unlock(&priv->sta_lock);
status_mask = readl(priv->iobase1 +
MACREG_REG_A2H_INTERRUPT_STATUS_MASK);
- writel(status_mask | MACREG_A2HRIC_BIT_QUEUE_EMPTY,
+ writel(status_mask | MACREG_A2HRIC_BIT_QUE_EMPTY,
priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK);
priv->is_qe_schedule = false;
}
+
+void mwl_tx_del_sta_amsdu_pkts(struct ieee80211_sta *sta)
+{
+ struct mwl_sta *sta_info = mwl_dev_get_sta(sta);
+ int num;
+ struct mwl_amsdu_frag *amsdu_frag;
+ struct ieee80211_tx_info *tx_info;
+ struct mwl_tx_ctrl *tx_ctrl;
+ struct sk_buff_head *amsdu_pkts;
+
+ spin_lock_bh(&sta_info->amsdu_lock);
+ for (num = 0; num < SYSADPT_TX_WMM_QUEUES; num++) {
+ amsdu_frag = &sta_info->amsdu_ctrl.frag[num];
+ if (amsdu_frag->num) {
+ amsdu_frag->num = 0;
+ amsdu_frag->cur_pos = NULL;
+ if (amsdu_frag->skb) {
+ tx_info = IEEE80211_SKB_CB(amsdu_frag->skb);
+ tx_ctrl = (struct mwl_tx_ctrl *)
+ &tx_info->status;
+ amsdu_pkts = (struct sk_buff_head *)
+ tx_ctrl->amsdu_pkts;
+ if (amsdu_pkts) {
+ skb_queue_purge(amsdu_pkts);
+ kfree(amsdu_pkts);
+ }
+ dev_kfree_skb_any(amsdu_frag->skb);
+ }
+ }
+ }
+ spin_unlock_bh(&sta_info->amsdu_lock);
+}
diff --git a/tx.h b/tx.h
index 0dafc80..ef1c7c5 100644
--- a/tx.h
+++ b/tx.h
@@ -23,7 +23,14 @@ void mwl_tx_deinit(struct ieee80211_hw *hw);
void mwl_tx_xmit(struct ieee80211_hw *hw,
struct ieee80211_tx_control *control,
struct sk_buff *skb);
+void mwl_tx_del_pkts_via_vif(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
+void mwl_tx_del_pkts_via_sta(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta);
+void mwl_tx_del_ampdu_pkts(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 tid);
void mwl_tx_done(unsigned long data);
void mwl_tx_flush_amsdu(unsigned long data);
+void mwl_tx_del_sta_amsdu_pkts(struct ieee80211_sta *sta);
#endif /* _tx_h_ */