summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Lin <dlin@marvell.com>2015-11-05 16:44:14 +0800
committerDavid Lin <dlin@marvell.com>2015-11-05 16:47:33 +0800
commit716010d6cfbeb6deda156c6d18f159889ec33a82 (patch)
tree6af9feea489841a45d6ebd4bdf907c7a9a75c1bc
parent30e6b06de659f1d5e46d1dd3bf590caf3529bb65 (diff)
Commit mwlwifi driver 10.3.0.13.
1. Use periodical timer to flush AMSDU packets instead of queue empty interrupt to decrease generated interrupts. 2. Refine code related to ampdu action. Signed-off-by: David Lin <dlin@marvell.com>
-rw-r--r--dev.h7
-rw-r--r--hostcmd.h2
-rw-r--r--isr.c12
-rw-r--r--mac80211.c104
-rw-r--r--main.c224
-rw-r--r--rx.c82
-rw-r--r--sysadpt.h2
-rw-r--r--tx.c33
8 files changed, 266 insertions, 200 deletions
diff --git a/dev.h b/dev.h
index 10c9d0e..3f606fc 100644
--- a/dev.h
+++ b/dev.h
@@ -27,7 +27,7 @@
#include <net/mac80211.h>
#define MWL_DRV_NAME KBUILD_MODNAME
-#define MWL_DRV_VERSION "10.3.0.12"
+#define MWL_DRV_VERSION "10.3.0.13"
/* Map to 0x80000000 (Bus control) on BAR0 */
#define MACREG_REG_H2A_INTERRUPT_EVENTS 0x00000C18 /* (From host to ARM) */
@@ -76,7 +76,6 @@
MACREG_A2HRIC_BIT_RADAR_DETECT | \
MACREG_A2HRIC_BIT_CHAN_SWITCH | \
MACREG_A2HRIC_BIT_TX_WATCHDOG | \
- MACREG_A2HRIC_BIT_QUE_EMPTY | \
MACREG_A2HRIC_BA_WATCHDOG | \
MACREG_A2HRIC_CONSEC_TXFAIL)
@@ -320,12 +319,11 @@ struct mwl_priv {
struct tasklet_struct tx_task;
struct tasklet_struct rx_task;
- struct tasklet_struct qe_task;
int txq_limit;
bool is_tx_schedule;
int recv_limit;
bool is_rx_schedule;
- bool is_qe_schedule;
+ struct timer_list period_timer;
s8 noise; /* Most recently reported noise in dBm */
struct ieee80211_supported_band band_24;
struct ieee80211_channel channels_24[BAND_24_CHANNEL_NUM];
@@ -433,6 +431,7 @@ struct mwl_amsdu_ctrl {
struct mwl_sta {
struct list_head list;
+ bool is_mesh_node;
bool is_ampdu_allowed;
struct mwl_tx_info tx_stats[MWL_MAX_TID];
bool is_amsdu_allowed;
diff --git a/hostcmd.h b/hostcmd.h
index 8c03626..8f265a1 100644
--- a/hostcmd.h
+++ b/hostcmd.h
@@ -44,7 +44,7 @@
#define HOSTCMD_CMD_SET_MAC_ADDR 0x0202 /* per-vif */
#define HOSTCMD_CMD_SET_RATE_ADAPT_MODE 0x0203
#define HOSTCMD_CMD_GET_WATCHDOG_BITMAP 0x0205
-#define HOSTCMD_CMD_DEL_MAC_ADDR 0x0206 /* pre-vif */
+#define HOSTCMD_CMD_DEL_MAC_ADDR 0x0206 /* per-vif */
#define HOSTCMD_CMD_BSS_START 0x1100 /* per-vif */
#define HOSTCMD_CMD_AP_BEACON 0x1101 /* per-vif */
#define HOSTCMD_CMD_SET_NEW_STN 0x1111 /* per-vif */
diff --git a/isr.c b/isr.c
index 20b6088..e44f66c 100644
--- a/isr.c
+++ b/isr.c
@@ -66,18 +66,6 @@ irqreturn_t mwl_isr(int irq, void *dev_id)
}
}
- 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_QUE_EMPTY),
- int_status_mask);
- tasklet_schedule(&priv->qe_task);
- priv->is_qe_schedule = true;
- }
- }
-
if (int_status & MACREG_A2HRIC_BA_WATCHDOG) {
status = readl(int_status_mask);
writel((status & ~MACREG_A2HRIC_BA_WATCHDOG),
diff --git a/mac80211.c b/mac80211.c
index afce509..e8dca94 100644
--- a/mac80211.c
+++ b/mac80211.c
@@ -77,7 +77,9 @@ static int mwl_mac80211_start(struct ieee80211_hw *hw)
/* Enable TX reclaim and RX tasklets. */
tasklet_enable(&priv->tx_task);
tasklet_enable(&priv->rx_task);
- tasklet_enable(&priv->qe_task);
+
+ /* Enable periodical timer */
+ mod_timer(&priv->period_timer, jiffies);
/* Enable interrupts */
mwl_fwcmd_int_enable(hw);
@@ -111,7 +113,6 @@ fwcmd_fail:
mwl_fwcmd_int_disable(hw);
tasklet_disable(&priv->tx_task);
tasklet_disable(&priv->rx_task);
- tasklet_disable(&priv->qe_task);
return rc;
}
@@ -130,7 +131,6 @@ static void mwl_mac80211_stop(struct ieee80211_hw *hw)
/* Disable TX reclaim and RX tasklets. */
tasklet_disable(&priv->tx_task);
tasklet_disable(&priv->rx_task);
- tasklet_disable(&priv->qe_task);
/* Return all skbs to mac80211 */
mwl_tx_done((unsigned long)hw);
@@ -463,6 +463,8 @@ static int mwl_mac80211_sta_add(struct ieee80211_hw *hw,
sta_info = mwl_dev_get_sta(sta);
memset(sta_info, 0, sizeof(*sta_info));
+ if (vif->type == NL80211_IFTYPE_MESH_POINT)
+ sta_info->is_mesh_node = true;
if (sta->ht_cap.ht_supported) {
sta_info->is_ampdu_allowed = true;
sta_info->is_amsdu_allowed = false;
@@ -593,58 +595,33 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_RX_STOP:
break;
case IEEE80211_AMPDU_TX_START:
- /* By the time we get here the hw queues may contain outgoing
- * packets for this RA/TID that are not part of this BA
- * session. The hw will assign sequence numbers to these
- * packets as they go out. So if we query the hw for its next
- * sequence number and use that for the SSN here, it may end up
- * being wrong, which will lead to sequence number mismatch at
- * the recipient. To avoid this, we reset the sequence number
- * to O for the first MPDU in this BA stream.
- */
- *ssn = 0;
-
- if (!stream) {
- /* This means that somebody outside this driver called
- * ieee80211_start_tx_ba_session. This is unexpected
- * because we do our own rate control. Just warn and
- * move on.
- */
- stream = mwl_fwcmd_add_stream(hw, sta, tid);
+ if (!sta_info->is_ampdu_allowed) {
+ wiphy_warn(hw->wiphy, "ampdu not allowed\n");
+ rc = -EPERM;
+ break;
}
if (!stream) {
- wiphy_warn(hw->wiphy, "no stream found\n");
- rc = -EBUSY;
- break;
+ stream = mwl_fwcmd_add_stream(hw, sta, tid);
+ if (!stream) {
+ wiphy_warn(hw->wiphy, "no stream found\n");
+ rc = -EPERM;
+ break;
+ }
}
- stream->state = AMPDU_STREAM_IN_PROGRESS;
-
- /* Release the lock before we do the time consuming stuff */
spin_unlock_bh(&priv->stream_lock);
-
- /* 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,
"ampdu start error code: %d\n", rc);
- rc = -EBUSY;
+ rc = -EPERM;
break;
}
-
+ stream->state = AMPDU_STREAM_IN_PROGRESS;
+ *ssn = 0;
ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
@@ -660,30 +637,35 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
}
mwl_fwcmd_remove_stream(hw, stream);
- }
-
- ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
+ } else
+ rc = -EPERM;
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
- 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);
-
- if (!rc) {
- stream->state = AMPDU_STREAM_ACTIVE;
- } else {
- idx = stream->idx;
+ if (stream) {
+ if (WARN_ON(stream->state !=
+ AMPDU_STREAM_IN_PROGRESS)) {
+ rc = -EPERM;
+ break;
+ }
spin_unlock_bh(&priv->stream_lock);
- mwl_fwcmd_destroy_ba(hw, idx);
+ rc = mwl_fwcmd_create_ba(hw, stream, buf_size, vif);
spin_lock_bh(&priv->stream_lock);
- mwl_fwcmd_remove_stream(hw, stream);
- wiphy_err(hw->wiphy,
- "ampdu operation error code: %d\n", rc);
- }
+
+ if (!rc) {
+ stream->state = AMPDU_STREAM_ACTIVE;
+ } else {
+ idx = stream->idx;
+ spin_unlock_bh(&priv->stream_lock);
+ 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);
+ }
+ } else
+ rc = -EPERM;
break;
default:
rc = -ENOTSUPP;
diff --git a/main.c b/main.c
index 8c19474..962e566 100644
--- a/main.c
+++ b/main.c
@@ -149,109 +149,6 @@ static const struct ieee80211_iface_combination ap_if_comb = {
.num_different_channels = 1,
};
-static int mwl_alloc_pci_resource(struct mwl_priv *priv)
-{
- struct pci_dev *pdev = priv->pdev;
- void __iomem *addr;
-
- priv->next_bar_num = 1; /* 32-bit */
- if (pci_resource_flags(pdev, 0) & 0x04)
- priv->next_bar_num = 2; /* 64-bit */
-
- 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;
- }
- priv->iobase0 = addr;
- wiphy_debug(priv->hw->wiphy, "priv->iobase0 = %p\n", priv->iobase0);
-
- 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;
- }
- priv->iobase1 = addr;
- wiphy_debug(priv->hw->wiphy, "priv->iobase1 = %p\n", priv->iobase1);
-
- priv->pcmd_buf =
- (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;
- }
- 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:
- wiphy_err(priv->hw->wiphy, "pci alloc fail\n");
-
- return -EIO;
-}
-
-static int mwl_init_firmware(struct mwl_priv *priv, const char *fw_name)
-{
- struct pci_dev *pdev;
- int rc = 0;
-
- pdev = priv->pdev;
-
-#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",
- MWL_DRV_NAME, fw_name);
- goto err_load_fw;
- }
-
- rc = mwl_fwdl_download_firmware(priv->hw);
- if (rc) {
- wiphy_err(priv->hw->wiphy,
- "%s: cannot download firmware image <%s>\n",
- MWL_DRV_NAME, fw_name);
- goto err_download_fw;
- }
-
- return rc;
-
-err_download_fw:
-
-#ifdef CONFIG_SUPPORT_MFG
- if (priv->mfg_mode)
- mwl_mfg_release_firmware(priv);
- else
-#endif
- release_firmware(priv->fw_ucode);
-
-err_load_fw:
-
- wiphy_err(priv->hw->wiphy, "firmware init fail\n");
-
- return rc;
-}
-
static void mwl_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
@@ -364,6 +261,109 @@ static void mwl_reg_notifier(struct wiphy *wiphy,
#endif
}
+static int mwl_alloc_pci_resource(struct mwl_priv *priv)
+{
+ struct pci_dev *pdev = priv->pdev;
+ void __iomem *addr;
+
+ priv->next_bar_num = 1; /* 32-bit */
+ if (pci_resource_flags(pdev, 0) & 0x04)
+ priv->next_bar_num = 2; /* 64-bit */
+
+ 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;
+ }
+ priv->iobase0 = addr;
+ wiphy_debug(priv->hw->wiphy, "priv->iobase0 = %p\n", priv->iobase0);
+
+ 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;
+ }
+ priv->iobase1 = addr;
+ wiphy_debug(priv->hw->wiphy, "priv->iobase1 = %p\n", priv->iobase1);
+
+ priv->pcmd_buf =
+ (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;
+ }
+ 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:
+ wiphy_err(priv->hw->wiphy, "pci alloc fail\n");
+
+ return -EIO;
+}
+
+static int mwl_init_firmware(struct mwl_priv *priv, const char *fw_name)
+{
+ struct pci_dev *pdev;
+ int rc = 0;
+
+ pdev = priv->pdev;
+
+#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",
+ MWL_DRV_NAME, fw_name);
+ goto err_load_fw;
+ }
+
+ rc = mwl_fwdl_download_firmware(priv->hw);
+ if (rc) {
+ wiphy_err(priv->hw->wiphy,
+ "%s: cannot download firmware image <%s>\n",
+ MWL_DRV_NAME, fw_name);
+ goto err_download_fw;
+ }
+
+ return rc;
+
+err_download_fw:
+
+#ifdef CONFIG_SUPPORT_MFG
+ if (priv->mfg_mode)
+ mwl_mfg_release_firmware(priv);
+ else
+#endif
+ release_firmware(priv->fw_ucode);
+
+err_load_fw:
+
+ wiphy_err(priv->hw->wiphy, "firmware init fail\n");
+
+ return rc;
+}
+
static void mwl_process_of_dts(struct mwl_priv *priv)
{
#ifdef CONFIG_OF
@@ -399,6 +399,16 @@ static void mwl_process_of_dts(struct mwl_priv *priv)
#endif
}
+static void mwl_period_timer(unsigned long data)
+{
+ struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+ struct mwl_priv *priv = hw->priv;
+
+ mwl_tx_flush_amsdu(data);
+
+ mod_timer(&priv->period_timer, jiffies + 1);
+}
+
static void mwl_set_ht_caps(struct mwl_priv *priv,
struct ieee80211_supported_band *band)
{
@@ -559,14 +569,12 @@ static int mwl_wl_init(struct mwl_priv *priv)
tasklet_disable(&priv->tx_task);
tasklet_init(&priv->rx_task, (void *)mwl_rx_recv, (unsigned long)hw);
tasklet_disable(&priv->rx_task);
- tasklet_init(&priv->qe_task,
- (void *)mwl_tx_flush_amsdu, (unsigned long)hw);
- tasklet_disable(&priv->qe_task);
priv->txq_limit = SYSADPT_TX_QUEUE_LIMIT;
priv->is_tx_schedule = false;
priv->recv_limit = SYSADPT_RECEIVE_LIMIT;
priv->is_rx_schedule = false;
- priv->is_qe_schedule = false;
+
+ setup_timer(&priv->period_timer, mwl_period_timer, (unsigned long)hw);
spin_lock_init(&priv->tx_desc_lock);
spin_lock_init(&priv->rx_desc_lock);
@@ -685,7 +693,7 @@ static void mwl_wl_deinit(struct mwl_priv *priv)
ieee80211_unregister_hw(hw);
mwl_rx_deinit(hw);
mwl_tx_deinit(hw);
- tasklet_kill(&priv->qe_task);
+ del_timer_sync(&priv->period_timer);
tasklet_kill(&priv->rx_task);
tasklet_kill(&priv->tx_task);
cancel_work_sync(&priv->watchdog_ba_handle);
diff --git a/rx.c b/rx.c
index 3908eef..3ed9d59 100644
--- a/rx.c
+++ b/rx.c
@@ -338,6 +338,76 @@ static inline void mwl_rx_remove_dma_header(struct sk_buff *skb, __le16 qos)
skb_pull(skb, sizeof(*tr) - hdrlen);
}
+static inline bool mwl_rx_process_mesh_amsdu(struct mwl_priv *priv,
+ struct sk_buff *skb,
+ struct ieee80211_rx_status *status)
+{
+ struct ieee80211_hdr *wh;
+ struct mwl_sta *sta_info;
+ struct ieee80211_sta *sta;
+ u8 *qc;
+ int wh_len;
+ int len;
+ u8 pad;
+ u8 *data;
+ u16 frame_len;
+ struct sk_buff *newskb;
+
+ wh = (struct ieee80211_hdr *)skb->data;
+
+ 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, wh->addr2)) {
+ if (!sta_info->is_mesh_node) {
+ spin_unlock_bh(&priv->sta_lock);
+ return false;
+ }
+ }
+ }
+ spin_unlock_bh(&priv->sta_lock);
+
+ qc = ieee80211_get_qos_ctl(wh);
+ *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+
+ wh_len = ieee80211_hdrlen(wh->frame_control);
+ len = wh_len;
+ data = skb->data;
+
+ while (len < skb->len) {
+ frame_len = *(u8 *)(data + len + ETH_HLEN - 1) |
+ (*(u8 *)(data + len + ETH_HLEN - 2) << 8);
+
+ if ((len + ETH_HLEN + frame_len) > skb->len)
+ break;
+
+ newskb = dev_alloc_skb(wh_len + frame_len);
+ if (!newskb)
+ break;
+
+ ether_addr_copy(wh->addr3, data + len);
+ ether_addr_copy(wh->addr4, data + len + ETH_ALEN);
+ memcpy(newskb->data, wh, wh_len);
+ memcpy(newskb->data + wh_len, data + len + ETH_HLEN, frame_len);
+ skb_put(newskb, wh_len + frame_len);
+
+ pad = ((ETH_HLEN + frame_len) % 4) ?
+ (4 - (ETH_HLEN + frame_len) % 4) : 0;
+ len += (ETH_HLEN + frame_len + pad);
+ if (len < skb->len)
+ status->flag |= RX_FLAG_AMSDU_MORE;
+ else
+ status->flag &= ~RX_FLAG_AMSDU_MORE;
+ memcpy(IEEE80211_SKB_RXCB(newskb), status, sizeof(*status));
+ ieee80211_rx(priv->hw, newskb);
+ }
+
+ dev_kfree_skb_any(skb);
+
+ return true;
+}
+
static int mwl_rx_refill(struct mwl_priv *priv, struct mwl_rx_hndl *rx_hndl)
{
struct mwl_desc_data *desc;
@@ -504,6 +574,8 @@ 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);
+ wh = (struct ieee80211_hdr *)prx_skb->data;
+
if (ieee80211_is_mgmt(wh->frame_control)) {
struct ieee80211_mgmt *mgmt;
__le16 capab;
@@ -521,6 +593,16 @@ void mwl_rx_recv(unsigned long data)
}
}
+ if (ieee80211_is_data_qos(wh->frame_control) &&
+ ieee80211_has_a4(wh->frame_control)) {
+ u8 *qc = ieee80211_get_qos_ctl(wh);
+
+ if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT)
+ if (mwl_rx_process_mesh_amsdu(priv, prx_skb,
+ &status))
+ goto out;
+ }
+
memcpy(IEEE80211_SKB_RXCB(prx_skb), &status, sizeof(status));
ieee80211_rx(hw, prx_skb);
out:
diff --git a/sysadpt.h b/sysadpt.h
index 0f6ab4f..8a1706a 100644
--- a/sysadpt.h
+++ b/sysadpt.h
@@ -62,7 +62,7 @@
#define SYSADPT_AMSDU_8K_MAX_SIZE SYSADPT_AMSDU_FW_MAX_SIZE
-#define SYSADPT_AMSDU_ALLOW_SIZE 1540
+#define SYSADPT_AMSDU_ALLOW_SIZE 1600
#define SYSADPT_AMSDU_FLUSH_TIME 500
diff --git a/tx.c b/tx.c
index 9bd247b..0a98ef8 100644
--- a/tx.c
+++ b/tx.c
@@ -510,6 +510,10 @@ static inline struct sk_buff *mwl_tx_do_amsdu(struct mwl_priv *priv,
if (!sta_info->is_amsdu_allowed)
return tx_skb;
+ wh = (struct ieee80211_hdr *)tx_skb->data;
+ if (sta_info->is_mesh_node && is_multicast_ether_addr(wh->addr3))
+ return tx_skb;
+
if (sta_info->amsdu_ctrl.cap == MWL_AMSDU_SIZE_4K)
amsdu_allow_size = SYSADPT_AMSDU_4K_MAX_SIZE;
else if (sta_info->amsdu_ctrl.cap == MWL_AMSDU_SIZE_8K)
@@ -539,7 +543,6 @@ static inline struct sk_buff *mwl_tx_do_amsdu(struct mwl_priv *priv,
/* potential amsdu size, should add amsdu header 14 bytes +
* maximum padding 3.
*/
- wh = (struct ieee80211_hdr *)tx_skb->data;
wh_len = ieee80211_hdrlen(wh->frame_control);
len = tx_skb->len - wh_len + 17;
@@ -573,8 +576,15 @@ static inline struct sk_buff *mwl_tx_do_amsdu(struct mwl_priv *priv,
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));
+ if (sta_info->is_mesh_node) {
+ ether_addr_copy(data + wh_len, wh->addr3);
+ ether_addr_copy(data + wh_len + ETH_ALEN, wh->addr4);
+ } else {
+ ether_addr_copy(data + wh_len,
+ ieee80211_get_DA(wh));
+ ether_addr_copy(data + wh_len + ETH_ALEN,
+ ieee80211_get_SA(wh));
+ }
*(u8 *)(data + wh_len + ETH_HLEN - 1) = len & 0xff;
*(u8 *)(data + wh_len + ETH_HLEN - 2) = (len >> 8) & 0xff;
memcpy(data + wh_len + ETH_HLEN, tx_skb->data + wh_len, len);
@@ -591,8 +601,13 @@ static inline struct sk_buff *mwl_tx_do_amsdu(struct mwl_priv *priv,
amsdu->cur_pos += amsdu->pad;
data = amsdu->cur_pos;
- ether_addr_copy(data, ieee80211_get_DA(wh));
- ether_addr_copy(data + ETH_ALEN, ieee80211_get_SA(wh));
+ if (sta_info->is_mesh_node) {
+ ether_addr_copy(data, wh->addr3);
+ ether_addr_copy(data + ETH_ALEN, wh->addr4);
+ } else {
+ ether_addr_copy(data, ieee80211_get_DA(wh));
+ ether_addr_copy(data + ETH_ALEN, ieee80211_get_SA(wh));
+ }
*(u8 *)(data + ETH_HLEN - 1) = len & 0xff;
*(u8 *)(data + ETH_HLEN - 2) = (len >> 8) & 0xff;
memcpy(data + ETH_HLEN, tx_skb->data + wh_len, len);
@@ -1165,7 +1180,6 @@ void mwl_tx_flush_amsdu(unsigned long data)
{
struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
struct mwl_priv *priv = hw->priv;
- u32 status_mask;
struct mwl_sta *sta_info;
int i;
struct mwl_amsdu_frag *amsdu_frag;
@@ -1192,13 +1206,6 @@ void mwl_tx_flush_amsdu(unsigned long data)
spin_unlock(&priv->tx_desc_lock);
}
spin_unlock(&priv->sta_lock);
-
- status_mask = readl(priv->iobase1 +
- MACREG_REG_A2H_INTERRUPT_STATUS_MASK);
- 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)