* Re: Ath10k probe response error related to mac80211 commit.
From: Johannes Berg @ 2016-09-01 18:01 UTC (permalink / raw)
To: Ben Greear, linux-wireless@vger.kernel.org
In-Reply-To: <cf9852df-6d14-baf6-af0a-9cc78c448fde@candelatech.com>
> If someone has any idea of why this patch might trigger it, please
> let me know.
> I'll keep digging in the meantime...
>
> Revert "mac80211: don't advertise NL80211_FEATURE_FULL_AP_CLIENT_STATE"
>
With a sufficiently recent hostapd/wpa_supplicant, the patch will cause
a station entry to be added to the firmware before sending the
authentication frame.
Why, of all frames, probe response frames should be corrupted I don't
know - I could imagine auth/assoc replies being treated differently
since they are now with a station entry rather than without.
> This only breaks AP mode (station mode works fine).
It also has no impact on anything but AP mode, as even indicated by the
name of the flag :)
Anyway, I was pretty sure this was safe and it does help other drivers
to have the full state, but I guess you can make the driver opt out of
the flag again (just unset it before register_hw).
johannes
^ permalink raw reply
* Re: [PATCH v5] mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue.
From: Jason Andryuk @ 2016-09-02 2:48 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: make-wifi-fast, linux-wireless@vger.kernel.org
In-Reply-To: <20160901160312.31540-1-toke@toke.dk>
On Thu, Sep 1, 2016 at 12:03 PM, Toke H=C3=B8iland-J=C3=B8rgensen <toke@tok=
e.dk> wrote:
> @@ -1481,33 +1506,57 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee8=
0211_hw *hw,
> {
> struct ieee80211_local *local =3D hw_to_local(hw);
> struct txq_info *txqi =3D container_of(txq, struct txq_info, txq)=
;
> - struct ieee80211_hdr *hdr;
> struct sk_buff *skb =3D NULL;
> struct fq *fq =3D &local->fq;
> struct fq_tin *tin =3D &txqi->tin;
> + struct ieee80211_tx_info *info;
>
> spin_lock_bh(&fq->lock);
>
> if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags))
> goto out;
>
> +begin:
> skb =3D fq_tin_dequeue(fq, tin, fq_tin_dequeue_func);
> if (!skb)
> goto out;
>
> ieee80211_set_skb_vif(skb, txqi);
>
> - hdr =3D (struct ieee80211_hdr *)skb->data;
> - if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) {
> + info =3D IEEE80211_SKB_CB(skb);
> + if (txq->sta && info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT=
) {
> struct sta_info *sta =3D container_of(txq->sta, struct st=
a_info,
> sta);
> - struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(skb);
> + struct ieee80211_fast_tx *fast_tx;
>
> - hdr->seq_ctrl =3D ieee80211_tx_next_seq(sta, txq->tid);
> - if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
> - info->flags |=3D IEEE80211_TX_CTL_AMPDU;
> - else
> - info->flags &=3D ~IEEE80211_TX_CTL_AMPDU;
> + fast_tx =3D rcu_dereference(sta->fast_tx);
> + if (WARN_ON(!fast_tx)) {
> + /* lost the fast_tx pointer while the packet was =
queued */
> + ieee80211_free_txskb(hw, skb);
> + goto begin;
> + }
> + ieee80211_xmit_fast_finish(sta->sdata, sta, fast_tx, skb,=
false);
> + } else {
> + struct ieee80211_tx_data tx =3D { };
> +
> + __skb_queue_head_init(&tx.skbs);
> + tx.local =3D local;
> + if (txq->sta) {
> + struct sta_info *sta =3D container_of(txq->sta,
> + struct sta_in=
fo,
> + sta);
sta is unneeded give the assignment below?
Regards,
Jason
> + tx.sta =3D container_of(txq->sta, struct sta_info=
, sta);
> + tx.sdata =3D sta->sdata;
> + } else {
> + tx.sdata =3D vif_to_sdata(info->control.vif);
> + }
> +
> + __skb_queue_tail(&tx.skbs, skb);
> +
> + if (invoke_tx_handlers_late(&tx))
> + goto begin;
> +
> + __skb_unlink(skb, &tx.skbs);
> }
^ permalink raw reply
* [PATCH] ath10k: fix reporting channel survey data
From: Ashok Raj Nagarajan @ 2016-09-02 5:29 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, arnagara, Ashok Raj Nagarajan
When user requests for survey dump data, driver is providing wrong survey
information. This information we sent is the survey data that we have
collected during previous user request.
This issue occurs because we request survey dump for wrong channel. With
this change, we correctly display the correct and current survey
information to userspace.
Fixes: fa7937e3d5c2 ("ath10k: update bss channel survey information")
Signed-off-by: Ashok Raj Nagarajan <arnagara@qti.qualcomm.com>
---
drivers/net/wireless/ath/ath10k/mac.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 0bbd0a0..1fa3c17 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -6538,7 +6538,7 @@ static int ath10k_get_survey(struct ieee80211_hw *hw, int idx,
goto exit;
}
- ath10k_mac_update_bss_chan_survey(ar, survey->channel);
+ ath10k_mac_update_bss_chan_survey(ar, &sband->channels[idx]);
spin_lock_bh(&ar->data_lock);
memcpy(survey, ar_survey, sizeof(*survey));
--
1.9.1
^ permalink raw reply related
* [PATCH v5 1/2] mwifiex: add manufacturing mode support
From: Amitkumar Karwar @ 2016-09-02 7:35 UTC (permalink / raw)
To: linux-wireless
Cc: Cathy Luo, Nishant Sarmukadam, Xinming Hu, Amitkumar Karwar
From: Xinming Hu <huxm@marvell.com>
By default normal mode is chosen when driver is loaded. This
patch adds a provision to choose manufacturing mode via module
parameters.
Below command loads driver in manufacturing mode
insmod mwifiex.ko mfg_mode=1.
Tested-by: chunfan chen <jeffc@marvell.com>
Signed-off-by: Xinming Hu <huxm@marvell.com>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
---
v5: Fix format issue and enhance mfg_mode module parameter description
(Brian Norris).
v4: Removed mfg_firmware module parameter and hardcoded the firmware name
in driver(Kalle Valo).
---
drivers/net/wireless/marvell/mwifiex/cmdevt.c | 8 ++++++++
drivers/net/wireless/marvell/mwifiex/init.c | 22 +++++++++++++++-------
drivers/net/wireless/marvell/mwifiex/main.c | 26 ++++++++++++++++++++++----
drivers/net/wireless/marvell/mwifiex/main.h | 2 ++
drivers/net/wireless/marvell/mwifiex/pcie.c | 2 +-
drivers/net/wireless/marvell/mwifiex/sdio.c | 2 +-
drivers/net/wireless/marvell/mwifiex/usb.c | 2 +-
7 files changed, 50 insertions(+), 14 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
index d433aa0..5347728 100644
--- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
@@ -595,6 +595,14 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
return -1;
}
}
+ /* We don't expect commands in manufacturing mode. They are cooked
+ * in application and ready to download buffer is passed to the driver
+ */
+ if (adapter->mfg_mode && cmd_no) {
+ dev_dbg(adapter->dev, "Ignoring commands in manufacturing mode\n");
+ return -1;
+ }
+
/* Get a new command node */
cmd_node = mwifiex_get_cmd_node(adapter);
diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c
index 1489c90..82839d9 100644
--- a/drivers/net/wireless/marvell/mwifiex/init.c
+++ b/drivers/net/wireless/marvell/mwifiex/init.c
@@ -298,6 +298,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
adapter->arp_filter_size = 0;
adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
+ adapter->mfg_mode = mfg_mode;
adapter->key_api_major_ver = 0;
adapter->key_api_minor_ver = 0;
eth_broadcast_addr(adapter->perm_addr);
@@ -553,15 +554,22 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter)
return -1;
}
}
+ if (adapter->mfg_mode) {
+ adapter->hw_status = MWIFIEX_HW_STATUS_READY;
+ ret = -EINPROGRESS;
+ } else {
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i]) {
+ ret = mwifiex_sta_init_cmd(adapter->priv[i],
+ first_sta, true);
+ if (ret == -1)
+ return -1;
+
+ first_sta = false;
+ }
+
- for (i = 0; i < adapter->priv_num; i++) {
- if (adapter->priv[i]) {
- ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta,
- true);
- if (ret == -1)
- return -1;
- first_sta = false;
}
}
diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
index db4925d..945275a 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -23,6 +23,7 @@
#include "11n.h"
#define VERSION "1.0"
+#define MFG_FIRMWARE "mwifiex_mfg.bin"
static unsigned int debug_mask = MWIFIEX_DEFAULT_DEBUG_MASK;
module_param(debug_mask, uint, 0);
@@ -37,6 +38,10 @@ module_param(driver_mode, ushort, 0);
MODULE_PARM_DESC(driver_mode,
"station=0x1(default), ap-sta=0x3, station-p2p=0x5, ap-sta-p2p=0x7");
+bool mfg_mode;
+module_param(mfg_mode, bool, 0);
+MODULE_PARM_DESC(mfg_mode, "manufacturing mode enable:1, disable:0");
+
/*
* This function registers the device and performs all the necessary
* initializations.
@@ -559,10 +564,12 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
goto done;
}
/* Wait for mwifiex_init to complete */
- wait_event_interruptible(adapter->init_wait_q,
- adapter->init_wait_q_woken);
- if (adapter->hw_status != MWIFIEX_HW_STATUS_READY)
- goto err_init_fw;
+ if (!adapter->mfg_mode) {
+ wait_event_interruptible(adapter->init_wait_q,
+ adapter->init_wait_q_woken);
+ if (adapter->hw_status != MWIFIEX_HW_STATUS_READY)
+ goto err_init_fw;
+ }
priv = adapter->priv[MWIFIEX_BSS_ROLE_STA];
if (mwifiex_register_cfg80211(adapter)) {
@@ -666,6 +673,17 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
{
int ret;
+ /* Override default firmware with manufacturing one if
+ * manufacturing mode is enabled
+ */
+ if (mfg_mode) {
+ if (strlcpy(adapter->fw_name, MFG_FIRMWARE,
+ sizeof(adapter->fw_name)) >=
+ sizeof(adapter->fw_name)) {
+ pr_err("%s: fw_name too long!\n", __func__);
+ return -1;
+ }
+ }
ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name,
adapter->dev, GFP_KERNEL, adapter,
mwifiex_fw_dpc);
diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
index 5902600..fcc2af35 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++ b/drivers/net/wireless/marvell/mwifiex/main.h
@@ -58,6 +58,7 @@
#include "sdio.h"
extern const char driver_version[];
+extern bool mfg_mode;
struct mwifiex_adapter;
struct mwifiex_private;
@@ -990,6 +991,7 @@ struct mwifiex_adapter {
u32 drv_info_size;
bool scan_chan_gap_enabled;
struct sk_buff_head rx_data_q;
+ bool mfg_mode;
struct mwifiex_chan_stats *chan_stats;
u32 num_in_chan_stats;
int survey_idx;
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 453ab6a..a6af85d 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -225,7 +225,7 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
if (!adapter || !adapter->priv_num)
return;
- if (user_rmmod) {
+ if (user_rmmod && !adapter->mfg_mode) {
#ifdef CONFIG_PM_SLEEP
if (adapter->is_suspended)
mwifiex_pcie_resume(&pdev->dev);
diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c
index d3e1561..6dba409 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.c
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
@@ -289,7 +289,7 @@ mwifiex_sdio_remove(struct sdio_func *func)
mwifiex_dbg(adapter, INFO, "info: SDIO func num=%d\n", func->num);
- if (user_rmmod) {
+ if (user_rmmod && !adapter->mfg_mode) {
if (adapter->is_suspended)
mwifiex_sdio_resume(adapter->dev);
diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c
index 3bd04f5..9213516 100644
--- a/drivers/net/wireless/marvell/mwifiex/usb.c
+++ b/drivers/net/wireless/marvell/mwifiex/usb.c
@@ -611,7 +611,7 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)
if (!adapter->priv_num)
return;
- if (user_rmmod) {
+ if (user_rmmod && !adapter->mfg_mode) {
#ifdef CONFIG_PM
if (adapter->is_suspended)
mwifiex_usb_resume(intf);
--
1.9.1
^ permalink raw reply related
* [PATCH v5 2/2] mwifiex: add cfg80211 testmode support
From: Amitkumar Karwar @ 2016-09-02 7:35 UTC (permalink / raw)
To: linux-wireless
Cc: Cathy Luo, Nishant Sarmukadam, Xinming Hu, Amitkumar Karwar
In-Reply-To: <1472801707-6939-1-git-send-email-akarwar@marvell.com>
From: Xinming Hu <huxm@marvell.com>
This patch adds cfg80211 testmode support so that userspace tools can
download necessary commands to firmware during manufacturing mode tests.
Signed-off-by: Xinming Hu <huxm@marvell.com>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
---
v5: Made the function as static.(Brian Norris)
v4: Used cfg80211 testmode interface instead of wext in 2/2 patch.(Kalle Valo)
v3: Add "select WIRELESS_EXT" in Kconfig to resolve kbuild test robot errors.
WEXT_PRIV seems to have a dependency with WIRELESS_EXT.
v2: 1) Sequence of these two patches are changed to resolve compilation
error seen if only 1/2 is applied.
2) Add "select WEXT_PRIV" in Kconfig to resolve warnings reported by
kbuild test robot.
---
drivers/net/wireless/marvell/mwifiex/cfg80211.c | 83 +++++++++++++++++++++++++
1 file changed, 83 insertions(+)
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index 235fb39..86f43df 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -3919,6 +3919,88 @@ static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy,
return ret;
}
+#ifdef CONFIG_NL80211_TESTMODE
+
+enum mwifiex_tm_attr {
+ __MWIFIEX_TM_ATTR_INVALID = 0,
+ MWIFIEX_TM_ATTR_CMD = 1,
+ MWIFIEX_TM_ATTR_DATA = 2,
+
+ /* keep last */
+ __MWIFIEX_TM_ATTR_AFTER_LAST,
+ MWIFIEX_TM_ATTR_MAX = __MWIFIEX_TM_ATTR_AFTER_LAST - 1,
+};
+
+static const struct nla_policy mwifiex_tm_policy[MWIFIEX_TM_ATTR_MAX + 1] = {
+ [MWIFIEX_TM_ATTR_CMD] = { .type = NLA_U32 },
+ [MWIFIEX_TM_ATTR_DATA] = { .type = NLA_BINARY,
+ .len = MWIFIEX_SIZE_OF_CMD_BUFFER },
+};
+
+enum mwifiex_tm_command {
+ MWIFIEX_TM_CMD_HOSTCMD = 0,
+};
+
+static int mwifiex_tm_cmd(struct wiphy *wiphy, struct wireless_dev *wdev,
+ void *data, int len)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
+ struct mwifiex_ds_misc_cmd *hostcmd;
+ struct nlattr *tb[MWIFIEX_TM_ATTR_MAX + 1];
+ struct mwifiex_adapter *adapter;
+ struct sk_buff *skb;
+ int err;
+
+ if (!priv)
+ return -EINVAL;
+ adapter = priv->adapter;
+
+ err = nla_parse(tb, MWIFIEX_TM_ATTR_MAX, data, len,
+ mwifiex_tm_policy);
+ if (err)
+ return err;
+
+ if (!tb[MWIFIEX_TM_ATTR_CMD])
+ return -EINVAL;
+
+ switch (nla_get_u32(tb[MWIFIEX_TM_ATTR_CMD])) {
+ case MWIFIEX_TM_CMD_HOSTCMD:
+ if (!tb[MWIFIEX_TM_ATTR_DATA])
+ return -EINVAL;
+
+ hostcmd = kzalloc(sizeof(*hostcmd), GFP_KERNEL);
+ if (!hostcmd)
+ return -ENOMEM;
+
+ hostcmd->len = nla_len(tb[MWIFIEX_TM_ATTR_DATA]);
+ memcpy(hostcmd->cmd, nla_data(tb[MWIFIEX_TM_ATTR_DATA]),
+ hostcmd->len);
+
+ if (mwifiex_send_cmd(priv, 0, 0, 0, hostcmd, true)) {
+ dev_err(priv->adapter->dev, "Failed to process hostcmd\n");
+ return -EFAULT;
+ }
+
+ /* process hostcmd response*/
+ skb = cfg80211_testmode_alloc_reply_skb(wiphy, hostcmd->len);
+ if (!skb)
+ return -ENOMEM;
+ err = nla_put(skb, MWIFIEX_TM_ATTR_DATA,
+ hostcmd->len, hostcmd->cmd);
+ if (err) {
+ kfree_skb(skb);
+ return -EMSGSIZE;
+ }
+
+ err = cfg80211_testmode_reply(skb);
+ kfree(hostcmd);
+ return err;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+#endif
+
static int
mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy,
struct net_device *dev,
@@ -4031,6 +4113,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.tdls_cancel_channel_switch = mwifiex_cfg80211_tdls_cancel_chan_switch,
.add_station = mwifiex_cfg80211_add_station,
.change_station = mwifiex_cfg80211_change_station,
+ CFG80211_TESTMODE_CMD(mwifiex_tm_cmd)
.get_channel = mwifiex_cfg80211_get_channel,
.start_radar_detection = mwifiex_cfg80211_start_radar_detection,
.channel_switch = mwifiex_cfg80211_channel_switch,
--
1.9.1
^ permalink raw reply related
* RE: [v4,1/2] mwifiex: add manufacturing mode support
From: Amitkumar Karwar @ 2016-09-02 7:39 UTC (permalink / raw)
To: Brian Norris; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <20160831193441.GA30908@localhost>
Hi Brian,
> From: Brian Norris [mailto:briannorris@chromium.org]
> Sent: Thursday, September 01, 2016 1:05 AM
> To: Amitkumar Karwar
> Cc: linux-wireless@vger.kernel.org; Cathy Luo; Nishant Sarmukadam
> Subject: Re: [v4,1/2] mwifiex: add manufacturing mode support
>
> Hi,
>
> On Tue, Jul 26, 2016 at 03:09:19PM +0530, Amitkumar Karwar wrote:
> > By default normal mode is chosen when driver is loaded. This patch
> > adds a provision to choose manufacturing mode via module parameters.
> >
> > Below command loads driver in manufacturing mode insmod mwifiex.ko
> > mfg_mode=1.
> >
> > Tested-by: chunfan chen <jeffc@marvell.com>
> > Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
> > ---
> > v4: Removed mfg_firmware module parameter and hardcoded the firmware
> name
> > in driver(Kalle Valo).
> > ---
> > drivers/net/wireless/marvell/mwifiex/cmdevt.c | 8 ++++++++
> > drivers/net/wireless/marvell/mwifiex/init.c | 22 +++++++++++++++---
> ----
> > drivers/net/wireless/marvell/mwifiex/main.c | 25
> +++++++++++++++++++++----
> > drivers/net/wireless/marvell/mwifiex/main.h | 2 ++
> > drivers/net/wireless/marvell/mwifiex/pcie.c | 2 +-
> > drivers/net/wireless/marvell/mwifiex/sdio.c | 2 +-
> > drivers/net/wireless/marvell/mwifiex/usb.c | 2 +-
> > 7 files changed, 49 insertions(+), 14 deletions(-)
> >
> > diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
> > b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
> > index d433aa0..636cfa0 100644
> > --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
> > +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
> > @@ -595,6 +595,14 @@ int mwifiex_send_cmd(struct mwifiex_private
> *priv, u16 cmd_no,
> > return -1;
> > }
> > }
> > + /* We don't expect commands in manufacturing mode. They are cooked
> > + * in application and ready to download buffer is passed to the
> driver
> > + */
>
> You have the alignment wrong here. Needs an extra space.
>
> > + if (adapter->mfg_mode && cmd_no) {
> > + dev_dbg(adapter->dev, "Ignoring commands in manufacturing
> mode\n");
> > + return -1;
> > + }
> > +
> >
> > /* Get a new command node */
> > cmd_node = mwifiex_get_cmd_node(adapter); diff --git
> > a/drivers/net/wireless/marvell/mwifiex/init.c
> > b/drivers/net/wireless/marvell/mwifiex/init.c
> > index 1489c90..82839d9 100644
> > --- a/drivers/net/wireless/marvell/mwifiex/init.c
> > +++ b/drivers/net/wireless/marvell/mwifiex/init.c
> > @@ -298,6 +298,7 @@ static void mwifiex_init_adapter(struct
> mwifiex_adapter *adapter)
> > memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
> > adapter->arp_filter_size = 0;
> > adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
> > + adapter->mfg_mode = mfg_mode;
> > adapter->key_api_major_ver = 0;
> > adapter->key_api_minor_ver = 0;
> > eth_broadcast_addr(adapter->perm_addr);
> > @@ -553,15 +554,22 @@ int mwifiex_init_fw(struct mwifiex_adapter
> *adapter)
> > return -1;
> > }
> > }
> > + if (adapter->mfg_mode) {
> > + adapter->hw_status = MWIFIEX_HW_STATUS_READY;
> > + ret = -EINPROGRESS;
> > + } else {
> > + for (i = 0; i < adapter->priv_num; i++) {
> > + if (adapter->priv[i]) {
> > + ret = mwifiex_sta_init_cmd(adapter->priv[i],
> > + first_sta, true);
> > + if (ret == -1)
> > + return -1;
> > +
> > + first_sta = false;
> > + }
> > +
> >
> > - for (i = 0; i < adapter->priv_num; i++) {
> > - if (adapter->priv[i]) {
> > - ret = mwifiex_sta_init_cmd(adapter->priv[i],
> first_sta,
> > - true);
> > - if (ret == -1)
> > - return -1;
> >
> > - first_sta = false;
> > }
> > }
> >
> > diff --git a/drivers/net/wireless/marvell/mwifiex/main.c
> > b/drivers/net/wireless/marvell/mwifiex/main.c
> > index db4925d..7fbf74b 100644
> > --- a/drivers/net/wireless/marvell/mwifiex/main.c
> > +++ b/drivers/net/wireless/marvell/mwifiex/main.c
> > @@ -23,6 +23,7 @@
> > #include "11n.h"
> >
> > #define VERSION "1.0"
> > +#define MFG_FIRMWARE "mwifiex_mfg.bin"
> >
> > static unsigned int debug_mask = MWIFIEX_DEFAULT_DEBUG_MASK;
> > module_param(debug_mask, uint, 0); @@ -36,6 +37,9 @@ static unsigned
> > short driver_mode; module_param(driver_mode, ushort, 0);
> > MODULE_PARM_DESC(driver_mode,
> > "station=0x1(default), ap-sta=0x3, station-p2p=0x5,
> > ap-sta-p2p=0x7");
> > +bool mfg_mode;
>
> Does this really need to be global? It's only actually used in init.c,
> so could it help to move it to init.c and make it static?
We also use mfg_mode in main.c(mwifiex_init_hw_fw), so it can't be moved to init.s
>
> > +module_param(mfg_mode, bool, 0);
> > +MODULE_PARM_DESC(mfg_mode, "0:disable 1:enable (bool)");
>
> That's not a very helpful description. Perhaps you could mention in a
> word or two what this mode means?
>
> Brian
Thanks. I just submitted v5 patches addressing your comments.
Regards,
Amitkumar Karwar
>
> >
> > /*
> > * This function registers the device and performs all the necessary
> > @@ -559,10 +563,12 @@ static void mwifiex_fw_dpc(const struct firmware
> *firmware, void *context)
> > goto done;
> > }
> > /* Wait for mwifiex_init to complete */
> > - wait_event_interruptible(adapter->init_wait_q,
> > - adapter->init_wait_q_woken);
> > - if (adapter->hw_status != MWIFIEX_HW_STATUS_READY)
> > - goto err_init_fw;
> > + if (!adapter->mfg_mode) {
> > + wait_event_interruptible(adapter->init_wait_q,
> > + adapter->init_wait_q_woken);
> > + if (adapter->hw_status != MWIFIEX_HW_STATUS_READY)
> > + goto err_init_fw;
> > + }
> >
> > priv = adapter->priv[MWIFIEX_BSS_ROLE_STA];
> > if (mwifiex_register_cfg80211(adapter)) { @@ -666,6 +672,17 @@
> > static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) {
> > int ret;
> >
> > + /* Override default firmware with manufacturing one if
> > + * manufacturing mode is enabled
> > + */
> > + if (mfg_mode) {
> > + if (strlcpy(adapter->fw_name, MFG_FIRMWARE,
> > + sizeof(adapter->fw_name)) >=
> > + sizeof(adapter->fw_name)) {
> > + pr_err("%s: fw_name too long!\n", __func__);
> > + return -1;
> > + }
> > + }
> > ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name,
> > adapter->dev, GFP_KERNEL, adapter,
> > mwifiex_fw_dpc);
> > diff --git a/drivers/net/wireless/marvell/mwifiex/main.h
> > b/drivers/net/wireless/marvell/mwifiex/main.h
> > index 5902600..fcc2af35 100644
> > --- a/drivers/net/wireless/marvell/mwifiex/main.h
> > +++ b/drivers/net/wireless/marvell/mwifiex/main.h
> > @@ -58,6 +58,7 @@
> > #include "sdio.h"
> >
> > extern const char driver_version[];
> > +extern bool mfg_mode;
> >
> > struct mwifiex_adapter;
> > struct mwifiex_private;
> > @@ -990,6 +991,7 @@ struct mwifiex_adapter {
> > u32 drv_info_size;
> > bool scan_chan_gap_enabled;
> > struct sk_buff_head rx_data_q;
> > + bool mfg_mode;
> > struct mwifiex_chan_stats *chan_stats;
> > u32 num_in_chan_stats;
> > int survey_idx;
> > diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c
> > b/drivers/net/wireless/marvell/mwifiex/pcie.c
> > index 453ab6a..a6af85d 100644
> > --- a/drivers/net/wireless/marvell/mwifiex/pcie.c
> > +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
> > @@ -225,7 +225,7 @@ static void mwifiex_pcie_remove(struct pci_dev
> *pdev)
> > if (!adapter || !adapter->priv_num)
> > return;
> >
> > - if (user_rmmod) {
> > + if (user_rmmod && !adapter->mfg_mode) {
> > #ifdef CONFIG_PM_SLEEP
> > if (adapter->is_suspended)
> > mwifiex_pcie_resume(&pdev->dev);
> > diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c
> > b/drivers/net/wireless/marvell/mwifiex/sdio.c
> > index d3e1561..6dba409 100644
> > --- a/drivers/net/wireless/marvell/mwifiex/sdio.c
> > +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
> > @@ -289,7 +289,7 @@ mwifiex_sdio_remove(struct sdio_func *func)
> >
> > mwifiex_dbg(adapter, INFO, "info: SDIO func num=%d\n", func->num);
> >
> > - if (user_rmmod) {
> > + if (user_rmmod && !adapter->mfg_mode) {
> > if (adapter->is_suspended)
> > mwifiex_sdio_resume(adapter->dev);
> >
> > diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c
> > b/drivers/net/wireless/marvell/mwifiex/usb.c
> > index 0857575..ba616ec 100644
> > --- a/drivers/net/wireless/marvell/mwifiex/usb.c
> > +++ b/drivers/net/wireless/marvell/mwifiex/usb.c
> > @@ -611,7 +611,7 @@ static void mwifiex_usb_disconnect(struct
> usb_interface *intf)
> > if (!adapter->priv_num)
> > return;
> >
> > - if (user_rmmod) {
> > + if (user_rmmod && !adapter->mfg_mode) {
> > #ifdef CONFIG_PM
> > if (adapter->is_suspended)
> > mwifiex_usb_resume(intf);
^ permalink raw reply
* RE: [v4,2/2] mwifiex: add cfg80211 testmode support
From: Amitkumar Karwar @ 2016-09-02 7:40 UTC (permalink / raw)
To: Brian Norris; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <20160831194003.GA31478@localhost>
Hi Brian,
> From: Brian Norris [mailto:briannorris@chromium.org]
> Sent: Thursday, September 01, 2016 1:10 AM
> To: Amitkumar Karwar
> Cc: linux-wireless@vger.kernel.org; Cathy Luo; Nishant Sarmukadam;
> Xinming Hu
> Subject: Re: [v4,2/2] mwifiex: add cfg80211 testmode support
>
> On Tue, Jul 26, 2016 at 03:09:20PM +0530, Amitkumar Karwar wrote:
> > From: Xinming Hu <huxm@marvell.com>
> >
> > This patch adds cfg80211 testmode support so that userspace tools can
> > download necessary commands to firmware during manufacturing mode
> tests.
> >
> > Signed-off-by: Xinming <huxm@marvell.com>
> > Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
> > ---
> > v4: Used cfg80211 testmode interface instead of wext in 2/2
> > patch.(Kalle Valo)
> > v3: Add "select WIRELESS_EXT" in Kconfig to resolve kbuild test robot
> errors.
> > WEXT_PRIV seems to have a dependency with WIRELESS_EXT.
> > v2: 1) Sequence of these two patches are changed to resolve
> compilation
> > error seen if only 1/2 is applied.
> > 2) Add "select WEXT_PRIV" in Kconfig to resolve warnings reported
> by
> > kbuild test robot.
> > ---
> > drivers/net/wireless/marvell/mwifiex/cfg80211.c | 83
> > +++++++++++++++++++++++++
> > 1 file changed, 83 insertions(+)
> >
> > diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
> > b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
> > index 235fb39..86b31b1 100644
> > --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
> > +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
> > @@ -3919,6 +3919,88 @@ static int mwifiex_cfg80211_get_channel(struct
> wiphy *wiphy,
> > return ret;
> > }
> >
> > +#ifdef CONFIG_NL80211_TESTMODE
> > +
> > +enum mwifiex_tm_attr {
> > + __MWIFIEX_TM_ATTR_INVALID = 0,
> > + MWIFIEX_TM_ATTR_CMD = 1,
> > + MWIFIEX_TM_ATTR_DATA = 2,
> > +
> > + /* keep last */
> > + __MWIFIEX_TM_ATTR_AFTER_LAST,
> > + MWIFIEX_TM_ATTR_MAX = __MWIFIEX_TM_ATTR_AFTER_LAST - 1,
> > +};
> > +
> > +static const struct nla_policy mwifiex_tm_policy[MWIFIEX_TM_ATTR_MAX
> + 1] = {
> > + [MWIFIEX_TM_ATTR_CMD] = { .type = NLA_U32 },
> > + [MWIFIEX_TM_ATTR_DATA] = { .type = NLA_BINARY,
> > + .len = MWIFIEX_SIZE_OF_CMD_BUFFER },
> };
> > +
> > +enum mwifiex_tm_cmd {
> > + MWIFIEX_TM_CMD_HOSTCMD = 0,
> > +};
> > +
> > +int mwifiex_tm_cmd(struct wiphy *wiphy, struct wireless_dev *wdev,
>
> This function should be static, no?
>
> Brian
>
Yes. This have been taken care of in V5 patch.
Regards,
Amitkumar Karwar
^ permalink raw reply
* Debugging RTL8192CU firmware loading on 3.12 powerpc
From: Simon Wunderlich @ 2016-09-02 8:50 UTC (permalink / raw)
To: Larry Finger, linux-wireless; +Cc: sven, Pannirselvam Kanagaratnam
[-- Attachment #1: Type: text/plain, Size: 1433 bytes --]
Hi,
we are trying to integrate a RTL8192CU based WiFi adapter (TP-Link TL-WL822N)
on a PowerPC based platform running a vendor-supplied/modified 3.12 kernel
using compat-wireless (I've tried 2016-01-06 and 2016-06-20 versions). While
the adapter works fine on my Laptop (using Debian 4.6 and 4.7 kernels), it
seems the firmware loading fails on the PowerPC box. Here is some output from
the kernel log:
[ 36.945820] rtl8192cu: Chip version 0x11
[ 37.026208] rtl8192cu: MAC address: ec:08:6b:15:38:0e
[ 37.031301] rtl8192cu: Board Type 0
[ 37.035074] rtl_usb: rx_max_size 15360, rx_urb_num 8, in_ep 1
[ 37.040911] rtl8192cu: Loading firmware rtlwifi/rtl8192cufw_TMSC.bin
[ 37.049583] usbcore: registered new interface driver rtl8192cu
[...]
[ 221.588911] rtl8192cu:_ResetDigitalProcedure1():<0-0> #####=> 8051 reset
failed!.........................
[ 221.637599] rtl8192cu: MAC auto ON okay!
[ 221.674610] rtl8192cu: Tx queue select: 0x05
[ 233.233554] rtl8192c_common:_rtl92c_fw_free_to_go():<0-0> Polling FW ready
fail!! REG_MCUFWDL:0x00030006 .
[ 233.233566] rtl8192c_common:rtl92c_download_fw():<0-0> Firmware is not
ready to run!
The outputs at 221 starts when I enable hostapd with a minimal AP-starting
configuration.
Do you have any recommendations where the firmware loading problems could come
from, and where we could start to debug? Any pointers would be appreciated.
Thank you,
Simon
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH v5] mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue.
From: Toke Høiland-Jørgensen @ 2016-09-02 9:27 UTC (permalink / raw)
To: Jason Andryuk; +Cc: make-wifi-fast, linux-wireless@vger.kernel.org
In-Reply-To: <CAKf6xptJrniYA3Q2pYN4DkpKf_30dNJTdHqm+jCM=enDRSQhJQ@mail.gmail.com>
Jason Andryuk <jandryuk@gmail.com> writes:
> On Thu, Sep 1, 2016 at 12:03 PM, Toke H=C3=B8iland-J=C3=B8rgensen <toke@t=
oke.dk> wrote:
>> @@ -1481,33 +1506,57 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee=
80211_hw *hw,
>> {
>> struct ieee80211_local *local =3D hw_to_local(hw);
>> struct txq_info *txqi =3D container_of(txq, struct txq_info, txq=
);
>> - struct ieee80211_hdr *hdr;
>> struct sk_buff *skb =3D NULL;
>> struct fq *fq =3D &local->fq;
>> struct fq_tin *tin =3D &txqi->tin;
>> + struct ieee80211_tx_info *info;
>>
>> spin_lock_bh(&fq->lock);
>>
>> if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags))
>> goto out;
>>
>> +begin:
>> skb =3D fq_tin_dequeue(fq, tin, fq_tin_dequeue_func);
>> if (!skb)
>> goto out;
>>
>> ieee80211_set_skb_vif(skb, txqi);
>>
>> - hdr =3D (struct ieee80211_hdr *)skb->data;
>> - if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) {
>> + info =3D IEEE80211_SKB_CB(skb);
>> + if (txq->sta && info->control.flags & IEEE80211_TX_CTRL_FAST_XMI=
T) {
>> struct sta_info *sta =3D container_of(txq->sta, struct s=
ta_info,
>> sta);
>> - struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(skb);
>> + struct ieee80211_fast_tx *fast_tx;
>>
>> - hdr->seq_ctrl =3D ieee80211_tx_next_seq(sta, txq->tid);
>> - if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
>> - info->flags |=3D IEEE80211_TX_CTL_AMPDU;
>> - else
>> - info->flags &=3D ~IEEE80211_TX_CTL_AMPDU;
>> + fast_tx =3D rcu_dereference(sta->fast_tx);
>> + if (WARN_ON(!fast_tx)) {
>> + /* lost the fast_tx pointer while the packet was=
queued */
>> + ieee80211_free_txskb(hw, skb);
>> + goto begin;
>> + }
>> + ieee80211_xmit_fast_finish(sta->sdata, sta, fast_tx, skb=
, false);
>> + } else {
>> + struct ieee80211_tx_data tx =3D { };
>> +
>> + __skb_queue_head_init(&tx.skbs);
>> + tx.local =3D local;
>> + if (txq->sta) {
>> + struct sta_info *sta =3D container_of(txq->sta,
>> + struct sta_i=
nfo,
>> + sta);
>
> sta is unneeded give the assignment below?
Yeah, you're right. Think that was left over from a previous version.
Thanks for spotting it :)
-Toke
^ permalink raw reply
* Re: Debugging RTL8192CU firmware loading on 3.12 powerpc
From: Arend Van Spriel @ 2016-09-02 11:13 UTC (permalink / raw)
To: Simon Wunderlich, Larry Finger, linux-wireless
Cc: sven, Pannirselvam Kanagaratnam
In-Reply-To: <1586991.4QUcrJhXOm@prime>
On 2-9-2016 10:50, Simon Wunderlich wrote:
> Hi,
>
> we are trying to integrate a RTL8192CU based WiFi adapter (TP-Link TL-WL822N)
> on a PowerPC based platform running a vendor-supplied/modified 3.12 kernel
> using compat-wireless (I've tried 2016-01-06 and 2016-06-20 versions). While
> the adapter works fine on my Laptop (using Debian 4.6 and 4.7 kernels), it
> seems the firmware loading fails on the PowerPC box. Here is some output from
> the kernel log:
>
> [ 36.945820] rtl8192cu: Chip version 0x11
> [ 37.026208] rtl8192cu: MAC address: ec:08:6b:15:38:0e
> [ 37.031301] rtl8192cu: Board Type 0
> [ 37.035074] rtl_usb: rx_max_size 15360, rx_urb_num 8, in_ep 1
> [ 37.040911] rtl8192cu: Loading firmware rtlwifi/rtl8192cufw_TMSC.bin
> [ 37.049583] usbcore: registered new interface driver rtl8192cu
> [...]
> [ 221.588911] rtl8192cu:_ResetDigitalProcedure1():<0-0> #####=> 8051 reset
> failed!.........................
> [ 221.637599] rtl8192cu: MAC auto ON okay!
> [ 221.674610] rtl8192cu: Tx queue select: 0x05
> [ 233.233554] rtl8192c_common:_rtl92c_fw_free_to_go():<0-0> Polling FW ready
> fail!! REG_MCUFWDL:0x00030006 .
> [ 233.233566] rtl8192c_common:rtl92c_download_fw():<0-0> Firmware is not
> ready to run!
>
> The outputs at 221 starts when I enable hostapd with a minimal AP-starting
> configuration.
>
> Do you have any recommendations where the firmware loading problems could come
> from, and where we could start to debug? Any pointers would be appreciated.
Hi Simon,
Could it be an endian issue?
Regards,
Arend
> Thank you,
> Simon
>
^ permalink raw reply
* [PATCH v3] cfg80211: Add support to configure a beacon data rate
From: Purushottam Kushwaha @ 2016-09-02 11:13 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, jouni, usdutt, amarnath, pkushwah
This allows an option to configure a single beacon tx rate (u8) for an AP.
Signed-off-by: Purushottam Kushwaha <pkushwah@qti.qualcomm.com>
---
include/net/cfg80211.h | 25 +--
net/wireless/nl80211.c | 493 +++++++++++++++++++++++++++----------------------
2 files changed, 285 insertions(+), 233 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d5e7f69..c58afc8 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -676,6 +676,18 @@ struct cfg80211_acl_data {
struct mac_address mac_addrs[];
};
+/*
+ * cfg80211_bitrate_mask - masks for bitrate control
+ */
+struct cfg80211_bitrate_mask {
+ struct {
+ u32 legacy;
+ u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN];
+ u16 vht_mcs[NL80211_VHT_NSS_MAX];
+ enum nl80211_txrate_gi gi;
+ } control[NUM_NL80211_BANDS];
+};
+
/**
* struct cfg80211_ap_settings - AP configuration
*
@@ -700,6 +712,7 @@ struct cfg80211_acl_data {
* MAC address based access control
* @pbss: If set, start as a PCP instead of AP. Relevant for DMG
* networks.
+ * @beacon_rate: masks for setting user configured beacon tx rate.
*/
struct cfg80211_ap_settings {
struct cfg80211_chan_def chandef;
@@ -719,6 +732,7 @@ struct cfg80211_ap_settings {
bool p2p_opp_ps;
const struct cfg80211_acl_data *acl;
bool pbss;
+ struct cfg80211_bitrate_mask beacon_rate;
};
/**
@@ -2001,17 +2015,6 @@ enum wiphy_params_flags {
WIPHY_PARAM_DYN_ACK = 1 << 5,
};
-/*
- * cfg80211_bitrate_mask - masks for bitrate control
- */
-struct cfg80211_bitrate_mask {
- struct {
- u32 legacy;
- u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN];
- u16 vht_mcs[NL80211_VHT_NSS_MAX];
- enum nl80211_txrate_gi gi;
- } control[NUM_NL80211_BANDS];
-};
/**
* struct cfg80211_pmksa - PMK Security Association
*
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 7ebad35..047bd26 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3324,6 +3324,236 @@ static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
return err;
}
+static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
+ u8 *rates, u8 rates_len)
+{
+ u8 i;
+ u32 mask = 0;
+
+ for (i = 0; i < rates_len; i++) {
+ int rate = (rates[i] & 0x7f) * 5;
+ int ridx;
+
+ for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
+ struct ieee80211_rate *srate =
+ &sband->bitrates[ridx];
+ if (rate == srate->bitrate) {
+ mask |= 1 << ridx;
+ break;
+ }
+ }
+ if (ridx == sband->n_bitrates)
+ return 0; /* rate not found */
+ }
+
+ return mask;
+}
+
+static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
+ u8 *rates, u8 rates_len,
+ u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
+{
+ u8 i;
+
+ memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
+
+ for (i = 0; i < rates_len; i++) {
+ int ridx, rbit;
+
+ ridx = rates[i] / 8;
+ rbit = BIT(rates[i] % 8);
+
+ /* check validity */
+ if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
+ return false;
+
+ /* check availability */
+ if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
+ mcs[ridx] |= rbit;
+ else
+ return false;
+ }
+
+ return true;
+}
+
+static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
+{
+ u16 mcs_mask = 0;
+
+ switch (vht_mcs_map) {
+ case IEEE80211_VHT_MCS_NOT_SUPPORTED:
+ break;
+ case IEEE80211_VHT_MCS_SUPPORT_0_7:
+ mcs_mask = 0x00FF;
+ break;
+ case IEEE80211_VHT_MCS_SUPPORT_0_8:
+ mcs_mask = 0x01FF;
+ break;
+ case IEEE80211_VHT_MCS_SUPPORT_0_9:
+ mcs_mask = 0x03FF;
+ break;
+ default:
+ break;
+ }
+
+ return mcs_mask;
+}
+
+static void vht_build_mcs_mask(u16 vht_mcs_map,
+ u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
+{
+ u8 nss;
+
+ for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
+ vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
+ vht_mcs_map >>= 2;
+ }
+}
+
+static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
+ struct nl80211_txrate_vht *txrate,
+ u16 mcs[NL80211_VHT_NSS_MAX])
+{
+ u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
+ u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
+ u8 i;
+
+ if (!sband->vht_cap.vht_supported)
+ return false;
+
+ memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
+
+ /* Build vht_mcs_mask from VHT capabilities */
+ vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
+
+ for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
+ if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
+ mcs[i] = txrate->mcs[i];
+ else
+ return false;
+ }
+
+ return true;
+}
+
+static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
+ [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
+ .len = NL80211_MAX_SUPP_RATES },
+ [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
+ .len = NL80211_MAX_SUPP_HT_RATES },
+ [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
+ [NL80211_TXRATE_GI] = { .type = NLA_U8 },
+};
+
+static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
+ struct cfg80211_bitrate_mask *mask)
+{
+ struct nlattr *tb[NL80211_TXRATE_MAX + 1];
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ int rem, i;
+ struct nlattr *tx_rates;
+ struct ieee80211_supported_band *sband;
+ u16 vht_tx_mcs_map;
+
+ memset(mask, 0, sizeof(*mask));
+ /* Default to all rates enabled */
+ for (i = 0; i < NUM_NL80211_BANDS; i++) {
+ sband = rdev->wiphy.bands[i];
+
+ if (!sband)
+ continue;
+
+ mask->control[i].legacy = (1 << sband->n_bitrates) - 1;
+ memcpy(mask->control[i].ht_mcs,
+ sband->ht_cap.mcs.rx_mask,
+ sizeof(mask->control[i].ht_mcs));
+
+ if (!sband->vht_cap.vht_supported)
+ continue;
+
+ vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
+ vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs);
+ }
+
+ /* if no rates are given set it back to the defaults */
+ if (!info->attrs[NL80211_ATTR_TX_RATES])
+ goto out;
+
+ /*
+ * The nested attribute uses enum nl80211_band as the index. This maps
+ * directly to the enum nl80211_band values used in cfg80211.
+ */
+ BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
+ nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
+ enum nl80211_band band = nla_type(tx_rates);
+ int err;
+
+ if (band < 0 || band >= NUM_NL80211_BANDS)
+ return -EINVAL;
+ sband = rdev->wiphy.bands[band];
+ if (sband == NULL)
+ return -EINVAL;
+ err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
+ nla_len(tx_rates), nl80211_txattr_policy);
+ if (err)
+ return err;
+ if (tb[NL80211_TXRATE_LEGACY]) {
+ mask->control[band].legacy = rateset_to_mask(
+ sband,
+ nla_data(tb[NL80211_TXRATE_LEGACY]),
+ nla_len(tb[NL80211_TXRATE_LEGACY]));
+ if ((mask->control[band].legacy == 0) &&
+ nla_len(tb[NL80211_TXRATE_LEGACY]))
+ return -EINVAL;
+ }
+ if (tb[NL80211_TXRATE_HT]) {
+ if (!ht_rateset_to_mask(
+ sband,
+ nla_data(tb[NL80211_TXRATE_HT]),
+ nla_len(tb[NL80211_TXRATE_HT]),
+ mask->control[band].ht_mcs))
+ return -EINVAL;
+ }
+ if (tb[NL80211_TXRATE_VHT]) {
+ if (!vht_set_mcs_mask(
+ sband,
+ nla_data(tb[NL80211_TXRATE_VHT]),
+ mask->control[band].vht_mcs))
+ return -EINVAL;
+ }
+ if (tb[NL80211_TXRATE_GI]) {
+ mask->control[band].gi =
+ nla_get_u8(tb[NL80211_TXRATE_GI]);
+ if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI)
+ return -EINVAL;
+ }
+
+ if (mask->control[band].legacy == 0) {
+ /* don't allow empty legacy rates if HT or VHT
+ * are not even supported.
+ */
+ if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
+ rdev->wiphy.bands[band]->vht_cap.vht_supported))
+ return -EINVAL;
+
+ for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
+ if (mask->control[band].ht_mcs[i])
+ goto out;
+
+ for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
+ if (mask->control[band].vht_mcs[i])
+ goto out;
+
+ /* legacy and mcs rates may not be both empty */
+ return -EINVAL;
+ }
+ }
+
+out:
+ return 0;
+}
+
static int nl80211_parse_beacon(struct nlattr *attrs[],
struct cfg80211_beacon_data *bcn)
{
@@ -3553,6 +3783,42 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
wdev->iftype))
return -EINVAL;
+ if (info->attrs[NL80211_ATTR_TX_RATES]) {
+ u32 rate, count_ht, count_vht, i;
+ enum nl80211_band band;
+
+ err = nl80211_parse_tx_bitrate_mask(info, ¶ms.beacon_rate);
+ if (err)
+ return err;
+
+ band = params.chandef.chan->band;
+ rate = params.beacon_rate.control[band].legacy;
+ /* Allow only one rate */
+ if (rate) {
+ if (rate & (rate - 1))
+ return -EINVAL;
+ } else {
+ count_ht = 0;
+ for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+ if (params.beacon_rate.control[band].ht_mcs[i]) {
+ count_ht++;
+ if (count_ht > 1)
+ return -EINVAL;
+ }
+ }
+ count_vht = 0;
+ for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
+ if (params.beacon_rate.control[band].vht_mcs[i]) {
+ count_vht++;
+ if (count_vht > 1)
+ return -EINVAL;
+ }
+ }
+ if (!count_ht && !count_vht)
+ return -EINVAL;
+ }
+ }
+
if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
params.smps_mode =
nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
@@ -8623,238 +8889,21 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
return rdev_cancel_remain_on_channel(rdev, wdev, cookie);
}
-static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
- u8 *rates, u8 rates_len)
-{
- u8 i;
- u32 mask = 0;
-
- for (i = 0; i < rates_len; i++) {
- int rate = (rates[i] & 0x7f) * 5;
- int ridx;
-
- for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
- struct ieee80211_rate *srate =
- &sband->bitrates[ridx];
- if (rate == srate->bitrate) {
- mask |= 1 << ridx;
- break;
- }
- }
- if (ridx == sband->n_bitrates)
- return 0; /* rate not found */
- }
-
- return mask;
-}
-
-static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
- u8 *rates, u8 rates_len,
- u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
-{
- u8 i;
-
- memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
-
- for (i = 0; i < rates_len; i++) {
- int ridx, rbit;
-
- ridx = rates[i] / 8;
- rbit = BIT(rates[i] % 8);
-
- /* check validity */
- if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
- return false;
-
- /* check availability */
- if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
- mcs[ridx] |= rbit;
- else
- return false;
- }
-
- return true;
-}
-
-static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
-{
- u16 mcs_mask = 0;
-
- switch (vht_mcs_map) {
- case IEEE80211_VHT_MCS_NOT_SUPPORTED:
- break;
- case IEEE80211_VHT_MCS_SUPPORT_0_7:
- mcs_mask = 0x00FF;
- break;
- case IEEE80211_VHT_MCS_SUPPORT_0_8:
- mcs_mask = 0x01FF;
- break;
- case IEEE80211_VHT_MCS_SUPPORT_0_9:
- mcs_mask = 0x03FF;
- break;
- default:
- break;
- }
-
- return mcs_mask;
-}
-
-static void vht_build_mcs_mask(u16 vht_mcs_map,
- u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
-{
- u8 nss;
-
- for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
- vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
- vht_mcs_map >>= 2;
- }
-}
-
-static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
- struct nl80211_txrate_vht *txrate,
- u16 mcs[NL80211_VHT_NSS_MAX])
-{
- u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
- u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
- u8 i;
-
- if (!sband->vht_cap.vht_supported)
- return false;
-
- memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
-
- /* Build vht_mcs_mask from VHT capabilities */
- vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
-
- for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
- if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
- mcs[i] = txrate->mcs[i];
- else
- return false;
- }
-
- return true;
-}
-
-static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
- [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
- .len = NL80211_MAX_SUPP_RATES },
- [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
- .len = NL80211_MAX_SUPP_HT_RATES },
- [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
- [NL80211_TXRATE_GI] = { .type = NLA_U8 },
-};
-
static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
struct genl_info *info)
{
- struct nlattr *tb[NL80211_TXRATE_MAX + 1];
- struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct cfg80211_bitrate_mask mask;
- int rem, i;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
- struct nlattr *tx_rates;
- struct ieee80211_supported_band *sband;
- u16 vht_tx_mcs_map;
+ int err;
if (!rdev->ops->set_bitrate_mask)
return -EOPNOTSUPP;
- memset(&mask, 0, sizeof(mask));
- /* Default to all rates enabled */
- for (i = 0; i < NUM_NL80211_BANDS; i++) {
- sband = rdev->wiphy.bands[i];
-
- if (!sband)
- continue;
-
- mask.control[i].legacy = (1 << sband->n_bitrates) - 1;
- memcpy(mask.control[i].ht_mcs,
- sband->ht_cap.mcs.rx_mask,
- sizeof(mask.control[i].ht_mcs));
-
- if (!sband->vht_cap.vht_supported)
- continue;
-
- vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
- vht_build_mcs_mask(vht_tx_mcs_map, mask.control[i].vht_mcs);
- }
-
- /* if no rates are given set it back to the defaults */
- if (!info->attrs[NL80211_ATTR_TX_RATES])
- goto out;
-
- /*
- * The nested attribute uses enum nl80211_band as the index. This maps
- * directly to the enum nl80211_band values used in cfg80211.
- */
- BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
- nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
- enum nl80211_band band = nla_type(tx_rates);
- int err;
-
- if (band < 0 || band >= NUM_NL80211_BANDS)
- return -EINVAL;
- sband = rdev->wiphy.bands[band];
- if (sband == NULL)
- return -EINVAL;
- err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
- nla_len(tx_rates), nl80211_txattr_policy);
- if (err)
- return err;
- if (tb[NL80211_TXRATE_LEGACY]) {
- mask.control[band].legacy = rateset_to_mask(
- sband,
- nla_data(tb[NL80211_TXRATE_LEGACY]),
- nla_len(tb[NL80211_TXRATE_LEGACY]));
- if ((mask.control[band].legacy == 0) &&
- nla_len(tb[NL80211_TXRATE_LEGACY]))
- return -EINVAL;
- }
- if (tb[NL80211_TXRATE_HT]) {
- if (!ht_rateset_to_mask(
- sband,
- nla_data(tb[NL80211_TXRATE_HT]),
- nla_len(tb[NL80211_TXRATE_HT]),
- mask.control[band].ht_mcs))
- return -EINVAL;
- }
- if (tb[NL80211_TXRATE_VHT]) {
- if (!vht_set_mcs_mask(
- sband,
- nla_data(tb[NL80211_TXRATE_VHT]),
- mask.control[band].vht_mcs))
- return -EINVAL;
- }
- if (tb[NL80211_TXRATE_GI]) {
- mask.control[band].gi =
- nla_get_u8(tb[NL80211_TXRATE_GI]);
- if (mask.control[band].gi > NL80211_TXRATE_FORCE_LGI)
- return -EINVAL;
- }
-
- if (mask.control[band].legacy == 0) {
- /* don't allow empty legacy rates if HT or VHT
- * are not even supported.
- */
- if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
- rdev->wiphy.bands[band]->vht_cap.vht_supported))
- return -EINVAL;
-
- for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
- if (mask.control[band].ht_mcs[i])
- goto out;
-
- for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
- if (mask.control[band].vht_mcs[i])
- goto out;
-
- /* legacy and mcs rates may not be both empty */
- return -EINVAL;
- }
- }
+ err = nl80211_parse_tx_bitrate_mask(info, &mask);
+ if (err)
+ return err;
-out:
return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
}
--
1.9.1
^ permalink raw reply related
* Re: Debugging RTL8192CU firmware loading on 3.12 powerpc
From: Sven Eckelmann @ 2016-09-02 11:26 UTC (permalink / raw)
To: Arend Van Spriel
Cc: Simon Wunderlich, Larry Finger, linux-wireless,
Pannirselvam Kanagaratnam
In-Reply-To: <8cae6bb9-0465-9210-b543-61136836c263@broadcom.com>
[-- Attachment #1: Type: text/plain, Size: 771 bytes --]
On Freitag, 2. September 2016 13:13:20 CEST Arend Van Spriel wrote:
[...]
> > Do you have any recommendations where the firmware loading problems could
> > come from, and where we could start to debug? Any pointers would be
> > appreciated.
> Hi Simon,
>
> Could it be an endian issue?
Yes, it could be one (at least I've also guessed this - I could still be
completely wrong). But the problem is now to find a good starting point for
the debugging effort.
I've only looked at Simon's screen once while he gather USB dumps but didn't
spot any obvious at that time. There was also the problem that the comparison
dump looked already a lot different due to some timing differences.
I think Simon can give you later more details (when required).
Kind regards,
Sven
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: Ath10k probe response error related to mac80211 commit.
From: Michal Kazior @ 2016-09-02 12:09 UTC (permalink / raw)
To: Ben Greear; +Cc: Johannes Berg, linux-wireless@vger.kernel.org, ath10k
In-Reply-To: <79ab7dfa-f485-ffcd-963c-b91f7d5a8386@candelatech.com>
On 1 September 2016 at 22:52, Ben Greear <greearb@candelatech.com> wrote:
> On 09/01/2016 11:53 AM, Johannes Berg wrote:
>> On Thu, 2016-09-01 at 11:23 -0700, Ben Greear wrote:
>>>
>>> Could easily be that others are corrupted too, but since probe resp
>>> is bad, the association will not proceed.
>>
>> makes sense.
>>
>>> Heh, I spent 4 days tracking this down, so I wanted to be precise in
>>> my bug report :)
>>
>> Ahrg, ouch. Sorry about that. I really didn't think the flag would
>> cause any issues for anyone.
>>
>>> The result I see is that there is an extra 10 bytes at the end of the
>>> frame on air. But, it looks like the exact same pkt is sent to the
>>> firmware both with and without this patch. Maybe the firmware is
>>> using the wrong tid or something like that due to how the station is
>>> created differently with this patch.
>>
>> That makes no sense though, unless this only happens on say the second
>> station that connects? Until the first station sends an authentication
>> frame, that patch really should have no impact whatsoever.
>
> Ok, I found the problem.
>
> In the 10.1 firmware (at least), it will force the TID to be NON-QOS-TID
> if the peer object does not have the qos_enabled flag set. This is proba=
bly
> a work-around for some other thing lost in antiquity.
>
> When using my firmware that puts mgt frames over HTT, the TID for mgt
> frames was being over-ridden and set to non-qos TID. Due to other
> hackery and work-arounds, mgt frames cannot be sent on the non-qos
> TID because they will be put on-air 10 bytes too long. They must be
> sent on the mgt-tid or non-pause tid.
Sounds like 802.11 header vs 802.3 header length problem (24 - 14 =3D
10). You can hit this if you start playing around tx encap mode as
well.
You could try fooling firmware into thinking the frame has a different
length either in htt TX_FRM or tx fragment list (or both) but since
this seems to be related to RA/DA peer state at xmit time it's
probably not going to be reliable unless you introduce extra tx
flushing barriers in the driver.
Micha=C5=82
^ permalink raw reply
* [PATCH v2 1/6] rtl8723au: remove declaration of unimplemented functions
From: Luca Ceresoli @ 2016-09-02 12:57 UTC (permalink / raw)
To: devel
Cc: Luca Ceresoli, Larry Finger, Jes Sorensen, Greg Kroah-Hartman,
linux-wireless, linux-kernel
These functions have been declared without any implementation since
the first commit (364e30ebd2dbaccba430c603da03e68746eb932a) and there
has been no mention of them in following commits.
Signed-off-by: Luca Ceresoli <luca@lucaceresoli.net>
Cc: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Jes Sorensen <Jes.Sorensen@redhat.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-wireless@vger.kernel.org
Cc: devel@driverdev.osuosl.org
Cc: linux-kernel@vger.kernel.org
---
Changes v1 -> v2:
- improve the commit message.
---
drivers/staging/rtl8723au/include/recv_osdep.h | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/staging/rtl8723au/include/recv_osdep.h b/drivers/staging/rtl8723au/include/recv_osdep.h
index c2d3f1b..c159dbc 100644
--- a/drivers/staging/rtl8723au/include/recv_osdep.h
+++ b/drivers/staging/rtl8723au/include/recv_osdep.h
@@ -26,9 +26,6 @@ int rtw_recv_indicatepkt23a(struct rtw_adapter *adapter, struct recv_frame *prec
void rtw_handle_tkip_mic_err23a(struct rtw_adapter *padapter, u8 bgroup);
-int rtw_init_recv_priv(struct recv_priv *precvpriv, struct rtw_adapter *padapter);
-void rtw_free_recv_priv (struct recv_priv *precvpriv);
-
int rtw_os_recv_resource_init(struct recv_priv *precvpriv, struct rtw_adapter *padapter);
void rtw_init_recv_timer23a(struct recv_reorder_ctrl *preorder_ctrl);
--
2.7.4
^ permalink raw reply related
* Re: Ath10k probe response error related to mac80211 commit.
From: Ben Greear @ 2016-09-02 13:30 UTC (permalink / raw)
To: Michal Kazior; +Cc: Johannes Berg, linux-wireless@vger.kernel.org, ath10k
In-Reply-To: <CA+BoTQmehZSR71LzJtzy+N+ANZJ8N=c7tg+XX9_NUQjL4R-phQ@mail.gmail.com>
On 09/02/2016 05:09 AM, Michal Kazior wrote:
> On 1 September 2016 at 22:52, Ben Greear <greearb@candelatech.com> wrote:
>> On 09/01/2016 11:53 AM, Johannes Berg wrote:
>>> On Thu, 2016-09-01 at 11:23 -0700, Ben Greear wrote:
>>>>
>>>> Could easily be that others are corrupted too, but since probe resp
>>>> is bad, the association will not proceed.
>>>
>>> makes sense.
>>>
>>>> Heh, I spent 4 days tracking this down, so I wanted to be precise in
>>>> my bug report :)
>>>
>>> Ahrg, ouch. Sorry about that. I really didn't think the flag would
>>> cause any issues for anyone.
>>>
>>>> The result I see is that there is an extra 10 bytes at the end of the
>>>> frame on air. But, it looks like the exact same pkt is sent to the
>>>> firmware both with and without this patch. Maybe the firmware is
>>>> using the wrong tid or something like that due to how the station is
>>>> created differently with this patch.
>>>
>>> That makes no sense though, unless this only happens on say the second
>>> station that connects? Until the first station sends an authentication
>>> frame, that patch really should have no impact whatsoever.
>>
>> Ok, I found the problem.
>>
>> In the 10.1 firmware (at least), it will force the TID to be NON-QOS-TID
>> if the peer object does not have the qos_enabled flag set. This is probably
>> a work-around for some other thing lost in antiquity.
>>
>> When using my firmware that puts mgt frames over HTT, the TID for mgt
>> frames was being over-ridden and set to non-qos TID. Due to other
>> hackery and work-arounds, mgt frames cannot be sent on the non-qos
>> TID because they will be put on-air 10 bytes too long. They must be
>> sent on the mgt-tid or non-pause tid.
>
> Sounds like 802.11 header vs 802.3 header length problem (24 - 14 =
> 10). You can hit this if you start playing around tx encap mode as
> well.
>
> You could try fooling firmware into thinking the frame has a different
> length either in htt TX_FRM or tx fragment list (or both) but since
> this seems to be related to RA/DA peer state at xmit time it's
> probably not going to be reliable unless you introduce extra tx
> flushing barriers in the driver.
The problem is that the OS sent the packet on the mgt-tid, but the firmware
over-rode this and put it on non-qos TID instead. mgt and non-pause TIDs
are 'raw', and do not need that -10 adjustment, and my logic to handle mgt frames on
the normal htt path depends on that distinction.
Probably I could fix up htt tx path to do that -10 stuff depending on eventual
TID instead of making assumptions, but if I do this, it will probably be in 10.4
as I am hoping to keep 10.1 mostly just stable fixes and the htt tx path is one
tricky beast.
Search firmware for "The tidno that DE finds needs to be overridden for non-QOS"
and you can see where this happens. I just fixed that firmware code to not override
TID if it were already >= non-qos-tid.
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* [PATCH v6] mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue.
From: Toke Høiland-Jørgensen @ 2016-09-02 13:41 UTC (permalink / raw)
To: make-wifi-fast, linux-wireless; +Cc: Toke Høiland-Jørgensen
In-Reply-To: <20160901160312.31540-1-toke@toke.dk>
The TXQ intermediate queues can cause packet reordering when more than
one flow is active to a single station. Since some of the wifi-specific
packet handling (notably sequence number and encryption handling) is
sensitive to re-ordering, things break if they are applied before the
TXQ.
This splits up the TX handlers and fast_xmit logic into two parts: An
early part and a late part. The former is applied before TXQ enqueue,
and the latter after dequeue. The non-TXQ path just applies both parts
at once.
Because fragments shouldn't be split up or reordered, the fragmentation
handler is run after dequeue. Any fragments are then kept in the TXQ and
on subsequent dequeues they take precedence over dequeueing from the FQ
structure.
This approach avoids having to scatter special cases for when TXQ is
enabled, at the cost of making the fast_xmit and TX handler code
slightly more complex.
Signed-off-by: Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk>
---
Changes since v5:
- Move the fragmentation handler to *after* TXQ dequeue. Fragments are
kept in the TXQ for subsequent dequeues. This change also means that
the changes to make some of the handlers fragmentation aware are no
longer necessary.
- One of the TX stats updates in the fast path was done before the
enqueue step; move that to xmit_fast_finish().
- Move the rate selection handler to after dequeue, so it's run closer
to the time where the packet is actually transmitted.
=20
include/net/mac80211.h | 2 +
net/mac80211/ieee80211_i.h | 2 +
net/mac80211/tx.c | 207 +++++++++++++++++++++++++++++++++++----=
------
3 files changed, 168 insertions(+), 43 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index cca510a..9a6a3e9 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -715,6 +715,7 @@ enum mac80211_tx_info_flags {
* frame (PS-Poll or uAPSD).
* @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate info=
rmation
* @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame
+ * @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xm=
it path
*
* These flags are used in tx_info->control.flags.
*/
@@ -723,6 +724,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_CTRL_PS_RESPONSE =3D BIT(1),
IEEE80211_TX_CTRL_RATE_INJECT =3D BIT(2),
IEEE80211_TX_CTRL_AMSDU =3D BIT(3),
+ IEEE80211_TX_CTRL_FAST_XMIT =3D BIT(4),
};
=20
/*
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f56d342..de9991d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -813,11 +813,13 @@ enum txq_info_flags {
* @def_flow: used as a fallback flow when a packet destined to @tin has=
hes to
* a fq_flow which is already owned by a different tin
* @def_cvars: codel vars for @def_flow
+ * @frags: used to keep fragments created after dequeue
*/
struct txq_info {
struct fq_tin tin;
struct fq_flow def_flow;
struct codel_vars def_cvars;
+ struct sk_buff_head frags;
unsigned long flags;
=20
/* keep last! */
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 1d0746d..a3a4593 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -38,6 +38,12 @@
#include "wme.h"
#include "rate.h"
=20
+static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx);
+static bool ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sda=
ta,
+ struct sta_info *sta,
+ struct ieee80211_fast_tx *fast_tx,
+ struct sk_buff *skb, bool xmit);
+
/* misc utils */
=20
static inline void ieee80211_tx_stats(struct net_device *dev, u32 len)
@@ -1403,6 +1409,7 @@ void ieee80211_txq_init(struct ieee80211_sub_if_dat=
a *sdata,
fq_tin_init(&txqi->tin);
fq_flow_init(&txqi->def_flow);
codel_vars_init(&txqi->def_cvars);
+ __skb_queue_head_init(&txqi->frags);
=20
txqi->txq.vif =3D &sdata->vif;
=20
@@ -1425,6 +1432,7 @@ void ieee80211_txq_purge(struct ieee80211_local *lo=
cal,
struct fq_tin *tin =3D &txqi->tin;
=20
fq_tin_reset(fq, tin, fq_skb_free_func);
+ ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
}
=20
int ieee80211_txq_setup_flows(struct ieee80211_local *local)
@@ -1481,33 +1489,62 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee8=
0211_hw *hw,
{
struct ieee80211_local *local =3D hw_to_local(hw);
struct txq_info *txqi =3D container_of(txq, struct txq_info, txq);
- struct ieee80211_hdr *hdr;
struct sk_buff *skb =3D NULL;
struct fq *fq =3D &local->fq;
struct fq_tin *tin =3D &txqi->tin;
+ struct ieee80211_tx_info *info;
=20
spin_lock_bh(&fq->lock);
=20
if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags))
goto out;
=20
+ /* Make sure fragments stay together. */
+ skb =3D __skb_dequeue(&txqi->frags);
+ if (skb)
+ goto out;
+
+begin:
skb =3D fq_tin_dequeue(fq, tin, fq_tin_dequeue_func);
if (!skb)
goto out;
=20
ieee80211_set_skb_vif(skb, txqi);
=20
- hdr =3D (struct ieee80211_hdr *)skb->data;
- if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) {
+ info =3D IEEE80211_SKB_CB(skb);
+ if (txq->sta && info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) {
struct sta_info *sta =3D container_of(txq->sta, struct sta_info,
sta);
- struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(skb);
+ struct ieee80211_fast_tx *fast_tx;
=20
- hdr->seq_ctrl =3D ieee80211_tx_next_seq(sta, txq->tid);
- if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
- info->flags |=3D IEEE80211_TX_CTL_AMPDU;
- else
- info->flags &=3D ~IEEE80211_TX_CTL_AMPDU;
+ fast_tx =3D rcu_dereference(sta->fast_tx);
+ if (WARN_ON(!fast_tx)) {
+ /* lost the fast_tx pointer while the packet was queued */
+ ieee80211_free_txskb(hw, skb);
+ goto begin;
+ }
+ ieee80211_xmit_fast_finish(sta->sdata, sta, fast_tx, skb, false);
+ } else {
+ struct ieee80211_tx_data tx =3D { };
+
+ __skb_queue_head_init(&tx.skbs);
+ tx.local =3D local;
+ tx.skb =3D skb;
+ if (txq->sta) {
+ tx.sta =3D container_of(txq->sta, struct sta_info, sta);
+ tx.sdata =3D tx.sta->sdata;
+ } else {
+ tx.sdata =3D vif_to_sdata(info->control.vif);
+ }
+
+
+ if (invoke_tx_handlers_late(&tx))
+ goto begin;
+
+ skb =3D __skb_dequeue(&tx.skbs);
+
+ if (!skb_queue_empty(&tx.skbs))
+ skb_queue_splice_tail(&tx.skbs, &txqi->frags);
}
=20
out:
@@ -1521,6 +1558,47 @@ out:
}
EXPORT_SYMBOL(ieee80211_tx_dequeue);
=20
+static bool ieee80211_queue_skb(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta,
+ struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(skb);
+ struct fq *fq =3D &local->fq;
+ struct ieee80211_vif *vif;
+ struct txq_info *txqi;
+ struct ieee80211_sta *pubsta;
+
+ if (!local->ops->wake_tx_queue ||
+ sdata->vif.type =3D=3D NL80211_IFTYPE_MONITOR)
+ return false;
+
+ if (sta && sta->uploaded)
+ pubsta =3D &sta->sta;
+ else
+ pubsta =3D NULL;
+
+ if (sdata->vif.type =3D=3D NL80211_IFTYPE_AP_VLAN)
+ sdata =3D container_of(sdata->bss,
+ struct ieee80211_sub_if_data, u.ap);
+
+ vif =3D &sdata->vif;
+ txqi =3D ieee80211_get_txq(local, vif, pubsta, skb);
+
+ if (!txqi)
+ return false;
+
+ info->control.vif =3D vif;
+
+ spin_lock_bh(&fq->lock);
+ ieee80211_txq_enqueue(local, txqi, skb);
+ spin_unlock_bh(&fq->lock);
+
+ drv_wake_tx_queue(local, txqi);
+
+ return true;
+}
+
static bool ieee80211_tx_frags(struct ieee80211_local *local,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -1528,9 +1606,7 @@ static bool ieee80211_tx_frags(struct ieee80211_loc=
al *local,
bool txpending)
{
struct ieee80211_tx_control control =3D {};
- struct fq *fq =3D &local->fq;
struct sk_buff *skb, *tmp;
- struct txq_info *txqi;
unsigned long flags;
=20
skb_queue_walk_safe(skbs, skb, tmp) {
@@ -1545,21 +1621,6 @@ static bool ieee80211_tx_frags(struct ieee80211_lo=
cal *local,
}
#endif
=20
- txqi =3D ieee80211_get_txq(local, vif, sta, skb);
- if (txqi) {
- info->control.vif =3D vif;
-
- __skb_unlink(skb, skbs);
-
- spin_lock_bh(&fq->lock);
- ieee80211_txq_enqueue(local, txqi, skb);
- spin_unlock_bh(&fq->lock);
-
- drv_wake_tx_queue(local, txqi);
-
- continue;
- }
-
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
if (local->queue_stop_reasons[q] ||
(!txpending && !skb_queue_empty(&local->pending[q]))) {
@@ -1680,10 +1741,13 @@ static bool __ieee80211_tx(struct ieee80211_local=
*local,
/*
* Invoke TX handlers, return 0 on success and non-zero if the
* frame was dropped or queued.
+ *
+ * The handlers are split into an early and late part. The latter is eve=
rything
+ * that can be sensitive to reordering, and will be deferred to after pa=
ckets
+ * are dequeued from the intermediate queues (when they are enabled).
*/
-static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
+static int invoke_tx_handlers_early(struct ieee80211_tx_data *tx)
{
- struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(tx->skb);
ieee80211_tx_result res =3D TX_DROP;
=20
#define CALL_TXH(txh) \
@@ -1697,7 +1761,28 @@ static int invoke_tx_handlers(struct ieee80211_tx_=
data *tx)
CALL_TXH(ieee80211_tx_h_check_assoc);
CALL_TXH(ieee80211_tx_h_ps_buf);
CALL_TXH(ieee80211_tx_h_check_control_port_protocol);
- CALL_TXH(ieee80211_tx_h_select_key);
+
+ txh_done:
+ if (unlikely(res =3D=3D TX_DROP)) {
+ I802_DEBUG_INC(tx->local->tx_handlers_drop);
+ if (tx->skb)
+ ieee80211_free_txskb(&tx->local->hw, tx->skb);
+ else
+ ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);
+ return -1;
+ } else if (unlikely(res =3D=3D TX_QUEUED)) {
+ I802_DEBUG_INC(tx->local->tx_handlers_queued);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx)
+{
+ struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(tx->skb);
+ ieee80211_tx_result res =3D TX_DROP;
+
if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
CALL_TXH(ieee80211_tx_h_rate_ctrl);
=20
@@ -1707,6 +1792,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_d=
ata *tx)
goto txh_done;
}
=20
+ CALL_TXH(ieee80211_tx_h_select_key);
CALL_TXH(ieee80211_tx_h_michael_mic_add);
CALL_TXH(ieee80211_tx_h_sequence);
CALL_TXH(ieee80211_tx_h_fragment);
@@ -1733,6 +1819,15 @@ static int invoke_tx_handlers(struct ieee80211_tx_=
data *tx)
return 0;
}
=20
+static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
+{
+ int r =3D invoke_tx_handlers_early(tx);
+ if (r)
+ return r;
+
+ return invoke_tx_handlers_late(tx);
+}
+
bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct sk_buff *skb,
int band, struct ieee80211_sta **sta)
@@ -1807,7 +1902,13 @@ static bool ieee80211_tx(struct ieee80211_sub_if_d=
ata *sdata,
info->hw_queue =3D
sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
=20
- if (!invoke_tx_handlers(&tx))
+ if (invoke_tx_handlers_early(&tx))
+ return false;
+
+ if (ieee80211_queue_skb(local, sdata, tx.sta, tx.skb))
+ return true;
+
+ if (!invoke_tx_handlers_late(&tx))
result =3D __ieee80211_tx(local, &tx.skbs, led_len,
tx.sta, txpending);
=20
@@ -3159,7 +3260,7 @@ out:
}
=20
static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
- struct net_device *dev, struct sta_info *sta,
+ struct sta_info *sta,
struct ieee80211_fast_tx *fast_tx,
struct sk_buff *skb)
{
@@ -3170,8 +3271,6 @@ static bool ieee80211_xmit_fast(struct ieee80211_su=
b_if_data *sdata,
struct ethhdr eth;
struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr =3D (void *)fast_tx->hdr;
- struct ieee80211_tx_data tx;
- ieee80211_tx_result r;
struct tid_ampdu_tx *tid_tx =3D NULL;
u8 tid =3D IEEE80211_NUM_TIDS;
=20
@@ -3210,8 +3309,6 @@ static bool ieee80211_xmit_fast(struct ieee80211_su=
b_if_data *sdata,
return true;
}
=20
- ieee80211_tx_stats(dev, skb->len + extra_head);
-
if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb))
return true;
@@ -3240,11 +3337,32 @@ static bool ieee80211_xmit_fast(struct ieee80211_=
sub_if_data *sdata,
info->flags =3D IEEE80211_TX_CTL_FIRST_FRAGMENT |
IEEE80211_TX_CTL_DONTFRAG |
(tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
+ info->control.flags =3D IEEE80211_TX_CTRL_FAST_XMIT;
+
+ if (ieee80211_queue_skb(local, sdata, sta, skb))
+ return true;
+
+ return ieee80211_xmit_fast_finish(sdata, sta, fast_tx, skb, true);
+}
+
+static bool ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sda=
ta,
+ struct sta_info *sta,
+ struct ieee80211_fast_tx *fast_tx,
+ struct sk_buff *skb, bool xmit)
+{
+ struct ieee80211_local *local =3D sdata->local;
+ struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr =3D (void *)skb->data;
+ struct ieee80211_tx_data tx;
+ ieee80211_tx_result r;
+ u8 tid =3D IEEE80211_NUM_TIDS;
+
+ ieee80211_tx_stats(skb->dev, skb->len);
=20
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
+ tid =3D skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
*ieee80211_get_qos_ctl(hdr) =3D tid;
- if (!sta->sta.txq[0])
- hdr->seq_ctrl =3D ieee80211_tx_next_seq(sta, tid);
+ hdr->seq_ctrl =3D ieee80211_tx_next_seq(sta, tid);
} else {
info->flags |=3D IEEE80211_TX_CTL_ASSIGN_SEQ;
hdr->seq_ctrl =3D cpu_to_le16(sdata->sequence_number);
@@ -3309,12 +3427,15 @@ static bool ieee80211_xmit_fast(struct ieee80211_=
sub_if_data *sdata,
}
}
=20
- if (sdata->vif.type =3D=3D NL80211_IFTYPE_AP_VLAN)
- sdata =3D container_of(sdata->bss,
- struct ieee80211_sub_if_data, u.ap);
+ if (xmit) {
+ if (sdata->vif.type =3D=3D NL80211_IFTYPE_AP_VLAN)
+ sdata =3D container_of(sdata->bss,
+ struct ieee80211_sub_if_data, u.ap);
+
+ __skb_queue_tail(&tx.skbs, skb);
+ ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false);
+ }
=20
- __skb_queue_tail(&tx.skbs, skb);
- ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false);
return true;
}
=20
@@ -3342,7 +3463,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *s=
kb,
fast_tx =3D rcu_dereference(sta->fast_tx);
=20
if (fast_tx &&
- ieee80211_xmit_fast(sdata, dev, sta, fast_tx, skb))
+ ieee80211_xmit_fast(sdata, sta, fast_tx, skb))
goto out;
}
=20
--=20
2.9.3
^ permalink raw reply related
* [PATCH v5] ath9k: Switch to using mac80211 intermediate software queues.
From: Toke Høiland-Jørgensen @ 2016-09-02 14:00 UTC (permalink / raw)
To: make-wifi-fast, linux-wireless
Cc: Toke Høiland-Jørgensen, Tim Shepard, Felix Fietkau
In-Reply-To: <20160805160346.10545-1-toke@toke.dk>
This switches ath9k over to using the mac80211 intermediate software
queueing mechanism for data packets. It removes the queueing inside the
driver, except for the retry queue, and instead pulls from mac80211 when
a packet is needed. The retry queue is used to store a packet that was
pulled but can't be sent immediately.
The old code path in ath_tx_start that would queue packets has been
removed completely, as has the qlen limit tunables (since there's no
longer a queue in the driver to limit).
Based on Tim's original patch set, but reworked quite thoroughly.
Cc: Tim Shepard <shep@alum.mit.edu>
Cc: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk>
---
Changes since v4:
- Fix regression where PS response frames (which go through the old TX
path) would not get assigned a seqno because the tid variable was not
assigned correctly. Many thanks to Felix for debugging this and coming
up with a fix.
Hopefully that is the last regression (apart from the ongoing mac80211
restructure). :)
drivers/net/wireless/ath/ath9k/ath9k.h | 27 ++-
drivers/net/wireless/ath/ath9k/channel.c | 2 -
drivers/net/wireless/ath/ath9k/debug.c | 14 +-
drivers/net/wireless/ath/ath9k/debug.h | 2 -
drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
drivers/net/wireless/ath/ath9k/init.c | 2 +-
drivers/net/wireless/ath/ath9k/main.c | 9 +-
drivers/net/wireless/ath/ath9k/xmit.c | 338 ++++++++++++-----------=
------
8 files changed, 163 insertions(+), 235 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireles=
s/ath/ath9k/ath9k.h
index 26fc8ec..378d345 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_=
descdma *dd,
#define ATH_RXBUF 512
#define ATH_TXBUF 512
#define ATH_TXBUF_RESERVE 5
-#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
#define ATH_TXMAXTRY 13
#define ATH_MAX_SW_RETRIES 30
=20
@@ -145,7 +144,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct at=
h_descdma *dd,
#define BAW_WITHIN(_start, _bawsz, _seqno) \
((((_seqno) - (_start)) & 4095) < (_bawsz))
=20
-#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)])
+#define ATH_AN_2_TID(_an, _tidno) ath_node_to_tid(_an, _tidno)
=20
#define IS_HT_RATE(rate) (rate & 0x80)
#define IS_CCK_RATE(rate) ((rate >=3D 0x18) && (rate <=3D 0x1e))
@@ -164,7 +163,6 @@ struct ath_txq {
spinlock_t axq_lock;
u32 axq_depth;
u32 axq_ampdu_depth;
- bool stopped;
bool axq_tx_inprogress;
struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
u8 txq_headidx;
@@ -232,7 +230,6 @@ struct ath_buf {
=20
struct ath_atx_tid {
struct list_head list;
- struct sk_buff_head buf_q;
struct sk_buff_head retry_q;
struct ath_node *an;
struct ath_txq *txq;
@@ -247,13 +244,13 @@ struct ath_atx_tid {
s8 bar_index;
bool active;
bool clear_ps_filter;
+ bool has_queued;
};
=20
struct ath_node {
struct ath_softc *sc;
struct ieee80211_sta *sta; /* station struct we're part of */
struct ieee80211_vif *vif; /* interface with which we're associated */
- struct ath_atx_tid tid[IEEE80211_NUM_TIDS];
=20
u16 maxampdu;
u8 mpdudensity;
@@ -276,7 +273,6 @@ struct ath_tx_control {
struct ath_node *an;
struct ieee80211_sta *sta;
u8 paprd;
- bool force_channel;
};
=20
=20
@@ -293,7 +289,6 @@ struct ath_tx {
struct ath_descdma txdma;
struct ath_txq *txq_map[IEEE80211_NUM_ACS];
struct ath_txq *uapsdq;
- u32 txq_max_pending[IEEE80211_NUM_ACS];
u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32];
};
=20
@@ -421,6 +416,22 @@ struct ath_offchannel {
int duration;
};
=20
+static inline struct ath_atx_tid *
+ath_node_to_tid(struct ath_node *an, u8 tidno)
+{
+ struct ieee80211_sta *sta =3D an->sta;
+ struct ieee80211_vif *vif =3D an->vif;
+ struct ieee80211_txq *txq;
+
+ BUG_ON(!vif);
+ if (sta)
+ txq =3D sta->txq[tidno % ARRAY_SIZE(sta->txq)];
+ else
+ txq =3D vif->txq;
+
+ return (struct ath_atx_tid *) txq->drv_priv;
+}
+
#define case_rtn_string(val) case val: return #val
=20
#define ath_for_each_chanctx(_sc, _ctx) \
@@ -575,7 +586,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc);
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn);
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u=
16 tid);
-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,=
u16 tid);
=20
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
@@ -585,6 +595,7 @@ void ath9k_release_buffered_frames(struct ieee80211_h=
w *hw,
u16 tids, int nframes,
enum ieee80211_frame_release_type reason,
bool more_data);
+void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *=
queue);
=20
/********/
/* VIFs */
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wirel=
ess/ath/ath9k/channel.c
index 57e26a6..929dd70 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -1010,7 +1010,6 @@ static void ath_scan_send_probe(struct ath_softc *s=
c,
goto error;
=20
txctl.txq =3D sc->tx.txq_map[IEEE80211_AC_VO];
- txctl.force_channel =3D true;
if (ath_tx_start(sc->hw, skb, &txctl))
goto error;
=20
@@ -1133,7 +1132,6 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc,=
struct ath_vif *avp,
memset(&txctl, 0, sizeof(txctl));
txctl.txq =3D sc->tx.txq_map[IEEE80211_AC_VO];
txctl.sta =3D sta;
- txctl.force_channel =3D true;
if (ath_tx_start(sc->hw, skb, &txctl)) {
ieee80211_free_txskb(sc->hw, skb);
return false;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireles=
s/ath/ath9k/debug.c
index c56e40f..89a94dd 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -600,7 +600,6 @@ static int read_file_xmit(struct seq_file *file, void=
*data)
PR("MPDUs XRetried: ", xretries);
PR("Aggregates: ", a_aggr);
PR("AMPDUs Queued HW:", a_queued_hw);
- PR("AMPDUs Queued SW:", a_queued_sw);
PR("AMPDUs Completed:", a_completed);
PR("AMPDUs Retried: ", a_retries);
PR("AMPDUs XRetried: ", a_xretries);
@@ -629,8 +628,7 @@ static void print_queue(struct ath_softc *sc, struct =
ath_txq *txq,
seq_printf(file, "%s: %d ", "qnum", txq->axq_qnum);
seq_printf(file, "%s: %2d ", "qdepth", txq->axq_depth);
seq_printf(file, "%s: %2d ", "ampdu-depth", txq->axq_ampdu_depth);
- seq_printf(file, "%s: %3d ", "pending", txq->pending_frames);
- seq_printf(file, "%s: %d\n", "stopped", txq->stopped);
+ seq_printf(file, "%s: %3d\n", "pending", txq->pending_frames);
=20
ath_txq_unlock(sc, txq);
}
@@ -1208,7 +1206,6 @@ static const char ath9k_gstrings_stats[][ETH_GSTRIN=
G_LEN] =3D {
AMKSTR(d_tx_mpdu_xretries),
AMKSTR(d_tx_aggregates),
AMKSTR(d_tx_ampdus_queued_hw),
- AMKSTR(d_tx_ampdus_queued_sw),
AMKSTR(d_tx_ampdus_completed),
AMKSTR(d_tx_ampdu_retries),
AMKSTR(d_tx_ampdu_xretries),
@@ -1288,7 +1285,6 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
AWDATA(xretries);
AWDATA(a_aggr);
AWDATA(a_queued_hw);
- AWDATA(a_queued_sw);
AWDATA(a_completed);
AWDATA(a_retries);
AWDATA(a_xretries);
@@ -1346,14 +1342,6 @@ int ath9k_init_debug(struct ath_hw *ah)
read_file_xmit);
debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy,
read_file_queues);
- debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BK]);
- debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BE]);
- debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VI]);
- debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VO]);
debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy,
read_file_misc);
debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy,
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireles=
s/ath/ath9k/debug.h
index cd68c5f..a078cdd 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -147,7 +147,6 @@ struct ath_interrupt_stats {
* @completed: Total MPDUs (non-aggr) completed
* @a_aggr: Total no. of aggregates queued
* @a_queued_hw: Total AMPDUs queued to hardware
- * @a_queued_sw: Total AMPDUs queued to software queues
* @a_completed: Total AMPDUs completed
* @a_retries: No. of AMPDUs retried (SW)
* @a_xretries: No. of AMPDUs dropped due to xretries
@@ -174,7 +173,6 @@ struct ath_tx_stats {
u32 xretries;
u32 a_aggr;
u32 a_queued_hw;
- u32 a_queued_sw;
u32 a_completed;
u32 a_retries;
u32 a_xretries;
diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wir=
eless/ath/ath9k/debug_sta.c
index b66cfa9..2a3a3c4 100644
--- a/drivers/net/wireless/ath/ath9k/debug_sta.c
+++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
@@ -52,8 +52,8 @@ static ssize_t read_file_node_aggr(struct file *file, c=
har __user *user_buf,
"TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE",
"BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED");
=20
- for (tidno =3D 0, tid =3D &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
+ for (tidno =3D 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid =3D ath_node_to_tid(an, tidno);
txq =3D tid->txq;
ath_txq_lock(sc, txq);
if (tid->active) {
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless=
/ath/ath9k/init.c
index cfa3fe8..96bba17 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -358,7 +358,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
for (i =3D 0; i < IEEE80211_NUM_ACS; i++) {
sc->tx.txq_map[i] =3D ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
sc->tx.txq_map[i]->mac80211_qnum =3D i;
- sc->tx.txq_max_pending[i] =3D ATH_MAX_QDEPTH;
}
return 0;
}
@@ -877,6 +876,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, =
struct ieee80211_hw *hw)
hw->max_rate_tries =3D 10;
hw->sta_data_size =3D sizeof(struct ath_node);
hw->vif_data_size =3D sizeof(struct ath_vif);
+ hw->txq_data_size =3D sizeof(struct ath_atx_tid);
hw->extra_tx_headroom =3D 4;
=20
hw->wiphy->available_antennas_rx =3D BIT(ah->caps.max_rxchains) - 1;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless=
/ath/ath9k/main.c
index a394622..1dedf13 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1896,9 +1896,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw =
*hw,
bool flush =3D false;
int ret =3D 0;
struct ieee80211_sta *sta =3D params->sta;
+ struct ath_node *an =3D (struct ath_node *)sta->drv_priv;
enum ieee80211_ampdu_mlme_action action =3D params->action;
u16 tid =3D params->tid;
u16 *ssn =3D ¶ms->ssn;
+ struct ath_atx_tid *atid;
=20
mutex_lock(&sc->mutex);
=20
@@ -1931,9 +1933,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *=
hw,
ath9k_ps_restore(sc);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
- ath9k_ps_wakeup(sc);
- ath_tx_aggr_resume(sc, sta, tid);
- ath9k_ps_restore(sc);
+ atid =3D ath_node_to_tid(an, tid);
+ atid->baw_size =3D IEEE80211_MIN_AMPDU_BUF <<
+ sta->ht_cap.ampdu_factor;
break;
default:
ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
@@ -2695,4 +2697,5 @@ struct ieee80211_ops ath9k_ops =3D {
.sw_scan_start =3D ath9k_sw_scan_start,
.sw_scan_complete =3D ath9k_sw_scan_complete,
.get_txpower =3D ath9k_get_txpower,
+ .wake_tx_queue =3D ath9k_wake_tx_queue,
};
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless=
/ath/ath9k/xmit.c
index 8ddd604..c074747 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -65,6 +65,8 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_s=
oftc *sc,
struct ath_txq *txq,
struct ath_atx_tid *tid,
struct sk_buff *skb);
+static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ath_tx_control *txctl);
=20
enum {
MCS_HT20,
@@ -118,6 +120,26 @@ static void ath_tx_queue_tid(struct ath_softc *sc, s=
truct ath_txq *txq,
list_add_tail(&tid->list, list);
}
=20
+void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *=
queue)
+{
+ struct ath_softc *sc =3D hw->priv;
+ struct ath_common *common =3D ath9k_hw_common(sc->sc_ah);
+ struct ath_atx_tid *tid =3D (struct ath_atx_tid *) queue->drv_priv;
+ struct ath_txq *txq =3D tid->txq;
+
+ ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n",
+ queue->sta ? queue->sta->addr : queue->vif->addr,
+ tid->tidno);
+
+ ath_txq_lock(sc, txq);
+
+ tid->has_queued =3D true;
+ ath_tx_queue_tid(sc, txq, tid);
+ ath_txq_schedule(sc, txq);
+
+ ath_txq_unlock(sc, txq);
+}
+
static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info =3D IEEE80211_SKB_CB(skb);
@@ -145,7 +167,6 @@ static void ath_set_rates(struct ieee80211_vif *vif, =
struct ieee80211_sta *sta,
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
struct sk_buff *skb)
{
- struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(skb);
struct ath_frame_info *fi =3D get_frame_info(skb);
int q =3D fi->txq;
=20
@@ -156,14 +177,6 @@ static void ath_txq_skb_done(struct ath_softc *sc, s=
truct ath_txq *txq,
if (WARN_ON(--txq->pending_frames < 0))
txq->pending_frames =3D 0;
=20
- if (txq->stopped &&
- txq->pending_frames < sc->tx.txq_max_pending[q]) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_wake_queue(sc->hw, info->hw_queue);
- else
- ieee80211_wake_queue(sc->hw, q);
- txq->stopped =3D false;
- }
}
=20
static struct ath_atx_tid *
@@ -173,9 +186,48 @@ ath_get_skb_tid(struct ath_softc *sc, struct ath_nod=
e *an, struct sk_buff *skb)
return ATH_AN_2_TID(an, tidno);
}
=20
+static struct sk_buff *
+ath_tid_pull(struct ath_atx_tid *tid)
+{
+ struct ieee80211_txq *txq =3D container_of((void*)tid, struct ieee80211=
_txq, drv_priv);
+ struct ath_softc *sc =3D tid->an->sc;
+ struct ieee80211_hw *hw =3D sc->hw;
+ struct ath_tx_control txctl =3D {
+ .txq =3D tid->txq,
+ .sta =3D tid->an->sta,
+ };
+ struct sk_buff *skb;
+ struct ath_frame_info *fi;
+ int q;
+
+ if (!tid->has_queued)
+ return NULL;
+
+ skb =3D ieee80211_tx_dequeue(hw, txq);
+ if (!skb) {
+ tid->has_queued =3D false;
+ return NULL;
+ }
+
+ if (ath_tx_prepare(hw, skb, &txctl)) {
+ ieee80211_free_txskb(hw, skb);
+ return NULL;
+ }
+
+ q =3D skb_get_queue_mapping(skb);
+ if (tid->txq =3D=3D sc->tx.txq_map[q]) {
+ fi =3D get_frame_info(skb);
+ fi->txq =3D q;
+ ++tid->txq->pending_frames;
+ }
+
+ return skb;
+ }
+
+
static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
{
- return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q)=
;
+ return !skb_queue_empty(&tid->retry_q) || tid->has_queued;
}
=20
static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
@@ -184,46 +236,11 @@ static struct sk_buff *ath_tid_dequeue(struct ath_a=
tx_tid *tid)
=20
skb =3D __skb_dequeue(&tid->retry_q);
if (!skb)
- skb =3D __skb_dequeue(&tid->buf_q);
+ skb =3D ath_tid_pull(tid);
=20
return skb;
}
=20
-/*
- * ath_tx_tid_change_state:
- * - clears a-mpdu flag of previous session
- * - force sequence number allocation to fix next BlockAck Window
- */
-static void
-ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)
-{
- struct ath_txq *txq =3D tid->txq;
- struct ieee80211_tx_info *tx_info;
- struct sk_buff *skb, *tskb;
- struct ath_buf *bf;
- struct ath_frame_info *fi;
-
- skb_queue_walk_safe(&tid->buf_q, skb, tskb) {
- fi =3D get_frame_info(skb);
- bf =3D fi->bf;
-
- tx_info =3D IEEE80211_SKB_CB(skb);
- tx_info->flags &=3D ~IEEE80211_TX_CTL_AMPDU;
-
- if (bf)
- continue;
-
- bf =3D ath_tx_setup_buffer(sc, txq, tid, skb);
- if (!bf) {
- __skb_unlink(skb, &tid->buf_q);
- ath_txq_skb_done(sc, txq, skb);
- ieee80211_free_txskb(sc->hw, skb);
- continue;
- }
- }
-
-}
-
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *t=
id)
{
struct ath_txq *txq =3D tid->txq;
@@ -858,20 +875,16 @@ static int ath_compute_num_delims(struct ath_softc =
*sc, struct ath_atx_tid *tid,
=20
static struct ath_buf *
ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_atx_tid *tid, struct sk_buff_head **q)
+ struct ath_atx_tid *tid)
{
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
- struct sk_buff *skb;
+ struct sk_buff *skb, *first_skb =3D NULL;
struct ath_buf *bf;
u16 seqno;
=20
while (1) {
- *q =3D &tid->retry_q;
- if (skb_queue_empty(*q))
- *q =3D &tid->buf_q;
-
- skb =3D skb_peek(*q);
+ skb =3D ath_tid_dequeue(tid);
if (!skb)
break;
=20
@@ -883,7 +896,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct =
ath_txq *txq,
bf->bf_state.stale =3D false;
=20
if (!bf) {
- __skb_unlink(skb, *q);
ath_txq_skb_done(sc, txq, skb);
ieee80211_free_txskb(sc->hw, skb);
continue;
@@ -912,8 +924,20 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct=
ath_txq *txq,
seqno =3D bf->bf_state.seqno;
=20
/* do not step over block-ack window */
- if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
+ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
+ __skb_queue_tail(&tid->retry_q, skb);
+
+ /* If there are other skbs in the retry q, they are
+ * probably within the BAW, so loop immediately to get
+ * one of them. Otherwise the queue can get stuck. */
+ if (!skb_queue_is_first(&tid->retry_q, skb) &&
+ !WARN_ON(skb =3D=3D first_skb)) {
+ if(!first_skb) /* infinite loop prevention */
+ first_skb =3D skb;
+ continue;
+ }
break;
+ }
=20
if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
struct ath_tx_status ts =3D {};
@@ -921,7 +945,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct =
ath_txq *txq,
=20
INIT_LIST_HEAD(&bf_head);
list_add(&bf->list, &bf_head);
- __skb_unlink(skb, *q);
ath_tx_update_baw(sc, tid, seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
continue;
@@ -933,11 +956,10 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struc=
t ath_txq *txq,
return NULL;
}
=20
-static bool
+static int
ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q,
- int *aggr_len)
+ struct ath_buf *bf_first)
{
#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
struct ath_buf *bf =3D bf_first, *bf_prev =3D NULL;
@@ -947,12 +969,13 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_t=
xq *txq,
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
struct sk_buff *skb;
- bool closed =3D false;
+
=20
bf =3D bf_first;
aggr_limit =3D ath_lookup_rate(sc, bf, tid);
=20
- do {
+ while (bf)
+ {
skb =3D bf->bf_mpdu;
fi =3D get_frame_info(skb);
=20
@@ -961,12 +984,12 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_t=
xq *txq,
if (nframes) {
if (aggr_limit < al + bpad + al_delta ||
ath_lookup_legacy(bf) || nframes >=3D h_baw)
- break;
+ goto stop;
=20
tx_info =3D IEEE80211_SKB_CB(bf->bf_mpdu);
if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
!(tx_info->flags & IEEE80211_TX_CTL_AMPDU))
- break;
+ goto stop;
}
=20
/* add padding for previous frame to aggregation length */
@@ -988,20 +1011,18 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_=
txq *txq,
ath_tx_addto_baw(sc, tid, bf);
bf->bf_state.ndelim =3D ndelim;
=20
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next =3D bf;
=20
bf_prev =3D bf;
=20
- bf =3D ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
- if (!bf) {
- closed =3D true;
- break;
- }
- } while (ath_tid_has_buffered(tid));
-
+ bf =3D ath_tx_get_tid_subframe(sc, txq, tid);
+ }
+ goto finish;
+stop:
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
+finish:
bf =3D bf_first;
bf->bf_lastbf =3D bf_prev;
=20
@@ -1012,9 +1033,7 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_t=
xq *txq,
TX_STAT_INC(txq->axq_qnum, a_aggr);
}
=20
- *aggr_len =3D al;
-
- return closed;
+ return al;
#undef PADBYTES
}
=20
@@ -1391,18 +1410,15 @@ static void ath_tx_fill_desc(struct ath_softc *sc=
, struct ath_buf *bf,
static void
ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q)
+ struct ath_buf *bf_first)
{
struct ath_buf *bf =3D bf_first, *bf_prev =3D NULL;
- struct sk_buff *skb;
int nframes =3D 0;
=20
do {
struct ieee80211_tx_info *tx_info;
- skb =3D bf->bf_mpdu;
=20
nframes++;
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next =3D bf;
@@ -1411,13 +1427,15 @@ ath_tx_form_burst(struct ath_softc *sc, struct at=
h_txq *txq,
if (nframes >=3D 2)
break;
=20
- bf =3D ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf =3D ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
break;
=20
tx_info =3D IEEE80211_SKB_CB(bf->bf_mpdu);
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
break;
+ }
=20
ath_set_rates(tid->an->vif, tid->an->sta, bf);
} while (1);
@@ -1428,34 +1446,33 @@ static bool ath_tx_sched_aggr(struct ath_softc *s=
c, struct ath_txq *txq,
{
struct ath_buf *bf;
struct ieee80211_tx_info *tx_info;
- struct sk_buff_head *tid_q;
struct list_head bf_q;
int aggr_len =3D 0;
- bool aggr, last =3D true;
+ bool aggr;
=20
if (!ath_tid_has_buffered(tid))
return false;
=20
INIT_LIST_HEAD(&bf_q);
=20
- bf =3D ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf =3D ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
return false;
=20
tx_info =3D IEEE80211_SKB_CB(bf->bf_mpdu);
aggr =3D !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
if ((aggr && txq->axq_ampdu_depth >=3D ATH_AGGR_MIN_QDEPTH) ||
- (!aggr && txq->axq_depth >=3D ATH_NON_AGGR_MIN_QDEPTH)) {
+ (!aggr && txq->axq_depth >=3D ATH_NON_AGGR_MIN_QDEPTH)) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
*stop =3D true;
return false;
}
=20
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (aggr)
- last =3D ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
- tid_q, &aggr_len);
+ aggr_len =3D ath_tx_form_aggr(sc, txq, tid, &bf_q, bf);
else
- ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q);
+ ath_tx_form_burst(sc, txq, tid, &bf_q, bf);
=20
if (list_empty(&bf_q))
return false;
@@ -1498,9 +1515,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct =
ieee80211_sta *sta,
an->mpdudensity =3D density;
}
=20
- /* force sequence number allocation for pending frames */
- ath_tx_tid_change_state(sc, txtid);
-
txtid->active =3D true;
*ssn =3D txtid->seq_start =3D txtid->seq_next;
txtid->bar_index =3D -1;
@@ -1525,7 +1539,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct =
ieee80211_sta *sta, u16 tid)
ath_txq_lock(sc, txq);
txtid->active =3D false;
ath_tx_flush_tid(sc, txtid);
- ath_tx_tid_change_state(sc, txtid);
ath_txq_unlock_complete(sc, txq);
}
=20
@@ -1535,14 +1548,12 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta,=
struct ath_softc *sc,
struct ath_common *common =3D ath9k_hw_common(sc->sc_ah);
struct ath_atx_tid *tid;
struct ath_txq *txq;
- bool buffered;
int tidno;
=20
ath_dbg(common, XMIT, "%s called\n", __func__);
=20
- for (tidno =3D 0, tid =3D &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
-
+ for (tidno =3D 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid =3D ath_node_to_tid(an, tidno);
txq =3D tid->txq;
=20
ath_txq_lock(sc, txq);
@@ -1552,13 +1563,12 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta,=
struct ath_softc *sc,
continue;
}
=20
- buffered =3D ath_tid_has_buffered(tid);
+ if (!skb_queue_empty(&tid->retry_q))
+ ieee80211_sta_set_buffered(sta, tid->tidno, true);
=20
list_del_init(&tid->list);
=20
ath_txq_unlock(sc, txq);
-
- ieee80211_sta_set_buffered(sta, tidno, buffered);
}
}
=20
@@ -1571,49 +1581,20 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, str=
uct ath_node *an)
=20
ath_dbg(common, XMIT, "%s called\n", __func__);
=20
- for (tidno =3D 0, tid =3D &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
-
+ for (tidno =3D 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid =3D ath_node_to_tid(an, tidno);
txq =3D tid->txq;
=20
ath_txq_lock(sc, txq);
tid->clear_ps_filter =3D true;
-
if (ath_tid_has_buffered(tid)) {
ath_tx_queue_tid(sc, txq, tid);
ath_txq_schedule(sc, txq);
}
-
ath_txq_unlock_complete(sc, txq);
}
}
=20
-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
- u16 tidno)
-{
- struct ath_common *common =3D ath9k_hw_common(sc->sc_ah);
- struct ath_atx_tid *tid;
- struct ath_node *an;
- struct ath_txq *txq;
-
- ath_dbg(common, XMIT, "%s called\n", __func__);
-
- an =3D (struct ath_node *)sta->drv_priv;
- tid =3D ATH_AN_2_TID(an, tidno);
- txq =3D tid->txq;
-
- ath_txq_lock(sc, txq);
-
- tid->baw_size =3D IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
-
- if (ath_tid_has_buffered(tid)) {
- ath_tx_queue_tid(sc, txq, tid);
- ath_txq_schedule(sc, txq);
- }
-
- ath_txq_unlock_complete(sc, txq);
-}
-
void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u16 tids, int nframes,
@@ -1626,7 +1607,6 @@ void ath9k_release_buffered_frames(struct ieee80211=
_hw *hw,
struct ieee80211_tx_info *info;
struct list_head bf_q;
struct ath_buf *bf_tail =3D NULL, *bf;
- struct sk_buff_head *tid_q;
int sent =3D 0;
int i;
=20
@@ -1641,11 +1621,10 @@ void ath9k_release_buffered_frames(struct ieee802=
11_hw *hw,
=20
ath_txq_lock(sc, tid->txq);
while (nframes > 0) {
- bf =3D ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q);
+ bf =3D ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid);
if (!bf)
break;
=20
- __skb_unlink(bf->bf_mpdu, tid_q);
list_add_tail(&bf->list, &bf_q);
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (bf_isampdu(bf)) {
@@ -1660,7 +1639,7 @@ void ath9k_release_buffered_frames(struct ieee80211=
_hw *hw,
sent++;
TX_STAT_INC(txq->axq_qnum, a_queued_hw);
=20
- if (an->sta && !ath_tid_has_buffered(tid))
+ if (an->sta && skb_queue_empty(&tid->retry_q))
ieee80211_sta_set_buffered(an->sta, i, false);
}
ath_txq_unlock_complete(sc, tid->txq);
@@ -1887,13 +1866,7 @@ bool ath_drain_all_txq(struct ath_softc *sc)
if (!ATH_TXQ_SETUP(sc, i))
continue;
=20
- /*
- * The caller will resume queues with ieee80211_wake_queues.
- * Mark the queue as not stopped to prevent ath_tx_complete
- * from waking the queue too early.
- */
txq =3D &sc->tx.txq[i];
- txq->stopped =3D false;
ath_draintxq(sc, txq);
}
=20
@@ -2292,16 +2265,14 @@ int ath_tx_start(struct ieee80211_hw *hw, struct =
sk_buff *skb,
struct ath_softc *sc =3D hw->priv;
struct ath_txq *txq =3D txctl->txq;
struct ath_atx_tid *tid =3D NULL;
+ struct ath_node *an =3D NULL;
struct ath_buf *bf;
- bool queue, skip_uapsd =3D false, ps_resp;
+ bool ps_resp;
int q, ret;
=20
if (vif)
avp =3D (void *)vif->drv_priv;
=20
- if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
- txctl->force_channel =3D true;
-
ps_resp =3D !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
=20
ret =3D ath_tx_prepare(hw, skb, txctl);
@@ -2316,63 +2287,18 @@ int ath_tx_start(struct ieee80211_hw *hw, struct =
sk_buff *skb,
=20
q =3D skb_get_queue_mapping(skb);
=20
- ath_txq_lock(sc, txq);
- if (txq =3D=3D sc->tx.txq_map[q]) {
- fi->txq =3D q;
- if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
- !txq->stopped) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_stop_queue(sc->hw, info->hw_queue);
- else
- ieee80211_stop_queue(sc->hw, q);
- txq->stopped =3D true;
- }
- }
-
- queue =3D ieee80211_is_data_present(hdr->frame_control);
-
- /* If chanctx, queue all null frames while NOA could be there */
- if (ath9k_is_chanctx_enabled() &&
- ieee80211_is_nullfunc(hdr->frame_control) &&
- !txctl->force_channel)
- queue =3D true;
-
- /* Force queueing of all frames that belong to a virtual interface on
- * a different channel context, to ensure that they are sent on the
- * correct channel.
- */
- if (((avp && avp->chanctx !=3D sc->cur_chan) ||
- sc->cur_chan->stopped) && !txctl->force_channel) {
- if (!txctl->an)
- txctl->an =3D &avp->mcast_node;
- queue =3D true;
- skip_uapsd =3D true;
- }
-
- if (txctl->an && queue)
- tid =3D ath_get_skb_tid(sc, txctl->an, skb);
-
- if (!skip_uapsd && ps_resp) {
- ath_txq_unlock(sc, txq);
+ if (ps_resp)
txq =3D sc->tx.uapsdq;
- ath_txq_lock(sc, txq);
- } else if (txctl->an && queue) {
- WARN_ON(tid->txq !=3D txctl->txq);
=20
- if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
- tid->clear_ps_filter =3D true;
-
- /*
- * Add this frame to software queue for scheduling later
- * for aggregation.
- */
- TX_STAT_INC(txq->axq_qnum, a_queued_sw);
- __skb_queue_tail(&tid->buf_q, skb);
- if (!txctl->an->sleeping)
- ath_tx_queue_tid(sc, txq, tid);
+ if (txctl->sta) {
+ an =3D (struct ath_node *) sta->drv_priv;
+ tid =3D ath_get_skb_tid(sc, an, skb);
+ }
=20
- ath_txq_schedule(sc, txq);
- goto out;
+ ath_txq_lock(sc, txq);
+ if (txq =3D=3D sc->tx.txq_map[q]) {
+ fi->txq =3D q;
+ ++txq->pending_frames;
}
=20
bf =3D ath_tx_setup_buffer(sc, txq, tid, skb);
@@ -2856,9 +2782,8 @@ void ath_tx_node_init(struct ath_softc *sc, struct =
ath_node *an)
struct ath_atx_tid *tid;
int tidno, acno;
=20
- for (tidno =3D 0, tid =3D &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS;
- tidno++, tid++) {
+ for (tidno =3D 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid =3D ath_node_to_tid(an, tidno);
tid->an =3D an;
tid->tidno =3D tidno;
tid->seq_start =3D tid->seq_next =3D 0;
@@ -2866,11 +2791,14 @@ void ath_tx_node_init(struct ath_softc *sc, struc=
t ath_node *an)
tid->baw_head =3D tid->baw_tail =3D 0;
tid->active =3D false;
tid->clear_ps_filter =3D true;
- __skb_queue_head_init(&tid->buf_q);
+ tid->has_queued =3D false;
__skb_queue_head_init(&tid->retry_q);
INIT_LIST_HEAD(&tid->list);
acno =3D TID_TO_WME_AC(tidno);
tid->txq =3D sc->tx.txq_map[acno];
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
=20
@@ -2880,9 +2808,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, stru=
ct ath_node *an)
struct ath_txq *txq;
int tidno;
=20
- for (tidno =3D 0, tid =3D &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
-
+ for (tidno =3D 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid =3D ath_node_to_tid(an, tidno);
txq =3D tid->txq;
=20
ath_txq_lock(sc, txq);
@@ -2894,6 +2821,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc, stru=
ct ath_node *an)
tid->active =3D false;
=20
ath_txq_unlock(sc, txq);
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
=20
--=20
2.9.3
^ permalink raw reply related
* Re: [PATCH v6] mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue.
From: Toke Høiland-Jørgensen @ 2016-09-02 14:44 UTC (permalink / raw)
To: make-wifi-fast; +Cc: linux-wireless
In-Reply-To: <20160902134104.29309-1-toke@toke.dk>
Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk> writes:
> The TXQ intermediate queues can cause packet reordering when more than
> one flow is active to a single station. Since some of the wifi-specific
> packet handling (notably sequence number and encryption handling) is
> sensitive to re-ordering, things break if they are applied before the
> TXQ.
>
> This splits up the TX handlers and fast_xmit logic into two parts: An
> early part and a late part. The former is applied before TXQ enqueue,
> and the latter after dequeue. The non-TXQ path just applies both parts
> at once.
>
> Because fragments shouldn't be split up or reordered, the fragmentation
> handler is run after dequeue. Any fragments are then kept in the TXQ and
> on subsequent dequeues they take precedence over dequeueing from the FQ
> structure.
>
> This approach avoids having to scatter special cases for when TXQ is
> enabled, at the cost of making the fast_xmit and TX handler code
> slightly more complex.
>
> Signed-off-by: Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk>
> ---
> Changes since v5:
> - Move the fragmentation handler to *after* TXQ dequeue. Fragments are
> kept in the TXQ for subsequent dequeues. This change also means that
> the changes to make some of the handlers fragmentation aware are no
> longer necessary.
> - One of the TX stats updates in the fast path was done before the
> enqueue step; move that to xmit_fast_finish().
> - Move the rate selection handler to after dequeue, so it's run closer
> to the time where the packet is actually transmitted.
Found one other thing that needs fixing shortly after posting this, but
figure that I'm probably not done anyway, so will leave it for the next
round. :)
-Toke
^ permalink raw reply
* Re: [PATCH] mwifiex: handle edmac vendor command
From: Kalle Valo @ 2016-09-02 14:56 UTC (permalink / raw)
To: Amitkumar Karwar; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <0fa2b5d5e09f4396a9c273c3c8dfc3db@SC-EXCH04.marvell.com>
Amitkumar Karwar <akarwar@marvell.com> writes:
>> Sorry for the delay. I have been thinking about vendor commands quite a
>> lot and I don't think they belong to upstream drivers. For regular use
>> cases (used by normal users) we have nl80211, for developer and testing
>> purposes we have debugfs and for manufacturing type of tests we have
>> nl80211 testmode interface. The focus of development should be adding
>> new functionality to nl80211 (and other generic interfaces), not to
>> driver specific vendor commands.
>>
>> I know brcm80211 and ti's wlcore have few vendor commands but I'm hoping
>> to remove them sometime soon.
>>
>> Thoughts?
>>
>
> Thanks for your reply.
>
> There is something called energy detect mode. Chip can detect non-WiFi
> radio signal also and monitor it for specified time before
> transmitting frames. As per ETSI specification, enabling this mode is
> mandatory for some countries for certain frequencies.
To me this looks this is something which can be generic, not a driver
specific interface. And why can't regulatory code enable this
automatically, without any user involvement? It already knows what
country we are in.
> The purpose of this patch is to configure the chip for working in this
> mode. I can see cfg80211 has a framework to handle vendor specific
> commands and events. I think having vendor commands would be helpful
> to support vendor specific functionalities which can't be generalized.
First of all, I don't see how the interface is mwifiex specific. If I
could trust that using vendor commands will not slow down the
development of nl80211, and other generic interfaces, I might think
otherwise. But at the moment I am nowhere near that.
> I suppose debugfs interface is only for collecting stats and info
> which can be used for debugging purpose.
Correct. I consider debugfs as a development and debugging interface for
developers and advanced users.
--
Kalle Valo
^ permalink raw reply
* Re: ath10k: Add WMI_SERVICE_PERIODIC_CHAN_STAT_SUPPORT wmi service
From: Kalle Valo @ 2016-09-02 15:26 UTC (permalink / raw)
To: c_traja; +Cc: ath10k, Tamizh chelvam, linux-wireless
In-Reply-To: <1470134594-10427-1-git-send-email-c_traja@qti.qualcomm.com>
c_traja@qti.qualcomm.com wrote:
> From: Tamizh chelvam <c_traja@qti.qualcomm.com>
>
> WMI_SERVICE_PERIODIC_CHAN_STAT_SUPPORT service has missed in
> the commit 7e247a9e88dc ("ath10k: add dynamic tx mode switch
> config support for qca4019"). This patch adds the service to
> avoid mismatch between host and target.
>
> Fixes:7e247a9e88dc ("ath10k: add dynamic tx mode switch config support for qca4019")
> Signed-off-by: Tamizh chelvam <c_traja@qti.qualcomm.com>
Thanks, 1 patch applied to ath-next branch of ath.git:
64ed5771aca2 ath10k: Add WMI_SERVICE_PERIODIC_CHAN_STAT_SUPPORT wmi service
--
Sent by pwcli
https://patchwork.kernel.org/patch/9255437/
^ permalink raw reply
* Re: ath10k: hide kernel addresses from logs using %pK format specifier
From: Kalle Valo @ 2016-09-02 15:29 UTC (permalink / raw)
To: c_mkenna; +Cc: ath10k, mkenna, linux-wireless, Maharaja Kennadyrajan
In-Reply-To: <1470318711-28986-1-git-send-email-c_mkenna@qti.qualcomm.com>
c_mkenna@qti.qualcomm.com wrote:
> From: Maharaja Kennadyrajan <c_mkenna@qti.qualcomm.com>
>
> With the %pK format specifier we hide the kernel addresses
> with the help of kptr_restrict sysctl.
> In this patch, %p is changed to %pK in the driver code.
>
> The sysctl is documented in Documentation/sysctl/kernel.txt.
>
> Signed-off-by: Maharaja Kennadyrajan <c_mkenna@qti.qualcomm.com>
Thanks, 1 patch applied to ath-next branch of ath.git:
75b34800a228 ath10k: hide kernel addresses from logs using %pK format specifier
--
Sent by pwcli
https://patchwork.kernel.org/patch/9263691/
^ permalink raw reply
* Re: [v2] ath10k: fix group privacy action frame decryption for qca4019
From: Kalle Valo @ 2016-09-02 15:38 UTC (permalink / raw)
To: Rajkumar Manoharan; +Cc: ath10k, linux-wireless, Rajkumar Manoharan, rmanohar
In-Reply-To: <20160809063151.25993-1-rmanohar@qti.qualcomm.com>
Rajkumar Manoharan <rmanohar@qti.qualcomm.com> wrote:
> Recent commit 'mac80211: Encrypt "Group addressed privacy" action frames'
> encrypts group privacy action frames. But qca99x0 family chipset delivers
> broadcast/multicast management frames as encrypted and it should be
> decrypted by mac80211. Setting RX_FLAG_DECRYPTED stats for those frames
> is breaking mesh connection establishment.
>
> Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
Thanks, 1 patch applied to ath-next branch of ath.git:
7d42298eb43d ath10k: fix group privacy action frame decryption for qca4019
--
Sent by pwcli
https://patchwork.kernel.org/patch/9270363/
^ permalink raw reply
* Re: [PATCH] ath10k: fix memory leak on caldata on error exit path
From: Valo, Kalle @ 2016-09-02 15:45 UTC (permalink / raw)
To: Colin King
Cc: ath10k@lists.infradead.org, linux-wireless@vger.kernel.org,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <1471268785-11576-1-git-send-email-colin.king@canonical.com>
Colin King <colin.king@canonical.com> writes:
> From: Colin Ian King <colin.king@canonical.com>
>
> caldata is not being free'd on the error exit path, causing
> a memory leak. kfree it to fix the leak.
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
> drivers/net/wireless/ath/ath10k/pci.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless=
/ath/ath10k/pci.c
> index 9a22c47..886337c 100644
> --- a/drivers/net/wireless/ath/ath10k/pci.c
> +++ b/drivers/net/wireless/ath/ath10k/pci.c
> @@ -2725,6 +2725,7 @@ static int ath10k_pci_hif_fetch_cal_eeprom(struct a=
th10k *ar, void **data,
> return 0;
> =20
> err_free:
> + kfree(caldata);
> kfree(data);
> =20
> return -EINVAL;
I don't think we should free data at all:
static int ath10k_download_cal_eeprom(struct ath10k *ar)
{
size_t data_len;
void *data =3D NULL;
int ret;
ret =3D ath10k_hif_fetch_cal_eeprom(ar, &data, &data_len);
Instead we should free only caldata, right?
--=20
Kalle Valo=
^ permalink raw reply
* Re: ath10k: suppress warnings when getting wmi WDS peer event id
From: Kalle Valo @ 2016-09-02 15:50 UTC (permalink / raw)
To: Mohammed Shafi Shajakhan
Cc: ath10k, mohammed, linux-wireless, Mohammed Shafi Shajakhan
In-Reply-To: <1471433280-15237-1-git-send-email-mohammed@qca.qualcomm.com>
Mohammed Shafi Shajakhan <mohammed@qti.qualcomm.com> wrote:
> From: Mohammed Shafi Shajakhan <mohammed@qti.qualcomm.com>
>
> 'WMI_10_4_WDS_PEER_EVENTID' is not yet handled/implemented for WDS mode,
> as of nowsuppress the warning message "Unknown eventid: 36903"
>
> Signed-off-by: Mohammed Shafi Shajakhan <mohammed@qti.qualcomm.com>
Thanks, 1 patch applied to ath-next branch of ath.git:
03c41cc126c8 ath10k: suppress warnings when getting wmi WDS peer event id
--
Sent by pwcli
https://patchwork.kernel.org/patch/9285623/
^ permalink raw reply
* Re: ath10k: improve wake_tx_queue ops performance
From: Kalle Valo @ 2016-09-02 15:52 UTC (permalink / raw)
To: Rajkumar Manoharan; +Cc: ath10k, linux-wireless, Rajkumar Manoharan, rmanohar
In-Reply-To: <20160817153253.6615-1-rmanohar@qti.qualcomm.com>
Rajkumar Manoharan <rmanohar@qti.qualcomm.com> wrote:
> txqs_lock is interfering with wake_tx_queue submitting more frames.
> so queues don't get filled in and don't keep firmware/hardware busy
> enough. This change helps to reduce the txqs_lock contention and
> wake_tx_queue() blockage to being possible in txrx_unref().
>
> To reduce turn around time of wake_tx_queue ops and to maintain fairness
> among all txqs, the callback is updated to push first txq alone from
> pending list for every wake_tx_queue call. Remaining txqs will be
> processed later upon tx completion.
>
> Below improvements are observed in push-only mode and validated on
> IPQ4019 platform. With this change, in AP mode ~10Mbps increase is
> observed in downlink (AP -> STA) traffic and approx. 5-10% of CPU
> usage is reduced.
>
> Major improvement is observed in 1-hop Mesh mode topology in 11ACVHT80.
> Compared to Infra mode, CPU overhead is higher in Mesh mode due to path
> lookup and no fast-xmit support. So reducing spin lock contention is
> helping in Mesh.
>
> TOT +change
> -------- --------
> TCP DL 545 Mbps 595 Mbps
> TCP UL 555 Mbps 585 Mbps
>
> Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
Thanks, 1 patch applied to ath-next branch of ath.git:
83e164b7679d ath10k: improve wake_tx_queue ops performance
--
Sent by pwcli
https://patchwork.kernel.org/patch/9286083/
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox