Linux wireless drivers development
 help / color / mirror / Atom feed
* [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

* 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 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: 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

* 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

* [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, &params.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: 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

* 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

* 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: [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

* 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

* [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

* [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] 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

* 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

* 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

* [PATCH] ath9k: bring back direction setting in ath9k_{start_stop}
From: Giedrius Statkevičius @ 2016-09-01 17:47 UTC (permalink / raw)
  To: kvalo
  Cc: ath9k-devel, linux-wireless, ath9k-devel, netdev, linux-kernel,
	Miaoqing Pan, Kalle Valo, stable, Giedrius Statkevičius

A regression was introduced in commit id 79d4db1214a ("ath9k: cleanup
led_pin initial") that broken the WLAN status led on my laptop with
AR9287 after suspending and resuming.

Steps to reproduce:
* Suspend (laptop)
* Resume (laptop)
* Observe that the WLAN led no longer turns ON/OFF depending on the
  status and is always red

Even though for my case it only needs to be set to OUT in ath9k_start
but for consistency bring back the IN direction setting as well.

Cc: Miaoqing Pan <miaoqing@codeaurora.org>
Cc: Kalle Valo <kvalo@qca.qualcomm.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Giedrius Statkevičius <giedrius.statkevicius@gmail.com>
---
This patch should be applied to all 4.7 and later kernels

Another user complaining about probably the same problem:
https://bugzilla.kernel.org/show_bug.cgi?id=151711

 drivers/net/wireless/ath/ath9k/main.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 8b63988..121dc05 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -718,9 +718,12 @@ static int ath9k_start(struct ieee80211_hw *hw)
 	if (!ath_complete_reset(sc, false))
 		ah->reset_power_on = false;
 
-	if (ah->led_pin >= 0)
+	if (ah->led_pin >= 0) {
 		ath9k_hw_set_gpio(ah, ah->led_pin,
 				  (ah->config.led_active_high) ? 1 : 0);
+		ath9k_hw_gpio_request_out(ah, ah->led_pin, NULL,
+					  AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+	}
 
 	/*
 	 * Reset key cache to sane defaults (all entries cleared) instead of
@@ -864,9 +867,11 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
 	spin_lock_bh(&sc->sc_pcu_lock);
 
-	if (ah->led_pin >= 0)
+	if (ah->led_pin >= 0) {
 		ath9k_hw_set_gpio(ah, ah->led_pin,
 				  (ah->config.led_active_high) ? 0 : 1);
+		ath9k_hw_gpio_request_in(ah, ah->led_pin, NULL);
+	}
 
 	ath_prepare_reset(sc);
 
-- 
2.9.3

^ permalink raw reply related

* Re: [PATCH v5] mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue.
From: Johannes Berg @ 2016-09-01 17:59 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen, make-wifi-fast, linux-wireless
In-Reply-To: <20160901160312.31540-1-toke@toke.dk>


> To avoid having to deal with fragmentation on dequeue, the split is
> set to be after the fragmentation handler. This means that some
> reordering of TX handlers is necessary, and some handlers had to be
> made aware of fragmentation due to this reordering.

Come to think of it, that's actually counterproductive.

If a fragment is dropped, or even just if fragments are reordered, the
receiver will not be able to defragment the frame, and will thus drop
it. Therefore, it's all-or-nothing, and we shouldn't transmit any
fragment if we drop/reorder one (*).

So ... I think you'll just have to deal with fragmentation on the
codel/fq/whatever queues and keep fragments together, or do
fragmentation afterwards.

johannes


(*) also, couldn't this mean that we send something completely stupid
like

seq=1,frag=0
seq=2,frag=0
seq=2,frag=1
seq=2,frag=1

if reordering happened?

^ permalink raw reply

* Re: Ath10k probe response error related to mac80211 commit.
From: Ben Greear @ 2016-09-01 19:00 UTC (permalink / raw)
  To: Johannes Berg, linux-wireless@vger.kernel.org
In-Reply-To: <1472756034.9608.15.camel@sipsolutions.net>

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.

It took so much time because for whatever reason git bisect couldn't
find the issue, and I spent a day thinking it was in ath10k driver and
poking hard at that.

Anyway, no worries...it happens, and could easily just be a bug in
my firmware modifications that are somehow triggered by this.

>> 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.

'makes no sense' is the ath10k motto.

I have verified that it is not an obvious difference in the ath10k driver
though...copying 4.5 ath10k driver onto 4.4 works fine, and copying 4.4
ath10k driver into 4.5 is broken.

I don't think any stations connect, but I didn't look precisely for that
yet.  I know the stations I'm trying to connect will not.

Thanks,
Ben


-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply

* Re: pull-request: wireless-drivers 2016-08-29
From: David Miller @ 2016-09-01 21:11 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <87h9a3iekv.fsf@kamboji.qca.qualcomm.com>

From: Kalle Valo <kvalo@codeaurora.org>
Date: Mon, 29 Aug 2016 22:02:08 +0300

> I'm quite backlogged after coming back from my vacation but luckily it
> has been pretty quiet. Here is the first batch of patches for 4.8, quite
> simple actually and not really anything special to mention. More to come
> later, most probably next week. Please let me know if there are any
> problems.

Pulled, thanks Kalle.

^ permalink raw reply

* Re: Ath10k probe response error related to mac80211 commit.
From: Johannes Berg @ 2016-09-01 18:53 UTC (permalink / raw)
  To: Ben Greear, linux-wireless@vger.kernel.org
In-Reply-To: <c7eb32b4-84c5-41ae-1fe6-89df7cbbe7d4@candelatech.com>

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.

johannes

^ permalink raw reply

* Re: [PATCH v5] mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue.
From: Johannes Berg @ 2016-09-01 18:35 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen; +Cc: make-wifi-fast, linux-wireless
In-Reply-To: <871t1379r0.fsf@toke.dk>

On Thu, 2016-09-01 at 20:30 +0200, Toke Høiland-Jørgensen wrote:

> > seq=1,frag=0
> > seq=2,frag=0
> > seq=2,frag=1
> > seq=2,frag=1
> > 
> > if reordering happened?
> 
> (assuming the last line was supposed to read 'seq=1,frag=1')

I did actually mean seq=2,frag=1, since the seqno assignment happened
after fragmentation in your patch, and after codel reordering, and
would not change the seqno until it encountered a frag=0 packet.

Or maybe that was only with the previous version of the patch.

> When does fragmentation happen anyway? Is it safe to assume there's
> no aggregation when it does?
> 

Yes, fragmented packets are not allowed to be aggregated.

johannes

^ permalink raw reply

* Re: Ath10k probe response error related to mac80211 commit.
From: Ben Greear @ 2016-09-01 20:52 UTC (permalink / raw)
  To: Johannes Berg, linux-wireless@vger.kernel.org, ath10k
In-Reply-To: <1472756034.9608.15.camel@sipsolutions.net>

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.

I am guessing that somehow this mac80211 change creates a peer early
that does not have the qos logic enabled, and so that is why I suddenly
started hitting this bug.

Probably stock firmware is OK since it uses a second tx path for management,
and I guess that by whatever time it starts sending non-mgt frames the
qos-enabled logic is set properly.

I can fix this in my firmware by making it not over-ride the TID in
this case.

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply

* Re: [PATCH v5] mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue.
From: Toke Høiland-Jørgensen @ 2016-09-01 18:30 UTC (permalink / raw)
  To: Johannes Berg; +Cc: make-wifi-fast, linux-wireless
In-Reply-To: <1472752745.9608.8.camel@sipsolutions.net>

Johannes Berg <johannes@sipsolutions.net> writes:

>> To avoid having to deal with fragmentation on dequeue, the split is
>> set to be after the fragmentation handler. This means that some
>> reordering of TX handlers is necessary, and some handlers had to be
>> made aware of fragmentation due to this reordering.
>
> Come to think of it, that's actually counterproductive.
>
> If a fragment is dropped, or even just if fragments are reordered, the
> receiver will not be able to defragment the frame, and will thus drop
> it. Therefore, it's all-or-nothing, and we shouldn't transmit any
> fragment if we drop/reorder one (*).
>
> So ... I think you'll just have to deal with fragmentation on the
> codel/fq/whatever queues and keep fragments together, or do
> fragmentation afterwards.

Hmm, guess that makes sense. Bugger. Will think about how to do that.

>
> johannes
>
> (*) also, couldn't this mean that we send something completely stupid
> like
>
> seq=1,frag=0
> seq=2,frag=0
> seq=2,frag=1
> seq=2,frag=1
>
> if reordering happened?

(assuming the last line was supposed to read 'seq=1,frag=1')

Yes, that could happen, in principle (it depends on the fragments' size
in relation to the FQ quantum).


When does fragmentation happen anyway? Is it safe to assume there's no
aggregation when it does?

-Toke

^ permalink raw reply

* Re: Ath10k probe response error related to mac80211 commit.
From: Ben Greear @ 2016-09-01 18:23 UTC (permalink / raw)
  To: Johannes Berg, linux-wireless@vger.kernel.org
In-Reply-To: <1472752911.9608.11.camel@sipsolutions.net>

On 09/01/2016 11:01 AM, Johannes Berg wrote:
>
>> 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.

Could easily be that others are corrupted too, but since probe resp is bad,
the association will not proceed.

>
>> 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 :)

Heh, I spent 4 days tracking this down, so I wanted to be precise in
my bug report :)

> 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).

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.

Since this only happens (as far as I know) with my modified firmware, then
I will try to fix it there.  Or, possibly I can change ath10k driver to flip this
mac80211 flag when loading my firmware variant if firmware cannot be easily fixed.

Thanks for the info,
--Ben

>
> johannes
>


-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox