summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dev.h7
-rw-r--r--hostcmd.h2
-rw-r--r--isr.c12
-rw-r--r--mac80211.c104
-rw-r--r--main.c228
-rw-r--r--rx.c91
-rw-r--r--sysadpt.h2
-rw-r--r--tx.c33
8 files changed, 276 insertions, 203 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..fb7ff27 100644
--- a/main.c
+++ b/main.c
@@ -147,111 +147,12 @@ static const struct ieee80211_iface_combination ap_if_comb = {
.n_limits = ARRAY_SIZE(ap_if_limits),
.max_interfaces = SYSADPT_NUM_OF_AP,
.num_different_channels = 1,
+ .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+ BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80),
};
-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 +265,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 +403,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 +573,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 +697,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..a7cf332 100644
--- a/rx.c
+++ b/rx.c
@@ -294,6 +294,7 @@ static inline void mwl_rx_enable_sta_amsdu(struct mwl_priv *priv,
drv_priv[0]);
if (ether_addr_equal(sta->addr, sta_addr)) {
sta_info->is_amsdu_allowed = true;
+ wiphy_dbg(priv->hw->wiphy, "enabling A-MSDU for %pM\n", sta_addr);
break;
}
}
@@ -338,6 +339,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,9 +575,11 @@ 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;
+ u16 capab;
mgmt = (struct ieee80211_mgmt *)prx_skb->data;
@@ -515,12 +588,24 @@ void mwl_rx_recv(unsigned long data)
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)
+ capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
+ wiphy_dbg(hw->wiphy, "%pM - addba_resp.capab=0x%hx\n",
+ mgmt->sa, capab);
+ if (capab & 1)
mwl_rx_enable_sta_amsdu(priv, mgmt->sa);
}
}
+ 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)