diff options
author | David Lin <dlin@marvell.com> | 2015-11-05 16:44:14 +0800 |
---|---|---|
committer | David Lin <dlin@marvell.com> | 2015-11-05 16:47:33 +0800 |
commit | 716010d6cfbeb6deda156c6d18f159889ec33a82 (patch) | |
tree | 6af9feea489841a45d6ebd4bdf907c7a9a75c1bc | |
parent | 30e6b06de659f1d5e46d1dd3bf590caf3529bb65 (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.h | 7 | ||||
-rw-r--r-- | hostcmd.h | 2 | ||||
-rw-r--r-- | isr.c | 12 | ||||
-rw-r--r-- | mac80211.c | 104 | ||||
-rw-r--r-- | main.c | 224 | ||||
-rw-r--r-- | rx.c | 82 | ||||
-rw-r--r-- | sysadpt.h | 2 | ||||
-rw-r--r-- | tx.c | 33 |
8 files changed, 266 insertions, 200 deletions
@@ -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; @@ -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 */ @@ -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), @@ -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; @@ -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); @@ -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: @@ -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 @@ -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) |