From kvalo at qca.qualcomm.com  Mon Nov  3 15:06:06 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 4 Nov 2014 01:06:06 +0200
Subject: [PATCH v3] ath10k: fix pm resume after suspend
In-Reply-To: <1414742623-308-1-git-send-email-bartosz.markowski@tieto.com>
 (Bartosz Markowski's message of "Fri, 31 Oct 2014 09:03:43 +0100")
References: <1414742623-308-1-git-send-email-bartosz.markowski@tieto.com>
Message-ID: <87d2937uld.fsf@kamboji.qca.qualcomm.com>

Bartosz Markowski <bartosz.markowski at tieto.com> writes:

> Firmware was crashing when we were trying to warm reset it
> after suspend. This was due to the fact that target registeres
> can be accessed only if the hardware is awaken.
>
> This patch makes sure to awake the device also on the hif up,
> not only in case of probe call.
>
> Signed-off-by: Bartosz Markowski <bartosz.markowski at tieto.com>

Thanks, applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov  3 15:34:37 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 4 Nov 2014 01:34:37 +0200
Subject: [PATCH v2] ath10k: handle ieee80211 header and payload tracing
 separately
In-Reply-To: <1414661336-20764-1-git-send-email-rmanohar@qti.qualcomm.com>
 (Rajkumar Manoharan's message of "Thu, 30 Oct 2014 14:58:56 +0530")
References: <1414661336-20764-1-git-send-email-rmanohar@qti.qualcomm.com>
Message-ID: <874muf7t9u.fsf@kamboji.qca.qualcomm.com>

Rajkumar Manoharan <rmanohar at qti.qualcomm.com> writes:

> For packet log, the transmitted frame 802.11 header alone is sufficient.
> Recording entire packet is also consuming lot of disk space. To optimize
> this, tx and rx data tracepoints are splitted into header and payload
> tracepoints.
>
> To record tx ieee80211 headers
>
>      trace-cmd record -e ath10k_tx_hdr
>
> To record complete packets
>
>      trace-cmd record -e ath10k_tx_hdr -e ath10k_tx_payload
>
> Cc: Michal Kazior <michal.kazior at tieto.com>
> Signed-off-by: Rajkumar Manoharan <rmanohar at qti.qualcomm.com>

[...]

> --- a/drivers/net/wireless/ath/ath10k/trace.h
> +++ b/drivers/net/wireless/ath/ath10k/trace.h
> @@ -341,7 +341,10 @@ TRACE_EVENT(ath10k_txrx_tx_unref,
>  	 )
>  );
>  
> -DECLARE_EVENT_CLASS(ath10k_data_event,
> +#define ATH10K_FRM_HDR_LEN  \
> +	ieee80211_hdrlen(((struct ieee80211_hdr *)data)->frame_control)

This macro does not look good. I would recommend to follow what Johannes
suggested:

"It would be worth hiding that inside the tracepoint's assign function,
so instead of passing data/len here you'd pass the full skb, or the full
skb data/skb len, like this:

ar, skb->data, skb->len

to both tracers. Then inside the tracer you can do the hdrlen check, and
that way move the code into the tracing so it's not hit when tracing is
disabled."

-- 
Kalle Valo


From greearb at candelatech.com  Mon Nov  3 17:04:28 2014
From: greearb at candelatech.com (Ben Greear)
Date: Mon, 03 Nov 2014 17:04:28 -0800
Subject: Slow connect times?
Message-ID: <5458261C.2020700@candelatech.com>

If I am reading my results right, it takes over 2 seconds to associate an
ath10k station with WPA2 PSK on my systems.

I was thinking this should be quite a bit faster than this...

Has anyone done any similar measurements?

Thanks,
Ben

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



From sujith at msujith.org  Mon Nov  3 17:06:47 2014
From: sujith at msujith.org (Sujith Manoharan)
Date: Tue, 4 Nov 2014 06:36:47 +0530
Subject: [ath9k-devel] Support for killer n1525
In-Reply-To: <CAAmLN2bKERAoiAjpe-wtSC6xHEZqcNtEmPUZOpLfy03MNpYQGA@mail.gmail.com>
References: <CAAmLN2bKERAoiAjpe-wtSC6xHEZqcNtEmPUZOpLfy03MNpYQGA@mail.gmail.com>
Message-ID: <21592.9895.190054.349562@gargle.gargle.HOWL>

Joris Guisson wrote:
> I recently purchased an MSI GT 72 gaming laptop with a killer n1525 wifi card
> in it. The wifi didn't work, so I took a look at the latest kernel release
> (3.18-rc3), and it seems there is no support in it for the card. I didn't find
> the PCI device id (0x003e) listed in any of the atheros drivers, the only
> killer related entries where in ath9k:
> 
> It may just be a matter of adding a new device ID entry in the table above, if
> the NIC more or less works like previous killer NIC's.

This card/HW is not supported by ath9k. I think work is ongoing to add
support for this HW family to ath10k.

Sujith


From apenwarr at gmail.com  Mon Nov  3 17:35:15 2014
From: apenwarr at gmail.com (Avery Pennarun)
Date: Mon, 3 Nov 2014 20:35:15 -0500
Subject: Slow connect times?
In-Reply-To: <5458261C.2020700@candelatech.com>
References: <5458261C.2020700@candelatech.com>
Message-ID: <CAHqTa-21YOPiV_UxxWh23mB7AqLhj0n+h6eA5cTUH8eh32heRw@mail.gmail.com>

On Mon, Nov 3, 2014 at 8:04 PM, Ben Greear <greearb at candelatech.com> wrote:
> If I am reading my results right, it takes over 2 seconds to associate an
> ath10k station with WPA2 PSK on my systems.
>
> I was thinking this should be quite a bit faster than this...
>
> Has anyone done any similar measurements?

I haven't noticed any delay like this.  WPA2 PSK negotiation is on the
order of ~200ms or less. Then DHCP screws around for a few seconds,
often.

A packet trace would probably be useful for narrowing it down :)


From greearb at candelatech.com  Mon Nov  3 18:45:08 2014
From: greearb at candelatech.com (Ben Greear)
Date: Mon, 03 Nov 2014 18:45:08 -0800
Subject: Slow connect times?
In-Reply-To: <CAHqTa-21YOPiV_UxxWh23mB7AqLhj0n+h6eA5cTUH8eh32heRw@mail.gmail.com>
References: <5458261C.2020700@candelatech.com>
 <CAHqTa-21YOPiV_UxxWh23mB7AqLhj0n+h6eA5cTUH8eh32heRw@mail.gmail.com>
Message-ID: <54583DB4.1030808@candelatech.com>



On 11/03/2014 05:35 PM, Avery Pennarun wrote:
> On Mon, Nov 3, 2014 at 8:04 PM, Ben Greear <greearb at candelatech.com> wrote:
>> If I am reading my results right, it takes over 2 seconds to associate an
>> ath10k station with WPA2 PSK on my systems.
>>
>> I was thinking this should be quite a bit faster than this...
>>
>> Has anyone done any similar measurements?
>
> I haven't noticed any delay like this.  WPA2 PSK negotiation is on the
> order of ~200ms or less. Then DHCP screws around for a few seconds,
> often.
>
> A packet trace would probably be useful for narrowing it down :)


Could be something weird with my setup.  I'll dig into it some more sometime
soon.

Thanks,
Ben

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


From rmanohar at qti.qualcomm.com  Mon Nov  3 21:16:45 2014
From: rmanohar at qti.qualcomm.com (Rajkumar Manoharan)
Date: Tue, 4 Nov 2014 10:46:45 +0530
Subject: [PATCH v2] ath10k: handle ieee80211 header and payload tracing
 separately
In-Reply-To: <874muf7t9u.fsf@kamboji.qca.qualcomm.com>
References: <1414661336-20764-1-git-send-email-rmanohar@qti.qualcomm.com>
 <874muf7t9u.fsf@kamboji.qca.qualcomm.com>
Message-ID: <20141104051643.GA14509@qca.qualcomm.com>

On Tue, Nov 04, 2014 at 01:34:37AM +0200, Kalle Valo wrote:
> Rajkumar Manoharan <rmanohar at qti.qualcomm.com> writes:
> 
> > For packet log, the transmitted frame 802.11 header alone is sufficient.
> > Recording entire packet is also consuming lot of disk space. To optimize
> > this, tx and rx data tracepoints are splitted into header and payload
> > tracepoints.
> >  
> > -DECLARE_EVENT_CLASS(ath10k_data_event,
> > +#define ATH10K_FRM_HDR_LEN  \
> > +	ieee80211_hdrlen(((struct ieee80211_hdr *)data)->frame_control)
> 
> This macro does not look good. I would recommend to follow what Johannes
> suggested:
>
> "It would be worth hiding that inside the tracepoint's assign function,
> so instead of passing data/len here you'd pass the full skb, or the full
> skb data/skb len, like this:
> 
> ar, skb->data, skb->len
> 
> to both tracers. Then inside the tracer you can do the hdrlen check, and
> that way move the code into the tracing so it's not hit when tracing is
> disabled."
v2 does the same. tracing functions just take ar, skb->data and skb->len.
header check is handled inside tracing funtions.

I do not understand your concerns. :(

-Rajkumar


From michal.kazior at tieto.com  Tue Nov  4 06:22:06 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue,  4 Nov 2014 15:22:06 +0100
Subject: [PATCH 2/7] ath10k: simplify Rx loop
In-Reply-To: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
References: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1415110931-10945-3-git-send-email-michal.kazior@tieto.com>

Since htt_rx_mpdu_status isn't used anymore
(instead attention flags are used) simplify the
loop.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/htt_rx.c | 80 ++++++++++++++++----------------
 1 file changed, 39 insertions(+), 41 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 85f11e6..cba2f3b 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1197,8 +1197,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 	int fw_desc_len;
 	u8 *fw_desc;
 	bool channel_set;
-	int i, j;
-	int ret;
+	int i, ret, mpdu_count = 0;
 
 	lockdep_assert_held(&htt->rx_ring.lock);
 
@@ -1237,51 +1236,50 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 			(sizeof(struct htt_rx_indication_mpdu_range) *
 				num_mpdu_ranges));
 
-	for (i = 0; i < num_mpdu_ranges; i++) {
-		for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) {
-			attention = 0;
-			__skb_queue_head_init(&amsdu);
-			ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc,
-						      &fw_desc_len, &amsdu,
-						      &attention);
-
-			if (ret < 0) {
-				ath10k_warn(ar, "failed to pop amsdu from htt rx ring %d\n",
-					    ret);
-				__skb_queue_purge(&amsdu);
-				continue;
-			}
+	for (i = 0; i < num_mpdu_ranges; i++)
+		mpdu_count += mpdu_ranges[i].mpdu_count;
+
+	while (mpdu_count--) {
+		attention = 0;
+		__skb_queue_head_init(&amsdu);
+		ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc,
+					      &fw_desc_len, &amsdu,
+					      &attention);
+		if (ret < 0) {
+			ath10k_warn(ar, "failed to pop amsdu from htt rx ring %d\n",
+				    ret);
+			__skb_queue_purge(&amsdu);
+			continue;
+		}
 
-			if (!ath10k_htt_rx_amsdu_allowed(htt, skb_peek(&amsdu),
-							 channel_set,
-							 attention)) {
-				__skb_queue_purge(&amsdu);
-				continue;
-			}
+		if (!ath10k_htt_rx_amsdu_allowed(htt, skb_peek(&amsdu),
+						 channel_set, attention)) {
+			__skb_queue_purge(&amsdu);
+			continue;
+		}
 
-			if (ret > 0 && ath10k_unchain_msdu(&amsdu) < 0) {
-				__skb_queue_purge(&amsdu);
-				continue;
-			}
+		if (ret > 0 && ath10k_unchain_msdu(&amsdu) < 0) {
+			__skb_queue_purge(&amsdu);
+			continue;
+		}
 
-			if (attention & RX_ATTENTION_FLAGS_FCS_ERR)
-				rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
-			else
-				rx_status->flag &= ~RX_FLAG_FAILED_FCS_CRC;
+		if (attention & RX_ATTENTION_FLAGS_FCS_ERR)
+			rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+		else
+			rx_status->flag &= ~RX_FLAG_FAILED_FCS_CRC;
 
-			if (attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR)
-				rx_status->flag |= RX_FLAG_MMIC_ERROR;
-			else
-				rx_status->flag &= ~RX_FLAG_MMIC_ERROR;
+		if (attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR)
+			rx_status->flag |= RX_FLAG_MMIC_ERROR;
+		else
+			rx_status->flag &= ~RX_FLAG_MMIC_ERROR;
 
-			hdr = ath10k_htt_rx_skb_get_hdr(skb_peek(&amsdu));
+		hdr = ath10k_htt_rx_skb_get_hdr(skb_peek(&amsdu));
 
-			if (ath10k_htt_rx_hdr_is_amsdu(hdr))
-				ath10k_htt_rx_amsdu(htt, rx_status, &amsdu);
-			else
-				ath10k_htt_rx_msdu(htt, rx_status,
-						   __skb_dequeue(&amsdu));
-		}
+		if (ath10k_htt_rx_hdr_is_amsdu(hdr))
+			ath10k_htt_rx_amsdu(htt, rx_status, &amsdu);
+		else
+			ath10k_htt_rx_msdu(htt, rx_status,
+					   __skb_dequeue(&amsdu));
 	}
 
 	tasklet_schedule(&htt->rx_replenish_task);
-- 
1.8.5.3



From michal.kazior at tieto.com  Tue Nov  4 06:22:09 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue,  4 Nov 2014 15:22:09 +0100
Subject: [PATCH 5/7] ath10k: remove unused function argument
In-Reply-To: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
References: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1415110931-10945-6-git-send-email-michal.kazior@tieto.com>

The original fix has been moved into a different
place in the code.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/htt_rx.c | 16 +++-------------
 1 file changed, 3 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 6abfea7..55e4568 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -306,8 +306,7 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
 /* return: < 0 fatal error, 0 - non chained msdu, 1 chained msdu */
 static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
 				   u8 **fw_desc, int *fw_desc_len,
-				   struct sk_buff_head *amsdu,
-				   u32 *attention)
+				   struct sk_buff_head *amsdu)
 {
 	struct ath10k *ar = htt->ar;
 	int msdu_len, msdu_chaining = 0;
@@ -348,11 +347,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
 			return -EIO;
 		}
 
-		*attention |= __le32_to_cpu(rx_desc->attention.flags) &
-					    (RX_ATTENTION_FLAGS_TKIP_MIC_ERR |
-					     RX_ATTENTION_FLAGS_DECRYPT_ERR |
-					     RX_ATTENTION_FLAGS_FCS_ERR |
-					     RX_ATTENTION_FLAGS_MGMT_TYPE);
 		/*
 		 * Copy the FW rx descriptor for this MSDU from the rx
 		 * indication message into the MSDU's netbuf. HL uses the
@@ -1362,7 +1356,6 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 	struct htt_rx_indication_mpdu_range *mpdu_ranges;
 	struct sk_buff_head amsdu;
 	int num_mpdu_ranges;
-	u32 attention;
 	int fw_desc_len;
 	u8 *fw_desc;
 	bool channel_set;
@@ -1412,11 +1405,9 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 		mpdu_count += mpdu_ranges[i].mpdu_count;
 
 	while (mpdu_count--) {
-		attention = 0;
 		__skb_queue_head_init(&amsdu);
 		ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc,
-					      &fw_desc_len, &amsdu,
-					      &attention);
+					      &fw_desc_len, &amsdu);
 		if (ret < 0) {
 			ath10k_warn(ar, "rx ring became corrupted: %d\n", ret);
 			__skb_queue_purge(&amsdu);
@@ -1445,7 +1436,6 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
 	int ret;
 	u8 *fw_desc;
 	int fw_desc_len;
-	u32 attention = 0;
 
 	fw_desc_len = __le16_to_cpu(frag->fw_rx_desc_bytes);
 	fw_desc = (u8 *)frag->fw_msdu_rx_desc;
@@ -1454,7 +1444,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
 
 	spin_lock_bh(&htt->rx_ring.lock);
 	ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len,
-				      &amsdu, &attention);
+				      &amsdu);
 	spin_unlock_bh(&htt->rx_ring.lock);
 
 	tasklet_schedule(&htt->rx_replenish_task);
-- 
1.8.5.3



From michal.kazior at tieto.com  Tue Nov  4 06:22:11 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue,  4 Nov 2014 15:22:11 +0100
Subject: [PATCH 7/7] ath10k: report rx rate and signal for fragmented Rx
In-Reply-To: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
References: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1415110931-10945-8-git-send-email-michal.kazior@tieto.com>

Fragmented Rx wasn't reporting everything. With
the reworked Rx code it's very easy to fix it.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/htt_rx.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 9073a0e..a22e832 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1519,9 +1519,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
 		return;
 	}
 
-	/* FIXME: implement signal strength */
-	rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
-
+	ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status);
 	ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
 	ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
 	ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
-- 
1.8.5.3



From michal.kazior at tieto.com  Tue Nov  4 06:22:04 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue,  4 Nov 2014 15:22:04 +0100
Subject: [PATCH 0/7] ath10k: rework rx path
Message-ID: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>

Hi,

This patchset unifies rx path. Instead of
branching for A-MSDU and MSDU cases a single
codepath is introduced.

This yields:

   text    data     bss     dec     hex filename
  14068       0       0   14068    36f4 before/htt_rx.o
  13308       3       0   13311    33ff after/htt_rx.o

I haven't measured any Rx performance loss in my
setup but I may be biased. In theory this could
reduce i-cache pressure and improve Rx throughput
on CPU contrained systems by a few mbps.

This patchset serves two purposes though:
 - clean up and unify the Rx path a bit
 - make it possible to reuse code more easily in
   the future


Michal Kazior (7):
  ath10k: start using sk_buff_head
  ath10k: simplify Rx loop
  ath10k: refactor htt->rx_confused
  ath10k: unify rx undecapping
  ath10k: remove unused function argument
  ath10k: use rx descriptor for ppdu status extraction
  ath10k: report rx rate and signal for fragmented Rx

 drivers/net/wireless/ath/ath10k/htt_rx.c | 1063 ++++++++++++++++--------------
 1 file changed, 577 insertions(+), 486 deletions(-)

-- 
1.8.5.3



From michal.kazior at tieto.com  Tue Nov  4 06:22:07 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue,  4 Nov 2014 15:22:07 +0100
Subject: [PATCH 3/7] ath10k: refactor htt->rx_confused
In-Reply-To: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
References: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1415110931-10945-4-git-send-email-michal.kazior@tieto.com>

Make the rx_confused be handled by the rx
indication handlers instead of the buffer popping
function.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/htt_rx.c | 29 ++++++++++++-----------------
 1 file changed, 12 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index cba2f3b..651028e 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -316,20 +316,13 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
 
 	lockdep_assert_held(&htt->rx_ring.lock);
 
-	if (htt->rx_confused) {
-		ath10k_warn(ar, "htt is confused. refusing rx\n");
-		return -1;
-	}
-
 	for (;;) {
 		int last_msdu, msdu_len_invalid, msdu_chained;
 
 		msdu = ath10k_htt_rx_netbuf_pop(htt);
 		if (!msdu) {
-			ath10k_err(ar, "failed to pop msdu\n");
 			__skb_queue_purge(amsdu);
-			htt->rx_confused = true;
-			break;
+			return -ENOENT;
 		}
 
 		__skb_queue_tail(amsdu, msdu);
@@ -351,10 +344,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
 		 */
 		if (!(__le32_to_cpu(rx_desc->attention.flags)
 				& RX_ATTENTION_FLAGS_MSDU_DONE)) {
-			ath10k_err(ar, "popped an incomplete msdu\n");
 			__skb_queue_purge(amsdu);
-			htt->rx_confused = true;
-			break;
+			return -EIO;
 		}
 
 		*attention |= __le32_to_cpu(rx_desc->attention.flags) &
@@ -422,10 +413,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
 		while (msdu_chained--) {
 			msdu = ath10k_htt_rx_netbuf_pop(htt);
 			if (!msdu) {
-				ath10k_warn(ar, "failed to pop chained msdu\n");
 				__skb_queue_purge(amsdu);
-				htt->rx_confused = true;
-				break;
+				return -ENOENT;
 			}
 
 			__skb_queue_tail(amsdu, msdu);
@@ -1201,6 +1190,9 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 
 	lockdep_assert_held(&htt->rx_ring.lock);
 
+	if (htt->rx_confused)
+		return;
+
 	fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes);
 	fw_desc = (u8 *)&rx->fw_desc;
 
@@ -1246,10 +1238,13 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 					      &fw_desc_len, &amsdu,
 					      &attention);
 		if (ret < 0) {
-			ath10k_warn(ar, "failed to pop amsdu from htt rx ring %d\n",
-				    ret);
+			ath10k_warn(ar, "rx ring became corrupted: %d\n", ret);
 			__skb_queue_purge(&amsdu);
-			continue;
+			/* FIXME: It's probably a good idea to reboot the
+			 * device instead of leaving it inoperable.
+			 */
+			htt->rx_confused = true;
+			break;
 		}
 
 		if (!ath10k_htt_rx_amsdu_allowed(htt, skb_peek(&amsdu),
-- 
1.8.5.3



From michal.kazior at tieto.com  Tue Nov  4 06:22:10 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue,  4 Nov 2014 15:22:10 +0100
Subject: [PATCH 6/7] ath10k: use rx descriptor for ppdu status extraction
In-Reply-To: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
References: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1415110931-10945-7-git-send-email-michal.kazior@tieto.com>

This makes it more in line with the new Rx path.
It also makes the code more reusable because Rx
descriptor is more accessible.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/htt_rx.c | 137 ++++++++++++++++++++++---------
 1 file changed, 96 insertions(+), 41 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 55e4568..9073a0e 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -631,23 +631,34 @@ static const u8 rx_legacy_rate_idx[] = {
 };
 
 static void ath10k_htt_rx_h_rates(struct ath10k *ar,
-				  enum ieee80211_band band,
-				  u8 info0, u32 info1, u32 info2,
-				  struct ieee80211_rx_status *status)
+				  struct ieee80211_rx_status *status,
+				  struct htt_rx_desc *rxd)
 {
+	enum ieee80211_band band;
 	u8 cck, rate, rate_idx, bw, sgi, mcs, nss;
 	u8 preamble = 0;
+	u32 info1, info2, info3;
 
-	/* Check if valid fields */
-	if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID))
+	/* Band value can't be set as undefined but freq can be 0 - use that to
+	 * determine whether band is provided.
+	 *
+	 * FIXME: Perhaps this can go away if CCK rate reporting is a little
+	 * reworked?
+	 */
+	if (!status->freq)
 		return;
 
-	preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE);
+	band = status->band;
+	info1 = __le32_to_cpu(rxd->ppdu_start.info1);
+	info2 = __le32_to_cpu(rxd->ppdu_start.info2);
+	info3 = __le32_to_cpu(rxd->ppdu_start.info3);
+
+	preamble = MS(info1, RX_PPDU_START_INFO1_PREAMBLE_TYPE);
 
 	switch (preamble) {
 	case HTT_RX_LEGACY:
-		cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK;
-		rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE);
+		cck = info1 & RX_PPDU_START_INFO1_L_SIG_RATE_SELECT;
+		rate = MS(info1, RX_PPDU_START_INFO1_L_SIG_RATE);
 		rate_idx = 0;
 
 		if (rate < 0x08 || rate > 0x0F)
@@ -674,11 +685,11 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
 		break;
 	case HTT_RX_HT:
 	case HTT_RX_HT_WITH_TXBF:
-		/* HT-SIG - Table 20-11 in info1 and info2 */
-		mcs = info1 & 0x1F;
+		/* HT-SIG - Table 20-11 in info2 and info3 */
+		mcs = info2 & 0x1F;
 		nss = mcs >> 3;
-		bw = (info1 >> 7) & 1;
-		sgi = (info2 >> 7) & 1;
+		bw = (info2 >> 7) & 1;
+		sgi = (info3 >> 7) & 1;
 
 		status->rate_idx = mcs;
 		status->flag |= RX_FLAG_HT;
@@ -689,12 +700,12 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
 		break;
 	case HTT_RX_VHT:
 	case HTT_RX_VHT_WITH_TXBF:
-		/* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2
+		/* VHT-SIG-A1 in info2, VHT-SIG-A2 in info3
 		   TODO check this */
-		mcs = (info2 >> 4) & 0x0F;
-		nss = ((info1 >> 10) & 0x07) + 1;
-		bw = info1 & 3;
-		sgi = info2 & 1;
+		mcs = (info3 >> 4) & 0x0F;
+		nss = ((info2 >> 10) & 0x07) + 1;
+		bw = info2 & 3;
+		sgi = info3 & 1;
 
 		status->rate_idx = mcs;
 		status->vht_nss = nss;
@@ -742,6 +753,73 @@ static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
 	return true;
 }
 
+static void ath10k_htt_rx_h_signal(struct ath10k *ar,
+				   struct ieee80211_rx_status *status,
+				   struct htt_rx_desc *rxd)
+{
+	/* FIXME: Get real NF */
+	status->signal = ATH10K_DEFAULT_NOISE_FLOOR +
+			 rxd->ppdu_start.rssi_comb;
+	status->flag &= ~RX_FLAG_NO_SIGNAL_VAL;
+}
+
+static void ath10k_htt_rx_h_mactime(struct ath10k *ar,
+				    struct ieee80211_rx_status *status,
+				    struct htt_rx_desc *rxd)
+{
+	/* FIXME: TSF is known only at the end of PPDU, in the last MPDU. This
+	 * means all prior MSDUs in a PPDU are reported to mac80211 without the
+	 * TSF. Is it worth holding frames until end of PPDU is known?
+	 *
+	 * FIXME: Can we get/compute 64bit TSF?
+	 */
+	status->mactime = __le32_to_cpu(rxd->ppdu_end.tsf_timestamp);
+	status->flag |= RX_FLAG_MACTIME_END;
+}
+
+static void ath10k_htt_rx_h_ppdu(struct ath10k *ar,
+				 struct sk_buff_head *amsdu,
+				 struct ieee80211_rx_status *status)
+{
+	struct sk_buff *first;
+	struct htt_rx_desc *rxd;
+	bool is_first_ppdu;
+	bool is_last_ppdu;
+
+	if (skb_queue_empty(amsdu))
+		return;
+
+	first = skb_peek(amsdu);
+	rxd = (void *)first->data - sizeof(*rxd);
+
+	is_first_ppdu = !!(rxd->attention.flags &
+			   __cpu_to_le32(RX_ATTENTION_FLAGS_FIRST_MPDU));
+	is_last_ppdu = !!(rxd->attention.flags &
+			  __cpu_to_le32(RX_ATTENTION_FLAGS_LAST_MPDU));
+
+	if (is_first_ppdu) {
+		/* New PPDU starts so clear out the old per-PPDU status. */
+		status->freq = 0;
+		status->rate_idx = 0;
+		status->vht_nss = 0;
+		status->vht_flag &= ~RX_VHT_FLAG_80MHZ;
+		status->flag &= ~(RX_FLAG_HT |
+				  RX_FLAG_VHT |
+				  RX_FLAG_SHORT_GI |
+				  RX_FLAG_40MHZ |
+				  RX_FLAG_MACTIME_END);
+		status->flag |= RX_FLAG_NO_SIGNAL_VAL;
+
+		ath10k_htt_rx_h_signal(ar, status, rxd);
+		ath10k_htt_rx_h_channel(ar, status);
+		ath10k_htt_rx_h_rates(ar, status, rxd);
+	}
+
+	if (is_last_ppdu) {
+		ath10k_htt_rx_h_mactime(ar, status, rxd);
+	}
+}
+
 static const char * const tid_to_ac[] = {
 	"BE",
 	"BK",
@@ -1358,7 +1436,6 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 	int num_mpdu_ranges;
 	int fw_desc_len;
 	u8 *fw_desc;
-	bool channel_set;
 	int i, ret, mpdu_count = 0;
 
 	lockdep_assert_held(&htt->rx_ring.lock);
@@ -1373,29 +1450,6 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 			     HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
 	mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx);
 
-	/* Fill this once, while this is per-ppdu */
-	if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_START_VALID) {
-		memset(rx_status, 0, sizeof(*rx_status));
-		rx_status->signal  = ATH10K_DEFAULT_NOISE_FLOOR +
-				     rx->ppdu.combined_rssi;
-	}
-
-	if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_END_VALID) {
-		/* TSF available only in 32-bit */
-		rx_status->mactime = __le32_to_cpu(rx->ppdu.tsf) & 0xffffffff;
-		rx_status->flag |= RX_FLAG_MACTIME_END;
-	}
-
-	channel_set = ath10k_htt_rx_h_channel(htt->ar, rx_status);
-
-	if (channel_set) {
-		ath10k_htt_rx_h_rates(htt->ar, rx_status->band,
-				      rx->ppdu.info0,
-				      __le32_to_cpu(rx->ppdu.info1),
-				      __le32_to_cpu(rx->ppdu.info2),
-				      rx_status);
-	}
-
 	ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
 			rx, sizeof(*rx) +
 			(sizeof(struct htt_rx_indication_mpdu_range) *
@@ -1418,6 +1472,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 			break;
 		}
 
+		ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status);
 		ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
 		ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
 		ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
-- 
1.8.5.3



From michal.kazior at tieto.com  Tue Nov  4 06:22:05 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue,  4 Nov 2014 15:22:05 +0100
Subject: [PATCH 1/7] ath10k: start using sk_buff_head
In-Reply-To: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
References: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1415110931-10945-2-git-send-email-michal.kazior@tieto.com>

Instead of using manual sk_buff linking via ->next
use sk_buff_head. It's more robust, cleaner and
there's plenty of helper functions in kernel
already to manage sk_buff_head.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/htt_rx.c | 213 +++++++++++++------------------
 1 file changed, 91 insertions(+), 122 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index a691fdf..85f11e6 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -303,27 +303,15 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
 	return msdu;
 }
 
-static void ath10k_htt_rx_free_msdu_chain(struct sk_buff *skb)
-{
-	struct sk_buff *next;
-
-	while (skb) {
-		next = skb->next;
-		dev_kfree_skb_any(skb);
-		skb = next;
-	}
-}
-
 /* return: < 0 fatal error, 0 - non chained msdu, 1 chained msdu */
 static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
 				   u8 **fw_desc, int *fw_desc_len,
-				   struct sk_buff **head_msdu,
-				   struct sk_buff **tail_msdu,
+				   struct sk_buff_head *amsdu,
 				   u32 *attention)
 {
 	struct ath10k *ar = htt->ar;
 	int msdu_len, msdu_chaining = 0;
-	struct sk_buff *msdu, *next;
+	struct sk_buff *msdu;
 	struct htt_rx_desc *rx_desc;
 
 	lockdep_assert_held(&htt->rx_ring.lock);
@@ -333,10 +321,19 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
 		return -1;
 	}
 
-	msdu = *head_msdu = ath10k_htt_rx_netbuf_pop(htt);
-	while (msdu) {
+	for (;;) {
 		int last_msdu, msdu_len_invalid, msdu_chained;
 
+		msdu = ath10k_htt_rx_netbuf_pop(htt);
+		if (!msdu) {
+			ath10k_err(ar, "failed to pop msdu\n");
+			__skb_queue_purge(amsdu);
+			htt->rx_confused = true;
+			break;
+		}
+
+		__skb_queue_tail(amsdu, msdu);
+
 		rx_desc = (struct htt_rx_desc *)msdu->data;
 
 		/* FIXME: we must report msdu payload since this is what caller
@@ -354,10 +351,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
 		 */
 		if (!(__le32_to_cpu(rx_desc->attention.flags)
 				& RX_ATTENTION_FLAGS_MSDU_DONE)) {
-			ath10k_htt_rx_free_msdu_chain(*head_msdu);
-			*head_msdu = NULL;
-			msdu = NULL;
-			ath10k_err(ar, "htt rx stopped. cannot recover\n");
+			ath10k_err(ar, "popped an incomplete msdu\n");
+			__skb_queue_purge(amsdu);
 			htt->rx_confused = true;
 			break;
 		}
@@ -423,25 +418,20 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
 		skb_put(msdu, min(msdu_len, HTT_RX_MSDU_SIZE));
 		msdu_len -= msdu->len;
 
-		/* FIXME: Do chained buffers include htt_rx_desc or not? */
+		/* Note: Chained buffers do not contain rx descriptor */
 		while (msdu_chained--) {
-			struct sk_buff *next = ath10k_htt_rx_netbuf_pop(htt);
-
-			if (!next) {
+			msdu = ath10k_htt_rx_netbuf_pop(htt);
+			if (!msdu) {
 				ath10k_warn(ar, "failed to pop chained msdu\n");
-				ath10k_htt_rx_free_msdu_chain(*head_msdu);
-				*head_msdu = NULL;
-				msdu = NULL;
+				__skb_queue_purge(amsdu);
 				htt->rx_confused = true;
 				break;
 			}
 
-			skb_trim(next, 0);
-			skb_put(next, min(msdu_len, HTT_RX_BUF_SIZE));
-			msdu_len -= next->len;
-
-			msdu->next = next;
-			msdu = next;
+			__skb_queue_tail(amsdu, msdu);
+			skb_trim(msdu, 0);
+			skb_put(msdu, min(msdu_len, HTT_RX_BUF_SIZE));
+			msdu_len -= msdu->len;
 			msdu_chaining = 1;
 		}
 
@@ -450,18 +440,12 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
 
 		trace_ath10k_htt_rx_desc(ar, &rx_desc->attention,
 					 sizeof(*rx_desc) - sizeof(u32));
-		if (last_msdu) {
-			msdu->next = NULL;
-			break;
-		}
 
-		next = ath10k_htt_rx_netbuf_pop(htt);
-		msdu->next = next;
-		msdu = next;
+		if (last_msdu)
+			break;
 	}
-	*tail_msdu = msdu;
 
-	if (*head_msdu == NULL)
+	if (skb_queue_empty(amsdu))
 		msdu_chaining = -1;
 
 	/*
@@ -915,11 +899,11 @@ static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr)
 
 static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
 				struct ieee80211_rx_status *rx_status,
-				struct sk_buff *skb_in)
+				struct sk_buff_head *amsdu)
 {
 	struct ath10k *ar = htt->ar;
 	struct htt_rx_desc *rxd;
-	struct sk_buff *skb = skb_in;
+	struct sk_buff *skb;
 	struct sk_buff *first;
 	enum rx_msdu_decap_format fmt;
 	enum htt_rx_mpdu_encrypt_type enctype;
@@ -927,7 +911,9 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
 	u8 hdr_buf[64], da[ETH_ALEN], sa[ETH_ALEN], *qos;
 	unsigned int hdr_len;
 
-	rxd = (void *)skb->data - sizeof(*rxd);
+	first = skb_peek(amsdu);
+
+	rxd = (void *)first->data - sizeof(*rxd);
 	enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
 		     RX_MPDU_START_INFO0_ENCRYPT_TYPE);
 
@@ -936,8 +922,7 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
 	memcpy(hdr_buf, hdr, hdr_len);
 	hdr = (struct ieee80211_hdr *)hdr_buf;
 
-	first = skb;
-	while (skb) {
+	while ((skb = __skb_dequeue(amsdu))) {
 		void *decap_hdr;
 		int len;
 
@@ -1005,18 +990,15 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
 			break;
 		}
 
-		skb_in = skb;
-		ath10k_htt_rx_h_protected(htt, rx_status, skb_in, enctype, fmt,
+		ath10k_htt_rx_h_protected(htt, rx_status, skb, enctype, fmt,
 					  false);
-		skb = skb->next;
-		skb_in->next = NULL;
 
-		if (skb)
-			rx_status->flag |= RX_FLAG_AMSDU_MORE;
-		else
+		if (skb_queue_empty(amsdu))
 			rx_status->flag &= ~RX_FLAG_AMSDU_MORE;
+		else
+			rx_status->flag |= RX_FLAG_AMSDU_MORE;
 
-		ath10k_process_rx(htt->ar, rx_status, skb_in);
+		ath10k_process_rx(htt->ar, rx_status, skb);
 	}
 
 	/* FIXME: It might be nice to re-assemble the A-MSDU when there's a
@@ -1035,13 +1017,6 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt,
 	int hdr_len;
 	void *rfc1042;
 
-	/* This shouldn't happen. If it does than it may be a FW bug. */
-	if (skb->next) {
-		ath10k_warn(ar, "htt rx received chained non A-MSDU frame\n");
-		ath10k_htt_rx_free_msdu_chain(skb->next);
-		skb->next = NULL;
-	}
-
 	rxd = (void *)skb->data - sizeof(*rxd);
 	fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
 		 RX_MSDU_START_INFO1_DECAP_FORMAT);
@@ -1127,10 +1102,9 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb)
 	return CHECKSUM_UNNECESSARY;
 }
 
-static int ath10k_unchain_msdu(struct sk_buff *msdu_head)
+static int ath10k_unchain_msdu(struct sk_buff_head *amsdu)
 {
-	struct sk_buff *next = msdu_head->next;
-	struct sk_buff *to_free = next;
+	struct sk_buff *skb, *first;
 	int space;
 	int total_len = 0;
 
@@ -1141,40 +1115,33 @@ static int ath10k_unchain_msdu(struct sk_buff *msdu_head)
 	 * skb?
 	 */
 
-	msdu_head->next = NULL;
+	first = __skb_dequeue(amsdu);
 
 	/* Allocate total length all at once. */
-	while (next) {
-		total_len += next->len;
-		next = next->next;
-	}
+	skb_queue_walk(amsdu, skb)
+		total_len += skb->len;
 
-	space = total_len - skb_tailroom(msdu_head);
+	space = total_len - skb_tailroom(first);
 	if ((space > 0) &&
-	    (pskb_expand_head(msdu_head, 0, space, GFP_ATOMIC) < 0)) {
+	    (pskb_expand_head(first, 0, space, GFP_ATOMIC) < 0)) {
 		/* TODO:  bump some rx-oom error stat */
 		/* put it back together so we can free the
 		 * whole list at once.
 		 */
-		msdu_head->next = to_free;
+		__skb_queue_head(amsdu, first);
 		return -1;
 	}
 
 	/* Walk list again, copying contents into
 	 * msdu_head
 	 */
-	next = to_free;
-	while (next) {
-		skb_copy_from_linear_data(next, skb_put(msdu_head, next->len),
-					  next->len);
-		next = next->next;
+	while ((skb = __skb_dequeue(amsdu))) {
+		skb_copy_from_linear_data(skb, skb_put(first, skb->len),
+					  skb->len);
+		dev_kfree_skb_any(skb);
 	}
 
-	/* If here, we have consolidated skb.  Free the
-	 * fragments and pass the main skb on up the
-	 * stack.
-	 */
-	ath10k_htt_rx_free_msdu_chain(to_free);
+	__skb_queue_head(amsdu, first);
 	return 0;
 }
 
@@ -1223,6 +1190,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 	struct ath10k *ar = htt->ar;
 	struct ieee80211_rx_status *rx_status = &htt->rx_status;
 	struct htt_rx_indication_mpdu_range *mpdu_ranges;
+	struct sk_buff_head amsdu;
 	struct ieee80211_hdr *hdr;
 	int num_mpdu_ranges;
 	u32 attention;
@@ -1271,35 +1239,28 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 
 	for (i = 0; i < num_mpdu_ranges; i++) {
 		for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) {
-			struct sk_buff *msdu_head, *msdu_tail;
-
 			attention = 0;
-			msdu_head = NULL;
-			msdu_tail = NULL;
-			ret = ath10k_htt_rx_amsdu_pop(htt,
-						      &fw_desc,
-						      &fw_desc_len,
-						      &msdu_head,
-						      &msdu_tail,
+			__skb_queue_head_init(&amsdu);
+			ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc,
+						      &fw_desc_len, &amsdu,
 						      &attention);
 
 			if (ret < 0) {
 				ath10k_warn(ar, "failed to pop amsdu from htt rx ring %d\n",
 					    ret);
-				ath10k_htt_rx_free_msdu_chain(msdu_head);
+				__skb_queue_purge(&amsdu);
 				continue;
 			}
 
-			if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head,
+			if (!ath10k_htt_rx_amsdu_allowed(htt, skb_peek(&amsdu),
 							 channel_set,
 							 attention)) {
-				ath10k_htt_rx_free_msdu_chain(msdu_head);
+				__skb_queue_purge(&amsdu);
 				continue;
 			}
 
-			if (ret > 0 &&
-			    ath10k_unchain_msdu(msdu_head) < 0) {
-				ath10k_htt_rx_free_msdu_chain(msdu_head);
+			if (ret > 0 && ath10k_unchain_msdu(&amsdu) < 0) {
+				__skb_queue_purge(&amsdu);
 				continue;
 			}
 
@@ -1313,12 +1274,13 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 			else
 				rx_status->flag &= ~RX_FLAG_MMIC_ERROR;
 
-			hdr = ath10k_htt_rx_skb_get_hdr(msdu_head);
+			hdr = ath10k_htt_rx_skb_get_hdr(skb_peek(&amsdu));
 
 			if (ath10k_htt_rx_hdr_is_amsdu(hdr))
-				ath10k_htt_rx_amsdu(htt, rx_status, msdu_head);
+				ath10k_htt_rx_amsdu(htt, rx_status, &amsdu);
 			else
-				ath10k_htt_rx_msdu(htt, rx_status, msdu_head);
+				ath10k_htt_rx_msdu(htt, rx_status,
+						   __skb_dequeue(&amsdu));
 		}
 	}
 
@@ -1329,12 +1291,13 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
 				       struct htt_rx_fragment_indication *frag)
 {
 	struct ath10k *ar = htt->ar;
-	struct sk_buff *msdu_head, *msdu_tail;
+	struct sk_buff *msdu;
 	enum htt_rx_mpdu_encrypt_type enctype;
 	struct htt_rx_desc *rxd;
 	enum rx_msdu_decap_format fmt;
 	struct ieee80211_rx_status *rx_status = &htt->rx_status;
 	struct ieee80211_hdr *hdr;
+	struct sk_buff_head amsdu;
 	int ret;
 	bool tkip_mic_err;
 	bool decrypt_err;
@@ -1346,13 +1309,11 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
 	fw_desc_len = __le16_to_cpu(frag->fw_rx_desc_bytes);
 	fw_desc = (u8 *)frag->fw_msdu_rx_desc;
 
-	msdu_head = NULL;
-	msdu_tail = NULL;
+	__skb_queue_head_init(&amsdu);
 
 	spin_lock_bh(&htt->rx_ring.lock);
 	ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len,
-				      &msdu_head, &msdu_tail,
-				      &attention);
+				      &amsdu, &attention);
 	spin_unlock_bh(&htt->rx_ring.lock);
 
 	tasklet_schedule(&htt->rx_replenish_task);
@@ -1362,15 +1323,23 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
 	if (ret) {
 		ath10k_warn(ar, "failed to pop amsdu from httr rx ring for fragmented rx %d\n",
 			    ret);
-		ath10k_htt_rx_free_msdu_chain(msdu_head);
+		__skb_queue_purge(&amsdu);
 		return;
 	}
 
+	if (skb_queue_len(&amsdu) != 1) {
+		ath10k_warn(ar, "failed to pop frag amsdu: too many msdus\n");
+		__skb_queue_purge(&amsdu);
+		return;
+	}
+
+	msdu = __skb_dequeue(&amsdu);
+
 	/* FIXME: implement signal strength */
 	rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
 
-	hdr = (struct ieee80211_hdr *)msdu_head->data;
-	rxd = (void *)msdu_head->data - sizeof(*rxd);
+	hdr = (struct ieee80211_hdr *)msdu->data;
+	rxd = (void *)msdu->data - sizeof(*rxd);
 	tkip_mic_err = !!(attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR);
 	decrypt_err = !!(attention & RX_ATTENTION_FLAGS_DECRYPT_ERR);
 	fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
@@ -1378,22 +1347,22 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
 
 	if (fmt != RX_MSDU_DECAP_RAW) {
 		ath10k_warn(ar, "we dont support non-raw fragmented rx yet\n");
-		dev_kfree_skb_any(msdu_head);
+		dev_kfree_skb_any(msdu);
 		goto end;
 	}
 
 	enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
 		     RX_MPDU_START_INFO0_ENCRYPT_TYPE);
-	ath10k_htt_rx_h_protected(htt, rx_status, msdu_head, enctype, fmt,
+	ath10k_htt_rx_h_protected(htt, rx_status, msdu, enctype, fmt,
 				  true);
-	msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head);
+	msdu->ip_summed = ath10k_htt_rx_get_csum_state(msdu);
 
 	if (tkip_mic_err)
 		ath10k_warn(ar, "tkip mic error\n");
 
 	if (decrypt_err) {
 		ath10k_warn(ar, "decryption err in fragmented rx\n");
-		dev_kfree_skb_any(msdu_head);
+		dev_kfree_skb_any(msdu);
 		goto end;
 	}
 
@@ -1402,11 +1371,11 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
 		paramlen = ath10k_htt_rx_crypto_param_len(ar, enctype);
 
 		/* It is more efficient to move the header than the payload */
-		memmove((void *)msdu_head->data + paramlen,
-			(void *)msdu_head->data,
+		memmove((void *)msdu->data + paramlen,
+			(void *)msdu->data,
 			hdrlen);
-		skb_pull(msdu_head, paramlen);
-		hdr = (struct ieee80211_hdr *)msdu_head->data;
+		skb_pull(msdu, paramlen);
+		hdr = (struct ieee80211_hdr *)msdu->data;
 	}
 
 	/* remove trailing FCS */
@@ -1420,17 +1389,17 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
 	    enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
 		trim += MICHAEL_MIC_LEN;
 
-	if (trim > msdu_head->len) {
+	if (trim > msdu->len) {
 		ath10k_warn(ar, "htt rx fragment: trailer longer than the frame itself? drop\n");
-		dev_kfree_skb_any(msdu_head);
+		dev_kfree_skb_any(msdu);
 		goto end;
 	}
 
-	skb_trim(msdu_head, msdu_head->len - trim);
+	skb_trim(msdu, msdu->len - trim);
 
 	ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
-			msdu_head->data, msdu_head->len);
-	ath10k_process_rx(htt->ar, rx_status, msdu_head);
+			msdu->data, msdu->len);
+	ath10k_process_rx(htt->ar, rx_status, msdu);
 
 end:
 	if (fw_desc_len > 0) {
-- 
1.8.5.3



From michal.kazior at tieto.com  Tue Nov  4 06:22:08 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue,  4 Nov 2014 15:22:08 +0100
Subject: [PATCH 4/7] ath10k: unify rx undecapping
In-Reply-To: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
References: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1415110931-10945-5-git-send-email-michal.kazior@tieto.com>

This creates a single, common path for MSDU,
A-MSDU and fragmented Rx.

Hopefully this will make it easier to understand
Rx path and make it easier to work with.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/htt_rx.c | 738 +++++++++++++++++--------------
 1 file changed, 412 insertions(+), 326 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 651028e..6abfea7 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -603,35 +603,6 @@ static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar,
 	return 0;
 }
 
-/* Applies for first msdu in chain, before altering it. */
-static struct ieee80211_hdr *ath10k_htt_rx_skb_get_hdr(struct sk_buff *skb)
-{
-	struct htt_rx_desc *rxd;
-	enum rx_msdu_decap_format fmt;
-
-	rxd = (void *)skb->data - sizeof(*rxd);
-	fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
-		 RX_MSDU_START_INFO1_DECAP_FORMAT);
-
-	if (fmt == RX_MSDU_DECAP_RAW)
-		return (void *)skb->data;
-
-	return (void *)skb->data - RX_HTT_HDR_STATUS_LEN;
-}
-
-/* This function only applies for first msdu in an msdu chain */
-static bool ath10k_htt_rx_hdr_is_amsdu(struct ieee80211_hdr *hdr)
-{
-	u8 *qc;
-
-	if (ieee80211_is_data_qos(hdr->frame_control)) {
-		qc = ieee80211_get_qos_ctl(hdr);
-		if (qc[0] & 0x80)
-			return true;
-	}
-	return false;
-}
-
 struct rfc1042_hdr {
 	u8 llc_dsap;
 	u8 llc_ssap;
@@ -757,41 +728,6 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
 	}
 }
 
-static void ath10k_htt_rx_h_protected(struct ath10k_htt *htt,
-				      struct ieee80211_rx_status *rx_status,
-				      struct sk_buff *skb,
-				      enum htt_rx_mpdu_encrypt_type enctype,
-				      enum rx_msdu_decap_format fmt,
-				      bool dot11frag)
-{
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-
-	rx_status->flag &= ~(RX_FLAG_DECRYPTED |
-			     RX_FLAG_IV_STRIPPED |
-			     RX_FLAG_MMIC_STRIPPED);
-
-	if (enctype == HTT_RX_MPDU_ENCRYPT_NONE)
-		return;
-
-	/*
-	 * There's no explicit rx descriptor flag to indicate whether a given
-	 * frame has been decrypted or not. We're forced to use the decap
-	 * format as an implicit indication. However fragmentation rx is always
-	 * raw and it probably never reports undecrypted raws.
-	 *
-	 * This makes sure sniffed frames are reported as-is without stripping
-	 * the protected flag.
-	 */
-	if (fmt == RX_MSDU_DECAP_RAW && !dot11frag)
-		return;
-
-	rx_status->flag |= RX_FLAG_DECRYPTED |
-			   RX_FLAG_IV_STRIPPED |
-			   RX_FLAG_MMIC_STRIPPED;
-	hdr->frame_control = __cpu_to_le16(__le16_to_cpu(hdr->frame_control) &
-					   ~IEEE80211_FCTL_PROTECTED);
-}
-
 static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
 				    struct ieee80211_rx_status *status)
 {
@@ -886,178 +822,262 @@ static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr)
 	return round_up(ieee80211_hdrlen(hdr->frame_control), 4);
 }
 
-static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
-				struct ieee80211_rx_status *rx_status,
-				struct sk_buff_head *amsdu)
+static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar,
+					struct sk_buff *msdu,
+					struct ieee80211_rx_status *status,
+					enum htt_rx_mpdu_encrypt_type enctype,
+					bool is_decrypted)
 {
-	struct ath10k *ar = htt->ar;
+	struct ieee80211_hdr *hdr;
 	struct htt_rx_desc *rxd;
-	struct sk_buff *skb;
-	struct sk_buff *first;
-	enum rx_msdu_decap_format fmt;
-	enum htt_rx_mpdu_encrypt_type enctype;
+	size_t hdr_len;
+	size_t crypto_len;
+	bool is_first;
+	bool is_last;
+
+	rxd = (void *)msdu->data - sizeof(*rxd);
+	is_first = !!(rxd->msdu_end.info0 &
+		      __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU));
+	is_last = !!(rxd->msdu_end.info0 &
+		     __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU));
+
+	/* Delivered decapped frame:
+	 * [802.11 header]
+	 * [crypto param] <-- can be trimmed if !fcs_err &&
+	 *                    !decrypt_err && !peer_idx_invalid
+	 * [amsdu header] <-- only if A-MSDU
+	 * [rfc1042/llc]
+	 * [payload]
+	 * [FCS] <-- at end, needs to be trimmed
+	 */
+
+	/* This probably shouldn't happen but warn just in case */
+	if (unlikely(WARN_ON_ONCE(!is_first)))
+		return;
+
+	/* This probably shouldn't happen but warn just in case */
+	if (unlikely(WARN_ON_ONCE(!(is_first && is_last))))
+		return;
+
+	skb_trim(msdu, msdu->len - FCS_LEN);
+
+	/* In most cases this will be true for sniffed frames. It makes sense
+	 * to deliver them as-is without stripping the crypto param. This would
+	 * also make sense for software based decryption (which is not
+	 * implemented in ath10k).
+	 *
+	 * If there's no error then the frame is decrypted. At least that is
+	 * the case for frames that come in via fragmented rx indication.
+	 */
+	if (!is_decrypted)
+		return;
+
+	/* The payload is decrypted so strip crypto params. Start from tail
+	 * since hdr is used to compute some stuff.
+	 */
+
+	hdr = (void *)msdu->data;
+
+	/* Tail */
+	skb_trim(msdu, msdu->len - ath10k_htt_rx_crypto_tail_len(ar, enctype));
+
+	/* MMIC */
+	if (!ieee80211_has_morefrags(hdr->frame_control) &&
+	    enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
+		skb_trim(msdu, msdu->len - 8);
+
+	/* Head */
+	hdr_len = ieee80211_hdrlen(hdr->frame_control);
+	crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype);
+
+	memmove((void *)msdu->data + crypto_len,
+		(void *)msdu->data, hdr_len);
+	skb_pull(msdu, crypto_len);
+}
+
+static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar,
+					  struct sk_buff *msdu,
+					  struct ieee80211_rx_status *status,
+					  const u8 first_hdr[64])
+{
 	struct ieee80211_hdr *hdr;
-	u8 hdr_buf[64], da[ETH_ALEN], sa[ETH_ALEN], *qos;
-	unsigned int hdr_len;
+	size_t hdr_len;
+	u8 da[ETH_ALEN];
+	u8 sa[ETH_ALEN];
 
-	first = skb_peek(amsdu);
+	/* Delivered decapped frame:
+	 * [nwifi 802.11 header] <-- replaced with 802.11 hdr
+	 * [rfc1042/llc]
+	 *
+	 * Note: The nwifi header doesn't have QoS Control and is
+	 * (always?) a 3addr frame.
+	 *
+	 * Note2: There's no A-MSDU subframe header. Even if it's part
+	 * of an A-MSDU.
+	 */
 
-	rxd = (void *)first->data - sizeof(*rxd);
-	enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
-		     RX_MPDU_START_INFO0_ENCRYPT_TYPE);
+	/* pull decapped header and copy SA & DA */
+	hdr = (struct ieee80211_hdr *)msdu->data;
+	hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr);
+	ether_addr_copy(da, ieee80211_get_DA(hdr));
+	ether_addr_copy(sa, ieee80211_get_SA(hdr));
+	skb_pull(msdu, hdr_len);
 
-	hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status;
+	/* push original 802.11 header */
+	hdr = (struct ieee80211_hdr *)first_hdr;
 	hdr_len = ieee80211_hdrlen(hdr->frame_control);
-	memcpy(hdr_buf, hdr, hdr_len);
-	hdr = (struct ieee80211_hdr *)hdr_buf;
+	memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
 
-	while ((skb = __skb_dequeue(amsdu))) {
-		void *decap_hdr;
-		int len;
-
-		rxd = (void *)skb->data - sizeof(*rxd);
-		fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
-			 RX_MSDU_START_INFO1_DECAP_FORMAT);
-		decap_hdr = (void *)rxd->rx_hdr_status;
-
-		skb->ip_summed = ath10k_htt_rx_get_csum_state(skb);
-
-		/* First frame in an A-MSDU chain has more decapped data. */
-		if (skb == first) {
-			len = round_up(ieee80211_hdrlen(hdr->frame_control), 4);
-			len += round_up(ath10k_htt_rx_crypto_param_len(ar,
-						enctype), 4);
-			decap_hdr += len;
-		}
+	/* original 802.11 header has a different DA and in
+	 * case of 4addr it may also have different SA
+	 */
+	hdr = (struct ieee80211_hdr *)msdu->data;
+	ether_addr_copy(ieee80211_get_DA(hdr), da);
+	ether_addr_copy(ieee80211_get_SA(hdr), sa);
+}
 
-		switch (fmt) {
-		case RX_MSDU_DECAP_RAW:
-			/* remove trailing FCS */
-			skb_trim(skb, skb->len - FCS_LEN);
-			break;
-		case RX_MSDU_DECAP_NATIVE_WIFI:
-			/* pull decapped header and copy SA & DA */
-			hdr = (struct ieee80211_hdr *)skb->data;
-			hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr);
-			ether_addr_copy(da, ieee80211_get_DA(hdr));
-			ether_addr_copy(sa, ieee80211_get_SA(hdr));
-			skb_pull(skb, hdr_len);
-
-			/* push original 802.11 header */
-			hdr = (struct ieee80211_hdr *)hdr_buf;
-			hdr_len = ieee80211_hdrlen(hdr->frame_control);
-			memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
-
-			/* original A-MSDU header has the bit set but we're
-			 * not including A-MSDU subframe header */
-			hdr = (struct ieee80211_hdr *)skb->data;
-			qos = ieee80211_get_qos_ctl(hdr);
-			qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
-
-			/* original 802.11 header has a different DA and in
-			 * case of 4addr it may also have different SA
-			 */
-			ether_addr_copy(ieee80211_get_DA(hdr), da);
-			ether_addr_copy(ieee80211_get_SA(hdr), sa);
-			break;
-		case RX_MSDU_DECAP_ETHERNET2_DIX:
-			/* strip ethernet header and insert decapped 802.11
-			 * header, amsdu subframe header and rfc1042 header */
+static void *ath10k_htt_rx_h_find_rfc1042(struct ath10k *ar,
+					  struct sk_buff *msdu,
+					  enum htt_rx_mpdu_encrypt_type enctype)
+{
+	struct ieee80211_hdr *hdr;
+	struct htt_rx_desc *rxd;
+	size_t hdr_len, crypto_len;
+	void *rfc1042;
+	bool is_first, is_last, is_amsdu;
 
-			len = 0;
-			len += sizeof(struct rfc1042_hdr);
-			len += sizeof(struct amsdu_subframe_hdr);
+	rxd = (void *)msdu->data - sizeof(*rxd);
+	hdr = (void *)rxd->rx_hdr_status;
 
-			skb_pull(skb, sizeof(struct ethhdr));
-			memcpy(skb_push(skb, len), decap_hdr, len);
-			memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
-			break;
-		case RX_MSDU_DECAP_8023_SNAP_LLC:
-			/* insert decapped 802.11 header making a singly
-			 * A-MSDU */
-			memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
-			break;
-		}
+	is_first = !!(rxd->msdu_end.info0 &
+		      __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU));
+	is_last = !!(rxd->msdu_end.info0 &
+		     __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU));
+	is_amsdu = !(is_first && is_last);
 
-		ath10k_htt_rx_h_protected(htt, rx_status, skb, enctype, fmt,
-					  false);
+	rfc1042 = hdr;
 
-		if (skb_queue_empty(amsdu))
-			rx_status->flag &= ~RX_FLAG_AMSDU_MORE;
-		else
-			rx_status->flag |= RX_FLAG_AMSDU_MORE;
+	if (is_first) {
+		hdr_len = ieee80211_hdrlen(hdr->frame_control);
+		crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype);
 
-		ath10k_process_rx(htt->ar, rx_status, skb);
+		rfc1042 += round_up(hdr_len, 4) +
+			   round_up(crypto_len, 4);
 	}
 
-	/* FIXME: It might be nice to re-assemble the A-MSDU when there's a
-	 * monitor interface active for sniffing purposes. */
+	if (is_amsdu)
+		rfc1042 += sizeof(struct amsdu_subframe_hdr);
+
+	return rfc1042;
 }
 
-static void ath10k_htt_rx_msdu(struct ath10k_htt *htt,
-			       struct ieee80211_rx_status *rx_status,
-			       struct sk_buff *skb)
+static void ath10k_htt_rx_h_undecap_eth(struct ath10k *ar,
+					struct sk_buff *msdu,
+					struct ieee80211_rx_status *status,
+					const u8 first_hdr[64],
+					enum htt_rx_mpdu_encrypt_type enctype)
 {
-	struct ath10k *ar = htt->ar;
-	struct htt_rx_desc *rxd;
 	struct ieee80211_hdr *hdr;
-	enum rx_msdu_decap_format fmt;
-	enum htt_rx_mpdu_encrypt_type enctype;
-	int hdr_len;
+	struct ethhdr *eth;
+	size_t hdr_len;
 	void *rfc1042;
+	u8 da[ETH_ALEN];
+	u8 sa[ETH_ALEN];
 
-	rxd = (void *)skb->data - sizeof(*rxd);
-	fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
-		 RX_MSDU_START_INFO1_DECAP_FORMAT);
-	enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
-		     RX_MPDU_START_INFO0_ENCRYPT_TYPE);
-	hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status;
+	/* Delivered decapped frame:
+	 * [eth header] <-- replaced with 802.11 hdr & rfc1042/llc
+	 * [payload]
+	 */
+
+	rfc1042 = ath10k_htt_rx_h_find_rfc1042(ar, msdu, enctype);
+	if (WARN_ON_ONCE(!rfc1042))
+		return;
+
+	/* pull decapped header and copy SA & DA */
+	eth = (struct ethhdr *)msdu->data;
+	ether_addr_copy(da, eth->h_dest);
+	ether_addr_copy(sa, eth->h_source);
+	skb_pull(msdu, sizeof(struct ethhdr));
+
+	/* push rfc1042/llc/snap */
+	memcpy(skb_push(msdu, sizeof(struct rfc1042_hdr)), rfc1042,
+	       sizeof(struct rfc1042_hdr));
+
+	/* push original 802.11 header */
+	hdr = (struct ieee80211_hdr *)first_hdr;
+	hdr_len = ieee80211_hdrlen(hdr->frame_control);
+	memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
+
+	/* original 802.11 header has a different DA and in
+	 * case of 4addr it may also have different SA
+	 */
+	hdr = (struct ieee80211_hdr *)msdu->data;
+	ether_addr_copy(ieee80211_get_DA(hdr), da);
+	ether_addr_copy(ieee80211_get_SA(hdr), sa);
+}
+
+static void ath10k_htt_rx_h_undecap_snap(struct ath10k *ar,
+					 struct sk_buff *msdu,
+					 struct ieee80211_rx_status *status,
+					 const u8 first_hdr[64])
+{
+	struct ieee80211_hdr *hdr;
+	size_t hdr_len;
+
+	/* Delivered decapped frame:
+	 * [amsdu header] <-- replaced with 802.11 hdr
+	 * [rfc1042/llc]
+	 * [payload]
+	 */
+
+	skb_pull(msdu, sizeof(struct amsdu_subframe_hdr));
+
+	hdr = (struct ieee80211_hdr *)first_hdr;
 	hdr_len = ieee80211_hdrlen(hdr->frame_control);
+	memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
+}
 
-	skb->ip_summed = ath10k_htt_rx_get_csum_state(skb);
+static void ath10k_htt_rx_h_undecap(struct ath10k *ar,
+				    struct sk_buff *msdu,
+				    struct ieee80211_rx_status *status,
+				    u8 first_hdr[64],
+				    enum htt_rx_mpdu_encrypt_type enctype,
+				    bool is_decrypted)
+{
+	struct htt_rx_desc *rxd;
+	enum rx_msdu_decap_format decap;
+	struct ieee80211_hdr *hdr;
 
-	switch (fmt) {
+	/* First msdu's decapped header:
+	 * [802.11 header] <-- padded to 4 bytes long
+	 * [crypto param] <-- padded to 4 bytes long
+	 * [amsdu header] <-- only if A-MSDU
+	 * [rfc1042/llc]
+	 *
+	 * Other (2nd, 3rd, ..) msdu's decapped header:
+	 * [amsdu header] <-- only if A-MSDU
+	 * [rfc1042/llc]
+	 */
+
+	rxd = (void *)msdu->data - sizeof(*rxd);
+	hdr = (void *)rxd->rx_hdr_status;
+	decap = MS(__le32_to_cpu(rxd->msdu_start.info1),
+		   RX_MSDU_START_INFO1_DECAP_FORMAT);
+
+	switch (decap) {
 	case RX_MSDU_DECAP_RAW:
-		/* remove trailing FCS */
-		skb_trim(skb, skb->len - FCS_LEN);
+		ath10k_htt_rx_h_undecap_raw(ar, msdu, status, enctype, is_decrypted);
 		break;
 	case RX_MSDU_DECAP_NATIVE_WIFI:
-		/* Pull decapped header */
-		hdr = (struct ieee80211_hdr *)skb->data;
-		hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr);
-		skb_pull(skb, hdr_len);
-
-		/* Push original header */
-		hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status;
-		hdr_len = ieee80211_hdrlen(hdr->frame_control);
-		memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
+		ath10k_htt_rx_h_undecap_nwifi(ar, msdu, status, first_hdr);
 		break;
 	case RX_MSDU_DECAP_ETHERNET2_DIX:
-		/* strip ethernet header and insert decapped 802.11 header and
-		 * rfc1042 header */
-
-		rfc1042 = hdr;
-		rfc1042 += roundup(hdr_len, 4);
-		rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(ar,
-					enctype), 4);
-
-		skb_pull(skb, sizeof(struct ethhdr));
-		memcpy(skb_push(skb, sizeof(struct rfc1042_hdr)),
-		       rfc1042, sizeof(struct rfc1042_hdr));
-		memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
+		ath10k_htt_rx_h_undecap_eth(ar, msdu, status, first_hdr, enctype);
 		break;
 	case RX_MSDU_DECAP_8023_SNAP_LLC:
-		/* remove A-MSDU subframe header and insert
-		 * decapped 802.11 header. rfc1042 header is already there */
-
-		skb_pull(skb, sizeof(struct amsdu_subframe_hdr));
-		memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
+		ath10k_htt_rx_h_undecap_snap(ar, msdu, status, first_hdr);
 		break;
 	}
-
-	ath10k_htt_rx_h_protected(htt, rx_status, skb, enctype, fmt, false);
-
-	ath10k_process_rx(htt->ar, rx_status, skb);
 }
 
 static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb)
@@ -1091,6 +1111,126 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb)
 	return CHECKSUM_UNNECESSARY;
 }
 
+static void ath10k_htt_rx_h_csum_offload(struct sk_buff *msdu)
+{
+	msdu->ip_summed = ath10k_htt_rx_get_csum_state(msdu);
+}
+
+static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
+				 struct sk_buff_head *amsdu,
+				 struct ieee80211_rx_status *status)
+{
+	struct sk_buff *first;
+	struct sk_buff *last;
+	struct sk_buff *msdu;
+	struct htt_rx_desc *rxd;
+	struct ieee80211_hdr *hdr;
+	enum htt_rx_mpdu_encrypt_type enctype;
+	u8 first_hdr[64];
+	u8 *qos;
+	size_t hdr_len;
+	bool has_fcs_err;
+	bool has_crypto_err;
+	bool has_tkip_err;
+	bool has_peer_idx_invalid;
+	bool is_decrypted;
+
+	if (skb_queue_empty(amsdu))
+		return;
+
+	first = skb_peek(amsdu);
+	rxd = (void *)first->data - sizeof(*rxd);
+
+	enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
+		     RX_MPDU_START_INFO0_ENCRYPT_TYPE);
+
+	/* First MSDU's Rx descriptor in an A-MSDU contains full 802.11
+	 * decapped header. It'll be used for undecapping of each MSDU.
+	 */
+	hdr = (void *)rxd->rx_hdr_status;
+	hdr_len = ieee80211_hdrlen(hdr->frame_control);
+	memcpy(first_hdr, hdr, hdr_len);
+
+	/* Each A-MSDU subframe will use the original header as the base and be
+	 * reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl.
+	 */
+	hdr = (void *)first_hdr;
+	qos = ieee80211_get_qos_ctl(hdr);
+	qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+
+	/* Some attention flags are valid only in the last MSDU. */
+	last = skb_peek_tail(amsdu);
+	rxd = (void *)last->data - sizeof(*rxd);
+	has_fcs_err = !!(rxd->attention.flags &
+			 __cpu_to_le32(RX_ATTENTION_FLAGS_FCS_ERR));
+	has_crypto_err = !!(rxd->attention.flags &
+			    __cpu_to_le32(RX_ATTENTION_FLAGS_DECRYPT_ERR));
+	has_tkip_err = !!(rxd->attention.flags &
+			  __cpu_to_le32(RX_ATTENTION_FLAGS_TKIP_MIC_ERR));
+	has_peer_idx_invalid = !!(rxd->attention.flags &
+			          __cpu_to_le32(RX_ATTENTION_FLAGS_PEER_IDX_INVALID));
+
+	/* Note: If hardware captures an encrypted frame that it can't decrypt,
+	 * e.g. due to fcs error, missing peer or invalid key data it will
+	 * report the frame as raw.
+	 */
+	is_decrypted = (enctype != HTT_RX_MPDU_ENCRYPT_NONE &&
+			!has_fcs_err &&
+			!has_crypto_err &&
+			!has_peer_idx_invalid);
+
+	/* Clear per-MPDU flags while leaving per-PPDU flags intact. */
+	status->flag &= ~(RX_FLAG_FAILED_FCS_CRC |
+			  RX_FLAG_MMIC_ERROR |
+			  RX_FLAG_DECRYPTED |
+			  RX_FLAG_IV_STRIPPED |
+			  RX_FLAG_MMIC_STRIPPED);
+
+	if (has_fcs_err)
+		status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+	if (has_tkip_err)
+		status->flag |= RX_FLAG_MMIC_ERROR;
+
+	if (is_decrypted)
+		status->flag |= RX_FLAG_DECRYPTED |
+				RX_FLAG_IV_STRIPPED |
+				RX_FLAG_MMIC_STRIPPED;
+
+	skb_queue_walk(amsdu, msdu) {
+		ath10k_htt_rx_h_csum_offload(msdu);
+		ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype,
+					is_decrypted);
+
+		/* Undecapping involves copying the original 802.11 header back
+		 * to sk_buff. If frame is protected and hardware has decrypted
+		 * it then remove the protected bit.
+		 */
+		if (!is_decrypted)
+			continue;
+
+		hdr = (void *)msdu->data;
+		hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+	}
+}
+
+static void ath10k_htt_rx_h_deliver(struct ath10k *ar,
+				    struct sk_buff_head *amsdu,
+				    struct ieee80211_rx_status *status)
+{
+	struct sk_buff *msdu;
+
+	while ((msdu = __skb_dequeue(amsdu))) {
+		/* Setup per-MSDU flags */
+		if (skb_queue_empty(amsdu))
+			status->flag &= ~RX_FLAG_AMSDU_MORE;
+		else
+			status->flag |= RX_FLAG_AMSDU_MORE;
+
+		ath10k_process_rx(ar, status, msdu);
+	}
+}
+
 static int ath10k_unchain_msdu(struct sk_buff_head *amsdu)
 {
 	struct sk_buff *skb, *first;
@@ -1134,45 +1274,86 @@ static int ath10k_unchain_msdu(struct sk_buff_head *amsdu)
 	return 0;
 }
 
-static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt,
-					struct sk_buff *head,
-					bool channel_set,
-					u32 attention)
+static void ath10k_htt_rx_h_unchain(struct ath10k *ar,
+				    struct sk_buff_head *amsdu,
+				    bool chained)
 {
-	struct ath10k *ar = htt->ar;
+	struct sk_buff *first;
+	struct htt_rx_desc *rxd;
+	enum rx_msdu_decap_format decap;
 
-	if (head->len == 0) {
-		ath10k_dbg(ar, ATH10K_DBG_HTT,
-			   "htt rx dropping due to zero-len\n");
-		return false;
-	}
+	first = skb_peek(amsdu);
+	rxd = (void *)first->data - sizeof(*rxd);
+	decap = MS(__le32_to_cpu(rxd->msdu_start.info1),
+		   RX_MSDU_START_INFO1_DECAP_FORMAT);
 
-	if (attention & RX_ATTENTION_FLAGS_DECRYPT_ERR) {
-		ath10k_dbg(ar, ATH10K_DBG_HTT,
-			   "htt rx dropping due to decrypt-err\n");
-		return false;
+	if (!chained)
+		return;
+
+	/* FIXME: Current unchaining logic can only handle simple case of raw
+	 * msdu chaining. If decapping is other than raw the chaining may be
+	 * more complex and this isn't handled by the current code. Don't even
+	 * try re-constructing such frames - it'll be pretty much garbage.
+	 */
+	if (decap != RX_MSDU_DECAP_RAW ||
+	    skb_queue_len(amsdu) != 1 + rxd->frag_info.ring2_more_count) {
+		__skb_queue_purge(amsdu);
+		return;
 	}
 
-	if (!channel_set) {
-		ath10k_warn(ar, "no channel configured; ignoring frame!\n");
+	ath10k_unchain_msdu(amsdu);
+}
+
+static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
+					struct sk_buff_head *amsdu,
+					struct ieee80211_rx_status *rx_status)
+{
+	struct sk_buff *msdu;
+	struct htt_rx_desc *rxd;
+
+	msdu = skb_peek(amsdu);
+	rxd = (void *)msdu->data - sizeof(*rxd);
+
+	/* FIXME: It might be a good idea to do some fuzzy-testing to drop
+	 * invalid/dangerous frames.
+	 */
+
+	if (!rx_status->freq) {
+		ath10k_warn(ar, "no channel configured; ignoring frame(s)!\n");
 		return false;
 	}
 
-	/* Skip mgmt frames while we handle this in WMI */
-	if (attention & RX_ATTENTION_FLAGS_MGMT_TYPE) {
+	/* Management frames are handled via WMI events. The pros of such
+	 * approach is that channel is explicitly provided in WMI events
+	 * whereas HTT doesn't provide channel information for Rxed frames.
+	 */
+	if (rxd->attention.flags &
+	    __cpu_to_le32(RX_ATTENTION_FLAGS_MGMT_TYPE)) {
 		ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
 		return false;
 	}
 
-	if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) {
-		ath10k_dbg(ar, ATH10K_DBG_HTT,
-			   "htt rx CAC running\n");
+	if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) {
+		ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx cac running\n");
 		return false;
 	}
 
 	return true;
 }
 
+static void ath10k_htt_rx_h_filter(struct ath10k *ar,
+				   struct sk_buff_head *amsdu,
+				   struct ieee80211_rx_status *rx_status)
+{
+	if (skb_queue_empty(amsdu))
+		return;
+
+	if (ath10k_htt_rx_amsdu_allowed(ar, amsdu, rx_status))
+		return;
+
+	__skb_queue_purge(amsdu);
+}
+
 static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 				  struct htt_rx_indication *rx)
 {
@@ -1180,7 +1361,6 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 	struct ieee80211_rx_status *rx_status = &htt->rx_status;
 	struct htt_rx_indication_mpdu_range *mpdu_ranges;
 	struct sk_buff_head amsdu;
-	struct ieee80211_hdr *hdr;
 	int num_mpdu_ranges;
 	u32 attention;
 	int fw_desc_len;
@@ -1247,34 +1427,10 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 			break;
 		}
 
-		if (!ath10k_htt_rx_amsdu_allowed(htt, skb_peek(&amsdu),
-						 channel_set, attention)) {
-			__skb_queue_purge(&amsdu);
-			continue;
-		}
-
-		if (ret > 0 && ath10k_unchain_msdu(&amsdu) < 0) {
-			__skb_queue_purge(&amsdu);
-			continue;
-		}
-
-		if (attention & RX_ATTENTION_FLAGS_FCS_ERR)
-			rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
-		else
-			rx_status->flag &= ~RX_FLAG_FAILED_FCS_CRC;
-
-		if (attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR)
-			rx_status->flag |= RX_FLAG_MMIC_ERROR;
-		else
-			rx_status->flag &= ~RX_FLAG_MMIC_ERROR;
-
-		hdr = ath10k_htt_rx_skb_get_hdr(skb_peek(&amsdu));
-
-		if (ath10k_htt_rx_hdr_is_amsdu(hdr))
-			ath10k_htt_rx_amsdu(htt, rx_status, &amsdu);
-		else
-			ath10k_htt_rx_msdu(htt, rx_status,
-					   __skb_dequeue(&amsdu));
+		ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
+		ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
+		ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
+		ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
 	}
 
 	tasklet_schedule(&htt->rx_replenish_task);
@@ -1284,19 +1440,11 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
 				       struct htt_rx_fragment_indication *frag)
 {
 	struct ath10k *ar = htt->ar;
-	struct sk_buff *msdu;
-	enum htt_rx_mpdu_encrypt_type enctype;
-	struct htt_rx_desc *rxd;
-	enum rx_msdu_decap_format fmt;
 	struct ieee80211_rx_status *rx_status = &htt->rx_status;
-	struct ieee80211_hdr *hdr;
 	struct sk_buff_head amsdu;
 	int ret;
-	bool tkip_mic_err;
-	bool decrypt_err;
 	u8 *fw_desc;
-	int fw_desc_len, hdrlen, paramlen;
-	int trim;
+	int fw_desc_len;
 	u32 attention = 0;
 
 	fw_desc_len = __le16_to_cpu(frag->fw_rx_desc_bytes);
@@ -1326,75 +1474,13 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
 		return;
 	}
 
-	msdu = __skb_dequeue(&amsdu);
-
 	/* FIXME: implement signal strength */
 	rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
 
-	hdr = (struct ieee80211_hdr *)msdu->data;
-	rxd = (void *)msdu->data - sizeof(*rxd);
-	tkip_mic_err = !!(attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR);
-	decrypt_err = !!(attention & RX_ATTENTION_FLAGS_DECRYPT_ERR);
-	fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
-		 RX_MSDU_START_INFO1_DECAP_FORMAT);
-
-	if (fmt != RX_MSDU_DECAP_RAW) {
-		ath10k_warn(ar, "we dont support non-raw fragmented rx yet\n");
-		dev_kfree_skb_any(msdu);
-		goto end;
-	}
-
-	enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
-		     RX_MPDU_START_INFO0_ENCRYPT_TYPE);
-	ath10k_htt_rx_h_protected(htt, rx_status, msdu, enctype, fmt,
-				  true);
-	msdu->ip_summed = ath10k_htt_rx_get_csum_state(msdu);
-
-	if (tkip_mic_err)
-		ath10k_warn(ar, "tkip mic error\n");
-
-	if (decrypt_err) {
-		ath10k_warn(ar, "decryption err in fragmented rx\n");
-		dev_kfree_skb_any(msdu);
-		goto end;
-	}
-
-	if (enctype != HTT_RX_MPDU_ENCRYPT_NONE) {
-		hdrlen = ieee80211_hdrlen(hdr->frame_control);
-		paramlen = ath10k_htt_rx_crypto_param_len(ar, enctype);
-
-		/* It is more efficient to move the header than the payload */
-		memmove((void *)msdu->data + paramlen,
-			(void *)msdu->data,
-			hdrlen);
-		skb_pull(msdu, paramlen);
-		hdr = (struct ieee80211_hdr *)msdu->data;
-	}
-
-	/* remove trailing FCS */
-	trim  = 4;
-
-	/* remove crypto trailer */
-	trim += ath10k_htt_rx_crypto_tail_len(ar, enctype);
-
-	/* last fragment of TKIP frags has MIC */
-	if (!ieee80211_has_morefrags(hdr->frame_control) &&
-	    enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
-		trim += MICHAEL_MIC_LEN;
-
-	if (trim > msdu->len) {
-		ath10k_warn(ar, "htt rx fragment: trailer longer than the frame itself? drop\n");
-		dev_kfree_skb_any(msdu);
-		goto end;
-	}
-
-	skb_trim(msdu, msdu->len - trim);
-
-	ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
-			msdu->data, msdu->len);
-	ath10k_process_rx(htt->ar, rx_status, msdu);
+	ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
+	ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
+	ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
 
-end:
 	if (fw_desc_len > 0) {
 		ath10k_dbg(ar, ATH10K_DBG_HTT,
 			   "expecting more fragmented rx in one indication %d\n",
-- 
1.8.5.3



From kvalo at qca.qualcomm.com  Tue Nov  4 10:37:37 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 4 Nov 2014 20:37:37 +0200
Subject: ath.git master branch rebased to 3.18.0-rc2-wl-ath
Message-ID: <87389y3j7y.fsf@kamboji.qca.qualcomm.com>

Hi,

I just rebased ath.git master branch to 3.18. As this was a rebase, be
careful when updating your local copies.

-- 
Kalle Valo


From greearb at candelatech.com  Tue Nov  4 11:55:42 2014
From: greearb at candelatech.com (Ben Greear)
Date: Tue, 04 Nov 2014 11:55:42 -0800
Subject: [PATCH v2 06/10] ath10k: use configured nss instead of max nss.
In-Reply-To: <1411507045-18973-6-git-send-email-greearb@candelatech.com>
References: <1411507045-18973-1-git-send-email-greearb@candelatech.com>
 <1411507045-18973-6-git-send-email-greearb@candelatech.com>
Message-ID: <54592F3E.10204@candelatech.com>

On 09/23/2014 02:17 PM, greearb at candelatech.com wrote:
> From: Ben Greear <greearb at candelatech.com>
> 
> When re-associating a station, the nss was set back to
> maximum value even if user had configured small number
> of tx chains.  So, pay attention to user's config in
> this case as well.

Looks like this (and probably the related patch) did not make
it upstream yet.

Is someone waiting for more changes from me or did this just
get lost?

Thanks,
Ben

> 
> Signed-off-by: Ben Greear <greearb at candelatech.com>
> ---
> 
> v2:  No changes from v1.
> 
>  drivers/net/wireless/ath/ath10k/mac.c | 11 +++++++++--
>  1 file changed, 9 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
> index e75607d..34ec992 100644
> --- a/drivers/net/wireless/ath/ath10k/mac.c
> +++ b/drivers/net/wireless/ath/ath10k/mac.c
> @@ -4114,6 +4114,10 @@ ath10k_default_bitrate_mask(struct ath10k *ar,
>  	u32 legacy = 0x00ff;
>  	u8 ht = 0xff, i;
>  	u16 vht = 0x3ff;
> +	u16 nrf = ar->num_rf_chains;
> +
> +	if (ar->cfg_tx_chainmask)
> +		nrf = get_nss_from_chainmask(ar->cfg_tx_chainmask);
>  
>  	switch (band) {
>  	case IEEE80211_BAND_2GHZ:
> @@ -4129,11 +4133,11 @@ ath10k_default_bitrate_mask(struct ath10k *ar,
>  	if (mask->control[band].legacy != legacy)
>  		return false;
>  
> -	for (i = 0; i < ar->num_rf_chains; i++)
> +	for (i = 0; i < nrf; i++)
>  		if (mask->control[band].ht_mcs[i] != ht)
>  			return false;
>  
> -	for (i = 0; i < ar->num_rf_chains; i++)
> +	for (i = 0; i < nrf; i++)
>  		if (mask->control[band].vht_mcs[i] != vht)
>  			return false;
>  
> @@ -4384,6 +4388,9 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
>  	u8 fixed_nss = ar->num_rf_chains;
>  	u8 force_sgi;
>  
> +	if (ar->cfg_tx_chainmask)
> +		fixed_nss = get_nss_from_chainmask(ar->cfg_tx_chainmask);
> +
>  	force_sgi = mask->control[band].gi;
>  	if (force_sgi == NL80211_TXRATE_FORCE_LGI)
>  		return -EINVAL;
> 


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



From kvalo at qca.qualcomm.com  Tue Nov  4 17:29:13 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 5 Nov 2014 03:29:13 +0200
Subject: [PATCH v2] ath10k: handle ieee80211 header and payload tracing
 separately
In-Reply-To: <20141104051643.GA14509@qca.qualcomm.com> (Rajkumar Manoharan's
 message of "Tue, 4 Nov 2014 10:46:45 +0530")
References: <1414661336-20764-1-git-send-email-rmanohar@qti.qualcomm.com>
 <874muf7t9u.fsf@kamboji.qca.qualcomm.com>
 <20141104051643.GA14509@qca.qualcomm.com>
Message-ID: <87k33a1lli.fsf@kamboji.qca.qualcomm.com>

Rajkumar Manoharan <rmanohar at qti.qualcomm.com> writes:

> On Tue, Nov 04, 2014 at 01:34:37AM +0200, Kalle Valo wrote:
>> Rajkumar Manoharan <rmanohar at qti.qualcomm.com> writes:
>> 
>> > For packet log, the transmitted frame 802.11 header alone is sufficient.
>> > Recording entire packet is also consuming lot of disk space. To optimize
>> > this, tx and rx data tracepoints are splitted into header and payload
>> > tracepoints.
>> >  
>> > -DECLARE_EVENT_CLASS(ath10k_data_event,
>> > +#define ATH10K_FRM_HDR_LEN  \
>> > +	ieee80211_hdrlen(((struct ieee80211_hdr *)data)->frame_control)
>> 
>> This macro does not look good. I would recommend to follow what Johannes
>> suggested:
>>
>> "It would be worth hiding that inside the tracepoint's assign function,
>> so instead of passing data/len here you'd pass the full skb, or the full
>> skb data/skb len, like this:
>> 
>> ar, skb->data, skb->len
>> 
>> to both tracers. Then inside the tracer you can do the hdrlen check, and
>> that way move the code into the tracing so it's not hit when tracing is
>> disabled."
>
> v2 does the same. tracing functions just take ar, skb->data and skb->len.
> header check is handled inside tracing funtions.
>
> I do not understand your concerns. :(

Sorry, I was confusing. I meant that wouldn't it be better to pass the
skb pointer instead of skb-data and skb->len? I understood that was what
Johannes suggested.

But ATH10K_FRM_HDR_LEN is the problem. To simplify this, what if you
just always send the first 30 bytes (or whatever would be the max header
length)? Also should you check that skb->len is at least the length
defined by ieee80211_hdrlen()?

-- 
Kalle Valo


From ohlee at mwnl.snu.ac.kr  Wed Nov  5 00:35:59 2014
From: ohlee at mwnl.snu.ac.kr (Okhwan Lee)
Date: Wed, 5 Nov 2014 17:35:59 +0900
Subject: 11ac packet capture using Wireshark & QCA9880
Message-ID: <etPan.5459e16f.19495cff.8770@Mac-Pro.local>

Hi all,?

We install a station to capture 11ac packets using wireshark.?
The station equips with QCA 9880 and operates ?Ubuntu (Kernel version 3.16.1)
We also install backport (3.16.1) to use the emerging ath10k device driver and 10.1.467.2-1 firmware.?

In our testbed, there is three nodes, AP (ASUS AC66), client (QCA9880) and the monitor station (QCA9880).?
The monitor station can capture the packets transmitted by AP but not capture the packets transmitted by the client.?
We use the same parameter settings (MCS~0, 1 streams, 20 MHz bandwidth, BCC, long preamble) on both AP and client, so there may be no packet error or loss.?
We also confirm that the packets transmitted by AP contain VHT information.?
In other word, ?the monitor station can capture 11ac packets (VHT-PPDU).?

Is there any reason why QCA 9880 can not capture only packets transmitted by the client equipped with QCA9880?

--?
Okhwan Lee
Sent with Airmail


From ohlee at mwnl.snu.ac.kr  Wed Nov  5 00:41:58 2014
From: ohlee at mwnl.snu.ac.kr (Okhwan Lee)
Date: Wed, 5 Nov 2014 17:41:58 +0900
Subject: Tx power setting
Message-ID: <etPan.5459e2d6.2ae8944a.8770@Mac-Pro.local>

Hi,?

We are trying to change the tx power of QCA 9880.  
We use 3.16.1 linux kernel and backport (3.16.1) to use the emerging ath10k device driver and 10.1.467.2-1 firmware.?

However, we can not change the tx power setting (default 0 dBm) by using iw or iwconfig commands.?
Based on my understanding, if we change the tx power using the commands, ath10k_config() function should be invoked.?
However, the function is not called.?
And the received signal strength at the receiver side does not change.?

If you have any idea, please let me know.?

Thank you.

--  
Okhwan Lee
Sent with Airmail


From michal.kazior at tieto.com  Wed Nov  5 01:05:21 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Wed, 5 Nov 2014 10:05:21 +0100
Subject: 11ac packet capture using Wireshark & QCA9880
In-Reply-To: <etPan.5459e16f.19495cff.8770@Mac-Pro.local>
References: <etPan.5459e16f.19495cff.8770@Mac-Pro.local>
Message-ID: <CA+BoTQkAGQhcdagiy_q-88HGgh8aNRNSSTF74rb6BzaBY1FwUQ@mail.gmail.com>

On 5 November 2014 09:35, Okhwan Lee <ohlee at mwnl.snu.ac.kr> wrote:
> Hi all,
>
> We install a station to capture 11ac packets using wireshark.
> The station equips with QCA 9880 and operates  Ubuntu (Kernel version 3.16.1)
> We also install backport (3.16.1) to use the emerging ath10k device driver and 10.1.467.2-1 firmware.
>
> In our testbed, there is three nodes, AP (ASUS AC66), client (QCA9880) and the monitor station (QCA9880).
> The monitor station can capture the packets transmitted by AP but not capture the packets transmitted by the client.
> We use the same parameter settings (MCS~0, 1 streams, 20 MHz bandwidth, BCC, long preamble) on both AP and client, so there may be no packet error or loss.
> We also confirm that the packets transmitted by AP contain VHT information.
> In other word,  the monitor station can capture 11ac packets (VHT-PPDU).
>
> Is there any reason why QCA 9880 can not capture only packets transmitted by the client equipped with QCA9880?

Hmm.. This may be related to A-MSDU. ath10k's msdu chaining code
doesn't handle all possible cases.

ath10k's firmware does A-MSDU for sure. I'm guessing AC66 doesn't do
it (or does it less often) - this would explain why sniffing AP -> STA
traffic works while STA -> AP does not.

Do you use encryption? Can you try setting the AP without encryption
and see if you can sniff STA -> AP traffic?

Another thing to try is to override amsdu aggregation setup on the STA:
 mount -t debugfs debug /sys/kernel/debug
 echo 1 64 > /sys/kernel/debug/ieee80211/phy*/ath10k/htt_max_amsdu_ampdu

This should effectively disable A-MSDU Tx on the ath10k STA so it
should check if this is related to msdu chaining at all.

I'm aware neither of this is a solution. It's more of a confirmation
if my reasoning is correct.


Micha?


From rmanohar at qti.qualcomm.com  Wed Nov  5 01:44:39 2014
From: rmanohar at qti.qualcomm.com (Rajkumar Manoharan)
Date: Wed, 5 Nov 2014 15:14:39 +0530
Subject: [PATCH v2] ath10k: handle ieee80211 header and payload tracing
 separately
In-Reply-To: <87k33a1lli.fsf@kamboji.qca.qualcomm.com>
References: <1414661336-20764-1-git-send-email-rmanohar@qti.qualcomm.com>
 <874muf7t9u.fsf@kamboji.qca.qualcomm.com>
 <20141104051643.GA14509@qca.qualcomm.com>
 <87k33a1lli.fsf@kamboji.qca.qualcomm.com>
Message-ID: <20141105094437.GA21839@qca.qualcomm.com>

On Wed, Nov 05, 2014 at 03:29:13AM +0200, Kalle Valo wrote:
> Rajkumar Manoharan <rmanohar at qti.qualcomm.com> writes:
> 
> > On Tue, Nov 04, 2014 at 01:34:37AM +0200, Kalle Valo wrote:
> >> Rajkumar Manoharan <rmanohar at qti.qualcomm.com> writes:
> >> 
> >> > -DECLARE_EVENT_CLASS(ath10k_data_event,
> >> > +#define ATH10K_FRM_HDR_LEN  \
> >> > +	ieee80211_hdrlen(((struct ieee80211_hdr *)data)->frame_control)
> >> 
> >> This macro does not look good. I would recommend to follow what Johannes
> >> suggested:
> >>
> >
> > v2 does the same. tracing functions just take ar, skb->data and skb->len.
> > header check is handled inside tracing funtions.
> >
> > I do not understand your concerns. :(
> 
> Sorry, I was confusing. I meant that wouldn't it be better to pass the
> skb pointer instead of skb-data and skb->len? I understood that was what
> Johannes suggested.
> 
> But ATH10K_FRM_HDR_LEN is the problem. To simplify this, what if you
> just always send the first 30 bytes (or whatever would be the max header
> length)? Also should you check that skb->len is at least the length
> defined by ieee80211_hdrlen()?
>
The goal of header & payload split is to reduce the amount of data being
collected. Sending maximum header size always will unnecessarily
increase the trace.dat size as hdr_size for mgmt and beacon always be 24.
This will also increase tracing traffic when it is being collected in
remote machine.

since tracepoints are being called only after the preprocessing,
skb->len never be lesser than 802.11 header size.

The macro is defined to ease readability and reduce # of line changes.
I originally thought of naming the macro as IEEE80211_HDR_LEN. But such
definition does not look correct inside driver.

-Rajkumar


From johannes at sipsolutions.net  Wed Nov  5 02:12:01 2014
From: johannes at sipsolutions.net (Johannes Berg)
Date: Wed, 05 Nov 2014 11:12:01 +0100
Subject: [PATCH v2] ath10k: handle ieee80211 header and payload tracing
 separately
In-Reply-To: <20141105094437.GA21839@qca.qualcomm.com>
 (sfid-20141105_104310_542370_58A02806)
References: <1414661336-20764-1-git-send-email-rmanohar@qti.qualcomm.com>
 <874muf7t9u.fsf@kamboji.qca.qualcomm.com>
 <20141104051643.GA14509@qca.qualcomm.com>
 <87k33a1lli.fsf@kamboji.qca.qualcomm.com>
 <20141105094437.GA21839@qca.qualcomm.com>
 (sfid-20141105_104310_542370_58A02806)
Message-ID: <1415182321.2589.14.camel@sipsolutions.net>

On Wed, 2014-11-05 at 15:14 +0530, Rajkumar Manoharan wrote:

> The macro is defined to ease readability and reduce # of line changes.
> I originally thought of naming the macro as IEEE80211_HDR_LEN. But such
> definition does not look correct inside driver.

FWIW, I pointed Kalle to the macro on IRC - IMHO you should pass
arguments to the macro (and probably even make it an inline function)
rather than having it assume certain variables exist when the macro is
used.

Kalle may have misunderstood what I was trying to say :)

johannes



From rmanohar at qti.qualcomm.com  Wed Nov  5 02:44:59 2014
From: rmanohar at qti.qualcomm.com (Rajkumar Manoharan)
Date: Wed, 5 Nov 2014 16:14:59 +0530
Subject: [PATCH v2] ath10k: handle ieee80211 header and payload tracing
 separately
In-Reply-To: <1415182321.2589.14.camel@sipsolutions.net>
References: <1414661336-20764-1-git-send-email-rmanohar@qti.qualcomm.com>
 <874muf7t9u.fsf@kamboji.qca.qualcomm.com>
 <20141104051643.GA14509@qca.qualcomm.com>
 <87k33a1lli.fsf@kamboji.qca.qualcomm.com>
 <20141105094437.GA21839@qca.qualcomm.com>
 <1415182321.2589.14.camel@sipsolutions.net>
Message-ID: <20141105104458.GA13249@qca.qualcomm.com>

On Wed, Nov 05, 2014 at 11:12:01AM +0100, Johannes Berg wrote:
> On Wed, 2014-11-05 at 15:14 +0530, Rajkumar Manoharan wrote:
> 
> > The macro is defined to ease readability and reduce # of line changes.
> > I originally thought of naming the macro as IEEE80211_HDR_LEN. But such
> > definition does not look correct inside driver.
> 
> FWIW, I pointed Kalle to the macro on IRC - IMHO you should pass
> arguments to the macro (and probably even make it an inline function)
> rather than having it assume certain variables exist when the macro is
> used.
> 
> Kalle may have misunderstood what I was trying to say :)
> 
Sounds clear..Thanks for pointing out. Will change it as inline funtion..

-Rajkumar


From rmanohar at qti.qualcomm.com  Wed Nov  5 05:44:31 2014
From: rmanohar at qti.qualcomm.com (Rajkumar Manoharan)
Date: Wed, 5 Nov 2014 19:14:31 +0530
Subject: [PATCH v3] ath10k: handle ieee80211 header and payload tracing
 separately
Message-ID: <1415195071-30250-1-git-send-email-rmanohar@qti.qualcomm.com>

For packet log, the transmitted frame 802.11 header alone is sufficient.
Recording entire packet is also consuming lot of disk space. To optimize
this, tx and rx data tracepoints are splitted into header and payload
tracepoints.

To record tx ieee80211 headers

     trace-cmd record -e ath10k_tx_hdr

To record complete packets

     trace-cmd record -e ath10k_tx_hdr -e ath10k_tx_payload

Cc: Michal Kazior <michal.kazior at tieto.com>
Signed-off-by: Rajkumar Manoharan <rmanohar at qti.qualcomm.com>
---
v2: Move header len processing inside trace
v3: Replace ATH10K_FRM_HDR_LEN by inline function
 drivers/net/wireless/ath/ath10k/htt_rx.c |  4 +-
 drivers/net/wireless/ath/ath10k/htt_tx.c |  3 +-
 drivers/net/wireless/ath/ath10k/trace.h  | 80 +++++++++++++++++++++++++++-----
 drivers/net/wireless/ath/ath10k/wmi.c    |  7 ++-
 4 files changed, 78 insertions(+), 16 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index a691fdf..52c6306 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -297,8 +297,6 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
 			 DMA_FROM_DEVICE);
 	ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx netbuf pop: ",
 			msdu->data, msdu->len + skb_tailroom(msdu));
-	trace_ath10k_htt_rx_pop_msdu(ar, msdu->data, msdu->len +
-				     skb_tailroom(msdu));
 
 	return msdu;
 }
@@ -903,6 +901,8 @@ static void ath10k_process_rx(struct ath10k *ar,
 		   !!(status->flag & RX_FLAG_AMSDU_MORE));
 	ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
 			skb->data, skb->len);
+	trace_ath10k_rx_hdr(ar, skb->data, skb->len);
+	trace_ath10k_rx_payload(ar, skb->data, skb->len);
 
 	ieee80211_rx(ar->hw, skb);
 }
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index b0df470..1e51249 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -564,7 +564,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 		   (u32)skb_cb->paddr, vdev_id, tid);
 	ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
 			msdu->data, msdu->len);
-	trace_ath10k_htt_tx_msdu(ar, msdu->data, msdu->len);
+	trace_ath10k_tx_hdr(ar, msdu->data, msdu->len);
+	trace_ath10k_tx_payload(ar, msdu->data, msdu->len);
 
 	sg_items[0].transfer_id = 0;
 	sg_items[0].transfer_context = NULL;
diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h
index b9a2ba6..ceea566 100644
--- a/drivers/net/wireless/ath/ath10k/trace.h
+++ b/drivers/net/wireless/ath/ath10k/trace.h
@@ -20,6 +20,13 @@
 #include <linux/tracepoint.h>
 #include "core.h"
 
+#if !defined(_TRACE_H_)
+static inline u32 ath10k_frm_hdr_len(void *buf)
+{
+	return ieee80211_hdrlen(((struct ieee80211_hdr *)buf)->frame_control);
+}
+#endif
+
 #define _TRACE_H_
 
 /* create empty functions when tracing is disabled */
@@ -341,7 +348,7 @@ TRACE_EVENT(ath10k_txrx_tx_unref,
 	 )
 );
 
-DECLARE_EVENT_CLASS(ath10k_data_event,
+DECLARE_EVENT_CLASS(ath10k_hdr_event,
 		    TP_PROTO(struct ath10k *ar, void *data, size_t len),
 
 	TP_ARGS(ar, data, len),
@@ -350,14 +357,14 @@ DECLARE_EVENT_CLASS(ath10k_data_event,
 		__string(device, dev_name(ar->dev))
 		__string(driver, dev_driver_string(ar->dev))
 		__field(size_t, len)
-		__dynamic_array(u8, data, len)
+		__dynamic_array(u8, data, ath10k_frm_hdr_len(data))
 	),
 
 	TP_fast_assign(
 		__assign_str(device, dev_name(ar->dev));
 		__assign_str(driver, dev_driver_string(ar->dev));
-		__entry->len = len;
-		memcpy(__get_dynamic_array(data), data, len);
+		__entry->len = ath10k_frm_hdr_len(data);
+		memcpy(__get_dynamic_array(data), data, __entry->len);
 	),
 
 	TP_printk(
@@ -368,30 +375,81 @@ DECLARE_EVENT_CLASS(ath10k_data_event,
 	)
 );
 
-DEFINE_EVENT(ath10k_data_event, ath10k_htt_tx_msdu,
-	     TP_PROTO(struct ath10k *ar, void *data, size_t len),
-	     TP_ARGS(ar, data, len)
+DECLARE_EVENT_CLASS(ath10k_payload_event,
+		    TP_PROTO(struct ath10k *ar, void *data, size_t len),
+
+	TP_ARGS(ar, data, len),
+
+	TP_STRUCT__entry(
+		__string(device, dev_name(ar->dev))
+		__string(driver, dev_driver_string(ar->dev))
+		__field(size_t, len)
+		__dynamic_array(u8, payload, (len - ath10k_frm_hdr_len(data)))
+	),
+
+	TP_fast_assign(
+		__assign_str(device, dev_name(ar->dev));
+		__assign_str(driver, dev_driver_string(ar->dev));
+		__entry->len = len - ath10k_frm_hdr_len(data);
+		memcpy(__get_dynamic_array(payload),
+		       data + ath10k_frm_hdr_len(data), __entry->len);
+	),
+
+	TP_printk(
+		"%s %s len %zu\n",
+		__get_str(driver),
+		__get_str(device),
+		__entry->len
+	)
 );
 
-DEFINE_EVENT(ath10k_data_event, ath10k_htt_rx_pop_msdu,
+DEFINE_EVENT(ath10k_hdr_event, ath10k_tx_hdr,
 	     TP_PROTO(struct ath10k *ar, void *data, size_t len),
 	     TP_ARGS(ar, data, len)
 );
 
-DEFINE_EVENT(ath10k_data_event, ath10k_wmi_mgmt_tx,
+DEFINE_EVENT(ath10k_payload_event, ath10k_tx_payload,
 	     TP_PROTO(struct ath10k *ar, void *data, size_t len),
 	     TP_ARGS(ar, data, len)
 );
 
-DEFINE_EVENT(ath10k_data_event, ath10k_wmi_bcn_tx,
+DEFINE_EVENT(ath10k_hdr_event, ath10k_rx_hdr,
 	     TP_PROTO(struct ath10k *ar, void *data, size_t len),
 	     TP_ARGS(ar, data, len)
 );
 
-DEFINE_EVENT(ath10k_data_event, ath10k_htt_rx_desc,
+DEFINE_EVENT(ath10k_payload_event, ath10k_rx_payload,
 	     TP_PROTO(struct ath10k *ar, void *data, size_t len),
 	     TP_ARGS(ar, data, len)
 );
+
+TRACE_EVENT(ath10k_htt_rx_desc,
+	    TP_PROTO(struct ath10k *ar, void *data, size_t len),
+
+	TP_ARGS(ar, data, len),
+
+	TP_STRUCT__entry(
+		__string(device, dev_name(ar->dev))
+		__string(driver, dev_driver_string(ar->dev))
+		__field(u16, len)
+		__dynamic_array(u8, rxdesc, len)
+	),
+
+	TP_fast_assign(
+		__assign_str(device, dev_name(ar->dev));
+		__assign_str(driver, dev_driver_string(ar->dev));
+		__entry->len = len;
+		memcpy(__get_dynamic_array(rxdesc), data, len);
+	),
+
+	TP_printk(
+		"%s %s rxdesc len %d",
+		__get_str(driver),
+		__get_str(device),
+		__entry->len
+	 )
+);
+
 #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/
 
 /* we don't want to use include/trace/events */
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index ae746ce..3dcb216 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -834,7 +834,8 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
 		   wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE,
 		   fc & IEEE80211_FCTL_STYPE);
-	trace_ath10k_wmi_mgmt_tx(ar, skb->data, skb->len);
+	trace_ath10k_tx_hdr(ar, skb->data, skb->len);
+	trace_ath10k_tx_payload(ar, skb->data, skb->len);
 
 	/* Send the management frame buffer to the target */
 	ret = ath10k_wmi_cmd_send(ar, wmi_skb, ar->wmi.cmd->mgmt_tx_cmdid);
@@ -1893,7 +1894,9 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
 		arvif->beacon = bcn;
 		arvif->beacon_sent = false;
 
-		trace_ath10k_wmi_bcn_tx(ar, bcn->data, bcn->len);
+		trace_ath10k_tx_hdr(ar, bcn->data, bcn->len);
+		trace_ath10k_tx_payload(ar, bcn->data, bcn->len);
+
 		ath10k_wmi_tx_beacon_nowait(arvif);
 skip:
 		spin_unlock_bh(&ar->data_lock);
-- 
2.1.3



From michal.kazior at tieto.com  Wed Nov  5 05:54:54 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Wed, 5 Nov 2014 14:54:54 +0100
Subject: Tx power setting
In-Reply-To: <etPan.5459e2d6.2ae8944a.8770@Mac-Pro.local>
References: <etPan.5459e2d6.2ae8944a.8770@Mac-Pro.local>
Message-ID: <CA+BoTQkJJjNG09Pp_Svpmr+4soXT8Dw1En91BrW9GnnhEFwhYg@mail.gmail.com>

On 5 November 2014 09:41, Okhwan Lee <ohlee at mwnl.snu.ac.kr> wrote:
> Hi,
>
> We are trying to change the tx power of QCA 9880.
> We use 3.16.1 linux kernel and backport (3.16.1) to use the emerging ath10k device driver and 10.1.467.2-1 firmware.
>
> However, we can not change the tx power setting (default 0 dBm) by using iw or iwconfig commands.

What do you mean "can not change". Do you get an error message? Where
does it say you have 0 dBm as the default?


> Based on my understanding, if we change the tx power using the commands, ath10k_config() function should be invoked.
> However, the function is not called.
> And the received signal strength at the receiver side does not change.
>
> If you have any idea, please let me know.

I'm using fbb5c042800ec42459a5cc307dec566d8e316927 from
github.com/kvalo/ath/ (based on 3.17). I don't see the problem you
describe - I can change tx powed with, e.g. `iw wlan1 set txpower
fixed 1000`. The other end reports different signal strength values
when I change txpower. Can you re-test with latest ath10k code,
please?


Micha?


From michal.kazior at tieto.com  Wed Nov  5 06:09:46 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Wed, 5 Nov 2014 15:09:46 +0100
Subject: TX Power Concerns between Firmware
In-Reply-To: <CAD1M062Um6PY2fE4AiM6D3=_McdTMkixzYQ23kYwM7_xdZR=wA@mail.gmail.com>
References: <CAD1M062Um6PY2fE4AiM6D3=_McdTMkixzYQ23kYwM7_xdZR=wA@mail.gmail.com>
Message-ID: <CA+BoTQkTpV1LViDWAj1yZwCgshStzHhGe9DTD8S++DK8uUe9oQ@mail.gmail.com>

On 29 October 2014 23:56, Pushpal Sidhu <psidhu at gateworks.com> wrote:
> Hi all,
>
[...]
> The follow are my results:
> | Firmware     | txpower (software) | reading | +15dBm offset |
> | 10.1.467.2-1 | 15                       | -6         | 9                     |
> | ''                  | 10                       | -10.6     | 4.4
>              |
>
> Then same radio(s), different firmware:
> | Firmware        | txpower (software) | reading | +15dBm offset |
> | 999.999.0.636 | 15                        | 10.3     | 25.3                |
> | ''                    | 10                        | 7.5       | 22.5
>                |
>
>
> As you can see, the results are wildly different. Is this something
> that the driver can fix? Or is this a firmware problem? It goes
> without saying that this is a big danger for devices etc connected to
> the radio.

Thanks for reporting.

My rough guess is the 999.999.0.636 blob has an old otp binary
embedded inside which doesn't support the XB140 design. We probably
need to update it.

@Kalle: Now that I think about it - do we really need to embed otp binaries?


Micha?


From greearb at candelatech.com  Wed Nov  5 09:39:44 2014
From: greearb at candelatech.com (Ben Greear)
Date: Wed, 05 Nov 2014 09:39:44 -0800
Subject: Slow connect times?
In-Reply-To: <CAHqTa-21YOPiV_UxxWh23mB7AqLhj0n+h6eA5cTUH8eh32heRw@mail.gmail.com>
References: <5458261C.2020700@candelatech.com>
 <CAHqTa-21YOPiV_UxxWh23mB7AqLhj0n+h6eA5cTUH8eh32heRw@mail.gmail.com>
Message-ID: <545A60E0.8070308@candelatech.com>

On 11/03/2014 05:35 PM, Avery Pennarun wrote:
> On Mon, Nov 3, 2014 at 8:04 PM, Ben Greear <greearb at candelatech.com> wrote:
>> If I am reading my results right, it takes over 2 seconds to associate an
>> ath10k station with WPA2 PSK on my systems.
>>
>> I was thinking this should be quite a bit faster than this...
>>
>> Has anyone done any similar measurements?
> 
> I haven't noticed any delay like this.  WPA2 PSK negotiation is on the
> order of ~200ms or less. Then DHCP screws around for a few seconds,
> often.
> 
> A packet trace would probably be useful for narrowing it down :)
> 

First part of my problem is that I had some extra debugging turned on and
that was being sent to serial console, which is slow.

But, even with that off I am still seeing ~200ms at best.

Ath9k system on crappy old Atom processors usually completes in
less than 20ms for comparison.

Off to go spelunking in the ath10k code :P

Thanks,
Ben

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



From apenwarr at gmail.com  Wed Nov  5 10:58:18 2014
From: apenwarr at gmail.com (Avery Pennarun)
Date: Wed, 5 Nov 2014 10:58:18 -0800
Subject: Slow connect times?
In-Reply-To: <545A60E0.8070308@candelatech.com>
References: <5458261C.2020700@candelatech.com>
 <CAHqTa-21YOPiV_UxxWh23mB7AqLhj0n+h6eA5cTUH8eh32heRw@mail.gmail.com>
 <545A60E0.8070308@candelatech.com>
Message-ID: <CAHqTa-2OKoKSqQXmfAq5esu5SWXJRvL8Vy+GMRsq4XertnTaFA@mail.gmail.com>

On Wed, Nov 5, 2014 at 9:39 AM, Ben Greear <greearb at candelatech.com> wrote:
> On 11/03/2014 05:35 PM, Avery Pennarun wrote:
>> On Mon, Nov 3, 2014 at 8:04 PM, Ben Greear <greearb at candelatech.com> wrote:
>>> If I am reading my results right, it takes over 2 seconds to associate an
>>> ath10k station with WPA2 PSK on my systems.
>>>
>>> I was thinking this should be quite a bit faster than this...
>>>
>>> Has anyone done any similar measurements?
>>
>> I haven't noticed any delay like this.  WPA2 PSK negotiation is on the
>> order of ~200ms or less. Then DHCP screws around for a few seconds,
>> often.
>>
>> A packet trace would probably be useful for narrowing it down :)
>
> First part of my problem is that I had some extra debugging turned on and
> that was being sent to serial console, which is slow.
>
> But, even with that off I am still seeing ~200ms at best.
>
> Ath9k system on crappy old Atom processors usually completes in
> less than 20ms for comparison.
>
> Off to go spelunking in the ath10k code :P

That's very interesting for me.  200ms was kind of a worst case in my
traces, and I'm mostly seeing 20-40ms.  I think the key exchange is
all hostapd, so I'm surprised it would take so long.  Do you have a
trace?

Note that I *have* seen weird problems with delayed probe packets to
some clients, which could cause things like this.  But that's
apparently only because I applied Michal's patch to get rid of queue
blocking :)


From greearb at candelatech.com  Wed Nov  5 11:03:40 2014
From: greearb at candelatech.com (Ben Greear)
Date: Wed, 05 Nov 2014 11:03:40 -0800
Subject: Slow connect times?
In-Reply-To: <CAHqTa-2OKoKSqQXmfAq5esu5SWXJRvL8Vy+GMRsq4XertnTaFA@mail.gmail.com>
References: <5458261C.2020700@candelatech.com>
 <CAHqTa-21YOPiV_UxxWh23mB7AqLhj0n+h6eA5cTUH8eh32heRw@mail.gmail.com>
 <545A60E0.8070308@candelatech.com>
 <CAHqTa-2OKoKSqQXmfAq5esu5SWXJRvL8Vy+GMRsq4XertnTaFA@mail.gmail.com>
Message-ID: <545A748C.9040008@candelatech.com>

On 11/05/2014 10:58 AM, Avery Pennarun wrote:
> On Wed, Nov 5, 2014 at 9:39 AM, Ben Greear <greearb at candelatech.com> wrote:
>> On 11/03/2014 05:35 PM, Avery Pennarun wrote:
>>> On Mon, Nov 3, 2014 at 8:04 PM, Ben Greear <greearb at candelatech.com> wrote:
>>>> If I am reading my results right, it takes over 2 seconds to associate an
>>>> ath10k station with WPA2 PSK on my systems.
>>>>
>>>> I was thinking this should be quite a bit faster than this...
>>>>
>>>> Has anyone done any similar measurements?
>>>
>>> I haven't noticed any delay like this.  WPA2 PSK negotiation is on the
>>> order of ~200ms or less. Then DHCP screws around for a few seconds,
>>> often.
>>>
>>> A packet trace would probably be useful for narrowing it down :)
>>
>> First part of my problem is that I had some extra debugging turned on and
>> that was being sent to serial console, which is slow.
>>
>> But, even with that off I am still seeing ~200ms at best.
>>
>> Ath9k system on crappy old Atom processors usually completes in
>> less than 20ms for comparison.
>>
>> Off to go spelunking in the ath10k code :P
> 
> That's very interesting for me.  200ms was kind of a worst case in my
> traces, and I'm mostly seeing 20-40ms.  I think the key exchange is
> all hostapd, so I'm surprised it would take so long.  Do you have a
> trace?
> 
> Note that I *have* seen weird problems with delayed probe packets to
> some clients, which could cause things like this.  But that's
> apparently only because I applied Michal's patch to get rid of queue
> blocking :)
> 

My first station comes up in ~20ms, the second one (on same machine) takes ~200ms.  If I try
bringing up 10 as fast as supplicant can do it's thing, then it takes around 1 sec for each
station.

Does not appear to be an AP problem, as ath9k stations to the ath10k AP are all
in the 20ms range.

I'm updating my test systems Fedora 20 to have easier use of some debugging tools and will then
start figuring out where the slowness is.  I'm running my firmware with patches that
should help with flush related problems, but that is still my first suspect!

Thanks,
Ben

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



From apenwarr at gmail.com  Wed Nov  5 11:12:14 2014
From: apenwarr at gmail.com (Avery Pennarun)
Date: Wed, 5 Nov 2014 11:12:14 -0800
Subject: Slow connect times?
In-Reply-To: <545A748C.9040008@candelatech.com>
References: <5458261C.2020700@candelatech.com>
 <CAHqTa-21YOPiV_UxxWh23mB7AqLhj0n+h6eA5cTUH8eh32heRw@mail.gmail.com>
 <545A60E0.8070308@candelatech.com>
 <CAHqTa-2OKoKSqQXmfAq5esu5SWXJRvL8Vy+GMRsq4XertnTaFA@mail.gmail.com>
 <545A748C.9040008@candelatech.com>
Message-ID: <CAHqTa-0nHBHR5FrxWvDfp7bhfN8LOK-EhpX+LDYPwBRvkZSWxw@mail.gmail.com>

On Wed, Nov 5, 2014 at 11:03 AM, Ben Greear <greearb at candelatech.com> wrote:
> Does not appear to be an AP problem, as ath9k stations to the ath10k AP are all
> in the 20ms range.

Ah, ok, I just assumed you were using ath10k as an AP.  In that case I
know nothing :)


From toshik at chromium.org  Wed Nov  5 15:25:52 2014
From: toshik at chromium.org (Toshi Kikuchi)
Date: Wed,  5 Nov 2014 15:25:52 -0800
Subject: [PATCH] ath10k: read calibration data from Device Tree
Message-ID: <1415229952-11929-1-git-send-email-toshik@chromium.org>

(This patch is based on Kalle Valo's "[PROTOTYPE PATCH] ath10k: prototype
code for Device Tree support")

This patch adds support for reading calibration data from Device Tree.

The node for the calibration data should look like this:

pci {
        pcie at 0 {
                reg = <0 0 0 0 0>;
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
                device_type = "pci";

                ath10k at 0,0 {
                        reg = <0 0 0 0 0>;
                        device_type = "pci";
                        qcom,ath10k-calibration-data = [ 01 02 03 ... ];
                };
        };
};

Signed-off-by: Toshi Kikuchi <toshik at chromium.org>
---
 drivers/net/wireless/ath/ath10k/core.c | 71 +++++++++++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath10k/core.h |  3 ++
 2 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 5c23d00..dc5928b 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -17,6 +17,7 @@
 
 #include <linux/module.h>
 #include <linux/firmware.h>
+#include <linux/of.h>
 
 #include "core.h"
 #include "mac.h"
@@ -27,6 +28,7 @@
 #include "debug.h"
 #include "htt.h"
 #include "testmode.h"
+#include "pci.h"
 
 unsigned int ath10k_debug_mask;
 static bool uart_print;
@@ -244,6 +246,67 @@ static int ath10k_download_cal_file(struct ath10k *ar)
 	return 0;
 }
 
+static int ath10k_download_cal_dt(struct ath10k *ar)
+{
+	struct device_node *node;
+	int data_len;
+	void *data;
+	int ret;
+
+	node = pci_device_to_OF_node(ath10k_pci_priv(ar)->pdev);
+	if (!node)
+		/* Device Tree is optional, don't print any warnings if
+		 * there's no node for ath10k.
+		 */
+		return -ENOENT;
+
+	if (!of_get_property(node, "qcom,ath10k-calibration-data",
+			     &data_len)) {
+		ath10k_warn(ar, "failed to find cal data length from DT: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (data_len != QCA988X_CAL_DATA_LEN) {
+		ath10k_warn(ar, "invalid calibration data length in DT: %d\n",
+			    data_len);
+		ret = -EMSGSIZE;
+		goto out;
+	}
+
+	data = kmalloc(data_len, GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = of_property_read_u8_array(node, "qcom,ath10k-calibration-data",
+					data, data_len);
+	if (ret) {
+		ath10k_warn(ar,
+			    "failed to read calibration data from DT: %d\n",
+			    ret);
+		goto out_free;
+	}
+
+	ret = ath10k_download_board_data(ar, data, data_len);
+	if (ret) {
+		ath10k_warn(ar,
+			    "failed to download calibration data from "
+			    "Device Tree: %d\n",
+			    ret);
+		goto out_free;
+	}
+
+	ret = 0;
+
+out_free:
+	kfree(data);
+
+out:
+	return ret;
+}
+
 static int ath10k_download_and_run_otp(struct ath10k *ar)
 {
 	u32 result, address = ar->hw_params.patch_load_addr;
@@ -657,9 +720,15 @@ static int ath10k_download_cal_data(struct ath10k *ar)
 	}
 
 	ath10k_dbg(ar, ATH10K_DBG_BOOT,
-		   "boot did not find a calibration file, try OTP next: %d\n",
+		   "boot did not find a calibration file, try DT next: %d\n",
 		   ret);
 
+	ret = ath10k_download_cal_dt(ar);
+	if (ret == 0) {
+		ar->cal_mode = ATH10K_CAL_MODE_DT;
+		goto done;
+	}
+
 	ret = ath10k_download_and_run_otp(ar);
 	if (ret) {
 		ath10k_err(ar, "failed to run otp: %d\n", ret);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 1e3fd10..8e89e31 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -391,6 +391,7 @@ enum ath10k_dev_flags {
 enum ath10k_cal_mode {
 	ATH10K_CAL_MODE_FILE,
 	ATH10K_CAL_MODE_OTP,
+	ATH10K_CAL_MODE_DT,
 };
 
 static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
@@ -400,6 +401,8 @@ static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
 		return "file";
 	case ATH10K_CAL_MODE_OTP:
 		return "otp";
+	case ATH10K_CAL_MODE_DT:
+		return "dt";
 	}
 
 	return "unknown";



From greearb at candelatech.com  Wed Nov  5 16:49:25 2014
From: greearb at candelatech.com (Ben Greear)
Date: Wed, 05 Nov 2014 16:49:25 -0800
Subject: Slow connect times?
In-Reply-To: <CAHqTa-0nHBHR5FrxWvDfp7bhfN8LOK-EhpX+LDYPwBRvkZSWxw@mail.gmail.com>
References: <5458261C.2020700@candelatech.com>
 <CAHqTa-21YOPiV_UxxWh23mB7AqLhj0n+h6eA5cTUH8eh32heRw@mail.gmail.com>
 <545A60E0.8070308@candelatech.com>
 <CAHqTa-2OKoKSqQXmfAq5esu5SWXJRvL8Vy+GMRsq4XertnTaFA@mail.gmail.com>
 <545A748C.9040008@candelatech.com>
 <CAHqTa-0nHBHR5FrxWvDfp7bhfN8LOK-EhpX+LDYPwBRvkZSWxw@mail.gmail.com>
Message-ID: <545AC595.1020608@candelatech.com>

On 11/05/2014 11:12 AM, Avery Pennarun wrote:
> On Wed, Nov 5, 2014 at 11:03 AM, Ben Greear <greearb at candelatech.com> wrote:
>> Does not appear to be an AP problem, as ath9k stations to the ath10k AP are all
>> in the 20ms range.
> 
> Ah, ok, I just assumed you were using ath10k as an AP.  In that case I
> know nothing :)
> 


Ahhh, found the problem.  Firmware was trying to be helpful and
reserve the channel on vdev-start.  But, took it 200+ms to grab the
reservation when another vdev exists, and it shouldn't be needed
anyway as far as I can tell.

Disabled that 'feature' by hacking on driver a bit to pass a new flag to modified firmware
to tell it to ignore the reservation logic, and now a second station vdev associates
in about 6-8 ms :)

Take it easy,
Ben

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



From greearb at candelatech.com  Thu Nov  6 11:57:11 2014
From: greearb at candelatech.com (Ben Greear)
Date: Thu, 06 Nov 2014 11:57:11 -0800
Subject: New ath10k CT firmware released.
Message-ID: <545BD297.5040806@candelatech.com>

I have uploaded the latest CT version of the ath10k firmware.

http://www.candelatech.com/ath10k.php

This firmware fixes bugs in raw-tx mode, though probably only
non-encrypted frames can be sent in this manner, and it requires
an out-of-tree patch from Michal Kazior to make it work:

http://comments.gmane.org/gmane.linux.drivers.ath10k.devel/246

This firmware also significantly improves association times when using
more than one vdev.  This, requires an additional kernel patch:

http://dmz2.candelatech.com/git/gitweb.cgi?p=linux-3.17.dev.y/.git;a=commitdiff;h=a9756b6e2efffbec4101dbe81e9d6a2c503239ff;hp=5bfa637376c352fc17c56afc7b1d2e752750162c

And, you may want the near-by patches that allow disabling some
logging, especially if using serial console.

There is also a small fix to max-nss logic in the firmware rate-control,
but I am not sure this is required.  It _is_ required that you use
currently-out-of-tree patches if you want anything other than 3x3 station
connecting to 3x3 AP to work properly with ath10k.

As always, I am interested to know how people are using
the CT firmware, and I would welcome any help with getting
even basic support (such as reserved feature flags)
for this firmware in the upstream kernel.

Thanks,
Ben

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



From greearb at candelatech.com  Thu Nov  6 16:47:33 2014
From: greearb at candelatech.com (Ben Greear)
Date: Thu, 06 Nov 2014 16:47:33 -0800
Subject: New ath10k CT firmware released.
In-Reply-To: <545BD297.5040806@candelatech.com>
References: <545BD297.5040806@candelatech.com>
Message-ID: <545C16A5.9030106@candelatech.com>

On 11/06/2014 11:57 AM, Ben Greear wrote:
> I have uploaded the latest CT version of the ath10k firmware.
> 
> http://www.candelatech.com/ath10k.php
> 
> This firmware fixes bugs in raw-tx mode, though probably only
> non-encrypted frames can be sent in this manner, and it requires
> an out-of-tree patch from Michal Kazior to make it work:
> 
> http://comments.gmane.org/gmane.linux.drivers.ath10k.devel/246
> 
> This firmware also significantly improves association times when using
> more than one vdev.  This, requires an additional kernel patch:
> 
> http://dmz2.candelatech.com/git/gitweb.cgi?p=linux-3.17.dev.y/.git;a=commitdiff;h=a9756b6e2efffbec4101dbe81e9d6a2c503239ff;hp=5bfa637376c352fc17c56afc7b1d2e752750162c

I was a bit too clever it seems....  I have to be more careful about disabling
the ch reservation when there are no vdevs active, I think.

Hope to have it fixed shortly.

Thanks,
Ben

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



From ohlee at mwnl.snu.ac.kr  Thu Nov  6 16:49:11 2014
From: ohlee at mwnl.snu.ac.kr (Okhwan Lee)
Date: Fri, 7 Nov 2014 09:49:11 +0900
Subject: Tx power setting
In-Reply-To: <CA+BoTQkJJjNG09Pp_Svpmr+4soXT8Dw1En91BrW9GnnhEFwhYg@mail.gmail.com>
References: <etPan.5459e2d6.2ae8944a.8770@Mac-Pro.local>
 <CA+BoTQkJJjNG09Pp_Svpmr+4soXT8Dw1En91BrW9GnnhEFwhYg@mail.gmail.com>
Message-ID: <etPan.545c1707.216231b.15130@Mac-Pro.local>

?
Hi all,?

Thank you for the answer.?
As you said, if we use the most recent version of ath10k, it works correctly.?

--  
Okhwan Lee
Sent with Airmail  

?? 2014? 11? 5? ?? ?? 10:54:55, Michal Kazior (michal.kazior at tieto.com(mailto:michal.kazior at tieto.com)) ???:

> On 5 November 2014 09:41, Okhwan Lee wrote:
> > Hi,
> >
> > We are trying to change the tx power of QCA 9880.
> > We use 3.16.1 linux kernel and backport (3.16.1) to use the emerging ath10k device driver and 10.1.467.2-1 firmware.
> >
> > However, we can not change the tx power setting (default 0 dBm) by using iw or iwconfig commands.
>  
> What do you mean "can not change". Do you get an error message? Where
> does it say you have 0 dBm as the default?
>  
>  
> > Based on my understanding, if we change the tx power using the commands, ath10k_config() function should be invoked.
> > However, the function is not called.
> > And the received signal strength at the receiver side does not change.
> >
> > If you have any idea, please let me know.
>  
> I'm using fbb5c042800ec42459a5cc307dec566d8e316927 from
> github.com/kvalo/ath/ (based on 3.17). I don't see the problem you
> describe - I can change tx powed with, e.g. `iw wlan1 set txpower
> fixed 1000`. The other end reports different signal strength values
> when I change txpower. Can you re-test with latest ath10k code,
> please?
>  
>  
> Micha?



From ohlee at mwnl.snu.ac.kr  Thu Nov  6 17:06:33 2014
From: ohlee at mwnl.snu.ac.kr (Okhwan Lee)
Date: Fri, 7 Nov 2014 10:06:33 +0900
Subject: Collecting CSI information
Message-ID: <etPan.545c1b19.1f16e9e8.15130@Mac-Pro.local>

?Hi all,?

I have one question about firmware update.  
As far as I know, the firmware is basically distributed from the Qualcom-Atheros.  
Some modified version of the official firmware is distributed from open source community.  

Is there any QCA9880 firmware which supports to collect and report CSI information (measured at VHT-LTF),  
like IWL5300 does (http://dhalperi.github.io/linux-80211n-csitool/)?

--  
Okhwan Lee
Sent with Airmail


From rmanohar at qti.qualcomm.com  Fri Nov  7 05:16:44 2014
From: rmanohar at qti.qualcomm.com (Rajkumar Manoharan)
Date: Fri, 7 Nov 2014 18:46:44 +0530
Subject: [PATCH 1/2] ath10k: add modpram 'skip_otp' to ignore empty otp error
 during BMI
Message-ID: <1415366205-11672-1-git-send-email-rmanohar@qti.qualcomm.com>

This patch would help bring up wifi interface with default board
data in case of failures in otp download. It is useful for initial
caliberation.

Signed-off-by: Rajkumar Manoharan <rmanohar at qti.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 5c23d00..2de49e4 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -31,12 +31,15 @@
 unsigned int ath10k_debug_mask;
 static bool uart_print;
 static unsigned int ath10k_p2p;
+static bool skip_otp;
 module_param_named(debug_mask, ath10k_debug_mask, uint, 0644);
 module_param(uart_print, bool, 0644);
 module_param_named(p2p, ath10k_p2p, uint, 0644);
+module_param(skip_otp, bool, 0644);
 MODULE_PARM_DESC(debug_mask, "Debugging mask");
 MODULE_PARM_DESC(uart_print, "Uart target debugging");
 MODULE_PARM_DESC(p2p, "Enable ath10k P2P support");
+MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");
 
 static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 	{
@@ -280,7 +283,7 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
 
 	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
 
-	if (result != 0) {
+	if (!skip_otp && result != 0) {
 		ath10k_err(ar, "otp calibration failed: %d", result);
 		return -EINVAL;
 	}
-- 
2.1.3



From rmanohar at qti.qualcomm.com  Fri Nov  7 05:16:45 2014
From: rmanohar at qti.qualcomm.com (Rajkumar Manoharan)
Date: Fri, 7 Nov 2014 18:46:45 +0530
Subject: [PATCH 2/2] ath10k: Advertise support for AP mode channel width
 changes
In-Reply-To: <1415366205-11672-1-git-send-email-rmanohar@qti.qualcomm.com>
References: <1415366205-11672-1-git-send-email-rmanohar@qti.qualcomm.com>
Message-ID: <1415366205-11672-2-git-send-email-rmanohar@qti.qualcomm.com>

This will enable AP mode to change channel width dynamically
based on 20/40 intolerance report sent by associated client.

Signed-off-by: Rajkumar Manoharan <rmanohar at qti.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index a726107..d6799f4 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4916,6 +4916,7 @@ int ath10k_mac_register(struct ath10k *ar)
 	ar->hw->wiphy->max_remain_on_channel_duration = 5000;
 
 	ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
+	ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
 	/*
 	 * on LL hardware queues are managed entirely by the FW
 	 * so we only advertise to mac we can do the queues thing
-- 
2.1.3



From psidhu at gateworks.com  Mon Nov 10 14:04:29 2014
From: psidhu at gateworks.com (Pushpal Sidhu)
Date: Mon, 10 Nov 2014 14:04:29 -0800
Subject: htt rx stopped. cannot recover
Message-ID: <CAD1M060Y+3r_-J12ZqT4TqddUf9tJHKCEPJ0DhFJ1sCiXimdVw@mail.gmail.com>

Hello everyone.

I am having issues that occur when I have heavy network traffic in a
wireless bridge. That is:
  {lan1}<--ether-->AP<--wifi-->STA<--ether-->{lan2}

Note that the above scenario requires 4addr to be turned on. Once I
associate the AP and STAtion and begin passing traffic through at a
rate of greater than ~250mbps TCP for several seconds, I see the below
on the STAtion:

> ...
> [   50.437806] wlan0: authenticate with 00:30:1a:4e:00:5d
> [   51.443940] wlan0: send auth to 00:30:1a:4e:00:5d (try 1/3)
> [   51.450692] wlan0: authenticated
> [   51.464272] wlan0: associate with 00:30:1a:4e:00:5d (try 1/3)
> [   51.471328] wlan0: RX AssocResp from 00:30:1a:4e:00:5d (capab=0x1 status=0 aid=1)
> [   51.992991] wlan0: associated
> [   51.996455] IPv6: ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready
> [   52.005001] br-lan: port 2(wlan0) entered forwarding state
> [   52.010561] br-lan: port 2(wlan0) entered forwarding state
Start passing traffic through
> [   61.614230] br-lan: port 1(eth1) entered forwarding state
> [   63.331225] ath10k_pci 0000:07:00.0: htt rx received chained non A-MSDU frame
> [   67.054654] br-lan: port 2(wlan0) entered forwarding state
> [   68.173786] ath10k_pci 0000:07:00.0: htt rx received chained non A-MSDU frame
> [   76.679431] ath10k_pci 0000:07:00.0: htt rx stopped. cannot recover
> [   76.685770] ath10k_pci 0000:07:00.0: failed to pop amsdu from htt rx ring -1
> [   76.692844] ath10k_pci 0000:07:00.0: htt is confused. refusing rx
> [   76.699005] ath10k_pci 0000:07:00.0: failed to pop amsdu from htt rx ring -1
> [   76.706138] ath10k_pci 0000:07:00.0: htt is confused. refusing rx
> [   76.712256] ath10k_pci 0000:07:00.0: failed to pop amsdu from htt rx ring -1
> [   76.719377] ath10k_pci 0000:07:00.0: htt is confused. refusing rx
> ...

Firmware: 10.1.467.2-1 (I've also tried 10.2-00082-4-2)
Kernel: 3.17.0-rc1-193451-g707b1bbd (From ath-next; I've also tried
several other kernel versions)
ath10k source: Current ath-next
(707b1bbd7e6ec533cfa027054ccbeb90113a40b0; I've also tried
backports-20141023 and backports-20140808)
Arch: arm
Software: Latest (released) wpa_supplicant and latest (released) hostapd
Radios: seen on both the ACE-DB-3 and WLE900VX

I've also tried disabling A-MSDU via "echo "1 64" >
htt_max_amsdu_ampdu", but continue seeing the issue. Any help on this
is appreciated.

Thanks,
Pushpal


From psidhu at gateworks.com  Mon Nov 10 14:21:08 2014
From: psidhu at gateworks.com (Pushpal Sidhu)
Date: Mon, 10 Nov 2014 14:21:08 -0800
Subject: htt rx stopped. cannot recover
In-Reply-To: <5461382B.6070607@candelatech.com>
References: <CAD1M060Y+3r_-J12ZqT4TqddUf9tJHKCEPJ0DhFJ1sCiXimdVw@mail.gmail.com>
 <5461382B.6070607@candelatech.com>
Message-ID: <CAD1M062xcGu2EJzxaXYQt5uHyDxHpEE+FDiPB4SBirXX5ePz_A@mail.gmail.com>

On Mon, Nov 10, 2014 at 2:11 PM, Ben Greear <greearb at candelatech.com> wrote:
>
> You might try my 'CT' firmware?
>
> http://www.candelatech.com/ath10k.php
>
> I'd be curious to know if it helps or not...

I just tried the "12" firmware on the station, but to no avail.

- Pushpal


From greearb at candelatech.com  Mon Nov 10 14:28:35 2014
From: greearb at candelatech.com (Ben Greear)
Date: Mon, 10 Nov 2014 14:28:35 -0800
Subject: htt rx stopped. cannot recover
In-Reply-To: <CAD1M062xcGu2EJzxaXYQt5uHyDxHpEE+FDiPB4SBirXX5ePz_A@mail.gmail.com>
References: <CAD1M060Y+3r_-J12ZqT4TqddUf9tJHKCEPJ0DhFJ1sCiXimdVw@mail.gmail.com>
 <5461382B.6070607@candelatech.com>
 <CAD1M062xcGu2EJzxaXYQt5uHyDxHpEE+FDiPB4SBirXX5ePz_A@mail.gmail.com>
Message-ID: <54613C13.9010008@candelatech.com>

On 11/10/2014 02:21 PM, Pushpal Sidhu wrote:
> On Mon, Nov 10, 2014 at 2:11 PM, Ben Greear <greearb at candelatech.com> wrote:
>>
>> You might try my 'CT' firmware?
>>
>> http://www.candelatech.com/ath10k.php
>>
>> I'd be curious to know if it helps or not...
> 
> I just tried the "12" firmware on the station, but to no avail.

Same problem, or totally not working?

Thanks,
Ben

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



From psidhu at gateworks.com  Mon Nov 10 14:33:59 2014
From: psidhu at gateworks.com (Pushpal Sidhu)
Date: Mon, 10 Nov 2014 14:33:59 -0800
Subject: htt rx stopped. cannot recover
In-Reply-To: <54613C13.9010008@candelatech.com>
References: <CAD1M060Y+3r_-J12ZqT4TqddUf9tJHKCEPJ0DhFJ1sCiXimdVw@mail.gmail.com>
 <5461382B.6070607@candelatech.com>
 <CAD1M062xcGu2EJzxaXYQt5uHyDxHpEE+FDiPB4SBirXX5ePz_A@mail.gmail.com>
 <54613C13.9010008@candelatech.com>
Message-ID: <CAD1M061wRo5MqmKYy8jw9fKpraA0DFJTh4k+QNzLkayLmBttfA@mail.gmail.com>

On Mon, Nov 10, 2014 at 2:28 PM, Ben Greear <greearb at candelatech.com> wrote:
> Same problem, or totally not working?

Same problem. I start passing traffic through and once there is
constant traffic of > 250mbps for several seconds, the issue occurs.

I forgot to mention in my original email that traffic stops once the
problem occurs.

- Pushpal


From greearb at candelatech.com  Mon Nov 10 14:53:22 2014
From: greearb at candelatech.com (Ben Greear)
Date: Mon, 10 Nov 2014 14:53:22 -0800
Subject: New ath10k CT firmware released.
In-Reply-To: <545C16A5.9030106@candelatech.com>
References: <545BD297.5040806@candelatech.com>
 <545C16A5.9030106@candelatech.com>
Message-ID: <546141E2.2080309@candelatech.com>

On 11/06/2014 04:47 PM, Ben Greear wrote:
> On 11/06/2014 11:57 AM, Ben Greear wrote:
>> I have uploaded the latest CT version of the ath10k firmware.
>>
>> http://www.candelatech.com/ath10k.php
>>
>> This firmware fixes bugs in raw-tx mode, though probably only
>> non-encrypted frames can be sent in this manner, and it requires
>> an out-of-tree patch from Michal Kazior to make it work:
>>
>> http://comments.gmane.org/gmane.linux.drivers.ath10k.devel/246
>>
>> This firmware also significantly improves association times when using
>> more than one vdev.  This, requires an additional kernel patch:
>>
>> http://dmz2.candelatech.com/git/gitweb.cgi?p=linux-3.17.dev.y/.git;a=commitdiff;h=a9756b6e2efffbec4101dbe81e9d6a2c503239ff;hp=5bfa637376c352fc17c56afc7b1d2e752750162c
> 
> I was a bit too clever it seems....  I have to be more careful about disabling
> the ch reservation when there are no vdevs active, I think.
> 
> Hope to have it fixed shortly.

Looks like firmware was fine, so it remains unchanged.  But, the driver patch has to
be more careful and only disable ch reservation if we currently have an active channel.

This patch (on top of the one linked above) seems to work well:

http://dmz2.candelatech.com/git/gitweb.cgi?p=linux-3.17.dev.y/.git;a=commitdiff;h=5ed93f05d72769b06246280d514b72d617bb9fde

Thanks,
Ben

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



From michal.kazior at tieto.com  Tue Nov 11 22:31:48 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Wed, 12 Nov 2014 07:31:48 +0100
Subject: htt rx stopped. cannot recover
In-Reply-To: <CAD1M061wRo5MqmKYy8jw9fKpraA0DFJTh4k+QNzLkayLmBttfA@mail.gmail.com>
References: <CAD1M060Y+3r_-J12ZqT4TqddUf9tJHKCEPJ0DhFJ1sCiXimdVw@mail.gmail.com>
 <5461382B.6070607@candelatech.com>
 <CAD1M062xcGu2EJzxaXYQt5uHyDxHpEE+FDiPB4SBirXX5ePz_A@mail.gmail.com>
 <54613C13.9010008@candelatech.com>
 <CAD1M061wRo5MqmKYy8jw9fKpraA0DFJTh4k+QNzLkayLmBttfA@mail.gmail.com>
Message-ID: <CA+BoTQk7idFbyYzLxKCgmSQ=zzQTraOJ-fy5_qhDpzkueQe8KQ@mail.gmail.com>

On 10 November 2014 23:33, Pushpal Sidhu <psidhu at gateworks.com> wrote:
> On Mon, Nov 10, 2014 at 2:28 PM, Ben Greear <greearb at candelatech.com> wrote:
>> Same problem, or totally not working?
>
> Same problem. I start passing traffic through and once there is
> constant traffic of > 250mbps for several seconds, the issue occurs.
>
> I forgot to mention in my original email that traffic stops once the
> problem occurs.

That's a safety mechanism to prevent memory corruption on the host.
The error you see is most likely an indication fw/hw Rx reporting
broke, i.e. fw says to pop more frames from the Rx ring than it is
ready to be popped.


Micha?


From toshik at chromium.org  Wed Nov 12 12:10:56 2014
From: toshik at chromium.org (Toshi Kikuchi)
Date: Wed, 12 Nov 2014 12:10:56 -0800
Subject: [PATCH V2] ath10k: read calibration data from Device Tree
Message-ID: <1415823056-10876-1-git-send-email-toshik@chromium.org>

V1->V2: fixed a bug that returns an uninitialized value if the node
is not found.

This patch adds support for reading calibration data from Device Tree.
It looks for the calibration data in Device Tree if it can't find it
in a file.

The node for the calibration data should be defined like this:

pci {
        pcie at 0 {
                reg = <0 0 0 0 0>;
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
                device_type = "pci";

                ath10k at 0,0 {
                        reg = <0 0 0 0 0>;
                        device_type = "pci";
                        qcom,ath10k-calibration-data = [ 01 02 03 ... ];
                };
        };
};

Change-Id: I6fe3c50fe2de9177d031a4c17bd95152372dd993
Signed-off-by: Toshi Kikuchi <toshik at chromium.org>
---
 drivers/net/wireless/ath/ath10k/core.c | 70 +++++++++++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath10k/core.h |  3 ++
 2 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 5c23d00..cea978e 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -17,6 +17,7 @@
 
 #include <linux/module.h>
 #include <linux/firmware.h>
+#include <linux/of.h>
 
 #include "core.h"
 #include "mac.h"
@@ -27,6 +28,7 @@
 #include "debug.h"
 #include "htt.h"
 #include "testmode.h"
+#include "pci.h"
 
 unsigned int ath10k_debug_mask;
 static bool uart_print;
@@ -244,6 +246,66 @@ static int ath10k_download_cal_file(struct ath10k *ar)
 	return 0;
 }
 
+static int ath10k_download_cal_dt(struct ath10k *ar)
+{
+	struct device_node *node;
+	int data_len;
+	void *data;
+	int ret;
+
+	node = pci_device_to_OF_node(ath10k_pci_priv(ar)->pdev);
+	if (!node)
+		/* Device Tree is optional, don't print any warnings if
+		 * there's no node for ath10k.
+		 */
+		return -ENOENT;
+
+	if (!of_get_property(node, "qcom,ath10k-calibration-data",
+			     &data_len)) {
+		/* The calibration data node is optional */
+		return -ENOENT;
+	}
+
+	if (data_len != QCA988X_CAL_DATA_LEN) {
+		ath10k_warn(ar, "invalid calibration data length in DT: %d\n",
+			    data_len);
+		ret = -EMSGSIZE;
+		goto out;
+	}
+
+	data = kmalloc(data_len, GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = of_property_read_u8_array(node, "qcom,ath10k-calibration-data",
+					data, data_len);
+	if (ret) {
+		ath10k_warn(ar,
+			    "failed to read calibration data from DT: %d\n",
+			    ret);
+		goto out_free;
+	}
+
+	ret = ath10k_download_board_data(ar, data, data_len);
+	if (ret) {
+		ath10k_warn(ar,
+			    "failed to download calibration data from "
+			    "Device Tree: %d\n",
+			    ret);
+		goto out_free;
+	}
+
+	ret = 0;
+
+out_free:
+	kfree(data);
+
+out:
+	return ret;
+}
+
 static int ath10k_download_and_run_otp(struct ath10k *ar)
 {
 	u32 result, address = ar->hw_params.patch_load_addr;
@@ -657,9 +719,15 @@ static int ath10k_download_cal_data(struct ath10k *ar)
 	}
 
 	ath10k_dbg(ar, ATH10K_DBG_BOOT,
-		   "boot did not find a calibration file, try OTP next: %d\n",
+		   "boot did not find a calibration file, try DT next: %d\n",
 		   ret);
 
+	ret = ath10k_download_cal_dt(ar);
+	if (ret == 0) {
+		ar->cal_mode = ATH10K_CAL_MODE_DT;
+		goto done;
+	}
+
 	ret = ath10k_download_and_run_otp(ar);
 	if (ret) {
 		ath10k_err(ar, "failed to run otp: %d\n", ret);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 1e3fd10..8e89e31 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -391,6 +391,7 @@ enum ath10k_dev_flags {
 enum ath10k_cal_mode {
 	ATH10K_CAL_MODE_FILE,
 	ATH10K_CAL_MODE_OTP,
+	ATH10K_CAL_MODE_DT,
 };
 
 static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
@@ -400,6 +401,8 @@ static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
 		return "file";
 	case ATH10K_CAL_MODE_OTP:
 		return "otp";
+	case ATH10K_CAL_MODE_DT:
+		return "dt";
 	}
 
 	return "unknown";
-- 
2.1.0.rc2.206.gedb03e5



From Dave.Dailey at spirent.com  Wed Nov 12 12:30:27 2014
From: Dave.Dailey at spirent.com (Dailey, Dave)
Date: Wed, 12 Nov 2014 20:30:27 +0000
Subject: Ath10k leaves AR9880 in a state that will not enumerate again when
 CPU warm booted
Message-ID: <21268C70AF91954BBF885CBEF2279F6D1C4658D0@SPCCOREXCMBX01.AD.SPIRENTCOM.COM>

Hello,

I have a wireless PCIe NIC with the AR9880 that is enumerating and working fine on the PCIe bus after a system cold boot, but after rebooting warm it doesn't show up in lspci.  We don't assert a hw reset line to the PCIe card on warm boot, but we don't see this issue with boards based on other wireless chipsets through system reboots.  Power supplies remain stable throughout the warm boot.

Is there a way to put the AR9880 in a state at reboot or module unload such that it will be recognized on the other side of a reboot?  I tried unbinding with sysfs and unloading the module, but no luck.

This is backports-next as of 2014/09/05/.

Thanks for any ideas.
Dave


Spirent Communications e-mail confidentiality.
------------------------------------------------------------------------
This e-mail contains confidential and / or privileged information belonging to Spirent Communications plc, its affiliates and / or subsidiaries. If you are not the intended recipient, you are hereby notified that any disclosure, copying, distribution and / or the taking of any action based upon reliance on the contents of this transmission is strictly forbidden. If you have received this message in error please notify the sender by return e-mail and delete it from your system.

Spirent Communications plc
Northwood Park, Gatwick Road, Crawley, West Sussex, RH10 9XN, United Kingdom.
Tel No. +44 (0) 1293 767676
Fax No. +44 (0) 1293 767677

Registered in England Number 470893
Registered at Northwood Park, Gatwick Road, Crawley, West Sussex, RH10 9XN, United Kingdom.

Or if within the US,

Spirent Communications,
26750 Agoura Road, Calabasas, CA, 91302, USA.
Tel No. 1-818-676- 2300


From daileycrew at gmail.com  Wed Nov 12 13:34:35 2014
From: daileycrew at gmail.com (David Dailey)
Date: Wed, 12 Nov 2014 16:34:35 -0500
Subject: Ath10k leaves AR9880 in a state that will not enumerate again
 when CPU warm booted
Message-ID: <CABfbVPKXg2HiVHuEy13s2_F=xw5nxyC7r0J229LsfRgGHySCMg@mail.gmail.com>

I discovered that this issue seems to follow at least 2 different
chipsets (AR9880 and AR9890) but doesn't happen with at least two BCM
chipsets.  And the enumeration failing after a warm boot doesn't
depend on ath10k loading at all.  Even with the module not present on
the system, the device doesn't enumerate after cold boot.  So it
appears this is something unique to the PCIe core on Atheros, not
ath10k.  I guess the only hope would be if somehow the unload of the
driver could restore the chipset back to a state where it would
enumerate again, but I don't have information on the chipset at that
level.

Dave


From adrian at freebsd.org  Wed Nov 12 13:43:24 2014
From: adrian at freebsd.org (Adrian Chadd)
Date: Wed, 12 Nov 2014 13:43:24 -0800
Subject: Ath10k leaves AR9880 in a state that will not enumerate again
 when CPU warm booted
In-Reply-To: <CABfbVPKXg2HiVHuEy13s2_F=xw5nxyC7r0J229LsfRgGHySCMg@mail.gmail.com>
References: <CABfbVPKXg2HiVHuEy13s2_F=xw5nxyC7r0J229LsfRgGHySCMg@mail.gmail.com>
Message-ID: <CAJ-VmokLQsJb9qCPs3FY5FQfhBBhLoc99iyG1gnqP396WcKcSA@mail.gmail.com>

Is the length / number of card resets during a warm boot differ to cold boot?

There's a known behavioural quirk where if the reset line isn't held
for long enough or there's too short a gap between one and another
reset assertion, the NIC doesn't fully initialise right.



-a


On 12 November 2014 13:34, David Dailey <daileycrew at gmail.com> wrote:
> I discovered that this issue seems to follow at least 2 different
> chipsets (AR9880 and AR9890) but doesn't happen with at least two BCM
> chipsets.  And the enumeration failing after a warm boot doesn't
> depend on ath10k loading at all.  Even with the module not present on
> the system, the device doesn't enumerate after cold boot.  So it
> appears this is something unique to the PCIe core on Atheros, not
> ath10k.  I guess the only hope would be if somehow the unload of the
> driver could restore the chipset back to a state where it would
> enumerate again, but I don't have information on the chipset at that
> level.
>
> Dave
>
> _______________________________________________
> ath10k mailing list
> ath10k at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath10k


From michal.kazior at tieto.com  Wed Nov 12 22:37:42 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 13 Nov 2014 07:37:42 +0100
Subject: Ath10k leaves AR9880 in a state that will not enumerate again
 when CPU warm booted
In-Reply-To: <CABfbVPKXg2HiVHuEy13s2_F=xw5nxyC7r0J229LsfRgGHySCMg@mail.gmail.com>
References: <CABfbVPKXg2HiVHuEy13s2_F=xw5nxyC7r0J229LsfRgGHySCMg@mail.gmail.com>
Message-ID: <CA+BoTQnzBRj5rk66RD61sRc-9mcwJFaPiAdYqrjCqOXWULHaGQ@mail.gmail.com>

On 12 November 2014 22:34, David Dailey <daileycrew at gmail.com> wrote:
> I discovered that this issue seems to follow at least 2 different
> chipsets (AR9880 and AR9890) but doesn't happen with at least two BCM
> chipsets.  And the enumeration failing after a warm boot doesn't
> depend on ath10k loading at all.  Even with the module not present on
> the system, the device doesn't enumerate after cold boot.  So it
> appears this is something unique to the PCIe core on Atheros, not
> ath10k.  I guess the only hope would be if somehow the unload of the
> driver could restore the chipset back to a state where it would
> enumerate again, but I don't have information on the chipset at that
> level.

Did you try to rescan the pci bus explicitly?

  echo 1 | sudo tee /sys/bus/pci/rescan


Micha?


From kvalo at qca.qualcomm.com  Thu Nov 13 05:22:12 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Thu, 13 Nov 2014 15:22:12 +0200
Subject: [PATCH v2 06/10] ath10k: use configured nss instead of max nss.
In-Reply-To: <54592F3E.10204@candelatech.com> (Ben Greear's message of "Tue,
 04 Nov 2014 11:55:42 -0800")
References: <1411507045-18973-1-git-send-email-greearb@candelatech.com>
 <1411507045-18973-6-git-send-email-greearb@candelatech.com>
 <54592F3E.10204@candelatech.com>
Message-ID: <87ioijteuz.fsf@kamboji.qca.qualcomm.com>

Ben Greear <greearb at candelatech.com> writes:

> On 09/23/2014 02:17 PM, greearb at candelatech.com wrote:
>> From: Ben Greear <greearb at candelatech.com>
>> 
>> When re-associating a station, the nss was set back to
>> maximum value even if user had configured small number
>> of tx chains.  So, pay attention to user's config in
>> this case as well.
>
> Looks like this (and probably the related patch) did not make
> it upstream yet.
>
> Is someone waiting for more changes from me or did this just
> get lost?

Sorry, it fell through the cracks. I'll take a look at them soon.

-- 
Kalle Valo


From daileycrew at gmail.com  Thu Nov 13 06:50:36 2014
From: daileycrew at gmail.com (David Dailey)
Date: Thu, 13 Nov 2014 09:50:36 -0500
Subject: Ath10k leaves AR9880 in a state that will not enumerate again
 when CPU warm booted
In-Reply-To: <CABfbVPKvcAkwY2_qywhvewVwuk4sktMsmzwdek1kdhZKhefLzA@mail.gmail.com>
References: <CABfbVPKXg2HiVHuEy13s2_F=xw5nxyC7r0J229LsfRgGHySCMg@mail.gmail.com>
 <CA+BoTQnzBRj5rk66RD61sRc-9mcwJFaPiAdYqrjCqOXWULHaGQ@mail.gmail.com>
 <CABfbVPKvcAkwY2_qywhvewVwuk4sktMsmzwdek1kdhZKhefLzA@mail.gmail.com>
Message-ID: <CABfbVP+jeJOG=pmpoOFhE=+mhgWWNJ7zY6xDUPYEL0OgnqYOHQ@mail.gmail.com>

Yes, I had no luck with that.
Dave

> On Nov 13, 2014 1:37 AM, "Michal Kazior" <michal.kazior at tieto.com> wrote:
>>
>> On 12 November 2014 22:34, David Dailey <daileycrew at gmail.com> wrote:
>> > I discovered that this issue seems to follow at least 2 different
>> > chipsets (AR9880 and AR9890) but doesn't happen with at least two BCM
>> > chipsets.  And the enumeration failing after a warm boot doesn't
>> > depend on ath10k loading at all.  Even with the module not present on
>> > the system, the device doesn't enumerate after cold boot.  So it
>> > appears this is something unique to the PCIe core on Atheros, not
>> > ath10k.  I guess the only hope would be if somehow the unload of the
>> > driver could restore the chipset back to a state where it would
>> > enumerate again, but I don't have information on the chipset at that
>> > level.
>>
>> Did you try to rescan the pci bus explicitly?
>>
>>   echo 1 | sudo tee /sys/bus/pci/rescan
>>
>>
>> Micha?


From daileycrew at gmail.com  Thu Nov 13 06:53:06 2014
From: daileycrew at gmail.com (David Dailey)
Date: Thu, 13 Nov 2014 09:53:06 -0500
Subject: Ath10k leaves AR9880 in a state that will not enumerate again
 when CPU warm booted
In-Reply-To: <CAJ-VmokLQsJb9qCPs3FY5FQfhBBhLoc99iyG1gnqP396WcKcSA@mail.gmail.com>
References: <CABfbVPKXg2HiVHuEy13s2_F=xw5nxyC7r0J229LsfRgGHySCMg@mail.gmail.com>
 <CAJ-VmokLQsJb9qCPs3FY5FQfhBBhLoc99iyG1gnqP396WcKcSA@mail.gmail.com>
Message-ID: <CABfbVPLJaHo3nde3biMYQq+RXjy2WKz2brFABMkFQ7DPsJw2oA@mail.gmail.com>

Yes, we have a known platform issue I mentioned where we don't assert
any hw reset line to the PCIe slot during warm boot.  It does assert
on cold boot.  Sounds like this issue is the same one you describe and
unique to QCA parts.  I was hoping to get lucky and someone would know
how to re-init the PCI block via software before reboot as a work
around.  Thanks for the info.

Dave

On Wed, Nov 12, 2014 at 4:43 PM, Adrian Chadd <adrian at freebsd.org> wrote:
> Is the length / number of card resets during a warm boot differ to cold boot?
>
> There's a known behavioural quirk where if the reset line isn't held
> for long enough or there's too short a gap between one and another
> reset assertion, the NIC doesn't fully initialise right.
>
>
>
> -a
>
>
> On 12 November 2014 13:34, David Dailey <daileycrew at gmail.com> wrote:
>> I discovered that this issue seems to follow at least 2 different
>> chipsets (AR9880 and AR9890) but doesn't happen with at least two BCM
>> chipsets.  And the enumeration failing after a warm boot doesn't
>> depend on ath10k loading at all.  Even with the module not present on
>> the system, the device doesn't enumerate after cold boot.  So it
>> appears this is something unique to the PCIe core on Atheros, not
>> ath10k.  I guess the only hope would be if somehow the unload of the
>> driver could restore the chipset back to a state where it would
>> enumerate again, but I don't have information on the chipset at that
>> level.
>>
>> Dave
>>
>> _______________________________________________
>> ath10k mailing list
>> ath10k at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/ath10k


From psidhu at gateworks.com  Thu Nov 13 11:09:31 2014
From: psidhu at gateworks.com (Pushpal Sidhu)
Date: Thu, 13 Nov 2014 11:09:31 -0800
Subject: htt rx stopped. cannot recover
In-Reply-To: <CA+BoTQk7idFbyYzLxKCgmSQ=zzQTraOJ-fy5_qhDpzkueQe8KQ@mail.gmail.com>
References: <CAD1M060Y+3r_-J12ZqT4TqddUf9tJHKCEPJ0DhFJ1sCiXimdVw@mail.gmail.com>
 <5461382B.6070607@candelatech.com>
 <CAD1M062xcGu2EJzxaXYQt5uHyDxHpEE+FDiPB4SBirXX5ePz_A@mail.gmail.com>
 <54613C13.9010008@candelatech.com>
 <CAD1M061wRo5MqmKYy8jw9fKpraA0DFJTh4k+QNzLkayLmBttfA@mail.gmail.com>
 <CA+BoTQk7idFbyYzLxKCgmSQ=zzQTraOJ-fy5_qhDpzkueQe8KQ@mail.gmail.com>
Message-ID: <CAD1M063n=WGeQRJKycvWYGMZRFN4gabM56dgeX_4tf8W8hyUKA@mail.gmail.com>

On Tue, Nov 11, 2014 at 10:31 PM, Michal Kazior <michal.kazior at tieto.com> wrote:
> That's a safety mechanism to prevent memory corruption on the host.
> The error you see is most likely an indication fw/hw Rx reporting
> broke, i.e. fw says to pop more frames from the Rx ring than it is
> ready to be popped.

So if this seems to indicate a hw/fw issue, how should I go about
fixing it? If it's a fw issue, it just goes to show how keeping this
particular fw closed-source is hurting this project more than anything
in my opinion.

Has anyone else been able to recreate this problem? If not, there
might be something else at play, but until someone else can recreate
the issue, I can't tell exactly where the problem lies. At first I
thought it was a 4addr mode issue, but I performed the following
scenario and believe that it might be related to bridging.
 {lan1}<--ether-->AP<--wifi-->STA

In this scenario, the AP bridges eth+wlan, with 4addr turned off (the
STA has no bridge). When I pass traffic through from lan1 to the
STAtion, the same issue occurs on the AP, this time with traffic above
~220mbps TCP. Does anyone know of any specific kernel configs relating
to bridging that I might not have enabled?

I understand that stopping traffic is a safety mechanism, but is there
a better way to handle the situation? I don't believe resetting
hardware is the proper solution as this requires reauthentication
(which takes time), only for the problem to remanifest itself in only
a few seconds of passing traffic through.

Thanks for any input,
Pushpal


From psidhu at gateworks.com  Thu Nov 13 16:08:30 2014
From: psidhu at gateworks.com (Pushpal Sidhu)
Date: Thu, 13 Nov 2014 16:08:30 -0800
Subject: [PATCH v4 0/2] ath10k: testmode support
In-Reply-To: <87zje528im.fsf@kamboji.qca.qualcomm.com>
References: <20140910152136.12610.18499.stgit@potku.adurom.net>
 <87zje528im.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CAD1M061Gky-a28Rokmgyd-5x_m_h1SNmj9ZxUd4v1fP=bae35g@mail.gmail.com>

On Thu, Sep 11, 2014 at 1:43 PM, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Kalle Valo <kvalo at qca.qualcomm.com> writes:
>
>> latest version of my testmode patches. Getting closer, more or less cosmetic
>> changes this time :)

While looking through this patchset (sorry it took two months), I have
to wonder: what's this utf.bin blob? It seems in order to use
testmode, we need this binary blob that I can't seem to find (I looked
in linux-firmware and https://github.com/kvalo/ath10k-firmware). If,
for whatever reason, this binary blob is not releasable, what's the
point of adding in testmode to this driver?

- Pushpal


From poh at qca.qualcomm.com  Thu Nov 13 19:17:51 2014
From: poh at qca.qualcomm.com (Peter Oh)
Date: Thu, 13 Nov 2014 19:17:51 -0800
Subject: [PATCH] ath10k: fix mismatched wmi api call
Message-ID: <1415935071-21422-1-git-send-email-poh@qca.qualcomm.com>

Fix to use v10.2 wmi call for firmware v10.2.
It turned out that peer association function was using
v10.1 wmi call for v10.2 firmware during code review.

Signed-off-by: Peter Oh <poh at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/wmi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index ae746ce..f5d1081 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -4187,9 +4187,9 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
 
 	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
 		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
-			ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg);
-		else
 			ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg);
+		else
+			ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg);
 	} else {
 		ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg);
 	}
-- 
1.9.1



From michal.kazior at tieto.com  Fri Nov 14 00:31:51 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 14 Nov 2014 09:31:51 +0100
Subject: htt rx stopped. cannot recover
In-Reply-To: <CAD1M063n=WGeQRJKycvWYGMZRFN4gabM56dgeX_4tf8W8hyUKA@mail.gmail.com>
References: <CAD1M060Y+3r_-J12ZqT4TqddUf9tJHKCEPJ0DhFJ1sCiXimdVw@mail.gmail.com>
 <5461382B.6070607@candelatech.com>
 <CAD1M062xcGu2EJzxaXYQt5uHyDxHpEE+FDiPB4SBirXX5ePz_A@mail.gmail.com>
 <54613C13.9010008@candelatech.com>
 <CAD1M061wRo5MqmKYy8jw9fKpraA0DFJTh4k+QNzLkayLmBttfA@mail.gmail.com>
 <CA+BoTQk7idFbyYzLxKCgmSQ=zzQTraOJ-fy5_qhDpzkueQe8KQ@mail.gmail.com>
 <CAD1M063n=WGeQRJKycvWYGMZRFN4gabM56dgeX_4tf8W8hyUKA@mail.gmail.com>
Message-ID: <CA+BoTQkfPJp4tg8eR4OJDs2Cf_s0x36QYD-Yq6fTQ41c1jm6TA@mail.gmail.com>

On 13 November 2014 20:09, Pushpal Sidhu <psidhu at gateworks.com> wrote:
> On Tue, Nov 11, 2014 at 10:31 PM, Michal Kazior <michal.kazior at tieto.com> wrote:
[...]
> Has anyone else been able to recreate this problem? If not, there
> might be something else at play, but until someone else can recreate
> the issue, I can't tell exactly where the problem lies. At first I
> thought it was a 4addr mode issue, but I performed the following
> scenario and believe that it might be related to bridging.
>  {lan1}<--ether-->AP<--wifi-->STA
>
> In this scenario, the AP bridges eth+wlan, with 4addr turned off (the
> STA has no bridge). When I pass traffic through from lan1 to the
> STAtion, the same issue occurs on the AP, this time with traffic above
> ~220mbps TCP. Does anyone know of any specific kernel configs relating
> to bridging that I might not have enabled?

I've used ath10k AP in a bridge many times and haven't seen this issue yet.

Putting an interface into a bridge enables promiscuous mode on it. In
ath10k this is handled by creating a monitor vdev to implicitly
influence Rx filters so that hw/fw pass everything up to host. I
suspect your RF environment may contain particular traffic patterns
which trigger the problem within firmware code related to monitor
vdev.

You could try hacking up ath10k to not create/start monitor vdev and
see if you can still reproduce the problem. Keep in mind bridging will
be crippled in some cases since firmware won't deliver some frames to
ath10k.

There's also new WMI_10X_PDEV_PARAM_RX_FILTER that was introduced in
10.2. I didn't have time to play with it yet. In theory it might be
able possible to use it instead of monitor vdev for promisc mode, at
least with 10.2. I'm not really fond of the idea though because this
will add more complexity and different codepaths to the driver
depending on firmware revision.


> I understand that stopping traffic is a safety mechanism, but is there
> a better way to handle the situation? I don't believe resetting
> hardware is the proper solution as this requires reauthentication
> (which takes time), only for the problem to remanifest itself in only
> a few seconds of passing traffic through.

Hmm.. Now that I think about it, after the recent Rx rework it might
be possible to circumvent the problem. ath10k uses very little data
from Rx indication event and instead Rx descriptor is used for most
things. Popping function would need some changes so that it can back
off safely if a frame buffer isn't ready. ath10k would probably need
to poll for Rx too.


Micha?


From kvalo at qca.qualcomm.com  Fri Nov 14 07:09:21 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 14 Nov 2014 17:09:21 +0200
Subject: [PATCH v4 0/2] ath10k: testmode support
In-Reply-To: <CAD1M061Gky-a28Rokmgyd-5x_m_h1SNmj9ZxUd4v1fP=bae35g@mail.gmail.com>
 (Pushpal Sidhu's message of "Thu, 13 Nov 2014 16:08:30 -0800")
References: <20140910152136.12610.18499.stgit@potku.adurom.net>
 <87zje528im.fsf@kamboji.qca.qualcomm.com>
 <CAD1M061Gky-a28Rokmgyd-5x_m_h1SNmj9ZxUd4v1fP=bae35g@mail.gmail.com>
Message-ID: <87389lstst.fsf@kamboji.qca.qualcomm.com>

Pushpal Sidhu <psidhu at gateworks.com> writes:

> On Thu, Sep 11, 2014 at 1:43 PM, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
>> Kalle Valo <kvalo at qca.qualcomm.com> writes:
>>
>>> latest version of my testmode patches. Getting closer, more or less cosmetic
>>> changes this time :)
>
> While looking through this patchset (sorry it took two months), I have
> to wonder: what's this utf.bin blob? It seems in order to use
> testmode, we need this binary blob that I can't seem to find (I looked
> in linux-firmware and https://github.com/kvalo/ath10k-firmware). If,
> for whatever reason, this binary blob is not releasable, what's the
> point of adding in testmode to this driver?

testmode is for functionality needed in the factory, it's not meant for
normal users. That's why all distros should have CONFIG_NL80211_TESTMODE
disabled.

-- 
Kalle Valo


From tharvey at gateworks.com  Fri Nov 14 17:00:34 2014
From: tharvey at gateworks.com (Tim Harvey)
Date: Fri, 14 Nov 2014 17:00:34 -0800
Subject: [PATCH v4 0/2] ath10k: testmode support
In-Reply-To: <87389lstst.fsf@kamboji.qca.qualcomm.com>
References: <20140910152136.12610.18499.stgit@potku.adurom.net>
 <87zje528im.fsf@kamboji.qca.qualcomm.com>
 <CAD1M061Gky-a28Rokmgyd-5x_m_h1SNmj9ZxUd4v1fP=bae35g@mail.gmail.com>
 <87389lstst.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CAJ+vNU2WopFqRVNQse96mKYkESsL=5_zjRa9rMfmEYinQBU26w@mail.gmail.com>

On Fri, Nov 14, 2014 at 7:09 AM, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Pushpal Sidhu <psidhu at gateworks.com> writes:
>
>> On Thu, Sep 11, 2014 at 1:43 PM, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
>>> Kalle Valo <kvalo at qca.qualcomm.com> writes:
>>>
>>>> latest version of my testmode patches. Getting closer, more or less cosmetic
>>>> changes this time :)
>>
>> While looking through this patchset (sorry it took two months), I have
>> to wonder: what's this utf.bin blob? It seems in order to use
>> testmode, we need this binary blob that I can't seem to find (I looked
>> in linux-firmware and https://github.com/kvalo/ath10k-firmware). If,
>> for whatever reason, this binary blob is not releasable, what's the
>> point of adding in testmode to this driver?
>
> testmode is for functionality needed in the factory, it's not meant for
> normal users. That's why all distros should have CONFIG_NL80211_TESTMODE
> disabled.

Kalle,

So what your saying is that 'the factory' (Quallcomm I assume) is
using the ath10k driver with some firmware it deems not publicly
releasable and the rest of us are paying for the extra lines of code
and thrash in the open source driver? This sounds kind of dirty. It
seems to me that QCA should either release the firmware or we should
remove any special handling in the driver for it.

Is this practice used in other Linux wireless drivers? I've cc'd John
to see if he has any comments on that.

Personally, I would rather see QCA document and release the uts
firmware which is likely useful for others rather than removing the
support for it. We have users often as for a continuous transmit mode
switch so that they can get through certification testing. But really,
deep down I would much rather QCA simply open up the firmware so that
developers that are trying really hard to make this a quality driver
can succeed and we can all benefit.

Tim

>
> --
> Kalle Valo
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


From sujith at msujith.org  Sun Nov 16 23:29:53 2014
From: sujith at msujith.org (Sujith Manoharan)
Date: Mon, 17 Nov 2014 12:59:53 +0530
Subject: [PATCH] ath10k: Block radar events when requested
Message-ID: <1416209393-24736-1-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha at qca.qualcomm.com>

This patch ensures that reporting of a radar in simulation
is not done when detection is disabled explicitly by
using the debugfs knob 'dfs_block_radar_events'.

Signed-off-by: Sujith Manoharan <c_manoha at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/debug.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 9147dd3..fa1accd 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1437,7 +1437,8 @@ static ssize_t ath10k_write_simulate_radar(struct file *file,
 {
 	struct ath10k *ar = file->private_data;
 
-	ieee80211_radar_detected(ar->hw);
+	if (!ar->dfs_block_radar_events)
+		ieee80211_radar_detected(ar->hw);
 
 	return count;
 }
-- 
2.1.3



From michal.kazior at tieto.com  Mon Nov 17 03:32:33 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 17 Nov 2014 12:32:33 +0100
Subject: [PATCH] ath10k: Block radar events when requested
In-Reply-To: <1416209393-24736-1-git-send-email-sujith@msujith.org>
References: <1416209393-24736-1-git-send-email-sujith@msujith.org>
Message-ID: <CA+BoTQkpqVKVHFoXuTJtkTmFZA0XfU56nLRaVegWUr29z83_tQ@mail.gmail.com>

On 17 November 2014 08:29, Sujith Manoharan <sujith at msujith.org> wrote:
> From: Sujith Manoharan <c_manoha at qca.qualcomm.com>
>
> This patch ensures that reporting of a radar in simulation
> is not done when detection is disabled explicitly by
> using the debugfs knob 'dfs_block_radar_events'.
>
> Signed-off-by: Sujith Manoharan <c_manoha at qca.qualcomm.com>
> ---
>  drivers/net/wireless/ath/ath10k/debug.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
> index 9147dd3..fa1accd 100644
> --- a/drivers/net/wireless/ath/ath10k/debug.c
> +++ b/drivers/net/wireless/ath/ath10k/debug.c
> @@ -1437,7 +1437,8 @@ static ssize_t ath10k_write_simulate_radar(struct file *file,
>  {
>         struct ath10k *ar = file->private_data;
>
> -       ieee80211_radar_detected(ar->hw);
> +       if (!ar->dfs_block_radar_events)
> +               ieee80211_radar_detected(ar->hw);

The simulate_radar knob is meant to be used with
dfs_block_radar_events being true in the first place so you can easily
block real DFS events and inject fake ones for testing of DFS upper
layers with ath10k.

Your patch breaks this. Why would you want to do that?


Micha?


From sujith at msujith.org  Mon Nov 17 03:53:55 2014
From: sujith at msujith.org (Sujith Manoharan)
Date: Mon, 17 Nov 2014 17:23:55 +0530
Subject: [PATCH] ath10k: Block radar events when requested
In-Reply-To: <CA+BoTQkpqVKVHFoXuTJtkTmFZA0XfU56nLRaVegWUr29z83_tQ@mail.gmail.com>
References: <1416209393-24736-1-git-send-email-sujith@msujith.org>
 <CA+BoTQkpqVKVHFoXuTJtkTmFZA0XfU56nLRaVegWUr29z83_tQ@mail.gmail.com>
Message-ID: <21609.57811.107846.718878@gargle.gargle.HOWL>

Michal Kazior wrote:
> The simulate_radar knob is meant to be used with
> dfs_block_radar_events being true in the first place so you can easily
> block real DFS events and inject fake ones for testing of DFS upper
> layers with ath10k.
> 
> Your patch breaks this. Why would you want to do that?

Apparently, this knob is also being used to make sure that
radar detection doesn't happen when NOL is disabled.

I'll check if this test case is needed at all before
adding another knob to the existing pile...

Sujith


From kvalo at qca.qualcomm.com  Mon Nov 17 06:32:41 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 17 Nov 2014 16:32:41 +0200
Subject: [PATCH 4/7] ath10k: unify rx undecapping
In-Reply-To: <1415110931-10945-5-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Tue, 4 Nov 2014 15:22:08 +0100")
References: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
 <1415110931-10945-5-git-send-email-michal.kazior@tieto.com>
Message-ID: <87ppclq4mu.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> This creates a single, common path for MSDU,
> A-MSDU and fragmented Rx.
>
> Hopefully this will make it easier to understand
> Rx path and make it easier to work with.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

This patch had few checkpatch warnings. I fixed them with the folded
patch and full patch here:

https://github.com/kvalo/ath/commit/71fbd07d43e54f5f9f442bc5f2f4f9ef83aead63

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 6abfea768173..08963439891b 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1066,7 +1066,8 @@ static void ath10k_htt_rx_h_undecap(struct ath10k *ar,
 
 	switch (decap) {
 	case RX_MSDU_DECAP_RAW:
-		ath10k_htt_rx_h_undecap_raw(ar, msdu, status, enctype, is_decrypted);
+		ath10k_htt_rx_h_undecap_raw(ar, msdu, status, enctype,
+					    is_decrypted);
 		break;
 	case RX_MSDU_DECAP_NATIVE_WIFI:
 		ath10k_htt_rx_h_undecap_nwifi(ar, msdu, status, first_hdr);
@@ -1132,7 +1133,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
 	bool has_fcs_err;
 	bool has_crypto_err;
 	bool has_tkip_err;
-	bool has_peer_idx_invalid;
+	bool has_idx_invalid;
 	bool is_decrypted;
 
 	if (skb_queue_empty(amsdu))
@@ -1167,8 +1168,8 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
 			    __cpu_to_le32(RX_ATTENTION_FLAGS_DECRYPT_ERR));
 	has_tkip_err = !!(rxd->attention.flags &
 			  __cpu_to_le32(RX_ATTENTION_FLAGS_TKIP_MIC_ERR));
-	has_peer_idx_invalid = !!(rxd->attention.flags &
-			          __cpu_to_le32(RX_ATTENTION_FLAGS_PEER_IDX_INVALID));
+	has_idx_invalid = !!(rxd->attention.flags &
+			     __cpu_to_le32(RX_ATTENTION_FLAGS_PEER_IDX_INVALID));
 
 	/* Note: If hardware captures an encrypted frame that it can't decrypt,
 	 * e.g. due to fcs error, missing peer or invalid key data it will
@@ -1177,7 +1178,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
 	is_decrypted = (enctype != HTT_RX_MPDU_ENCRYPT_NONE &&
 			!has_fcs_err &&
 			!has_crypto_err &&
-			!has_peer_idx_invalid);
+			!has_idx_invalid);
 
 	/* Clear per-MPDU flags while leaving per-PPDU flags intact. */
 	status->flag &= ~(RX_FLAG_FAILED_FCS_CRC |


-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov 17 06:33:54 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 17 Nov 2014 16:33:54 +0200
Subject: [PATCH 6/7] ath10k: use rx descriptor for ppdu status extraction
In-Reply-To: <1415110931-10945-7-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Tue, 4 Nov 2014 15:22:10 +0100")
References: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
 <1415110931-10945-7-git-send-email-michal.kazior@tieto.com>
Message-ID: <87lhn9q4kt.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> This makes it more in line with the new Rx path.
> It also makes the code more reusable because Rx
> descriptor is more accessible.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

This patch also had a checkpatch warning. Full patch here:

https://github.com/kvalo/ath/commit/d01090f45a5891f811bfaadb9a15c7e47ef0ef26

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 41dce044e3e8..bf82cb756548 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -815,9 +815,8 @@ static void ath10k_htt_rx_h_ppdu(struct ath10k *ar,
 		ath10k_htt_rx_h_rates(ar, status, rxd);
 	}
 
-	if (is_last_ppdu) {
+	if (is_last_ppdu)
 		ath10k_htt_rx_h_mactime(ar, status, rxd);
-	}
 }
 
 static const char * const tid_to_ac[] = {


-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov 17 06:38:52 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 17 Nov 2014 16:38:52 +0200
Subject: [PATCH v3] ath10k: handle ieee80211 header and payload tracing
 separately
In-Reply-To: <1415195071-30250-1-git-send-email-rmanohar@qti.qualcomm.com>
 (Rajkumar Manoharan's message of "Wed, 5 Nov 2014 19:14:31 +0530")
References: <1415195071-30250-1-git-send-email-rmanohar@qti.qualcomm.com>
Message-ID: <87egt1q4cj.fsf@kamboji.qca.qualcomm.com>

Rajkumar Manoharan <rmanohar at qti.qualcomm.com> writes:

> For packet log, the transmitted frame 802.11 header alone is sufficient.
> Recording entire packet is also consuming lot of disk space. To optimize
> this, tx and rx data tracepoints are splitted into header and payload
> tracepoints.
>
> To record tx ieee80211 headers
>
>      trace-cmd record -e ath10k_tx_hdr
>
> To record complete packets
>
>      trace-cmd record -e ath10k_tx_hdr -e ath10k_tx_payload
>
> Cc: Michal Kazior <michal.kazior at tieto.com>
> Signed-off-by: Rajkumar Manoharan <rmanohar at qti.qualcomm.com>

Thanks, applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov 17 06:41:47 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 17 Nov 2014 16:41:47 +0200
Subject: [PATCH 1/2] ath10k: add modpram 'skip_otp' to ignore empty otp
 error during BMI
In-Reply-To: <1415366205-11672-1-git-send-email-rmanohar@qti.qualcomm.com>
 (Rajkumar Manoharan's message of "Fri, 7 Nov 2014 18:46:44 +0530")
References: <1415366205-11672-1-git-send-email-rmanohar@qti.qualcomm.com>
Message-ID: <87a93pq47o.fsf@kamboji.qca.qualcomm.com>

Rajkumar Manoharan <rmanohar at qti.qualcomm.com> writes:

> This patch would help bring up wifi interface with default board
> data in case of failures in otp download. It is useful for initial
> caliberation.
>
> Signed-off-by: Rajkumar Manoharan <rmanohar at qti.qualcomm.com>

[...]

> --- a/drivers/net/wireless/ath/ath10k/core.c
> +++ b/drivers/net/wireless/ath/ath10k/core.c
> @@ -31,12 +31,15 @@
>  unsigned int ath10k_debug_mask;
>  static bool uart_print;
>  static unsigned int ath10k_p2p;
> +static bool skip_otp;
>  module_param_named(debug_mask, ath10k_debug_mask, uint, 0644);
>  module_param(uart_print, bool, 0644);
>  module_param_named(p2p, ath10k_p2p, uint, 0644);
> +module_param(skip_otp, bool, 0644);
>  MODULE_PARM_DESC(debug_mask, "Debugging mask");
>  MODULE_PARM_DESC(uart_print, "Uart target debugging");
>  MODULE_PARM_DESC(p2p, "Enable ath10k P2P support");
> +MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");

I added back the newlines:

--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -32,10 +32,12 @@ unsigned int ath10k_debug_mask;
 static bool uart_print;
 static unsigned int ath10k_p2p;
 static bool skip_otp;
+
 module_param_named(debug_mask, ath10k_debug_mask, uint, 0644);
 module_param(uart_print, bool, 0644);
 module_param_named(p2p, ath10k_p2p, uint, 0644);
 module_param(skip_otp, bool, 0644);
+
 MODULE_PARM_DESC(debug_mask, "Debugging mask");
 MODULE_PARM_DESC(uart_print, "Uart target debugging");
 MODULE_PARM_DESC(p2p, "Enable ath10k P2P support");

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov 17 06:43:36 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 17 Nov 2014 16:43:36 +0200
Subject: [PATCH 2/2] ath10k: Advertise support for AP mode channel width
 changes
In-Reply-To: <1415366205-11672-2-git-send-email-rmanohar@qti.qualcomm.com>
 (Rajkumar Manoharan's message of "Fri, 7 Nov 2014 18:46:45 +0530")
References: <1415366205-11672-1-git-send-email-rmanohar@qti.qualcomm.com>
 <1415366205-11672-2-git-send-email-rmanohar@qti.qualcomm.com>
Message-ID: <8761edq44n.fsf@kamboji.qca.qualcomm.com>

Rajkumar Manoharan <rmanohar at qti.qualcomm.com> writes:

> This will enable AP mode to change channel width dynamically
> based on 20/40 intolerance report sent by associated client.
>
> Signed-off-by: Rajkumar Manoharan <rmanohar at qti.qualcomm.com>

[...]

> --- a/drivers/net/wireless/ath/ath10k/mac.c
> +++ b/drivers/net/wireless/ath/ath10k/mac.c
> @@ -4916,6 +4916,7 @@ int ath10k_mac_register(struct ath10k *ar)
>  	ar->hw->wiphy->max_remain_on_channel_duration = 5000;
>  
>  	ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
> +	ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
>  	/*
>  	 * on LL hardware queues are managed entirely by the FW
>  	 * so we only advertise to mac we can do the queues thing

I added newline to here as well:

--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4928,6 +4928,7 @@ int ath10k_mac_register(struct ath10k *ar)
 
        ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
        ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
+
        /*
         * on LL hardware queues are managed entirely by the FW
         * so we only advertise to mac we can do the queues thing

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov 17 06:48:08 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 17 Nov 2014 16:48:08 +0200
Subject: [PATCH 1/2] ath10k: add modpram 'skip_otp' to ignore empty otp
 error during BMI
In-Reply-To: <1415366205-11672-1-git-send-email-rmanohar@qti.qualcomm.com>
 (Rajkumar Manoharan's message of "Fri, 7 Nov 2014 18:46:44 +0530")
References: <1415366205-11672-1-git-send-email-rmanohar@qti.qualcomm.com>
Message-ID: <871tp1q3x3.fsf@kamboji.qca.qualcomm.com>

Rajkumar Manoharan <rmanohar at qti.qualcomm.com> writes:

> This patch would help bring up wifi interface with default board
> data in case of failures in otp download. It is useful for initial
> caliberation.
>
> Signed-off-by: Rajkumar Manoharan <rmanohar at qti.qualcomm.com>

Thanks, both patches applied.

-- 
Kalle Valo


From michal.kazior at tieto.com  Mon Nov 17 06:54:23 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 17 Nov 2014 15:54:23 +0100
Subject: [PATCH 4/7] ath10k: unify rx undecapping
In-Reply-To: <87ppclq4mu.fsf@kamboji.qca.qualcomm.com>
References: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
 <1415110931-10945-5-git-send-email-michal.kazior@tieto.com>
 <87ppclq4mu.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CA+BoTQ=Ws0JGsVBd2J0fe2_JqAhCVpHmNkn10CJx6BCNG-r0cg@mail.gmail.com>

On 17 November 2014 15:32, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Michal Kazior <michal.kazior at tieto.com> writes:
>
>> This creates a single, common path for MSDU,
>> A-MSDU and fragmented Rx.
>>
>> Hopefully this will make it easier to understand
>> Rx path and make it easier to work with.
>>
>> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
>
> This patch had few checkpatch warnings. I fixed them with the folded
> patch and full patch here:
>
> https://github.com/kvalo/ath/commit/71fbd07d43e54f5f9f442bc5f2f4f9ef83aead63

Thanks!

[...]
> @@ -1132,7 +1133,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
>         bool has_fcs_err;
>         bool has_crypto_err;
>         bool has_tkip_err;
> -       bool has_peer_idx_invalid;
> +       bool has_idx_invalid;
>         bool is_decrypted;

I don't really like the has_idx_invalid. Perhaps has_peer_err conveys
a bit more of the original meaning?

As much as I'd like to leave the original var name I'd like to be
checkpatch warning free. Sigh..


Micha?


From kvalo at qca.qualcomm.com  Mon Nov 17 07:11:29 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 17 Nov 2014 17:11:29 +0200
Subject: [PATCH 4/7] ath10k: unify rx undecapping
In-Reply-To: <CA+BoTQ=Ws0JGsVBd2J0fe2_JqAhCVpHmNkn10CJx6BCNG-r0cg@mail.gmail.com>
 (Michal Kazior's message of "Mon, 17 Nov 2014 15:54:23 +0100")
References: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
 <1415110931-10945-5-git-send-email-michal.kazior@tieto.com>
 <87ppclq4mu.fsf@kamboji.qca.qualcomm.com>
 <CA+BoTQ=Ws0JGsVBd2J0fe2_JqAhCVpHmNkn10CJx6BCNG-r0cg@mail.gmail.com>
Message-ID: <87vbmdoo9q.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> On 17 November 2014 15:32, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
>> Michal Kazior <michal.kazior at tieto.com> writes:
>>
>>> This creates a single, common path for MSDU,
>>> A-MSDU and fragmented Rx.
>>>
>>> Hopefully this will make it easier to understand
>>> Rx path and make it easier to work with.
>>>
>>> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
>>
>> This patch had few checkpatch warnings. I fixed them with the folded
>> patch and full patch here:
>>
>> https://github.com/kvalo/ath/commit/71fbd07d43e54f5f9f442bc5f2f4f9ef83aead63
>
> Thanks!
>
> [...]
>> @@ -1132,7 +1133,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
>>         bool has_fcs_err;
>>         bool has_crypto_err;
>>         bool has_tkip_err;
>> -       bool has_peer_idx_invalid;
>> +       bool has_idx_invalid;
>>         bool is_decrypted;
>
> I don't really like the has_idx_invalid. Perhaps has_peer_err conveys
> a bit more of the original meaning?

What about just peer_idx_invalid? IMHO we really don't need the has_
prefix in that relatively small function.

> As much as I'd like to leave the original var name I'd like to be
> checkpatch warning free. Sigh..

Same here. The checkpatch is just so useful tool to keep the style
unified.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov 17 07:30:07 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 17 Nov 2014 17:30:07 +0200
Subject: Pull request: ath 20141117
Message-ID: <87r3x1oneo.fsf@kamboji.qca.qualcomm.com>

Hi John,

new pull request again, here's the changelog:

----------------------------------------------------------------------
One ath6kl patch and rest for ath10k, but nothing really major which
stands out. Most notable:

o fix resume (Bartosz)

o firmware restart is now faster and more reliable (Michal)

o it's now possible to test hardware restart functionality without
  crashing the firmware using hw-restart parameter with
  simulate_fw_crash debugfs file (Michal)

----------------------------------------------------------------------

The following changes since commit 84cbf3a7592879810f80cece6c7f736f099ab163:

  ath10k: split ce pipe init/alloc further (2014-10-23 16:41:32 +0300)

are available in the git repository at:

  git://github.com/kvalo/ath.git for-linville

for you to fetch changes up to 9de8f26f0038133bdfb8cf847936645dab949d88:

  ath10k: fix mismatched wmi api call (2014-11-17 16:48:49 +0200)

----------------------------------------------------------------
Alexey Khoroshilov (1):
      ath6kl: remove incorrect reset_resume handler

Bartosz Markowski (1):
      ath10k: fix pm resume after suspend

Felix Fietkau (1):
      ath10k: add SURVEY_INFO_IN_USE for current channel on survey

Michal Kazior (20):
      ath10k: don't drop control and null func Rx
      ath10k: remove unused variable
      ath10k: use ieee80211 defines for crypto param lengths
      ath10k: fix rx buffer tracing
      ath10k: deduplicate htt rx dma unmapping
      ath10k: don't drop frames aggressively
      ath10k: add extra sanity check when popping amsdu
      ath10k: don't forget to replenish after fragmented Rx
      ath10k: clear htt->rx_confused on load
      ath10k: remove tsf argument from rx_desc tracing
      ath10k: re-use trace class
      ath10k: call correct function for frag threshold
      ath10k: avoid possible deadlock with scan timeout
      ath10k: change ce ring cleanup logic
      ath10k: make warm reset a bit safer and faster
      ath10k: split reset logic from power up
      ath10k: don't reset chip on power_down
      ath10k: fix possible bmi crash
      ath10k: expose hw restart via debugfs
      ath10k: speed up hw recovery

Peter Oh (1):
      ath10k: fix mismatched wmi api call

Rajkumar Manoharan (3):
      ath10k: handle ieee80211 header and payload tracing separately
      ath10k: add modpram 'skip_otp' to ignore empty otp error during BMI
      ath10k: advertise support for AP mode channel width changes

 drivers/net/wireless/ath/ath10k/ce.c     |    9 +-
 drivers/net/wireless/ath/ath10k/core.c   |   30 ++-
 drivers/net/wireless/ath/ath10k/core.h   |    5 +
 drivers/net/wireless/ath/ath10k/debug.c  |    7 +-
 drivers/net/wireless/ath/ath10k/htt_rx.c |   99 ++++----
 drivers/net/wireless/ath/ath10k/htt_tx.c |    4 +-
 drivers/net/wireless/ath/ath10k/mac.c    |   27 ++-
 drivers/net/wireless/ath/ath10k/mac.h    |    1 +
 drivers/net/wireless/ath/ath10k/pci.c    |  364 ++++++++++++++++--------------
 drivers/net/wireless/ath/ath10k/trace.h  |  109 +++++----
 drivers/net/wireless/ath/ath10k/txrx.c   |    3 +-
 drivers/net/wireless/ath/ath10k/wmi.c    |   16 +-
 drivers/net/wireless/ath/ath6kl/usb.c    |    9 -
 13 files changed, 388 insertions(+), 295 deletions(-)

-- 
Kalle Valo


From linville at tuxdriver.com  Mon Nov 17 12:29:44 2014
From: linville at tuxdriver.com (John W. Linville)
Date: Mon, 17 Nov 2014 15:29:44 -0500
Subject: Pull request: ath 20141117
In-Reply-To: <87r3x1oneo.fsf@kamboji.qca.qualcomm.com>
References: <87r3x1oneo.fsf@kamboji.qca.qualcomm.com>
Message-ID: <20141117202944.GE3511@tuxdriver.com>

On Mon, Nov 17, 2014 at 05:30:07PM +0200, Kalle Valo wrote:
> Hi John,
> 
> new pull request again, here's the changelog:
> 
> ----------------------------------------------------------------------
> One ath6kl patch and rest for ath10k, but nothing really major which
> stands out. Most notable:
> 
> o fix resume (Bartosz)
> 
> o firmware restart is now faster and more reliable (Michal)
> 
> o it's now possible to test hardware restart functionality without
>   crashing the firmware using hw-restart parameter with
>   simulate_fw_crash debugfs file (Michal)
> 
> ----------------------------------------------------------------------
> 
> The following changes since commit 84cbf3a7592879810f80cece6c7f736f099ab163:
> 
>   ath10k: split ce pipe init/alloc further (2014-10-23 16:41:32 +0300)
> 
> are available in the git repository at:
> 
>   git://github.com/kvalo/ath.git for-linville
> 
> for you to fetch changes up to 9de8f26f0038133bdfb8cf847936645dab949d88:
> 
>   ath10k: fix mismatched wmi api call (2014-11-17 16:48:49 +0200)

Pulling now...

-- 
John W. Linville		Someday the world will need a hero, and you
linville at tuxdriver.com			might be all we have.  Be ready.


From psidhu at gateworks.com  Mon Nov 17 17:20:45 2014
From: psidhu at gateworks.com (Pushpal Sidhu)
Date: Mon, 17 Nov 2014 17:20:45 -0800
Subject: htt rx stopped. cannot recover
In-Reply-To: <CA+BoTQkfPJp4tg8eR4OJDs2Cf_s0x36QYD-Yq6fTQ41c1jm6TA@mail.gmail.com>
References: <CAD1M060Y+3r_-J12ZqT4TqddUf9tJHKCEPJ0DhFJ1sCiXimdVw@mail.gmail.com>
 <5461382B.6070607@candelatech.com>
 <CAD1M062xcGu2EJzxaXYQt5uHyDxHpEE+FDiPB4SBirXX5ePz_A@mail.gmail.com>
 <54613C13.9010008@candelatech.com>
 <CAD1M061wRo5MqmKYy8jw9fKpraA0DFJTh4k+QNzLkayLmBttfA@mail.gmail.com>
 <CA+BoTQk7idFbyYzLxKCgmSQ=zzQTraOJ-fy5_qhDpzkueQe8KQ@mail.gmail.com>
 <CAD1M063n=WGeQRJKycvWYGMZRFN4gabM56dgeX_4tf8W8hyUKA@mail.gmail.com>
 <CA+BoTQkfPJp4tg8eR4OJDs2Cf_s0x36QYD-Yq6fTQ41c1jm6TA@mail.gmail.com>
Message-ID: <CAD1M0638VrB_hAqAn-H-02cjF6ivQzFBwtqs02BxgzLRdpCGsg@mail.gmail.com>

On Fri, Nov 14, 2014 at 12:31 AM, Michal Kazior <michal.kazior at tieto.com> wrote:
> I've used ath10k AP in a bridge many times and haven't seen this issue yet.

I just found that I can reproduce the problem passing traffic through
from AP <-wifi-> STA with no bridging. The reason I didn't see the
problem before is that it takes considerably longer to reproduce and I
wasn't necessarily looking for it (65 seconds vs 5 seconds).

> Putting an interface into a bridge enables promiscuous mode on it. In
> ath10k this is handled by creating a monitor vdev to implicitly
> influence Rx filters so that hw/fw pass everything up to host. I
> suspect your RF environment may contain particular traffic patterns
> which trigger the problem within firmware code related to monitor
> vdev.
>
> You could try hacking up ath10k to not create/start monitor vdev and
> see if you can still reproduce the problem. Keep in mind bridging will
> be crippled in some cases since firmware won't deliver some frames to
> ath10k.

I've actually been using attenuators for these tests, a little more
than 60dB on each chain and as I mentioned above, I don't believe it's
a vdev issue due to the fact that I can reproduce this without
bridging (which doesn't put the radio into promiscuous mode and thus
doesn't create a monitor vdev, correct?).

> Hmm.. Now that I think about it, after the recent Rx rework it might
> be possible to circumvent the problem. ath10k uses very little data
> from Rx indication event and instead Rx descriptor is used for most
> things. Popping function would need some changes so that it can back
> off safely if a frame buffer isn't ready. ath10k would probably need
> to poll for Rx too.

I saw those patches and I liked what I saw. When I tested with them in
place, I found it failed in the same 'test' of checking for MSDU_DONE
flag (duh, just wanted to make that clear, haha). I tried not setting
the confused flag when the issue was hit, but eventually a kernel
panic would occur.

Something very interesting that I found was I only see this issue when
the radio's are behind a PCIe bridge. That is, I tested on two set's
of boards with the same CPU/structure, with the one difference that
there is no PCIe bridge on one. I am currently running an extended
test on the board without PCIe to see if it isn't an issue that will
manifest itself at a later time, but as of now, it's looking like
that's no the case. Do you have any thoughts on this?

- Pushpal


From michal.kazior at tieto.com  Mon Nov 17 22:46:35 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue, 18 Nov 2014 07:46:35 +0100
Subject: [PATCH 4/7] ath10k: unify rx undecapping
In-Reply-To: <87vbmdoo9q.fsf@kamboji.qca.qualcomm.com>
References: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
 <1415110931-10945-5-git-send-email-michal.kazior@tieto.com>
 <87ppclq4mu.fsf@kamboji.qca.qualcomm.com>
 <CA+BoTQ=Ws0JGsVBd2J0fe2_JqAhCVpHmNkn10CJx6BCNG-r0cg@mail.gmail.com>
 <87vbmdoo9q.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CA+BoTQm1tzJhz7HtF941z8hrkOpyCpfJhqzmx1tifVFCMo=R1A@mail.gmail.com>

On 17 November 2014 16:11, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Michal Kazior <michal.kazior at tieto.com> writes:
>> On 17 November 2014 15:32, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
[...]
>>> This patch had few checkpatch warnings. I fixed them with the folded
>>> patch and full patch here:
>>>
>>> https://github.com/kvalo/ath/commit/71fbd07d43e54f5f9f442bc5f2f4f9ef83aead63
[...]
>>> @@ -1132,7 +1133,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
>>>         bool has_fcs_err;
>>>         bool has_crypto_err;
>>>         bool has_tkip_err;
>>> -       bool has_peer_idx_invalid;
>>> +       bool has_idx_invalid;
>>>         bool is_decrypted;
>>
>> I don't really like the has_idx_invalid. Perhaps has_peer_err conveys
>> a bit more of the original meaning?
>
> What about just peer_idx_invalid? IMHO we really don't need the has_
> prefix in that relatively small function.

Good point but the assignment line with `peer_idx_invalid` will still
be over 80 chars long, no?

So perhaps instead of doing `rxd->attention.flags &
__cpu_to_le32(FLAG)` it could be `attention =
__le32_to_cpu(rxd->attention.flags)` and then `attention & FLAG` ?
This way it shouldn't exceed the 80 char limit and var names won't
need to be changed. Hopefully compiler will optimize it away.


Micha?


From michal.kazior at tieto.com  Mon Nov 17 22:56:47 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue, 18 Nov 2014 07:56:47 +0100
Subject: htt rx stopped. cannot recover
In-Reply-To: <CAD1M0638VrB_hAqAn-H-02cjF6ivQzFBwtqs02BxgzLRdpCGsg@mail.gmail.com>
References: <CAD1M060Y+3r_-J12ZqT4TqddUf9tJHKCEPJ0DhFJ1sCiXimdVw@mail.gmail.com>
 <5461382B.6070607@candelatech.com>
 <CAD1M062xcGu2EJzxaXYQt5uHyDxHpEE+FDiPB4SBirXX5ePz_A@mail.gmail.com>
 <54613C13.9010008@candelatech.com>
 <CAD1M061wRo5MqmKYy8jw9fKpraA0DFJTh4k+QNzLkayLmBttfA@mail.gmail.com>
 <CA+BoTQk7idFbyYzLxKCgmSQ=zzQTraOJ-fy5_qhDpzkueQe8KQ@mail.gmail.com>
 <CAD1M063n=WGeQRJKycvWYGMZRFN4gabM56dgeX_4tf8W8hyUKA@mail.gmail.com>
 <CA+BoTQkfPJp4tg8eR4OJDs2Cf_s0x36QYD-Yq6fTQ41c1jm6TA@mail.gmail.com>
 <CAD1M0638VrB_hAqAn-H-02cjF6ivQzFBwtqs02BxgzLRdpCGsg@mail.gmail.com>
Message-ID: <CA+BoTQkdZ52GKaGzKL_NU8TD5fCxxxiObj6RnBXk1Rz=426N7w@mail.gmail.com>

On 18 November 2014 02:20, Pushpal Sidhu <psidhu at gateworks.com> wrote:
> On Fri, Nov 14, 2014 at 12:31 AM, Michal Kazior <michal.kazior at tieto.com> wrote:
>> I've used ath10k AP in a bridge many times and haven't seen this issue yet.
>
> I just found that I can reproduce the problem passing traffic through
> from AP <-wifi-> STA with no bridging. The reason I didn't see the
> problem before is that it takes considerably longer to reproduce and I
> wasn't necessarily looking for it (65 seconds vs 5 seconds).
>
>> Putting an interface into a bridge enables promiscuous mode on it. In
>> ath10k this is handled by creating a monitor vdev to implicitly
>> influence Rx filters so that hw/fw pass everything up to host. I
>> suspect your RF environment may contain particular traffic patterns
>> which trigger the problem within firmware code related to monitor
>> vdev.
>>
>> You could try hacking up ath10k to not create/start monitor vdev and
>> see if you can still reproduce the problem. Keep in mind bridging will
>> be crippled in some cases since firmware won't deliver some frames to
>> ath10k.
>
> I've actually been using attenuators for these tests, a little more
> than 60dB on each chain and as I mentioned above, I don't believe it's
> a vdev issue due to the fact that I can reproduce this without
> bridging (which doesn't put the radio into promiscuous mode and thus
> doesn't create a monitor vdev, correct?).

You can get super sure and take a look in dmesg/syslog to verify if
ath10k's wlan interface is in promisc mode or not. I guess it's not
though.


>> Hmm.. Now that I think about it, after the recent Rx rework it might
>> be possible to circumvent the problem. ath10k uses very little data
>> from Rx indication event and instead Rx descriptor is used for most
>> things. Popping function would need some changes so that it can back
>> off safely if a frame buffer isn't ready. ath10k would probably need
>> to poll for Rx too.
>
> I saw those patches and I liked what I saw. When I tested with them in
> place, I found it failed in the same 'test' of checking for MSDU_DONE
> flag (duh, just wanted to make that clear, haha). I tried not setting
> the confused flag when the issue was hit, but eventually a kernel
> panic would occur.

I'm glad you like them.

The result of not setting the confused flag in this case is pretty expected :-)


> Something very interesting that I found was I only see this issue when
> the radio's are behind a PCIe bridge. That is, I tested on two set's
> of boards with the same CPU/structure, with the one difference that
> there is no PCIe bridge on one. I am currently running an extended
> test on the board without PCIe to see if it isn't an issue that will
> manifest itself at a later time, but as of now, it's looking like
> that's no the case. Do you have any thoughts on this?

Hmm.. Perhaps there's some kind of race and the host main memory isn't
updated in a timely fashion? In that case ath10k could try to, instead
of immediatelly unmapping, keep on syncing dma to cpu and checking the
MSDU_DONE bit for a few msecs (what an ugly workaround..) before it
finally unmaps the frame.

I wonder if that's a bug in ath10k's target device PCIe controller or
the PCIe bridge?


Micha?


From kvalo at qca.qualcomm.com  Tue Nov 18 05:58:19 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 18 Nov 2014 15:58:19 +0200
Subject: [PATCH 4/7] ath10k: unify rx undecapping
In-Reply-To: <CA+BoTQm1tzJhz7HtF941z8hrkOpyCpfJhqzmx1tifVFCMo=R1A@mail.gmail.com>
 (Michal Kazior's message of "Tue, 18 Nov 2014 07:46:35 +0100")
References: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
 <1415110931-10945-5-git-send-email-michal.kazior@tieto.com>
 <87ppclq4mu.fsf@kamboji.qca.qualcomm.com>
 <CA+BoTQ=Ws0JGsVBd2J0fe2_JqAhCVpHmNkn10CJx6BCNG-r0cg@mail.gmail.com>
 <87vbmdoo9q.fsf@kamboji.qca.qualcomm.com>
 <CA+BoTQm1tzJhz7HtF941z8hrkOpyCpfJhqzmx1tifVFCMo=R1A@mail.gmail.com>
Message-ID: <87r3x0k3us.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> On 17 November 2014 16:11, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
>> Michal Kazior <michal.kazior at tieto.com> writes:
>>> On 17 November 2014 15:32, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> [...]
>>>> This patch had few checkpatch warnings. I fixed them with the folded
>>>> patch and full patch here:
>>>>
>>>> https://github.com/kvalo/ath/commit/71fbd07d43e54f5f9f442bc5f2f4f9ef83aead63
> [...]
>>>> @@ -1132,7 +1133,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
>>>>         bool has_fcs_err;
>>>>         bool has_crypto_err;
>>>>         bool has_tkip_err;
>>>> -       bool has_peer_idx_invalid;
>>>> +       bool has_idx_invalid;
>>>>         bool is_decrypted;
>>>
>>> I don't really like the has_idx_invalid. Perhaps has_peer_err conveys
>>> a bit more of the original meaning?
>>
>> What about just peer_idx_invalid? IMHO we really don't need the has_
>> prefix in that relatively small function.
>
> Good point but the assignment line with `peer_idx_invalid` will still
> be over 80 chars long, no?

I actually test with 83 char limit nowadays. I should add the checkpatch
command line to the wiki.

> So perhaps instead of doing `rxd->attention.flags &
> __cpu_to_le32(FLAG)` it could be `attention =
> __le32_to_cpu(rxd->attention.flags)` and then `attention & FLAG` ?
> This way it shouldn't exceed the 80 char limit and var names won't
> need to be changed. Hopefully compiler will optimize it away.

That's much better and actually has a lot less calls to cpu_le32(). I
folded the patch below.

But aren't the '!!' operators useless? 'has_*' variables are booleans,
doesn't compiler handle that automatically?

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 6f58b7f912cd..6abb3b6a348f 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1133,8 +1133,9 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
 	bool has_fcs_err;
 	bool has_crypto_err;
 	bool has_tkip_err;
-	bool has_idx_invalid;
+	bool has_peer_idx_invalid;
 	bool is_decrypted;
+	u32 attention;
 
 	if (skb_queue_empty(amsdu))
 		return;
@@ -1162,14 +1163,12 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
 	/* Some attention flags are valid only in the last MSDU. */
 	last = skb_peek_tail(amsdu);
 	rxd = (void *)last->data - sizeof(*rxd);
-	has_fcs_err = !!(rxd->attention.flags &
-			 __cpu_to_le32(RX_ATTENTION_FLAGS_FCS_ERR));
-	has_crypto_err = !!(rxd->attention.flags &
-			    __cpu_to_le32(RX_ATTENTION_FLAGS_DECRYPT_ERR));
-	has_tkip_err = !!(rxd->attention.flags &
-			  __cpu_to_le32(RX_ATTENTION_FLAGS_TKIP_MIC_ERR));
-	has_idx_invalid = !!(rxd->attention.flags &
-			     __cpu_to_le32(RX_ATTENTION_FLAGS_PEER_IDX_INVALID));
+	attention = __le32_to_cpu(rxd->attention.flags);
+
+	has_fcs_err = !!(attention & RX_ATTENTION_FLAGS_FCS_ERR);
+	has_crypto_err = !!(attention & RX_ATTENTION_FLAGS_DECRYPT_ERR);
+	has_tkip_err = !!(attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR);
+	has_peer_idx_invalid = !!(attention & RX_ATTENTION_FLAGS_PEER_IDX_INVALID);
 
 	/* Note: If hardware captures an encrypted frame that it can't decrypt,
 	 * e.g. due to fcs error, missing peer or invalid key data it will
@@ -1178,7 +1177,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
 	is_decrypted = (enctype != HTT_RX_MPDU_ENCRYPT_NONE &&
 			!has_fcs_err &&
 			!has_crypto_err &&
-			!has_idx_invalid);
+			!has_peer_idx_invalid);
 
 	/* Clear per-MPDU flags while leaving per-PPDU flags intact. */
 	status->flag &= ~(RX_FLAG_FAILED_FCS_CRC |




-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 18 06:11:07 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 18 Nov 2014 16:11:07 +0200
Subject: TX Power Concerns between Firmware
In-Reply-To: <CA+BoTQkTpV1LViDWAj1yZwCgshStzHhGe9DTD8S++DK8uUe9oQ@mail.gmail.com>
 (Michal Kazior's message of "Wed, 5 Nov 2014 15:09:46 +0100")
References: <CAD1M062Um6PY2fE4AiM6D3=_McdTMkixzYQ23kYwM7_xdZR=wA@mail.gmail.com>
 <CA+BoTQkTpV1LViDWAj1yZwCgshStzHhGe9DTD8S++DK8uUe9oQ@mail.gmail.com>
Message-ID: <87ioick39g.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> @Kalle: Now that I think about it - do we really need to embed otp binaries?

In theory we could release otp.bin separetely. But that would be error
prone from user's point of view (they need to update two files instead
of just one), more work for us to track otp.bin releases etc.

So I'm not really fond of the idea. I would rather update otp.bin and
create a new firmware version.

-- 
Kalle Valo


From psidhu at gateworks.com  Tue Nov 18 17:23:26 2014
From: psidhu at gateworks.com (Pushpal Sidhu)
Date: Tue, 18 Nov 2014 17:23:26 -0800
Subject: htt rx stopped. cannot recover
In-Reply-To: <CA+BoTQkdZ52GKaGzKL_NU8TD5fCxxxiObj6RnBXk1Rz=426N7w@mail.gmail.com>
References: <CAD1M060Y+3r_-J12ZqT4TqddUf9tJHKCEPJ0DhFJ1sCiXimdVw@mail.gmail.com>
 <5461382B.6070607@candelatech.com>
 <CAD1M062xcGu2EJzxaXYQt5uHyDxHpEE+FDiPB4SBirXX5ePz_A@mail.gmail.com>
 <54613C13.9010008@candelatech.com>
 <CAD1M061wRo5MqmKYy8jw9fKpraA0DFJTh4k+QNzLkayLmBttfA@mail.gmail.com>
 <CA+BoTQk7idFbyYzLxKCgmSQ=zzQTraOJ-fy5_qhDpzkueQe8KQ@mail.gmail.com>
 <CAD1M063n=WGeQRJKycvWYGMZRFN4gabM56dgeX_4tf8W8hyUKA@mail.gmail.com>
 <CA+BoTQkfPJp4tg8eR4OJDs2Cf_s0x36QYD-Yq6fTQ41c1jm6TA@mail.gmail.com>
 <CAD1M0638VrB_hAqAn-H-02cjF6ivQzFBwtqs02BxgzLRdpCGsg@mail.gmail.com>
 <CA+BoTQkdZ52GKaGzKL_NU8TD5fCxxxiObj6RnBXk1Rz=426N7w@mail.gmail.com>
Message-ID: <CAD1M062FNiiAD=Q6zGX8ooSfrQTj8gi_1oDSdEPjAQsaNPrjEw@mail.gmail.com>

On Mon, Nov 17, 2014 at 10:56 PM, Michal Kazior <michal.kazior at tieto.com> wrote:
> You can get super sure and take a look in dmesg/syslog to verify if
> ath10k's wlan interface is in promisc mode or not. I guess it's not
> though.
It seems that there's a "vdev 0". I'll look into hacking this out
later when I get some more time, though it seems that whenever a
station is associated with an AP, a vdev is always created.

>> ...
>> I tried not setting
>> the confused flag when the issue was hit, but eventually a kernel
>> panic would occur.
>
> I'm glad you like them.
>
> The result of not setting the confused flag in this case is pretty expected :-)
>
>> Something very interesting that I found was I only see this issue when
>> the radio's are behind a PCIe bridge. That is, I tested on two set's
>> of boards with the same CPU/structure, with the one difference that
>> there is no PCIe bridge on one. I am currently running an extended
>> test on the board without PCIe to see if it isn't an issue that will
>> manifest itself at a later time, but as of now, it's looking like
>> that's no the case. Do you have any thoughts on this?
>
> Hmm.. Perhaps there's some kind of race and the host main memory isn't
> updated in a timely fashion? In that case ath10k could try to, instead
> of immediatelly unmapping, keep on syncing dma to cpu and checking the
> MSDU_DONE bit for a few msecs (what an ugly workaround..) before it
> finally unmaps the frame.
>
> I wonder if that's a bug in ath10k's target device PCIe controller or
> the PCIe bridge?

While running the extended test, at about 7 hours of continuous
testing with the two boards without a PCIe bridge (configured as a
wireless bridge e.g. 4addr=on), the STAtion has a kernel panic that
seems to be caused by a double free or something similar. Log is
located here (glad I set 'debug' in kernel cmdline):
http://dpaste.com/1G77X7N (most interesting info located between times
[25684.512971] - [25684.587585]).

This is basically the same kernel oops I saw earlier when I disabled
the confused flag (occurs on skb_release_data). I've ruled out a SMP
issue as I can recreate this with nosmp. Because I see this issue on a
board without a PCIe bridge, I'm leaning towards the root cause of the
issue to maybe be in the ath10k's target device PCIe controller (irq's
being fired is what lead to this code path).

When I get some time later, I'll try that workaround, though I don't
think that's the "right" way to fix this problem.

- Pushpal


From michal.kazior at tieto.com  Tue Nov 18 22:44:10 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Wed, 19 Nov 2014 07:44:10 +0100
Subject: htt rx stopped. cannot recover
In-Reply-To: <CAD1M062FNiiAD=Q6zGX8ooSfrQTj8gi_1oDSdEPjAQsaNPrjEw@mail.gmail.com>
References: <CAD1M060Y+3r_-J12ZqT4TqddUf9tJHKCEPJ0DhFJ1sCiXimdVw@mail.gmail.com>
 <5461382B.6070607@candelatech.com>
 <CAD1M062xcGu2EJzxaXYQt5uHyDxHpEE+FDiPB4SBirXX5ePz_A@mail.gmail.com>
 <54613C13.9010008@candelatech.com>
 <CAD1M061wRo5MqmKYy8jw9fKpraA0DFJTh4k+QNzLkayLmBttfA@mail.gmail.com>
 <CA+BoTQk7idFbyYzLxKCgmSQ=zzQTraOJ-fy5_qhDpzkueQe8KQ@mail.gmail.com>
 <CAD1M063n=WGeQRJKycvWYGMZRFN4gabM56dgeX_4tf8W8hyUKA@mail.gmail.com>
 <CA+BoTQkfPJp4tg8eR4OJDs2Cf_s0x36QYD-Yq6fTQ41c1jm6TA@mail.gmail.com>
 <CAD1M0638VrB_hAqAn-H-02cjF6ivQzFBwtqs02BxgzLRdpCGsg@mail.gmail.com>
 <CA+BoTQkdZ52GKaGzKL_NU8TD5fCxxxiObj6RnBXk1Rz=426N7w@mail.gmail.com>
 <CAD1M062FNiiAD=Q6zGX8ooSfrQTj8gi_1oDSdEPjAQsaNPrjEw@mail.gmail.com>
Message-ID: <CA+BoTQn2xi3ssEn+HGc_5pgdb5Xrw4SPqBD4-QaWT1d9LqieMA@mail.gmail.com>

On 19 November 2014 02:23, Pushpal Sidhu <psidhu at gateworks.com> wrote:
> On Mon, Nov 17, 2014 at 10:56 PM, Michal Kazior <michal.kazior at tieto.com> wrote:
>> You can get super sure and take a look in dmesg/syslog to verify if
>> ath10k's wlan interface is in promisc mode or not. I guess it's not
>> though.
> It seems that there's a "vdev 0". I'll look into hacking this out
> later when I get some more time, though it seems that whenever a
> station is associated with an AP, a vdev is always created.

This is fine. Each vif will have a vdev of an according type. Promisc
mode triggers creation of an additional, special vdev (which isn't
associated with any vif whatsoever) with type=monitor


[...]
> While running the extended test, at about 7 hours of continuous
> testing with the two boards without a PCIe bridge (configured as a
> wireless bridge e.g. 4addr=on), the STAtion has a kernel panic that
> seems to be caused by a double free or something similar. Log is
> located here (glad I set 'debug' in kernel cmdline):
> http://dpaste.com/1G77X7N (most interesting info located between times
> [25684.512971] - [25684.587585]).

Is this on vanilla ath10k code or did you ignore the rx_confused flag
during the test?

Anyway it'd be lovely if you could get the code line for
ath10k_htt_txrx_compl_task+0x100 (e.g. via `gdb` with `l *
ath10k_htt_txrx_compl_task+0x100)`.


Micha?


From kvalo at qca.qualcomm.com  Thu Nov 20 03:17:56 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Thu, 20 Nov 2014 13:17:56 +0200
Subject: [PATCH] ath10k: fix mismatched wmi api call
In-Reply-To: <1415935071-21422-1-git-send-email-poh@qca.qualcomm.com> (Peter
 Oh's message of "Thu, 13 Nov 2014 19:17:51 -0800")
References: <1415935071-21422-1-git-send-email-poh@qca.qualcomm.com>
Message-ID: <87tx1udst7.fsf@kamboji.qca.qualcomm.com>

Peter Oh <poh at qca.qualcomm.com> writes:

> Fix to use v10.2 wmi call for firmware v10.2.
> It turned out that peer association function was using
> v10.1 wmi call for v10.2 firmware during code review.
>
> Signed-off-by: Peter Oh <poh at qca.qualcomm.com>

Thanks, applied.

(Actually I had applied this already on Nov 17 but forgot to reply.)

-- 
Kalle Valo


From sujith at msujith.org  Thu Nov 20 06:06:22 2014
From: sujith at msujith.org (Sujith Manoharan)
Date: Thu, 20 Nov 2014 19:36:22 +0530
Subject: [RFC] ath10k: Fix shared WEP
Message-ID: <1416492382-18058-1-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha at qca.qualcomm.com>

When static keys are used in shared WEP, when a
station is associated, message 3 is sent with an
encrypted payload. But, for subsequent
authentications that are triggered without a
deauth, the auth frame is decrypted by the HW. To
handle this, check if the WEP keys have already
been set for the peer and if so, mark the
frame as decrypted.

Signed-off-by: Sujith Manoharan <c_manoha at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 25 +++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/mac.h |  2 ++
 drivers/net/wireless/ath/ath10k/wmi.c | 29 +++++++++++++++++++++++++++++
 3 files changed, 56 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 1245ac8..e8fee46 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -179,6 +179,31 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
 	return first_errno;
 }
 
+bool ath10k_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
+				u8 keyidx)
+{
+	struct ath10k_peer *peer;
+	int i;
+
+	/*
+	 * We don't know which vdev this peer belongs to,
+	 * since WMI doesn't give us that information.
+	 */
+	spin_lock_bh(&ar->data_lock);
+	peer = ath10k_peer_find(ar, 0, addr);
+	spin_unlock_bh(&ar->data_lock);
+
+	if (!peer)
+		return false;
+
+	for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
+		if (peer->keys[i] && peer->keys[i]->keyidx == keyidx)
+			return true;
+	}
+
+	return false;
+}
+
 static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
 				 struct ieee80211_key_conf *key)
 {
diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
index 4e3c989..f5d0a5b 100644
--- a/drivers/net/wireless/ath/ath10k/mac.h
+++ b/drivers/net/wireless/ath/ath10k/mac.h
@@ -41,6 +41,8 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work);
 void ath10k_halt(struct ath10k *ar);
 void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif);
 void ath10k_drain_tx(struct ath10k *ar);
+bool ath10k_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
+				u8 keyidx);
 
 static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
 {
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c2bc828..8f1186e 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -1113,6 +1113,33 @@ static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band)
 	return rate_idx;
 }
 
+static void ath10k_check_wep(struct ath10k *ar, struct sk_buff *skb,
+			     struct ieee80211_rx_status *status)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	unsigned int hdrlen;
+	bool peer_key;
+	u8 *addr, keyidx;
+
+	if (ieee80211_is_auth(hdr->frame_control) &&
+	    ieee80211_has_protected(hdr->frame_control)) {
+		hdrlen = ieee80211_hdrlen(hdr->frame_control);
+		if (skb->len < (hdrlen + 4))
+			return;
+
+		keyidx = skb->data[hdrlen + 3] >> 6;
+		addr = ieee80211_get_SA(hdr);
+		peer_key = ath10k_is_peer_wep_key_set(ar, addr, keyidx);
+
+		if (peer_key) {
+			ath10k_dbg(ar, ATH10K_DBG_MAC,
+				   "wep key present for peer: %pM\n", addr);
+			status->flag |= RX_FLAG_DECRYPTED;
+		}
+	}
+
+}
+
 static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_mgmt_rx_event_v1 *ev_v1;
@@ -1200,6 +1227,8 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 	hdr = (struct ieee80211_hdr *)skb->data;
 	fc = le16_to_cpu(hdr->frame_control);
 
+	ath10k_check_wep(ar, skb, status);
+
 	/* FW delivers WEP Shared Auth frame with Protected Bit set and
 	 * encrypted payload. However in case of PMF it delivers decrypted
 	 * frames with Protected Bit set. */
-- 
2.1.3



From yanbol at qti.qualcomm.com  Thu Nov 20 08:22:45 2014
From: yanbol at qti.qualcomm.com (Yanbo Li)
Date: Fri, 21 Nov 2014 00:22:45 +0800
Subject: [PATCH] Add the target register read/write and memory dump debugfs
 interface
Message-ID: <1416500565-29875-1-git-send-email-yanbol@qti.qualcomm.com>

The debugfs interface reg_addr&reg_val used to read and write the target
register.
The interface mmem_val used to dump the targer memory and also can be
used to assign value to target memory

The basic usage explain as below:

Register read/write:
reg_addr       (the register address)                    (read&write)
reg_value      (the register value,  output is ASCII)    (read&write)

Read operation:
1. Write the reg address to reg_addr
   IE:  echo 0x100000 > reg_addr
2. Read the value from reg_value
   IE:  cat reg_value
Write operation:
1. Write the reg address to reg_addr IE:  echo 0x100000 > reg_addr
2. Write the value to the reg_value  IE:  echo  0x2400 > reg_value

Target memory dump:
mem_value (the target memory, access with the length and start address
							(read&write)
Read operation:

1: Read 4K(bs*count)) from address 0x400000(bs*skip)
dd if=mem_value bs=4 count=1024 skip=1048576 | xxd -g1

2: Read 0x50000(bs*count) from address 0x400000(bs*skip)
dd if=mem_value bs=4 count=81920 skip=1048576 | xxd -g1

Write operation:

1: Write the 0x01020304 to address 0x400400(bs*seek)
echo 0x01020304 | xxd -r | dd of=mem_value bs=4 seek=1048832

2: Read the memory and then write back after edit
dd if=mem_value bs=4 count=1024 skip=1048576 > tmp.bin
edit the tmp.bin
dd if=tmp.bin of=mem_value bs=4 count=4 seek=1048576

It suggests assign the 4 align number to bs, IE, 4, 8, 16 ....
Cause the target memory width is 32bit

Signed-off-by: Yanbo Li <yanbol at qti.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.h  |    2 +
 drivers/net/wireless/ath/ath10k/debug.c |  189 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/hif.h   |   37 ++++++
 drivers/net/wireless/ath/ath10k/pci.c   |    3 +
 4 files changed, 231 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 8f86bd3..5cb4fe9 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -321,6 +321,8 @@ struct ath10k_debug {
 	u32 fw_dbglog_mask;
 	u32 pktlog_filter;
 
+	u32 reg_addr;
+
 	u8 htt_max_amsdu;
 	u8 htt_max_ampdu;
 
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index a8f5a72..302ad55 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -22,6 +22,7 @@
 #include <linux/vmalloc.h>
 
 #include "core.h"
+#include "hif.h"
 #include "debug.h"
 #include "hif.h"
 
@@ -929,6 +930,185 @@ static const struct file_operations fops_fw_crash_dump = {
 	.llseek = default_llseek,
 };
 
+static ssize_t ath10k_reg_addr_read(struct file *file,
+				    char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 buf[32];
+	unsigned int len = 0;
+	u32 reg_addr;
+
+	spin_lock_bh(&ar->data_lock);
+	reg_addr = ar->debug.reg_addr;
+	spin_unlock_bh(&ar->data_lock);
+
+	len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", reg_addr);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath10k_reg_addr_write(struct file *file,
+				     const char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u32 reg_addr;
+	int ret;
+
+	ret = kstrtou32_from_user(user_buf, count, 0, &reg_addr);
+	if (ret)
+		return ret;
+
+	if (!IS_ALIGNED(reg_addr, 4))
+		return -EFAULT;
+
+	spin_lock_bh(&ar->data_lock);
+	ar->debug.reg_addr = reg_addr;
+	spin_unlock_bh(&ar->data_lock);
+
+	return count;
+}
+
+static const struct file_operations fops_reg_addr = {
+	.read = ath10k_reg_addr_read,
+	.write = ath10k_reg_addr_write,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t ath10k_reg_value_read(struct file *file,
+				     char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 buf[48];
+	unsigned int len;
+	u32 reg_addr, reg_val;
+
+	spin_lock_bh(&ar->data_lock);
+	reg_addr = ar->debug.reg_addr;
+	spin_unlock_bh(&ar->data_lock);
+
+	reg_val = ath10k_hif_read32(ar, reg_addr);
+	len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath10k_reg_value_write(struct file *file,
+				      const char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u32 reg_addr, reg_val;
+	int ret;
+
+	spin_lock_bh(&ar->data_lock);
+	reg_addr = ar->debug.reg_addr;
+	spin_unlock_bh(&ar->data_lock);
+
+	ret = kstrtou32_from_user(user_buf, count, 0, &reg_val);
+	if (ret)
+		return ret;
+
+	ath10k_hif_write32(ar, reg_addr, reg_val);
+
+	return count;
+}
+
+static const struct file_operations fops_reg_value = {
+	.read = ath10k_reg_value_read,
+	.write = ath10k_reg_value_write,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t ath10k_mem_value_read(struct file *file,
+				     char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 *buf;
+	int ret;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	if (!count)
+		return 0;
+
+	buf = vmalloc(count);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = ath10k_hif_diag_read(ar, *ppos, buf, count);
+	if (ret) {
+		ath10k_warn(ar, "failed to read address 0x%08x via diagnose window from debugfs: %d\n",
+			    (u32)(*ppos), ret);
+		goto read_err;
+	}
+
+	ret = copy_to_user(user_buf, buf, count);
+	if (ret == count)
+		return -EFAULT;
+
+	count -= ret;
+	*ppos += count;
+	ret = count;
+
+read_err:
+	vfree(buf);
+	return ret;
+}
+
+static ssize_t ath10k_mem_value_write(struct file *file,
+				      const char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 *buf;
+	int ret;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	if (!count)
+		return 0;
+
+	buf = vmalloc(count);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = copy_from_user(buf, user_buf, count);
+	if (ret)
+		goto err_free_copy;
+
+	ret = ath10k_hif_diag_write(ar, *ppos, buf, count);
+	if (ret) {
+		ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n",
+			    (u32)(*ppos), ret);
+		goto err_free_copy;
+	}
+
+	*ppos += count;
+	ret = count;
+
+err_free_copy:
+	vfree(buf);
+	return ret;
+}
+
+static const struct file_operations fops_mem_value = {
+	.read = ath10k_mem_value_read,
+	.write = ath10k_mem_value_write,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 static int ath10k_debug_htt_stats_req(struct ath10k *ar)
 {
 	u64 cookie;
@@ -1630,6 +1810,15 @@ int ath10k_debug_register(struct ath10k *ar)
 	debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy,
 			    ar, &fops_fw_crash_dump);
 
+	debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar, &fops_reg_addr);
+
+	debugfs_create_file("reg_value", S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar, &fops_reg_value);
+
+	debugfs_create_file("mem_value", S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar, &fops_mem_value);
+
 	debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
 			    ar, &fops_chip_id);
 
diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
index 30301f5..6ac5523 100644
--- a/drivers/net/wireless/ath/ath10k/hif.h
+++ b/drivers/net/wireless/ath/ath10k/hif.h
@@ -20,6 +20,7 @@
 
 #include <linux/kernel.h>
 #include "core.h"
+#include "debug.h"
 
 struct ath10k_hif_sg_item {
 	u16 transfer_id;
@@ -47,6 +48,8 @@ struct ath10k_hif_ops {
 	int (*diag_read)(struct ath10k *ar, u32 address, void *buf,
 			 size_t buf_len);
 
+	int (*diag_write)(struct ath10k *ar, u32 address, const void *data,
+			  int nbytes);
 	/*
 	 * API to handle HIF-specific BMI message exchanges, this API is
 	 * synchronous and only allowed to be called from a context that
@@ -84,6 +87,10 @@ struct ath10k_hif_ops {
 
 	u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id);
 
+	u32 (*read32)(struct ath10k *ar, u32 address);
+
+	void (*write32)(struct ath10k *ar, u32 address, u32 value);
+
 	/* Power up the device and enter BMI transfer mode for FW download */
 	int (*power_up)(struct ath10k *ar);
 
@@ -108,6 +115,15 @@ static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf
 	return ar->hif.ops->diag_read(ar, address, buf, buf_len);
 }
 
+static inline int ath10k_hif_diag_write(struct ath10k *ar, u32 address,
+					const void *data, int nbytes)
+{
+	if (!ar->hif.ops->diag_write)
+		return -EOPNOTSUPP;
+
+	return ar->hif.ops->diag_write(ar, address, data, nbytes);
+}
+
 static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar,
 					      void *request, u32 request_len,
 					      void *response, u32 *response_len)
@@ -187,4 +203,25 @@ static inline int ath10k_hif_resume(struct ath10k *ar)
 	return ar->hif.ops->resume(ar);
 }
 
+static inline u32 ath10k_hif_read32(struct ath10k *ar, u32 address)
+{
+	if (!ar->hif.ops->read32) {
+		ath10k_warn(ar, "hif read32 not supported\n");
+		return 0xdeaddead;
+	}
+
+	return ar->hif.ops->read32(ar, address);
+}
+
+static inline void ath10k_hif_write32(struct ath10k *ar,
+				      u32 address, u32 data)
+{
+	if (!ar->hif.ops->write32) {
+		ath10k_warn(ar, "hif write32 not supported\n");
+		return;
+	}
+
+	ar->hif.ops->write32(ar, address, data);
+}
+
 #endif /* _HIF_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 3a6b8a5..0816098 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1988,6 +1988,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
 static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
 	.tx_sg			= ath10k_pci_hif_tx_sg,
 	.diag_read		= ath10k_pci_hif_diag_read,
+	.diag_write		= ath10k_pci_diag_write_mem,
 	.exchange_bmi_msg	= ath10k_pci_hif_exchange_bmi_msg,
 	.start			= ath10k_pci_hif_start,
 	.stop			= ath10k_pci_hif_stop,
@@ -1998,6 +1999,8 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
 	.get_free_queue_number	= ath10k_pci_hif_get_free_queue_number,
 	.power_up		= ath10k_pci_hif_power_up,
 	.power_down		= ath10k_pci_hif_power_down,
+	.read32			= ath10k_pci_read32,
+	.write32		= ath10k_pci_write32,
 #ifdef CONFIG_PM
 	.suspend		= ath10k_pci_hif_suspend,
 	.resume			= ath10k_pci_hif_resume,
-- 
1.7.9.5



From linville at tuxdriver.com  Thu Nov 20 11:45:22 2014
From: linville at tuxdriver.com (John W. Linville)
Date: Thu, 20 Nov 2014 14:45:22 -0500
Subject: [PATCH] Add the target register read/write and memory dump
 debugfs interface
In-Reply-To: <1416500565-29875-1-git-send-email-yanbol@qti.qualcomm.com>
References: <1416500565-29875-1-git-send-email-yanbol@qti.qualcomm.com>
Message-ID: <20141120194521.GC31881@tuxdriver.com>

The subject should start like "ath10k: ..."

On Fri, Nov 21, 2014 at 12:22:45AM +0800, Yanbo Li wrote:
> The debugfs interface reg_addr&reg_val used to read and write the target
> register.
> The interface mmem_val used to dump the targer memory and also can be
> used to assign value to target memory
> 
> The basic usage explain as below:
> 
> Register read/write:
> reg_addr       (the register address)                    (read&write)
> reg_value      (the register value,  output is ASCII)    (read&write)
> 
> Read operation:
> 1. Write the reg address to reg_addr
>    IE:  echo 0x100000 > reg_addr
> 2. Read the value from reg_value
>    IE:  cat reg_value
> Write operation:
> 1. Write the reg address to reg_addr IE:  echo 0x100000 > reg_addr
> 2. Write the value to the reg_value  IE:  echo  0x2400 > reg_value
> 
> Target memory dump:
> mem_value (the target memory, access with the length and start address
> 							(read&write)
> Read operation:
> 
> 1: Read 4K(bs*count)) from address 0x400000(bs*skip)
> dd if=mem_value bs=4 count=1024 skip=1048576 | xxd -g1
> 
> 2: Read 0x50000(bs*count) from address 0x400000(bs*skip)
> dd if=mem_value bs=4 count=81920 skip=1048576 | xxd -g1
> 
> Write operation:
> 
> 1: Write the 0x01020304 to address 0x400400(bs*seek)
> echo 0x01020304 | xxd -r | dd of=mem_value bs=4 seek=1048832
> 
> 2: Read the memory and then write back after edit
> dd if=mem_value bs=4 count=1024 skip=1048576 > tmp.bin
> edit the tmp.bin
> dd if=tmp.bin of=mem_value bs=4 count=4 seek=1048576
> 
> It suggests assign the 4 align number to bs, IE, 4, 8, 16 ....
> Cause the target memory width is 32bit
> 
> Signed-off-by: Yanbo Li <yanbol at qti.qualcomm.com>
> ---
>  drivers/net/wireless/ath/ath10k/core.h  |    2 +
>  drivers/net/wireless/ath/ath10k/debug.c |  189 +++++++++++++++++++++++++++++++
>  drivers/net/wireless/ath/ath10k/hif.h   |   37 ++++++
>  drivers/net/wireless/ath/ath10k/pci.c   |    3 +
>  4 files changed, 231 insertions(+)
> 
> diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
> index 8f86bd3..5cb4fe9 100644
> --- a/drivers/net/wireless/ath/ath10k/core.h
> +++ b/drivers/net/wireless/ath/ath10k/core.h
> @@ -321,6 +321,8 @@ struct ath10k_debug {
>  	u32 fw_dbglog_mask;
>  	u32 pktlog_filter;
>  
> +	u32 reg_addr;
> +
>  	u8 htt_max_amsdu;
>  	u8 htt_max_ampdu;
>  
> diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
> index a8f5a72..302ad55 100644
> --- a/drivers/net/wireless/ath/ath10k/debug.c
> +++ b/drivers/net/wireless/ath/ath10k/debug.c
> @@ -22,6 +22,7 @@
>  #include <linux/vmalloc.h>
>  
>  #include "core.h"
> +#include "hif.h"
>  #include "debug.h"
>  #include "hif.h"
>  
> @@ -929,6 +930,185 @@ static const struct file_operations fops_fw_crash_dump = {
>  	.llseek = default_llseek,
>  };
>  
> +static ssize_t ath10k_reg_addr_read(struct file *file,
> +				    char __user *user_buf,
> +				    size_t count, loff_t *ppos)
> +{
> +	struct ath10k *ar = file->private_data;
> +	u8 buf[32];
> +	unsigned int len = 0;
> +	u32 reg_addr;
> +
> +	spin_lock_bh(&ar->data_lock);
> +	reg_addr = ar->debug.reg_addr;
> +	spin_unlock_bh(&ar->data_lock);
> +
> +	len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", reg_addr);
> +
> +	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
> +}
> +
> +static ssize_t ath10k_reg_addr_write(struct file *file,
> +				     const char __user *user_buf,
> +				     size_t count, loff_t *ppos)
> +{
> +	struct ath10k *ar = file->private_data;
> +	u32 reg_addr;
> +	int ret;
> +
> +	ret = kstrtou32_from_user(user_buf, count, 0, &reg_addr);
> +	if (ret)
> +		return ret;
> +
> +	if (!IS_ALIGNED(reg_addr, 4))
> +		return -EFAULT;
> +
> +	spin_lock_bh(&ar->data_lock);
> +	ar->debug.reg_addr = reg_addr;
> +	spin_unlock_bh(&ar->data_lock);
> +
> +	return count;
> +}
> +
> +static const struct file_operations fops_reg_addr = {
> +	.read = ath10k_reg_addr_read,
> +	.write = ath10k_reg_addr_write,
> +	.open = simple_open,
> +	.owner = THIS_MODULE,
> +	.llseek = default_llseek,
> +};
> +
> +static ssize_t ath10k_reg_value_read(struct file *file,
> +				     char __user *user_buf,
> +				     size_t count, loff_t *ppos)
> +{
> +	struct ath10k *ar = file->private_data;
> +	u8 buf[48];
> +	unsigned int len;
> +	u32 reg_addr, reg_val;
> +
> +	spin_lock_bh(&ar->data_lock);
> +	reg_addr = ar->debug.reg_addr;
> +	spin_unlock_bh(&ar->data_lock);
> +
> +	reg_val = ath10k_hif_read32(ar, reg_addr);
> +	len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val);
> +
> +	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
> +}
> +
> +static ssize_t ath10k_reg_value_write(struct file *file,
> +				      const char __user *user_buf,
> +				      size_t count, loff_t *ppos)
> +{
> +	struct ath10k *ar = file->private_data;
> +	u32 reg_addr, reg_val;
> +	int ret;
> +
> +	spin_lock_bh(&ar->data_lock);
> +	reg_addr = ar->debug.reg_addr;
> +	spin_unlock_bh(&ar->data_lock);
> +
> +	ret = kstrtou32_from_user(user_buf, count, 0, &reg_val);
> +	if (ret)
> +		return ret;
> +
> +	ath10k_hif_write32(ar, reg_addr, reg_val);
> +
> +	return count;
> +}
> +
> +static const struct file_operations fops_reg_value = {
> +	.read = ath10k_reg_value_read,
> +	.write = ath10k_reg_value_write,
> +	.open = simple_open,
> +	.owner = THIS_MODULE,
> +	.llseek = default_llseek,
> +};
> +
> +static ssize_t ath10k_mem_value_read(struct file *file,
> +				     char __user *user_buf,
> +				     size_t count, loff_t *ppos)
> +{
> +	struct ath10k *ar = file->private_data;
> +	u8 *buf;
> +	int ret;
> +
> +	if (*ppos < 0)
> +		return -EINVAL;
> +
> +	if (!count)
> +		return 0;
> +
> +	buf = vmalloc(count);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	ret = ath10k_hif_diag_read(ar, *ppos, buf, count);
> +	if (ret) {
> +		ath10k_warn(ar, "failed to read address 0x%08x via diagnose window from debugfs: %d\n",
> +			    (u32)(*ppos), ret);
> +		goto read_err;
> +	}
> +
> +	ret = copy_to_user(user_buf, buf, count);
> +	if (ret == count)
> +		return -EFAULT;
> +
> +	count -= ret;
> +	*ppos += count;
> +	ret = count;
> +
> +read_err:
> +	vfree(buf);
> +	return ret;
> +}
> +
> +static ssize_t ath10k_mem_value_write(struct file *file,
> +				      const char __user *user_buf,
> +				      size_t count, loff_t *ppos)
> +{
> +	struct ath10k *ar = file->private_data;
> +	u8 *buf;
> +	int ret;
> +
> +	if (*ppos < 0)
> +		return -EINVAL;
> +
> +	if (!count)
> +		return 0;
> +
> +	buf = vmalloc(count);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	ret = copy_from_user(buf, user_buf, count);
> +	if (ret)
> +		goto err_free_copy;
> +
> +	ret = ath10k_hif_diag_write(ar, *ppos, buf, count);
> +	if (ret) {
> +		ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n",
> +			    (u32)(*ppos), ret);
> +		goto err_free_copy;
> +	}
> +
> +	*ppos += count;
> +	ret = count;
> +
> +err_free_copy:
> +	vfree(buf);
> +	return ret;
> +}
> +
> +static const struct file_operations fops_mem_value = {
> +	.read = ath10k_mem_value_read,
> +	.write = ath10k_mem_value_write,
> +	.open = simple_open,
> +	.owner = THIS_MODULE,
> +	.llseek = default_llseek,
> +};
> +
>  static int ath10k_debug_htt_stats_req(struct ath10k *ar)
>  {
>  	u64 cookie;
> @@ -1630,6 +1810,15 @@ int ath10k_debug_register(struct ath10k *ar)
>  	debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy,
>  			    ar, &fops_fw_crash_dump);
>  
> +	debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR,
> +			    ar->debug.debugfs_phy, ar, &fops_reg_addr);
> +
> +	debugfs_create_file("reg_value", S_IRUSR | S_IWUSR,
> +			    ar->debug.debugfs_phy, ar, &fops_reg_value);
> +
> +	debugfs_create_file("mem_value", S_IRUSR | S_IWUSR,
> +			    ar->debug.debugfs_phy, ar, &fops_mem_value);
> +
>  	debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
>  			    ar, &fops_chip_id);
>  
> diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
> index 30301f5..6ac5523 100644
> --- a/drivers/net/wireless/ath/ath10k/hif.h
> +++ b/drivers/net/wireless/ath/ath10k/hif.h
> @@ -20,6 +20,7 @@
>  
>  #include <linux/kernel.h>
>  #include "core.h"
> +#include "debug.h"
>  
>  struct ath10k_hif_sg_item {
>  	u16 transfer_id;
> @@ -47,6 +48,8 @@ struct ath10k_hif_ops {
>  	int (*diag_read)(struct ath10k *ar, u32 address, void *buf,
>  			 size_t buf_len);
>  
> +	int (*diag_write)(struct ath10k *ar, u32 address, const void *data,
> +			  int nbytes);
>  	/*
>  	 * API to handle HIF-specific BMI message exchanges, this API is
>  	 * synchronous and only allowed to be called from a context that
> @@ -84,6 +87,10 @@ struct ath10k_hif_ops {
>  
>  	u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id);
>  
> +	u32 (*read32)(struct ath10k *ar, u32 address);
> +
> +	void (*write32)(struct ath10k *ar, u32 address, u32 value);
> +
>  	/* Power up the device and enter BMI transfer mode for FW download */
>  	int (*power_up)(struct ath10k *ar);
>  
> @@ -108,6 +115,15 @@ static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf
>  	return ar->hif.ops->diag_read(ar, address, buf, buf_len);
>  }
>  
> +static inline int ath10k_hif_diag_write(struct ath10k *ar, u32 address,
> +					const void *data, int nbytes)
> +{
> +	if (!ar->hif.ops->diag_write)
> +		return -EOPNOTSUPP;
> +
> +	return ar->hif.ops->diag_write(ar, address, data, nbytes);
> +}
> +
>  static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar,
>  					      void *request, u32 request_len,
>  					      void *response, u32 *response_len)
> @@ -187,4 +203,25 @@ static inline int ath10k_hif_resume(struct ath10k *ar)
>  	return ar->hif.ops->resume(ar);
>  }
>  
> +static inline u32 ath10k_hif_read32(struct ath10k *ar, u32 address)
> +{
> +	if (!ar->hif.ops->read32) {
> +		ath10k_warn(ar, "hif read32 not supported\n");
> +		return 0xdeaddead;
> +	}
> +
> +	return ar->hif.ops->read32(ar, address);
> +}
> +
> +static inline void ath10k_hif_write32(struct ath10k *ar,
> +				      u32 address, u32 data)
> +{
> +	if (!ar->hif.ops->write32) {
> +		ath10k_warn(ar, "hif write32 not supported\n");
> +		return;
> +	}
> +
> +	ar->hif.ops->write32(ar, address, data);
> +}
> +
>  #endif /* _HIF_H_ */
> diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
> index 3a6b8a5..0816098 100644
> --- a/drivers/net/wireless/ath/ath10k/pci.c
> +++ b/drivers/net/wireless/ath/ath10k/pci.c
> @@ -1988,6 +1988,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
>  static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
>  	.tx_sg			= ath10k_pci_hif_tx_sg,
>  	.diag_read		= ath10k_pci_hif_diag_read,
> +	.diag_write		= ath10k_pci_diag_write_mem,
>  	.exchange_bmi_msg	= ath10k_pci_hif_exchange_bmi_msg,
>  	.start			= ath10k_pci_hif_start,
>  	.stop			= ath10k_pci_hif_stop,
> @@ -1998,6 +1999,8 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
>  	.get_free_queue_number	= ath10k_pci_hif_get_free_queue_number,
>  	.power_up		= ath10k_pci_hif_power_up,
>  	.power_down		= ath10k_pci_hif_power_down,
> +	.read32			= ath10k_pci_read32,
> +	.write32		= ath10k_pci_write32,
>  #ifdef CONFIG_PM
>  	.suspend		= ath10k_pci_hif_suspend,
>  	.resume			= ath10k_pci_hif_resume,
> -- 
> 1.7.9.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

-- 
John W. Linville		Someday the world will need a hero, and you
linville at tuxdriver.com			might be all we have.  Be ready.


From yanbol at qti.qualcomm.com  Thu Nov 20 18:39:42 2014
From: yanbol at qti.qualcomm.com (Li, Yanbo)
Date: Fri, 21 Nov 2014 02:39:42 +0000
Subject: [PATCH] Add the target register read/write and memory dump
 debugfs interface
In-Reply-To: <20141120194521.GC31881@tuxdriver.com>
References: <1416500565-29875-1-git-send-email-yanbol@qti.qualcomm.com>
 <20141120194521.GC31881@tuxdriver.com>
Message-ID: <5b9b8ec5e5234a81be5fffcaab520d4e@nasanexm02e.na.qualcomm.com>

> -----Original Message-----
> From: John W. Linville [mailto:linville at tuxdriver.com]
> Sent: Friday, November 21, 2014 3:45 AM
> To: Li, Yanbo
> Cc: Valo, Kalle; dreamfly281 at gmail.com; michal.kazior at tieto.com;
> ath10k at lists.infradead.org; linux-wireless at vger.kernel.org
> Subject: Re: [PATCH] Add the target register read/write and memory dump
> debugfs interface
> 
> The subject should start like "ath10k: ..."
> 
Resend with the prefix, please review base on the new thread.

Thanks 
BR /Yanbo


From michal.kazior at tieto.com  Fri Nov 21 01:03:30 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 21 Nov 2014 10:03:30 +0100
Subject: [RFC] ath10k: Fix shared WEP
In-Reply-To: <1416492382-18058-1-git-send-email-sujith@msujith.org>
References: <1416492382-18058-1-git-send-email-sujith@msujith.org>
Message-ID: <CA+BoTQnyf0tvg8ngLqsoux-A9-3J46cDuJdd-V=kS24wWS4Y1A@mail.gmail.com>

On 20 November 2014 15:06, Sujith Manoharan <sujith at msujith.org> wrote:
> From: Sujith Manoharan <c_manoha at qca.qualcomm.com>
>
> When static keys are used in shared WEP, when a
> station is associated, message 3 is sent with an
> encrypted payload. But, for subsequent
> authentications that are triggered without a
> deauth, the auth frame is decrypted by the HW. To
> handle this, check if the WEP keys have already
> been set for the peer and if so, mark the
> frame as decrypted.

IOW This fixes a corner case when station reconnects but ath10k AP for
some reason didn't notice it (e.g. station went out of range and came
back before AP inactivity timer kicked in), right? Or is there another
scenario? It might be a good idea to include this in the commit log.


[...]
> diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
> index 1245ac8..e8fee46 100644
> --- a/drivers/net/wireless/ath/ath10k/mac.c
> +++ b/drivers/net/wireless/ath/ath10k/mac.c
> @@ -179,6 +179,31 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
>         return first_errno;
>  }
>
> +bool ath10k_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
> +                               u8 keyidx)

Functions in mac.c should have ath10k_mac_ prefix. I'm aware not all
function follow this rule (albeit they should).


> +{
> +       struct ath10k_peer *peer;
> +       int i;
> +
> +       /*
> +        * We don't know which vdev this peer belongs to,
> +        * since WMI doesn't give us that information.
> +        */
> +       spin_lock_bh(&ar->data_lock);
> +       peer = ath10k_peer_find(ar, 0, addr);
> +       spin_unlock_bh(&ar->data_lock);

I don't think the above will work for mBSS, e.g. consider vdev_id=0
being an open network and vdev_id=1 being wep-shared. Maybe it's about
time to introduce ath10k_peer_find_by_addr(struct ath10k *ar, const u8
*)?


> +
> +       if (!peer)
> +               return false;
> +
> +       for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
> +               if (peer->keys[i] && peer->keys[i]->keyidx == keyidx)
> +                       return true;
> +       }

Read access to peer->keys should be protected by either data_lock or
conf_mutex. Obviously the latter can't be used because this function
will be called from an atomic context leaving the data_lock. The
entire is_peer_wep_key_set() should require data_lock to be held while
it is called to avoid races.

Oh, and apparently this is buggy anyway because
ath10k_install_peer_wep_keys() is oblivious to this. Oops..


[...]
> diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
> index c2bc828..8f1186e 100644
> --- a/drivers/net/wireless/ath/ath10k/wmi.c
> +++ b/drivers/net/wireless/ath/ath10k/wmi.c
> @@ -1113,6 +1113,33 @@ static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band)
>         return rate_idx;
>  }
>
> +static void ath10k_check_wep(struct ath10k *ar, struct sk_buff *skb,
> +                            struct ieee80211_rx_status *status)

Function in wmi.c should have ath10k_wmi_ prefix. I also don't like
the name as it doesn't convey what it does in the slightest. Perhaps
ath10k_wmi_mgmt_rx_h_wep_reauth() or ath10k_wmi_handle_wep_reauth()
would be a bit better?


> +{
> +       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
> +       unsigned int hdrlen;
> +       bool peer_key;
> +       u8 *addr, keyidx;
> +
> +       if (ieee80211_is_auth(hdr->frame_control) &&
> +           ieee80211_has_protected(hdr->frame_control)) {

My preference is to use guards in functions like these, i.e.
  if (!auth || !protected) return;
and then continue with the code without extra indentation.


> +               hdrlen = ieee80211_hdrlen(hdr->frame_control);
> +               if (skb->len < (hdrlen + 4))

It's probably a good idea to use IEEE80211_WEP_IV_LEN instead of literal 4.


> +                       return;
> +
> +               keyidx = skb->data[hdrlen + 3] >> 6;
> +               addr = ieee80211_get_SA(hdr);
> +               peer_key = ath10k_is_peer_wep_key_set(ar, addr, keyidx);
> +
> +               if (peer_key) {

Again, I'd do a guard: `if (!peer_key) return`. But I'm just picky :-P
I leave the final decision up to you or Kalle.


[...]
> @@ -1200,6 +1227,8 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
>         hdr = (struct ieee80211_hdr *)skb->data;
>         fc = le16_to_cpu(hdr->frame_control);
>
> +       ath10k_check_wep(ar, skb, status);
> +
>         /* FW delivers WEP Shared Auth frame with Protected Bit set and
>          * encrypted payload. However in case of PMF it delivers decrypted
>          * frames with Protected Bit set. */

This is getting a little messy. Did you consider to somehow unify the
previous wep shared & pmf code with your new fix?


Micha?


From sujith at msujith.org  Fri Nov 21 01:54:19 2014
From: sujith at msujith.org (Sujith Manoharan)
Date: Fri, 21 Nov 2014 15:24:19 +0530
Subject: [RFC] ath10k: Fix shared WEP
In-Reply-To: <CA+BoTQnyf0tvg8ngLqsoux-A9-3J46cDuJdd-V=kS24wWS4Y1A@mail.gmail.com>
References: <1416492382-18058-1-git-send-email-sujith@msujith.org>
 <CA+BoTQnyf0tvg8ngLqsoux-A9-3J46cDuJdd-V=kS24wWS4Y1A@mail.gmail.com>
Message-ID: <21615.3019.437408.992893@gargle.gargle.HOWL>

Michal Kazior wrote:
> IOW This fixes a corner case when station reconnects but ath10k AP for
> some reason didn't notice it (e.g. station went out of range and came
> back before AP inactivity timer kicked in), right? Or is there another
> scenario? It might be a good idea to include this in the commit log.

The corner case is when a station changes its default key and tries
to reassociate, but does not send a deauth first.

> I don't think the above will work for mBSS, e.g. consider vdev_id=0
> being an open network and vdev_id=1 being wep-shared. Maybe it's about
> time to introduce ath10k_peer_find_by_addr(struct ath10k *ar, const u8
> *)?

Yep, I was aware of this. I think we can do this for a single BSS
now and have a FIXME to address multiple BSS later. This issue
is rarely seen in practice.

> Read access to peer->keys should be protected by either data_lock or
> conf_mutex. Obviously the latter can't be used because this function
> will be called from an atomic context leaving the data_lock. The
> entire is_peer_wep_key_set() should require data_lock to be held while
> it is called to avoid races.
> 
> Oh, and apparently this is buggy anyway because
> ath10k_install_peer_wep_keys() is oblivious to this. Oops..

I don't think it can happen, though ? ath10k_install_peer_wep_keys()
would be called only when a station transitions to ASSOC and message 3
can't be received when that happens ?

(But, I did see a lockdep splat when using WEP).

> This is getting a little messy. Did you consider to somehow unify the
> previous wep shared & pmf code with your new fix?

For shared wep, the FW delivers the first auth frame as encrypted and
subsequent auth frames as decrypted, so we need to differentiate them somehow...

I'll address the other stylistic comments and send a v2.

Sujith


From michal.kazior at tieto.com  Fri Nov 21 02:14:03 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 21 Nov 2014 11:14:03 +0100
Subject: [RFC] ath10k: Fix shared WEP
In-Reply-To: <21615.3019.437408.992893@gargle.gargle.HOWL>
References: <1416492382-18058-1-git-send-email-sujith@msujith.org>
 <CA+BoTQnyf0tvg8ngLqsoux-A9-3J46cDuJdd-V=kS24wWS4Y1A@mail.gmail.com>
 <21615.3019.437408.992893@gargle.gargle.HOWL>
Message-ID: <CA+BoTQm_X3-kpJanZu=dJ3LDPqjAfnUoyBwqzgYGX3bK+H1f2g@mail.gmail.com>

On 21 November 2014 10:54, Sujith Manoharan <sujith at msujith.org> wrote:
> Michal Kazior wrote:
[...]
>> Read access to peer->keys should be protected by either data_lock or
>> conf_mutex. Obviously the latter can't be used because this function
>> will be called from an atomic context leaving the data_lock. The
>> entire is_peer_wep_key_set() should require data_lock to be held while
>> it is called to avoid races.
>>
>> Oh, and apparently this is buggy anyway because
>> ath10k_install_peer_wep_keys() is oblivious to this. Oops..
>
> I don't think it can happen, though ? ath10k_install_peer_wep_keys()
> would be called only when a station transitions to ASSOC and message 3
> can't be received when that happens ?

Good point, but what I'm worried it'll be easier to miss this subtlety
and introduce races in the future.


> (But, I did see a lockdep splat when using WEP).

Do you have it saved somewhere? If so, can you post it, please?


Micha?


From sujith at msujith.org  Fri Nov 21 02:36:21 2014
From: sujith at msujith.org (Sujith Manoharan)
Date: Fri, 21 Nov 2014 16:06:21 +0530
Subject: [RFC] ath10k: Fix shared WEP
In-Reply-To: <CA+BoTQm_X3-kpJanZu=dJ3LDPqjAfnUoyBwqzgYGX3bK+H1f2g@mail.gmail.com>
References: <1416492382-18058-1-git-send-email-sujith@msujith.org>
 <CA+BoTQnyf0tvg8ngLqsoux-A9-3J46cDuJdd-V=kS24wWS4Y1A@mail.gmail.com>
 <21615.3019.437408.992893@gargle.gargle.HOWL>
 <CA+BoTQm_X3-kpJanZu=dJ3LDPqjAfnUoyBwqzgYGX3bK+H1f2g@mail.gmail.com>
Message-ID: <21615.5541.120044.376524@gargle.gargle.HOWL>

Michal Kazior wrote:
> Good point, but what I'm worried it'll be easier to miss this subtlety
> and introduce races in the future.

I am not very familiar with ath10k locking, but peer_keys is
also used in ath10k_clear_peer_keys(), where it relies on conf_mutex.
Should that be addressed too ?

> Do you have it saved somewhere? If so, can you post it, please?

http://pastebin.com/yywiPZXL

Sujith


From michal.kazior at tieto.com  Fri Nov 21 02:40:27 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 21 Nov 2014 11:40:27 +0100
Subject: [RFC] ath10k: Fix shared WEP
In-Reply-To: <21615.5541.120044.376524@gargle.gargle.HOWL>
References: <1416492382-18058-1-git-send-email-sujith@msujith.org>
 <CA+BoTQnyf0tvg8ngLqsoux-A9-3J46cDuJdd-V=kS24wWS4Y1A@mail.gmail.com>
 <21615.3019.437408.992893@gargle.gargle.HOWL>
 <CA+BoTQm_X3-kpJanZu=dJ3LDPqjAfnUoyBwqzgYGX3bK+H1f2g@mail.gmail.com>
 <21615.5541.120044.376524@gargle.gargle.HOWL>
Message-ID: <CA+BoTQk2fy024b5E=khSrzpUGzCL=jU_4wpxJ0AAyxmsFZuWhA@mail.gmail.com>

On 21 November 2014 11:36, Sujith Manoharan <sujith at msujith.org> wrote:
> Michal Kazior wrote:
>> Good point, but what I'm worried it'll be easier to miss this subtlety
>> and introduce races in the future.
>
> I am not very familiar with ath10k locking, but peer_keys is
> also used in ath10k_clear_peer_keys(), where it relies on conf_mutex.
> Should that be addressed too ?

Yes. Basically peer->keys[] should be protected by both conf_mutex and
data_lock if you want to modify it. If you want to read it you need
either one.


>> Do you have it saved somewhere? If so, can you post it, please?
>
> http://pastebin.com/yywiPZXL

Thanks! Looks like the `cancel_work_sync(&arvif->wep_key_work);`
should go _before_ `mutex_lock(&ar->conf_mutex);`.

I'm busy with some stuff so feel free to send a patch :-)


Micha?


From sujith at msujith.org  Fri Nov 21 02:57:30 2014
From: sujith at msujith.org (Sujith Manoharan)
Date: Fri, 21 Nov 2014 16:27:30 +0530
Subject: [RFC] ath10k: Fix shared WEP
In-Reply-To: <CA+BoTQk2fy024b5E=khSrzpUGzCL=jU_4wpxJ0AAyxmsFZuWhA@mail.gmail.com>
References: <1416492382-18058-1-git-send-email-sujith@msujith.org>
 <CA+BoTQnyf0tvg8ngLqsoux-A9-3J46cDuJdd-V=kS24wWS4Y1A@mail.gmail.com>
 <21615.3019.437408.992893@gargle.gargle.HOWL>
 <CA+BoTQm_X3-kpJanZu=dJ3LDPqjAfnUoyBwqzgYGX3bK+H1f2g@mail.gmail.com>
 <21615.5541.120044.376524@gargle.gargle.HOWL>
 <CA+BoTQk2fy024b5E=khSrzpUGzCL=jU_4wpxJ0AAyxmsFZuWhA@mail.gmail.com>
Message-ID: <21615.6810.716982.963365@gargle.gargle.HOWL>

Michal Kazior wrote:
> Yes. Basically peer->keys[] should be protected by both conf_mutex and
> data_lock if you want to modify it. If you want to read it you need
> either one.

Ok.

> Thanks! Looks like the `cancel_work_sync(&arvif->wep_key_work);`
> should go _before_ `mutex_lock(&ar->conf_mutex);`.
> 
> I'm busy with some stuff so feel free to send a patch :-)

I'll send a fix after this one. Thanks for the review !

Sujith


From kvalo at qca.qualcomm.com  Fri Nov 21 09:01:13 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 21 Nov 2014 19:01:13 +0200
Subject: [PATCH] Add the target register read/write and memory dump
 debugfs interface
In-Reply-To: <5b9b8ec5e5234a81be5fffcaab520d4e@nasanexm02e.na.qualcomm.com>
 (Yanbo Li's message of "Fri, 21 Nov 2014 02:39:42 +0000")
References: <1416500565-29875-1-git-send-email-yanbol@qti.qualcomm.com>
 <20141120194521.GC31881@tuxdriver.com>
 <5b9b8ec5e5234a81be5fffcaab520d4e@nasanexm02e.na.qualcomm.com>
Message-ID: <87sihcbi92.fsf@kamboji.qca.qualcomm.com>

"Li, Yanbo" <yanbol at qti.qualcomm.com> writes:

>> -----Original Message-----
>> From: John W. Linville [mailto:linville at tuxdriver.com]
>> Sent: Friday, November 21, 2014 3:45 AM
>> To: Li, Yanbo
>> Cc: Valo, Kalle; dreamfly281 at gmail.com; michal.kazior at tieto.com;
>> ath10k at lists.infradead.org; linux-wireless at vger.kernel.org
>> Subject: Re: [PATCH] Add the target register read/write and memory dump
>> debugfs interface
>> 
>> The subject should start like "ath10k: ..."
>> 
> Resend with the prefix, please review base on the new thread.

Where did you send it? I can't find it.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Fri Nov 21 09:01:51 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 21 Nov 2014 19:01:51 +0200
Subject: [PATCH 0/7] ath10k: rework rx path
In-Reply-To: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Tue, 4 Nov 2014 15:22:04 +0100")
References: <1415110931-10945-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87oas0bi80.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> This patchset unifies rx path. Instead of
> branching for A-MSDU and MSDU cases a single
> codepath is introduced.
>
> This yields:
>
>    text    data     bss     dec     hex filename
>   14068       0       0   14068    36f4 before/htt_rx.o
>   13308       3       0   13311    33ff after/htt_rx.o
>
> I haven't measured any Rx performance loss in my
> setup but I may be biased. In theory this could
> reduce i-cache pressure and improve Rx throughput
> on CPU contrained systems by a few mbps.
>
> This patchset serves two purposes though:
>  - clean up and unify the Rx path a bit
>  - make it possible to reuse code more easily in
>    the future
>
>
> Michal Kazior (7):
>   ath10k: start using sk_buff_head
>   ath10k: simplify Rx loop
>   ath10k: refactor htt->rx_confused
>   ath10k: unify rx undecapping
>   ath10k: remove unused function argument
>   ath10k: use rx descriptor for ppdu status extraction
>   ath10k: report rx rate and signal for fragmented Rx

Thanks, all seven applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Fri Nov 21 09:05:41 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 21 Nov 2014 19:05:41 +0200
Subject: [RFC] ath10k: Fix shared WEP
In-Reply-To: <1416492382-18058-1-git-send-email-sujith@msujith.org> (Sujith
 Manoharan's message of "Thu, 20 Nov 2014 19:36:22 +0530")
References: <1416492382-18058-1-git-send-email-sujith@msujith.org>
Message-ID: <87k32obi1m.fsf@kamboji.qca.qualcomm.com>

Sujith Manoharan <sujith at msujith.org> writes:

> From: Sujith Manoharan <c_manoha at qca.qualcomm.com>
>
> When static keys are used in shared WEP, when a
> station is associated, message 3 is sent with an
> encrypted payload. But, for subsequent
> authentications that are triggered without a
> deauth, the auth frame is decrypted by the HW. To
> handle this, check if the WEP keys have already
> been set for the peer and if so, mark the
> frame as decrypted.
>
> Signed-off-by: Sujith Manoharan <c_manoha at qca.qualcomm.com>

[...]

> +		if (peer_key) {
> +			ath10k_dbg(ar, ATH10K_DBG_MAC,
> +				   "wep key present for peer: %pM\n", addr);
> +			status->flag |= RX_FLAG_DECRYPTED;
> +		}
> +	}
> +
> +}

A checkpatch warning:

drivers/net/wireless/ath/ath10k/wmi.c:1141: CHECK: Blank lines aren't necessary before a close brace '}'

-- 
Kalle Valo


From wifi at mindchasers.com  Fri Nov 21 10:11:31 2014
From: wifi at mindchasers.com (Robert E. Cochran)
Date: Fri, 21 Nov 2014 13:11:31 -0500
Subject: seeking further info on firmware-3
Message-ID: <546F8053.3010003@mindchasers.com>

Hi,

I'm testing Linux 3.18-rc5 with a QCA9880 / Compex WLE900VX.

During boot, I'm seeing complaints about not finding firmware-3.bin:

ath10k_pci 0001:03:00.0: Direct firmware load for 
ath10k/QCA988X/hw2.0/firmware-3.bin failed with error -2
ath10k_pci 0001:03:00.0: could not fetch firmware file 
'ath10k/QCA988X/hw2.0/firmware-3.bin': -2


Can someone please confirm that we should be using 
firmware-3.bin_10.2-00082-4-2 from the 10.2 folder on 
https://github.com/kvalo/ath10k-firmware.git
?  When we use this firmware, we see the following during boot:

ath10k_pci 0001:03:00.0: qca988x hw2.0 (0x4100016c, 0x043202ff) fw 
10.2-00082-4-2 api 3 htt 2.1
ath10k_pci 0001:03:00.0: debug 1 debugfs 1 tracing 0 dfs 0 testmode 1



If this isn't the latest & greatest firmware, then where do I find 
firmware-3.bin?


And If I should be using firmware-3.bin_10.2-00082-4-2, then are there 
some release notes available for this?


Finally, please let me know if it's a mistake to be working with 
firmware-3 on the 3.18 kernel.   We're performing some early integration 
testing with this WiFi module, and it's more important to get things 
working as an AP with hostapd than getting the latest cutting edge 
features working.



Thanks,

Bob




From yanbol at qti.qualcomm.com  Sat Nov 22 03:48:42 2014
From: yanbol at qti.qualcomm.com (Yanbo Li)
Date: Sat, 22 Nov 2014 19:48:42 +0800
Subject: [PATCH] ath10k: Add the target register access and memory dump
 debugfs interface
Message-ID: <1416656922-6645-1-git-send-email-yanbol@qti.qualcomm.com>

The debugfs interface reg_addr&reg_val used to read and write the target
register.
The interface mmem_val used to dump the targer memory and also can be
used to assign value to target memory

The basic usage explain as below:

Register read/write:
reg_addr       (the register address)                    (read&write)
reg_value      (the register value,  output is ASCII)    (read&write)

Read operation:
1. Write the reg address to reg_addr
   IE:  echo 0x100000 > reg_addr
2. Read the value from reg_value
   IE:  cat reg_value
Write operation:
1. Write the reg address to reg_addr IE:  echo 0x100000 > reg_addr
2. Write the value to the reg_value  IE:  echo  0x2400 > reg_value

Target memory dump:
mem_value (the target memory, access with the length and start address
							(read&write)
Read operation:

1: Read 4K(bs*count)) from address 0x400000(bs*skip)
dd if=mem_value bs=4 count=1024 skip=1048576 | xxd -g1

2: Read 0x50000(bs*count) from address 0x400000(bs*skip)
dd if=mem_value bs=4 count=81920 skip=1048576 | xxd -g1

Write operation:

1: Write the 0x01020304 to address 0x400400(bs*seek)
echo 0x01020304 | xxd -r | dd of=mem_value bs=4 seek=1048832

2: Read the memory and then write back after edit
dd if=mem_value bs=4 count=1024 skip=1048576 > tmp.bin
edit the tmp.bin
dd if=tmp.bin of=mem_value bs=4 count=4 seek=1048576

It suggests assign the 4 align number to bs, IE, 4, 8, 16 ....
Cause the target memory width is 32bit

Signed-off-by: Yanbo Li <yanbol at qti.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.h  |    2 +
 drivers/net/wireless/ath/ath10k/debug.c |  189 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/hif.h   |   37 ++++++
 drivers/net/wireless/ath/ath10k/pci.c   |    3 +
 4 files changed, 231 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 8f86bd3..5cb4fe9 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -321,6 +321,8 @@ struct ath10k_debug {
 	u32 fw_dbglog_mask;
 	u32 pktlog_filter;
 
+	u32 reg_addr;
+
 	u8 htt_max_amsdu;
 	u8 htt_max_ampdu;
 
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index a8f5a72..302ad55 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -22,6 +22,7 @@
 #include <linux/vmalloc.h>
 
 #include "core.h"
+#include "hif.h"
 #include "debug.h"
 #include "hif.h"
 
@@ -929,6 +930,185 @@ static const struct file_operations fops_fw_crash_dump = {
 	.llseek = default_llseek,
 };
 
+static ssize_t ath10k_reg_addr_read(struct file *file,
+				    char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 buf[32];
+	unsigned int len = 0;
+	u32 reg_addr;
+
+	spin_lock_bh(&ar->data_lock);
+	reg_addr = ar->debug.reg_addr;
+	spin_unlock_bh(&ar->data_lock);
+
+	len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", reg_addr);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath10k_reg_addr_write(struct file *file,
+				     const char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u32 reg_addr;
+	int ret;
+
+	ret = kstrtou32_from_user(user_buf, count, 0, &reg_addr);
+	if (ret)
+		return ret;
+
+	if (!IS_ALIGNED(reg_addr, 4))
+		return -EFAULT;
+
+	spin_lock_bh(&ar->data_lock);
+	ar->debug.reg_addr = reg_addr;
+	spin_unlock_bh(&ar->data_lock);
+
+	return count;
+}
+
+static const struct file_operations fops_reg_addr = {
+	.read = ath10k_reg_addr_read,
+	.write = ath10k_reg_addr_write,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t ath10k_reg_value_read(struct file *file,
+				     char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 buf[48];
+	unsigned int len;
+	u32 reg_addr, reg_val;
+
+	spin_lock_bh(&ar->data_lock);
+	reg_addr = ar->debug.reg_addr;
+	spin_unlock_bh(&ar->data_lock);
+
+	reg_val = ath10k_hif_read32(ar, reg_addr);
+	len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath10k_reg_value_write(struct file *file,
+				      const char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u32 reg_addr, reg_val;
+	int ret;
+
+	spin_lock_bh(&ar->data_lock);
+	reg_addr = ar->debug.reg_addr;
+	spin_unlock_bh(&ar->data_lock);
+
+	ret = kstrtou32_from_user(user_buf, count, 0, &reg_val);
+	if (ret)
+		return ret;
+
+	ath10k_hif_write32(ar, reg_addr, reg_val);
+
+	return count;
+}
+
+static const struct file_operations fops_reg_value = {
+	.read = ath10k_reg_value_read,
+	.write = ath10k_reg_value_write,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t ath10k_mem_value_read(struct file *file,
+				     char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 *buf;
+	int ret;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	if (!count)
+		return 0;
+
+	buf = vmalloc(count);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = ath10k_hif_diag_read(ar, *ppos, buf, count);
+	if (ret) {
+		ath10k_warn(ar, "failed to read address 0x%08x via diagnose window from debugfs: %d\n",
+			    (u32)(*ppos), ret);
+		goto read_err;
+	}
+
+	ret = copy_to_user(user_buf, buf, count);
+	if (ret == count)
+		return -EFAULT;
+
+	count -= ret;
+	*ppos += count;
+	ret = count;
+
+read_err:
+	vfree(buf);
+	return ret;
+}
+
+static ssize_t ath10k_mem_value_write(struct file *file,
+				      const char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 *buf;
+	int ret;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	if (!count)
+		return 0;
+
+	buf = vmalloc(count);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = copy_from_user(buf, user_buf, count);
+	if (ret)
+		goto err_free_copy;
+
+	ret = ath10k_hif_diag_write(ar, *ppos, buf, count);
+	if (ret) {
+		ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n",
+			    (u32)(*ppos), ret);
+		goto err_free_copy;
+	}
+
+	*ppos += count;
+	ret = count;
+
+err_free_copy:
+	vfree(buf);
+	return ret;
+}
+
+static const struct file_operations fops_mem_value = {
+	.read = ath10k_mem_value_read,
+	.write = ath10k_mem_value_write,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 static int ath10k_debug_htt_stats_req(struct ath10k *ar)
 {
 	u64 cookie;
@@ -1630,6 +1810,15 @@ int ath10k_debug_register(struct ath10k *ar)
 	debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy,
 			    ar, &fops_fw_crash_dump);
 
+	debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar, &fops_reg_addr);
+
+	debugfs_create_file("reg_value", S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar, &fops_reg_value);
+
+	debugfs_create_file("mem_value", S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar, &fops_mem_value);
+
 	debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
 			    ar, &fops_chip_id);
 
diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
index 30301f5..6ac5523 100644
--- a/drivers/net/wireless/ath/ath10k/hif.h
+++ b/drivers/net/wireless/ath/ath10k/hif.h
@@ -20,6 +20,7 @@
 
 #include <linux/kernel.h>
 #include "core.h"
+#include "debug.h"
 
 struct ath10k_hif_sg_item {
 	u16 transfer_id;
@@ -47,6 +48,8 @@ struct ath10k_hif_ops {
 	int (*diag_read)(struct ath10k *ar, u32 address, void *buf,
 			 size_t buf_len);
 
+	int (*diag_write)(struct ath10k *ar, u32 address, const void *data,
+			  int nbytes);
 	/*
 	 * API to handle HIF-specific BMI message exchanges, this API is
 	 * synchronous and only allowed to be called from a context that
@@ -84,6 +87,10 @@ struct ath10k_hif_ops {
 
 	u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id);
 
+	u32 (*read32)(struct ath10k *ar, u32 address);
+
+	void (*write32)(struct ath10k *ar, u32 address, u32 value);
+
 	/* Power up the device and enter BMI transfer mode for FW download */
 	int (*power_up)(struct ath10k *ar);
 
@@ -108,6 +115,15 @@ static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf
 	return ar->hif.ops->diag_read(ar, address, buf, buf_len);
 }
 
+static inline int ath10k_hif_diag_write(struct ath10k *ar, u32 address,
+					const void *data, int nbytes)
+{
+	if (!ar->hif.ops->diag_write)
+		return -EOPNOTSUPP;
+
+	return ar->hif.ops->diag_write(ar, address, data, nbytes);
+}
+
 static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar,
 					      void *request, u32 request_len,
 					      void *response, u32 *response_len)
@@ -187,4 +203,25 @@ static inline int ath10k_hif_resume(struct ath10k *ar)
 	return ar->hif.ops->resume(ar);
 }
 
+static inline u32 ath10k_hif_read32(struct ath10k *ar, u32 address)
+{
+	if (!ar->hif.ops->read32) {
+		ath10k_warn(ar, "hif read32 not supported\n");
+		return 0xdeaddead;
+	}
+
+	return ar->hif.ops->read32(ar, address);
+}
+
+static inline void ath10k_hif_write32(struct ath10k *ar,
+				      u32 address, u32 data)
+{
+	if (!ar->hif.ops->write32) {
+		ath10k_warn(ar, "hif write32 not supported\n");
+		return;
+	}
+
+	ar->hif.ops->write32(ar, address, data);
+}
+
 #endif /* _HIF_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 3a6b8a5..0816098 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1988,6 +1988,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
 static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
 	.tx_sg			= ath10k_pci_hif_tx_sg,
 	.diag_read		= ath10k_pci_hif_diag_read,
+	.diag_write		= ath10k_pci_diag_write_mem,
 	.exchange_bmi_msg	= ath10k_pci_hif_exchange_bmi_msg,
 	.start			= ath10k_pci_hif_start,
 	.stop			= ath10k_pci_hif_stop,
@@ -1998,6 +1999,8 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
 	.get_free_queue_number	= ath10k_pci_hif_get_free_queue_number,
 	.power_up		= ath10k_pci_hif_power_up,
 	.power_down		= ath10k_pci_hif_power_down,
+	.read32			= ath10k_pci_read32,
+	.write32		= ath10k_pci_write32,
 #ifdef CONFIG_PM
 	.suspend		= ath10k_pci_hif_suspend,
 	.resume			= ath10k_pci_hif_resume,
-- 
1.7.9.5



From kvalo at qca.qualcomm.com  Sat Nov 22 06:53:18 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Sat, 22 Nov 2014 16:53:18 +0200
Subject: seeking further info on firmware-3
In-Reply-To: <546F8053.3010003@mindchasers.com> (Robert E. Cochran's message
 of "Fri, 21 Nov 2014 13:11:31 -0500")
References: <546F8053.3010003@mindchasers.com>
Message-ID: <87h9xr8ext.fsf@kamboji.qca.qualcomm.com>

"Robert E. Cochran" <wifi at mindchasers.com> writes:

> I'm testing Linux 3.18-rc5 with a QCA9880 / Compex WLE900VX.
>
> During boot, I'm seeing complaints about not finding firmware-3.bin:
>
> ath10k_pci 0001:03:00.0: Direct firmware load for
> ath10k/QCA988X/hw2.0/firmware-3.bin failed with error -2
> ath10k_pci 0001:03:00.0: could not fetch firmware file
> ath10k/QCA988X/hw2.0/firmware-3.bin': -2

You can ignore this warning. ath10k is just telling (in a confusing way)
that it could not find firmware-3.bin and will try firmware-2.bin next.
We should clear up that warning message.

> Can someone please confirm that we should be using
> firmware-3.bin_10.2-00082-4-2 from the 10.2 folder on
> https://github.com/kvalo/ath10k-firmware.git
> ?  When we use this firmware, we see the following during boot:
>
> ath10k_pci 0001:03:00.0: qca988x hw2.0 (0x4100016c, 0x043202ff) fw
> 10.2-00082-4-2 api 3 htt 2.1
> ath10k_pci 0001:03:00.0: debug 1 debugfs 1 tracing 0 dfs 0 testmode 1

That's good. Using firmware from 10.2 branch is a good idea. But did you
rename it to firmware-2.bin? It should be called firmware-3.bin.

> If this isn't the latest & greatest firmware, then where do I find
> firmware-3.bin?

ath10k-firmware.git is the correct location to find the firmware.

> And If I should be using firmware-3.bin_10.2-00082-4-2, then are there
> some release notes available for this?

Unfortunately there are no firmware release notes available.

> Finally, please let me know if it's a mistake to be working with
> firmware-3 on the 3.18 kernel.   We're performing some early
> integration testing with this WiFi module, and it's more important to
> get things working as an AP with hostapd than getting the latest
> cutting edge features working.

The number three in "firmware-3.bin" is just an API number, just like
the soname in shared libraries, to make it possible to have backwards
compatibility with the firmware releases. Instead use version string
like "10.2-00082-4-2" to identify between firmware releases.

And yes, using firmware version 10.2-00082-4-2 is the firmware version I
recommend to use at the moment.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Sat Nov 22 07:28:22 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Sat, 22 Nov 2014 17:28:22 +0200
Subject: [PATCH v2 04/10] ath10k: make firmware text debug messages more
 verbose.
In-Reply-To: <1411507045-18973-4-git-send-email-greearb@candelatech.com>
 (greearb@candelatech.com's message of "Tue, 23 Sep 2014 14:17:19
 -0700")
References: <1411507045-18973-1-git-send-email-greearb@candelatech.com>
 <1411507045-18973-4-git-send-email-greearb@candelatech.com>
Message-ID: <878uj38dbd.fsf@kamboji.qca.qualcomm.com>

greearb at candelatech.com writes:

> From: Ben Greear <greearb at candelatech.com>
>
> There are not many of these messages producted by the
> firmware, but they are generally fairly useful, so print
> them at info level.
>
> Signed-off-by: Ben Greear <greearb at candelatech.com>

[...]

> --- a/drivers/net/wireless/ath/ath10k/debug.h
> +++ b/drivers/net/wireless/ath/ath10k/debug.h
> @@ -35,6 +35,7 @@ enum ath10k_debug_mask {
>  	ATH10K_DBG_BMI		= 0x00000400,
>  	ATH10K_DBG_REGULATORY	= 0x00000800,
>  	ATH10K_DBG_TESTMODE	= 0x00001000,
> +	ATH10K_DBG_FW_MSG	= 0x00002000,

I think FW_MSG is a bit too ambiguous, so I changed this to WMI_PRINT so
that it's closer the real event name.

Full patch: https://github.com/kvalo/ath/commit/ce4269787f4b5e538731f34cb3a7358343efaa00

-- 
Kalle Valo


From greearb at candelatech.com  Sat Nov 22 08:07:49 2014
From: greearb at candelatech.com (Ben Greear)
Date: Sat, 22 Nov 2014 08:07:49 -0800
Subject: [PATCH v2 04/10] ath10k: make firmware text debug messages more
 verbose.
In-Reply-To: <878uj38dbd.fsf@kamboji.qca.qualcomm.com>
References: <1411507045-18973-1-git-send-email-greearb@candelatech.com>	<1411507045-18973-4-git-send-email-greearb@candelatech.com>
 <878uj38dbd.fsf@kamboji.qca.qualcomm.com>
Message-ID: <5470B4D5.7090508@candelatech.com>



On 11/22/2014 07:28 AM, Kalle Valo wrote:
> greearb at candelatech.com writes:
>
>> From: Ben Greear <greearb at candelatech.com>
>>
>> There are not many of these messages producted by the
>> firmware, but they are generally fairly useful, so print
>> them at info level.
>>
>> Signed-off-by: Ben Greear <greearb at candelatech.com>
>
> [...]
>
>> --- a/drivers/net/wireless/ath/ath10k/debug.h
>> +++ b/drivers/net/wireless/ath/ath10k/debug.h
>> @@ -35,6 +35,7 @@ enum ath10k_debug_mask {
>>   	ATH10K_DBG_BMI		= 0x00000400,
>>   	ATH10K_DBG_REGULATORY	= 0x00000800,
>>   	ATH10K_DBG_TESTMODE	= 0x00001000,
>> +	ATH10K_DBG_FW_MSG	= 0x00002000,
>
> I think FW_MSG is a bit too ambiguous, so I changed this to WMI_PRINT so
> that it's closer the real event name.

Better than nothing, but my idea was that this flag would be able to affect
more than one thing related to firmware debugging.  Calling it something about
WMI does not indicate to me that it is really about firmware debugging.

Thanks,
Ben

> Full patch: https://github.com/kvalo/ath/commit/ce4269787f4b5e538731f34cb3a7358343efaa00
>

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


From sujith at msujith.org  Sun Nov 23 18:37:37 2014
From: sujith at msujith.org (Sujith Manoharan)
Date: Mon, 24 Nov 2014 08:07:37 +0530
Subject: [PATCH 3/3] ath10k: Fix bug reported by lockdep
In-Reply-To: <1416796657-24657-1-git-send-email-sujith@msujith.org>
References: <1416796657-24657-1-git-send-email-sujith@msujith.org>
Message-ID: <1416796657-24657-4-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha at qca.qualcomm.com>

ath10k_tx_wep_key_work() acquires conf_mutex, so
cancelling it when conf_mutex is already taken
in ath10k_remove_interface() is incorrect, so
move it outside the lock.

Snippet from the lockdep report:

kernel: ======================================================
kernel: [ INFO: possible circular locking dependency detected ]
kernel: 3.18.0-rc5-wl-debug #34 Tainted: G           O
kernel: -------------------------------------------------------
kernel: hostapd/451 is trying to acquire lock:
kernel:  ((&arvif->wep_key_work)){+.+...}, at: [<ffffffff810872d5>] flush_work+0x5/0x290
kernel: but task is already holding lock:
kernel:  (&ar->conf_mutex){+.+.+.}, at: [<ffffffffa0b99f00>] ath10k_remove_interface+0x40/0x290 [ath10k_core]
kernel: which lock already depends on the new lock.

Signed-off-by: Sujith Manoharan <c_manoha at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 2200c64..651e318 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3041,10 +3041,10 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
 	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 	int ret;
 
-	mutex_lock(&ar->conf_mutex);
-
 	cancel_work_sync(&arvif->wep_key_work);
 
+	mutex_lock(&ar->conf_mutex);
+
 	spin_lock_bh(&ar->data_lock);
 	ath10k_mac_vif_beacon_cleanup(arvif);
 	spin_unlock_bh(&ar->data_lock);
-- 
2.1.3



From sujith at msujith.org  Sun Nov 23 18:37:35 2014
From: sujith at msujith.org (Sujith Manoharan)
Date: Mon, 24 Nov 2014 08:07:35 +0530
Subject: [PATCH 1/3] ath10k: Fix shared WEP
In-Reply-To: <1416796657-24657-1-git-send-email-sujith@msujith.org>
References: <1416796657-24657-1-git-send-email-sujith@msujith.org>
Message-ID: <1416796657-24657-2-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha at qca.qualcomm.com>

When static keys are used in shared WEP, when a
station is associated, message 3 is sent with an
encrypted payload. But, for subsequent
authentications that are triggered without a
deauth, the auth frame is decrypted by the HW.

To handle this, check if the WEP keys have already
been set for the peer and if so, mark the
frame as decrypted. This scenario can happen
when a station changes its default TX key and initiates
a new authentication sequence.

Signed-off-by: Sujith Manoharan <c_manoha at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 23 +++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/mac.h |  2 ++
 drivers/net/wireless/ath/ath10k/wmi.c | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 58 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 1245ac8..23116c2 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -179,6 +179,29 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
 	return first_errno;
 }
 
+bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
+				    u8 keyidx)
+{
+	struct ath10k_peer *peer;
+	int i;
+
+	/* We don't know which vdev this peer belongs to,
+	 * since WMI doesn't give us that information.
+	 *
+	 * FIXME: multi-bss needs to be handled.
+	 */
+	peer = ath10k_peer_find(ar, 0, addr);
+	if (!peer)
+		return false;
+
+	for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
+		if (peer->keys[i] && peer->keys[i]->keyidx == keyidx)
+			return true;
+	}
+
+	return false;
+}
+
 static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
 				 struct ieee80211_key_conf *key)
 {
diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
index 4e3c989..cfa4d5d 100644
--- a/drivers/net/wireless/ath/ath10k/mac.h
+++ b/drivers/net/wireless/ath/ath10k/mac.h
@@ -41,6 +41,8 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work);
 void ath10k_halt(struct ath10k *ar);
 void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif);
 void ath10k_drain_tx(struct ath10k *ar);
+bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
+				    u8 keyidx);
 
 static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
 {
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c2bc828..a12bba4 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -1113,6 +1113,37 @@ static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band)
 	return rate_idx;
 }
 
+static void ath10k_wmi_handle_wep_reauth(struct ath10k *ar,
+					 struct sk_buff *skb,
+					 struct ieee80211_rx_status *status)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	unsigned int hdrlen;
+	bool peer_key;
+	u8 *addr, keyidx;
+
+	if (!ieee80211_is_auth(hdr->frame_control) ||
+	    !ieee80211_has_protected(hdr->frame_control))
+		return;
+
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
+	if (skb->len < (hdrlen + IEEE80211_WEP_IV_LEN))
+		return;
+
+	keyidx = skb->data[hdrlen + 3] >> 6;
+	addr = ieee80211_get_SA(hdr);
+
+	spin_lock_bh(&ar->data_lock);
+	peer_key = ath10k_mac_is_peer_wep_key_set(ar, addr, keyidx);
+	spin_unlock_bh(&ar->data_lock);
+
+	if (peer_key) {
+		ath10k_dbg(ar, ATH10K_DBG_MAC,
+			   "wep key present for peer: %pM\n", addr);
+		status->flag |= RX_FLAG_DECRYPTED;
+	}
+}
+
 static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_mgmt_rx_event_v1 *ev_v1;
@@ -1200,6 +1231,8 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 	hdr = (struct ieee80211_hdr *)skb->data;
 	fc = le16_to_cpu(hdr->frame_control);
 
+	ath10k_wmi_handle_wep_reauth(ar, skb, status);
+
 	/* FW delivers WEP Shared Auth frame with Protected Bit set and
 	 * encrypted payload. However in case of PMF it delivers decrypted
 	 * frames with Protected Bit set. */
-- 
2.1.3



From sujith at msujith.org  Sun Nov 23 18:37:34 2014
From: sujith at msujith.org (Sujith Manoharan)
Date: Mon, 24 Nov 2014 08:07:34 +0530
Subject: [PATCH 0/3] ath10k patches
Message-ID: <1416796657-24657-1-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha at qca.qualcomm.com>

Fixes for WEP.

Sujith Manoharan (3):
  ath10k: Fix shared WEP
  ath10k: Fix locking for WEP keys
  ath10k: Fix bug reported by lockdep

 drivers/net/wireless/ath/ath10k/mac.c | 31 +++++++++++++++++++++++++++++--
 drivers/net/wireless/ath/ath10k/mac.h |  2 ++
 drivers/net/wireless/ath/ath10k/wmi.c | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 64 insertions(+), 2 deletions(-)

-- 
2.1.3



From sujith at msujith.org  Sun Nov 23 18:37:36 2014
From: sujith at msujith.org (Sujith Manoharan)
Date: Mon, 24 Nov 2014 08:07:36 +0530
Subject: [PATCH 2/3] ath10k: Fix locking for WEP keys
In-Reply-To: <1416796657-24657-1-git-send-email-sujith@msujith.org>
References: <1416796657-24657-1-git-send-email-sujith@msujith.org>
Message-ID: <1416796657-24657-3-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha at qca.qualcomm.com>

peer->keys needs to be protected by data_lock
since it is also accessed from the WMI path.

Both install() and clear() routines for peer
keys modify the key contents, so use the data_lock
to avoid races.

Signed-off-by: Sujith Manoharan <c_manoha at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 23116c2..2200c64 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -136,7 +136,9 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
 		if (ret)
 			return ret;
 
+		spin_lock_bh(&ar->data_lock);
 		peer->keys[i] = arvif->wep_keys[i];
+		spin_unlock_bh(&ar->data_lock);
 	}
 
 	return 0;
@@ -173,7 +175,9 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
 			ath10k_warn(ar, "failed to remove peer wep key %d: %d\n",
 				    i, ret);
 
+		spin_lock_bh(&ar->data_lock);
 		peer->keys[i] = NULL;
+		spin_unlock_bh(&ar->data_lock);
 	}
 
 	return first_errno;
-- 
2.1.3



From kvalo at qca.qualcomm.com  Mon Nov 24 02:09:42 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 24 Nov 2014 12:09:42 +0200
Subject: [PATCH 2/2] ath10k: re-config ht_caps when chainmask is modified.
In-Reply-To: <1411576506-11815-2-git-send-email-greearb@candelatech.com>
 (greearb@candelatech.com's message of "Wed, 24 Sep 2014 09:35:06
 -0700")
References: <1411576506-11815-1-git-send-email-greearb@candelatech.com>
 <1411576506-11815-2-git-send-email-greearb@candelatech.com>
Message-ID: <87ioi47vvd.fsf@kamboji.qca.qualcomm.com>

Hi,

something to clarify about mac80211 behaviour:

greearb at candelatech.com writes:

> This lets the mac80211 stack use the proper ht-caps when
> negotiating with the peer.  Note that all vdevs are guaranteed
> to be down when antenna changes, so we can set the ht_caps
> without worrying about messing up existing stations.

[...]

> @@ -2537,6 +2560,17 @@ static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
>  	ar->cfg_tx_chainmask = tx_ant;
>  	ar->cfg_rx_chainmask = rx_ant;
>  
> +	ht_cap = ath10k_get_ht_cap(ar, true);
> +	vht_cap = ath10k_create_vht_cap(ar, true);
> +
> +	if (ar->phy_capability & WHAL_WLAN_11G_CAPABILITY)
> +		ar->mac.sbands[IEEE80211_BAND_2GHZ].ht_cap = ht_cap;
> +
> +	if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) {
> +		ar->mac.sbands[IEEE80211_BAND_5GHZ].ht_cap = ht_cap;
> +		ar->mac.sbands[IEEE80211_BAND_5GHZ].vht_cap = vht_cap;
> +	}

So this modifies stryct wiphy::bands after we have called
ieee80211_register_hw(). Is this something which both cfg80211 and
mac80211 support? I didn't find the documentation mentioning anything
about this so I got a bit worried.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov 24 02:53:04 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 24 Nov 2014 12:53:04 +0200
Subject: [PATCH 2/2] ath10k: re-config ht_caps when chainmask is modified.
In-Reply-To: <87ioi47vvd.fsf@kamboji.qca.qualcomm.com> (Kalle Valo's message
 of "Mon, 24 Nov 2014 12:09:42 +0200")
References: <1411576506-11815-1-git-send-email-greearb@candelatech.com>
 <1411576506-11815-2-git-send-email-greearb@candelatech.com>
 <87ioi47vvd.fsf@kamboji.qca.qualcomm.com>
Message-ID: <87egss7tv3.fsf@kamboji.qca.qualcomm.com>

Kalle Valo <kvalo at qca.qualcomm.com> writes:

>> @@ -2537,6 +2560,17 @@ static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
>>  	ar->cfg_tx_chainmask = tx_ant;
>>  	ar->cfg_rx_chainmask = rx_ant;
>>  
>> +	ht_cap = ath10k_get_ht_cap(ar, true);
>> +	vht_cap = ath10k_create_vht_cap(ar, true);
>> +
>> +	if (ar->phy_capability & WHAL_WLAN_11G_CAPABILITY)
>> +		ar->mac.sbands[IEEE80211_BAND_2GHZ].ht_cap = ht_cap;
>> +
>> +	if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) {
>> +		ar->mac.sbands[IEEE80211_BAND_5GHZ].ht_cap = ht_cap;
>> +		ar->mac.sbands[IEEE80211_BAND_5GHZ].vht_cap = vht_cap;
>> +	}
>
> So this modifies stryct wiphy::bands after we have called
> ieee80211_register_hw(). Is this something which both cfg80211 and
> mac80211 support? I didn't find the documentation mentioning anything
> about this so I got a bit worried.

Johannes mentioned me that this is not supported so I am reluctant to
take these. Unless I'm missing something, of course.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov 24 02:59:08 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 24 Nov 2014 12:59:08 +0200
Subject: [PATCH 1/2] ath10k: Do not limit RTS threshold value to 2347
In-Reply-To: <1416821930-3003-1-git-send-email-nataraja@qti.qualcomm.com>
 (Vivek Natarajan's message of "Mon, 24 Nov 2014 15:08:49 +0530")
References: <1416821930-3003-1-git-send-email-nataraja@qti.qualcomm.com>
Message-ID: <87a93g7tkz.fsf@kamboji.qca.qualcomm.com>

Vivek Natarajan <nataraja at qti.qualcomm.com> writes:

> Signed-off-by: Vivek Natarajan <nataraja at qti.qualcomm.com>

Please no patches with empty commit logs.

Also please send ath10k patches both to ath10k and linux-wireless lists.
This is important especially now that I'm experimenting with patchwork
and it won't see the patch otherwise.

Documentation is here:

http://wireless.kernel.org/en/users/Drivers/ath10k/sources#Submitting_patches

-- 
Kalle Valo


From vivek.natraj at gmail.com  Mon Nov 24 03:54:41 2014
From: vivek.natraj at gmail.com (Vivek Natarajan)
Date: Mon, 24 Nov 2014 17:24:41 +0530
Subject: Tx Status of multicast frames
Message-ID: <CAJqpcCTAPcG4F5-oFxGa0mQhaHzDd=8b2BpTtyYvmX2vZHxYNA@mail.gmail.com>

Hi Johannes,
  We are noticing a issue in updating the multicast frame statistics.
Though mac80211 explicitly sets the IEEE80211_TX_CTL_NO_ACK, it checks
IEEE80211_TX_STAT_ACK to increment the frame count. So, for multicast
frames, is the driver expected to set this STAT_ACK if the frame is
successfully transmitted over the air?

The naming convention seems to be a bit confusing from unicast and
multicast frames perspectives:

For multicast, IEEE80211_TX_STAT_ACK can denote if a frame is
successfully transmitted over the air or failed to be transmitted.

In case of normal frames, IEEE80211_TX_STAT_ACK decides if the frame
is acked or not-acked/not-transmitted.

Do you think renaming this to something like STAT_SUCCESS would be a
better thing to do?

Vivek.

mac80211/status.c:
if (info->flags & IEEE80211_TX_STAT_ACK) {
                if (ieee80211_is_first_frag(hdr->seq_ctrl)) {
                        local->dot11TransmittedFrameCount++;
                        if (is_multicast_ether_addr(hdr->addr1))
                                local->dot11MulticastTransmittedFrameCount++;
                        if (retry_count > 0)
                                local->dot11RetryCount++;
                        if (retry_count > 1)
                                local->dot11MultipleRetryCount++;
                }

                /* This counter shall be incremented for an acknowledged MPDU
                 * with an individual address in the address 1 field or an MPDU
                 * with a multicast address in the address 1 field of type Data
                 * or Management. */
                if (!is_multicast_ether_addr(hdr->addr1) ||
                    ieee80211_is_data(fc) ||
                    ieee80211_is_mgmt(fc))
                        local->dot11TransmittedFragmentCount++;
        } else {
                if (ieee80211_is_first_frag(hdr->seq_ctrl))
                        local->dot11FailedCount++;
        }


From nataraja at qti.qualcomm.com  Mon Nov 24 03:56:22 2014
From: nataraja at qti.qualcomm.com (Vivek Natarajan)
Date: Mon, 24 Nov 2014 17:26:22 +0530
Subject: [PATCH] ath: Fix a false radar detection pattern
Message-ID: <1416830183-2985-1-git-send-email-nataraja@qti.qualcomm.com>

For FCC and JP, in one of the radar patterns, PPB and PRF seems to be
interchanged leading to frequent incorrect radar detections.

Signed-off-by: Vivek Natarajan <nataraja at qti.qualcomm.com>
---
 drivers/net/wireless/ath/dfs_pattern_detector.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c
index 7a16686..0e383ef 100644
--- a/drivers/net/wireless/ath/dfs_pattern_detector.c
+++ b/drivers/net/wireless/ath/dfs_pattern_detector.c
@@ -86,7 +86,7 @@ static const struct radar_detector_specs fcc_radar_ref_types[] = {
 	FCC_PATTERN(1, 0, 5, 150, 230, 1, 23),
 	FCC_PATTERN(2, 6, 10, 200, 500, 1, 16),
 	FCC_PATTERN(3, 11, 20, 200, 500, 1, 12),
-	FCC_PATTERN(4, 50, 100, 1000, 2000, 20, 1),
+	FCC_PATTERN(4, 50, 100, 1000, 2000, 1, 20),
 	FCC_PATTERN(5, 0, 1, 333, 333, 1, 9),
 };
 
@@ -105,7 +105,7 @@ static const struct radar_detector_specs jp_radar_ref_types[] = {
 	JP_PATTERN(4, 0, 5, 150, 230, 1, 23),
 	JP_PATTERN(5, 6, 10, 200, 500, 1, 16),
 	JP_PATTERN(6, 11, 20, 200, 500, 1, 12),
-	JP_PATTERN(7, 50, 100, 1000, 2000, 20, 1),
+	JP_PATTERN(7, 50, 100, 1000, 2000, 1, 20),
 	JP_PATTERN(5, 0, 1, 333, 333, 1, 9),
 };
 
-- 
1.7.9.5



From nataraja at qti.qualcomm.com  Mon Nov 24 03:57:20 2014
From: nataraja at qti.qualcomm.com (Vivek Natarajan)
Date: Mon, 24 Nov 2014 17:27:20 +0530
Subject: [PATCH] ath10k: Do not limit RTS threshold value to 2347
Message-ID: <1416830240-3019-1-git-send-email-nataraja@qti.qualcomm.com>

Increase the rts threshold from the legacy value of 2347 to support higher
threshold limit.

Signed-off-by: Vivek Natarajan <nataraja at qti.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/mac.c |    6 +-----
 drivers/net/wireless/ath/ath10k/wmi.h |    1 -
 2 files changed, 1 insertion(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 8b60749..61f7e22 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -391,15 +391,11 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
 	return 0;
 }
 
-static int  ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
+static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
 {
 	struct ath10k *ar = arvif->ar;
 	u32 vdev_param;
 
-	if (value != 0xFFFFFFFF)
-		value = min_t(u32, arvif->ar->hw->wiphy->rts_threshold,
-			      ATH10K_RTS_MAX);
-
 	vdev_param = ar->wmi.vdev_param->rts_threshold;
 	return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value);
 }
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index a38d788..8a4e779 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -4547,7 +4547,6 @@ struct wmi_dbglog_cfg_cmd {
 	__le32 config_valid;
 } __packed;
 
-#define ATH10K_RTS_MAX		2347
 #define ATH10K_FRAGMT_THRESHOLD_MIN	540
 #define ATH10K_FRAGMT_THRESHOLD_MAX	2346
 
-- 
1.7.9.5



From michal.kazior at tieto.com  Mon Nov 24 05:15:07 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 24 Nov 2014 14:15:07 +0100
Subject: [PATCH 1/3] ath10k: add missing goto
Message-ID: <1416834909-7130-1-git-send-email-michal.kazior@tieto.com>

This prevents warning spamming if peer creation
fails during sta_state in some cases.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 1245ac8..7b5a888 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3559,9 +3559,11 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			   arvif->vdev_id, sta->addr, ar->num_peers);
 
 		ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
-		if (ret)
+		if (ret) {
 			ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
+			goto exit;
+		}
 
 		if (vif->type == NL80211_IFTYPE_STATION) {
 			WARN_ON(arvif->is_started);
-- 
1.8.5.3



From michal.kazior at tieto.com  Mon Nov 24 05:15:08 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 24 Nov 2014 14:15:08 +0100
Subject: [PATCH 2/3] ath10k: clean up num_peers locking
In-Reply-To: <1416834909-7130-1-git-send-email-michal.kazior@tieto.com>
References: <1416834909-7130-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1416834909-7130-2-git-send-email-michal.kazior@tieto.com>

The var was supposed to be protected by data_lock
but it wasn't so in all instances. It's actually
not necessary to have a spinlock protected
num_peers so drop it.

All instances of num_peers are already within
conf_mutex sections so use that.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h | 2 +-
 drivers/net/wireless/ath/ath10k/mac.c  | 8 +++-----
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 8f86bd3..be7e50b6 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -560,7 +560,7 @@ struct ath10k {
 	struct list_head peers;
 	wait_queue_head_t peer_mapping_wq;
 
-	/* number of created peers; protected by data_lock */
+	/* protected by conf_mutex */
 	int num_peers;
 
 	struct work_struct offchan_tx_work;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 7b5a888..3312e75 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -339,9 +339,8 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
 			    addr, vdev_id, ret);
 		return ret;
 	}
-	spin_lock_bh(&ar->data_lock);
+
 	ar->num_peers++;
-	spin_unlock_bh(&ar->data_lock);
 
 	return 0;
 }
@@ -432,9 +431,7 @@ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
 	if (ret)
 		return ret;
 
-	spin_lock_bh(&ar->data_lock);
 	ar->num_peers--;
-	spin_unlock_bh(&ar->data_lock);
 
 	return 0;
 }
@@ -471,8 +468,9 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
 		list_del(&peer->list);
 		kfree(peer);
 	}
-	ar->num_peers = 0;
 	spin_unlock_bh(&ar->data_lock);
+
+	ar->num_peers = 0;
 }
 
 /************************/
-- 
1.8.5.3



From michal.kazior at tieto.com  Mon Nov 24 05:15:09 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 24 Nov 2014 14:15:09 +0100
Subject: [PATCH 3/3] ath10k: fix station count enforcement
In-Reply-To: <1416834909-7130-1-git-send-email-michal.kazior@tieto.com>
References: <1416834909-7130-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1416834909-7130-3-git-send-email-michal.kazior@tieto.com>

The number of peers isn't directly translatable to
the number of stations because ath10k needs to
reserve a few extra peers for special cases like
multi-vif concurrency.

The previous limit was 126 and 15 stations in AP
mode for 10.x and main firmware branches
respectively. The limit is now 128 and 16 which
was the original intention.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.c  | 13 +++++++
 drivers/net/wireless/ath/ath10k/core.h  |  3 ++
 drivers/net/wireless/ath/ath10k/debug.c |  5 +--
 drivers/net/wireless/ath/ath10k/hw.h    | 15 ++++++---
 drivers/net/wireless/ath/ath10k/mac.c   | 60 ++++++++++++++++++++++++++-------
 drivers/net/wireless/ath/ath10k/wmi.c   |  2 +-
 6 files changed, 77 insertions(+), 21 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index f660553..fea63ac 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -799,6 +799,17 @@ static void ath10k_core_restart(struct work_struct *work)
 	mutex_unlock(&ar->conf_mutex);
 }
 
+static void ath10k_core_init_max_sta_count(struct ath10k *ar)
+{
+	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+		ar->max_num_peers = TARGET_10X_NUM_PEERS;
+		ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+	} else {
+		ar->max_num_peers = TARGET_NUM_PEERS;
+		ar->max_num_stations = TARGET_NUM_STATIONS;
+	}
+}
+
 int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
 {
 	int status;
@@ -939,6 +950,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
 	else
 		ar->free_vdev_map = (1LL << TARGET_NUM_VDEVS) - 1;
 
+	ath10k_core_init_max_sta_count(ar);
+
 	INIT_LIST_HEAD(&ar->arvifs);
 
 	return 0;
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index be7e50b6..0baaff4 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -562,6 +562,9 @@ struct ath10k {
 
 	/* protected by conf_mutex */
 	int num_peers;
+	int num_stations;
+	int max_num_peers;
+	int max_num_stations;
 
 	struct work_struct offchan_tx_work;
 	struct sk_buff_head offchan_tx_queue;
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index a8f5a72..75f7c8c 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -124,7 +124,7 @@ EXPORT_SYMBOL(ath10k_info);
 
 void ath10k_print_driver_info(struct ath10k *ar)
 {
-	ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s\n",
+	ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s max_sta %d\n",
 		    ar->hw_params.name,
 		    ar->target_version,
 		    ar->chip_id,
@@ -136,7 +136,8 @@ void ath10k_print_driver_info(struct ath10k *ar)
 		    ar->fw_version_minor,
 		    ar->fw_version_release,
 		    ar->fw_version_build,
-		    ath10k_cal_mode_str(ar->cal_mode));
+		    ath10k_cal_mode_str(ar->cal_mode),
+		    ar->max_num_stations);
 	ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n",
 		    config_enabled(CONFIG_ATH10K_DEBUG),
 		    config_enabled(CONFIG_ATH10K_DEBUGFS),
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 392c250..dfedfd0 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -97,11 +97,13 @@ struct ath10k_pktlog_hdr {
 #define TARGET_DMA_BURST_SIZE			0
 #define TARGET_MAC_AGGR_DELIM			0
 #define TARGET_AST_SKID_LIMIT			16
-#define TARGET_NUM_PEERS			16
+#define TARGET_NUM_STATIONS			16
+#define TARGET_NUM_PEERS			((TARGET_NUM_STATIONS) + \
+						 (TARGET_NUM_VDEVS))
 #define TARGET_NUM_OFFLOAD_PEERS		0
 #define TARGET_NUM_OFFLOAD_REORDER_BUFS         0
 #define TARGET_NUM_PEER_KEYS			2
-#define TARGET_NUM_TIDS		(2 * ((TARGET_NUM_PEERS) + (TARGET_NUM_VDEVS)))
+#define TARGET_NUM_TIDS				((TARGET_NUM_PEERS) * 2)
 #define TARGET_TX_CHAIN_MASK			(BIT(0) | BIT(1) | BIT(2))
 #define TARGET_RX_CHAIN_MASK			(BIT(0) | BIT(1) | BIT(2))
 #define TARGET_RX_TIMEOUT_LO_PRI		100
@@ -132,12 +134,15 @@ struct ath10k_pktlog_hdr {
 #define TARGET_10X_DMA_BURST_SIZE		0
 #define TARGET_10X_MAC_AGGR_DELIM		0
 #define TARGET_10X_AST_SKID_LIMIT		16
-#define TARGET_10X_NUM_PEERS			(128 + (TARGET_10X_NUM_VDEVS))
-#define TARGET_10X_NUM_PEERS_MAX		128
+#define TARGET_10X_NUM_STATIONS			128
+#define TARGET_10X_NUM_PEERS			((TARGET_10X_NUM_STATIONS) + \
+						 (TARGET_10X_NUM_VDEVS))
 #define TARGET_10X_NUM_OFFLOAD_PEERS		0
 #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS	0
 #define TARGET_10X_NUM_PEER_KEYS		2
-#define TARGET_10X_NUM_TIDS			256
+#define TARGET_10X_NUM_TIDS_MAX			256
+#define TARGET_10X_NUM_TIDS			min((TARGET_10X_NUM_TIDS_MAX), \
+						    (TARGET_10X_NUM_PEERS) * 2)
 #define TARGET_10X_TX_CHAIN_MASK		(BIT(0) | BIT(1) | BIT(2))
 #define TARGET_10X_RX_CHAIN_MASK		(BIT(0) | BIT(1) | BIT(2))
 #define TARGET_10X_RX_TIMEOUT_LO_PRI		100
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 3312e75..95d0f30 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -326,6 +326,9 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
 
 	lockdep_assert_held(&ar->conf_mutex);
 
+	if (ar->num_peers >= ar->max_num_peers)
+		return -ENOBUFS;
+
 	ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
 	if (ret) {
 		ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n",
@@ -471,6 +474,7 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
 	spin_unlock_bh(&ar->data_lock);
 
 	ar->num_peers = 0;
+	ar->num_stations = 0;
 }
 
 /************************/
@@ -3509,6 +3513,37 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
 	mutex_unlock(&ar->conf_mutex);
 }
 
+static int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif)
+{
+	struct ath10k *ar = arvif->ar;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
+	    arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
+		return 0;
+
+	if (ar->num_stations >= ar->max_num_stations)
+		return -ENOBUFS;
+
+	ar->num_stations++;
+
+	return 0;
+}
+
+static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif)
+{
+	struct ath10k *ar = arvif->ar;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
+	    arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
+		return;
+
+	ar->num_stations--;
+}
+
 static int ath10k_sta_state(struct ieee80211_hw *hw,
 			    struct ieee80211_vif *vif,
 			    struct ieee80211_sta *sta,
@@ -3518,7 +3553,6 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 	struct ath10k *ar = hw->priv;
 	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
-	int max_num_peers;
 	int ret = 0;
 
 	if (old_state == IEEE80211_STA_NOTEXIST &&
@@ -3540,26 +3574,24 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 		/*
 		 * New station addition.
 		 */
-		if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
-			max_num_peers = TARGET_10X_NUM_PEERS_MAX - 1;
-		else
-			max_num_peers = TARGET_NUM_PEERS;
+		ath10k_dbg(ar, ATH10K_DBG_MAC,
+			   "mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d\n",
+			   arvif->vdev_id, sta->addr,
+			   ar->num_stations + 1, ar->max_num_stations,
+			   ar->num_peers + 1, ar->max_num_peers);
 
-		if (ar->num_peers >= max_num_peers) {
-			ath10k_warn(ar, "number of peers exceeded: peers number %d (max peers %d)\n",
-				    ar->num_peers, max_num_peers);
-			ret = -ENOBUFS;
+		ret = ath10k_mac_inc_num_stations(arvif);
+		if (ret) {
+			ath10k_warn(ar, "refusing to associate station: too many connected already (%d)\n",
+				    ar->max_num_stations);
 			goto exit;
 		}
 
-		ath10k_dbg(ar, ATH10K_DBG_MAC,
-			   "mac vdev %d peer create %pM (new sta) num_peers %d\n",
-			   arvif->vdev_id, sta->addr, ar->num_peers);
-
 		ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
 		if (ret) {
 			ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
+			ath10k_mac_dec_num_stations(arvif);
 			goto exit;
 		}
 
@@ -3572,6 +3604,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 					    arvif->vdev_id, ret);
 				WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id,
 							   sta->addr));
+				ath10k_mac_dec_num_stations(arvif);
 				goto exit;
 			}
 
@@ -3602,6 +3635,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
 
+		ath10k_mac_dec_num_stations(arvif);
 	} else if (old_state == IEEE80211_STA_AUTH &&
 		   new_state == IEEE80211_STA_ASSOC &&
 		   (vif->type == NL80211_IFTYPE_AP ||
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c2bc828..84a1efa 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -3142,7 +3142,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
 	u32 len, val;
 
 	config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS);
-	config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS);
+	config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS);
 	config.num_offload_peers = __cpu_to_le32(TARGET_NUM_OFFLOAD_PEERS);
 
 	config.num_offload_reorder_bufs =
-- 
1.8.5.3



From kvalo at qca.qualcomm.com  Mon Nov 24 05:50:07 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 24 Nov 2014 15:50:07 +0200
Subject: [PATCH] ath10k: Add the target register access and memory dump
 debugfs interface
In-Reply-To: <1416656922-6645-1-git-send-email-yanbol@qti.qualcomm.com> (Yanbo
 Li's message of "Sat, 22 Nov 2014 19:48:42 +0800")
References: <1416656922-6645-1-git-send-email-yanbol@qti.qualcomm.com>
Message-ID: <871tos7lo0.fsf@kamboji.qca.qualcomm.com>

Yanbo Li <yanbol at qti.qualcomm.com> writes:

> The debugfs interface reg_addr&reg_val used to read and write the target
> register.
> The interface mmem_val used to dump the targer memory and also can be
> used to assign value to target memory
>
> The basic usage explain as below:
>
> Register read/write:
> reg_addr       (the register address)                    (read&write)
> reg_value      (the register value,  output is ASCII)    (read&write)
>
> Read operation:
> 1. Write the reg address to reg_addr
>    IE:  echo 0x100000 > reg_addr
> 2. Read the value from reg_value
>    IE:  cat reg_value
> Write operation:
> 1. Write the reg address to reg_addr IE:  echo 0x100000 > reg_addr
> 2. Write the value to the reg_value  IE:  echo  0x2400 > reg_value
>
> Target memory dump:
> mem_value (the target memory, access with the length and start address
> 							(read&write)
> Read operation:
>
> 1: Read 4K(bs*count)) from address 0x400000(bs*skip)
> dd if=mem_value bs=4 count=1024 skip=1048576 | xxd -g1
>
> 2: Read 0x50000(bs*count) from address 0x400000(bs*skip)
> dd if=mem_value bs=4 count=81920 skip=1048576 | xxd -g1
>
> Write operation:
>
> 1: Write the 0x01020304 to address 0x400400(bs*seek)
> echo 0x01020304 | xxd -r | dd of=mem_value bs=4 seek=1048832
>
> 2: Read the memory and then write back after edit
> dd if=mem_value bs=4 count=1024 skip=1048576 > tmp.bin
> edit the tmp.bin
> dd if=tmp.bin of=mem_value bs=4 count=4 seek=1048576
>
> It suggests assign the 4 align number to bs, IE, 4, 8, 16 ....
> Cause the target memory width is 32bit
>
> Signed-off-by: Yanbo Li <yanbol at qti.qualcomm.com>

The commit log is quite hard to read due to formatting, but I can clean
that up.

> +	spin_lock_bh(&ar->data_lock);
> +	reg_addr = ar->debug.reg_addr;
> +	spin_unlock_bh(&ar->data_lock);

[...]

> +	spin_lock_bh(&ar->data_lock);
> +	ar->debug.reg_addr = reg_addr;
> +	spin_unlock_bh(&ar->data_lock);

[...]

> +	spin_lock_bh(&ar->data_lock);
> +	reg_addr = ar->debug.reg_addr;
> +	spin_unlock_bh(&ar->data_lock);

[...]

> +	spin_lock_bh(&ar->data_lock);
> +	reg_addr = ar->debug.reg_addr;
> +	spin_unlock_bh(&ar->data_lock);

I admit that I'm far from a locking expert, but does that make any
difference in the functionality?

-- 
Kalle Valo


From michal.kazior at tieto.com  Mon Nov 24 06:03:10 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 24 Nov 2014 15:03:10 +0100
Subject: [PATCH] ath10k: Add the target register access and memory dump
 debugfs interface
In-Reply-To: <871tos7lo0.fsf@kamboji.qca.qualcomm.com>
References: <1416656922-6645-1-git-send-email-yanbol@qti.qualcomm.com>
 <871tos7lo0.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CA+BoTQmdK1fYaWmPAd4GswKR7dKErD5MA2DtrNRZLEc-dFTYLA@mail.gmail.com>

On 24 November 2014 at 14:50, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Yanbo Li <yanbol at qti.qualcomm.com> writes:
[...]
>> +     spin_lock_bh(&ar->data_lock);
>> +     reg_addr = ar->debug.reg_addr;
>> +     spin_unlock_bh(&ar->data_lock);
>
> [...]
>
>> +     spin_lock_bh(&ar->data_lock);
>> +     ar->debug.reg_addr = reg_addr;
>> +     spin_unlock_bh(&ar->data_lock);
>
> [...]
>
>> +     spin_lock_bh(&ar->data_lock);
>> +     reg_addr = ar->debug.reg_addr;
>> +     spin_unlock_bh(&ar->data_lock);
>
> [...]
>
>> +     spin_lock_bh(&ar->data_lock);
>> +     reg_addr = ar->debug.reg_addr;
>> +     spin_unlock_bh(&ar->data_lock);
>
> I admit that I'm far from a locking expert, but does that make any
> difference in the functionality?

I imagine reg_addr could end up needing 2 instructions to be set on
some weird architecture+compiler combination in which case locking is
desired. With multiple access to write reg_addr you could end up
reading an address that either isn't the old nor the new one. Should
be harmless though and you could argue that you shouldn't access the
reg_addr debugfs file simultaneously in the first place. Maybe I'm
just over-exaggerating? :-)


Micha?


From michal.kazior at tieto.com  Mon Nov 24 05:58:32 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 24 Nov 2014 14:58:32 +0100
Subject: [PATCH 2/3] ath10k: make hw roc more reliable
In-Reply-To: <1416837513-13386-1-git-send-email-michal.kazior@tieto.com>
References: <1416837513-13386-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1416837513-13386-2-git-send-email-michal.kazior@tieto.com>

With P2P concurrency requested hw roc duration
time can be very small. Some firmware revisions
refuse scan requests with too small channel dwell
time.

This prevents messages like, e.g. with connected
STA vif and performing P2P Find:

 ath10k_pci 0000:00:05.0: failed to switch to channel for roc scan
 ieee80211 phy3: failed to start next HW ROC (-110)

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 2 ++
 drivers/net/wireless/ath/ath10k/wmi.h | 5 +++++
 2 files changed, 7 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 8deae4d..272a9d9 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3807,6 +3807,8 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
 	if (ret)
 		goto exit;
 
+	duration = max(duration, WMI_SCAN_CHAN_MIN_TIME_MSEC);
+
 	memset(&arg, 0, sizeof(arg));
 	ath10k_wmi_start_scan_init(ar, &arg);
 	arg.vdev_id = arvif->vdev_id;
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index a38d788..1b7141a 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -1952,6 +1952,11 @@ struct wmi_ssid_list {
 #define WLAN_SCAN_PARAMS_MAX_BSSID   4
 #define WLAN_SCAN_PARAMS_MAX_IE_LEN  256
 
+/* Values lower than this may be refused by some firmware revisions with a scan
+ * completion with a timedout reason.
+ */
+#define WMI_SCAN_CHAN_MIN_TIME_MSEC 40
+
 /* Scan priority numbers must be sequential, starting with 0 */
 enum wmi_scan_priority {
 	WMI_SCAN_PRIORITY_VERY_LOW = 0,
-- 
1.8.5.3



From michal.kazior at tieto.com  Mon Nov 24 05:58:33 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 24 Nov 2014 14:58:33 +0100
Subject: [PATCH 3/3] ath10k: fix offchannel cancel failures
In-Reply-To: <1416837513-13386-1-git-send-email-michal.kazior@tieto.com>
References: <1416837513-13386-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1416837513-13386-3-git-send-email-michal.kazior@tieto.com>

When mac80211 requests driver to cancel a hw roc
the driver must not call the expired() callback or
else roc will fail in some cases depending on how
things get scheduled.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 272a9d9..42b5982 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2184,10 +2184,10 @@ void __ath10k_scan_finish(struct ath10k *ar)
 	case ATH10K_SCAN_IDLE:
 		break;
 	case ATH10K_SCAN_RUNNING:
-	case ATH10K_SCAN_ABORTING:
 		if (ar->scan.is_roc)
 			ieee80211_remain_on_channel_expired(ar->hw);
-		else
+	case ATH10K_SCAN_ABORTING:
+		if (!ar->scan.is_roc)
 			ieee80211_scan_completed(ar->hw,
 						 (ar->scan.state ==
 						  ATH10K_SCAN_ABORTING));
-- 
1.8.5.3



From michal.kazior at tieto.com  Mon Nov 24 05:58:31 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 24 Nov 2014 14:58:31 +0100
Subject: [PATCH 1/3] ath10k: fix offchan reliability
Message-ID: <1416837513-13386-1-git-send-email-michal.kazior@tieto.com>

New firmware revisions don't need peer creation
when doing offchannel tx. Earlier revisions would
queue and never release frames without a peer.

This prevent new firmware revisions from stopping
replenishing wmi-htc tx credits and improves
reliability of offchannel tx which would sometimes
silently fail.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h   |  1 +
 drivers/net/wireless/ath/ath10k/htt.h    |  4 +++-
 drivers/net/wireless/ath/ath10k/htt_tx.c |  7 ++++---
 drivers/net/wireless/ath/ath10k/mac.c    | 29 +++++++++++++++++++++++------
 4 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 8f86bd3..c510785 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -83,6 +83,7 @@ struct ath10k_skb_cb {
 
 	struct {
 		u8 tid;
+		u16 freq;
 		bool is_offchan;
 		struct ath10k_htt_txbuf *txbuf;
 		u32 txbuf_paddr;
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 15c58e8..17ca6ac 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -126,6 +126,7 @@ enum htt_data_tx_ext_tid {
  *                  (HL hosts manage queues on the host )
  *       more_in_batch: only for HL hosts. indicates if more packets are
  *                      pending. this allows target to wait and aggregate
+ *       freq: 0 means home channel of given vdev. intended for offchannel
  */
 struct htt_data_tx_desc {
 	u8 flags0; /* %HTT_DATA_TX_DESC_FLAGS0_ */
@@ -133,7 +134,8 @@ struct htt_data_tx_desc {
 	__le16 len;
 	__le16 id;
 	__le32 frags_paddr;
-	__le32 peerid;
+	__le16 peerid;
+	__le16 freq;
 	u8 prefetch[0]; /* start of frame, for FW classification engine */
 } __packed;
 
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 5b7e42f..4bc51d8 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -554,13 +554,14 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 	skb_cb->htt.txbuf->cmd_tx.len = __cpu_to_le16(msdu->len);
 	skb_cb->htt.txbuf->cmd_tx.id = __cpu_to_le16(msdu_id);
 	skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr);
-	skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID);
+	skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le16(HTT_INVALID_PEERID);
+	skb_cb->htt.txbuf->cmd_tx.freq = __cpu_to_le16(skb_cb->htt.freq);
 
 	trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid);
 	ath10k_dbg(ar, ATH10K_DBG_HTT,
-		   "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n",
+		   "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu freq %hu\n",
 		   flags0, flags1, msdu->len, msdu_id, frags_paddr,
-		   (u32)skb_cb->paddr, vdev_id, tid);
+		   (u32)skb_cb->paddr, vdev_id, tid, skb_cb->htt.freq);
 	ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
 			msdu->data, msdu->len);
 	trace_ath10k_tx_hdr(ar, msdu->data, msdu->len);
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 1245ac8..8deae4d 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1997,6 +1997,18 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
 	}
 }
 
+static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar)
+{
+	/* FIXME: Not really sure since when the behaviour changed. At some
+	 * point new firmware stopped requiring creation of peer entries for
+	 * offchannel tx (and actually creating them causes issues with wmi-htc
+	 * tx credit replenishment and reliability). Assuming it's at least 3.4
+	 * because that's when the `freq` was introduced to TX_FRM HTT command.
+	 */
+	return !(ar->htt.target_version_major >= 3 &&
+		 ar->htt.target_version_minor >= 4);
+}
+
 static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
@@ -2341,16 +2353,21 @@ static void ath10k_tx(struct ieee80211_hw *hw,
 
 	if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
 		spin_lock_bh(&ar->data_lock);
-		ATH10K_SKB_CB(skb)->htt.is_offchan = true;
+		ATH10K_SKB_CB(skb)->htt.freq = ar->scan.roc_freq;
 		ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id;
 		spin_unlock_bh(&ar->data_lock);
 
-		ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n",
-			   skb);
+		if (ath10k_mac_need_offchan_tx_work(ar)) {
+			ATH10K_SKB_CB(skb)->htt.freq = 0;
+			ATH10K_SKB_CB(skb)->htt.is_offchan = true;
 
-		skb_queue_tail(&ar->offchan_tx_queue, skb);
-		ieee80211_queue_work(hw, &ar->offchan_tx_work);
-		return;
+			ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n",
+				   skb);
+
+			skb_queue_tail(&ar->offchan_tx_queue, skb);
+			ieee80211_queue_work(hw, &ar->offchan_tx_work);
+			return;
+		}
 	}
 
 	ath10k_tx_htt(ar, skb);
-- 
1.8.5.3



From kvalo at qca.qualcomm.com  Mon Nov 24 06:11:23 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 24 Nov 2014 16:11:23 +0200
Subject: [PATCH] ath10k: don't rebuild all the time
In-Reply-To: <1416423188-8394-1-git-send-email-johannes@sipsolutions.net>
 (Johannes Berg's message of "Wed, 19 Nov 2014 19:53:08 +0100")
References: <1416423188-8394-1-git-send-email-johannes@sipsolutions.net>
Message-ID: <87wq6k6644.fsf@kamboji.qca.qualcomm.com>

Johannes Berg <johannes at sipsolutions.net> writes:

> There are better ways to get the kernel information, use the
> utsname and omit the version code entirely since it's duplicate.
> The version magic is rather useless anyway
>
> Signed-off-by: Johannes Berg <johannes at sipsolutions.net>

Thanks, applied.

-- 
Kalle Valo


From michal.kazior at tieto.com  Mon Nov 24 06:04:46 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 24 Nov 2014 15:04:46 +0100
Subject: [PATCH] ath10k: remove extra_tx_headroom
Message-ID: <1416837886-18377-1-git-send-email-michal.kazior@tieto.com>

Comment was out-of-date. The headroom is no longer
necessary because HTT Tx fragment list is stored
in dma pool item associated with each sk_buff.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 1245ac8..5bb9f83 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4905,10 +4905,6 @@ int ath10k_mac_register(struct ath10k *ar)
 			IEEE80211_HW_AP_LINK_PS |
 			IEEE80211_HW_SPECTRUM_MGMT;
 
-	/* MSDU can have HTT TX fragment pushed in front. The additional 4
-	 * bytes is used for padding/alignment if necessary. */
-	ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4;
-
 	ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
 
 	if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS)
-- 
1.8.5.3



From kvalo at qca.qualcomm.com  Mon Nov 24 06:19:06 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 24 Nov 2014 16:19:06 +0200
Subject: [PATCH v2 04/10] ath10k: make firmware text debug messages more
 verbose.
In-Reply-To: <1411507045-18973-4-git-send-email-greearb@candelatech.com>
 (greearb@candelatech.com's message of "Tue, 23 Sep 2014 14:17:19
 -0700")
References: <1411507045-18973-1-git-send-email-greearb@candelatech.com>
 <1411507045-18973-4-git-send-email-greearb@candelatech.com>
Message-ID: <87sih865r9.fsf@kamboji.qca.qualcomm.com>

greearb at candelatech.com writes:

> From: Ben Greear <greearb at candelatech.com>
>
> There are not many of these messages producted by the
> firmware, but they are generally fairly useful, so print
> them at info level.
>
> Signed-off-by: Ben Greear <greearb at candelatech.com>

Thanks, applied. Though I did change the commit log:

commit 3be004c3aa4341c7c2461b37612a3a7a3323579d
Author: Ben Greear <greearb at candelatech.com>
Date:   Tue Sep 23 14:17:19 2014 -0700

    ath10k: add ATH10K_DBG_WMI_PRINT debug level
    
    There are not many of these messages producted by the
    firmware, but they are generally fairly useful, so make it easy to print them
    with a separate debug level.
    
    kvalo: fix commit log, rename debug level
    
    Signed-off-by: Ben Greear <greearb at candelatech.com>
    Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>

-- 
Kalle Valo


From michal.kazior at tieto.com  Mon Nov 24 06:17:24 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 24 Nov 2014 15:17:24 +0100
Subject: [PATCH 1/3] ath10k: embed supported chip ids in hw_params
Message-ID: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>

This will make it easier to extend and maintain
list of supported hardware.

As a requirement this moves chip_id checking a
little later because target_version isn't known
until BMI can be queried.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.c | 72 ++++++++++++++++------------------
 drivers/net/wireless/ath/ath10k/core.h |  3 +-
 2 files changed, 36 insertions(+), 39 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index f660553..3904ce3 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -43,11 +43,21 @@ MODULE_PARM_DESC(uart_print, "Uart target debugging");
 MODULE_PARM_DESC(p2p, "Enable ath10k P2P support");
 MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");
 
+static u32 qca988x_supported_chips[] = {
+	/* QCA988X_HW_1_0_CHIP_ID_REV is not supported. It's way too buggy and
+	 * crashes because ath10k doesn't have hacks and workarounds for it.
+	 */
+
+	QCA988X_HW_2_0_CHIP_ID_REV
+};
+
 static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 	{
 		.id = QCA988X_HW_2_0_VERSION,
 		.name = "qca988x hw2.0",
 		.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
+		.supported_chips = qca988x_supported_chips,
+		.num_supported_chips = ARRAY_SIZE(qca988x_supported_chips),
 		.fw = {
 			.dir = QCA988X_HW_2_0_FW_DIR,
 			.fw = QCA988X_HW_2_0_FW_FILE,
@@ -719,10 +729,26 @@ static int ath10k_init_uart(struct ath10k *ar)
 	return 0;
 }
 
+static int ath10k_core_check_chip_id(struct ath10k *ar, u32 chip_id,
+				     const struct ath10k_hw_params *hw_params)
+{
+	u32 hw_revision = MS(chip_id, SOC_CHIP_ID_REV);
+	int i;
+
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n",
+		   chip_id, hw_revision);
+
+	for (i = 0; i < hw_params->num_supported_chips; i++)
+		if (hw_params->supported_chips[i] == hw_revision)
+			return 0;
+
+	return -ENOTSUPP;
+}
+
 static int ath10k_init_hw_params(struct ath10k *ar)
 {
 	const struct ath10k_hw_params *uninitialized_var(hw_params);
-	int i;
+	int i, ret;
 
 	for (i = 0; i < ARRAY_SIZE(ath10k_hw_params_list); i++) {
 		hw_params = &ath10k_hw_params_list[i];
@@ -737,6 +763,13 @@ static int ath10k_init_hw_params(struct ath10k *ar)
 		return -EINVAL;
 	}
 
+	ret = ath10k_core_check_chip_id(ar, ar->chip_id, hw_params);
+	if (ret) {
+		ath10k_err(ar, "unsupported hardware %s chip_id 0x%08x\n",
+			   hw_params->name, ar->chip_id);
+		return ret;
+	}
+
 	ar->hw_params = *hw_params;
 
 	ath10k_dbg(ar, ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n",
@@ -1055,34 +1088,6 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
 	return 0;
 }
 
-static int ath10k_core_check_chip_id(struct ath10k *ar)
-{
-	u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV);
-
-	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n",
-		   ar->chip_id, hw_revision);
-
-	/* Check that we are not using hw1.0 (some of them have same pci id
-	 * as hw2.0) before doing anything else as ath10k crashes horribly
-	 * due to missing hw1.0 workarounds. */
-	switch (hw_revision) {
-	case QCA988X_HW_1_0_CHIP_ID_REV:
-		ath10k_err(ar, "ERROR: qca988x hw1.0 is not supported\n");
-		return -EOPNOTSUPP;
-
-	case QCA988X_HW_2_0_CHIP_ID_REV:
-		/* known hardware revision, continue normally */
-		return 0;
-
-	default:
-		ath10k_warn(ar, "Warning: hardware revision unknown (0x%x), expect problems\n",
-			    ar->chip_id);
-		return 0;
-	}
-
-	return 0;
-}
-
 static void ath10k_core_register_work(struct work_struct *work)
 {
 	struct ath10k *ar = container_of(work, struct ath10k, register_work);
@@ -1130,16 +1135,7 @@ err:
 
 int ath10k_core_register(struct ath10k *ar, u32 chip_id)
 {
-	int status;
-
 	ar->chip_id = chip_id;
-
-	status = ath10k_core_check_chip_id(ar);
-	if (status) {
-		ath10k_err(ar, "Unsupported chip id 0x%08x\n", ar->chip_id);
-		return status;
-	}
-
 	queue_work(ar->workqueue, &ar->register_work);
 
 	return 0;
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 8f86bd3..d37ffd6 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -475,7 +475,8 @@ struct ath10k {
 		u32 id;
 		const char *name;
 		u32 patch_load_addr;
-
+		const u32 *supported_chips;
+		int num_supported_chips;
 		struct ath10k_hw_params_fw {
 			const char *dir;
 			const char *fw;
-- 
1.8.5.3



From michal.kazior at tieto.com  Mon Nov 24 06:17:25 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 24 Nov 2014 15:17:25 +0100
Subject: [PATCH 2/3] ath10k: put board size into hw_params
In-Reply-To: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
References: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1416838646-18801-2-git-send-email-michal.kazior@tieto.com>

This makes it easier to extend the list of
supported hardware.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.c | 8 +++++---
 drivers/net/wireless/ath/ath10k/core.h | 2 ++
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 3904ce3..204aa04 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -63,6 +63,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 			.fw = QCA988X_HW_2_0_FW_FILE,
 			.otp = QCA988X_HW_2_0_OTP_FILE,
 			.board = QCA988X_HW_2_0_BOARD_DATA_FILE,
+			.board_size = QCA988X_BOARD_DATA_SZ,
+			.board_ext_size = QCA988X_BOARD_EXT_DATA_SZ,
 		},
 	},
 };
@@ -156,8 +158,8 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,
 static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data,
 				      size_t data_len)
 {
-	u32 board_data_size = QCA988X_BOARD_DATA_SZ;
-	u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ;
+	u32 board_data_size = ar->hw_params.fw.board_size;
+	u32 board_ext_data_size = ar->hw_params.fw.board_ext_size;
 	u32 board_ext_data_addr;
 	int ret;
 
@@ -203,7 +205,7 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data,
 static int ath10k_download_board_data(struct ath10k *ar, const void *data,
 				      size_t data_len)
 {
-	u32 board_data_size = QCA988X_BOARD_DATA_SZ;
+	u32 board_data_size = ar->hw_params.fw.board_size;
 	u32 address;
 	int ret;
 
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index d37ffd6..1cc81e8 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -482,6 +482,8 @@ struct ath10k {
 			const char *fw;
 			const char *otp;
 			const char *board;
+			size_t board_size;
+			size_t board_ext_size;
 		} fw;
 	} hw_params;
 
-- 
1.8.5.3



From michal.kazior at tieto.com  Mon Nov 24 06:17:26 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 24 Nov 2014 15:17:26 +0100
Subject: [PATCH 3/3] ath10k: move uart pin config into hw_params
In-Reply-To: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
References: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1416838646-18801-3-git-send-email-michal.kazior@tieto.com>

This will make it possible to easily support
different hardware with different uart pin
configuration.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.c | 3 ++-
 drivers/net/wireless/ath/ath10k/core.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 204aa04..0bce152 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -58,6 +58,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 		.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
 		.supported_chips = qca988x_supported_chips,
 		.num_supported_chips = ARRAY_SIZE(qca988x_supported_chips),
+		.uart_pin = 7,
 		.fw = {
 			.dir = QCA988X_HW_2_0_FW_DIR,
 			.fw = QCA988X_HW_2_0_FW_FILE,
@@ -708,7 +709,7 @@ static int ath10k_init_uart(struct ath10k *ar)
 	if (!uart_print)
 		return 0;
 
-	ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7);
+	ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, ar->hw_params.uart_pin);
 	if (ret) {
 		ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);
 		return ret;
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 1cc81e8..f8dd904 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -477,6 +477,7 @@ struct ath10k {
 		u32 patch_load_addr;
 		const u32 *supported_chips;
 		int num_supported_chips;
+		int uart_pin;
 		struct ath10k_hw_params_fw {
 			const char *dir;
 			const char *fw;
-- 
1.8.5.3



From michal.kazior at tieto.com  Mon Nov 24 06:34:08 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon, 24 Nov 2014 15:34:08 +0100
Subject: [PATCH] ath10k: don't drop corrupted mgmt frames
Message-ID: <1416839648-31803-1-git-send-email-michal.kazior@tieto.com>

Some firmware revisions don't seem to deilver
management frames with FCS error via WMI so narrow
down the HTT rule to not drop corrupted management
frames.

This basically increases number of frames ath10k
reports while sniffing.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/htt_rx.c | 13 +++++++++++--
 drivers/net/wireless/ath/ath10k/wmi.c    |  7 +++++--
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 75b2293..85910b2 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1381,6 +1381,8 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
 {
 	struct sk_buff *msdu;
 	struct htt_rx_desc *rxd;
+	bool is_mgmt;
+	bool has_fcs_err;
 
 	msdu = skb_peek(amsdu);
 	rxd = (void *)msdu->data - sizeof(*rxd);
@@ -1394,12 +1396,19 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
 		return false;
 	}
 
+	is_mgmt = !!(rxd->attention.flags &
+		     __cpu_to_le32(RX_ATTENTION_FLAGS_MGMT_TYPE));
+	has_fcs_err = !!(rxd->attention.flags &
+			 __cpu_to_le32(RX_ATTENTION_FLAGS_FCS_ERR));
+
 	/* Management frames are handled via WMI events. The pros of such
 	 * approach is that channel is explicitly provided in WMI events
 	 * whereas HTT doesn't provide channel information for Rxed frames.
+	 *
+	 * However some firmware revisions don't report corrupted frames via
+	 * WMI so don't drop them.
 	 */
-	if (rxd->attention.flags &
-	    __cpu_to_le32(RX_ATTENTION_FLAGS_MGMT_TYPE)) {
+	if (is_mgmt && !has_fcs_err) {
 		ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
 		return false;
 	}
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c2bc828..df948a4 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -1166,8 +1166,11 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 		return 0;
 	}
 
-	if (rx_status & WMI_RX_STATUS_ERR_CRC)
-		status->flag |= RX_FLAG_FAILED_FCS_CRC;
+	if (rx_status & WMI_RX_STATUS_ERR_CRC) {
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
 	if (rx_status & WMI_RX_STATUS_ERR_MIC)
 		status->flag |= RX_FLAG_MMIC_ERROR;
 
-- 
1.8.5.3



From kvalo at qca.qualcomm.com  Mon Nov 24 07:12:47 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 24 Nov 2014 17:12:47 +0200
Subject: [PATCH 1/3] ath10k: Fix shared WEP
In-Reply-To: <1416796657-24657-2-git-send-email-sujith@msujith.org> (Sujith
 Manoharan's message of "Mon, 24 Nov 2014 08:07:35 +0530")
References: <1416796657-24657-1-git-send-email-sujith@msujith.org>
 <1416796657-24657-2-git-send-email-sujith@msujith.org>
Message-ID: <87lhn0639s.fsf@kamboji.qca.qualcomm.com>

Sujith Manoharan <sujith at msujith.org> writes:

> From: Sujith Manoharan <c_manoha at qca.qualcomm.com>
>
> When static keys are used in shared WEP, when a
> station is associated, message 3 is sent with an
> encrypted payload. But, for subsequent
> authentications that are triggered without a
> deauth, the auth frame is decrypted by the HW.
>
> To handle this, check if the WEP keys have already
> been set for the peer and if so, mark the
> frame as decrypted. This scenario can happen
> when a station changes its default TX key and initiates
> a new authentication sequence.
>
> Signed-off-by: Sujith Manoharan <c_manoha at qca.qualcomm.com>

[...]

> +bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
> +				    u8 keyidx)
> +{
> +	struct ath10k_peer *peer;
> +	int i;
> +
> +	/* We don't know which vdev this peer belongs to,
> +	 * since WMI doesn't give us that information.
> +	 *
> +	 * FIXME: multi-bss needs to be handled.
> +	 */
> +	peer = ath10k_peer_find(ar, 0, addr);
> +	if (!peer)
> +		return false;

This requires that data_lock is taken, right? If yes, can you document
that with lockdep_assert_held(), please?

> +static void ath10k_wmi_handle_wep_reauth(struct ath10k *ar,
> +					 struct sk_buff *skb,
> +					 struct ieee80211_rx_status *status)
> +{
> +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
> +	unsigned int hdrlen;
> +	bool peer_key;
> +	u8 *addr, keyidx;

Some kind of comment to document what this workaround is about would be
good to have. For example, the first paragraph from the commit log
sounds perfect.

> +
> +	if (!ieee80211_is_auth(hdr->frame_control) ||
> +	    !ieee80211_has_protected(hdr->frame_control))
> +		return;
> +
> +	hdrlen = ieee80211_hdrlen(hdr->frame_control);
> +	if (skb->len < (hdrlen + IEEE80211_WEP_IV_LEN))
> +		return;
> +
> +	keyidx = skb->data[hdrlen + 3] >> 6;

No magic numbers, please. I didn't find anything for IV internals from
ieee80211.h, not sure if we should add them there or just use ath10k
internal defines.

> +	addr = ieee80211_get_SA(hdr);
> +
> +	spin_lock_bh(&ar->data_lock);
> +	peer_key = ath10k_mac_is_peer_wep_key_set(ar, addr, keyidx);
> +	spin_unlock_bh(&ar->data_lock);
> +
> +	if (peer_key) {
> +		ath10k_dbg(ar, ATH10K_DBG_MAC,
> +			   "wep key present for peer: %pM\n", addr);

"mac wep key present for peer %pM"

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov 24 07:15:38 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 24 Nov 2014 17:15:38 +0200
Subject: [PATCH 2/3] ath10k: Fix locking for WEP keys
In-Reply-To: <1416796657-24657-3-git-send-email-sujith@msujith.org> (Sujith
 Manoharan's message of "Mon, 24 Nov 2014 08:07:36 +0530")
References: <1416796657-24657-1-git-send-email-sujith@msujith.org>
 <1416796657-24657-3-git-send-email-sujith@msujith.org>
Message-ID: <87h9xo6351.fsf@kamboji.qca.qualcomm.com>

Sujith Manoharan <sujith at msujith.org> writes:

> From: Sujith Manoharan <c_manoha at qca.qualcomm.com>
>
> peer->keys needs to be protected by data_lock
> since it is also accessed from the WMI path.
>
> Both install() and clear() routines for peer
> keys modify the key contents, so use the data_lock
> to avoid races.
>
> Signed-off-by: Sujith Manoharan <c_manoha at qca.qualcomm.com>

Can you also document the field with "protected by data_lock" in core.h?

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov 24 07:18:20 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 24 Nov 2014 17:18:20 +0200
Subject: [PATCH v2 04/10] ath10k: make firmware text debug messages more
 verbose.
In-Reply-To: <5470B4D5.7090508@candelatech.com> (Ben Greear's message of "Sat, 
 22 Nov 2014 08:07:49 -0800")
References: <1411507045-18973-1-git-send-email-greearb@candelatech.com>
 <1411507045-18973-4-git-send-email-greearb@candelatech.com>
 <878uj38dbd.fsf@kamboji.qca.qualcomm.com>
 <5470B4D5.7090508@candelatech.com>
Message-ID: <87d28c630j.fsf@kamboji.qca.qualcomm.com>

Ben Greear <greearb at candelatech.com> writes:

> On 11/22/2014 07:28 AM, Kalle Valo wrote:
>> greearb at candelatech.com writes:
>>
>>> From: Ben Greear <greearb at candelatech.com>
>>>
>>> There are not many of these messages producted by the
>>> firmware, but they are generally fairly useful, so print
>>> them at info level.
>>>
>>> Signed-off-by: Ben Greear <greearb at candelatech.com>
>>
>> [...]
>>
>>> --- a/drivers/net/wireless/ath/ath10k/debug.h
>>> +++ b/drivers/net/wireless/ath/ath10k/debug.h
>>> @@ -35,6 +35,7 @@ enum ath10k_debug_mask {
>>>   	ATH10K_DBG_BMI		= 0x00000400,
>>>   	ATH10K_DBG_REGULATORY	= 0x00000800,
>>>   	ATH10K_DBG_TESTMODE	= 0x00001000,
>>> +	ATH10K_DBG_FW_MSG	= 0x00002000,
>>
>> I think FW_MSG is a bit too ambiguous, so I changed this to WMI_PRINT so
>> that it's closer the real event name.
>
> Better than nothing, but my idea was that this flag would be able to affect
> more than one thing related to firmware debugging.  Calling it something about
> WMI does not indicate to me that it is really about firmware debugging.

For other debug methods we can always add a new debug level, or rename
this one.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov 24 07:31:51 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 24 Nov 2014 17:31:51 +0200
Subject: [PATCH] ath10k: Add the target register access and memory dump
 debugfs interface
In-Reply-To: <1416656922-6645-1-git-send-email-yanbol@qti.qualcomm.com> (Yanbo
 Li's message of "Sat, 22 Nov 2014 19:48:42 +0800")
References: <1416656922-6645-1-git-send-email-yanbol@qti.qualcomm.com>
Message-ID: <87wq6k4ntk.fsf@kamboji.qca.qualcomm.com>

Yanbo Li <yanbol at qti.qualcomm.com> writes:

> --- a/drivers/net/wireless/ath/ath10k/debug.c
> +++ b/drivers/net/wireless/ath/ath10k/debug.c
> @@ -22,6 +22,7 @@
>  #include <linux/vmalloc.h>
>  
>  #include "core.h"
> +#include "hif.h"
>  #include "debug.h"
>  #include "hif.h"

hif.h is now included twice.

Let me send a v2. I'll also try splitting the patches as then it makes
it easier to write the commit log.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Mon Nov 24 08:41:38 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 24 Nov 2014 18:41:38 +0200
Subject: [PATCH v2 0/2] ath10k: firmware memory debugfs interface
Message-ID: <20141124164037.29422.14033.stgit@potku.adurom.net>

Hi,

this is v2 of Yanbo's firmware memory debugfs interface.

Changelog:

v2:

* split patches into two

* simplify the commit logs

* remove extra #include "hif.h" from debug.c

---

Yanbo Li (2):
      ath10k: add register access debugfs interface
      ath10k: add memory dump debugfs interface


 drivers/net/wireless/ath/ath10k/core.h  |    2 
 drivers/net/wireless/ath/ath10k/debug.c |  188 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/hif.h   |   37 ++++++
 drivers/net/wireless/ath/ath10k/pci.c   |    3 
 4 files changed, 230 insertions(+)



From kvalo at qca.qualcomm.com  Mon Nov 24 08:41:59 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 24 Nov 2014 18:41:59 +0200
Subject: [PATCH v2 1/2] ath10k: add register access debugfs interface
In-Reply-To: <20141124164037.29422.14033.stgit@potku.adurom.net>
References: <20141124164037.29422.14033.stgit@potku.adurom.net>
Message-ID: <20141124164159.29422.98462.stgit@potku.adurom.net>

From: Yanbo Li <yanbol at qti.qualcomm.com>

Debugfs files reg_addr and reg_val are used for reading and writing to the
firmware (target) registers. reg_addr contains the address to be accessed,
which also needs to be set first, and reg_value is when used for reading and
writing the actual value in ASCII.

To read a value from the firmware register 0x100000:

# echo 0x100000 > reg_addr
# cat reg_value
0x00100000:0x000002d3

To write value 0x2400 to address 0x100000:

# echo 0x100000 > reg_addr
# echo  0x2400 > reg_value
#

Signed-off-by: Yanbo Li <yanbol at qti.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.h  |    2 +
 drivers/net/wireless/ath/ath10k/debug.c |  102 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/hif.h   |   26 ++++++++
 drivers/net/wireless/ath/ath10k/pci.c   |    2 +
 4 files changed, 132 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 8f86bd34e823..5cb4fe97b4ff 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -321,6 +321,8 @@ struct ath10k_debug {
 	u32 fw_dbglog_mask;
 	u32 pktlog_filter;
 
+	u32 reg_addr;
+
 	u8 htt_max_amsdu;
 	u8 htt_max_ampdu;
 
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index f10721da4980..b500cd619c05 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -928,6 +928,102 @@ static const struct file_operations fops_fw_crash_dump = {
 	.llseek = default_llseek,
 };
 
+static ssize_t ath10k_reg_addr_read(struct file *file,
+				    char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 buf[32];
+	unsigned int len = 0;
+	u32 reg_addr;
+
+	spin_lock_bh(&ar->data_lock);
+	reg_addr = ar->debug.reg_addr;
+	spin_unlock_bh(&ar->data_lock);
+
+	len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", reg_addr);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath10k_reg_addr_write(struct file *file,
+				     const char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u32 reg_addr;
+	int ret;
+
+	ret = kstrtou32_from_user(user_buf, count, 0, &reg_addr);
+	if (ret)
+		return ret;
+
+	if (!IS_ALIGNED(reg_addr, 4))
+		return -EFAULT;
+
+	spin_lock_bh(&ar->data_lock);
+	ar->debug.reg_addr = reg_addr;
+	spin_unlock_bh(&ar->data_lock);
+
+	return count;
+}
+
+static const struct file_operations fops_reg_addr = {
+	.read = ath10k_reg_addr_read,
+	.write = ath10k_reg_addr_write,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t ath10k_reg_value_read(struct file *file,
+				     char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 buf[48];
+	unsigned int len;
+	u32 reg_addr, reg_val;
+
+	spin_lock_bh(&ar->data_lock);
+	reg_addr = ar->debug.reg_addr;
+	spin_unlock_bh(&ar->data_lock);
+
+	reg_val = ath10k_hif_read32(ar, reg_addr);
+	len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath10k_reg_value_write(struct file *file,
+				      const char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u32 reg_addr, reg_val;
+	int ret;
+
+	spin_lock_bh(&ar->data_lock);
+	reg_addr = ar->debug.reg_addr;
+	spin_unlock_bh(&ar->data_lock);
+
+	ret = kstrtou32_from_user(user_buf, count, 0, &reg_val);
+	if (ret)
+		return ret;
+
+	ath10k_hif_write32(ar, reg_addr, reg_val);
+
+	return count;
+}
+
+static const struct file_operations fops_reg_value = {
+	.read = ath10k_reg_value_read,
+	.write = ath10k_reg_value_write,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 static int ath10k_debug_htt_stats_req(struct ath10k *ar)
 {
 	u64 cookie;
@@ -1629,6 +1725,12 @@ int ath10k_debug_register(struct ath10k *ar)
 	debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy,
 			    ar, &fops_fw_crash_dump);
 
+	debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar, &fops_reg_addr);
+
+	debugfs_create_file("reg_value", S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar, &fops_reg_value);
+
 	debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
 			    ar, &fops_chip_id);
 
diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
index 30301f5b6051..bad071906540 100644
--- a/drivers/net/wireless/ath/ath10k/hif.h
+++ b/drivers/net/wireless/ath/ath10k/hif.h
@@ -20,6 +20,7 @@
 
 #include <linux/kernel.h>
 #include "core.h"
+#include "debug.h"
 
 struct ath10k_hif_sg_item {
 	u16 transfer_id;
@@ -84,6 +85,10 @@ struct ath10k_hif_ops {
 
 	u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id);
 
+	u32 (*read32)(struct ath10k *ar, u32 address);
+
+	void (*write32)(struct ath10k *ar, u32 address, u32 value);
+
 	/* Power up the device and enter BMI transfer mode for FW download */
 	int (*power_up)(struct ath10k *ar);
 
@@ -187,4 +192,25 @@ static inline int ath10k_hif_resume(struct ath10k *ar)
 	return ar->hif.ops->resume(ar);
 }
 
+static inline u32 ath10k_hif_read32(struct ath10k *ar, u32 address)
+{
+	if (!ar->hif.ops->read32) {
+		ath10k_warn(ar, "hif read32 not supported\n");
+		return 0xdeaddead;
+	}
+
+	return ar->hif.ops->read32(ar, address);
+}
+
+static inline void ath10k_hif_write32(struct ath10k *ar,
+				      u32 address, u32 data)
+{
+	if (!ar->hif.ops->write32) {
+		ath10k_warn(ar, "hif write32 not supported\n");
+		return;
+	}
+
+	ar->hif.ops->write32(ar, address, data);
+}
+
 #endif /* _HIF_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 3a6b8a5ca96c..328ab6c5d053 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1998,6 +1998,8 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
 	.get_free_queue_number	= ath10k_pci_hif_get_free_queue_number,
 	.power_up		= ath10k_pci_hif_power_up,
 	.power_down		= ath10k_pci_hif_power_down,
+	.read32			= ath10k_pci_read32,
+	.write32		= ath10k_pci_write32,
 #ifdef CONFIG_PM
 	.suspend		= ath10k_pci_hif_suspend,
 	.resume			= ath10k_pci_hif_resume,



From kvalo at qca.qualcomm.com  Mon Nov 24 08:42:08 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 24 Nov 2014 18:42:08 +0200
Subject: [PATCH v2 2/2] ath10k: add memory dump debugfs interface
In-Reply-To: <20141124164037.29422.14033.stgit@potku.adurom.net>
References: <20141124164037.29422.14033.stgit@potku.adurom.net>
Message-ID: <20141124164208.29422.76134.stgit@potku.adurom.net>

From: Yanbo Li <yanbol at qti.qualcomm.com>

Add mem_val debugfs file for dumping the firmware (target) memory and also for
writing to the memory. The firmware memory is accessed through one file which
uses position of the file as the firmware memory address. For example, with dd
use skip parameter for the address.

Beucase target memory width is 32 bits it's strongly recommended to use
blocksize divisable with 4 when using this interface. For example, when using
dd use bs=4 to set the block size to 4 and remember to divide both count and
skip values with four.

To read 4 kB chunk from address 0x400000:

dd if=mem_value bs=4 count=1024 skip=1048576 | xxd -g1

To write value 0x01020304 to address 0x400400:

echo 0x01020304 | xxd -r | dd of=mem_value bs=4 seek=1048832

To read 4 KB chunk of memory and then write back after edit:

dd if=mem_value of=tmp.bin bs=4 count=1024 skip=1048576
emacs tmp.bin
dd if=tmp.bin of=mem_value bs=4 count=1024 seek=1048576

Signed-off-by: Yanbo Li <yanbol at qti.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/debug.c |   86 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/hif.h   |   11 ++++
 drivers/net/wireless/ath/ath10k/pci.c   |    1 
 3 files changed, 98 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index b500cd619c05..3988220e3e66 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1024,6 +1024,89 @@ static const struct file_operations fops_reg_value = {
 	.llseek = default_llseek,
 };
 
+static ssize_t ath10k_mem_value_read(struct file *file,
+				     char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 *buf;
+	int ret;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	if (!count)
+		return 0;
+
+	buf = vmalloc(count);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = ath10k_hif_diag_read(ar, *ppos, buf, count);
+	if (ret) {
+		ath10k_warn(ar, "failed to read address 0x%08x via diagnose window from debugfs: %d\n",
+			    (u32)(*ppos), ret);
+		goto read_err;
+	}
+
+	ret = copy_to_user(user_buf, buf, count);
+	if (ret == count)
+		return -EFAULT;
+
+	count -= ret;
+	*ppos += count;
+	ret = count;
+
+read_err:
+	vfree(buf);
+	return ret;
+}
+
+static ssize_t ath10k_mem_value_write(struct file *file,
+				      const char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 *buf;
+	int ret;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	if (!count)
+		return 0;
+
+	buf = vmalloc(count);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = copy_from_user(buf, user_buf, count);
+	if (ret)
+		goto err_free_copy;
+
+	ret = ath10k_hif_diag_write(ar, *ppos, buf, count);
+	if (ret) {
+		ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n",
+			    (u32)(*ppos), ret);
+		goto err_free_copy;
+	}
+
+	*ppos += count;
+	ret = count;
+
+err_free_copy:
+	vfree(buf);
+	return ret;
+}
+
+static const struct file_operations fops_mem_value = {
+	.read = ath10k_mem_value_read,
+	.write = ath10k_mem_value_write,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 static int ath10k_debug_htt_stats_req(struct ath10k *ar)
 {
 	u64 cookie;
@@ -1731,6 +1814,9 @@ int ath10k_debug_register(struct ath10k *ar)
 	debugfs_create_file("reg_value", S_IRUSR | S_IWUSR,
 			    ar->debug.debugfs_phy, ar, &fops_reg_value);
 
+	debugfs_create_file("mem_value", S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar, &fops_mem_value);
+
 	debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
 			    ar, &fops_chip_id);
 
diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
index bad071906540..6ac552304546 100644
--- a/drivers/net/wireless/ath/ath10k/hif.h
+++ b/drivers/net/wireless/ath/ath10k/hif.h
@@ -48,6 +48,8 @@ struct ath10k_hif_ops {
 	int (*diag_read)(struct ath10k *ar, u32 address, void *buf,
 			 size_t buf_len);
 
+	int (*diag_write)(struct ath10k *ar, u32 address, const void *data,
+			  int nbytes);
 	/*
 	 * API to handle HIF-specific BMI message exchanges, this API is
 	 * synchronous and only allowed to be called from a context that
@@ -113,6 +115,15 @@ static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf
 	return ar->hif.ops->diag_read(ar, address, buf, buf_len);
 }
 
+static inline int ath10k_hif_diag_write(struct ath10k *ar, u32 address,
+					const void *data, int nbytes)
+{
+	if (!ar->hif.ops->diag_write)
+		return -EOPNOTSUPP;
+
+	return ar->hif.ops->diag_write(ar, address, data, nbytes);
+}
+
 static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar,
 					      void *request, u32 request_len,
 					      void *response, u32 *response_len)
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 328ab6c5d053..0816098af578 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1988,6 +1988,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
 static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
 	.tx_sg			= ath10k_pci_hif_tx_sg,
 	.diag_read		= ath10k_pci_hif_diag_read,
+	.diag_write		= ath10k_pci_diag_write_mem,
 	.exchange_bmi_msg	= ath10k_pci_hif_exchange_bmi_msg,
 	.start			= ath10k_pci_hif_start,
 	.stop			= ath10k_pci_hif_stop,



From kvalo at qca.qualcomm.com  Mon Nov 24 08:52:58 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 24 Nov 2014 18:52:58 +0200
Subject: [PATCH v2 2/2] ath10k: add memory dump debugfs interface
In-Reply-To: <20141124164208.29422.76134.stgit@potku.adurom.net> (Kalle Valo's
 message of "Mon, 24 Nov 2014 18:42:08 +0200")
References: <20141124164037.29422.14033.stgit@potku.adurom.net>
 <20141124164208.29422.76134.stgit@potku.adurom.net>
Message-ID: <87mw7g4k2d.fsf@kamboji.qca.qualcomm.com>

Kalle Valo <kvalo at qca.qualcomm.com> writes:

> +	ret = copy_from_user(buf, user_buf, count);
> +	if (ret)
> +		goto err_free_copy;
> +
> +	ret = ath10k_hif_diag_write(ar, *ppos, buf, count);
> +	if (ret) {
> +		ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n",
> +			    (u32)(*ppos), ret);
> +		goto err_free_copy;
> +	}
> +
> +	*ppos += count;
> +	ret = count;
> +
> +err_free_copy:
> +	vfree(buf);
> +	return ret;

This introduces a new smatch warning:

drivers/net/wireless/ath/ath10k/debug.c:1100 ath10k_mem_value_write()
warn: maybe return -EFAULT instead of the bytes remaining?

I think it should be like this:

ret = copy_from_user(buf, user_buf, count);
if (ret) {
        ret = -EFAULT;
	goto err_free_copy;
}

Comments?

-- 
Kalle Valo


From greearb at candelatech.com  Mon Nov 24 10:35:56 2014
From: greearb at candelatech.com (Ben Greear)
Date: Mon, 24 Nov 2014 10:35:56 -0800
Subject: [PATCH] ath10k: Do not limit RTS threshold value to 2347
In-Reply-To: <1416830240-3019-1-git-send-email-nataraja@qti.qualcomm.com>
References: <1416830240-3019-1-git-send-email-nataraja@qti.qualcomm.com>
Message-ID: <54737A8C.40102@candelatech.com>

On 11/24/2014 03:57 AM, Vivek Natarajan wrote:
> Increase the rts threshold from the legacy value of 2347 to support higher
> threshold limit.

Does any firmware actually support RTS?  It didn't work last I tested
it on 10.1.

Thanks,
Ben

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



From greearb at candelatech.com  Mon Nov 24 10:54:35 2014
From: greearb at candelatech.com (Ben Greear)
Date: Mon, 24 Nov 2014 10:54:35 -0800
Subject: [PATCH 2/2] ath10k: re-config ht_caps when chainmask is modified.
In-Reply-To: <87egss7tv3.fsf@kamboji.qca.qualcomm.com>
References: <1411576506-11815-1-git-send-email-greearb@candelatech.com>
 <1411576506-11815-2-git-send-email-greearb@candelatech.com>
 <87ioi47vvd.fsf@kamboji.qca.qualcomm.com>
 <87egss7tv3.fsf@kamboji.qca.qualcomm.com>
Message-ID: <54737EEB.2050104@candelatech.com>

On 11/24/2014 02:53 AM, Kalle Valo wrote:
> Kalle Valo <kvalo at qca.qualcomm.com> writes:
> 
>>> @@ -2537,6 +2560,17 @@ static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
>>>  	ar->cfg_tx_chainmask = tx_ant;
>>>  	ar->cfg_rx_chainmask = rx_ant;
>>>  
>>> +	ht_cap = ath10k_get_ht_cap(ar, true);
>>> +	vht_cap = ath10k_create_vht_cap(ar, true);
>>> +
>>> +	if (ar->phy_capability & WHAL_WLAN_11G_CAPABILITY)
>>> +		ar->mac.sbands[IEEE80211_BAND_2GHZ].ht_cap = ht_cap;
>>> +
>>> +	if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) {
>>> +		ar->mac.sbands[IEEE80211_BAND_5GHZ].ht_cap = ht_cap;
>>> +		ar->mac.sbands[IEEE80211_BAND_5GHZ].vht_cap = vht_cap;
>>> +	}
>>
>> So this modifies stryct wiphy::bands after we have called
>> ieee80211_register_hw(). Is this something which both cfg80211 and
>> mac80211 support? I didn't find the documentation mentioning anything
>> about this so I got a bit worried.
> 
> Johannes mentioned me that this is not supported so I am reluctant to
> take these. Unless I'm missing something, of course.

I did test the code, and it seems to work fine.  But, I could
be missing some subtle issues.

Any idea how this is supposed to be done?

Thanks,
Ben

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



From psidhu at gateworks.com  Mon Nov 24 15:31:19 2014
From: psidhu at gateworks.com (Pushpal Sidhu)
Date: Mon, 24 Nov 2014 15:31:19 -0800
Subject: htt rx stopped. cannot recover
In-Reply-To: <CA+BoTQn2xi3ssEn+HGc_5pgdb5Xrw4SPqBD4-QaWT1d9LqieMA@mail.gmail.com>
References: <CAD1M060Y+3r_-J12ZqT4TqddUf9tJHKCEPJ0DhFJ1sCiXimdVw@mail.gmail.com>
 <5461382B.6070607@candelatech.com>
 <CAD1M062xcGu2EJzxaXYQt5uHyDxHpEE+FDiPB4SBirXX5ePz_A@mail.gmail.com>
 <54613C13.9010008@candelatech.com>
 <CAD1M061wRo5MqmKYy8jw9fKpraA0DFJTh4k+QNzLkayLmBttfA@mail.gmail.com>
 <CA+BoTQk7idFbyYzLxKCgmSQ=zzQTraOJ-fy5_qhDpzkueQe8KQ@mail.gmail.com>
 <CAD1M063n=WGeQRJKycvWYGMZRFN4gabM56dgeX_4tf8W8hyUKA@mail.gmail.com>
 <CA+BoTQkfPJp4tg8eR4OJDs2Cf_s0x36QYD-Yq6fTQ41c1jm6TA@mail.gmail.com>
 <CAD1M0638VrB_hAqAn-H-02cjF6ivQzFBwtqs02BxgzLRdpCGsg@mail.gmail.com>
 <CA+BoTQkdZ52GKaGzKL_NU8TD5fCxxxiObj6RnBXk1Rz=426N7w@mail.gmail.com>
 <CAD1M062FNiiAD=Q6zGX8ooSfrQTj8gi_1oDSdEPjAQsaNPrjEw@mail.gmail.com>
 <CA+BoTQn2xi3ssEn+HGc_5pgdb5Xrw4SPqBD4-QaWT1d9LqieMA@mail.gmail.com>
Message-ID: <CAD1M061c2u8kykkPPRCWSTVBaTj=cbgy8rbzqrE3XzoOew2bHA@mail.gmail.com>

On Tue, Nov 18, 2014 at 10:44 PM, Michal Kazior <michal.kazior at tieto.com> wrote:
>> While running the extended test, at about 7 hours of continuous
>> testing with the two boards without a PCIe bridge (configured as a
>> wireless bridge e.g. 4addr=on), the STAtion has a kernel panic that
>> seems to be caused by a double free or something similar. Log is
>> located here (glad I set 'debug' in kernel cmdline):
>> http://dpaste.com/1G77X7N (most interesting info located between times
>> [25684.512971] - [25684.587585]).
>
> Is this on vanilla ath10k code or did you ignore the rx_confused flag
> during the test?

Vanilla code.

> Anyway it'd be lovely if you could get the code line for
> ath10k_htt_txrx_compl_task+0x100 (e.g. via `gdb` with `l *
> ath10k_htt_txrx_compl_task+0x100)`.

I'm on a slightly constrained system, but here's the info I could grab
(I couldn't get the exact code line):

(gdb) list *ath10k_htt_txrx_compl_task+0x100
0xca3c is in ath10k_htt_txrx_compl_task (include/linux/skbuff.h:987).
982     include/linux/skbuff.h: No such file or directory.
(gdb) list *ath10k_htt_txrx_compl_task+0x100/0x544
0xc93c is in ath10k_htt_txrx_compl_task (include/linux/spinlock.h:290).
285     include/linux/spinlock.h: No such file or directory.

However, if I were to make a guess, I would think the the oops
occurred in the rx_ring.lock when freeing.

>From your comment a few emails back, you mentioned that a possible
workaround is to "keep on syncing dma to cpu and checking the
MSDU_DONE bit for a few msecs." I tried this out and found (waited an
infinite amount of time just to verify) that it would never quit out,
meaning the memory wasn't there in the first place.

- Pushpal


From xerofoify at gmail.com  Mon Nov 24 18:45:55 2014
From: xerofoify at gmail.com (nick)
Date: Mon, 24 Nov 2014 21:45:55 -0500
Subject: Fix Me in htc.c
Message-ID: <5473ED63.8070601@gmail.com>

Greetings Kalle and John,
I am wondering about what amount we need to reserve for amount of bytes needed for the function, ath10k_htc_build_tx_ctrl_skb in htc.c If one of you can send me the amount of bytes we need to 
reserve for this to function correctly, I will gladly write a patch for this :).
Nick


From sujith at msujith.org  Mon Nov 24 21:28:57 2014
From: sujith at msujith.org (Sujith Manoharan)
Date: Tue, 25 Nov 2014 10:58:57 +0530
Subject: [PATCH 1/3] ath10k: Fix shared WEP
In-Reply-To: <87lhn0639s.fsf@kamboji.qca.qualcomm.com>
References: <1416796657-24657-1-git-send-email-sujith@msujith.org>
 <1416796657-24657-2-git-send-email-sujith@msujith.org>
 <87lhn0639s.fsf@kamboji.qca.qualcomm.com>
Message-ID: <21620.5017.657509.251220@gargle.gargle.HOWL>

Kalle Valo wrote:
> No magic numbers, please. I didn't find anything for IV internals from
> ieee80211.h, not sure if we should add them there or just use ath10k
> internal defines.

We are just retrieving the keyidx from the IV - not sure adding a couple
of macros for "6" and "3" will make any difference.

Sujith


From kvalo at qca.qualcomm.com  Mon Nov 24 21:53:12 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 25 Nov 2014 07:53:12 +0200
Subject: [PATCH 1/3] ath10k: Fix shared WEP
In-Reply-To: <21620.5017.657509.251220@gargle.gargle.HOWL> (Sujith Manoharan's
 message of "Tue, 25 Nov 2014 10:58:57 +0530")
References: <1416796657-24657-1-git-send-email-sujith@msujith.org>
 <1416796657-24657-2-git-send-email-sujith@msujith.org>
 <87lhn0639s.fsf@kamboji.qca.qualcomm.com>
 <21620.5017.657509.251220@gargle.gargle.HOWL>
Message-ID: <87y4qz3jxz.fsf@kamboji.qca.qualcomm.com>

Sujith Manoharan <sujith at msujith.org> writes:

> Kalle Valo wrote:
>> No magic numbers, please. I didn't find anything for IV internals from
>> ieee80211.h, not sure if we should add them there or just use ath10k
>> internal defines.
>
> We are just retrieving the keyidx from the IV - not sure adding a couple
> of macros for "6" and "3" will make any difference.

It won't make a difference for you but it will for someone else reading
that part of code.

keyidx = skb->data[hdrlen + WEP_HDR_IV_LEN] >> WEP_HDR_KEY_ID_LSB;

versus:

keyidx = skb->data[hdrlen + 3] >> 6;

(I didn't check the standard so tha names can be totally wrong.)

-- 
Kalle Valo


From sujith at msujith.org  Mon Nov 24 22:17:00 2014
From: sujith at msujith.org (Sujith Manoharan)
Date: Tue, 25 Nov 2014 11:47:00 +0530
Subject: [PATCH v2 3/3] ath10k: Fix bug reported by lockdep
In-Reply-To: <1416896220-29691-1-git-send-email-sujith@msujith.org>
References: <1416896220-29691-1-git-send-email-sujith@msujith.org>
Message-ID: <1416896220-29691-3-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha at qca.qualcomm.com>

ath10k_tx_wep_key_work() acquires conf_mutex, so
cancelling it when conf_mutex is already taken
in ath10k_remove_interface() is incorrect, so
move it outside the lock.

Snippet from the lockdep report:

kernel: ======================================================
kernel: [ INFO: possible circular locking dependency detected ]
kernel: 3.18.0-rc5-wl-debug #34 Tainted: G           O
kernel: -------------------------------------------------------
kernel: hostapd/451 is trying to acquire lock:
kernel:  ((&arvif->wep_key_work)){+.+...}, at: [<ffffffff810872d5>] flush_work+0x5/0x290
kernel: but task is already holding lock:
kernel:  (&ar->conf_mutex){+.+.+.}, at: [<ffffffffa0b99f00>] ath10k_remove_interface+0x40/0x290 [ath10k_core]
kernel: which lock already depends on the new lock.

Signed-off-by: Sujith Manoharan <c_manoha at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 01de6f3..cf1e579 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3043,10 +3043,10 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
 	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 	int ret;
 
-	mutex_lock(&ar->conf_mutex);
-
 	cancel_work_sync(&arvif->wep_key_work);
 
+	mutex_lock(&ar->conf_mutex);
+
 	spin_lock_bh(&ar->data_lock);
 	ath10k_mac_vif_beacon_cleanup(arvif);
 	spin_unlock_bh(&ar->data_lock);
-- 
2.1.3



From sujith at msujith.org  Mon Nov 24 22:16:59 2014
From: sujith at msujith.org (Sujith Manoharan)
Date: Tue, 25 Nov 2014 11:46:59 +0530
Subject: [PATCH v2 2/3] ath10k: Fix locking for WEP keys
In-Reply-To: <1416896220-29691-1-git-send-email-sujith@msujith.org>
References: <1416896220-29691-1-git-send-email-sujith@msujith.org>
Message-ID: <1416896220-29691-2-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha at qca.qualcomm.com>

peer->keys needs to be protected by data_lock
since it is also accessed from the WMI path.

Both install() and clear() routines for peer
keys modify the key contents, so use the data_lock
to avoid races.

Signed-off-by: Sujith Manoharan <c_manoha at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.h | 2 ++
 drivers/net/wireless/ath/ath10k/mac.c  | 4 ++++
 2 files changed, 6 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 8f86bd3..73da1bb 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -218,6 +218,8 @@ struct ath10k_peer {
 	int vdev_id;
 	u8 addr[ETH_ALEN];
 	DECLARE_BITMAP(peer_ids, ATH10K_MAX_NUM_PEER_IDS);
+
+	/* protected by ar->data_lock */
 	struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
 };
 
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index fb95d4d..01de6f3 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -136,7 +136,9 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
 		if (ret)
 			return ret;
 
+		spin_lock_bh(&ar->data_lock);
 		peer->keys[i] = arvif->wep_keys[i];
+		spin_unlock_bh(&ar->data_lock);
 	}
 
 	return 0;
@@ -173,7 +175,9 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
 			ath10k_warn(ar, "failed to remove peer wep key %d: %d\n",
 				    i, ret);
 
+		spin_lock_bh(&ar->data_lock);
 		peer->keys[i] = NULL;
+		spin_unlock_bh(&ar->data_lock);
 	}
 
 	return first_errno;
-- 
2.1.3



From sujith at msujith.org  Mon Nov 24 22:16:58 2014
From: sujith at msujith.org (Sujith Manoharan)
Date: Tue, 25 Nov 2014 11:46:58 +0530
Subject: [PATCH v2 1/3] ath10k: Fix shared WEP
Message-ID: <1416896220-29691-1-git-send-email-sujith@msujith.org>

From: Sujith Manoharan <c_manoha at qca.qualcomm.com>

When static keys are used in shared WEP, when a
station is associated, message 3 is sent with an
encrypted payload. But, for subsequent
authentications that are triggered without a
deauth, the auth frame is decrypted by the HW.

To handle this, check if the WEP keys have already
been set for the peer and if so, mark the
frame as decrypted. This scenario can happen
when a station changes its default TX key and initiates
a new authentication sequence.

Signed-off-by: Sujith Manoharan <c_manoha at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 25 ++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/mac.h |  4 ++++
 drivers/net/wireless/ath/ath10k/wmi.c | 36 +++++++++++++++++++++++++++++++++++
 3 files changed, 65 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 1245ac8..fb95d4d 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -179,6 +179,31 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
 	return first_errno;
 }
 
+bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
+				    u8 keyidx)
+{
+	struct ath10k_peer *peer;
+	int i;
+
+	lockdep_assert_held(&ar->data_lock);
+
+	/* We don't know which vdev this peer belongs to,
+	 * since WMI doesn't give us that information.
+	 *
+	 * FIXME: multi-bss needs to be handled.
+	 */
+	peer = ath10k_peer_find(ar, 0, addr);
+	if (!peer)
+		return false;
+
+	for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
+		if (peer->keys[i] && peer->keys[i]->keyidx == keyidx)
+			return true;
+	}
+
+	return false;
+}
+
 static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
 				 struct ieee80211_key_conf *key)
 {
diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
index 4e3c989..6829611 100644
--- a/drivers/net/wireless/ath/ath10k/mac.h
+++ b/drivers/net/wireless/ath/ath10k/mac.h
@@ -21,6 +21,8 @@
 #include <net/mac80211.h>
 #include "core.h"
 
+#define WEP_KEYID_SHIFT 6
+
 struct ath10k_generic_iter {
 	struct ath10k *ar;
 	int ret;
@@ -41,6 +43,8 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work);
 void ath10k_halt(struct ath10k *ar);
 void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif);
 void ath10k_drain_tx(struct ath10k *ar);
+bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
+				    u8 keyidx);
 
 static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
 {
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c300a53..c7e4b9f 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -1113,6 +1113,40 @@ static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band)
 	return rate_idx;
 }
 
+/* If keys are configured, HW decrypts all frames
+ * with protected bit set. Mark such frames as decrypted.
+ */
+static void ath10k_wmi_handle_wep_reauth(struct ath10k *ar,
+					 struct sk_buff *skb,
+					 struct ieee80211_rx_status *status)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	unsigned int hdrlen;
+	bool peer_key;
+	u8 *addr, keyidx;
+
+	if (!ieee80211_is_auth(hdr->frame_control) ||
+	    !ieee80211_has_protected(hdr->frame_control))
+		return;
+
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
+	if (skb->len < (hdrlen + IEEE80211_WEP_IV_LEN))
+		return;
+
+	keyidx = skb->data[hdrlen + (IEEE80211_WEP_IV_LEN - 1)] >> WEP_KEYID_SHIFT;
+	addr = ieee80211_get_SA(hdr);
+
+	spin_lock_bh(&ar->data_lock);
+	peer_key = ath10k_mac_is_peer_wep_key_set(ar, addr, keyidx);
+	spin_unlock_bh(&ar->data_lock);
+
+	if (peer_key) {
+		ath10k_dbg(ar, ATH10K_DBG_MAC,
+			   "mac wep key present for peer %pM\n", addr);
+		status->flag |= RX_FLAG_DECRYPTED;
+	}
+}
+
 static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_mgmt_rx_event_v1 *ev_v1;
@@ -1200,6 +1234,8 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 	hdr = (struct ieee80211_hdr *)skb->data;
 	fc = le16_to_cpu(hdr->frame_control);
 
+	ath10k_wmi_handle_wep_reauth(ar, skb, status);
+
 	/* FW delivers WEP Shared Auth frame with Protected Bit set and
 	 * encrypted payload. However in case of PMF it delivers decrypted
 	 * frames with Protected Bit set. */
-- 
2.1.3



From kvalo at qca.qualcomm.com  Tue Nov 25 00:01:55 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 25 Nov 2014 10:01:55 +0200
Subject: [PATCH 3/3] ath10k: fix station count enforcement
In-Reply-To: <1416834909-7130-3-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Mon, 24 Nov 2014 14:15:09 +0100")
References: <1416834909-7130-1-git-send-email-michal.kazior@tieto.com>
 <1416834909-7130-3-git-send-email-michal.kazior@tieto.com>
Message-ID: <87d28b3dzg.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> The number of peers isn't directly translatable to
> the number of stations because ath10k needs to
> reserve a few extra peers for special cases like
> multi-vif concurrency.
>
> The previous limit was 126 and 15 stations in AP
> mode for 10.x and main firmware branches
> respectively. The limit is now 128 and 16 which
> was the original intention.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

[...]

> +static void ath10k_core_init_max_sta_count(struct ath10k *ar)
> +{
> +	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
> +		ar->max_num_peers = TARGET_10X_NUM_PEERS;
> +		ar->max_num_stations = TARGET_10X_NUM_STATIONS;
> +	} else {
> +		ar->max_num_peers = TARGET_NUM_PEERS;
> +		ar->max_num_stations = TARGET_NUM_STATIONS;
> +	}
> +}
> +
>  int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
>  {
>  	int status;
> @@ -939,6 +950,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
>  	else
>  		ar->free_vdev_map = (1LL << TARGET_NUM_VDEVS) - 1;
>  
> +	ath10k_core_init_max_sta_count(ar);

I don't see the need to call this during every firmware start as these
are not changed afterwards. I think it would be better to call this once
just after ath10k_core_fetch_firmware_files() is called.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 25 00:08:32 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 25 Nov 2014 10:08:32 +0200
Subject: [PATCH 1/2] ath10k: move create-ht-cap methods above set-antenna.
In-Reply-To: <1411576506-11815-1-git-send-email-greearb@candelatech.com>
 (greearb@candelatech.com's message of "Wed, 24 Sep 2014 09:35:05
 -0700")
References: <1411576506-11815-1-git-send-email-greearb@candelatech.com>
Message-ID: <874mtn3dof.fsf@kamboji.qca.qualcomm.com>

greearb at candelatech.com writes:

> From: Ben Greear <greearb at candelatech.com>
>
> We will need to use these in set-antenna, so move them
> so that we do not have to define the method signatures.
>
> Signed-off-by: Ben Greear <greearb at candelatech.com>

I'm dropping these two patches. Please resend once we figure out how to
handle the band updated.

-- 
Kalle Valo


From michal.kazior at tieto.com  Tue Nov 25 00:38:41 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue, 25 Nov 2014 09:38:41 +0100
Subject: [PATCH 3/3] ath10k: fix station count enforcement
In-Reply-To: <87d28b3dzg.fsf@kamboji.qca.qualcomm.com>
References: <1416834909-7130-1-git-send-email-michal.kazior@tieto.com>
 <1416834909-7130-3-git-send-email-michal.kazior@tieto.com>
 <87d28b3dzg.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CA+BoTQmf6+U20083pHxMdDPMDZf=MNoup+CxBTn=azLZupQYPw@mail.gmail.com>

On 25 November 2014 at 09:01, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Michal Kazior <michal.kazior at tieto.com> writes:
>
>> The number of peers isn't directly translatable to
>> the number of stations because ath10k needs to
>> reserve a few extra peers for special cases like
>> multi-vif concurrency.
>>
>> The previous limit was 126 and 15 stations in AP
>> mode for 10.x and main firmware branches
>> respectively. The limit is now 128 and 16 which
>> was the original intention.
>>
>> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
>
> [...]
>
>> +static void ath10k_core_init_max_sta_count(struct ath10k *ar)
>> +{
>> +     if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
>> +             ar->max_num_peers = TARGET_10X_NUM_PEERS;
>> +             ar->max_num_stations = TARGET_10X_NUM_STATIONS;
>> +     } else {
>> +             ar->max_num_peers = TARGET_NUM_PEERS;
>> +             ar->max_num_stations = TARGET_NUM_STATIONS;
>> +     }
>> +}
>> +
>>  int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
>>  {
>>       int status;
>> @@ -939,6 +950,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
>>       else
>>               ar->free_vdev_map = (1LL << TARGET_NUM_VDEVS) - 1;
>>
>> +     ath10k_core_init_max_sta_count(ar);
>
> I don't see the need to call this during every firmware start as these
> are not changed afterwards. I think it would be better to call this once
> just after ath10k_core_fetch_firmware_files() is called.

Hmm.. It makes sense but now that I think about it the max number of
peers should actually depend on WMI_SERVICE_IRAM_TIDS which is known
after booting firmware. However since only 10.x was released with the
service enabled we used fw_features. So.. yeah. I can move the
function call if you want though.


Micha?


From kvalo at qca.qualcomm.com  Tue Nov 25 00:39:55 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 25 Nov 2014 10:39:55 +0200
Subject: [PATCH v2 1/2] ath10k: add register access debugfs interface
In-Reply-To: <20141124164159.29422.98462.stgit@potku.adurom.net> (Kalle Valo's
 message of "Mon, 24 Nov 2014 18:41:59 +0200")
References: <20141124164037.29422.14033.stgit@potku.adurom.net>
 <20141124164159.29422.98462.stgit@potku.adurom.net>
Message-ID: <87vbm31xno.fsf@kamboji.qca.qualcomm.com>

Kalle Valo <kvalo at qca.qualcomm.com> writes:

> +static ssize_t ath10k_reg_value_read(struct file *file,
> +				     char __user *user_buf,
> +				     size_t count, loff_t *ppos)
> +{
> +	struct ath10k *ar = file->private_data;
> +	u8 buf[48];
> +	unsigned int len;
> +	u32 reg_addr, reg_val;
> +
> +	spin_lock_bh(&ar->data_lock);
> +	reg_addr = ar->debug.reg_addr;
> +	spin_unlock_bh(&ar->data_lock);
> +
> +	reg_val = ath10k_hif_read32(ar, reg_addr);
> +	len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val);
> +
> +	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
> +}

I just realised that we need to check ar->state to make sure that
firmware is running. Because of that I'll need to change the data_lock
to conf_mutex as well.

> +static ssize_t ath10k_reg_value_write(struct file *file,
> +				      const char __user *user_buf,
> +				      size_t count, loff_t *ppos)
> +{
> +	struct ath10k *ar = file->private_data;
> +	u32 reg_addr, reg_val;
> +	int ret;
> +
> +	spin_lock_bh(&ar->data_lock);
> +	reg_addr = ar->debug.reg_addr;
> +	spin_unlock_bh(&ar->data_lock);
> +
> +	ret = kstrtou32_from_user(user_buf, count, 0, &reg_val);
> +	if (ret)
> +		return ret;
> +
> +	ath10k_hif_write32(ar, reg_addr, reg_val);
> +
> +	return count;
> +}

And same here as well. I'll send v3.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 25 00:41:25 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 25 Nov 2014 10:41:25 +0200
Subject: [PATCH v2 2/2] ath10k: add memory dump debugfs interface
In-Reply-To: <20141124164208.29422.76134.stgit@potku.adurom.net> (Kalle Valo's
 message of "Mon, 24 Nov 2014 18:42:08 +0200")
References: <20141124164037.29422.14033.stgit@potku.adurom.net>
 <20141124164208.29422.76134.stgit@potku.adurom.net>
Message-ID: <87r3wr1xl6.fsf@kamboji.qca.qualcomm.com>

Kalle Valo <kvalo at qca.qualcomm.com> writes:

> +static ssize_t ath10k_mem_value_read(struct file *file,
> +				     char __user *user_buf,
> +				     size_t count, loff_t *ppos)
> +{
> +	struct ath10k *ar = file->private_data;
> +	u8 *buf;
> +	int ret;
> +
> +	if (*ppos < 0)
> +		return -EINVAL;
> +
> +	if (!count)
> +		return 0;
> +
> +	buf = vmalloc(count);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	ret = ath10k_hif_diag_read(ar, *ppos, buf, count);
> +	if (ret) {
> +		ath10k_warn(ar, "failed to read address 0x%08x via diagnose window from debugfs: %d\n",
> +			    (u32)(*ppos), ret);
> +		goto read_err;
> +	}
> +

[...]

> +static ssize_t ath10k_mem_value_write(struct file *file,
> +				      const char __user *user_buf,
> +				      size_t count, loff_t *ppos)
> +{
> +	struct ath10k *ar = file->private_data;
> +	u8 *buf;
> +	int ret;
> +
> +	if (*ppos < 0)
> +		return -EINVAL;
> +
> +	if (!count)
> +		return 0;
> +
> +	buf = vmalloc(count);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	ret = copy_from_user(buf, user_buf, count);
> +	if (ret)
> +		goto err_free_copy;
> +
> +	ret = ath10k_hif_diag_write(ar, *ppos, buf, count);
> +	if (ret) {
> +		ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n",
> +			    (u32)(*ppos), ret);
> +		goto err_free_copy;
> +	}

In these two functions we also need to check ar->state.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 25 00:58:39 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 25 Nov 2014 10:58:39 +0200
Subject: [PATCH 3/3] ath10k: fix station count enforcement
In-Reply-To: <CA+BoTQmf6+U20083pHxMdDPMDZf=MNoup+CxBTn=azLZupQYPw@mail.gmail.com>
 (Michal Kazior's message of "Tue, 25 Nov 2014 09:38:41 +0100")
References: <1416834909-7130-1-git-send-email-michal.kazior@tieto.com>
 <1416834909-7130-3-git-send-email-michal.kazior@tieto.com>
 <87d28b3dzg.fsf@kamboji.qca.qualcomm.com>
 <CA+BoTQmf6+U20083pHxMdDPMDZf=MNoup+CxBTn=azLZupQYPw@mail.gmail.com>
Message-ID: <87ioi31wsg.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

>>>  int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
>>>  {
>>>       int status;
>>> @@ -939,6 +950,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
>>>       else
>>>               ar->free_vdev_map = (1LL << TARGET_NUM_VDEVS) - 1;
>>>
>>> +     ath10k_core_init_max_sta_count(ar);
>>
>> I don't see the need to call this during every firmware start as these
>> are not changed afterwards. I think it would be better to call this once
>> just after ath10k_core_fetch_firmware_files() is called.
>
> Hmm.. It makes sense but now that I think about it the max number of
> peers should actually depend on WMI_SERVICE_IRAM_TIDS which is known
> after booting firmware. However since only 10.x was released with the
> service enabled we used fw_features. So..

I think this is good enough for now. We can always improve this later.

> yeah. I can move the function call if you want though.

Please do that. To keep things simple I would like to have the absolute
minimum in start() calls.

-- 
Kalle Valo


From michal.kazior at tieto.com  Tue Nov 25 00:58:57 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue, 25 Nov 2014 09:58:57 +0100
Subject: [PATCH v2 1/2] ath10k: add register access debugfs interface
In-Reply-To: <87vbm31xno.fsf@kamboji.qca.qualcomm.com>
References: <20141124164037.29422.14033.stgit@potku.adurom.net>
 <20141124164159.29422.98462.stgit@potku.adurom.net>
 <87vbm31xno.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CA+BoTQmZ=xa=z3237E55cejfOOZM3GYp8OstJobF7NHe=8wTHA@mail.gmail.com>

On 25 November 2014 at 09:39, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Kalle Valo <kvalo at qca.qualcomm.com> writes:
>
>> +static ssize_t ath10k_reg_value_read(struct file *file,
>> +                                  char __user *user_buf,
>> +                                  size_t count, loff_t *ppos)
>> +{
>> +     struct ath10k *ar = file->private_data;
>> +     u8 buf[48];
>> +     unsigned int len;
>> +     u32 reg_addr, reg_val;
>> +
>> +     spin_lock_bh(&ar->data_lock);
>> +     reg_addr = ar->debug.reg_addr;
>> +     spin_unlock_bh(&ar->data_lock);
>> +
>> +     reg_val = ath10k_hif_read32(ar, reg_addr);
>> +     len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val);
>> +
>> +     return simple_read_from_buffer(user_buf, count, ppos, buf, len);
>> +}
>
> I just realised that we need to check ar->state to make sure that
> firmware is running. Because of that I'll need to change the data_lock
> to conf_mutex as well.

Hmm.. It could actually work without firmware running. It just reads MMIO.

The problem I see now is the target may not be awake (Bartosz recently
fixed suspend bug by moving ath10k_pci_wake/sleep back to
hif_power_up) and accessing target registers without it being fully
awake can lead to host memory corruption. I guess ar->state will do
for now because getting this to work otherwise is going to be a little
tricky.


Micha?


From michal.kazior at tieto.com  Tue Nov 25 01:03:16 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue, 25 Nov 2014 10:03:16 +0100
Subject: [PATCH v2 2/2] ath10k: add memory dump debugfs interface
In-Reply-To: <87r3wr1xl6.fsf@kamboji.qca.qualcomm.com>
References: <20141124164037.29422.14033.stgit@potku.adurom.net>
 <20141124164208.29422.76134.stgit@potku.adurom.net>
 <87r3wr1xl6.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CA+BoTQ=fc0hRr2Vad_P-wLWdKna-mzHaaFgGrYsO0KavTG7e7g@mail.gmail.com>

On 25 November 2014 at 09:41, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Kalle Valo <kvalo at qca.qualcomm.com> writes:
>
>> +static ssize_t ath10k_mem_value_read(struct file *file,
>> +                                  char __user *user_buf,
>> +                                  size_t count, loff_t *ppos)
>> +{
[...]
>> +static ssize_t ath10k_mem_value_write(struct file *file,
>> +                                   const char __user *user_buf,
>> +                                   size_t count, loff_t *ppos)
[...]
> In these two functions we also need to check ar->state.

It should work but the pci_wake (I've mentioned in the other mail) is
tricky though.


Micha?


From kvalo at qca.qualcomm.com  Tue Nov 25 01:04:12 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 25 Nov 2014 11:04:12 +0200
Subject: [PATCH] ath10k: don't drop corrupted mgmt frames
In-Reply-To: <1416839648-31803-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Mon, 24 Nov 2014 15:34:08 +0100")
References: <1416839648-31803-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87egsr1wj7.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> --- a/drivers/net/wireless/ath/ath10k/htt_rx.c
> +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
> @@ -1381,6 +1381,8 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
>  {
>  	struct sk_buff *msdu;
>  	struct htt_rx_desc *rxd;
> +	bool is_mgmt;
> +	bool has_fcs_err;
>  
>  	msdu = skb_peek(amsdu);
>  	rxd = (void *)msdu->data - sizeof(*rxd);
> @@ -1394,12 +1396,19 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
>  		return false;
>  	}
>  
> +	is_mgmt = !!(rxd->attention.flags &
> +		     __cpu_to_le32(RX_ATTENTION_FLAGS_MGMT_TYPE));
> +	has_fcs_err = !!(rxd->attention.flags &
> +			 __cpu_to_le32(RX_ATTENTION_FLAGS_FCS_ERR));

I think I asked this before in some other patch, but isn't '!!' operator
useless here? is_mgmt is a boolean so the compiler should convert it
correctly without '!!' anyway, right?

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 25 01:11:31 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 25 Nov 2014 11:11:31 +0200
Subject: Experimenting with patchwork
Message-ID: <87a93f1w70.fsf@kamboji.qca.qualcomm.com>

Hi,

to make it easier to handle the patchflow I'm experimenting with
patchwork at the moment. From patch submitters point of view nothing
changes at the moment, except one can easily check the state of his
patch from patchwork:

https://patchwork.kernel.org/project/ath10k/list/

Let's see how this goes. Feel free to send comments if this is helpful
or not.

-- 
Kalle Valo


From michal.kazior at tieto.com  Tue Nov 25 01:22:04 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue, 25 Nov 2014 10:22:04 +0100
Subject: [PATCH] ath10k: don't drop corrupted mgmt frames
In-Reply-To: <87egsr1wj7.fsf@kamboji.qca.qualcomm.com>
References: <1416839648-31803-1-git-send-email-michal.kazior@tieto.com>
 <87egsr1wj7.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CA+BoTQnk+40Pxkxfcu47Z-3j=8h2iMP8tKqXKf2GhAY3WkQxCw@mail.gmail.com>

On 25 November 2014 at 10:04, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Michal Kazior <michal.kazior at tieto.com> writes:
[...]
>> @@ -1394,12 +1396,19 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
>>               return false;
>>       }
>>
>> +     is_mgmt = !!(rxd->attention.flags &
>> +                  __cpu_to_le32(RX_ATTENTION_FLAGS_MGMT_TYPE));
>> +     has_fcs_err = !!(rxd->attention.flags &
>> +                      __cpu_to_le32(RX_ATTENTION_FLAGS_FCS_ERR));
>
> I think I asked this before in some other patch, but isn't '!!' operator
> useless here? is_mgmt is a boolean so the compiler should convert it
> correctly without '!!' anyway, right?

If I remove `!!` I get:

 warning: incorrect type in assignment (different base types)
    expected bool [unsigned] [usertype] is_mgmt
    got restricted __le32

I could do a temporary `u32 attention` to get rid of the `!!`. You
want me to update it?


Micha?


From kvalo at qca.qualcomm.com  Tue Nov 25 01:24:26 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 25 Nov 2014 11:24:26 +0200
Subject: [PATCH] ath10k: don't drop corrupted mgmt frames
In-Reply-To: <CA+BoTQnk+40Pxkxfcu47Z-3j=8h2iMP8tKqXKf2GhAY3WkQxCw@mail.gmail.com>
 (Michal Kazior's message of "Tue, 25 Nov 2014 10:22:04 +0100")
References: <1416839648-31803-1-git-send-email-michal.kazior@tieto.com>
 <87egsr1wj7.fsf@kamboji.qca.qualcomm.com>
 <CA+BoTQnk+40Pxkxfcu47Z-3j=8h2iMP8tKqXKf2GhAY3WkQxCw@mail.gmail.com>
Message-ID: <871tor1vlh.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> On 25 November 2014 at 10:04, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
>> Michal Kazior <michal.kazior at tieto.com> writes:
> [...]
>>> @@ -1394,12 +1396,19 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
>>>               return false;
>>>       }
>>>
>>> +     is_mgmt = !!(rxd->attention.flags &
>>> +                  __cpu_to_le32(RX_ATTENTION_FLAGS_MGMT_TYPE));
>>> +     has_fcs_err = !!(rxd->attention.flags &
>>> +                      __cpu_to_le32(RX_ATTENTION_FLAGS_FCS_ERR));
>>
>> I think I asked this before in some other patch, but isn't '!!' operator
>> useless here? is_mgmt is a boolean so the compiler should convert it
>> correctly without '!!' anyway, right?
>
> If I remove `!!` I get:
>
>  warning: incorrect type in assignment (different base types)
>     expected bool [unsigned] [usertype] is_mgmt
>     got restricted __le32

Oh. Sorry, my bad.

> I could do a temporary `u32 attention` to get rid of the `!!`. You
> want me to update it?

Please don't, this is fine.

-- 
Kalle Valo


From nbd at openwrt.org  Tue Nov 25 02:18:37 2014
From: nbd at openwrt.org (Felix Fietkau)
Date: Tue, 25 Nov 2014 11:18:37 +0100
Subject: [PATCH 2/2] ath10k: re-config ht_caps when chainmask is modified.
In-Reply-To: <87egss7tv3.fsf@kamboji.qca.qualcomm.com>
References: <1411576506-11815-1-git-send-email-greearb@candelatech.com>	<1411576506-11815-2-git-send-email-greearb@candelatech.com>	<87ioi47vvd.fsf@kamboji.qca.qualcomm.com>
 <87egss7tv3.fsf@kamboji.qca.qualcomm.com>
Message-ID: <5474577D.5070002@openwrt.org>

On 2014-11-24 11:53, Kalle Valo wrote:
> Kalle Valo <kvalo at qca.qualcomm.com> writes:
> 
>>> @@ -2537,6 +2560,17 @@ static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
>>>  	ar->cfg_tx_chainmask = tx_ant;
>>>  	ar->cfg_rx_chainmask = rx_ant;
>>>  
>>> +	ht_cap = ath10k_get_ht_cap(ar, true);
>>> +	vht_cap = ath10k_create_vht_cap(ar, true);
>>> +
>>> +	if (ar->phy_capability & WHAL_WLAN_11G_CAPABILITY)
>>> +		ar->mac.sbands[IEEE80211_BAND_2GHZ].ht_cap = ht_cap;
>>> +
>>> +	if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) {
>>> +		ar->mac.sbands[IEEE80211_BAND_5GHZ].ht_cap = ht_cap;
>>> +		ar->mac.sbands[IEEE80211_BAND_5GHZ].vht_cap = vht_cap;
>>> +	}
>>
>> So this modifies stryct wiphy::bands after we have called
>> ieee80211_register_hw(). Is this something which both cfg80211 and
>> mac80211 support? I didn't find the documentation mentioning anything
>> about this so I got a bit worried.
> 
> Johannes mentioned me that this is not supported so I am reluctant to
> take these. Unless I'm missing something, of course.
FWIW, ath9k has been doing the same for a long time now. Antenna
settings can only be changed while the device is stopped, so it should
be safe.

- Felix


From kvalo at qca.qualcomm.com  Tue Nov 25 02:24:23 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 25 Nov 2014 12:24:23 +0200
Subject: [PATCH v3 0/2] ath10k: firmware memory debugfs interface
Message-ID: <20141125102302.3951.10641.stgit@potku.adurom.net>

Hi,

this is v3 of Yanbo's firmware memory debugfs interface.

Changelog:

v3:

* check ath10k state and return an error if firmware is not running

* switch to use conf_mutex because using ar->state

* fix copy_from_user() error handling

v2:

* split patches into two

* simplify the commit logs

* remove extra #include "hif.h" from debug.c

---

Yanbo Li (2):
      ath10k: add register access debugfs interface
      ath10k: add memory dump debugfs interface


 drivers/net/wireless/ath/ath10k/core.h  |    1 
 drivers/net/wireless/ath/ath10k/debug.c |  239 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/hif.h   |   37 +++++
 drivers/net/wireless/ath/ath10k/pci.c   |    3 
 4 files changed, 280 insertions(+)



From kvalo at qca.qualcomm.com  Tue Nov 25 02:24:33 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 25 Nov 2014 12:24:33 +0200
Subject: [PATCH v3 1/2] ath10k: add register access debugfs interface
In-Reply-To: <20141125102302.3951.10641.stgit@potku.adurom.net>
References: <20141125102302.3951.10641.stgit@potku.adurom.net>
Message-ID: <20141125102433.3951.37783.stgit@potku.adurom.net>

From: Yanbo Li <yanbol at qti.qualcomm.com>

Debugfs files reg_addr and reg_val are used for reading and writing to the
firmware (target) registers. reg_addr contains the address to be accessed,
which also needs to be set first, and reg_value is when used for reading and
writing the actual value in ASCII.

To read a value from the firmware register 0x100000:

# echo 0x100000 > reg_addr
# cat reg_value
0x00100000:0x000002d3

To write value 0x2400 to address 0x100000:

# echo 0x100000 > reg_addr
# echo  0x2400 > reg_value
#

Signed-off-by: Yanbo Li <yanbol at qti.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.h  |    1 
 drivers/net/wireless/ath/ath10k/debug.c |  125 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/hif.h   |   26 ++++++
 drivers/net/wireless/ath/ath10k/pci.c   |    2 
 4 files changed, 154 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 8f86bd34e823..f5f2dcd2b65d 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -320,6 +320,7 @@ struct ath10k_debug {
 	/* protected by conf_mutex */
 	u32 fw_dbglog_mask;
 	u32 pktlog_filter;
+	u32 reg_addr;
 
 	u8 htt_max_amsdu;
 	u8 htt_max_ampdu;
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index f10721da4980..d0397d119862 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -928,6 +928,125 @@ static const struct file_operations fops_fw_crash_dump = {
 	.llseek = default_llseek,
 };
 
+static ssize_t ath10k_reg_addr_read(struct file *file,
+				    char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 buf[32];
+	unsigned int len = 0;
+	u32 reg_addr;
+
+	mutex_lock(&ar->conf_mutex);
+	reg_addr = ar->debug.reg_addr;
+	mutex_unlock(&ar->conf_mutex);
+
+	len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", reg_addr);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath10k_reg_addr_write(struct file *file,
+				     const char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u32 reg_addr;
+	int ret;
+
+	ret = kstrtou32_from_user(user_buf, count, 0, &reg_addr);
+	if (ret)
+		return ret;
+
+	if (!IS_ALIGNED(reg_addr, 4))
+		return -EFAULT;
+
+	mutex_lock(&ar->conf_mutex);
+	ar->debug.reg_addr = reg_addr;
+	mutex_unlock(&ar->conf_mutex);
+
+	return count;
+}
+
+static const struct file_operations fops_reg_addr = {
+	.read = ath10k_reg_addr_read,
+	.write = ath10k_reg_addr_write,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t ath10k_reg_value_read(struct file *file,
+				     char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 buf[48];
+	unsigned int len;
+	u32 reg_addr, reg_val;
+	int ret;
+
+	mutex_lock(&ar->conf_mutex);
+
+	if (ar->state != ATH10K_STATE_ON &&
+	    ar->state != ATH10K_STATE_UTF) {
+		ret = -ENETDOWN;
+		goto exit;
+	}
+
+	reg_addr = ar->debug.reg_addr;
+
+	reg_val = ath10k_hif_read32(ar, reg_addr);
+	len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+exit:
+	mutex_unlock(&ar->conf_mutex);
+
+	return ret;
+}
+
+static ssize_t ath10k_reg_value_write(struct file *file,
+				      const char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u32 reg_addr, reg_val;
+	int ret;
+
+	mutex_lock(&ar->conf_mutex);
+
+	if (ar->state != ATH10K_STATE_ON &&
+	    ar->state != ATH10K_STATE_UTF) {
+		ret = -ENETDOWN;
+		goto exit;
+	}
+
+	reg_addr = ar->debug.reg_addr;
+
+	ret = kstrtou32_from_user(user_buf, count, 0, &reg_val);
+	if (ret)
+		goto exit;
+
+	ath10k_hif_write32(ar, reg_addr, reg_val);
+
+	ret = count;
+
+exit:
+	mutex_unlock(&ar->conf_mutex);
+
+	return ret;
+}
+
+static const struct file_operations fops_reg_value = {
+	.read = ath10k_reg_value_read,
+	.write = ath10k_reg_value_write,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 static int ath10k_debug_htt_stats_req(struct ath10k *ar)
 {
 	u64 cookie;
@@ -1629,6 +1748,12 @@ int ath10k_debug_register(struct ath10k *ar)
 	debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy,
 			    ar, &fops_fw_crash_dump);
 
+	debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar, &fops_reg_addr);
+
+	debugfs_create_file("reg_value", S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar, &fops_reg_value);
+
 	debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
 			    ar, &fops_chip_id);
 
diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
index 30301f5b6051..bad071906540 100644
--- a/drivers/net/wireless/ath/ath10k/hif.h
+++ b/drivers/net/wireless/ath/ath10k/hif.h
@@ -20,6 +20,7 @@
 
 #include <linux/kernel.h>
 #include "core.h"
+#include "debug.h"
 
 struct ath10k_hif_sg_item {
 	u16 transfer_id;
@@ -84,6 +85,10 @@ struct ath10k_hif_ops {
 
 	u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id);
 
+	u32 (*read32)(struct ath10k *ar, u32 address);
+
+	void (*write32)(struct ath10k *ar, u32 address, u32 value);
+
 	/* Power up the device and enter BMI transfer mode for FW download */
 	int (*power_up)(struct ath10k *ar);
 
@@ -187,4 +192,25 @@ static inline int ath10k_hif_resume(struct ath10k *ar)
 	return ar->hif.ops->resume(ar);
 }
 
+static inline u32 ath10k_hif_read32(struct ath10k *ar, u32 address)
+{
+	if (!ar->hif.ops->read32) {
+		ath10k_warn(ar, "hif read32 not supported\n");
+		return 0xdeaddead;
+	}
+
+	return ar->hif.ops->read32(ar, address);
+}
+
+static inline void ath10k_hif_write32(struct ath10k *ar,
+				      u32 address, u32 data)
+{
+	if (!ar->hif.ops->write32) {
+		ath10k_warn(ar, "hif write32 not supported\n");
+		return;
+	}
+
+	ar->hif.ops->write32(ar, address, data);
+}
+
 #endif /* _HIF_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 3a6b8a5ca96c..328ab6c5d053 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1998,6 +1998,8 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
 	.get_free_queue_number	= ath10k_pci_hif_get_free_queue_number,
 	.power_up		= ath10k_pci_hif_power_up,
 	.power_down		= ath10k_pci_hif_power_down,
+	.read32			= ath10k_pci_read32,
+	.write32		= ath10k_pci_write32,
 #ifdef CONFIG_PM
 	.suspend		= ath10k_pci_hif_suspend,
 	.resume			= ath10k_pci_hif_resume,



From kvalo at qca.qualcomm.com  Tue Nov 25 02:24:48 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Tue, 25 Nov 2014 12:24:48 +0200
Subject: [PATCH v3 2/2] ath10k: add memory dump debugfs interface
In-Reply-To: <20141125102302.3951.10641.stgit@potku.adurom.net>
References: <20141125102302.3951.10641.stgit@potku.adurom.net>
Message-ID: <20141125102448.3951.97429.stgit@potku.adurom.net>

From: Yanbo Li <yanbol at qti.qualcomm.com>

Add mem_val debugfs file for dumping the firmware (target) memory and also for
writing to the memory. The firmware memory is accessed through one file which
uses position of the file as the firmware memory address. For example, with dd
use skip parameter for the address.

Beucase target memory width is 32 bits it's strongly recommended to use
blocksize divisable with 4 when using this interface. For example, when using
dd use bs=4 to set the block size to 4 and remember to divide both count and
skip values with four.

To read 4 kB chunk from address 0x400000:

dd if=mem_value bs=4 count=1024 skip=1048576 | xxd -g1

To write value 0x01020304 to address 0x400400:

echo 0x01020304 | xxd -r | dd of=mem_value bs=4 seek=1048832

To read 4 KB chunk of memory and then write back after edit:

dd if=mem_value of=tmp.bin bs=4 count=1024 skip=1048576
emacs tmp.bin
dd if=tmp.bin of=mem_value bs=4 count=1024 seek=1048576

Signed-off-by: Yanbo Li <yanbol at qti.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/debug.c |  114 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/hif.h   |   11 +++
 drivers/net/wireless/ath/ath10k/pci.c   |    1 
 3 files changed, 126 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index d0397d119862..ff831ca507f7 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1047,6 +1047,117 @@ static const struct file_operations fops_reg_value = {
 	.llseek = default_llseek,
 };
 
+static ssize_t ath10k_mem_value_read(struct file *file,
+				     char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 *buf;
+	int ret;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	if (!count)
+		return 0;
+
+	mutex_lock(&ar->conf_mutex);
+
+	buf = vmalloc(count);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	if (ar->state != ATH10K_STATE_ON &&
+	    ar->state != ATH10K_STATE_UTF) {
+		ret = -ENETDOWN;
+		goto exit;
+	}
+
+	ret = ath10k_hif_diag_read(ar, *ppos, buf, count);
+	if (ret) {
+		ath10k_warn(ar, "failed to read address 0x%08x via diagnose window fnrom debugfs: %d\n",
+			    (u32)(*ppos), ret);
+		goto exit;
+	}
+
+	ret = copy_to_user(user_buf, buf, count);
+	if (ret) {
+		ret = -EFAULT;
+		goto exit;
+	}
+
+	count -= ret;
+	*ppos += count;
+	ret = count;
+
+exit:
+	vfree(buf);
+	mutex_unlock(&ar->conf_mutex);
+
+	return ret;
+}
+
+static ssize_t ath10k_mem_value_write(struct file *file,
+				      const char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	u8 *buf;
+	int ret;
+
+	if (*ppos < 0)
+		return -EINVAL;
+
+	if (!count)
+		return 0;
+
+	mutex_lock(&ar->conf_mutex);
+
+	buf = vmalloc(count);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	if (ar->state != ATH10K_STATE_ON &&
+	    ar->state != ATH10K_STATE_UTF) {
+		ret = -ENETDOWN;
+		goto exit;
+	}
+
+	ret = copy_from_user(buf, user_buf, count);
+	if (ret) {
+		ret = -EFAULT;
+		goto exit;
+	}
+
+	ret = ath10k_hif_diag_write(ar, *ppos, buf, count);
+	if (ret) {
+		ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n",
+			    (u32)(*ppos), ret);
+		goto exit;
+	}
+
+	*ppos += count;
+	ret = count;
+
+exit:
+	vfree(buf);
+	mutex_unlock(&ar->conf_mutex);
+
+	return ret;
+}
+
+static const struct file_operations fops_mem_value = {
+	.read = ath10k_mem_value_read,
+	.write = ath10k_mem_value_write,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 static int ath10k_debug_htt_stats_req(struct ath10k *ar)
 {
 	u64 cookie;
@@ -1754,6 +1865,9 @@ int ath10k_debug_register(struct ath10k *ar)
 	debugfs_create_file("reg_value", S_IRUSR | S_IWUSR,
 			    ar->debug.debugfs_phy, ar, &fops_reg_value);
 
+	debugfs_create_file("mem_value", S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar, &fops_mem_value);
+
 	debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
 			    ar, &fops_chip_id);
 
diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
index bad071906540..6ac552304546 100644
--- a/drivers/net/wireless/ath/ath10k/hif.h
+++ b/drivers/net/wireless/ath/ath10k/hif.h
@@ -48,6 +48,8 @@ struct ath10k_hif_ops {
 	int (*diag_read)(struct ath10k *ar, u32 address, void *buf,
 			 size_t buf_len);
 
+	int (*diag_write)(struct ath10k *ar, u32 address, const void *data,
+			  int nbytes);
 	/*
 	 * API to handle HIF-specific BMI message exchanges, this API is
 	 * synchronous and only allowed to be called from a context that
@@ -113,6 +115,15 @@ static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf
 	return ar->hif.ops->diag_read(ar, address, buf, buf_len);
 }
 
+static inline int ath10k_hif_diag_write(struct ath10k *ar, u32 address,
+					const void *data, int nbytes)
+{
+	if (!ar->hif.ops->diag_write)
+		return -EOPNOTSUPP;
+
+	return ar->hif.ops->diag_write(ar, address, data, nbytes);
+}
+
 static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar,
 					      void *request, u32 request_len,
 					      void *response, u32 *response_len)
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 328ab6c5d053..0816098af578 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1988,6 +1988,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
 static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
 	.tx_sg			= ath10k_pci_hif_tx_sg,
 	.diag_read		= ath10k_pci_hif_diag_read,
+	.diag_write		= ath10k_pci_diag_write_mem,
 	.exchange_bmi_msg	= ath10k_pci_hif_exchange_bmi_msg,
 	.start			= ath10k_pci_hif_start,
 	.stop			= ath10k_pci_hif_stop,



From michal.kazior at tieto.com  Tue Nov 25 06:16:03 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue, 25 Nov 2014 15:16:03 +0100
Subject: [PATCH v2 1/3] ath10k: add missing goto
In-Reply-To: <1416834909-7130-1-git-send-email-michal.kazior@tieto.com>
References: <1416834909-7130-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1416924965-28216-1-git-send-email-michal.kazior@tieto.com>

This prevents warning spamming if peer creation
fails during sta_state in some cases.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 1245ac8..7b5a888 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3559,9 +3559,11 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			   arvif->vdev_id, sta->addr, ar->num_peers);
 
 		ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
-		if (ret)
+		if (ret) {
 			ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
+			goto exit;
+		}
 
 		if (vif->type == NL80211_IFTYPE_STATION) {
 			WARN_ON(arvif->is_started);
-- 
1.8.5.3



From michal.kazior at tieto.com  Tue Nov 25 06:16:05 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue, 25 Nov 2014 15:16:05 +0100
Subject: [PATCH v2 3/3] ath10k: fix station count enforcement
In-Reply-To: <1416924965-28216-1-git-send-email-michal.kazior@tieto.com>
References: <1416834909-7130-1-git-send-email-michal.kazior@tieto.com>
 <1416924965-28216-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1416924965-28216-3-git-send-email-michal.kazior@tieto.com>

The number of peers isn't directly translatable to
the number of stations because ath10k needs to
reserve a few extra peers for special cases like
multi-vif concurrency.

The previous limit was 126 and 15 stations in AP
mode for 10.x and main firmware branches
respectively. The limit is now 128 and 16 which
was the original intention.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---

Notes:
    v2:
     * move ath10k_core_init_max_sta_count() call to
       ath10k_core_probe_fw() before ath10k_core_stat() [Kalle]

 drivers/net/wireless/ath/ath10k/core.c  | 13 +++++++
 drivers/net/wireless/ath/ath10k/core.h  |  4 +++
 drivers/net/wireless/ath/ath10k/debug.c |  5 +--
 drivers/net/wireless/ath/ath10k/hw.h    | 15 ++++++---
 drivers/net/wireless/ath/ath10k/mac.c   | 60 ++++++++++++++++++++++++++-------
 drivers/net/wireless/ath/ath10k/wmi.c   |  2 +-
 6 files changed, 78 insertions(+), 21 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index f660553..7762061 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -799,6 +799,17 @@ static void ath10k_core_restart(struct work_struct *work)
 	mutex_unlock(&ar->conf_mutex);
 }
 
+static void ath10k_core_init_max_sta_count(struct ath10k *ar)
+{
+	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+		ar->max_num_peers = TARGET_10X_NUM_PEERS;
+		ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+	} else {
+		ar->max_num_peers = TARGET_NUM_PEERS;
+		ar->max_num_stations = TARGET_NUM_STATIONS;
+	}
+}
+
 int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
 {
 	int status;
@@ -1035,6 +1046,8 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
 		return ret;
 	}
 
+	ath10k_core_init_max_sta_count(ar);
+
 	mutex_lock(&ar->conf_mutex);
 
 	ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index be7e50b6..ab3b656 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -562,6 +562,10 @@ struct ath10k {
 
 	/* protected by conf_mutex */
 	int num_peers;
+	int num_stations;
+
+	int max_num_peers;
+	int max_num_stations;
 
 	struct work_struct offchan_tx_work;
 	struct sk_buff_head offchan_tx_queue;
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index f10721d..49930e2 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -123,7 +123,7 @@ EXPORT_SYMBOL(ath10k_info);
 
 void ath10k_print_driver_info(struct ath10k *ar)
 {
-	ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s\n",
+	ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s max_sta %d\n",
 		    ar->hw_params.name,
 		    ar->target_version,
 		    ar->chip_id,
@@ -135,7 +135,8 @@ void ath10k_print_driver_info(struct ath10k *ar)
 		    ar->fw_version_minor,
 		    ar->fw_version_release,
 		    ar->fw_version_build,
-		    ath10k_cal_mode_str(ar->cal_mode));
+		    ath10k_cal_mode_str(ar->cal_mode),
+		    ar->max_num_stations);
 	ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n",
 		    config_enabled(CONFIG_ATH10K_DEBUG),
 		    config_enabled(CONFIG_ATH10K_DEBUGFS),
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 392c250..dfedfd0 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -97,11 +97,13 @@ struct ath10k_pktlog_hdr {
 #define TARGET_DMA_BURST_SIZE			0
 #define TARGET_MAC_AGGR_DELIM			0
 #define TARGET_AST_SKID_LIMIT			16
-#define TARGET_NUM_PEERS			16
+#define TARGET_NUM_STATIONS			16
+#define TARGET_NUM_PEERS			((TARGET_NUM_STATIONS) + \
+						 (TARGET_NUM_VDEVS))
 #define TARGET_NUM_OFFLOAD_PEERS		0
 #define TARGET_NUM_OFFLOAD_REORDER_BUFS         0
 #define TARGET_NUM_PEER_KEYS			2
-#define TARGET_NUM_TIDS		(2 * ((TARGET_NUM_PEERS) + (TARGET_NUM_VDEVS)))
+#define TARGET_NUM_TIDS				((TARGET_NUM_PEERS) * 2)
 #define TARGET_TX_CHAIN_MASK			(BIT(0) | BIT(1) | BIT(2))
 #define TARGET_RX_CHAIN_MASK			(BIT(0) | BIT(1) | BIT(2))
 #define TARGET_RX_TIMEOUT_LO_PRI		100
@@ -132,12 +134,15 @@ struct ath10k_pktlog_hdr {
 #define TARGET_10X_DMA_BURST_SIZE		0
 #define TARGET_10X_MAC_AGGR_DELIM		0
 #define TARGET_10X_AST_SKID_LIMIT		16
-#define TARGET_10X_NUM_PEERS			(128 + (TARGET_10X_NUM_VDEVS))
-#define TARGET_10X_NUM_PEERS_MAX		128
+#define TARGET_10X_NUM_STATIONS			128
+#define TARGET_10X_NUM_PEERS			((TARGET_10X_NUM_STATIONS) + \
+						 (TARGET_10X_NUM_VDEVS))
 #define TARGET_10X_NUM_OFFLOAD_PEERS		0
 #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS	0
 #define TARGET_10X_NUM_PEER_KEYS		2
-#define TARGET_10X_NUM_TIDS			256
+#define TARGET_10X_NUM_TIDS_MAX			256
+#define TARGET_10X_NUM_TIDS			min((TARGET_10X_NUM_TIDS_MAX), \
+						    (TARGET_10X_NUM_PEERS) * 2)
 #define TARGET_10X_TX_CHAIN_MASK		(BIT(0) | BIT(1) | BIT(2))
 #define TARGET_10X_RX_CHAIN_MASK		(BIT(0) | BIT(1) | BIT(2))
 #define TARGET_10X_RX_TIMEOUT_LO_PRI		100
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 3312e75..95d0f30 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -326,6 +326,9 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
 
 	lockdep_assert_held(&ar->conf_mutex);
 
+	if (ar->num_peers >= ar->max_num_peers)
+		return -ENOBUFS;
+
 	ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
 	if (ret) {
 		ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n",
@@ -471,6 +474,7 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
 	spin_unlock_bh(&ar->data_lock);
 
 	ar->num_peers = 0;
+	ar->num_stations = 0;
 }
 
 /************************/
@@ -3509,6 +3513,37 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
 	mutex_unlock(&ar->conf_mutex);
 }
 
+static int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif)
+{
+	struct ath10k *ar = arvif->ar;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
+	    arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
+		return 0;
+
+	if (ar->num_stations >= ar->max_num_stations)
+		return -ENOBUFS;
+
+	ar->num_stations++;
+
+	return 0;
+}
+
+static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif)
+{
+	struct ath10k *ar = arvif->ar;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
+	    arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
+		return;
+
+	ar->num_stations--;
+}
+
 static int ath10k_sta_state(struct ieee80211_hw *hw,
 			    struct ieee80211_vif *vif,
 			    struct ieee80211_sta *sta,
@@ -3518,7 +3553,6 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 	struct ath10k *ar = hw->priv;
 	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
-	int max_num_peers;
 	int ret = 0;
 
 	if (old_state == IEEE80211_STA_NOTEXIST &&
@@ -3540,26 +3574,24 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 		/*
 		 * New station addition.
 		 */
-		if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
-			max_num_peers = TARGET_10X_NUM_PEERS_MAX - 1;
-		else
-			max_num_peers = TARGET_NUM_PEERS;
+		ath10k_dbg(ar, ATH10K_DBG_MAC,
+			   "mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d\n",
+			   arvif->vdev_id, sta->addr,
+			   ar->num_stations + 1, ar->max_num_stations,
+			   ar->num_peers + 1, ar->max_num_peers);
 
-		if (ar->num_peers >= max_num_peers) {
-			ath10k_warn(ar, "number of peers exceeded: peers number %d (max peers %d)\n",
-				    ar->num_peers, max_num_peers);
-			ret = -ENOBUFS;
+		ret = ath10k_mac_inc_num_stations(arvif);
+		if (ret) {
+			ath10k_warn(ar, "refusing to associate station: too many connected already (%d)\n",
+				    ar->max_num_stations);
 			goto exit;
 		}
 
-		ath10k_dbg(ar, ATH10K_DBG_MAC,
-			   "mac vdev %d peer create %pM (new sta) num_peers %d\n",
-			   arvif->vdev_id, sta->addr, ar->num_peers);
-
 		ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
 		if (ret) {
 			ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
+			ath10k_mac_dec_num_stations(arvif);
 			goto exit;
 		}
 
@@ -3572,6 +3604,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 					    arvif->vdev_id, ret);
 				WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id,
 							   sta->addr));
+				ath10k_mac_dec_num_stations(arvif);
 				goto exit;
 			}
 
@@ -3602,6 +3635,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
 
+		ath10k_mac_dec_num_stations(arvif);
 	} else if (old_state == IEEE80211_STA_AUTH &&
 		   new_state == IEEE80211_STA_ASSOC &&
 		   (vif->type == NL80211_IFTYPE_AP ||
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c300a53..eda3bf0 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -3142,7 +3142,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
 	u32 len, val;
 
 	config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS);
-	config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS);
+	config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS);
 	config.num_offload_peers = __cpu_to_le32(TARGET_NUM_OFFLOAD_PEERS);
 
 	config.num_offload_reorder_bufs =
-- 
1.8.5.3



From michal.kazior at tieto.com  Tue Nov 25 06:16:04 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Tue, 25 Nov 2014 15:16:04 +0100
Subject: [PATCH v2 2/3] ath10k: clean up num_peers locking
In-Reply-To: <1416924965-28216-1-git-send-email-michal.kazior@tieto.com>
References: <1416834909-7130-1-git-send-email-michal.kazior@tieto.com>
 <1416924965-28216-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1416924965-28216-2-git-send-email-michal.kazior@tieto.com>

The var was supposed to be protected by data_lock
but it wasn't so in all instances. It's actually
not necessary to have a spinlock protected
num_peers so drop it.

All instances of num_peers are already within
conf_mutex sections so use that.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h | 2 +-
 drivers/net/wireless/ath/ath10k/mac.c  | 8 +++-----
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 8f86bd3..be7e50b6 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -560,7 +560,7 @@ struct ath10k {
 	struct list_head peers;
 	wait_queue_head_t peer_mapping_wq;
 
-	/* number of created peers; protected by data_lock */
+	/* protected by conf_mutex */
 	int num_peers;
 
 	struct work_struct offchan_tx_work;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 7b5a888..3312e75 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -339,9 +339,8 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
 			    addr, vdev_id, ret);
 		return ret;
 	}
-	spin_lock_bh(&ar->data_lock);
+
 	ar->num_peers++;
-	spin_unlock_bh(&ar->data_lock);
 
 	return 0;
 }
@@ -432,9 +431,7 @@ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
 	if (ret)
 		return ret;
 
-	spin_lock_bh(&ar->data_lock);
 	ar->num_peers--;
-	spin_unlock_bh(&ar->data_lock);
 
 	return 0;
 }
@@ -471,8 +468,9 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
 		list_del(&peer->list);
 		kfree(peer);
 	}
-	ar->num_peers = 0;
 	spin_unlock_bh(&ar->data_lock);
+
+	ar->num_peers = 0;
 }
 
 /************************/
-- 
1.8.5.3



From greearb at candelatech.com  Tue Nov 25 08:22:23 2014
From: greearb at candelatech.com (Ben Greear)
Date: Tue, 25 Nov 2014 08:22:23 -0800
Subject: [PATCH 1/2] ath10k: move create-ht-cap methods above set-antenna.
In-Reply-To: <874mtn3dof.fsf@kamboji.qca.qualcomm.com>
References: <1411576506-11815-1-git-send-email-greearb@candelatech.com>
 <874mtn3dof.fsf@kamboji.qca.qualcomm.com>
Message-ID: <5474ACBF.7090905@candelatech.com>

On 11/25/2014 12:08 AM, Kalle Valo wrote:
> greearb at candelatech.com writes:
> 
>> From: Ben Greear <greearb at candelatech.com>
>>
>> We will need to use these in set-antenna, so move them
>> so that we do not have to define the method signatures.
>>
>> Signed-off-by: Ben Greear <greearb at candelatech.com>
> 
> I'm dropping these two patches. Please resend once we figure out how to
> handle the band updated.

It might be a while...I'm working on some other tasks these days
and don't have time to respin ath10k patches at the moment.

If someone else wants to work on getting them upstream, please be
my guest.

Per Felix's comment, maybe my patches were actually OK as they are....

Thanks,
Ben

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



From poh at qca.qualcomm.com  Tue Nov 25 12:02:44 2014
From: poh at qca.qualcomm.com (Peter Oh)
Date: Tue, 25 Nov 2014 12:02:44 -0800
Subject: [PATCH 1/2] ath10k: add new pdev parameters for fw 10.2
Message-ID: <1416945765-26902-1-git-send-email-poh@qca.qualcomm.com>

New pdev paramters have been added to firmware 10.2,
hence update wmi interfaces to sync with.

Signed-off-by: Peter Oh <poh at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/wmi.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index a38d788..8fa0192 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -2707,6 +2707,9 @@ enum wmi_10x_pdev_param {
 	WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_MODE,
 	WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_BUFFER,
 	WMI_10X_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER,
+	WMI_10X_PDEV_PEER_STA_PS_STATECHG_ENABLE,
+	WMI_10X_PDEV_PARAM_RTS_FIXED_RATE,
+	WMI_10X_PDEV_PARAM_CAL_PERIOD
 };
 
 struct wmi_pdev_set_param_cmd {
-- 
1.9.1



From poh at qca.qualcomm.com  Tue Nov 25 12:02:45 2014
From: poh at qca.qualcomm.com (Peter Oh)
Date: Tue, 25 Nov 2014 12:02:45 -0800
Subject: [PATCH 2/2] ath10k: add new wmi interface of NF cal period
In-Reply-To: <1416945765-26902-1-git-send-email-poh@qca.qualcomm.com>
References: <1416945765-26902-1-git-send-email-poh@qca.qualcomm.com>
Message-ID: <1416945765-26902-2-git-send-email-poh@qca.qualcomm.com>

Introduce a new wmi interface controls noise floor (NF) calibration
period via debugfs as firmware has introduced it on v10.2.

It allows users to modify frequency of NF calibration in millisecond
and changes RSSI reporting frequency consequently.
Short calibration period will trigger more frequent NF calibration,
so that RSSI reported in receive frames is more realistic.

Till now calibration was done at 30 seconds.

Signed-off-by: Peter Oh <poh at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.h  |  1 +
 drivers/net/wireless/ath/ath10k/debug.c | 64 +++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi.c   |  2 ++
 drivers/net/wireless/ath/ath10k/wmi.h   |  1 +
 4 files changed, 68 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 8f86bd3..5de988c 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -320,6 +320,7 @@ struct ath10k_debug {
 	/* protected by conf_mutex */
 	u32 fw_dbglog_mask;
 	u32 pktlog_filter;
+	u32 fw_cal_period;
 
 	u8 htt_max_amsdu;
 	u8 htt_max_ampdu;
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index f10721d..d8426fd 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1381,6 +1381,67 @@ static const struct file_operations fops_cal_data = {
 	.llseek = default_llseek,
 };
 
+static ssize_t ath10k_read_cal_period(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	unsigned int len;
+	char buf[32];
+
+	len = scnprintf(buf, sizeof(buf), "%d\n",
+			ar->debug.fw_cal_period);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath10k_write_cal_period(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	unsigned long period;
+	int ret;
+
+	ret = kstrtoul_from_user(user_buf, count, 0, &period);
+	if (ret)
+		return ret;
+	/* period unit in millisecond */
+	if (period < 1 || period > 60000)
+		return -EINVAL;
+
+	mutex_lock(&ar->conf_mutex);
+
+	ar->debug.fw_cal_period = period;
+
+	if (ar->state == ATH10K_STATE_ON) {
+		ret = ath10k_wmi_pdev_set_param
+			(ar, ar->wmi.pdev_param->cal_period,
+			ar->debug.fw_cal_period);
+		if (ret) {
+			ath10k_warn
+				(ar, "cal period cfg failed from debugfs: %d\n",
+				ret);
+			goto exit;
+		}
+	}
+
+	ret = count;
+
+exit:
+	mutex_unlock(&ar->conf_mutex);
+
+	return ret;
+}
+
+static const struct file_operations fops_cal_period = {
+	.read = ath10k_read_cal_period,
+	.write = ath10k_write_cal_period,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 int ath10k_debug_start(struct ath10k *ar)
 {
 	int ret;
@@ -1645,6 +1706,9 @@ int ath10k_debug_register(struct ath10k *ar)
 	debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy,
 			    ar, &fops_cal_data);
 
+	debugfs_create_file("cal_period", S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar, &fops_cal_period);
+
 	if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
 		debugfs_create_file("dfs_simulate_radar", S_IWUSR,
 				    ar->debug.debugfs_phy, ar,
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c300a53..b144b39 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -434,6 +434,7 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = {
 	.fast_channel_reset = WMI_PDEV_PARAM_UNSUPPORTED,
 	.burst_dur = WMI_PDEV_PARAM_UNSUPPORTED,
 	.burst_enable = WMI_PDEV_PARAM_UNSUPPORTED,
+	.cal_period = WMI_PDEV_PARAM_UNSUPPORTED,
 };
 
 static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
@@ -486,6 +487,7 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
 	.fast_channel_reset = WMI_10X_PDEV_PARAM_FAST_CHANNEL_RESET,
 	.burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR,
 	.burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE,
+	.cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD,
 };
 
 /* firmware 10.2 specific mappings */
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 8fa0192..fe35ba9 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -2497,6 +2497,7 @@ struct wmi_pdev_param_map {
 	u32 fast_channel_reset;
 	u32 burst_dur;
 	u32 burst_enable;
+	u32 cal_period; /* valid period is 1 ~ 60000ms */
 };
 
 #define WMI_PDEV_PARAM_UNSUPPORTED 0
-- 
1.9.1



From greearb at candelatech.com  Tue Nov 25 16:59:00 2014
From: greearb at candelatech.com (Ben Greear)
Date: Tue, 25 Nov 2014 16:59:00 -0800
Subject: IBSS mode is now supported by CT firmware.
Message-ID: <547525D4.5080701@candelatech.com>

A company that wishes to remain anonymous is sponsoring my
effort to add IBSS (ADHOC) support to my 10.1.467 CT firmware.

The kernel driver must be patched to enable IBSS mode when
CT firmware is detected.

The firmware was improved by copying some of the missing IBSS
code from the 999.x firmware branch.

I still cannot get WPA2 encryption to work, but open authentication
seems to work fine.  I still have a good bit more testing to do.
I cannot get ath9k to do encryption in IBSS mode either, so I
probably am mis-configuring something.

If someone wants to try this out, please download the appropriate
firmware binary from here:

http://www.candelatech.com/downloads/ath10k-fw-beta/

Either hack your own kernel, or grab my latest 3.17 kernel:

git clone git://dmz2.candelatech.com/linux-3.17.dev.y

I'm interested to know results if someone tries it out.

Thanks,
Ben

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



From yeohchunyeow at gmail.com  Tue Nov 25 17:21:47 2014
From: yeohchunyeow at gmail.com (Yeoh Chun-Yeow)
Date: Wed, 26 Nov 2014 09:21:47 +0800
Subject: IBSS mode is now supported by CT firmware.
In-Reply-To: <547525D4.5080701@candelatech.com>
References: <547525D4.5080701@candelatech.com>
Message-ID: <CAEFj9850cLVSVH=BmDNwZwEpgymRhLS2yeVGgn5gUMxkj3Wunw@mail.gmail.com>

On Wed, Nov 26, 2014 at 8:59 AM, Ben Greear <greearb at candelatech.com> wrote:
> A company that wishes to remain anonymous is sponsoring my
> effort to add IBSS (ADHOC) support to my 10.1.467 CT firmware.
>

Great!

> The kernel driver must be patched to enable IBSS mode when
> CT firmware is detected.
>

Where can I find the patches?

---
ChunYeow


From greearb at candelatech.com  Tue Nov 25 17:39:10 2014
From: greearb at candelatech.com (Ben Greear)
Date: Tue, 25 Nov 2014 17:39:10 -0800
Subject: IBSS mode is now supported by CT firmware.
In-Reply-To: <CAEFj9850cLVSVH=BmDNwZwEpgymRhLS2yeVGgn5gUMxkj3Wunw@mail.gmail.com>
References: <547525D4.5080701@candelatech.com>
 <CAEFj9850cLVSVH=BmDNwZwEpgymRhLS2yeVGgn5gUMxkj3Wunw@mail.gmail.com>
Message-ID: <54752F3E.6000704@candelatech.com>

On 11/25/2014 05:21 PM, Yeoh Chun-Yeow wrote:
> On Wed, Nov 26, 2014 at 8:59 AM, Ben Greear <greearb at candelatech.com> wrote:
>> A company that wishes to remain anonymous is sponsoring my
>> effort to add IBSS (ADHOC) support to my 10.1.467 CT firmware.
>>
> 
> Great!
> 
>> The kernel driver must be patched to enable IBSS mode when
>> CT firmware is detected.
>>
> 
> Where can I find the patches?

My 3.17 kernel:

git clone git://dmz2.candelatech.com/linux-3.17.dev.y

or, browse gitweb:

http://dmz2.candelatech.com/git/gitweb.cgi?p=linux-3.17.dev.y/.git;a=summary


I'll also backport to my 3.14 tree when I get a chance,
but it is not done yet.

Probably not worth trying to post for upstream inclusion
since it needs the CT feature flag...

Thanks,
Ben


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



From yeohchunyeow at gmail.com  Tue Nov 25 17:48:07 2014
From: yeohchunyeow at gmail.com (Yeoh Chun-Yeow)
Date: Wed, 26 Nov 2014 09:48:07 +0800
Subject: IBSS mode is now supported by CT firmware.
In-Reply-To: <54752F3E.6000704@candelatech.com>
References: <547525D4.5080701@candelatech.com>
 <CAEFj9850cLVSVH=BmDNwZwEpgymRhLS2yeVGgn5gUMxkj3Wunw@mail.gmail.com>
 <54752F3E.6000704@candelatech.com>
Message-ID: <CAEFj984VgP2u2ehBzmY6U=utRmKOAjxF_-bY+FPxgwxma5hu_g@mail.gmail.com>

Is this the only patch we need to enable IBSS mode?
http://dmz2.candelatech.com/git/gitweb.cgi?p=linux-3.17.dev.y/.git;a=commit;h=af9dabe5f23e2ad8f8603a5156ebe9227340e9e3

Please advice. Thanks

----
ChunYeow

On Wed, Nov 26, 2014 at 9:39 AM, Ben Greear <greearb at candelatech.com> wrote:
> On 11/25/2014 05:21 PM, Yeoh Chun-Yeow wrote:
>> On Wed, Nov 26, 2014 at 8:59 AM, Ben Greear <greearb at candelatech.com> wrote:
>>> A company that wishes to remain anonymous is sponsoring my
>>> effort to add IBSS (ADHOC) support to my 10.1.467 CT firmware.
>>>
>>
>> Great!
>>
>>> The kernel driver must be patched to enable IBSS mode when
>>> CT firmware is detected.
>>>
>>
>> Where can I find the patches?
>
> My 3.17 kernel:
>
> git clone git://dmz2.candelatech.com/linux-3.17.dev.y
>
> or, browse gitweb:
>
> http://dmz2.candelatech.com/git/gitweb.cgi?p=linux-3.17.dev.y/.git;a=summary
>
>
> I'll also backport to my 3.14 tree when I get a chance,
> but it is not done yet.
>
> Probably not worth trying to post for upstream inclusion
> since it needs the CT feature flag...
>
> Thanks,
> Ben
>
>
> --
> Ben Greear <greearb at candelatech.com>
> Candela Technologies Inc  http://www.candelatech.com
>


From greearb at candelatech.com  Tue Nov 25 17:50:24 2014
From: greearb at candelatech.com (Ben Greear)
Date: Tue, 25 Nov 2014 17:50:24 -0800
Subject: IBSS mode is now supported by CT firmware.
In-Reply-To: <CAEFj984VgP2u2ehBzmY6U=utRmKOAjxF_-bY+FPxgwxma5hu_g@mail.gmail.com>
References: <547525D4.5080701@candelatech.com>
 <CAEFj9850cLVSVH=BmDNwZwEpgymRhLS2yeVGgn5gUMxkj3Wunw@mail.gmail.com>
 <54752F3E.6000704@candelatech.com>
 <CAEFj984VgP2u2ehBzmY6U=utRmKOAjxF_-bY+FPxgwxma5hu_g@mail.gmail.com>
Message-ID: <547531E0.6040707@candelatech.com>

On 11/25/2014 05:48 PM, Yeoh Chun-Yeow wrote:
> Is this the only patch we need to enable IBSS mode?
> http://dmz2.candelatech.com/git/gitweb.cgi?p=linux-3.17.dev.y/.git;a=commit;h=af9dabe5f23e2ad8f8603a5156ebe9227340e9e3
> 
> Please advice. Thanks

Sort of, but that is patching a previous patch of mine that is not upstream.

So, you are going to have to go crawling through the code a bit
to find out how to do a similar action in your code base.

Thanks,
Ben


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



From dave.taht at gmail.com  Tue Nov 25 17:57:39 2014
From: dave.taht at gmail.com (Dave Taht)
Date: Tue, 25 Nov 2014 17:57:39 -0800
Subject: IBSS mode is now supported by CT firmware.
In-Reply-To: <547525D4.5080701@candelatech.com>
References: <547525D4.5080701@candelatech.com>
Message-ID: <CAA93jw5RuVtGMRwSJMsGdsa4YSbNHinDuTLhTLshKwtOiAZH+A@mail.gmail.com>

On Tue, Nov 25, 2014 at 4:59 PM, Ben Greear <greearb at candelatech.com> wrote:
> A company that wishes to remain anonymous is sponsoring my
> effort to add IBSS (ADHOC) support to my 10.1.467 CT firmware.

Oh, wonderful. I would love to get babeld running on this stuff on
adhoc mode....

> The kernel driver must be patched to enable IBSS mode when
> CT firmware is detected.
>
> The firmware was improved by copying some of the missing IBSS
> code from the 999.x firmware branch.
>
> I still cannot get WPA2 encryption to work, but open authentication
> seems to work fine.  I still have a good bit more testing to do.
> I cannot get ath9k to do encryption in IBSS mode either, so I
> probably am mis-configuring something.
>
> If someone wants to try this out, please download the appropriate
> firmware binary from here:
>
> http://www.candelatech.com/downloads/ath10k-fw-beta/
>
> Either hack your own kernel, or grab my latest 3.17 kernel:
>
> git clone git://dmz2.candelatech.com/linux-3.17.dev.y
>
> I'm interested to know results if someone tries it out.
>
> Thanks,
> Ben
>
> --
> Ben Greear <greearb at candelatech.com>
> Candela Technologies Inc  http://www.candelatech.com
>
>
> _______________________________________________
> ath10k mailing list
> ath10k at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath10k



-- 
Dave T?ht

thttp://www.bufferbloat.net/projects/bloat/wiki/Upcoming_Talks


From yeohchunyeow at gmail.com  Tue Nov 25 18:14:52 2014
From: yeohchunyeow at gmail.com (Yeoh Chun-Yeow)
Date: Wed, 26 Nov 2014 10:14:52 +0800
Subject: IBSS mode is now supported by CT firmware.
In-Reply-To: <547531E0.6040707@candelatech.com>
References: <547525D4.5080701@candelatech.com>
 <CAEFj9850cLVSVH=BmDNwZwEpgymRhLS2yeVGgn5gUMxkj3Wunw@mail.gmail.com>
 <54752F3E.6000704@candelatech.com>
 <CAEFj984VgP2u2ehBzmY6U=utRmKOAjxF_-bY+FPxgwxma5hu_g@mail.gmail.com>
 <547531E0.6040707@candelatech.com>
Message-ID: <CAEFj987GH29R44GDpRUck7KLZ6M4TvKSyCpFgRaKaKub+OBoFQ@mail.gmail.com>

Ok. Thanks. Will take a try on this later.

---
ChunYeow

On Wed, Nov 26, 2014 at 9:50 AM, Ben Greear <greearb at candelatech.com> wrote:
> On 11/25/2014 05:48 PM, Yeoh Chun-Yeow wrote:
>> Is this the only patch we need to enable IBSS mode?
>> http://dmz2.candelatech.com/git/gitweb.cgi?p=linux-3.17.dev.y/.git;a=commit;h=af9dabe5f23e2ad8f8603a5156ebe9227340e9e3
>>
>> Please advice. Thanks
>
> Sort of, but that is patching a previous patch of mine that is not upstream.
>
> So, you are going to have to go crawling through the code a bit
> to find out how to do a similar action in your code base.
>
> Thanks,
> Ben
>
>
> --
> Ben Greear <greearb at candelatech.com>
> Candela Technologies Inc  http://www.candelatech.com
>


From kvalo at qca.qualcomm.com  Tue Nov 25 22:25:37 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 26 Nov 2014 08:25:37 +0200
Subject: [PATCH v2 05/10] ath10k: apply chainmask settings to vdev on
 creation.
In-Reply-To: <1411507045-18973-5-git-send-email-greearb@candelatech.com>
 (greearb@candelatech.com's message of "Tue, 23 Sep 2014 14:17:20
 -0700")
References: <1411507045-18973-1-git-send-email-greearb@candelatech.com>
 <1411507045-18973-5-git-send-email-greearb@candelatech.com>
Message-ID: <87bnnuzdem.fsf@kamboji.qca.qualcomm.com>

greearb at candelatech.com writes:

> From: Ben Greear <greearb at candelatech.com>
>
> It appears it takes more than just setting the
> hardware's chainmask to make things work well.  Without
> this patch, a vdev would only use 1x1 rates when chainmask
> was set to 0x3.
>
> Setting the 'nss' (number of spatial streams) on the vdev
> helps the firmware's rate-control algorithm work properly.
>
> Tested on CT firmware, but probably this works (and
> is required) on normal firmware.
>
> Signed-off-by: Ben Greear <greearb at candelatech.com>
> ---
>
> v2:  Add warning if chainmask is set to probably-invalid configuration.
>   Also, from a quick test, it appears you cannot even set the chainmask
>   using 'iw' when vdevs are active.

Thanks, applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 25 22:26:08 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 26 Nov 2014 08:26:08 +0200
Subject: [PATCH v2 06/10] ath10k: use configured nss instead of max nss.
In-Reply-To: <1411507045-18973-6-git-send-email-greearb@candelatech.com>
 (greearb@candelatech.com's message of "Tue, 23 Sep 2014 14:17:21
 -0700")
References: <1411507045-18973-1-git-send-email-greearb@candelatech.com>
 <1411507045-18973-6-git-send-email-greearb@candelatech.com>
Message-ID: <877fyizddr.fsf@kamboji.qca.qualcomm.com>

greearb at candelatech.com writes:

> From: Ben Greear <greearb at candelatech.com>
>
> When re-associating a station, the nss was set back to
> maximum value even if user had configured small number
> of tx chains.  So, pay attention to user's config in
> this case as well.
>
> Signed-off-by: Ben Greear <greearb at candelatech.com>

Thanks, applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 25 22:28:32 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 26 Nov 2014 08:28:32 +0200
Subject: [PATCH] ath10k: remove extra_tx_headroom
In-Reply-To: <1416837886-18377-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Mon, 24 Nov 2014 15:04:46 +0100")
References: <1416837886-18377-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <873896zd9r.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> Comment was out-of-date. The headroom is no longer
> necessary because HTT Tx fragment list is stored
> in dma pool item associated with each sk_buff.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

Thanks, applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 25 22:32:06 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 26 Nov 2014 08:32:06 +0200
Subject: [PATCH 1/3] ath10k: fix offchan reliability
In-Reply-To: <1416837513-13386-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Mon, 24 Nov 2014 14:58:31 +0100")
References: <1416837513-13386-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87y4qyxyjd.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> New firmware revisions don't need peer creation
> when doing offchannel tx. Earlier revisions would
> queue and never release frames without a peer.
>
> This prevent new firmware revisions from stopping
> replenishing wmi-htc tx credits and improves
> reliability of offchannel tx which would sometimes
> silently fail.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

Thanks, all three patches applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 25 22:35:07 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 26 Nov 2014 08:35:07 +0200
Subject: [PATCH] ath10k: don't drop corrupted mgmt frames
In-Reply-To: <1416839648-31803-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Mon, 24 Nov 2014 15:34:08 +0100")
References: <1416839648-31803-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87tx1mxyec.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> Some firmware revisions don't seem to deilver
> management frames with FCS error via WMI so narrow
> down the HTT rule to not drop corrupted management
> frames.
>
> This basically increases number of frames ath10k
> reports while sniffing.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

Thanks, applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 25 22:36:29 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 26 Nov 2014 08:36:29 +0200
Subject: [PATCH] ath10k: don't drop corrupted mgmt frames
In-Reply-To: <1416839648-31803-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Mon, 24 Nov 2014 15:34:08 +0100")
References: <1416839648-31803-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87ppcaxyc2.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> Some firmware revisions don't seem to deilver
> management frames with FCS error via WMI so narrow
> down the HTT rule to not drop corrupted management
> frames.
>
> This basically increases number of frames ath10k
> reports while sniffing.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

Thanks, applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 25 22:38:10 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 26 Nov 2014 08:38:10 +0200
Subject: [PATCH v2 1/3] ath10k: Fix shared WEP
In-Reply-To: <1416896220-29691-1-git-send-email-sujith@msujith.org> (Sujith
 Manoharan's message of "Tue, 25 Nov 2014 11:46:58 +0530")
References: <1416896220-29691-1-git-send-email-sujith@msujith.org>
Message-ID: <87lhmyxy99.fsf@kamboji.qca.qualcomm.com>

Sujith Manoharan <sujith at msujith.org> writes:

> From: Sujith Manoharan <c_manoha at qca.qualcomm.com>
>
> When static keys are used in shared WEP, when a
> station is associated, message 3 is sent with an
> encrypted payload. But, for subsequent
> authentications that are triggered without a
> deauth, the auth frame is decrypted by the HW.
>
> To handle this, check if the WEP keys have already
> been set for the peer and if so, mark the
> frame as decrypted. This scenario can happen
> when a station changes its default TX key and initiates
> a new authentication sequence.
>
> Signed-off-by: Sujith Manoharan <c_manoha at qca.qualcomm.com>

Thanks, all three applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 25 22:40:58 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 26 Nov 2014 08:40:58 +0200
Subject: [PATCH v3 0/2] ath10k: firmware memory debugfs interface
In-Reply-To: <20141125102302.3951.10641.stgit@potku.adurom.net> (Kalle Valo's
 message of "Tue, 25 Nov 2014 12:24:23 +0200")
References: <20141125102302.3951.10641.stgit@potku.adurom.net>
Message-ID: <87h9xmxy4l.fsf@kamboji.qca.qualcomm.com>

Kalle Valo <kvalo at qca.qualcomm.com> writes:

> this is v3 of Yanbo's firmware memory debugfs interface.
>
> Changelog:
>
> v3:
>
> * check ath10k state and return an error if firmware is not running
>
> * switch to use conf_mutex because using ar->state
>
> * fix copy_from_user() error handling
>
> v2:
>
> * split patches into two
>
> * simplify the commit logs
>
> * remove extra #include "hif.h" from debug.c
>
> ---
>
> Yanbo Li (2):
>       ath10k: add register access debugfs interface
>       ath10k: add memory dump debugfs interface

Thanks Yanbo, both patches applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 25 22:44:55 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 26 Nov 2014 08:44:55 +0200
Subject: [PATCH v2 1/3] ath10k: add missing goto
In-Reply-To: <1416924965-28216-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Tue, 25 Nov 2014 15:16:03 +0100")
References: <1416834909-7130-1-git-send-email-michal.kazior@tieto.com>
 <1416924965-28216-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87d28axxy0.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> This prevents warning spamming if peer creation
> fails during sta_state in some cases.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

Thanks, all three patches applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 25 23:12:04 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 26 Nov 2014 09:12:04 +0200
Subject: [PATCH 2/2] ath10k: add new wmi interface of NF cal period
In-Reply-To: <1416945765-26902-2-git-send-email-poh@qca.qualcomm.com> (Peter
 Oh's message of "Tue, 25 Nov 2014 12:02:45 -0800")
References: <1416945765-26902-1-git-send-email-poh@qca.qualcomm.com>
 <1416945765-26902-2-git-send-email-poh@qca.qualcomm.com>
Message-ID: <874mtmxwor.fsf@kamboji.qca.qualcomm.com>

Peter Oh <poh at qca.qualcomm.com> writes:

> Introduce a new wmi interface controls noise floor (NF) calibration
> period via debugfs as firmware has introduced it on v10.2.
>
> It allows users to modify frequency of NF calibration in millisecond
> and changes RSSI reporting frequency consequently.
> Short calibration period will trigger more frequent NF calibration,
> so that RSSI reported in receive frames is more realistic.
>
> Till now calibration was done at 30 seconds.
>
> Signed-off-by: Peter Oh <poh at qca.qualcomm.com>

There was a trivial conflict in struct ath10k_debug, please double check
my conflict resolution:

https://github.com/kvalo/ath/commit/1abcc1aa6046231a55a296ea78ab2f374f6f791b

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 25 23:16:29 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 26 Nov 2014 09:16:29 +0200
Subject: [PATCH] ath10k: Do not limit RTS threshold value to 2347
In-Reply-To: <54737A8C.40102@candelatech.com> (Ben Greear's message of "Mon,
 24 Nov 2014 10:35:56 -0800")
References: <1416830240-3019-1-git-send-email-nataraja@qti.qualcomm.com>
 <54737A8C.40102@candelatech.com>
Message-ID: <87zjbewhwy.fsf@kamboji.qca.qualcomm.com>

Ben Greear <greearb at candelatech.com> writes:

> On 11/24/2014 03:57 AM, Vivek Natarajan wrote:
>> Increase the rts threshold from the legacy value of 2347 to support higher
>> threshold limit.
>
> Does any firmware actually support RTS?  It didn't work last I tested
> it on 10.1.

Vivek?

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Tue Nov 25 23:21:16 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Wed, 26 Nov 2014 09:21:16 +0200
Subject: [PATCH 1/3] ath10k: embed supported chip ids in hw_params
In-Reply-To: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Mon, 24 Nov 2014 15:17:24 +0100")
References: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87vbm2whoz.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> This will make it easier to extend and maintain
> list of supported hardware.
>
> As a requirement this moves chip_id checking a
> little later because target_version isn't known
> until BMI can be queried.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

The reason why I originally added the chip_id check was that QCA988X hw
1.0 failed badly (ath10k might have even crashed, don't remember
anymore) and I added this chip_id as an ugly workaround to detect hw1.0
early. Most likely with this patch the problem comes back again.

I don't know what's a good solution, need to think more. Any ideas?

-- 
Kalle Valo


From nataraja at qti.qualcomm.com  Tue Nov 25 23:29:37 2014
From: nataraja at qti.qualcomm.com (Natarajan, Vivekanandan)
Date: Wed, 26 Nov 2014 07:29:37 +0000
Subject: [PATCH] ath10k: Do not limit RTS threshold value to 2347
In-Reply-To: <54737A8C.40102@candelatech.com>
References: <1416830240-3019-1-git-send-email-nataraja@qti.qualcomm.com>,
 <54737A8C.40102@candelatech.com>
Message-ID: <6523f8d09c714868843b0927b8830a71@APHYDEXM01E.ap.qualcomm.com>

It works with the 10.2 firmware.

Moreover, the issue reported here was rts_threshold displayed in debugfs was different than the one that we had configured to the firmware(2347) .

Thanks
________________________________________
From: Ben Greear <greearb at candelatech.com>
Sent: Tuesday, November 25, 2014 12:05 AM
To: Natarajan, Vivekanandan
Cc: Valo, Kalle; ath10k at lists.infradead.org
Subject: Re: [PATCH] ath10k: Do not limit RTS threshold value to 2347

On 11/24/2014 03:57 AM, Vivek Natarajan wrote:
> Increase the rts threshold from the legacy value of 2347 to support higher
> threshold limit.

Does any firmware actually support RTS?  It didn't work last I tested
it on 10.1.

Thanks,
Ben

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



From michal.kazior at tieto.com  Tue Nov 25 23:54:30 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Wed, 26 Nov 2014 08:54:30 +0100
Subject: [PATCH 1/3] ath10k: embed supported chip ids in hw_params
In-Reply-To: <87vbm2whoz.fsf@kamboji.qca.qualcomm.com>
References: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
 <87vbm2whoz.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CA+BoTQ=56six2CEQ6Rzr7yMEM7UVNQ3RX9UpdgmxMEoG0+kDAA@mail.gmail.com>

On 26 November 2014 at 08:21, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Michal Kazior <michal.kazior at tieto.com> writes:
>
>> This will make it easier to extend and maintain
>> list of supported hardware.
>>
>> As a requirement this moves chip_id checking a
>> little later because target_version isn't known
>> until BMI can be queried.
>>
>> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
>
> The reason why I originally added the chip_id check was that QCA988X hw
> 1.0 failed badly (ath10k might have even crashed, don't remember
> anymore) and I added this chip_id as an ugly workaround to detect hw1.0
> early. Most likely with this patch the problem comes back again.

Hmm.. good point. I think it mostly failed during firmware transfer to
target but since BMI also needs CE then it might as well fail mid-way.


> I don't know what's a good solution, need to think more. Any ideas?

Hmm.. I have a couple of ideas:

1. Don't use BMI to read target_version. Instead use a register
(assuming there is one). This implies each transport (we have pci only
now) would need to be able to read it somehow unless we support a
fallback to BMI if it wasn't prepped by the transport.

2. Have a dedicatd pci-specific structure:

 struct ath10k_pci_supported_chip {
   u16 dev_id;
   u32 chip_id;
 };

 struct ath10k_pci_supported_chip ath10k_pci_supported_chips[] = {
   { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV },
   // ...
 };

Probably the simplest and has least impact.

3. Don't use target_version to decide hw_params. Use pci device id
instead. This is a bit of a problem because ath10k_hw_params_list is
in core and is supposed to be transport-agnostic (but should it really
be? I can imagine theoretical usb transport could have devices
reporting identical target_version as a pci one but would need
different firmware files to be used). This probably needs more
thinking through.


Micha?


From psidhu at gateworks.com  Wed Nov 26 14:36:16 2014
From: psidhu at gateworks.com (Pushpal Sidhu)
Date: Wed, 26 Nov 2014 14:36:16 -0800
Subject: IBSS mode is now supported by CT firmware.
In-Reply-To: <547525D4.5080701@candelatech.com>
References: <547525D4.5080701@candelatech.com>
Message-ID: <CAD1M061uAfCfCnnVY1bh6kCcXXZhwOOiyww5mkU8VkxGov9DwA@mail.gmail.com>

On Tue, Nov 25, 2014 at 4:59 PM, Ben Greear <greearb at candelatech.com> wrote:
> I still cannot get WPA2 encryption to work, but open authentication
> seems to work fine.  I still have a good bit more testing to do.
> I cannot get ath9k to do encryption in IBSS mode either, so I
> probably am mis-configuring something.

I don't believe WPA2 is supported with adhoc (at least through
wpa_supplicant). However, WPA should be and while testing your
firmware, I found that it doesn't seem to work (They don't see each
other and thus don't associate).

I also found that, like the 999.x firmware, the rate's do not go
higher than 54mbit/s. Is this due to the firmware not advertising
proper rates or..?

As for throughput, I get 22mbps TCP, 27.6mbps UDP with no encryption.

- Pushpal


From yeohchunyeow at gmail.com  Wed Nov 26 17:04:59 2014
From: yeohchunyeow at gmail.com (Yeoh Chun-Yeow)
Date: Thu, 27 Nov 2014 09:04:59 +0800
Subject: IBSS mode is now supported by CT firmware.
In-Reply-To: <CAD1M061uAfCfCnnVY1bh6kCcXXZhwOOiyww5mkU8VkxGov9DwA@mail.gmail.com>
References: <547525D4.5080701@candelatech.com>
 <CAD1M061uAfCfCnnVY1bh6kCcXXZhwOOiyww5mkU8VkxGov9DwA@mail.gmail.com>
Message-ID: <CAEFj986B15pFo2WY_2x0VwEXBEBy+j0-nff2-B=Ff=qP66iP_w@mail.gmail.com>

On Thu, Nov 27, 2014 at 6:36 AM, Pushpal Sidhu <psidhu at gateworks.com> wrote:
> On Tue, Nov 25, 2014 at 4:59 PM, Ben Greear <greearb at candelatech.com> wrote:
>> I still cannot get WPA2 encryption to work, but open authentication
>> seems to work fine.  I still have a good bit more testing to do.
>> I cannot get ath9k to do encryption in IBSS mode either, so I
>> probably am mis-configuring something.
>
> I don't believe WPA2 is supported with adhoc (at least through
> wpa_supplicant). However, WPA should be and while testing your
> firmware, I found that it doesn't seem to work (They don't see each
> other and thus don't associate).
>
> I also found that, like the 999.x firmware, the rate's do not go
> higher than 54mbit/s. Is this due to the firmware not advertising
> proper rates or..?

Are you joining the adhoc network in non-HT mode? Anyway, even if you
use HT mode, the rate control is not working for 999.x firmware and
always stuck at 6Mbps as far as I know.

-----
Chun-Yeow


From kvalo at qca.qualcomm.com  Wed Nov 26 23:30:09 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Thu, 27 Nov 2014 09:30:09 +0200
Subject: [PATCH 1/3] ath10k: embed supported chip ids in hw_params
In-Reply-To: <CA+BoTQ=56six2CEQ6Rzr7yMEM7UVNQ3RX9UpdgmxMEoG0+kDAA@mail.gmail.com>
 (Michal Kazior's message of "Wed, 26 Nov 2014 08:54:30 +0100")
References: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
 <87vbm2whoz.fsf@kamboji.qca.qualcomm.com>
 <CA+BoTQ=56six2CEQ6Rzr7yMEM7UVNQ3RX9UpdgmxMEoG0+kDAA@mail.gmail.com>
Message-ID: <87ppc9umm6.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> 2. Have a dedicatd pci-specific structure:
>
>  struct ath10k_pci_supported_chip {
>    u16 dev_id;
>    u32 chip_id;
>  };
>
>  struct ath10k_pci_supported_chip ath10k_pci_supported_chips[] = {
>    { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV },
>    // ...
>  };
>
> Probably the simplest and has least impact.

Another idea which is a variation of this:

In ath10k_core_register() we iterate through ath10k_hw_params_list and
make sure that the chip id is supported and if not, bail out. If the
chip id is found from the array continue the registration process like
in this patch. Basically this would be a whitelist check.

-- 
Kalle Valo


From michal.kazior at tieto.com  Wed Nov 26 23:45:38 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 27 Nov 2014 08:45:38 +0100
Subject: [PATCH 1/3] ath10k: embed supported chip ids in hw_params
In-Reply-To: <87ppc9umm6.fsf@kamboji.qca.qualcomm.com>
References: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
 <87vbm2whoz.fsf@kamboji.qca.qualcomm.com>
 <CA+BoTQ=56six2CEQ6Rzr7yMEM7UVNQ3RX9UpdgmxMEoG0+kDAA@mail.gmail.com>
 <87ppc9umm6.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CA+BoTQ=dt9fMHpCYk6ofX5W4=Ynn7C4t+vCoHHuZM1oF3Ngdtw@mail.gmail.com>

On 27 November 2014 at 08:30, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Michal Kazior <michal.kazior at tieto.com> writes:
>
>> 2. Have a dedicatd pci-specific structure:
>>
>>  struct ath10k_pci_supported_chip {
>>    u16 dev_id;
>>    u32 chip_id;
>>  };
>>
>>  struct ath10k_pci_supported_chip ath10k_pci_supported_chips[] = {
>>    { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV },
>>    // ...
>>  };
>>
>> Probably the simplest and has least impact.
>
> Another idea which is a variation of this:
>
> In ath10k_core_register() we iterate through ath10k_hw_params_list and
> make sure that the chip id is supported and if not, bail out. If the
> chip id is found from the array continue the registration process like
> in this patch. Basically this would be a whitelist check.

This won't work because chip ids can overlap between different
hardware designs and you'd get false positives.


Micha?


From kvalo at qca.qualcomm.com  Wed Nov 26 23:46:00 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Thu, 27 Nov 2014 09:46:00 +0200
Subject: [PATCH V2] ath10k: read calibration data from Device Tree
In-Reply-To: <1415823056-10876-1-git-send-email-toshik@chromium.org> (Toshi
 Kikuchi's message of "Wed, 12 Nov 2014 12:10:56 -0800")
References: <1415823056-10876-1-git-send-email-toshik@chromium.org>
Message-ID: <87lhmxulvr.fsf@kamboji.qca.qualcomm.com>

Toshi Kikuchi <toshik at chromium.org> writes:

> V1->V2: fixed a bug that returns an uninitialized value if the node
> is not found.
>
> This patch adds support for reading calibration data from Device Tree.
> It looks for the calibration data in Device Tree if it can't find it
> in a file.
>
> The node for the calibration data should be defined like this:
>
> pci {
>         pcie at 0 {
>                 reg = <0 0 0 0 0>;
>                 #interrupt-cells = <1>;
>                 #size-cells = <2>;
>                 #address-cells = <3>;
>                 device_type = "pci";
>
>                 ath10k at 0,0 {
>                         reg = <0 0 0 0 0>;
>                         device_type = "pci";
>                         qcom,ath10k-calibration-data = [ 01 02 03 ... ];
>                 };
>         };
> };
>
> Change-Id: I6fe3c50fe2de9177d031a4c17bd95152372dd993
> Signed-off-by: Toshi Kikuchi <toshik at chromium.org>

Thanks! I'll fix some issues I found in the patch, write a bindings
document and send it for review to the devicetree folks.

-- 
Kalle Valo


From michal.kazior at tieto.com  Wed Nov 26 23:42:11 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 27 Nov 2014 08:42:11 +0100
Subject: [PATCH] ath10k: add pointer constness to traces
Message-ID: <1417074131-18460-1-git-send-email-michal.kazior@tieto.com>

Traces shouldn't modified passed data. This will
make it possible to pass const arguments to
traces.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/trace.h | 31 +++++++++++++++++--------------
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h
index ceea566..b289378 100644
--- a/drivers/net/wireless/ath/ath10k/trace.h
+++ b/drivers/net/wireless/ath/ath10k/trace.h
@@ -21,9 +21,11 @@
 #include "core.h"
 
 #if !defined(_TRACE_H_)
-static inline u32 ath10k_frm_hdr_len(void *buf)
+static inline u32 ath10k_frm_hdr_len(const void *buf)
 {
-	return ieee80211_hdrlen(((struct ieee80211_hdr *)buf)->frame_control);
+	const struct ieee80211_hdr *hdr = buf;
+
+	return ieee80211_hdrlen(hdr->frame_control);
 }
 #endif
 
@@ -145,7 +147,8 @@ TRACE_EVENT(ath10k_log_dbg_dump,
 );
 
 TRACE_EVENT(ath10k_wmi_cmd,
-	TP_PROTO(struct ath10k *ar, int id, void *buf, size_t buf_len, int ret),
+	TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len,
+		 int ret),
 
 	TP_ARGS(ar, id, buf, buf_len, ret),
 
@@ -178,7 +181,7 @@ TRACE_EVENT(ath10k_wmi_cmd,
 );
 
 TRACE_EVENT(ath10k_wmi_event,
-	TP_PROTO(struct ath10k *ar, int id, void *buf, size_t buf_len),
+	TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len),
 
 	TP_ARGS(ar, id, buf, buf_len),
 
@@ -208,7 +211,7 @@ TRACE_EVENT(ath10k_wmi_event,
 );
 
 TRACE_EVENT(ath10k_htt_stats,
-	TP_PROTO(struct ath10k *ar, void *buf, size_t buf_len),
+	TP_PROTO(struct ath10k *ar, const void *buf, size_t buf_len),
 
 	TP_ARGS(ar, buf, buf_len),
 
@@ -235,7 +238,7 @@ TRACE_EVENT(ath10k_htt_stats,
 );
 
 TRACE_EVENT(ath10k_wmi_dbglog,
-	TP_PROTO(struct ath10k *ar, void *buf, size_t buf_len),
+	TP_PROTO(struct ath10k *ar, const void *buf, size_t buf_len),
 
 	TP_ARGS(ar, buf, buf_len),
 
@@ -262,7 +265,7 @@ TRACE_EVENT(ath10k_wmi_dbglog,
 );
 
 TRACE_EVENT(ath10k_htt_pktlog,
-	    TP_PROTO(struct ath10k *ar, void *buf, u16 buf_len),
+	    TP_PROTO(struct ath10k *ar, const void *buf, u16 buf_len),
 
 	TP_ARGS(ar, buf, buf_len),
 
@@ -349,7 +352,7 @@ TRACE_EVENT(ath10k_txrx_tx_unref,
 );
 
 DECLARE_EVENT_CLASS(ath10k_hdr_event,
-		    TP_PROTO(struct ath10k *ar, void *data, size_t len),
+		    TP_PROTO(struct ath10k *ar, const void *data, size_t len),
 
 	TP_ARGS(ar, data, len),
 
@@ -376,7 +379,7 @@ DECLARE_EVENT_CLASS(ath10k_hdr_event,
 );
 
 DECLARE_EVENT_CLASS(ath10k_payload_event,
-		    TP_PROTO(struct ath10k *ar, void *data, size_t len),
+		    TP_PROTO(struct ath10k *ar, const void *data, size_t len),
 
 	TP_ARGS(ar, data, len),
 
@@ -404,27 +407,27 @@ DECLARE_EVENT_CLASS(ath10k_payload_event,
 );
 
 DEFINE_EVENT(ath10k_hdr_event, ath10k_tx_hdr,
-	     TP_PROTO(struct ath10k *ar, void *data, size_t len),
+	     TP_PROTO(struct ath10k *ar, const void *data, size_t len),
 	     TP_ARGS(ar, data, len)
 );
 
 DEFINE_EVENT(ath10k_payload_event, ath10k_tx_payload,
-	     TP_PROTO(struct ath10k *ar, void *data, size_t len),
+	     TP_PROTO(struct ath10k *ar, const void *data, size_t len),
 	     TP_ARGS(ar, data, len)
 );
 
 DEFINE_EVENT(ath10k_hdr_event, ath10k_rx_hdr,
-	     TP_PROTO(struct ath10k *ar, void *data, size_t len),
+	     TP_PROTO(struct ath10k *ar, const void *data, size_t len),
 	     TP_ARGS(ar, data, len)
 );
 
 DEFINE_EVENT(ath10k_payload_event, ath10k_rx_payload,
-	     TP_PROTO(struct ath10k *ar, void *data, size_t len),
+	     TP_PROTO(struct ath10k *ar, const void *data, size_t len),
 	     TP_ARGS(ar, data, len)
 );
 
 TRACE_EVENT(ath10k_htt_rx_desc,
-	    TP_PROTO(struct ath10k *ar, void *data, size_t len),
+	    TP_PROTO(struct ath10k *ar, const void *data, size_t len),
 
 	TP_ARGS(ar, data, len),
 
-- 
1.8.5.3



From michal.kazior at tieto.com  Thu Nov 27 01:11:14 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 27 Nov 2014 10:11:14 +0100
Subject: [PATCH v2 0/7] ath10k: add support for new wmi-tlv backend
Message-ID: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>

Hi,

First 2 patches are simple fixes. Patch 3 isn't
strictly related to wmi-tlv but I decided to
include it anyway. Other patches gradually
implement wmi-tlv.

There's a bunch of false-positive checkpatch
warnings regarding `CHECK: No space is necessary
after a cast`.

v2:
 * a lot of fixes (see notes on patch #7)

Michal Kazior (7):
  ath10k: fix wmi svc bitmap dbg print
  ath10k: add sanity checks for service bmap parsing
  ath10k: make wmi service bitmap non-debug
  ath10k: implement intermediate event args
  ath10k: introduce wmi ops
  ath10k: make some wmi functions public
  ath10k: implement wmi-tlv backend

 drivers/net/wireless/ath/ath10k/Makefile   |    1 +
 drivers/net/wireless/ath/ath10k/ce.c       |    2 +
 drivers/net/wireless/ath/ath10k/core.c     |    4 +
 drivers/net/wireless/ath/ath10k/core.h     |    6 +-
 drivers/net/wireless/ath/ath10k/debug.c    |   12 +-
 drivers/net/wireless/ath/ath10k/debug.h    |    9 -
 drivers/net/wireless/ath/ath10k/hw.h       |    9 +
 drivers/net/wireless/ath/ath10k/mac.c      |   47 +
 drivers/net/wireless/ath/ath10k/spectral.c |    1 +
 drivers/net/wireless/ath/ath10k/wmi-ops.h  |  820 ++++++++++
 drivers/net/wireless/ath/ath10k/wmi-tlv.c  | 2218 ++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi-tlv.h  | 1380 +++++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi.c      | 1359 ++++++++++-------
 drivers/net/wireless/ath/ath10k/wmi.h      |  386 +++--
 14 files changed, 5593 insertions(+), 661 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath10k/wmi-ops.h
 create mode 100644 drivers/net/wireless/ath/ath10k/wmi-tlv.c
 create mode 100644 drivers/net/wireless/ath/ath10k/wmi-tlv.h

-- 
1.8.5.3



From michal.kazior at tieto.com  Thu Nov 27 01:11:15 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 27 Nov 2014 10:11:15 +0100
Subject: [PATCH v2 1/7] ath10k: fix wmi svc bitmap dbg print
In-Reply-To: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
References: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1417079481-22255-2-git-send-email-michal.kazior@tieto.com>

The dump print uses sizeof() but since service_map
was a mere pointer the dump was too short.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/wmi.c | 4 +++-
 drivers/net/wireless/ath/ath10k/wmi.h | 1 +
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 23fee9a..c6c03e5 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2457,6 +2457,7 @@ static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb,
 	arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
 	arg->num_mem_reqs = ev->num_mem_reqs;
 	arg->service_map = ev->wmi_service_bitmap;
+	arg->service_map_len = sizeof(ev->wmi_service_bitmap);
 
 	n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs),
 		  ARRAY_SIZE(arg->mem_reqs));
@@ -2491,6 +2492,7 @@ static int ath10k_wmi_10x_pull_svc_rdy_ev(struct sk_buff *skb,
 	arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
 	arg->num_mem_reqs = ev->num_mem_reqs;
 	arg->service_map = ev->wmi_service_bitmap;
+	arg->service_map_len = sizeof(ev->wmi_service_bitmap);
 
 	n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs),
 		  ARRAY_SIZE(arg->mem_reqs));
@@ -2541,7 +2543,7 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar,
 
 	ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
 	ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
-			arg.service_map, sizeof(arg.service_map));
+			arg.service_map, arg.service_map_len);
 
 	/* only manually set fw features when not using FW IE format */
 	if (ar->fw_api == 1 && ar->fw_version_build > 636)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 1b7141a..fc6b844 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -4577,6 +4577,7 @@ struct wmi_svc_rdy_ev_arg {
 	__le32 eeprom_rd;
 	__le32 num_mem_reqs;
 	const __le32 *service_map;
+	size_t service_map_len;
 	const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS];
 };
 
-- 
1.8.5.3



From michal.kazior at tieto.com  Thu Nov 27 01:11:17 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 27 Nov 2014 10:11:17 +0100
Subject: [PATCH v2 3/7] ath10k: make wmi service bitmap non-debug
In-Reply-To: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
References: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1417079481-22255-4-git-send-email-michal.kazior@tieto.com>

The service bitmap can be used to determine
firmware capabilities.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h  |  2 +-
 drivers/net/wireless/ath/ath10k/debug.c | 11 +++--------
 drivers/net/wireless/ath/ath10k/debug.h |  9 ---------
 drivers/net/wireless/ath/ath10k/wmi.c   |  8 ++++----
 4 files changed, 8 insertions(+), 22 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 4a29498..5af9a24 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -123,6 +123,7 @@ struct ath10k_wmi {
 	struct completion service_ready;
 	struct completion unified_ready;
 	wait_queue_head_t tx_credits_wq;
+	DECLARE_BITMAP(svc_map, WMI_SERVICE_MAX);
 	struct wmi_cmd_map *cmd;
 	struct wmi_vdev_param_map *vdev_param;
 	struct wmi_pdev_param_map *pdev_param;
@@ -313,7 +314,6 @@ struct ath10k_debug {
 	struct ath10k_fw_stats fw_stats;
 	struct completion fw_stats_complete;
 	bool fw_stats_done;
-	DECLARE_BITMAP(wmi_service_bitmap, WMI_SERVICE_MAX);
 
 	unsigned long htt_stats_mask;
 	struct delayed_work htt_stats_dwork;
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index c096d00a..a716758 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -179,13 +179,6 @@ EXPORT_SYMBOL(ath10k_warn);
 
 #ifdef CONFIG_ATH10K_DEBUGFS
 
-void ath10k_debug_read_service_map(struct ath10k *ar,
-				   const void *service_map,
-				   size_t map_size)
-{
-	memcpy(ar->debug.wmi_service_bitmap, service_map, map_size);
-}
-
 static ssize_t ath10k_read_wmi_services(struct file *file,
 					char __user *user_buf,
 					size_t count, loff_t *ppos)
@@ -207,8 +200,9 @@ static ssize_t ath10k_read_wmi_services(struct file *file,
 	if (len > buf_len)
 		len = buf_len;
 
+	spin_lock_bh(&ar->data_lock);
 	for (i = 0; i < WMI_SERVICE_MAX; i++) {
-		enabled = test_bit(i, ar->debug.wmi_service_bitmap);
+		enabled = test_bit(i, ar->wmi.svc_map);
 		name = wmi_service_name(i);
 
 		if (!name) {
@@ -224,6 +218,7 @@ static ssize_t ath10k_read_wmi_services(struct file *file,
 				 "%-40s %s\n",
 				 name, enabled ? "enabled" : "-");
 	}
+	spin_unlock_bh(&ar->data_lock);
 
 	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
 
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index 815d325..1b87a5d 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -62,9 +62,6 @@ int ath10k_debug_create(struct ath10k *ar);
 void ath10k_debug_destroy(struct ath10k *ar);
 int ath10k_debug_register(struct ath10k *ar);
 void ath10k_debug_unregister(struct ath10k *ar);
-void ath10k_debug_read_service_map(struct ath10k *ar,
-				   const void *service_map,
-				   size_t map_size);
 void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb);
 struct ath10k_fw_crash_data *
 ath10k_debug_get_new_fw_crash_data(struct ath10k *ar);
@@ -109,12 +106,6 @@ static inline void ath10k_debug_unregister(struct ath10k *ar)
 {
 }
 
-static inline void ath10k_debug_read_service_map(struct ath10k *ar,
-						 const void *service_map,
-						 size_t map_size)
-{
-}
-
 static inline void ath10k_debug_fw_stats_process(struct ath10k *ar,
 						 struct sk_buff *skb)
 {
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 81ccc2e..c0f3e4d 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2511,16 +2511,17 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar,
 {
 	struct wmi_svc_rdy_ev_arg arg = {};
 	u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
-	DECLARE_BITMAP(svc_bmap, WMI_SERVICE_MAX) = {};
 	int ret;
 
+	memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map));
+
 	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
 		ret = ath10k_wmi_10x_pull_svc_rdy_ev(skb, &arg);
-		wmi_10x_svc_map(arg.service_map, svc_bmap,
+		wmi_10x_svc_map(arg.service_map, ar->wmi.svc_map,
 				arg.service_map_len);
 	} else {
 		ret = ath10k_wmi_main_pull_svc_rdy_ev(skb, &arg);
-		wmi_main_svc_map(arg.service_map, svc_bmap,
+		wmi_main_svc_map(arg.service_map, ar->wmi.svc_map,
 				 arg.service_map_len);
 	}
 
@@ -2543,7 +2544,6 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar,
 	ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains);
 	ar->ath_common.regulatory.current_rd = __le32_to_cpu(arg.eeprom_rd);
 
-	ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
 	ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
 			arg.service_map, arg.service_map_len);
 
-- 
1.8.5.3



From michal.kazior at tieto.com  Thu Nov 27 01:11:16 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 27 Nov 2014 10:11:16 +0100
Subject: [PATCH v2 2/7] ath10k: add sanity checks for service bmap parsing
In-Reply-To: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
References: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1417079481-22255-3-git-send-email-michal.kazior@tieto.com>

This shouldn't really happen but take into account
the original service bitmap length when mapping
service ids.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---

Notes:
    v2:
     * remove space between brackets as per checkpatch warning

 drivers/net/wireless/ath/ath10k/wmi.c |   6 +-
 drivers/net/wireless/ath/ath10k/wmi.h | 121 +++++++++++++++++-----------------
 2 files changed, 66 insertions(+), 61 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c6c03e5..81ccc2e 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2516,10 +2516,12 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar,
 
 	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
 		ret = ath10k_wmi_10x_pull_svc_rdy_ev(skb, &arg);
-		wmi_10x_svc_map(arg.service_map, svc_bmap);
+		wmi_10x_svc_map(arg.service_map, svc_bmap,
+				arg.service_map_len);
 	} else {
 		ret = ath10k_wmi_main_pull_svc_rdy_ev(skb, &arg);
-		wmi_main_svc_map(arg.service_map, svc_bmap);
+		wmi_main_svc_map(arg.service_map, svc_bmap,
+				 arg.service_map_len);
 	}
 
 	if (ret) {
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index fc6b844..724929d 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -222,128 +222,131 @@ static inline char *wmi_service_name(int service_id)
 #undef SVCSTR
 }
 
-#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \
-	(__le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
+#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \
+	((svc_id) < (len) && \
+	 __le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
 	 BIT((svc_id)%(sizeof(u32))))
 
-#define SVCMAP(x, y) \
+#define SVCMAP(x, y, len) \
 	do { \
-		if (WMI_SERVICE_IS_ENABLED((in), (x))) \
+		if (WMI_SERVICE_IS_ENABLED((in), (x), (len))) \
 			__set_bit(y, out); \
 	} while (0)
 
-static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out)
+static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out,
+				   size_t len)
 {
 	SVCMAP(WMI_10X_SERVICE_BEACON_OFFLOAD,
-	       WMI_SERVICE_BEACON_OFFLOAD);
+	       WMI_SERVICE_BEACON_OFFLOAD, len);
 	SVCMAP(WMI_10X_SERVICE_SCAN_OFFLOAD,
-	       WMI_SERVICE_SCAN_OFFLOAD);
+	       WMI_SERVICE_SCAN_OFFLOAD, len);
 	SVCMAP(WMI_10X_SERVICE_ROAM_OFFLOAD,
-	       WMI_SERVICE_ROAM_OFFLOAD);
+	       WMI_SERVICE_ROAM_OFFLOAD, len);
 	SVCMAP(WMI_10X_SERVICE_BCN_MISS_OFFLOAD,
-	       WMI_SERVICE_BCN_MISS_OFFLOAD);
+	       WMI_SERVICE_BCN_MISS_OFFLOAD, len);
 	SVCMAP(WMI_10X_SERVICE_STA_PWRSAVE,
-	       WMI_SERVICE_STA_PWRSAVE);
+	       WMI_SERVICE_STA_PWRSAVE, len);
 	SVCMAP(WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE,
-	       WMI_SERVICE_STA_ADVANCED_PWRSAVE);
+	       WMI_SERVICE_STA_ADVANCED_PWRSAVE, len);
 	SVCMAP(WMI_10X_SERVICE_AP_UAPSD,
-	       WMI_SERVICE_AP_UAPSD);
+	       WMI_SERVICE_AP_UAPSD, len);
 	SVCMAP(WMI_10X_SERVICE_AP_DFS,
-	       WMI_SERVICE_AP_DFS);
+	       WMI_SERVICE_AP_DFS, len);
 	SVCMAP(WMI_10X_SERVICE_11AC,
-	       WMI_SERVICE_11AC);
+	       WMI_SERVICE_11AC, len);
 	SVCMAP(WMI_10X_SERVICE_BLOCKACK,
-	       WMI_SERVICE_BLOCKACK);
+	       WMI_SERVICE_BLOCKACK, len);
 	SVCMAP(WMI_10X_SERVICE_PHYERR,
-	       WMI_SERVICE_PHYERR);
+	       WMI_SERVICE_PHYERR, len);
 	SVCMAP(WMI_10X_SERVICE_BCN_FILTER,
-	       WMI_SERVICE_BCN_FILTER);
+	       WMI_SERVICE_BCN_FILTER, len);
 	SVCMAP(WMI_10X_SERVICE_RTT,
-	       WMI_SERVICE_RTT);
+	       WMI_SERVICE_RTT, len);
 	SVCMAP(WMI_10X_SERVICE_RATECTRL,
-	       WMI_SERVICE_RATECTRL);
+	       WMI_SERVICE_RATECTRL, len);
 	SVCMAP(WMI_10X_SERVICE_WOW,
-	       WMI_SERVICE_WOW);
+	       WMI_SERVICE_WOW, len);
 	SVCMAP(WMI_10X_SERVICE_RATECTRL_CACHE,
-	       WMI_SERVICE_RATECTRL_CACHE);
+	       WMI_SERVICE_RATECTRL_CACHE, len);
 	SVCMAP(WMI_10X_SERVICE_IRAM_TIDS,
-	       WMI_SERVICE_IRAM_TIDS);
+	       WMI_SERVICE_IRAM_TIDS, len);
 	SVCMAP(WMI_10X_SERVICE_BURST,
-	       WMI_SERVICE_BURST);
+	       WMI_SERVICE_BURST, len);
 	SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT,
-	       WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT);
+	       WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT, len);
 	SVCMAP(WMI_10X_SERVICE_FORCE_FW_HANG,
-	       WMI_SERVICE_FORCE_FW_HANG);
+	       WMI_SERVICE_FORCE_FW_HANG, len);
 	SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
-	       WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT);
+	       WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT, len);
 }
 
-static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out)
+static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out,
+				    size_t len)
 {
 	SVCMAP(WMI_MAIN_SERVICE_BEACON_OFFLOAD,
-	       WMI_SERVICE_BEACON_OFFLOAD);
+	       WMI_SERVICE_BEACON_OFFLOAD, len);
 	SVCMAP(WMI_MAIN_SERVICE_SCAN_OFFLOAD,
-	       WMI_SERVICE_SCAN_OFFLOAD);
+	       WMI_SERVICE_SCAN_OFFLOAD, len);
 	SVCMAP(WMI_MAIN_SERVICE_ROAM_OFFLOAD,
-	       WMI_SERVICE_ROAM_OFFLOAD);
+	       WMI_SERVICE_ROAM_OFFLOAD, len);
 	SVCMAP(WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD,
-	       WMI_SERVICE_BCN_MISS_OFFLOAD);
+	       WMI_SERVICE_BCN_MISS_OFFLOAD, len);
 	SVCMAP(WMI_MAIN_SERVICE_STA_PWRSAVE,
-	       WMI_SERVICE_STA_PWRSAVE);
+	       WMI_SERVICE_STA_PWRSAVE, len);
 	SVCMAP(WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE,
-	       WMI_SERVICE_STA_ADVANCED_PWRSAVE);
+	       WMI_SERVICE_STA_ADVANCED_PWRSAVE, len);
 	SVCMAP(WMI_MAIN_SERVICE_AP_UAPSD,
-	       WMI_SERVICE_AP_UAPSD);
+	       WMI_SERVICE_AP_UAPSD, len);
 	SVCMAP(WMI_MAIN_SERVICE_AP_DFS,
-	       WMI_SERVICE_AP_DFS);
+	       WMI_SERVICE_AP_DFS, len);
 	SVCMAP(WMI_MAIN_SERVICE_11AC,
-	       WMI_SERVICE_11AC);
+	       WMI_SERVICE_11AC, len);
 	SVCMAP(WMI_MAIN_SERVICE_BLOCKACK,
-	       WMI_SERVICE_BLOCKACK);
+	       WMI_SERVICE_BLOCKACK, len);
 	SVCMAP(WMI_MAIN_SERVICE_PHYERR,
-	       WMI_SERVICE_PHYERR);
+	       WMI_SERVICE_PHYERR, len);
 	SVCMAP(WMI_MAIN_SERVICE_BCN_FILTER,
-	       WMI_SERVICE_BCN_FILTER);
+	       WMI_SERVICE_BCN_FILTER, len);
 	SVCMAP(WMI_MAIN_SERVICE_RTT,
-	       WMI_SERVICE_RTT);
+	       WMI_SERVICE_RTT, len);
 	SVCMAP(WMI_MAIN_SERVICE_RATECTRL,
-	       WMI_SERVICE_RATECTRL);
+	       WMI_SERVICE_RATECTRL, len);
 	SVCMAP(WMI_MAIN_SERVICE_WOW,
-	       WMI_SERVICE_WOW);
+	       WMI_SERVICE_WOW, len);
 	SVCMAP(WMI_MAIN_SERVICE_RATECTRL_CACHE,
-	       WMI_SERVICE_RATECTRL_CACHE);
+	       WMI_SERVICE_RATECTRL_CACHE, len);
 	SVCMAP(WMI_MAIN_SERVICE_IRAM_TIDS,
-	       WMI_SERVICE_IRAM_TIDS);
+	       WMI_SERVICE_IRAM_TIDS, len);
 	SVCMAP(WMI_MAIN_SERVICE_ARPNS_OFFLOAD,
-	       WMI_SERVICE_ARPNS_OFFLOAD);
+	       WMI_SERVICE_ARPNS_OFFLOAD, len);
 	SVCMAP(WMI_MAIN_SERVICE_NLO,
-	       WMI_SERVICE_NLO);
+	       WMI_SERVICE_NLO, len);
 	SVCMAP(WMI_MAIN_SERVICE_GTK_OFFLOAD,
-	       WMI_SERVICE_GTK_OFFLOAD);
+	       WMI_SERVICE_GTK_OFFLOAD, len);
 	SVCMAP(WMI_MAIN_SERVICE_SCAN_SCH,
-	       WMI_SERVICE_SCAN_SCH);
+	       WMI_SERVICE_SCAN_SCH, len);
 	SVCMAP(WMI_MAIN_SERVICE_CSA_OFFLOAD,
-	       WMI_SERVICE_CSA_OFFLOAD);
+	       WMI_SERVICE_CSA_OFFLOAD, len);
 	SVCMAP(WMI_MAIN_SERVICE_CHATTER,
-	       WMI_SERVICE_CHATTER);
+	       WMI_SERVICE_CHATTER, len);
 	SVCMAP(WMI_MAIN_SERVICE_COEX_FREQAVOID,
-	       WMI_SERVICE_COEX_FREQAVOID);
+	       WMI_SERVICE_COEX_FREQAVOID, len);
 	SVCMAP(WMI_MAIN_SERVICE_PACKET_POWER_SAVE,
-	       WMI_SERVICE_PACKET_POWER_SAVE);
+	       WMI_SERVICE_PACKET_POWER_SAVE, len);
 	SVCMAP(WMI_MAIN_SERVICE_FORCE_FW_HANG,
-	       WMI_SERVICE_FORCE_FW_HANG);
+	       WMI_SERVICE_FORCE_FW_HANG, len);
 	SVCMAP(WMI_MAIN_SERVICE_GPIO,
-	       WMI_SERVICE_GPIO);
+	       WMI_SERVICE_GPIO, len);
 	SVCMAP(WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
-	       WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM);
+	       WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, len);
 	SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
-	       WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG);
+	       WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len);
 	SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
-	       WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG);
+	       WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len);
 	SVCMAP(WMI_MAIN_SERVICE_STA_KEEP_ALIVE,
-	       WMI_SERVICE_STA_KEEP_ALIVE);
+	       WMI_SERVICE_STA_KEEP_ALIVE, len);
 	SVCMAP(WMI_MAIN_SERVICE_TX_ENCAP,
-	       WMI_SERVICE_TX_ENCAP);
+	       WMI_SERVICE_TX_ENCAP, len);
 }
 
 #undef SVCMAP
-- 
1.8.5.3



From michal.kazior at tieto.com  Thu Nov 27 01:11:18 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 27 Nov 2014 10:11:18 +0100
Subject: [PATCH v2 4/7] ath10k: implement intermediate event args
In-Reply-To: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
References: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1417079481-22255-5-git-send-email-michal.kazior@tieto.com>

This splits the actual event parsing into
intermediary structures to facilitate future
support of vastly different ABI WMI backends.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/wmi.c | 383 +++++++++++++++++++++++++---------
 drivers/net/wireless/ath/ath10k/wmi.h |  60 +++++-
 2 files changed, 347 insertions(+), 96 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c0f3e4d..4a9468e 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -977,22 +977,48 @@ ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type,
 	}
 }
 
+static int ath10k_wmi_pull_scan_ev(struct sk_buff *skb,
+				   struct wmi_scan_ev_arg *arg)
+{
+	struct wmi_scan_event *ev = (void *)skb->data;
+
+	if (skb->len < sizeof(*ev))
+		return -EPROTO;
+
+	skb_pull(skb, sizeof(*ev));
+	arg->event_type = ev->event_type;
+	arg->reason = ev->reason;
+	arg->channel_freq = ev->channel_freq;
+	arg->scan_req_id = ev->scan_req_id;
+	arg->scan_id = ev->scan_id;
+	arg->vdev_id = ev->vdev_id;
+
+	return 0;
+}
+
 static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
 {
-	struct wmi_scan_event *event = (struct wmi_scan_event *)skb->data;
+	struct wmi_scan_ev_arg arg = {};
 	enum wmi_scan_event_type event_type;
 	enum wmi_scan_completion_reason reason;
 	u32 freq;
 	u32 req_id;
 	u32 scan_id;
 	u32 vdev_id;
+	int ret;
 
-	event_type = __le32_to_cpu(event->event_type);
-	reason     = __le32_to_cpu(event->reason);
-	freq       = __le32_to_cpu(event->channel_freq);
-	req_id     = __le32_to_cpu(event->scan_req_id);
-	scan_id    = __le32_to_cpu(event->scan_id);
-	vdev_id    = __le32_to_cpu(event->vdev_id);
+	ret = ath10k_wmi_pull_scan_ev(skb, &arg);
+	if (ret) {
+		ath10k_warn(ar, "failed to parse scan event: %d\n", ret);
+		return ret;
+	}
+
+	event_type = __le32_to_cpu(arg.event_type);
+	reason = __le32_to_cpu(arg.reason);
+	freq = __le32_to_cpu(arg.channel_freq);
+	req_id = __le32_to_cpu(arg.scan_req_id);
+	scan_id = __le32_to_cpu(arg.scan_id);
+	vdev_id = __le32_to_cpu(arg.vdev_id);
 
 	spin_lock_bh(&ar->data_lock);
 
@@ -1147,11 +1173,52 @@ static void ath10k_wmi_handle_wep_reauth(struct ath10k *ar,
 	}
 }
 
-static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_wmi_pull_mgmt_rx_ev(struct sk_buff *skb,
+				      struct wmi_mgmt_rx_ev_arg *arg,
+				      struct ath10k *ar)
 {
 	struct wmi_mgmt_rx_event_v1 *ev_v1;
 	struct wmi_mgmt_rx_event_v2 *ev_v2;
 	struct wmi_mgmt_rx_hdr_v1 *ev_hdr;
+	size_t pull_len;
+	u32 msdu_len;
+
+	if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) {
+		ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data;
+		ev_hdr = &ev_v2->hdr.v1;
+		pull_len = sizeof(*ev_v2);
+	} else {
+		ev_v1 = (struct wmi_mgmt_rx_event_v1 *)skb->data;
+		ev_hdr = &ev_v1->hdr;
+		pull_len = sizeof(*ev_v1);
+	}
+
+	if (skb->len < pull_len)
+		return -EPROTO;
+
+	skb_pull(skb, pull_len);
+	arg->channel = ev_hdr->channel;
+	arg->buf_len = ev_hdr->buf_len;
+	arg->status = ev_hdr->status;
+	arg->snr = ev_hdr->snr;
+	arg->phy_mode = ev_hdr->phy_mode;
+	arg->rate = ev_hdr->rate;
+
+	msdu_len = __le32_to_cpu(arg->buf_len);
+	if (skb->len < msdu_len)
+		return -EPROTO;
+
+	/* the WMI buffer might've ended up being padded to 4 bytes due to HTC
+	 * trailer with credit update. Trim the excess garbage.
+	 */
+	skb_trim(skb, msdu_len);
+
+	return 0;
+}
+
+static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
+{
+	struct wmi_mgmt_rx_ev_arg arg = {};
 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 	struct ieee80211_hdr *hdr;
 	u32 rx_status;
@@ -1161,24 +1228,20 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 	u32 rate;
 	u32 buf_len;
 	u16 fc;
-	int pull_len;
+	int ret;
 
-	if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) {
-		ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data;
-		ev_hdr = &ev_v2->hdr.v1;
-		pull_len = sizeof(*ev_v2);
-	} else {
-		ev_v1 = (struct wmi_mgmt_rx_event_v1 *)skb->data;
-		ev_hdr = &ev_v1->hdr;
-		pull_len = sizeof(*ev_v1);
+	ret = ath10k_wmi_pull_mgmt_rx_ev(skb, &arg, ar);
+	if (ret) {
+		ath10k_warn(ar, "failed to parse mgmt rx event: %d\n", ret);
+		return ret;
 	}
 
-	channel   = __le32_to_cpu(ev_hdr->channel);
-	buf_len   = __le32_to_cpu(ev_hdr->buf_len);
-	rx_status = __le32_to_cpu(ev_hdr->status);
-	snr       = __le32_to_cpu(ev_hdr->snr);
-	phy_mode  = __le32_to_cpu(ev_hdr->phy_mode);
-	rate	  = __le32_to_cpu(ev_hdr->rate);
+	channel = __le32_to_cpu(arg.channel);
+	buf_len = __le32_to_cpu(arg.buf_len);
+	rx_status = __le32_to_cpu(arg.status);
+	snr = __le32_to_cpu(arg.snr);
+	phy_mode = __le32_to_cpu(arg.phy_mode);
+	rate = __le32_to_cpu(arg.rate);
 
 	memset(status, 0, sizeof(*status));
 
@@ -1232,8 +1295,6 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 	status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR;
 	status->rate_idx = get_rate_idx(rate, status->band);
 
-	skb_pull(skb, pull_len);
-
 	hdr = (struct ieee80211_hdr *)skb->data;
 	fc = le16_to_cpu(hdr->frame_control);
 
@@ -1266,12 +1327,6 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 		   status->freq, status->band, status->signal,
 		   status->rate_idx);
 
-	/*
-	 * packets from HTC come aligned to 4byte boundaries
-	 * because they can originally come in along with a trailer
-	 */
-	skb_trim(skb, buf_len);
-
 	ieee80211_rx(ar->hw, skb);
 	return 0;
 }
@@ -1295,21 +1350,44 @@ exit:
 	return idx;
 }
 
+static int ath10k_wmi_pull_ch_info_ev(struct sk_buff *skb,
+				      struct wmi_ch_info_ev_arg *arg)
+{
+	struct wmi_chan_info_event *ev = (void *)skb->data;
+
+	if (skb->len < sizeof(*ev))
+		return -EPROTO;
+
+	skb_pull(skb, sizeof(*ev));
+	arg->err_code = ev->err_code;
+	arg->freq = ev->freq;
+	arg->cmd_flags = ev->cmd_flags;
+	arg->noise_floor = ev->noise_floor;
+	arg->rx_clear_count = ev->rx_clear_count;
+	arg->cycle_count = ev->cycle_count;
+
+	return 0;
+}
+
 static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
 {
-	struct wmi_chan_info_event *ev;
+	struct wmi_ch_info_ev_arg arg = {};
 	struct survey_info *survey;
 	u32 err_code, freq, cmd_flags, noise_floor, rx_clear_count, cycle_count;
-	int idx;
+	int idx, ret;
 
-	ev = (struct wmi_chan_info_event *)skb->data;
+	ret = ath10k_wmi_pull_ch_info_ev(skb, &arg);
+	if (ret) {
+		ath10k_warn(ar, "failed to parse chan info event: %d\n", ret);
+		return;
+	}
 
-	err_code = __le32_to_cpu(ev->err_code);
-	freq = __le32_to_cpu(ev->freq);
-	cmd_flags = __le32_to_cpu(ev->cmd_flags);
-	noise_floor = __le32_to_cpu(ev->noise_floor);
-	rx_clear_count = __le32_to_cpu(ev->rx_clear_count);
-	cycle_count = __le32_to_cpu(ev->cycle_count);
+	err_code = __le32_to_cpu(arg.err_code);
+	freq = __le32_to_cpu(arg.freq);
+	cmd_flags = __le32_to_cpu(arg.cmd_flags);
+	noise_floor = __le32_to_cpu(arg.noise_floor);
+	rx_clear_count = __le32_to_cpu(arg.rx_clear_count);
+	cycle_count = __le32_to_cpu(arg.cycle_count);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n",
@@ -1566,16 +1644,38 @@ static void ath10k_wmi_event_update_stats(struct ath10k *ar,
 	ath10k_debug_fw_stats_process(ar, skb);
 }
 
+static int ath10k_wmi_pull_vdev_start_ev(struct sk_buff *skb,
+					 struct wmi_vdev_start_ev_arg *arg)
+{
+	struct wmi_vdev_start_response_event *ev = (void *)skb->data;
+
+	if (skb->len < sizeof(*ev))
+		return -EPROTO;
+
+	skb_pull(skb, sizeof(*ev));
+	arg->vdev_id = ev->vdev_id;
+	arg->req_id = ev->req_id;
+	arg->resp_type = ev->resp_type;
+	arg->status = ev->status;
+
+	return 0;
+}
+
 static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar,
 					     struct sk_buff *skb)
 {
-	struct wmi_vdev_start_response_event *ev;
+	struct wmi_vdev_start_ev_arg arg = {};
+	int ret;
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n");
 
-	ev = (struct wmi_vdev_start_response_event *)skb->data;
+	ret = ath10k_wmi_pull_vdev_start_ev(skb, &arg);
+	if (ret) {
+		ath10k_warn(ar, "failed to parse vdev start event: %d\n", ret);
+		return;
+	}
 
-	if (WARN_ON(__le32_to_cpu(ev->status)))
+	if (WARN_ON(__le32_to_cpu(arg.status)))
 		return;
 
 	complete(&ar->vdev_setup_done);
@@ -1588,23 +1688,43 @@ static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar,
 	complete(&ar->vdev_setup_done);
 }
 
+static int ath10k_wmi_pull_peer_kick_ev(struct sk_buff *skb,
+					struct wmi_peer_kick_ev_arg *arg)
+{
+	struct wmi_peer_sta_kickout_event *ev = (void *)skb->data;
+
+	if (skb->len < sizeof(*ev))
+		return -EPROTO;
+
+	skb_pull(skb, sizeof(*ev));
+	arg->mac_addr = ev->peer_macaddr.addr;
+
+	return 0;
+}
+
 static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar,
 					      struct sk_buff *skb)
 {
-	struct wmi_peer_sta_kickout_event *ev;
+	struct wmi_peer_kick_ev_arg arg = {};
 	struct ieee80211_sta *sta;
+	int ret;
 
-	ev = (struct wmi_peer_sta_kickout_event *)skb->data;
+	ret = ath10k_wmi_pull_peer_kick_ev(skb, &arg);
+	if (ret) {
+		ath10k_warn(ar, "failed to parse peer kickout event: %d\n",
+			    ret);
+		return;
+	}
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
-		   ev->peer_macaddr.addr);
+		   arg.mac_addr);
 
 	rcu_read_lock();
 
-	sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL);
+	sta = ieee80211_find_sta_by_ifaddr(ar->hw, arg.mac_addr, NULL);
 	if (!sta) {
 		ath10k_warn(ar, "Spurious quick kickout for STA %pM\n",
-			    ev->peer_macaddr.addr);
+			    arg.mac_addr);
 		goto exit;
 	}
 
@@ -1641,7 +1761,7 @@ exit:
 static void ath10k_wmi_update_tim(struct ath10k *ar,
 				  struct ath10k_vif *arvif,
 				  struct sk_buff *bcn,
-				  struct wmi_bcn_info *bcn_info)
+				  const struct wmi_tim_info *tim_info)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)bcn->data;
 	struct ieee80211_tim_ie *tim;
@@ -1652,14 +1772,14 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
 
 	/* if next SWBA has no tim_changed the tim_bitmap is garbage.
 	 * we must copy the bitmap upon change and reuse it later */
-	if (__le32_to_cpu(bcn_info->tim_info.tim_changed)) {
+	if (__le32_to_cpu(tim_info->tim_changed)) {
 		int i;
 
 		BUILD_BUG_ON(sizeof(arvif->u.ap.tim_bitmap) !=
-			     sizeof(bcn_info->tim_info.tim_bitmap));
+			     sizeof(tim_info->tim_bitmap));
 
 		for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) {
-			t = bcn_info->tim_info.tim_bitmap[i / 4];
+			t = tim_info->tim_bitmap[i / 4];
 			v = __le32_to_cpu(t);
 			arvif->u.ap.tim_bitmap[i] = (v >> ((i % 4) * 8)) & 0xFF;
 		}
@@ -1711,13 +1831,13 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
 		return;
 	}
 
-	tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast);
+	tim->bitmap_ctrl = !!__le32_to_cpu(tim_info->tim_mcast);
 	memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len);
 
 	if (tim->dtim_count == 0) {
 		ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true;
 
-		if (__le32_to_cpu(bcn_info->tim_info.tim_mcast) == 1)
+		if (__le32_to_cpu(tim_info->tim_mcast) == 1)
 			ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true;
 	}
 
@@ -1727,7 +1847,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
 }
 
 static void ath10k_p2p_fill_noa_ie(u8 *data, u32 len,
-				   struct wmi_p2p_noa_info *noa)
+				   const struct wmi_p2p_noa_info *noa)
 {
 	struct ieee80211_p2p_noa_attr *noa_attr;
 	u8  ctwindow_oppps = noa->ctwindow_oppps;
@@ -1769,7 +1889,7 @@ static void ath10k_p2p_fill_noa_ie(u8 *data, u32 len,
 	*noa_attr_len = __cpu_to_le16(attr_len);
 }
 
-static u32 ath10k_p2p_calc_noa_ie_len(struct wmi_p2p_noa_info *noa)
+static u32 ath10k_p2p_calc_noa_ie_len(const struct wmi_p2p_noa_info *noa)
 {
 	u32 len = 0;
 	u8 noa_descriptors = noa->num_descriptors;
@@ -1789,9 +1909,8 @@ static u32 ath10k_p2p_calc_noa_ie_len(struct wmi_p2p_noa_info *noa)
 
 static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif,
 				  struct sk_buff *bcn,
-				  struct wmi_bcn_info *bcn_info)
+				  const struct wmi_p2p_noa_info *noa)
 {
-	struct wmi_p2p_noa_info *noa = &bcn_info->p2p_noa_info;
 	u8 *new_data, *old_data = arvif->u.ap.noa_data;
 	u32 new_len;
 
@@ -1832,22 +1951,59 @@ cleanup:
 	kfree(old_data);
 }
 
+static int ath10k_wmi_pull_swba_ev(struct sk_buff *skb,
+				   struct wmi_swba_ev_arg *arg)
+{
+	struct wmi_host_swba_event *ev = (void *)skb->data;
+	u32 map;
+	size_t i;
+
+	if (skb->len < sizeof(*ev))
+		return -EPROTO;
+
+	skb_pull(skb, sizeof(*ev));
+	arg->vdev_map = ev->vdev_map;
+
+	for (i = 0, map = __le32_to_cpu(ev->vdev_map); map; map >>= 1) {
+		if (!(map & BIT(0)))
+			continue;
+
+		/* If this happens there were some changes in firmware and
+		 * ath10k should update the max size of tim_info array.
+		 */
+		if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info)))
+			break;
+
+		arg->tim_info[i] = &ev->bcn_info[i].tim_info;
+		arg->noa_info[i] = &ev->bcn_info[i].p2p_noa_info;
+		i++;
+	}
+
+	return 0;
+}
+
 static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
 {
-	struct wmi_host_swba_event *ev;
+	struct wmi_swba_ev_arg arg = {};
 	u32 map;
 	int i = -1;
-	struct wmi_bcn_info *bcn_info;
+	const struct wmi_tim_info *tim_info;
+	const struct wmi_p2p_noa_info *noa_info;
 	struct ath10k_vif *arvif;
 	struct sk_buff *bcn;
 	dma_addr_t paddr;
 	int ret, vdev_id = 0;
 
-	ev = (struct wmi_host_swba_event *)skb->data;
-	map = __le32_to_cpu(ev->vdev_map);
+	ret = ath10k_wmi_pull_swba_ev(skb, &arg);
+	if (ret) {
+		ath10k_warn(ar, "failed to parse swba event: %d\n", ret);
+		return;
+	}
+
+	map = __le32_to_cpu(arg.vdev_map);
 
 	ath10k_dbg(ar, ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n",
-		   ev->vdev_map);
+		   map);
 
 	for (; map; map >>= 1, vdev_id++) {
 		if (!(map & 0x1))
@@ -1860,19 +2016,20 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
 			break;
 		}
 
-		bcn_info = &ev->bcn_info[i];
+		tim_info = arg.tim_info[i];
+		noa_info = arg.noa_info[i];
 
 		ath10k_dbg(ar, ATH10K_DBG_MGMT,
 			   "mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n",
 			   i,
-			   __le32_to_cpu(bcn_info->tim_info.tim_len),
-			   __le32_to_cpu(bcn_info->tim_info.tim_mcast),
-			   __le32_to_cpu(bcn_info->tim_info.tim_changed),
-			   __le32_to_cpu(bcn_info->tim_info.tim_num_ps_pending),
-			   __le32_to_cpu(bcn_info->tim_info.tim_bitmap[3]),
-			   __le32_to_cpu(bcn_info->tim_info.tim_bitmap[2]),
-			   __le32_to_cpu(bcn_info->tim_info.tim_bitmap[1]),
-			   __le32_to_cpu(bcn_info->tim_info.tim_bitmap[0]));
+			   __le32_to_cpu(tim_info->tim_len),
+			   __le32_to_cpu(tim_info->tim_mcast),
+			   __le32_to_cpu(tim_info->tim_changed),
+			   __le32_to_cpu(tim_info->tim_num_ps_pending),
+			   __le32_to_cpu(tim_info->tim_bitmap[3]),
+			   __le32_to_cpu(tim_info->tim_bitmap[2]),
+			   __le32_to_cpu(tim_info->tim_bitmap[1]),
+			   __le32_to_cpu(tim_info->tim_bitmap[0]));
 
 		arvif = ath10k_get_arvif(ar, vdev_id);
 		if (arvif == NULL) {
@@ -1899,8 +2056,8 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
 		}
 
 		ath10k_tx_h_seq_no(arvif->vif, bcn);
-		ath10k_wmi_update_tim(ar, arvif, bcn, bcn_info);
-		ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info);
+		ath10k_wmi_update_tim(ar, arvif, bcn, tim_info);
+		ath10k_wmi_update_noa(ar, arvif, bcn, noa_info);
 
 		spin_lock_bh(&ar->data_lock);
 
@@ -2188,37 +2345,53 @@ ath10k_wmi_event_spectral_scan(struct ath10k *ar,
 	}
 }
 
+static int ath10k_wmi_pull_phyerr_ev(struct sk_buff *skb,
+				     struct wmi_phyerr_ev_arg *arg)
+{
+	struct wmi_phyerr_event *ev = (void *)skb->data;
+
+	if (skb->len < sizeof(*ev))
+		return -EPROTO;
+
+	arg->num_phyerrs = ev->num_phyerrs;
+	arg->tsf_l32 = ev->tsf_l32;
+	arg->tsf_u32 = ev->tsf_u32;
+	arg->buf_len = __cpu_to_le32(skb->len - sizeof(*ev));
+	arg->phyerrs = ev->phyerrs;
+
+	return 0;
+}
+
 static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
 {
-	const struct wmi_phyerr_event *ev;
+	struct wmi_phyerr_ev_arg arg = {};
 	const struct wmi_phyerr *phyerr;
 	u32 count, i, buf_len, phy_err_code;
 	u64 tsf;
-	int left_len = skb->len;
+	int left_len, ret;
 
 	ATH10K_DFS_STAT_INC(ar, phy_errors);
 
-	/* Check if combined event available */
-	if (left_len < sizeof(*ev)) {
-		ath10k_warn(ar, "wmi phyerr combined event wrong len\n");
+	ret = ath10k_wmi_pull_phyerr_ev(skb, &arg);
+	if (ret) {
+		ath10k_warn(ar, "failed to parse phyerr event: %d\n", ret);
 		return;
 	}
 
-	left_len -= sizeof(*ev);
+	left_len = __le32_to_cpu(arg.buf_len);
 
 	/* Check number of included events */
-	ev = (const struct wmi_phyerr_event *)skb->data;
-	count = __le32_to_cpu(ev->num_phyerrs);
+	count = __le32_to_cpu(arg.num_phyerrs);
 
-	tsf = __le32_to_cpu(ev->tsf_u32);
+	tsf = __le32_to_cpu(arg.tsf_u32);
 	tsf <<= 32;
-	tsf |= __le32_to_cpu(ev->tsf_l32);
+	tsf |= __le32_to_cpu(arg.tsf_l32);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi event phyerr count %d tsf64 0x%llX\n",
 		   count, tsf);
 
-	phyerr = ev->phyerrs;
+	phyerr = arg.phyerrs;
 	for (i = 0; i < count; i++) {
 		/* Check if we can read event header */
 		if (left_len < sizeof(*phyerr)) {
@@ -2622,22 +2795,42 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar,
 	complete(&ar->wmi.service_ready);
 }
 
-static int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_wmi_pull_rdy_ev(struct sk_buff *skb,
+				  struct wmi_rdy_ev_arg *arg)
 {
-	struct wmi_ready_event *ev = (struct wmi_ready_event *)skb->data;
+	struct wmi_ready_event *ev = (void *)skb->data;
 
-	if (WARN_ON(skb->len < sizeof(*ev)))
-		return -EINVAL;
+	if (skb->len < sizeof(*ev))
+		return -EPROTO;
+
+	skb_pull(skb, sizeof(*ev));
+	arg->sw_version = ev->sw_version;
+	arg->abi_version = ev->abi_version;
+	arg->status = ev->status;
+	arg->mac_addr = ev->mac_addr.addr;
+
+	return 0;
+}
 
-	ether_addr_copy(ar->mac_addr, ev->mac_addr.addr);
+static int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
+{
+	struct wmi_rdy_ev_arg arg = {};
+	int ret;
+
+	ret = ath10k_wmi_pull_rdy_ev(skb, &arg);
+	if (ret) {
+		ath10k_warn(ar, "failed to parse ready event: %d\n", ret);
+		return ret;
+	}
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
-		   "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n",
-		   __le32_to_cpu(ev->sw_version),
-		   __le32_to_cpu(ev->abi_version),
-		   ev->mac_addr.addr,
-		   __le32_to_cpu(ev->status), skb->len, sizeof(*ev));
+		   "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n",
+		   __le32_to_cpu(arg.sw_version),
+		   __le32_to_cpu(arg.abi_version),
+		   arg.mac_addr,
+		   __le32_to_cpu(arg.status));
 
+	ether_addr_copy(ar->mac_addr, arg.mac_addr);
 	complete(&ar->wmi.unified_ready);
 	return 0;
 }
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 724929d..0952bc2 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -4120,7 +4120,7 @@ struct wmi_bcn_info {
 
 struct wmi_host_swba_event {
 	__le32 vdev_map;
-	struct wmi_bcn_info bcn_info[1];
+	struct wmi_bcn_info bcn_info[0];
 } __packed;
 
 #define WMI_MAX_AP_VDEV 16
@@ -4568,6 +4568,57 @@ struct wmi_dbglog_cfg_cmd {
 
 #define WMI_MAX_MEM_REQS 16
 
+struct wmi_scan_ev_arg {
+	__le32 event_type; /* %WMI_SCAN_EVENT_ */
+	__le32 reason; /* %WMI_SCAN_REASON_ */
+	__le32 channel_freq; /* only valid for WMI_SCAN_EVENT_FOREIGN_CHANNEL */
+	__le32 scan_req_id;
+	__le32 scan_id;
+	__le32 vdev_id;
+};
+
+struct wmi_mgmt_rx_ev_arg {
+	__le32 channel;
+	__le32 snr;
+	__le32 rate;
+	__le32 phy_mode;
+	__le32 buf_len;
+	__le32 status; /* %WMI_RX_STATUS_ */
+};
+
+struct wmi_ch_info_ev_arg {
+	__le32 err_code;
+	__le32 freq;
+	__le32 cmd_flags;
+	__le32 noise_floor;
+	__le32 rx_clear_count;
+	__le32 cycle_count;
+};
+
+struct wmi_vdev_start_ev_arg {
+	__le32 vdev_id;
+	__le32 req_id;
+	__le32 resp_type; /* %WMI_VDEV_RESP_ */
+	__le32 status;
+};
+
+struct wmi_peer_kick_ev_arg {
+	const u8 *mac_addr;
+};
+
+struct wmi_swba_ev_arg {
+	__le32 vdev_map;
+	const struct wmi_tim_info *tim_info[WMI_MAX_AP_VDEV];
+	const struct wmi_p2p_noa_info *noa_info[WMI_MAX_AP_VDEV];
+};
+
+struct wmi_phyerr_ev_arg {
+	__le32 num_phyerrs;
+	__le32 tsf_l32;
+	__le32 tsf_u32;
+	__le32 buf_len;
+	const struct wmi_phyerr *phyerrs;
+};
 struct wmi_svc_rdy_ev_arg {
 	__le32 min_tx_power;
 	__le32 max_tx_power;
@@ -4584,6 +4635,13 @@ struct wmi_svc_rdy_ev_arg {
 	const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS];
 };
 
+struct wmi_rdy_ev_arg {
+	__le32 sw_version;
+	__le32 abi_version;
+	__le32 status;
+	const u8 *mac_addr;
+};
+
 struct ath10k;
 struct ath10k_vif;
 struct ath10k_fw_stats;
-- 
1.8.5.3



From michal.kazior at tieto.com  Thu Nov 27 01:11:20 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 27 Nov 2014 10:11:20 +0100
Subject: [PATCH v2 6/7] ath10k: make some wmi functions public
In-Reply-To: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
References: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1417079481-22255-7-git-send-email-michal.kazior@tieto.com>

Some functions can be shared across different WMI
ABIs. Make them public so different WMI backends
can use them from different source files in the
future.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/wmi.c | 136 ++++++++++++++--------------------
 drivers/net/wireless/ath/ath10k/wmi.h |  61 +++++++++++++++
 2 files changed, 117 insertions(+), 80 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 0f3c410..e2dbe39 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -610,9 +610,8 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = {
 	.gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,
 };
 
-static void
-ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
-			   const struct wmi_channel_arg *arg)
+void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
+				const struct wmi_channel_arg *arg)
 {
 	u32 flags = 0;
 
@@ -987,7 +986,7 @@ static int ath10k_wmi_op_pull_scan_ev(struct ath10k *ar, struct sk_buff *skb,
 	return 0;
 }
 
-static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
+int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_scan_ev_arg arg = {};
 	enum wmi_scan_event_type event_type;
@@ -1206,7 +1205,7 @@ static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb,
 	return 0;
 }
 
-static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
+int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_mgmt_rx_ev_arg arg = {};
 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
@@ -1359,7 +1358,7 @@ static int ath10k_wmi_op_pull_ch_info_ev(struct ath10k *ar, struct sk_buff *skb,
 	return 0;
 }
 
-static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
+void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_ch_info_ev_arg arg = {};
 	struct survey_info *survey;
@@ -1427,12 +1426,12 @@ exit:
 	spin_unlock_bh(&ar->data_lock);
 }
 
-static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
+void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");
 }
 
-static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
+int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
 		   skb->len);
@@ -1442,8 +1441,8 @@ static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
 	return 0;
 }
 
-static void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src,
-				       struct ath10k_fw_stats_pdev *dst)
+void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src,
+				struct ath10k_fw_stats_pdev *dst)
 {
 	const struct wal_dbg_tx_stats *tx = &src->wal.tx;
 	const struct wal_dbg_rx_stats *rx = &src->wal.rx;
@@ -1495,8 +1494,8 @@ static void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src,
 	dst->mpdu_errs = __le32_to_cpu(rx->mpdu_errs);
 }
 
-static void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src,
-				       struct ath10k_fw_stats_peer *dst)
+void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src,
+				struct ath10k_fw_stats_peer *dst)
 {
 	ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr);
 	dst->peer_rssi = __le32_to_cpu(src->peer_rssi);
@@ -1618,8 +1617,7 @@ static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k *ar,
 	return 0;
 }
 
-static void ath10k_wmi_event_update_stats(struct ath10k *ar,
-					  struct sk_buff *skb)
+void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n");
 	ath10k_debug_fw_stats_process(ar, skb);
@@ -1643,8 +1641,7 @@ ath10k_wmi_op_pull_vdev_start_ev(struct ath10k *ar, struct sk_buff *skb,
 	return 0;
 }
 
-static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar,
-					     struct sk_buff *skb)
+void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_vdev_start_ev_arg arg = {};
 	int ret;
@@ -1663,8 +1660,7 @@ static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar,
 	complete(&ar->vdev_setup_done);
 }
 
-static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar,
-					  struct sk_buff *skb)
+void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n");
 	complete(&ar->vdev_setup_done);
@@ -1685,8 +1681,7 @@ ath10k_wmi_op_pull_peer_kick_ev(struct ath10k *ar, struct sk_buff *skb,
 	return 0;
 }
 
-static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar,
-					      struct sk_buff *skb)
+void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_peer_kick_ev_arg arg = {};
 	struct ieee80211_sta *sta;
@@ -1965,7 +1960,7 @@ static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb,
 	return 0;
 }
 
-static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
+void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_swba_ev_arg arg = {};
 	u32 map;
@@ -2086,8 +2081,7 @@ skip:
 	}
 }
 
-static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar,
-					       struct sk_buff *skb)
+void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
 }
@@ -2208,9 +2202,9 @@ static int ath10k_dfs_fft_report(struct ath10k *ar,
 	return 0;
 }
 
-static void ath10k_wmi_event_dfs(struct ath10k *ar,
-				 const struct wmi_phyerr *phyerr,
-				 u64 tsf)
+void ath10k_wmi_event_dfs(struct ath10k *ar,
+			  const struct wmi_phyerr *phyerr,
+			  u64 tsf)
 {
 	int buf_len, tlv_len, res, i = 0;
 	const struct phyerr_tlv *tlv;
@@ -2273,10 +2267,9 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar,
 	}
 }
 
-static void
-ath10k_wmi_event_spectral_scan(struct ath10k *ar,
-			       const struct wmi_phyerr *phyerr,
-			       u64 tsf)
+void ath10k_wmi_event_spectral_scan(struct ath10k *ar,
+				    const struct wmi_phyerr *phyerr,
+				    u64 tsf)
 {
 	int buf_len, tlv_len, res, i = 0;
 	struct phyerr_tlv *tlv;
@@ -2345,7 +2338,7 @@ static int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, struct sk_buff *skb,
 	return 0;
 }
 
-static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
+void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_phyerr_ev_arg arg = {};
 	const struct wmi_phyerr *phyerr;
@@ -2414,19 +2407,17 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
 	}
 }
 
-static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb)
+void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n");
 }
 
-static void ath10k_wmi_event_profile_match(struct ath10k *ar,
-					   struct sk_buff *skb)
+void ath10k_wmi_event_profile_match(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n");
 }
 
-static void ath10k_wmi_event_debug_print(struct ath10k *ar,
-					 struct sk_buff *skb)
+void ath10k_wmi_event_debug_print(struct ath10k *ar, struct sk_buff *skb)
 {
 	char buf[101], c;
 	int i;
@@ -2459,103 +2450,90 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar,
 	ath10k_dbg(ar, ATH10K_DBG_WMI_PRINT, "wmi print '%s'\n", buf);
 }
 
-static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
+void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n");
 }
 
-static void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar,
-					       struct sk_buff *skb)
+void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n");
 }
 
-static void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar,
-						    struct sk_buff *skb)
+void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar,
+					     struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n");
 }
 
-static void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar,
-						    struct sk_buff *skb)
+void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar,
+					     struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n");
 }
 
-static void ath10k_wmi_event_rtt_error_report(struct ath10k *ar,
-					      struct sk_buff *skb)
+void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n");
 }
 
-static void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar,
-					     struct sk_buff *skb)
+void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n");
 }
 
-static void ath10k_wmi_event_dcs_interference(struct ath10k *ar,
-					      struct sk_buff *skb)
+void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n");
 }
 
-static void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar,
-					     struct sk_buff *skb)
+void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n");
 }
 
-static void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar,
-					   struct sk_buff *skb)
+void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
 }
 
-static void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar,
-						struct sk_buff *skb)
+void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n");
 }
 
-static void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar,
-					    struct sk_buff *skb)
+void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n");
 }
 
-static void ath10k_wmi_event_delba_complete(struct ath10k *ar,
-					    struct sk_buff *skb)
+void ath10k_wmi_event_delba_complete(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n");
 }
 
-static void ath10k_wmi_event_addba_complete(struct ath10k *ar,
-					    struct sk_buff *skb)
+void ath10k_wmi_event_addba_complete(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n");
 }
 
-static void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,
-						       struct sk_buff *skb)
+void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,
+						struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n");
 }
 
-static void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar,
-					     struct sk_buff *skb)
+void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n");
 }
 
-static void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar,
-					      struct sk_buff *skb)
+void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n");
 }
 
-static void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar,
-					     struct sk_buff *skb)
+void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb)
 {
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
 }
@@ -2664,8 +2642,7 @@ ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
 	return 0;
 }
 
-static void ath10k_wmi_event_service_ready(struct ath10k *ar,
-					   struct sk_buff *skb)
+void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_svc_rdy_ev_arg arg = {};
 	u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
@@ -2790,7 +2767,7 @@ static int ath10k_wmi_op_pull_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
 	return 0;
 }
 
-static int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
+int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_rdy_ev_arg arg = {};
 	int ret;
@@ -3311,8 +3288,8 @@ ath10k_wmi_op_gen_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
 	return skb;
 }
 
-static void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar,
-					   struct wmi_host_mem_chunks *chunks)
+void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar,
+				    struct wmi_host_mem_chunks *chunks)
 {
 	struct host_memory_chunk *chunk;
 	int i;
@@ -3539,7 +3516,7 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
 	return buf;
 }
 
-static int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg)
+int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg)
 {
 	if (arg->ie_len && !arg->ie)
 		return -EINVAL;
@@ -3590,9 +3567,8 @@ ath10k_wmi_start_scan_tlvs_len(const struct wmi_start_scan_arg *arg)
 	return len;
 }
 
-static void
-ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn,
-				 const struct wmi_start_scan_arg *arg)
+void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn,
+				      const struct wmi_start_scan_arg *arg)
 {
 	u32 scan_id;
 	u32 scan_req_id;
@@ -4470,8 +4446,8 @@ ath10k_wmi_op_gen_beacon_dma(struct ath10k_vif *arvif)
 	return skb;
 }
 
-static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params,
-					  const struct wmi_wmm_params_arg *arg)
+void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params,
+				   const struct wmi_wmm_params_arg *arg)
 {
 	params->cwmin  = __cpu_to_le32(arg->cwmin);
 	params->cwmax  = __cpu_to_le32(arg->cwmax);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index b8308f6..bdb87dd 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -4644,12 +4644,15 @@ struct wmi_rdy_ev_arg {
 
 struct ath10k;
 struct ath10k_vif;
+struct ath10k_fw_stats_pdev;
+struct ath10k_fw_stats_peer;
 
 int ath10k_wmi_attach(struct ath10k *ar);
 void ath10k_wmi_detach(struct ath10k *ar);
 int ath10k_wmi_wait_for_service_ready(struct ath10k *ar);
 int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
 
+struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len);
 int ath10k_wmi_connect(struct ath10k *ar);
 
 struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len);
@@ -4658,4 +4661,62 @@ int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
 			       u32 cmd_id);
 void ath10k_wmi_start_scan_init(struct ath10k *ar, struct wmi_start_scan_arg *);
 
+void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src,
+				struct ath10k_fw_stats_pdev *dst);
+void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src,
+				struct ath10k_fw_stats_peer *dst);
+void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar,
+				    struct wmi_host_mem_chunks *chunks);
+void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn,
+				      const struct wmi_start_scan_arg *arg);
+void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params,
+				   const struct wmi_wmm_params_arg *arg);
+void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
+				const struct wmi_channel_arg *arg);
+int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg);
+
+int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb);
+int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb);
+int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_dfs(struct ath10k *ar,
+			  const struct wmi_phyerr *phyerr, u64 tsf);
+void ath10k_wmi_event_spectral_scan(struct ath10k *ar,
+				    const struct wmi_phyerr *phyerr,
+				    u64 tsf);
+void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_profile_match(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_debug_print(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar,
+					     struct sk_buff *skb);
+void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar,
+					     struct sk_buff *skb);
+void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar,
+					 struct sk_buff *skb);
+void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_delba_complete(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_addba_complete(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,
+						struct sk_buff *skb);
+void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb);
+int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb);
+
 #endif /* _WMI_H_ */
-- 
1.8.5.3



From michal.kazior at tieto.com  Thu Nov 27 01:11:19 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 27 Nov 2014 10:11:19 +0100
Subject: [PATCH v2 5/7] ath10k: introduce wmi ops
In-Reply-To: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
References: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1417079481-22255-6-git-send-email-michal.kazior@tieto.com>

Since the 10.x fw branch support was introduced it
became apparent ath10k will need to be able to
deal with different fw ABIs eventually.

The patch creates an abstraction for dealing with
command and event structures across different ABIs
and mostly gets rid of the
ATH10K_FW_FEATURE_WMI_10X flag usage.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.c     |   1 +
 drivers/net/wireless/ath/ath10k/core.h     |   1 +
 drivers/net/wireless/ath/ath10k/debug.c    |   1 +
 drivers/net/wireless/ath/ath10k/mac.c      |   2 +
 drivers/net/wireless/ath/ath10k/spectral.c |   1 +
 drivers/net/wireless/ath/ath10k/wmi-ops.h  | 820 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi.c      | 888 +++++++++++++++++------------
 drivers/net/wireless/ath/ath10k/wmi.h      |  67 +--
 8 files changed, 1345 insertions(+), 436 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath10k/wmi-ops.h

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 7762061..e8384e1 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -27,6 +27,7 @@
 #include "debug.h"
 #include "htt.h"
 #include "testmode.h"
+#include "wmi-ops.h"
 
 unsigned int ath10k_debug_mask;
 static bool uart_print;
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 5af9a24..837972c 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -127,6 +127,7 @@ struct ath10k_wmi {
 	struct wmi_cmd_map *cmd;
 	struct wmi_vdev_param_map *vdev_param;
 	struct wmi_pdev_param_map *pdev_param;
+	const struct wmi_ops *ops;
 
 	u32 num_mem_chunks;
 	struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS];
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index a716758..c15b5774 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -23,6 +23,7 @@
 #include "core.h"
 #include "debug.h"
 #include "hif.h"
+#include "wmi-ops.h"
 
 /* ms */
 #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index e475cc4..2bc97f3 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -27,6 +27,8 @@
 #include "htt.h"
 #include "txrx.h"
 #include "testmode.h"
+#include "wmi.h"
+#include "wmi-ops.h"
 
 /**********/
 /* Crypto */
diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c
index 63ce61f..d22addf 100644
--- a/drivers/net/wireless/ath/ath10k/spectral.c
+++ b/drivers/net/wireless/ath/ath10k/spectral.c
@@ -17,6 +17,7 @@
 #include <linux/relay.h>
 #include "core.h"
 #include "debug.h"
+#include "wmi-ops.h"
 
 static void send_fft_sample(struct ath10k *ar,
 			    const struct fft_sample_tlv *fft_sample_tlv)
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
new file mode 100644
index 0000000..f3b87a8
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -0,0 +1,820 @@
+/*
+ * Copyright (c) 2005-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _WMI_OPS_H_
+#define _WMI_OPS_H_
+
+struct ath10k;
+struct sk_buff;
+
+struct wmi_ops {
+	void (*rx)(struct ath10k *ar, struct sk_buff *skb);
+	void (*map_svc)(const __le32 *in, unsigned long *out, size_t len);
+
+	int (*pull_scan)(struct ath10k *ar, struct sk_buff *skb,
+			 struct wmi_scan_ev_arg *arg);
+	int (*pull_mgmt_rx)(struct ath10k *ar, struct sk_buff *skb,
+			    struct wmi_mgmt_rx_ev_arg *arg);
+	int (*pull_ch_info)(struct ath10k *ar, struct sk_buff *skb,
+			    struct wmi_ch_info_ev_arg *arg);
+	int (*pull_vdev_start)(struct ath10k *ar, struct sk_buff *skb,
+			       struct wmi_vdev_start_ev_arg *arg);
+	int (*pull_peer_kick)(struct ath10k *ar, struct sk_buff *skb,
+			      struct wmi_peer_kick_ev_arg *arg);
+	int (*pull_swba)(struct ath10k *ar, struct sk_buff *skb,
+			 struct wmi_swba_ev_arg *arg);
+	int (*pull_phyerr)(struct ath10k *ar, struct sk_buff *skb,
+			   struct wmi_phyerr_ev_arg *arg);
+	int (*pull_svc_rdy)(struct ath10k *ar, struct sk_buff *skb,
+			    struct wmi_svc_rdy_ev_arg *arg);
+	int (*pull_rdy)(struct ath10k *ar, struct sk_buff *skb,
+			struct wmi_rdy_ev_arg *arg);
+	int (*pull_fw_stats)(struct ath10k *ar, struct sk_buff *skb,
+			     struct ath10k_fw_stats *stats);
+
+	struct sk_buff *(*gen_pdev_suspend)(struct ath10k *ar, u32 suspend_opt);
+	struct sk_buff *(*gen_pdev_resume)(struct ath10k *ar);
+	struct sk_buff *(*gen_pdev_set_rd)(struct ath10k *ar, u16 rd, u16 rd2g,
+					   u16 rd5g, u16 ctl2g, u16 ctl5g,
+					   enum wmi_dfs_region dfs_reg);
+	struct sk_buff *(*gen_pdev_set_param)(struct ath10k *ar, u32 id,
+					      u32 value);
+	struct sk_buff *(*gen_init)(struct ath10k *ar);
+	struct sk_buff *(*gen_start_scan)(struct ath10k *ar,
+					  const struct wmi_start_scan_arg *arg);
+	struct sk_buff *(*gen_stop_scan)(struct ath10k *ar,
+					 const struct wmi_stop_scan_arg *arg);
+	struct sk_buff *(*gen_vdev_create)(struct ath10k *ar, u32 vdev_id,
+					   enum wmi_vdev_type type,
+					   enum wmi_vdev_subtype subtype,
+					   const u8 macaddr[ETH_ALEN]);
+	struct sk_buff *(*gen_vdev_delete)(struct ath10k *ar, u32 vdev_id);
+	struct sk_buff *(*gen_vdev_start)(struct ath10k *ar,
+					  const struct wmi_vdev_start_request_arg *arg,
+					  bool restart);
+	struct sk_buff *(*gen_vdev_stop)(struct ath10k *ar, u32 vdev_id);
+	struct sk_buff *(*gen_vdev_up)(struct ath10k *ar, u32 vdev_id, u32 aid,
+				       const u8 *bssid);
+	struct sk_buff *(*gen_vdev_down)(struct ath10k *ar, u32 vdev_id);
+	struct sk_buff *(*gen_vdev_set_param)(struct ath10k *ar, u32 vdev_id,
+					      u32 param_id, u32 param_value);
+	struct sk_buff *(*gen_vdev_install_key)(struct ath10k *ar,
+						const struct wmi_vdev_install_key_arg *arg);
+	struct sk_buff *(*gen_vdev_spectral_conf)(struct ath10k *ar,
+						  const struct wmi_vdev_spectral_conf_arg *arg);
+	struct sk_buff *(*gen_vdev_spectral_enable)(struct ath10k *ar, u32 vdev_id,
+						    u32 trigger, u32 enable);
+	struct sk_buff *(*gen_peer_create)(struct ath10k *ar, u32 vdev_id,
+					   const u8 peer_addr[ETH_ALEN]);
+	struct sk_buff *(*gen_peer_delete)(struct ath10k *ar, u32 vdev_id,
+					   const u8 peer_addr[ETH_ALEN]);
+	struct sk_buff *(*gen_peer_flush)(struct ath10k *ar, u32 vdev_id,
+					  const u8 peer_addr[ETH_ALEN],
+					  u32 tid_bitmap);
+	struct sk_buff *(*gen_peer_set_param)(struct ath10k *ar, u32 vdev_id,
+					      const u8 *peer_addr,
+					      enum wmi_peer_param param_id,
+					      u32 param_value);
+	struct sk_buff *(*gen_peer_assoc)(struct ath10k *ar,
+					  const struct wmi_peer_assoc_complete_arg *arg);
+	struct sk_buff *(*gen_set_psmode)(struct ath10k *ar, u32 vdev_id,
+					  enum wmi_sta_ps_mode psmode);
+	struct sk_buff *(*gen_set_sta_ps)(struct ath10k *ar, u32 vdev_id,
+					  enum wmi_sta_powersave_param param_id,
+					  u32 value);
+	struct sk_buff *(*gen_set_ap_ps)(struct ath10k *ar, u32 vdev_id,
+					 const u8 *mac,
+					 enum wmi_ap_ps_peer_param param_id,
+					 u32 value);
+	struct sk_buff *(*gen_scan_chan_list)(struct ath10k *ar,
+					      const struct wmi_scan_chan_list_arg *arg);
+	struct sk_buff *(*gen_beacon_dma)(struct ath10k_vif *arvif);
+	struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar,
+					    const struct wmi_pdev_set_wmm_params_arg *arg);
+	struct sk_buff *(*gen_request_stats)(struct ath10k *ar,
+					     enum wmi_stats_id stats_id);
+	struct sk_buff *(*gen_force_fw_hang)(struct ath10k *ar,
+					     enum wmi_force_fw_hang_type type,
+					     u32 delay_ms);
+	struct sk_buff *(*gen_mgmt_tx)(struct ath10k *ar, struct sk_buff *skb);
+	struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u32 module_enable);
+	struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter);
+	struct sk_buff *(*gen_pktlog_disable)(struct ath10k *ar);
+};
+
+int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
+
+static inline int
+ath10k_wmi_rx(struct ath10k *ar, struct sk_buff *skb)
+{
+	if (WARN_ON_ONCE(!ar->wmi.ops->rx))
+		return -EOPNOTSUPP;
+
+	ar->wmi.ops->rx(ar, skb);
+	return 0;
+}
+
+static inline int
+ath10k_wmi_map_svc(struct ath10k *ar, const __le32 *in, unsigned long *out,
+		   size_t len)
+{
+	if (!ar->wmi.ops->map_svc)
+		return -EOPNOTSUPP;
+
+	ar->wmi.ops->map_svc(in, out, len);
+	return 0;
+}
+
+static inline int
+ath10k_wmi_pull_scan(struct ath10k *ar, struct sk_buff *skb,
+		     struct wmi_scan_ev_arg *arg)
+{
+	if (!ar->wmi.ops->pull_scan)
+		return -EOPNOTSUPP;
+
+	return ar->wmi.ops->pull_scan(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_mgmt_rx(struct ath10k *ar, struct sk_buff *skb,
+			struct wmi_mgmt_rx_ev_arg *arg)
+{
+	if (!ar->wmi.ops->pull_mgmt_rx)
+		return -EOPNOTSUPP;
+
+	return ar->wmi.ops->pull_mgmt_rx(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_ch_info(struct ath10k *ar, struct sk_buff *skb,
+			struct wmi_ch_info_ev_arg *arg)
+{
+	if (!ar->wmi.ops->pull_ch_info)
+		return -EOPNOTSUPP;
+
+	return ar->wmi.ops->pull_ch_info(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_vdev_start(struct ath10k *ar, struct sk_buff *skb,
+			   struct wmi_vdev_start_ev_arg *arg)
+{
+	if (!ar->wmi.ops->pull_vdev_start)
+		return -EOPNOTSUPP;
+
+	return ar->wmi.ops->pull_vdev_start(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_peer_kick(struct ath10k *ar, struct sk_buff *skb,
+			  struct wmi_peer_kick_ev_arg *arg)
+{
+	if (!ar->wmi.ops->pull_peer_kick)
+		return -EOPNOTSUPP;
+
+	return ar->wmi.ops->pull_peer_kick(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_swba(struct ath10k *ar, struct sk_buff *skb,
+		     struct wmi_swba_ev_arg *arg)
+{
+	if (!ar->wmi.ops->pull_swba)
+		return -EOPNOTSUPP;
+
+	return ar->wmi.ops->pull_swba(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_phyerr(struct ath10k *ar, struct sk_buff *skb,
+		       struct wmi_phyerr_ev_arg *arg)
+{
+	if (!ar->wmi.ops->pull_phyerr)
+		return -EOPNOTSUPP;
+
+	return ar->wmi.ops->pull_phyerr(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_svc_rdy(struct ath10k *ar, struct sk_buff *skb,
+			struct wmi_svc_rdy_ev_arg *arg)
+{
+	if (!ar->wmi.ops->pull_svc_rdy)
+		return -EOPNOTSUPP;
+
+	return ar->wmi.ops->pull_svc_rdy(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_rdy(struct ath10k *ar, struct sk_buff *skb,
+		    struct wmi_rdy_ev_arg *arg)
+{
+	if (!ar->wmi.ops->pull_rdy)
+		return -EOPNOTSUPP;
+
+	return ar->wmi.ops->pull_rdy(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb,
+			 struct ath10k_fw_stats *stats)
+{
+	if (!ar->wmi.ops->pull_fw_stats)
+		return -EOPNOTSUPP;
+
+	return ar->wmi.ops->pull_fw_stats(ar, skb, stats);
+}
+
+static inline int
+ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
+{
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
+	struct sk_buff *skb;
+	int ret;
+
+	if (!ar->wmi.ops->gen_mgmt_tx)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_mgmt_tx(ar, msdu);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	ret = ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->mgmt_tx_cmdid);
+	if (ret)
+		return ret;
+
+	/* FIXME There's no ACK event for Management Tx. This probably
+	 * shouldn't be called here either. */
+	info->flags |= IEEE80211_TX_STAT_ACK;
+	ieee80211_tx_status_irqsafe(ar->hw, msdu);
+
+	return 0;
+}
+
+static inline int
+ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, u16 rd5g,
+			      u16 ctl2g, u16 ctl5g,
+			      enum wmi_dfs_region dfs_reg)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_pdev_set_rd)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_pdev_set_rd(ar, rd, rd2g, rd5g, ctl2g, ctl5g,
+					   dfs_reg);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb,
+				   ar->wmi.cmd->pdev_set_regdomain_cmdid);
+}
+
+static inline int
+ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_pdev_suspend)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_pdev_suspend(ar, suspend_opt);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid);
+}
+
+static inline int
+ath10k_wmi_pdev_resume_target(struct ath10k *ar)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_pdev_resume)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_pdev_resume(ar);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_resume_cmdid);
+}
+
+static inline int
+ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_pdev_set_param)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_pdev_set_param(ar, id, value);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid);
+}
+
+static inline int
+ath10k_wmi_cmd_init(struct ath10k *ar)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_init)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_init(ar);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->init_cmdid);
+}
+
+static inline int
+ath10k_wmi_start_scan(struct ath10k *ar,
+		      const struct wmi_start_scan_arg *arg)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_start_scan)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_start_scan(ar, arg);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid);
+}
+
+static inline int
+ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_stop_scan)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_stop_scan(ar, arg);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
+		       enum wmi_vdev_type type,
+		       enum wmi_vdev_subtype subtype,
+		       const u8 macaddr[ETH_ALEN])
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_vdev_create)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_vdev_create(ar, vdev_id, type, subtype, macaddr);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_create_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_vdev_delete)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_vdev_delete(ar, vdev_id);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_start(struct ath10k *ar,
+		      const struct wmi_vdev_start_request_arg *arg)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_vdev_start)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_vdev_start(ar, arg, false);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb,
+				   ar->wmi.cmd->vdev_start_request_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_restart(struct ath10k *ar,
+			const struct wmi_vdev_start_request_arg *arg)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_vdev_start)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_vdev_start(ar, arg, true);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb,
+				   ar->wmi.cmd->vdev_restart_request_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_vdev_stop)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_vdev_stop(ar, vdev_id);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_vdev_up)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_vdev_up(ar, vdev_id, aid, bssid);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_up_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_vdev_down)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_vdev_down(ar, vdev_id);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, u32 param_id,
+			  u32 param_value)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_vdev_set_param)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_vdev_set_param(ar, vdev_id, param_id,
+					      param_value);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_set_param_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_install_key(struct ath10k *ar,
+			    const struct wmi_vdev_install_key_arg *arg)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_vdev_install_key)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_vdev_install_key(ar, arg);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb,
+				   ar->wmi.cmd->vdev_install_key_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
+			      const struct wmi_vdev_spectral_conf_arg *arg)
+{
+	struct sk_buff *skb;
+	u32 cmd_id;
+
+	skb = ar->wmi.ops->gen_vdev_spectral_conf(ar, arg);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	cmd_id = ar->wmi.cmd->vdev_spectral_scan_configure_cmdid;
+	return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
+				u32 enable)
+{
+	struct sk_buff *skb;
+	u32 cmd_id;
+
+	skb = ar->wmi.ops->gen_vdev_spectral_enable(ar, vdev_id, trigger,
+						    enable);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	cmd_id = ar->wmi.cmd->vdev_spectral_scan_enable_cmdid;
+	return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
+		       const u8 peer_addr[ETH_ALEN])
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_peer_create)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_peer_create(ar, vdev_id, peer_addr);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid);
+}
+
+static inline int
+ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
+		       const u8 peer_addr[ETH_ALEN])
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_peer_delete)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_peer_delete(ar, vdev_id, peer_addr);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid);
+}
+
+static inline int
+ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
+		      const u8 peer_addr[ETH_ALEN], u32 tid_bitmap)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_peer_flush)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_peer_flush(ar, vdev_id, peer_addr, tid_bitmap);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid);
+}
+
+static inline int
+ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, const u8 *peer_addr,
+			  enum wmi_peer_param param_id, u32 param_value)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_peer_set_param)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_peer_set_param(ar, vdev_id, peer_addr, param_id,
+					      param_value);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_set_param_cmdid);
+}
+
+static inline int
+ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
+		      enum wmi_sta_ps_mode psmode)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_set_psmode)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_set_psmode(ar, vdev_id, psmode);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb,
+				   ar->wmi.cmd->sta_powersave_mode_cmdid);
+}
+
+static inline int
+ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
+			    enum wmi_sta_powersave_param param_id, u32 value)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_set_sta_ps)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_set_sta_ps(ar, vdev_id, param_id, value);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb,
+				   ar->wmi.cmd->sta_powersave_param_cmdid);
+}
+
+static inline int
+ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
+			   enum wmi_ap_ps_peer_param param_id, u32 value)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_set_ap_ps)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_set_ap_ps(ar, vdev_id, mac, param_id, value);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb,
+				   ar->wmi.cmd->ap_ps_peer_param_cmdid);
+}
+
+static inline int
+ath10k_wmi_scan_chan_list(struct ath10k *ar,
+			  const struct wmi_scan_chan_list_arg *arg)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_scan_chan_list)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_scan_chan_list(ar, arg);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid);
+}
+
+static inline int
+ath10k_wmi_peer_assoc(struct ath10k *ar,
+		      const struct wmi_peer_assoc_complete_arg *arg)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_peer_assoc)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_peer_assoc(ar, arg);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid);
+}
+
+static inline int
+ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
+{
+	struct ath10k *ar = arvif->ar;
+	struct sk_buff *skb;
+	int ret;
+
+	if (!ar->wmi.ops->gen_beacon_dma)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_beacon_dma(arvif);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	ret = ath10k_wmi_cmd_send_nowait(ar, skb,
+					 ar->wmi.cmd->pdev_send_bcn_cmdid);
+	if (ret) {
+		dev_kfree_skb(skb);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int
+ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
+			       const struct wmi_pdev_set_wmm_params_arg *arg)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_pdev_set_wmm)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_pdev_set_wmm(ar, arg);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb,
+				   ar->wmi.cmd->pdev_set_wmm_params_cmdid);
+}
+
+static inline int
+ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_request_stats)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_request_stats(ar, stats_id);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid);
+}
+
+static inline int
+ath10k_wmi_force_fw_hang(struct ath10k *ar,
+			 enum wmi_force_fw_hang_type type, u32 delay_ms)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_force_fw_hang)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_force_fw_hang(ar, type, delay_ms);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid);
+}
+
+static inline int
+ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_dbglog_cfg)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_dbglog_cfg(ar, module_enable);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid);
+}
+
+static inline int
+ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 filter)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_pktlog_enable)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_pktlog_enable(ar, filter);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_pktlog_enable_cmdid);
+}
+
+static inline int
+ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar)
+{
+	struct sk_buff *skb;
+
+	if (!ar->wmi.ops->gen_pktlog_disable)
+		return -EOPNOTSUPP;
+
+	skb = ar->wmi.ops->gen_pktlog_disable(ar);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_pktlog_disable_cmdid);
+}
+
+#endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 4a9468e..0f3c410 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -24,6 +24,7 @@
 #include "wmi.h"
 #include "mac.h"
 #include "testmode.h"
+#include "wmi-ops.h"
 
 /* MAIN WMI cmd track */
 static struct wmi_cmd_map wmi_cmd_map = {
@@ -685,8 +686,8 @@ static void ath10k_wmi_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
 	dev_kfree_skb(skb);
 }
 
-static int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
-				      u32 cmd_id)
+int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
+			       u32 cmd_id)
 {
 	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
 	struct wmi_cmd_hdr *cmd_hdr;
@@ -792,24 +793,23 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
 	return ret;
 }
 
-int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
+static struct sk_buff *
+ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
 {
-	int ret = 0;
 	struct wmi_mgmt_tx_cmd *cmd;
 	struct ieee80211_hdr *hdr;
-	struct sk_buff *wmi_skb;
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct sk_buff *skb;
 	int len;
-	u32 buf_len = skb->len;
+	u32 buf_len = msdu->len;
 	u16 fc;
 
-	hdr = (struct ieee80211_hdr *)skb->data;
+	hdr = (struct ieee80211_hdr *)msdu->data;
 	fc = le16_to_cpu(hdr->frame_control);
 
 	if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control)))
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
-	len = sizeof(cmd->hdr) + skb->len;
+	len = sizeof(cmd->hdr) + msdu->len;
 
 	if ((ieee80211_is_action(hdr->frame_control) ||
 	     ieee80211_is_deauth(hdr->frame_control) ||
@@ -821,36 +821,27 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
 
 	len = round_up(len, 4);
 
-	wmi_skb = ath10k_wmi_alloc_skb(ar, len);
-	if (!wmi_skb)
-		return -ENOMEM;
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
 
-	cmd = (struct wmi_mgmt_tx_cmd *)wmi_skb->data;
+	cmd = (struct wmi_mgmt_tx_cmd *)skb->data;
 
-	cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(skb)->vdev_id);
+	cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(msdu)->vdev_id);
 	cmd->hdr.tx_rate = 0;
 	cmd->hdr.tx_power = 0;
 	cmd->hdr.buf_len = __cpu_to_le32(buf_len);
 
 	ether_addr_copy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr));
-	memcpy(cmd->buf, skb->data, skb->len);
+	memcpy(cmd->buf, msdu->data, msdu->len);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
-		   wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE,
+		   msdu, skb->len, fc & IEEE80211_FCTL_FTYPE,
 		   fc & IEEE80211_FCTL_STYPE);
 	trace_ath10k_tx_hdr(ar, skb->data, skb->len);
 	trace_ath10k_tx_payload(ar, skb->data, skb->len);
 
-	/* Send the management frame buffer to the target */
-	ret = ath10k_wmi_cmd_send(ar, wmi_skb, ar->wmi.cmd->mgmt_tx_cmdid);
-	if (ret)
-		return ret;
-
-	/* TODO: report tx status to mac80211 - temporary just ACK */
-	info->flags |= IEEE80211_TX_STAT_ACK;
-	ieee80211_tx_status_irqsafe(ar->hw, skb);
-
-	return ret;
+	return skb;
 }
 
 static void ath10k_wmi_event_scan_started(struct ath10k *ar)
@@ -977,8 +968,8 @@ ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type,
 	}
 }
 
-static int ath10k_wmi_pull_scan_ev(struct sk_buff *skb,
-				   struct wmi_scan_ev_arg *arg)
+static int ath10k_wmi_op_pull_scan_ev(struct ath10k *ar, struct sk_buff *skb,
+				      struct wmi_scan_ev_arg *arg)
 {
 	struct wmi_scan_event *ev = (void *)skb->data;
 
@@ -1007,7 +998,7 @@ static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
 	u32 vdev_id;
 	int ret;
 
-	ret = ath10k_wmi_pull_scan_ev(skb, &arg);
+	ret = ath10k_wmi_pull_scan(ar, skb, &arg);
 	if (ret) {
 		ath10k_warn(ar, "failed to parse scan event: %d\n", ret);
 		return ret;
@@ -1173,9 +1164,8 @@ static void ath10k_wmi_handle_wep_reauth(struct ath10k *ar,
 	}
 }
 
-static int ath10k_wmi_pull_mgmt_rx_ev(struct sk_buff *skb,
-				      struct wmi_mgmt_rx_ev_arg *arg,
-				      struct ath10k *ar)
+static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb,
+					 struct wmi_mgmt_rx_ev_arg *arg)
 {
 	struct wmi_mgmt_rx_event_v1 *ev_v1;
 	struct wmi_mgmt_rx_event_v2 *ev_v2;
@@ -1230,7 +1220,7 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 	u16 fc;
 	int ret;
 
-	ret = ath10k_wmi_pull_mgmt_rx_ev(skb, &arg, ar);
+	ret = ath10k_wmi_pull_mgmt_rx(ar, skb, &arg);
 	if (ret) {
 		ath10k_warn(ar, "failed to parse mgmt rx event: %d\n", ret);
 		return ret;
@@ -1350,8 +1340,8 @@ exit:
 	return idx;
 }
 
-static int ath10k_wmi_pull_ch_info_ev(struct sk_buff *skb,
-				      struct wmi_ch_info_ev_arg *arg)
+static int ath10k_wmi_op_pull_ch_info_ev(struct ath10k *ar, struct sk_buff *skb,
+					 struct wmi_ch_info_ev_arg *arg)
 {
 	struct wmi_chan_info_event *ev = (void *)skb->data;
 
@@ -1376,7 +1366,7 @@ static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
 	u32 err_code, freq, cmd_flags, noise_floor, rx_clear_count, cycle_count;
 	int idx, ret;
 
-	ret = ath10k_wmi_pull_ch_info_ev(skb, &arg);
+	ret = ath10k_wmi_pull_ch_info(ar, skb, &arg);
 	if (ret) {
 		ath10k_warn(ar, "failed to parse chan info event: %d\n", ret);
 		return;
@@ -1513,9 +1503,9 @@ static void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src,
 	dst->peer_tx_rate = __le32_to_cpu(src->peer_tx_rate);
 }
 
-static int ath10k_wmi_main_pull_fw_stats(struct ath10k *ar,
-					 struct sk_buff *skb,
-					 struct ath10k_fw_stats *stats)
+static int ath10k_wmi_main_op_pull_fw_stats(struct ath10k *ar,
+					    struct sk_buff *skb,
+					    struct ath10k_fw_stats *stats)
 {
 	const struct wmi_stats_event *ev = (void *)skb->data;
 	u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
@@ -1565,9 +1555,9 @@ static int ath10k_wmi_main_pull_fw_stats(struct ath10k *ar,
 	return 0;
 }
 
-static int ath10k_wmi_10x_pull_fw_stats(struct ath10k *ar,
-					struct sk_buff *skb,
-					struct ath10k_fw_stats *stats)
+static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k *ar,
+					   struct sk_buff *skb,
+					   struct ath10k_fw_stats *stats)
 {
 	const struct wmi_stats_event *ev = (void *)skb->data;
 	u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
@@ -1628,15 +1618,6 @@ static int ath10k_wmi_10x_pull_fw_stats(struct ath10k *ar,
 	return 0;
 }
 
-int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb,
-			     struct ath10k_fw_stats *stats)
-{
-	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
-		return ath10k_wmi_10x_pull_fw_stats(ar, skb, stats);
-	else
-		return ath10k_wmi_main_pull_fw_stats(ar, skb, stats);
-}
-
 static void ath10k_wmi_event_update_stats(struct ath10k *ar,
 					  struct sk_buff *skb)
 {
@@ -1644,8 +1625,9 @@ static void ath10k_wmi_event_update_stats(struct ath10k *ar,
 	ath10k_debug_fw_stats_process(ar, skb);
 }
 
-static int ath10k_wmi_pull_vdev_start_ev(struct sk_buff *skb,
-					 struct wmi_vdev_start_ev_arg *arg)
+static int
+ath10k_wmi_op_pull_vdev_start_ev(struct ath10k *ar, struct sk_buff *skb,
+				 struct wmi_vdev_start_ev_arg *arg)
 {
 	struct wmi_vdev_start_response_event *ev = (void *)skb->data;
 
@@ -1669,7 +1651,7 @@ static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar,
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n");
 
-	ret = ath10k_wmi_pull_vdev_start_ev(skb, &arg);
+	ret = ath10k_wmi_pull_vdev_start(ar, skb, &arg);
 	if (ret) {
 		ath10k_warn(ar, "failed to parse vdev start event: %d\n", ret);
 		return;
@@ -1688,8 +1670,9 @@ static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar,
 	complete(&ar->vdev_setup_done);
 }
 
-static int ath10k_wmi_pull_peer_kick_ev(struct sk_buff *skb,
-					struct wmi_peer_kick_ev_arg *arg)
+static int
+ath10k_wmi_op_pull_peer_kick_ev(struct ath10k *ar, struct sk_buff *skb,
+				struct wmi_peer_kick_ev_arg *arg)
 {
 	struct wmi_peer_sta_kickout_event *ev = (void *)skb->data;
 
@@ -1709,7 +1692,7 @@ static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar,
 	struct ieee80211_sta *sta;
 	int ret;
 
-	ret = ath10k_wmi_pull_peer_kick_ev(skb, &arg);
+	ret = ath10k_wmi_pull_peer_kick(ar, skb, &arg);
 	if (ret) {
 		ath10k_warn(ar, "failed to parse peer kickout event: %d\n",
 			    ret);
@@ -1951,8 +1934,8 @@ cleanup:
 	kfree(old_data);
 }
 
-static int ath10k_wmi_pull_swba_ev(struct sk_buff *skb,
-				   struct wmi_swba_ev_arg *arg)
+static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb,
+				      struct wmi_swba_ev_arg *arg)
 {
 	struct wmi_host_swba_event *ev = (void *)skb->data;
 	u32 map;
@@ -1994,7 +1977,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
 	dma_addr_t paddr;
 	int ret, vdev_id = 0;
 
-	ret = ath10k_wmi_pull_swba_ev(skb, &arg);
+	ret = ath10k_wmi_pull_swba(ar, skb, &arg);
 	if (ret) {
 		ath10k_warn(ar, "failed to parse swba event: %d\n", ret);
 		return;
@@ -2345,8 +2328,8 @@ ath10k_wmi_event_spectral_scan(struct ath10k *ar,
 	}
 }
 
-static int ath10k_wmi_pull_phyerr_ev(struct sk_buff *skb,
-				     struct wmi_phyerr_ev_arg *arg)
+static int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, struct sk_buff *skb,
+					struct wmi_phyerr_ev_arg *arg)
 {
 	struct wmi_phyerr_event *ev = (void *)skb->data;
 
@@ -2372,7 +2355,7 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
 
 	ATH10K_DFS_STAT_INC(ar, phy_errors);
 
-	ret = ath10k_wmi_pull_phyerr_ev(skb, &arg);
+	ret = ath10k_wmi_pull_phyerr(ar, skb, &arg);
 	if (ret) {
 		ath10k_warn(ar, "failed to parse phyerr event: %d\n", ret);
 		return;
@@ -2608,8 +2591,9 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
 	return 0;
 }
 
-static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb,
-					   struct wmi_svc_rdy_ev_arg *arg)
+static int
+ath10k_wmi_main_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
+				   struct wmi_svc_rdy_ev_arg *arg)
 {
 	struct wmi_service_ready_event *ev;
 	size_t i, n;
@@ -2644,8 +2628,9 @@ static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb,
 	return 0;
 }
 
-static int ath10k_wmi_10x_pull_svc_rdy_ev(struct sk_buff *skb,
-					  struct wmi_svc_rdy_ev_arg *arg)
+static int
+ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
+				  struct wmi_svc_rdy_ev_arg *arg)
 {
 	struct wmi_10x_service_ready_event *ev;
 	int i, n;
@@ -2686,23 +2671,16 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar,
 	u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
 	int ret;
 
-	memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map));
-
-	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
-		ret = ath10k_wmi_10x_pull_svc_rdy_ev(skb, &arg);
-		wmi_10x_svc_map(arg.service_map, ar->wmi.svc_map,
-				arg.service_map_len);
-	} else {
-		ret = ath10k_wmi_main_pull_svc_rdy_ev(skb, &arg);
-		wmi_main_svc_map(arg.service_map, ar->wmi.svc_map,
-				 arg.service_map_len);
-	}
-
+	ret = ath10k_wmi_pull_svc_rdy(ar, skb, &arg);
 	if (ret) {
 		ath10k_warn(ar, "failed to parse service ready: %d\n", ret);
 		return;
 	}
 
+	memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map));
+	ath10k_wmi_map_svc(ar, arg.service_map, ar->wmi.svc_map,
+			   arg.service_map_len);
+
 	ar->hw_min_tx_power = __le32_to_cpu(arg.min_tx_power);
 	ar->hw_max_tx_power = __le32_to_cpu(arg.max_tx_power);
 	ar->ht_cap_info = __le32_to_cpu(arg.ht_cap);
@@ -2795,8 +2773,8 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar,
 	complete(&ar->wmi.service_ready);
 }
 
-static int ath10k_wmi_pull_rdy_ev(struct sk_buff *skb,
-				  struct wmi_rdy_ev_arg *arg)
+static int ath10k_wmi_op_pull_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
+				     struct wmi_rdy_ev_arg *arg)
 {
 	struct wmi_ready_event *ev = (void *)skb->data;
 
@@ -2817,7 +2795,7 @@ static int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
 	struct wmi_rdy_ev_arg arg = {};
 	int ret;
 
-	ret = ath10k_wmi_pull_rdy_ev(skb, &arg);
+	ret = ath10k_wmi_pull_rdy(ar, skb, &arg);
 	if (ret) {
 		ath10k_warn(ar, "failed to parse ready event: %d\n", ret);
 		return ret;
@@ -2835,7 +2813,7 @@ static int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
 	return 0;
 }
 
-static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb)
+static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_cmd_hdr *cmd_hdr;
 	enum wmi_event_id id;
@@ -2951,7 +2929,7 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb)
 	dev_kfree_skb(skb);
 }
 
-static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb)
+static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_cmd_hdr *cmd_hdr;
 	enum wmi_10x_event_id id;
@@ -3075,7 +3053,7 @@ out:
 	dev_kfree_skb(skb);
 }
 
-static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb)
+static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_cmd_hdr *cmd_hdr;
 	enum wmi_10_2_event_id id;
@@ -3194,14 +3172,11 @@ static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb)
 
 static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb)
 {
-	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
-		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
-			ath10k_wmi_10_2_process_rx(ar, skb);
-		else
-			ath10k_wmi_10x_process_rx(ar, skb);
-	} else {
-		ath10k_wmi_main_process_rx(ar, skb);
-	}
+	int ret;
+
+	ret = ath10k_wmi_rx(ar, skb);
+	if (ret)
+		ath10k_warn(ar, "failed to process wmi rx: %d\n", ret);
 }
 
 int ath10k_wmi_connect(struct ath10k *ar)
@@ -3232,16 +3207,17 @@ int ath10k_wmi_connect(struct ath10k *ar)
 	return 0;
 }
 
-static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd,
-					      u16 rd2g, u16 rd5g, u16 ctl2g,
-					      u16 ctl5g)
+static struct sk_buff *
+ath10k_wmi_op_gen_pdev_set_rd(struct ath10k *ar, u16 rd, u16 rd2g, u16 rd5g,
+			      u16 ctl2g, u16 ctl5g,
+			      enum wmi_dfs_region dfs_reg)
 {
 	struct wmi_pdev_set_regdomain_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_pdev_set_regdomain_cmd *)skb->data;
 	cmd->reg_domain = __cpu_to_le32(rd);
@@ -3253,22 +3229,20 @@ static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd,
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x\n",
 		   rd, rd2g, rd5g, ctl2g, ctl5g);
-
-	return ath10k_wmi_cmd_send(ar, skb,
-				   ar->wmi.cmd->pdev_set_regdomain_cmdid);
+	return skb;
 }
 
-static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd,
-					     u16 rd2g, u16 rd5g,
-					     u16 ctl2g, u16 ctl5g,
-					     enum wmi_dfs_region dfs_reg)
+static struct sk_buff *
+ath10k_wmi_10x_op_gen_pdev_set_rd(struct ath10k *ar, u16 rd, u16 rd2g, u16
+				  rd5g, u16 ctl2g, u16 ctl5g,
+				  enum wmi_dfs_region dfs_reg)
 {
 	struct wmi_pdev_set_regdomain_cmd_10x *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_pdev_set_regdomain_cmd_10x *)skb->data;
 	cmd->reg_domain = __cpu_to_le32(rd);
@@ -3281,50 +3255,39 @@ static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd,
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n",
 		   rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg);
-
-	return ath10k_wmi_cmd_send(ar, skb,
-				   ar->wmi.cmd->pdev_set_regdomain_cmdid);
-}
-
-int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
-				  u16 rd5g, u16 ctl2g, u16 ctl5g,
-				  enum wmi_dfs_region dfs_reg)
-{
-	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
-		return ath10k_wmi_10x_pdev_set_regdomain(ar, rd, rd2g, rd5g,
-							ctl2g, ctl5g, dfs_reg);
-	else
-		return ath10k_wmi_main_pdev_set_regdomain(ar, rd, rd2g, rd5g,
-							 ctl2g, ctl5g);
+	return skb;
 }
 
-int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)
+static struct sk_buff *
+ath10k_wmi_op_gen_pdev_suspend(struct ath10k *ar, u32 suspend_opt)
 {
 	struct wmi_pdev_suspend_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_pdev_suspend_cmd *)skb->data;
 	cmd->suspend_opt = __cpu_to_le32(suspend_opt);
 
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_pdev_resume_target(struct ath10k *ar)
+static struct sk_buff *
+ath10k_wmi_op_gen_pdev_resume(struct ath10k *ar)
 {
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, 0);
-	if (skb == NULL)
-		return -ENOMEM;
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
 
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_resume_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
+static struct sk_buff *
+ath10k_wmi_op_gen_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
 {
 	struct wmi_pdev_set_param_cmd *cmd;
 	struct sk_buff *skb;
@@ -3332,12 +3295,12 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
 	if (id == WMI_PDEV_PARAM_UNSUPPORTED) {
 		ath10k_warn(ar, "pdev param %d not supported by firmware\n",
 			    id);
-		return -EOPNOTSUPP;
+		return ERR_PTR(-EOPNOTSUPP);
 	}
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_pdev_set_param_cmd *)skb->data;
 	cmd->param_id    = __cpu_to_le32(id);
@@ -3345,7 +3308,7 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n",
 		   id, value);
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid);
+	return skb;
 }
 
 static void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar,
@@ -3370,7 +3333,7 @@ static void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar,
 	}
 }
 
-static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
+static struct sk_buff *ath10k_wmi_op_gen_init(struct ath10k *ar)
 {
 	struct wmi_init_cmd *cmd;
 	struct sk_buff *buf;
@@ -3433,7 +3396,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
 
 	buf = ath10k_wmi_alloc_skb(ar, len);
 	if (!buf)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_init_cmd *)buf->data;
 
@@ -3441,10 +3404,10 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
 	ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init\n");
-	return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
+	return buf;
 }
 
-static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
+static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
 {
 	struct wmi_init_cmd_10x *cmd;
 	struct sk_buff *buf;
@@ -3499,7 +3462,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
 
 	buf = ath10k_wmi_alloc_skb(ar, len);
 	if (!buf)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_init_cmd_10x *)buf->data;
 
@@ -3507,10 +3470,10 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
 	ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10x\n");
-	return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
+	return buf;
 }
 
-static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar)
+static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
 {
 	struct wmi_init_cmd_10_2 *cmd;
 	struct sk_buff *buf;
@@ -3565,7 +3528,7 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar)
 
 	buf = ath10k_wmi_alloc_skb(ar, len);
 	if (!buf)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_init_cmd_10_2 *)buf->data;
 
@@ -3573,23 +3536,7 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar)
 	ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.2\n");
-	return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
-}
-
-int ath10k_wmi_cmd_init(struct ath10k *ar)
-{
-	int ret;
-
-	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
-		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
-			ret = ath10k_wmi_10_2_cmd_init(ar);
-		else
-			ret = ath10k_wmi_10x_cmd_init(ar);
-	} else {
-		ret = ath10k_wmi_main_cmd_init(ar);
-	}
-
-	return ret;
+	return buf;
 }
 
 static int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg)
@@ -3739,46 +3686,60 @@ ath10k_wmi_put_start_scan_tlvs(struct wmi_start_scan_tlvs *tlvs,
 	}
 }
 
-int ath10k_wmi_start_scan(struct ath10k *ar,
-			  const struct wmi_start_scan_arg *arg)
+static struct sk_buff *
+ath10k_wmi_op_gen_start_scan(struct ath10k *ar,
+			     const struct wmi_start_scan_arg *arg)
 {
+	struct wmi_start_scan_cmd *cmd;
 	struct sk_buff *skb;
 	size_t len;
 	int ret;
 
 	ret = ath10k_wmi_start_scan_verify(arg);
 	if (ret)
-		return ret;
-
-	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
-		len = sizeof(struct wmi_10x_start_scan_cmd) +
-		      ath10k_wmi_start_scan_tlvs_len(arg);
-	else
-		len = sizeof(struct wmi_start_scan_cmd) +
-		      ath10k_wmi_start_scan_tlvs_len(arg);
+		return ERR_PTR(ret);
 
+	len = sizeof(*cmd) + ath10k_wmi_start_scan_tlvs_len(arg);
 	skb = ath10k_wmi_alloc_skb(ar, len);
 	if (!skb)
-		return -ENOMEM;
-
-	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
-		struct wmi_10x_start_scan_cmd *cmd;
+		return ERR_PTR(-ENOMEM);
 
-		cmd = (struct wmi_10x_start_scan_cmd *)skb->data;
-		ath10k_wmi_put_start_scan_common(&cmd->common, arg);
-		ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
-	} else {
-		struct wmi_start_scan_cmd *cmd;
+	cmd = (struct wmi_start_scan_cmd *)skb->data;
 
-		cmd = (struct wmi_start_scan_cmd *)skb->data;
-		cmd->burst_duration_ms = __cpu_to_le32(0);
+	ath10k_wmi_put_start_scan_common(&cmd->common, arg);
+	ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
 
-		ath10k_wmi_put_start_scan_common(&cmd->common, arg);
-		ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
-	}
+	cmd->burst_duration_ms = __cpu_to_le32(0);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi start scan\n");
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid);
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_10x_op_gen_start_scan(struct ath10k *ar,
+				 const struct wmi_start_scan_arg *arg)
+{
+	struct wmi_10x_start_scan_cmd *cmd;
+	struct sk_buff *skb;
+	size_t len;
+	int ret;
+
+	ret = ath10k_wmi_start_scan_verify(arg);
+	if (ret)
+		return ERR_PTR(ret);
+
+	len = sizeof(*cmd) + ath10k_wmi_start_scan_tlvs_len(arg);
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	cmd = (struct wmi_10x_start_scan_cmd *)skb->data;
+
+	ath10k_wmi_put_start_scan_common(&cmd->common, arg);
+	ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi 10x start scan\n");
+	return skb;
 }
 
 void ath10k_wmi_start_scan_init(struct ath10k *ar,
@@ -3807,7 +3768,9 @@ void ath10k_wmi_start_scan_init(struct ath10k *ar,
 	arg->bssids[0].bssid = "\xFF\xFF\xFF\xFF\xFF\xFF";
 }
 
-int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
+static struct sk_buff *
+ath10k_wmi_op_gen_stop_scan(struct ath10k *ar,
+			    const struct wmi_stop_scan_arg *arg)
 {
 	struct wmi_stop_scan_cmd *cmd;
 	struct sk_buff *skb;
@@ -3815,13 +3778,13 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
 	u32 req_id;
 
 	if (arg->req_id > 0xFFF)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 	if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	scan_id = arg->u.scan_id;
 	scan_id |= WMI_HOST_SCAN_REQ_ID_PREFIX;
@@ -3838,20 +3801,21 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi stop scan reqid %d req_type %d vdev/scan_id %d\n",
 		   arg->req_id, arg->req_type, arg->u.scan_id);
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
-			   enum wmi_vdev_type type,
-			   enum wmi_vdev_subtype subtype,
-			   const u8 macaddr[ETH_ALEN])
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_create(struct ath10k *ar, u32 vdev_id,
+			      enum wmi_vdev_type type,
+			      enum wmi_vdev_subtype subtype,
+			      const u8 macaddr[ETH_ALEN])
 {
 	struct wmi_vdev_create_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_vdev_create_cmd *)skb->data;
 	cmd->vdev_id      = __cpu_to_le32(vdev_id);
@@ -3862,58 +3826,52 @@ int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "WMI vdev create: id %d type %d subtype %d macaddr %pM\n",
 		   vdev_id, type, subtype, macaddr);
-
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_create_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_delete(struct ath10k *ar, u32 vdev_id)
 {
 	struct wmi_vdev_delete_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_vdev_delete_cmd *)skb->data;
 	cmd->vdev_id = __cpu_to_le32(vdev_id);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "WMI vdev delete id %d\n", vdev_id);
-
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid);
+	return skb;
 }
 
-static int
-ath10k_wmi_vdev_start_restart(struct ath10k *ar,
-			      const struct wmi_vdev_start_request_arg *arg,
-			      u32 cmd_id)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_start(struct ath10k *ar,
+			     const struct wmi_vdev_start_request_arg *arg,
+			     bool restart)
 {
 	struct wmi_vdev_start_request_cmd *cmd;
 	struct sk_buff *skb;
 	const char *cmdname;
 	u32 flags = 0;
 
-	if (cmd_id != ar->wmi.cmd->vdev_start_request_cmdid &&
-	    cmd_id != ar->wmi.cmd->vdev_restart_request_cmdid)
-		return -EINVAL;
 	if (WARN_ON(arg->ssid && arg->ssid_len == 0))
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 	if (WARN_ON(arg->hidden_ssid && !arg->ssid))
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 	if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid)))
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
-	if (cmd_id == ar->wmi.cmd->vdev_start_request_cmdid)
-		cmdname = "start";
-	else if (cmd_id == ar->wmi.cmd->vdev_restart_request_cmdid)
+	if (restart)
 		cmdname = "restart";
 	else
-		return -EINVAL; /* should not happen, we already check cmd_id */
+		cmdname = "start";
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	if (arg->hidden_ssid)
 		flags |= WMI_VDEV_START_HIDDEN_SSID;
@@ -3942,50 +3900,36 @@ ath10k_wmi_vdev_start_restart(struct ath10k *ar,
 		   flags, arg->channel.freq, arg->channel.mode,
 		   cmd->chan.flags, arg->channel.max_power);
 
-	return ath10k_wmi_cmd_send(ar, skb, cmd_id);
-}
-
-int ath10k_wmi_vdev_start(struct ath10k *ar,
-			  const struct wmi_vdev_start_request_arg *arg)
-{
-	u32 cmd_id = ar->wmi.cmd->vdev_start_request_cmdid;
-
-	return ath10k_wmi_vdev_start_restart(ar, arg, cmd_id);
-}
-
-int ath10k_wmi_vdev_restart(struct ath10k *ar,
-			    const struct wmi_vdev_start_request_arg *arg)
-{
-	u32 cmd_id = ar->wmi.cmd->vdev_restart_request_cmdid;
-
-	return ath10k_wmi_vdev_start_restart(ar, arg, cmd_id);
+	return skb;
 }
 
-int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_stop(struct ath10k *ar, u32 vdev_id)
 {
 	struct wmi_vdev_stop_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_vdev_stop_cmd *)skb->data;
 	cmd->vdev_id = __cpu_to_le32(vdev_id);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id);
-
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid,
+			  const u8 *bssid)
 {
 	struct wmi_vdev_up_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_vdev_up_cmd *)skb->data;
 	cmd->vdev_id       = __cpu_to_le32(vdev_id);
@@ -3995,30 +3939,30 @@ int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi mgmt vdev up id 0x%x assoc id %d bssid %pM\n",
 		   vdev_id, aid, bssid);
-
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_up_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_down(struct ath10k *ar, u32 vdev_id)
 {
 	struct wmi_vdev_down_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_vdev_down_cmd *)skb->data;
 	cmd->vdev_id = __cpu_to_le32(vdev_id);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi mgmt vdev down id 0x%x\n", vdev_id);
-
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
-			      u32 param_id, u32 param_value)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_set_param(struct ath10k *ar, u32 vdev_id,
+				 u32 param_id, u32 param_value)
 {
 	struct wmi_vdev_set_param_cmd *cmd;
 	struct sk_buff *skb;
@@ -4027,12 +3971,12 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
 		ath10k_dbg(ar, ATH10K_DBG_WMI,
 			   "vdev param %d not supported by firmware\n",
 			    param_id);
-		return -EOPNOTSUPP;
+		return ERR_PTR(-EOPNOTSUPP);
 	}
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_vdev_set_param_cmd *)skb->data;
 	cmd->vdev_id     = __cpu_to_le32(vdev_id);
@@ -4042,24 +3986,24 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi vdev id 0x%x set param %d value %d\n",
 		   vdev_id, param_id, param_value);
-
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_set_param_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_vdev_install_key(struct ath10k *ar,
-				const struct wmi_vdev_install_key_arg *arg)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_install_key(struct ath10k *ar,
+				   const struct wmi_vdev_install_key_arg *arg)
 {
 	struct wmi_vdev_install_key_cmd *cmd;
 	struct sk_buff *skb;
 
 	if (arg->key_cipher == WMI_CIPHER_NONE && arg->key_data != NULL)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 	if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + arg->key_len);
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_vdev_install_key_cmd *)skb->data;
 	cmd->vdev_id       = __cpu_to_le32(arg->vdev_id);
@@ -4078,20 +4022,19 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar,
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi vdev install key idx %d cipher %d len %d\n",
 		   arg->key_idx, arg->key_cipher, arg->key_len);
-	return ath10k_wmi_cmd_send(ar, skb,
-				   ar->wmi.cmd->vdev_install_key_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
-				  const struct wmi_vdev_spectral_conf_arg *arg)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_spectral_conf(struct ath10k *ar,
+				     const struct wmi_vdev_spectral_conf_arg *arg)
 {
 	struct wmi_vdev_spectral_conf_cmd *cmd;
 	struct sk_buff *skb;
-	u32 cmdid;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_vdev_spectral_conf_cmd *)skb->data;
 	cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
@@ -4114,39 +4057,38 @@ int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
 	cmd->scan_dbm_adj = __cpu_to_le32(arg->scan_dbm_adj);
 	cmd->scan_chn_mask = __cpu_to_le32(arg->scan_chn_mask);
 
-	cmdid = ar->wmi.cmd->vdev_spectral_scan_configure_cmdid;
-	return ath10k_wmi_cmd_send(ar, skb, cmdid);
+	return skb;
 }
 
-int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
-				    u32 enable)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id,
+				       u32 trigger, u32 enable)
 {
 	struct wmi_vdev_spectral_enable_cmd *cmd;
 	struct sk_buff *skb;
-	u32 cmdid;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_vdev_spectral_enable_cmd *)skb->data;
 	cmd->vdev_id = __cpu_to_le32(vdev_id);
 	cmd->trigger_cmd = __cpu_to_le32(trigger);
 	cmd->enable_cmd = __cpu_to_le32(enable);
 
-	cmdid = ar->wmi.cmd->vdev_spectral_scan_enable_cmdid;
-	return ath10k_wmi_cmd_send(ar, skb, cmdid);
+	return skb;
 }
 
-int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
-			   const u8 peer_addr[ETH_ALEN])
+static struct sk_buff *
+ath10k_wmi_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
+			      const u8 peer_addr[ETH_ALEN])
 {
 	struct wmi_peer_create_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_peer_create_cmd *)skb->data;
 	cmd->vdev_id = __cpu_to_le32(vdev_id);
@@ -4155,18 +4097,19 @@ int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi peer create vdev_id %d peer_addr %pM\n",
 		   vdev_id, peer_addr);
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
-			   const u8 peer_addr[ETH_ALEN])
+static struct sk_buff *
+ath10k_wmi_op_gen_peer_delete(struct ath10k *ar, u32 vdev_id,
+			      const u8 peer_addr[ETH_ALEN])
 {
 	struct wmi_peer_delete_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_peer_delete_cmd *)skb->data;
 	cmd->vdev_id = __cpu_to_le32(vdev_id);
@@ -4175,18 +4118,19 @@ int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi peer delete vdev_id %d peer_addr %pM\n",
 		   vdev_id, peer_addr);
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
-			  const u8 peer_addr[ETH_ALEN], u32 tid_bitmap)
+static struct sk_buff *
+ath10k_wmi_op_gen_peer_flush(struct ath10k *ar, u32 vdev_id,
+			     const u8 peer_addr[ETH_ALEN], u32 tid_bitmap)
 {
 	struct wmi_peer_flush_tids_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_peer_flush_tids_cmd *)skb->data;
 	cmd->vdev_id         = __cpu_to_le32(vdev_id);
@@ -4196,19 +4140,21 @@ int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi peer flush vdev_id %d peer_addr %pM tids %08x\n",
 		   vdev_id, peer_addr, tid_bitmap);
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,
-			      const u8 *peer_addr, enum wmi_peer_param param_id,
-			      u32 param_value)
+static struct sk_buff *
+ath10k_wmi_op_gen_peer_set_param(struct ath10k *ar, u32 vdev_id,
+				 const u8 *peer_addr,
+				 enum wmi_peer_param param_id,
+				 u32 param_value)
 {
 	struct wmi_peer_set_param_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_peer_set_param_cmd *)skb->data;
 	cmd->vdev_id     = __cpu_to_le32(vdev_id);
@@ -4219,19 +4165,19 @@ int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi vdev %d peer 0x%pM set param %d value %d\n",
 		   vdev_id, peer_addr, param_id, param_value);
-
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_set_param_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
-			  enum wmi_sta_ps_mode psmode)
+static struct sk_buff *
+ath10k_wmi_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id,
+			     enum wmi_sta_ps_mode psmode)
 {
 	struct wmi_sta_powersave_mode_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_sta_powersave_mode_cmd *)skb->data;
 	cmd->vdev_id     = __cpu_to_le32(vdev_id);
@@ -4240,21 +4186,20 @@ int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi set powersave id 0x%x mode %d\n",
 		   vdev_id, psmode);
-
-	return ath10k_wmi_cmd_send(ar, skb,
-				   ar->wmi.cmd->sta_powersave_mode_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
-				enum wmi_sta_powersave_param param_id,
-				u32 value)
+static struct sk_buff *
+ath10k_wmi_op_gen_set_sta_ps(struct ath10k *ar, u32 vdev_id,
+			     enum wmi_sta_powersave_param param_id,
+			     u32 value)
 {
 	struct wmi_sta_powersave_param_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_sta_powersave_param_cmd *)skb->data;
 	cmd->vdev_id     = __cpu_to_le32(vdev_id);
@@ -4264,22 +4209,22 @@ int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi sta ps param vdev_id 0x%x param %d value %d\n",
 		   vdev_id, param_id, value);
-	return ath10k_wmi_cmd_send(ar, skb,
-				   ar->wmi.cmd->sta_powersave_param_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
-			       enum wmi_ap_ps_peer_param param_id, u32 value)
+static struct sk_buff *
+ath10k_wmi_op_gen_set_ap_ps(struct ath10k *ar, u32 vdev_id, const u8 *mac,
+			    enum wmi_ap_ps_peer_param param_id, u32 value)
 {
 	struct wmi_ap_ps_peer_cmd *cmd;
 	struct sk_buff *skb;
 
 	if (!mac)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_ap_ps_peer_cmd *)skb->data;
 	cmd->vdev_id = __cpu_to_le32(vdev_id);
@@ -4290,13 +4235,12 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi ap ps param vdev_id 0x%X param %d value %d mac_addr %pM\n",
 		   vdev_id, param_id, value, mac);
-
-	return ath10k_wmi_cmd_send(ar, skb,
-				   ar->wmi.cmd->ap_ps_peer_param_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_scan_chan_list(struct ath10k *ar,
-			      const struct wmi_scan_chan_list_arg *arg)
+static struct sk_buff *
+ath10k_wmi_op_gen_scan_chan_list(struct ath10k *ar,
+				 const struct wmi_scan_chan_list_arg *arg)
 {
 	struct wmi_scan_chan_list_cmd *cmd;
 	struct sk_buff *skb;
@@ -4309,7 +4253,7 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,
 
 	skb = ath10k_wmi_alloc_skb(ar, len);
 	if (!skb)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
 	cmd = (struct wmi_scan_chan_list_cmd *)skb->data;
 	cmd->num_scan_chans = __cpu_to_le32(arg->n_channels);
@@ -4321,7 +4265,7 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,
 		ath10k_wmi_put_wmi_channel(ci, ch);
 	}
 
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid);
+	return skb;
 }
 
 static void
@@ -4402,12 +4346,9 @@ ath10k_wmi_peer_assoc_fill_10_2(struct ath10k *ar, void *buf,
 	cmd->info0 = __cpu_to_le32(info0);
 }
 
-int ath10k_wmi_peer_assoc(struct ath10k *ar,
-			  const struct wmi_peer_assoc_complete_arg *arg)
+static int
+ath10k_wmi_peer_assoc_check_arg(const struct wmi_peer_assoc_complete_arg *arg)
 {
-	struct sk_buff *skb;
-	int len;
-
 	if (arg->peer_mpdu_density > 16)
 		return -EINVAL;
 	if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
@@ -4415,49 +4356,98 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
 	if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
 		return -EINVAL;
 
-	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
-		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
-			len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd);
-		else
-			len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd);
-	} else {
-		len = sizeof(struct wmi_main_peer_assoc_complete_cmd);
-	}
+	return 0;
+}
+
+static struct sk_buff *
+ath10k_wmi_op_gen_peer_assoc(struct ath10k *ar,
+			     const struct wmi_peer_assoc_complete_arg *arg)
+{
+	size_t len = sizeof(struct wmi_main_peer_assoc_complete_cmd);
+	struct sk_buff *skb;
+	int ret;
+
+	ret = ath10k_wmi_peer_assoc_check_arg(arg);
+	if (ret)
+		return ERR_PTR(ret);
 
 	skb = ath10k_wmi_alloc_skb(ar, len);
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
-	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
-		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
-			ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg);
-		else
-			ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg);
-	} else {
-		ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg);
-	}
+	ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
+		   "wmi peer assoc vdev %d addr %pM (%s)\n",
+		   arg->vdev_id, arg->addr,
+		   arg->peer_reassoc ? "reassociate" : "new");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_10_1_op_gen_peer_assoc(struct ath10k *ar,
+				  const struct wmi_peer_assoc_complete_arg *arg)
+{
+	size_t len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd);
+	struct sk_buff *skb;
+	int ret;
+
+	ret = ath10k_wmi_peer_assoc_check_arg(arg);
+	if (ret)
+		return ERR_PTR(ret);
+
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
+		   "wmi peer assoc vdev %d addr %pM (%s)\n",
+		   arg->vdev_id, arg->addr,
+		   arg->peer_reassoc ? "reassociate" : "new");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_10_2_op_gen_peer_assoc(struct ath10k *ar,
+				  const struct wmi_peer_assoc_complete_arg *arg)
+{
+	size_t len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd);
+	struct sk_buff *skb;
+	int ret;
+
+	ret = ath10k_wmi_peer_assoc_check_arg(arg);
+	if (ret)
+		return ERR_PTR(ret);
+
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi peer assoc vdev %d addr %pM (%s)\n",
 		   arg->vdev_id, arg->addr,
 		   arg->peer_reassoc ? "reassociate" : "new");
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid);
+	return skb;
 }
 
 /* This function assumes the beacon is already DMA mapped */
-int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
+static struct sk_buff *
+ath10k_wmi_op_gen_beacon_dma(struct ath10k_vif *arvif)
 {
+	struct ath10k *ar = arvif->ar;
 	struct wmi_bcn_tx_ref_cmd *cmd;
 	struct sk_buff *skb;
 	struct sk_buff *beacon = arvif->beacon;
-	struct ath10k *ar = arvif->ar;
 	struct ieee80211_hdr *hdr;
-	int ret;
 	u16 fc;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	hdr = (struct ieee80211_hdr *)beacon->data;
 	fc = le16_to_cpu(hdr->frame_control);
@@ -4477,13 +4467,7 @@ int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
 	if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab)
 		cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB);
 
-	ret = ath10k_wmi_cmd_send_nowait(ar, skb,
-					 ar->wmi.cmd->pdev_send_bcn_cmdid);
-
-	if (ret)
-		dev_kfree_skb(skb);
-
-	return ret;
+	return skb;
 }
 
 static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params,
@@ -4497,15 +4481,16 @@ static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params,
 	params->no_ack = __cpu_to_le32(arg->no_ack);
 }
 
-int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
-				   const struct wmi_pdev_set_wmm_params_arg *arg)
+static struct sk_buff *
+ath10k_wmi_op_gen_pdev_set_wmm(struct ath10k *ar,
+			       const struct wmi_pdev_set_wmm_params_arg *arg)
 {
 	struct wmi_pdev_set_wmm_params *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_pdev_set_wmm_params *)skb->data;
 	ath10k_wmi_pdev_set_wmm_param(&cmd->ac_be, &arg->ac_be);
@@ -4514,35 +4499,36 @@ int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
 	ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vo, &arg->ac_vo);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set wmm params\n");
-	return ath10k_wmi_cmd_send(ar, skb,
-				   ar->wmi.cmd->pdev_set_wmm_params_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id)
+static struct sk_buff *
+ath10k_wmi_op_gen_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id)
 {
 	struct wmi_request_stats_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_request_stats_cmd *)skb->data;
 	cmd->stats_id = __cpu_to_le32(stats_id);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id);
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_force_fw_hang(struct ath10k *ar,
-			     enum wmi_force_fw_hang_type type, u32 delay_ms)
+static struct sk_buff *
+ath10k_wmi_op_gen_force_fw_hang(struct ath10k *ar,
+				enum wmi_force_fw_hang_type type, u32 delay_ms)
 {
 	struct wmi_force_fw_hang_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_force_fw_hang_cmd *)skb->data;
 	cmd->type = __cpu_to_le32(type);
@@ -4550,10 +4536,11 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar,
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n",
 		   type, delay_ms);
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
+static struct sk_buff *
+ath10k_wmi_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable)
 {
 	struct wmi_dbglog_cfg_cmd *cmd;
 	struct sk_buff *skb;
@@ -4561,7 +4548,7 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	cmd = (struct wmi_dbglog_cfg_cmd *)skb->data;
 
@@ -4586,50 +4573,208 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
 		   __le32_to_cpu(cmd->module_valid),
 		   __le32_to_cpu(cmd->config_enable),
 		   __le32_to_cpu(cmd->config_valid));
-
-	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid);
+	return skb;
 }
 
-int ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 ev_bitmap)
+static struct sk_buff *
+ath10k_wmi_op_gen_pktlog_enable(struct ath10k *ar, u32 ev_bitmap)
 {
 	struct wmi_pdev_pktlog_enable_cmd *cmd;
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	ev_bitmap &= ATH10K_PKTLOG_ANY;
-	ath10k_dbg(ar, ATH10K_DBG_WMI,
-		   "wmi enable pktlog filter:%x\n", ev_bitmap);
 
 	cmd = (struct wmi_pdev_pktlog_enable_cmd *)skb->data;
 	cmd->ev_bitmap = __cpu_to_le32(ev_bitmap);
-	return ath10k_wmi_cmd_send(ar, skb,
-				   ar->wmi.cmd->pdev_pktlog_enable_cmdid);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi enable pktlog filter 0x%08x\n",
+		   ev_bitmap);
+	return skb;
 }
 
-int ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar)
+static struct sk_buff *
+ath10k_wmi_op_gen_pktlog_disable(struct ath10k *ar)
 {
 	struct sk_buff *skb;
 
 	skb = ath10k_wmi_alloc_skb(ar, 0);
 	if (!skb)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi disable pktlog\n");
-
-	return ath10k_wmi_cmd_send(ar, skb,
-				   ar->wmi.cmd->pdev_pktlog_disable_cmdid);
+	return skb;
 }
 
+static const struct wmi_ops wmi_ops = {
+	.rx = ath10k_wmi_op_rx,
+	.map_svc = wmi_main_svc_map,
+
+	.pull_scan = ath10k_wmi_op_pull_scan_ev,
+	.pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev,
+	.pull_ch_info = ath10k_wmi_op_pull_ch_info_ev,
+	.pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,
+	.pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,
+	.pull_swba = ath10k_wmi_op_pull_swba_ev,
+	.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
+	.pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev,
+	.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
+	.pull_fw_stats = ath10k_wmi_main_op_pull_fw_stats,
+
+	.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
+	.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
+	.gen_pdev_set_rd = ath10k_wmi_op_gen_pdev_set_rd,
+	.gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param,
+	.gen_init = ath10k_wmi_op_gen_init,
+	.gen_start_scan = ath10k_wmi_op_gen_start_scan,
+	.gen_stop_scan = ath10k_wmi_op_gen_stop_scan,
+	.gen_vdev_create = ath10k_wmi_op_gen_vdev_create,
+	.gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete,
+	.gen_vdev_start = ath10k_wmi_op_gen_vdev_start,
+	.gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop,
+	.gen_vdev_up = ath10k_wmi_op_gen_vdev_up,
+	.gen_vdev_down = ath10k_wmi_op_gen_vdev_down,
+	.gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param,
+	.gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key,
+	.gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf,
+	.gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable,
+	.gen_peer_create = ath10k_wmi_op_gen_peer_create,
+	.gen_peer_delete = ath10k_wmi_op_gen_peer_delete,
+	.gen_peer_flush = ath10k_wmi_op_gen_peer_flush,
+	.gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param,
+	.gen_peer_assoc = ath10k_wmi_op_gen_peer_assoc,
+	.gen_set_psmode = ath10k_wmi_op_gen_set_psmode,
+	.gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps,
+	.gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps,
+	.gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list,
+	.gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma,
+	.gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm,
+	.gen_request_stats = ath10k_wmi_op_gen_request_stats,
+	.gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang,
+	.gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx,
+	.gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg,
+	.gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable,
+	.gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable,
+};
+
+static const struct wmi_ops wmi_10_1_ops = {
+	.rx = ath10k_wmi_10_1_op_rx,
+	.map_svc = wmi_10x_svc_map,
+	.pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev,
+	.pull_fw_stats = ath10k_wmi_10x_op_pull_fw_stats,
+	.gen_init = ath10k_wmi_10_1_op_gen_init,
+	.gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd,
+	.gen_start_scan = ath10k_wmi_10x_op_gen_start_scan,
+	.gen_peer_assoc = ath10k_wmi_10_1_op_gen_peer_assoc,
+
+	/* shared with main branch */
+	.pull_scan = ath10k_wmi_op_pull_scan_ev,
+	.pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev,
+	.pull_ch_info = ath10k_wmi_op_pull_ch_info_ev,
+	.pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,
+	.pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,
+	.pull_swba = ath10k_wmi_op_pull_swba_ev,
+	.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
+	.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
+
+	.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
+	.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
+	.gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param,
+	.gen_stop_scan = ath10k_wmi_op_gen_stop_scan,
+	.gen_vdev_create = ath10k_wmi_op_gen_vdev_create,
+	.gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete,
+	.gen_vdev_start = ath10k_wmi_op_gen_vdev_start,
+	.gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop,
+	.gen_vdev_up = ath10k_wmi_op_gen_vdev_up,
+	.gen_vdev_down = ath10k_wmi_op_gen_vdev_down,
+	.gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param,
+	.gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key,
+	.gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf,
+	.gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable,
+	.gen_peer_create = ath10k_wmi_op_gen_peer_create,
+	.gen_peer_delete = ath10k_wmi_op_gen_peer_delete,
+	.gen_peer_flush = ath10k_wmi_op_gen_peer_flush,
+	.gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param,
+	.gen_set_psmode = ath10k_wmi_op_gen_set_psmode,
+	.gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps,
+	.gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps,
+	.gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list,
+	.gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma,
+	.gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm,
+	.gen_request_stats = ath10k_wmi_op_gen_request_stats,
+	.gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang,
+	.gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx,
+	.gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg,
+	.gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable,
+	.gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable,
+};
+
+static const struct wmi_ops wmi_10_2_ops = {
+	.rx = ath10k_wmi_10_2_op_rx,
+	.gen_init = ath10k_wmi_10_2_op_gen_init,
+	.gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc,
+
+	/* shared with 10.1 */
+	.map_svc = wmi_10x_svc_map,
+	.pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev,
+	.pull_fw_stats = ath10k_wmi_10x_op_pull_fw_stats,
+	.gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd,
+	.gen_start_scan = ath10k_wmi_10x_op_gen_start_scan,
+
+	.pull_scan = ath10k_wmi_op_pull_scan_ev,
+	.pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev,
+	.pull_ch_info = ath10k_wmi_op_pull_ch_info_ev,
+	.pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,
+	.pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,
+	.pull_swba = ath10k_wmi_op_pull_swba_ev,
+	.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
+	.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
+
+	.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
+	.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
+	.gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param,
+	.gen_stop_scan = ath10k_wmi_op_gen_stop_scan,
+	.gen_vdev_create = ath10k_wmi_op_gen_vdev_create,
+	.gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete,
+	.gen_vdev_start = ath10k_wmi_op_gen_vdev_start,
+	.gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop,
+	.gen_vdev_up = ath10k_wmi_op_gen_vdev_up,
+	.gen_vdev_down = ath10k_wmi_op_gen_vdev_down,
+	.gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param,
+	.gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key,
+	.gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf,
+	.gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable,
+	.gen_peer_create = ath10k_wmi_op_gen_peer_create,
+	.gen_peer_delete = ath10k_wmi_op_gen_peer_delete,
+	.gen_peer_flush = ath10k_wmi_op_gen_peer_flush,
+	.gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param,
+	.gen_set_psmode = ath10k_wmi_op_gen_set_psmode,
+	.gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps,
+	.gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps,
+	.gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list,
+	.gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma,
+	.gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm,
+	.gen_request_stats = ath10k_wmi_op_gen_request_stats,
+	.gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang,
+	.gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx,
+	.gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg,
+	.gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable,
+	.gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable,
+};
+
 int ath10k_wmi_attach(struct ath10k *ar)
 {
 	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
-		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) {
 			ar->wmi.cmd = &wmi_10_2_cmd_map;
-		else
+			ar->wmi.ops = &wmi_10_2_ops;
+		} else {
 			ar->wmi.cmd = &wmi_10x_cmd_map;
+			ar->wmi.ops = &wmi_10_1_ops;
+		}
 
 		ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
 		ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
@@ -4637,6 +4782,7 @@ int ath10k_wmi_attach(struct ath10k *ar)
 		ar->wmi.cmd = &wmi_cmd_map;
 		ar->wmi.vdev_param = &wmi_vdev_param_map;
 		ar->wmi.pdev_param = &wmi_pdev_param_map;
+		ar->wmi.ops = &wmi_ops;
 	}
 
 	init_completion(&ar->wmi.service_ready);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 0952bc2..b8308f6 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -4644,7 +4644,6 @@ struct wmi_rdy_ev_arg {
 
 struct ath10k;
 struct ath10k_vif;
-struct ath10k_fw_stats;
 
 int ath10k_wmi_attach(struct ath10k *ar);
 void ath10k_wmi_detach(struct ath10k *ar);
@@ -4655,70 +4654,8 @@ int ath10k_wmi_connect(struct ath10k *ar);
 
 struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len);
 int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
-
-int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt);
-int ath10k_wmi_pdev_resume_target(struct ath10k *ar);
-int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
-				  u16 rd5g, u16 ctl2g, u16 ctl5g,
-				  enum wmi_dfs_region dfs_reg);
-int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value);
-int ath10k_wmi_cmd_init(struct ath10k *ar);
-int ath10k_wmi_start_scan(struct ath10k *ar, const struct wmi_start_scan_arg *);
+int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
+			       u32 cmd_id);
 void ath10k_wmi_start_scan_init(struct ath10k *ar, struct wmi_start_scan_arg *);
-int ath10k_wmi_stop_scan(struct ath10k *ar,
-			 const struct wmi_stop_scan_arg *arg);
-int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
-			   enum wmi_vdev_type type,
-			   enum wmi_vdev_subtype subtype,
-			   const u8 macaddr[ETH_ALEN]);
-int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id);
-int ath10k_wmi_vdev_start(struct ath10k *ar,
-			  const struct wmi_vdev_start_request_arg *);
-int ath10k_wmi_vdev_restart(struct ath10k *ar,
-			    const struct wmi_vdev_start_request_arg *);
-int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id);
-int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid,
-		       const u8 *bssid);
-int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id);
-int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
-			      u32 param_id, u32 param_value);
-int ath10k_wmi_vdev_install_key(struct ath10k *ar,
-				const struct wmi_vdev_install_key_arg *arg);
-int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
-				  const struct wmi_vdev_spectral_conf_arg *arg);
-int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
-				    u32 enable);
-int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
-			   const u8 peer_addr[ETH_ALEN]);
-int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
-			   const u8 peer_addr[ETH_ALEN]);
-int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
-			  const u8 peer_addr[ETH_ALEN], u32 tid_bitmap);
-int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,
-			      const u8 *peer_addr,
-			      enum wmi_peer_param param_id, u32 param_value);
-int ath10k_wmi_peer_assoc(struct ath10k *ar,
-			  const struct wmi_peer_assoc_complete_arg *arg);
-int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
-			  enum wmi_sta_ps_mode psmode);
-int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
-				enum wmi_sta_powersave_param param_id,
-				u32 value);
-int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
-			       enum wmi_ap_ps_peer_param param_id, u32 value);
-int ath10k_wmi_scan_chan_list(struct ath10k *ar,
-			      const struct wmi_scan_chan_list_arg *arg);
-int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif);
-int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
-				   const struct wmi_pdev_set_wmm_params_arg *arg);
-int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id);
-int ath10k_wmi_force_fw_hang(struct ath10k *ar,
-			     enum wmi_force_fw_hang_type type, u32 delay_ms);
-int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb);
-int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable);
-int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb,
-			     struct ath10k_fw_stats *stats);
-int ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 ev_list);
-int ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar);
 
 #endif /* _WMI_H_ */
-- 
1.8.5.3



From michal.kazior at tieto.com  Thu Nov 27 01:11:21 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 27 Nov 2014 10:11:21 +0100
Subject: [PATCH v2 7/7] ath10k: implement wmi-tlv backend
In-Reply-To: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
References: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1417079481-22255-8-git-send-email-michal.kazior@tieto.com>

Latest main firmware branch introduced a new WMI
ABI called wmi-tlv. It is not a tlv strictly
speaking but something that resembles it because
it is ordered and may have duplicate id entries.

This prepares ath10k to support new hw.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---

Notes:
    v2:
     * fix kbuildbot warning regarding %ld
     * add missing __packed to wmi_tlv_peer_create_cmd
     * fix pdev set wmm param command generation
     * tune wmi init setup to avoid some multi-vif related fw crashes
     * add missing pktlog enable/disable impl.
     * remove space between brackets as per checkpatch error
     * rename vdev stat var (shorter)
     * add more enum entries (pdev, vdev, cmd, event, tags, services)
     * s/STRUC/STRUCT/ to satisfy checkpatch
     * fix some other checkpatch warnings
     * changed some enum names to be shorter
       (s/_FIXED_PARAM// and s/STRUCT_WMI_/STRUCT_/)

 drivers/net/wireless/ath/ath10k/Makefile  |    1 +
 drivers/net/wireless/ath/ath10k/ce.c      |    2 +
 drivers/net/wireless/ath/ath10k/core.c    |    3 +
 drivers/net/wireless/ath/ath10k/core.h    |    3 +
 drivers/net/wireless/ath/ath10k/hw.h      |    9 +
 drivers/net/wireless/ath/ath10k/mac.c     |   45 +
 drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2218 +++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi-tlv.h | 1380 ++++++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi.c     |    6 +-
 drivers/net/wireless/ath/ath10k/wmi.h     |   76 +
 10 files changed, 3742 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/wireless/ath/ath10k/wmi-tlv.c
 create mode 100644 drivers/net/wireless/ath/ath10k/wmi-tlv.h

diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile
index 8b1b1ad..8abb66c 100644
--- a/drivers/net/wireless/ath/ath10k/Makefile
+++ b/drivers/net/wireless/ath/ath10k/Makefile
@@ -8,6 +8,7 @@ ath10k_core-y += mac.o \
 		 htt_tx.o \
 		 txrx.o \
 		 wmi.o \
+		 wmi-tlv.o \
 		 bmi.o
 
 ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index a156e6e..42ec793 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -1093,6 +1093,8 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
 		     (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
 	BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
 		     (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
+	BUILD_BUG_ON(2*TARGET_TLV_NUM_MSDU_DESC >
+		     (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
 
 	ce_state->ar = ar;
 	ce_state->id = ce_id;
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index e8384e1..6e820a6 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -805,6 +805,9 @@ static void ath10k_core_init_max_sta_count(struct ath10k *ar)
 	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
 		ar->max_num_peers = TARGET_10X_NUM_PEERS;
 		ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+	} else if (test_bit(ATH10K_FW_FEATURE_WMI_TLV, ar->fw_features)) {
+		ar->max_num_peers = TARGET_TLV_NUM_PEERS;
+		ar->max_num_stations = TARGET_TLV_NUM_STATIONS;
 	} else {
 		ar->max_num_peers = TARGET_NUM_PEERS;
 		ar->max_num_stations = TARGET_NUM_STATIONS;
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 837972c..88bedaf 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -383,6 +383,9 @@ enum ath10k_fw_features {
 	 */
 	ATH10K_FW_FEATURE_WMI_10_2 = 4,
 
+	/* Firmware uses WMI TLV */
+	ATH10K_FW_FEATURE_WMI_TLV = 5,
+
 	/* keep last */
 	ATH10K_FW_FEATURE_COUNT,
 };
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index dfedfd0..479dc4d 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -162,6 +162,15 @@ struct ath10k_pktlog_hdr {
 #define TARGET_10X_NUM_MSDU_DESC		(1024 + 400)
 #define TARGET_10X_MAX_FRAG_ENTRIES		0
 
+/* Target specific defines for WMI-TLV firmware */
+#define TARGET_TLV_NUM_VDEVS			3
+#define TARGET_TLV_NUM_STATIONS			32
+#define TARGET_TLV_NUM_PEERS			((TARGET_TLV_NUM_STATIONS) + \
+						 (TARGET_TLV_NUM_VDEVS) + \
+						 2)
+#define TARGET_TLV_NUM_TIDS			((TARGET_TLV_NUM_PEERS) * 2)
+#define TARGET_TLV_NUM_MSDU_DESC		(1024 + 32)
+
 /* Number of Copy Engines supported */
 #define CE_COUNT 8
 
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 2bc97f3..065df0f 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4843,6 +4843,45 @@ static const struct ieee80211_iface_combination ath10k_10x_if_comb[] = {
 	},
 };
 
+static const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = {
+	{
+		.max = 2,
+		.types = BIT(NL80211_IFTYPE_STATION) |
+			 BIT(NL80211_IFTYPE_AP) |
+			 BIT(NL80211_IFTYPE_P2P_CLIENT) |
+			 BIT(NL80211_IFTYPE_P2P_GO),
+	},
+};
+
+static const struct ieee80211_iface_limit ath10k_tlv_if_limit_ibss[] = {
+	{
+		.max = 1,
+		.types = BIT(NL80211_IFTYPE_STATION),
+	},
+	{
+		.max = 1,
+		.types = BIT(NL80211_IFTYPE_ADHOC),
+	},
+};
+
+/* FIXME: This is not tested. The hardware/firmware may not be able to run all
+ * the possible combinations and/or might be actually able to run some more.
+ */
+static struct ieee80211_iface_combination ath10k_tlv_if_comb[] = {
+	{
+		.limits = ath10k_tlv_if_limit,
+		.num_different_channels = 1,
+		.max_interfaces = 2,
+		.n_limits = ARRAY_SIZE(ath10k_tlv_if_limit),
+	},
+	{
+		.limits = ath10k_tlv_if_limit_ibss,
+		.num_different_channels = 1,
+		.max_interfaces = 2,
+		.n_limits = ARRAY_SIZE(ath10k_tlv_if_limit_ibss),
+	},
+};
+
 static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
 {
 	struct ieee80211_sta_vht_cap vht_cap = {0};
@@ -5072,6 +5111,12 @@ int ath10k_mac_register(struct ath10k *ar)
 		ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
 		ar->hw->wiphy->n_iface_combinations =
 			ARRAY_SIZE(ath10k_10x_if_comb);
+	} else if (test_bit(ATH10K_FW_FEATURE_WMI_TLV, ar->fw_features)) {
+		ar->hw->wiphy->iface_combinations = ath10k_tlv_if_comb;
+		ar->hw->wiphy->n_iface_combinations =
+			ARRAY_SIZE(ath10k_tlv_if_comb);
+
+		ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
 	} else {
 		ar->hw->wiphy->iface_combinations = ath10k_if_comb;
 		ar->hw->wiphy->n_iface_combinations =
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
new file mode 100644
index 0000000..b21048c
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -0,0 +1,2218 @@
+/*
+ * Copyright (c) 2005-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "core.h"
+#include "debug.h"
+#include "hw.h"
+#include "wmi.h"
+#include "wmi-ops.h"
+#include "wmi-tlv.h"
+
+/***************/
+/* TLV helpers */
+/**************/
+
+struct wmi_tlv_policy {
+	size_t min_len;
+};
+
+static const struct wmi_tlv_policy wmi_tlv_policies[] = {
+	[WMI_TLV_TAG_ARRAY_BYTE]
+		= { .min_len = sizeof(u8) },
+	[WMI_TLV_TAG_ARRAY_UINT32]
+		= { .min_len = sizeof(u32) },
+	[WMI_TLV_TAG_STRUCT_SCAN_EVENT]
+		= { .min_len = sizeof(struct wmi_scan_event) },
+	[WMI_TLV_TAG_STRUCT_MGMT_RX_HDR]
+		= { .min_len = sizeof(struct wmi_tlv_mgmt_rx_ev) },
+	[WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT]
+		= { .min_len = sizeof(struct wmi_chan_info_event) },
+	[WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT]
+		= { .min_len = sizeof(struct wmi_vdev_start_response_event) },
+	[WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT]
+		= { .min_len = sizeof(struct wmi_peer_sta_kickout_event) },
+	[WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT]
+		= { .min_len = sizeof(struct wmi_host_swba_event) },
+	[WMI_TLV_TAG_STRUCT_TIM_INFO]
+		= { .min_len = sizeof(struct wmi_tim_info) },
+	[WMI_TLV_TAG_STRUCT_P2P_NOA_INFO]
+		= { .min_len = sizeof(struct wmi_p2p_noa_info) },
+	[WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT]
+		= { .min_len = sizeof(struct wmi_tlv_svc_rdy_ev) },
+	[WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES]
+		= { .min_len = sizeof(struct hal_reg_capabilities) },
+	[WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ]
+		= { .min_len = sizeof(struct wlan_host_mem_req) },
+	[WMI_TLV_TAG_STRUCT_READY_EVENT]
+		= { .min_len = sizeof(struct wmi_tlv_rdy_ev) },
+};
+
+static int
+ath10k_wmi_tlv_iter(struct ath10k *ar, const void *ptr, size_t len,
+		    int (*iter)(struct ath10k *ar, u16 tag, u16 len,
+				const void *ptr, void *data),
+		    void *data)
+{
+	const void *begin = ptr;
+	const struct wmi_tlv *tlv;
+	u16 tlv_tag, tlv_len;
+	int ret;
+
+	while (len > 0) {
+		if (len < sizeof(*tlv)) {
+			ath10k_dbg(ar, ATH10K_DBG_WMI,
+				   "wmi tlv parse failure at byte %zd (%zu bytes left, %zu expected)\n",
+				   ptr - begin, len, sizeof(*tlv));
+			return -EINVAL;
+		}
+
+		tlv = ptr;
+		tlv_tag = __le16_to_cpu(tlv->tag);
+		tlv_len = __le16_to_cpu(tlv->len);
+		ptr += sizeof(*tlv);
+		len -= sizeof(*tlv);
+
+		if (tlv_len > len) {
+			ath10k_dbg(ar, ATH10K_DBG_WMI,
+				   "wmi tlv parse failure of tag %hhu at byte %zd (%zu bytes left, %hhu expected)\n",
+				   tlv_tag, ptr - begin, len, tlv_len);
+			return -EINVAL;
+		}
+
+		if (tlv_tag < ARRAY_SIZE(wmi_tlv_policies) &&
+		    wmi_tlv_policies[tlv_tag].min_len &&
+		    wmi_tlv_policies[tlv_tag].min_len > tlv_len) {
+			ath10k_dbg(ar, ATH10K_DBG_WMI,
+				   "wmi tlv parse failure of tag %hhu at byte %zd (%hhu bytes is less than min length %zu)\n",
+				   tlv_tag, ptr - begin, tlv_len,
+				   wmi_tlv_policies[tlv_tag].min_len);
+			return -EINVAL;
+		}
+
+		ret = iter(ar, tlv_tag, tlv_len, ptr, data);
+		if (ret)
+			return ret;
+
+		ptr += tlv_len;
+		len -= tlv_len;
+	}
+
+	return 0;
+}
+
+static int ath10k_wmi_tlv_iter_parse(struct ath10k *ar, u16 tag, u16 len,
+				     const void *ptr, void *data)
+{
+	const void **tb = data;
+
+	if (tag < WMI_TLV_TAG_MAX)
+		tb[tag] = ptr;
+
+	return 0;
+}
+
+static int ath10k_wmi_tlv_parse(struct ath10k *ar, const void **tb,
+				const void *ptr, size_t len)
+{
+	return ath10k_wmi_tlv_iter(ar, ptr, len, ath10k_wmi_tlv_iter_parse,
+				   (void *)tb);
+}
+
+static const void **
+ath10k_wmi_tlv_parse_alloc(struct ath10k *ar, const void *ptr,
+			   size_t len, gfp_t gfp)
+{
+	const void **tb;
+	int ret;
+
+	tb = kzalloc(sizeof(*tb) * WMI_TLV_TAG_MAX, gfp);
+	if (!tb)
+		return ERR_PTR(-ENOMEM);
+
+	ret = ath10k_wmi_tlv_parse(ar, tb, ptr, len);
+	if (ret) {
+		kfree(tb);
+		return ERR_PTR(ret);
+	}
+
+	return tb;
+}
+
+static u16 ath10k_wmi_tlv_len(const void *ptr)
+{
+	return __le16_to_cpu((((const struct wmi_tlv *)ptr) - 1)->len);
+}
+
+/***********/
+/* TLV ops */
+/***********/
+
+static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
+{
+	struct wmi_cmd_hdr *cmd_hdr;
+	enum wmi_tlv_event_id id;
+
+	cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
+	id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
+
+	if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
+		return;
+
+	trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
+
+	switch (id) {
+	case WMI_TLV_MGMT_RX_EVENTID:
+		ath10k_wmi_event_mgmt_rx(ar, skb);
+		/* mgmt_rx() owns the skb now! */
+		return;
+	case WMI_TLV_SCAN_EVENTID:
+		ath10k_wmi_event_scan(ar, skb);
+		break;
+	case WMI_TLV_CHAN_INFO_EVENTID:
+		ath10k_wmi_event_chan_info(ar, skb);
+		break;
+	case WMI_TLV_ECHO_EVENTID:
+		ath10k_wmi_event_echo(ar, skb);
+		break;
+	case WMI_TLV_DEBUG_MESG_EVENTID:
+		ath10k_wmi_event_debug_mesg(ar, skb);
+		break;
+	case WMI_TLV_UPDATE_STATS_EVENTID:
+		ath10k_wmi_event_update_stats(ar, skb);
+		break;
+	case WMI_TLV_VDEV_START_RESP_EVENTID:
+		ath10k_wmi_event_vdev_start_resp(ar, skb);
+		break;
+	case WMI_TLV_VDEV_STOPPED_EVENTID:
+		ath10k_wmi_event_vdev_stopped(ar, skb);
+		break;
+	case WMI_TLV_PEER_STA_KICKOUT_EVENTID:
+		ath10k_wmi_event_peer_sta_kickout(ar, skb);
+		break;
+	case WMI_TLV_HOST_SWBA_EVENTID:
+		ath10k_wmi_event_host_swba(ar, skb);
+		break;
+	case WMI_TLV_TBTTOFFSET_UPDATE_EVENTID:
+		ath10k_wmi_event_tbttoffset_update(ar, skb);
+		break;
+	case WMI_TLV_PHYERR_EVENTID:
+		ath10k_wmi_event_phyerr(ar, skb);
+		break;
+	case WMI_TLV_ROAM_EVENTID:
+		ath10k_wmi_event_roam(ar, skb);
+		break;
+	case WMI_TLV_PROFILE_MATCH:
+		ath10k_wmi_event_profile_match(ar, skb);
+		break;
+	case WMI_TLV_DEBUG_PRINT_EVENTID:
+		ath10k_wmi_event_debug_print(ar, skb);
+		break;
+	case WMI_TLV_PDEV_QVIT_EVENTID:
+		ath10k_wmi_event_pdev_qvit(ar, skb);
+		break;
+	case WMI_TLV_WLAN_PROFILE_DATA_EVENTID:
+		ath10k_wmi_event_wlan_profile_data(ar, skb);
+		break;
+	case WMI_TLV_RTT_MEASUREMENT_REPORT_EVENTID:
+		ath10k_wmi_event_rtt_measurement_report(ar, skb);
+		break;
+	case WMI_TLV_TSF_MEASUREMENT_REPORT_EVENTID:
+		ath10k_wmi_event_tsf_measurement_report(ar, skb);
+		break;
+	case WMI_TLV_RTT_ERROR_REPORT_EVENTID:
+		ath10k_wmi_event_rtt_error_report(ar, skb);
+		break;
+	case WMI_TLV_WOW_WAKEUP_HOST_EVENTID:
+		ath10k_wmi_event_wow_wakeup_host(ar, skb);
+		break;
+	case WMI_TLV_DCS_INTERFERENCE_EVENTID:
+		ath10k_wmi_event_dcs_interference(ar, skb);
+		break;
+	case WMI_TLV_PDEV_TPC_CONFIG_EVENTID:
+		ath10k_wmi_event_pdev_tpc_config(ar, skb);
+		break;
+	case WMI_TLV_PDEV_FTM_INTG_EVENTID:
+		ath10k_wmi_event_pdev_ftm_intg(ar, skb);
+		break;
+	case WMI_TLV_GTK_OFFLOAD_STATUS_EVENTID:
+		ath10k_wmi_event_gtk_offload_status(ar, skb);
+		break;
+	case WMI_TLV_GTK_REKEY_FAIL_EVENTID:
+		ath10k_wmi_event_gtk_rekey_fail(ar, skb);
+		break;
+	case WMI_TLV_TX_DELBA_COMPLETE_EVENTID:
+		ath10k_wmi_event_delba_complete(ar, skb);
+		break;
+	case WMI_TLV_TX_ADDBA_COMPLETE_EVENTID:
+		ath10k_wmi_event_addba_complete(ar, skb);
+		break;
+	case WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID:
+		ath10k_wmi_event_vdev_install_key_complete(ar, skb);
+		break;
+	case WMI_TLV_SERVICE_READY_EVENTID:
+		ath10k_wmi_event_service_ready(ar, skb);
+		break;
+	case WMI_TLV_READY_EVENTID:
+		ath10k_wmi_event_ready(ar, skb);
+		break;
+	default:
+		ath10k_warn(ar, "Unknown eventid: %d\n", id);
+		break;
+	}
+
+	dev_kfree_skb(skb);
+}
+
+static int ath10k_wmi_tlv_op_pull_scan_ev(struct ath10k *ar,
+					  struct sk_buff *skb,
+					  struct wmi_scan_ev_arg *arg)
+{
+	const void **tb;
+	const struct wmi_scan_event *ev;
+	int ret;
+
+	tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+	if (IS_ERR(tb)) {
+		ret = PTR_ERR(tb);
+		ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+		return ret;
+	}
+
+	ev = tb[WMI_TLV_TAG_STRUCT_SCAN_EVENT];
+	if (!ev) {
+		kfree(tb);
+		return -EPROTO;
+	}
+
+	arg->event_type = ev->event_type;
+	arg->reason = ev->reason;
+	arg->channel_freq = ev->channel_freq;
+	arg->scan_req_id = ev->scan_req_id;
+	arg->scan_id = ev->scan_id;
+	arg->vdev_id = ev->vdev_id;
+
+	kfree(tb);
+	return 0;
+}
+
+static int ath10k_wmi_tlv_op_pull_mgmt_rx_ev(struct ath10k *ar,
+					     struct sk_buff *skb,
+					     struct wmi_mgmt_rx_ev_arg *arg)
+{
+	const void **tb;
+	const struct wmi_tlv_mgmt_rx_ev *ev;
+	const u8 *frame;
+	u32 msdu_len;
+	int ret;
+
+	tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+	if (IS_ERR(tb)) {
+		ret = PTR_ERR(tb);
+		ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+		return ret;
+	}
+
+	ev = tb[WMI_TLV_TAG_STRUCT_MGMT_RX_HDR];
+	frame = tb[WMI_TLV_TAG_ARRAY_BYTE];
+
+	if (!ev || !frame) {
+		kfree(tb);
+		return -EPROTO;
+	}
+
+	arg->channel = ev->channel;
+	arg->buf_len = ev->buf_len;
+	arg->status = ev->status;
+	arg->snr = ev->snr;
+	arg->phy_mode = ev->phy_mode;
+	arg->rate = ev->rate;
+
+	msdu_len = __le32_to_cpu(arg->buf_len);
+
+	if (skb->len < (frame - skb->data) + msdu_len) {
+		kfree(tb);
+		return -EPROTO;
+	}
+
+	/* shift the sk_buff to point to `frame` */
+	skb_trim(skb, 0);
+	skb_put(skb, frame - skb->data);
+	skb_pull(skb, frame - skb->data);
+	skb_put(skb, msdu_len);
+
+	kfree(tb);
+	return 0;
+}
+
+static int ath10k_wmi_tlv_op_pull_ch_info_ev(struct ath10k *ar,
+					     struct sk_buff *skb,
+					     struct wmi_ch_info_ev_arg *arg)
+{
+	const void **tb;
+	const struct wmi_chan_info_event *ev;
+	int ret;
+
+	tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+	if (IS_ERR(tb)) {
+		ret = PTR_ERR(tb);
+		ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+		return ret;
+	}
+
+	ev = tb[WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT];
+	if (!ev) {
+		kfree(tb);
+		return -EPROTO;
+	}
+
+	arg->err_code = ev->err_code;
+	arg->freq = ev->freq;
+	arg->cmd_flags = ev->cmd_flags;
+	arg->noise_floor = ev->noise_floor;
+	arg->rx_clear_count = ev->rx_clear_count;
+	arg->cycle_count = ev->cycle_count;
+
+	kfree(tb);
+	return 0;
+}
+
+static int
+ath10k_wmi_tlv_op_pull_vdev_start_ev(struct ath10k *ar, struct sk_buff *skb,
+				     struct wmi_vdev_start_ev_arg *arg)
+{
+	const void **tb;
+	const struct wmi_vdev_start_response_event *ev;
+	int ret;
+
+	tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+	if (IS_ERR(tb)) {
+		ret = PTR_ERR(tb);
+		ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+		return ret;
+	}
+
+	ev = tb[WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT];
+	if (!ev) {
+		kfree(tb);
+		return -EPROTO;
+	}
+
+	skb_pull(skb, sizeof(*ev));
+	arg->vdev_id = ev->vdev_id;
+	arg->req_id = ev->req_id;
+	arg->resp_type = ev->resp_type;
+	arg->status = ev->status;
+
+	kfree(tb);
+	return 0;
+}
+
+static int ath10k_wmi_tlv_op_pull_peer_kick_ev(struct ath10k *ar,
+					       struct sk_buff *skb,
+					       struct wmi_peer_kick_ev_arg *arg)
+{
+	const void **tb;
+	const struct wmi_peer_sta_kickout_event *ev;
+	int ret;
+
+	tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+	if (IS_ERR(tb)) {
+		ret = PTR_ERR(tb);
+		ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+		return ret;
+	}
+
+	ev = tb[WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT];
+	if (!ev) {
+		kfree(tb);
+		return -EPROTO;
+	}
+
+	arg->mac_addr = ev->peer_macaddr.addr;
+
+	kfree(tb);
+	return 0;
+}
+
+struct wmi_tlv_swba_parse {
+	const struct wmi_host_swba_event *ev;
+	bool tim_done;
+	bool noa_done;
+	size_t n_tim;
+	size_t n_noa;
+	struct wmi_swba_ev_arg *arg;
+};
+
+static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len,
+					 const void *ptr, void *data)
+{
+	struct wmi_tlv_swba_parse *swba = data;
+
+	if (tag != WMI_TLV_TAG_STRUCT_TIM_INFO)
+		return -EPROTO;
+
+	if (swba->n_tim >= ARRAY_SIZE(swba->arg->tim_info))
+		return -ENOBUFS;
+
+	swba->arg->tim_info[swba->n_tim++] = ptr;
+	return 0;
+}
+
+static int ath10k_wmi_tlv_swba_noa_parse(struct ath10k *ar, u16 tag, u16 len,
+					 const void *ptr, void *data)
+{
+	struct wmi_tlv_swba_parse *swba = data;
+
+	if (tag != WMI_TLV_TAG_STRUCT_P2P_NOA_INFO)
+		return -EPROTO;
+
+	if (swba->n_noa >= ARRAY_SIZE(swba->arg->noa_info))
+		return -ENOBUFS;
+
+	swba->arg->noa_info[swba->n_noa++] = ptr;
+	return 0;
+}
+
+static int ath10k_wmi_tlv_swba_parse(struct ath10k *ar, u16 tag, u16 len,
+				     const void *ptr, void *data)
+{
+	struct wmi_tlv_swba_parse *swba = data;
+	int ret;
+
+	switch (tag) {
+	case WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT:
+		swba->ev = ptr;
+		break;
+	case WMI_TLV_TAG_ARRAY_STRUCT:
+		if (!swba->tim_done) {
+			swba->tim_done = true;
+			ret = ath10k_wmi_tlv_iter(ar, ptr, len,
+						  ath10k_wmi_tlv_swba_tim_parse,
+						  swba);
+			if (ret)
+				return ret;
+		} else if (!swba->noa_done) {
+			swba->noa_done = true;
+			ret = ath10k_wmi_tlv_iter(ar, ptr, len,
+						  ath10k_wmi_tlv_swba_noa_parse,
+						  swba);
+			if (ret)
+				return ret;
+		}
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int ath10k_wmi_tlv_op_pull_swba_ev(struct ath10k *ar,
+					  struct sk_buff *skb,
+					  struct wmi_swba_ev_arg *arg)
+{
+	struct wmi_tlv_swba_parse swba = { .arg = arg };
+	u32 map;
+	size_t n_vdevs;
+	int ret;
+
+	ret = ath10k_wmi_tlv_iter(ar, skb->data, skb->len,
+				  ath10k_wmi_tlv_swba_parse, &swba);
+	if (ret) {
+		ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+		return ret;
+	}
+
+	if (!swba.ev)
+		return -EPROTO;
+
+	arg->vdev_map = swba.ev->vdev_map;
+
+	for (map = __le32_to_cpu(arg->vdev_map), n_vdevs = 0; map; map >>= 1)
+		if (map & BIT(0))
+			n_vdevs++;
+
+	if (n_vdevs != swba.n_tim ||
+	    n_vdevs != swba.n_noa)
+		return -EPROTO;
+
+	return 0;
+}
+
+static int ath10k_wmi_tlv_op_pull_phyerr_ev(struct ath10k *ar,
+					    struct sk_buff *skb,
+					    struct wmi_phyerr_ev_arg *arg)
+{
+	const void **tb;
+	const struct wmi_tlv_phyerr_ev *ev;
+	const void *phyerrs;
+	int ret;
+
+	tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+	if (IS_ERR(tb)) {
+		ret = PTR_ERR(tb);
+		ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+		return ret;
+	}
+
+	ev = tb[WMI_TLV_TAG_STRUCT_COMB_PHYERR_RX_HDR];
+	phyerrs = tb[WMI_TLV_TAG_ARRAY_BYTE];
+
+	if (!ev || !phyerrs) {
+		kfree(tb);
+		return -EPROTO;
+	}
+
+	arg->num_phyerrs  = ev->num_phyerrs;
+	arg->tsf_l32 = ev->tsf_l32;
+	arg->tsf_u32 = ev->tsf_u32;
+	arg->buf_len = ev->buf_len;
+	arg->phyerrs = phyerrs;
+
+	kfree(tb);
+	return 0;
+}
+
+#define WMI_TLV_ABI_VER_NS0 0x5F414351
+#define WMI_TLV_ABI_VER_NS1 0x00004C4D
+#define WMI_TLV_ABI_VER_NS2 0x00000000
+#define WMI_TLV_ABI_VER_NS3 0x00000000
+
+#define WMI_TLV_ABI_VER0_MAJOR 1
+#define WMI_TLV_ABI_VER0_MINOR 0
+#define WMI_TLV_ABI_VER0 ((((WMI_TLV_ABI_VER0_MAJOR) << 24) & 0xFF000000) | \
+			  (((WMI_TLV_ABI_VER0_MINOR) <<  0) & 0x00FFFFFF))
+#define WMI_TLV_ABI_VER1 53
+
+static int
+ath10k_wmi_tlv_parse_mem_reqs(struct ath10k *ar, u16 tag, u16 len,
+			      const void *ptr, void *data)
+{
+	struct wmi_svc_rdy_ev_arg *arg = data;
+	int i;
+
+	if (tag != WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ)
+		return -EPROTO;
+
+	for (i = 0; i < ARRAY_SIZE(arg->mem_reqs); i++) {
+		if (!arg->mem_reqs[i]) {
+			arg->mem_reqs[i] = ptr;
+			return 0;
+		}
+	}
+
+	return -ENOMEM;
+}
+
+static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar,
+					     struct sk_buff *skb,
+					     struct wmi_svc_rdy_ev_arg *arg)
+{
+	const void **tb;
+	const struct hal_reg_capabilities *reg;
+	const struct wmi_tlv_svc_rdy_ev *ev;
+	const __le32 *svc_bmap;
+	const struct wlan_host_mem_req *mem_reqs;
+	int ret;
+
+	tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+	if (IS_ERR(tb)) {
+		ret = PTR_ERR(tb);
+		ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+		return ret;
+	}
+
+	ev = tb[WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT];
+	reg = tb[WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES];
+	svc_bmap = tb[WMI_TLV_TAG_ARRAY_UINT32];
+	mem_reqs = tb[WMI_TLV_TAG_ARRAY_STRUCT];
+
+	if (!ev || !reg || !svc_bmap || !mem_reqs) {
+		kfree(tb);
+		return -EPROTO;
+	}
+
+	/* This is an internal ABI compatibility check for WMI TLV so check it
+	 * here instead of the generic WMI code.
+	 */
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
+		   "wmi tlv abi 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x\n",
+		   __le32_to_cpu(ev->abi.abi_ver0), WMI_TLV_ABI_VER0,
+		   __le32_to_cpu(ev->abi.abi_ver_ns0), WMI_TLV_ABI_VER_NS0,
+		   __le32_to_cpu(ev->abi.abi_ver_ns1), WMI_TLV_ABI_VER_NS1,
+		   __le32_to_cpu(ev->abi.abi_ver_ns2), WMI_TLV_ABI_VER_NS2,
+		   __le32_to_cpu(ev->abi.abi_ver_ns3), WMI_TLV_ABI_VER_NS3);
+
+	if (__le32_to_cpu(ev->abi.abi_ver0) != WMI_TLV_ABI_VER0 ||
+	    __le32_to_cpu(ev->abi.abi_ver_ns0) != WMI_TLV_ABI_VER_NS0 ||
+	    __le32_to_cpu(ev->abi.abi_ver_ns1) != WMI_TLV_ABI_VER_NS1 ||
+	    __le32_to_cpu(ev->abi.abi_ver_ns2) != WMI_TLV_ABI_VER_NS2 ||
+	    __le32_to_cpu(ev->abi.abi_ver_ns3) != WMI_TLV_ABI_VER_NS3) {
+		kfree(tb);
+		return -ENOTSUPP;
+	}
+
+	arg->min_tx_power = ev->hw_min_tx_power;
+	arg->max_tx_power = ev->hw_max_tx_power;
+	arg->ht_cap = ev->ht_cap_info;
+	arg->vht_cap = ev->vht_cap_info;
+	arg->sw_ver0 = ev->abi.abi_ver0;
+	arg->sw_ver1 = ev->abi.abi_ver1;
+	arg->fw_build = ev->fw_build_vers;
+	arg->phy_capab = ev->phy_capability;
+	arg->num_rf_chains = ev->num_rf_chains;
+	arg->eeprom_rd = reg->eeprom_rd;
+	arg->num_mem_reqs = ev->num_mem_reqs;
+	arg->service_map = svc_bmap;
+	arg->service_map_len = ath10k_wmi_tlv_len(svc_bmap);
+
+	ret = ath10k_wmi_tlv_iter(ar, mem_reqs, ath10k_wmi_tlv_len(mem_reqs),
+				  ath10k_wmi_tlv_parse_mem_reqs, arg);
+	if (ret) {
+		kfree(tb);
+		ath10k_warn(ar, "failed to parse mem_reqs tlv: %d\n", ret);
+		return ret;
+	}
+
+	kfree(tb);
+	return 0;
+}
+
+static int ath10k_wmi_tlv_op_pull_rdy_ev(struct ath10k *ar,
+					 struct sk_buff *skb,
+					 struct wmi_rdy_ev_arg *arg)
+{
+	const void **tb;
+	const struct wmi_tlv_rdy_ev *ev;
+	int ret;
+
+	tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+	if (IS_ERR(tb)) {
+		ret = PTR_ERR(tb);
+		ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+		return ret;
+	}
+
+	ev = tb[WMI_TLV_TAG_STRUCT_READY_EVENT];
+	if (!ev) {
+		kfree(tb);
+		return -EPROTO;
+	}
+
+	arg->sw_version = ev->abi.abi_ver0;
+	arg->abi_version = ev->abi.abi_ver1;
+	arg->status = ev->status;
+	arg->mac_addr = ev->mac_addr.addr;
+
+	kfree(tb);
+	return 0;
+}
+
+static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar,
+					   struct sk_buff *skb,
+					   struct ath10k_fw_stats *stats)
+{
+	const void **tb;
+	const struct wmi_stats_event *ev;
+	const void *data;
+	u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
+	size_t data_len;
+	int ret;
+
+	tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+	if (IS_ERR(tb)) {
+		ret = PTR_ERR(tb);
+		ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+		return ret;
+	}
+
+	ev = tb[WMI_TLV_TAG_STRUCT_STATS_EVENT];
+	data = tb[WMI_TLV_TAG_ARRAY_BYTE];
+
+	if (!ev || !data) {
+		kfree(tb);
+		return -EPROTO;
+	}
+
+	data_len = ath10k_wmi_tlv_len(data);
+	num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
+	num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
+	num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
+
+	WARN_ON(1); /* FIXME: not implemented yet */
+
+	kfree(tb);
+	return 0;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pdev_suspend(struct ath10k *ar, u32 opt)
+{
+	struct wmi_tlv_pdev_suspend *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SUSPEND_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->opt = __cpu_to_le32(opt);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev suspend\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pdev_resume(struct ath10k *ar)
+{
+	struct wmi_tlv_resume_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_RESUME_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->reserved = __cpu_to_le32(0);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev resume\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pdev_set_rd(struct ath10k *ar,
+				  u16 rd, u16 rd2g, u16 rd5g,
+				  u16 ctl2g, u16 ctl5g,
+				  enum wmi_dfs_region dfs_reg)
+{
+	struct wmi_tlv_pdev_set_rd_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_REGDOMAIN_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->regd = __cpu_to_le32(rd);
+	cmd->regd_2ghz = __cpu_to_le32(rd2g);
+	cmd->regd_5ghz = __cpu_to_le32(rd5g);
+	cmd->conform_limit_2ghz = __cpu_to_le32(rd2g);
+	cmd->conform_limit_5ghz = __cpu_to_le32(rd5g);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set rd\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pdev_set_param(struct ath10k *ar, u32 param_id,
+				     u32 param_value)
+{
+	struct wmi_tlv_pdev_set_param_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_PARAM_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->param_id = __cpu_to_le32(param_id);
+	cmd->param_value = __cpu_to_le32(param_value);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set param\n");
+	return skb;
+}
+
+static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
+{
+	struct sk_buff *skb;
+	struct wmi_tlv *tlv;
+	struct wmi_tlv_init_cmd *cmd;
+	struct wmi_tlv_resource_config *cfg;
+	struct wmi_host_mem_chunks *chunks;
+	size_t len, chunks_len;
+	void *ptr;
+
+	chunks_len = ar->wmi.num_mem_chunks * sizeof(struct host_memory_chunk);
+	len = (sizeof(*tlv) + sizeof(*cmd)) +
+	      (sizeof(*tlv) + sizeof(*cfg)) +
+	      (sizeof(*tlv) + chunks_len);
+
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = skb->data;
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_INIT_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cmd);
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_RESOURCE_CONFIG);
+	tlv->len = __cpu_to_le16(sizeof(*cfg));
+	cfg = (void *)tlv->value;
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cfg);
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+	tlv->len = __cpu_to_le16(chunks_len);
+	chunks = (void *)tlv->value;
+
+	ptr += sizeof(*tlv);
+	ptr += chunks_len;
+
+	cmd->abi.abi_ver0 = __cpu_to_le32(WMI_TLV_ABI_VER0);
+	cmd->abi.abi_ver1 = __cpu_to_le32(WMI_TLV_ABI_VER1);
+	cmd->abi.abi_ver_ns0 = __cpu_to_le32(WMI_TLV_ABI_VER_NS0);
+	cmd->abi.abi_ver_ns1 = __cpu_to_le32(WMI_TLV_ABI_VER_NS1);
+	cmd->abi.abi_ver_ns2 = __cpu_to_le32(WMI_TLV_ABI_VER_NS2);
+	cmd->abi.abi_ver_ns3 = __cpu_to_le32(WMI_TLV_ABI_VER_NS3);
+	cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
+
+	cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
+	cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS);
+	cfg->num_offload_peers = __cpu_to_le32(0);
+	cfg->num_offload_reorder_bufs = __cpu_to_le32(0);
+	cfg->num_peer_keys = __cpu_to_le32(2);
+	cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS);
+	cfg->ast_skid_limit = __cpu_to_le32(0x10);
+	cfg->tx_chain_mask = __cpu_to_le32(0x7);
+	cfg->rx_chain_mask = __cpu_to_le32(0x7);
+	cfg->rx_timeout_pri[0] = __cpu_to_le32(0x64);
+	cfg->rx_timeout_pri[1] = __cpu_to_le32(0x64);
+	cfg->rx_timeout_pri[2] = __cpu_to_le32(0x64);
+	cfg->rx_timeout_pri[3] = __cpu_to_le32(0x28);
+	cfg->rx_decap_mode = __cpu_to_le32(1);
+	cfg->scan_max_pending_reqs = __cpu_to_le32(4);
+	cfg->bmiss_offload_max_vdev = __cpu_to_le32(3);
+	cfg->roam_offload_max_vdev = __cpu_to_le32(3);
+	cfg->roam_offload_max_ap_profiles = __cpu_to_le32(8);
+	cfg->num_mcast_groups = __cpu_to_le32(0);
+	cfg->num_mcast_table_elems = __cpu_to_le32(0);
+	cfg->mcast2ucast_mode = __cpu_to_le32(0);
+	cfg->tx_dbg_log_size = __cpu_to_le32(0x400);
+	cfg->num_wds_entries = __cpu_to_le32(0x20);
+	cfg->dma_burst_size = __cpu_to_le32(0);
+	cfg->mac_aggr_delim = __cpu_to_le32(0);
+	cfg->rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(0);
+	cfg->vow_config = __cpu_to_le32(0);
+	cfg->gtk_offload_max_vdev = __cpu_to_le32(2);
+	cfg->num_msdu_desc = __cpu_to_le32(TARGET_TLV_NUM_MSDU_DESC);
+	cfg->max_frag_entries = __cpu_to_le32(2);
+	cfg->num_tdls_vdevs = __cpu_to_le32(1);
+	cfg->num_tdls_conn_table_entries = __cpu_to_le32(0x20);
+	cfg->beacon_tx_offload_max_vdev = __cpu_to_le32(2);
+	cfg->num_multicast_filter_entries = __cpu_to_le32(5);
+	cfg->num_wow_filters = __cpu_to_le32(0x16);
+	cfg->num_keep_alive_pattern = __cpu_to_le32(6);
+	cfg->keep_alive_pattern_size = __cpu_to_le32(0);
+	cfg->max_tdls_concurrent_sleep_sta = __cpu_to_le32(1);
+	cfg->max_tdls_concurrent_buffer_sta = __cpu_to_le32(1);
+
+	ath10k_wmi_put_host_mem_chunks(ar, chunks);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv init\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_start_scan(struct ath10k *ar,
+				 const struct wmi_start_scan_arg *arg)
+{
+	struct wmi_tlv_start_scan_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	size_t len, chan_len, ssid_len, bssid_len, ie_len;
+	__le32 *chans;
+	struct wmi_ssid *ssids;
+	struct wmi_mac_addr *addrs;
+	void *ptr;
+	int i, ret;
+
+	ret = ath10k_wmi_start_scan_verify(arg);
+	if (ret)
+		return ERR_PTR(ret);
+
+	chan_len = arg->n_channels * sizeof(__le32);
+	ssid_len = arg->n_ssids * sizeof(struct wmi_ssid);
+	bssid_len = arg->n_bssids * sizeof(struct wmi_mac_addr);
+	ie_len = roundup(arg->ie_len, 4);
+	len = (sizeof(*tlv) + sizeof(*cmd)) +
+	      (arg->n_channels ? sizeof(*tlv) + chan_len : 0) +
+	      (arg->n_ssids ? sizeof(*tlv) + ssid_len : 0) +
+	      (arg->n_bssids ? sizeof(*tlv) + bssid_len : 0) +
+	      (arg->ie_len ? sizeof(*tlv) + ie_len : 0);
+
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = (void *)skb->data;
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_START_SCAN_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+
+	ath10k_wmi_put_start_scan_common(&cmd->common, arg);
+	cmd->burst_duration_ms = __cpu_to_le32(0);
+	cmd->num_channels = __cpu_to_le32(arg->n_channels);
+	cmd->num_ssids = __cpu_to_le32(arg->n_ssids);
+	cmd->num_bssids = __cpu_to_le32(arg->n_bssids);
+	cmd->ie_len = __cpu_to_le32(arg->ie_len);
+	cmd->num_probes = __cpu_to_le32(3);
+
+	/* FIXME: There are some scan flag inconsistencies across firmwares,
+	 * e.g. WMI-TLV inverts the logic behind the following flag.
+	 */
+	cmd->common.scan_ctrl_flags ^= __cpu_to_le32(WMI_SCAN_FILTER_PROBE_REQ);
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cmd);
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32);
+	tlv->len = __cpu_to_le16(chan_len);
+	chans = (void *)tlv->value;
+	for (i = 0; i < arg->n_channels; i++)
+		chans[i] = __cpu_to_le32(arg->channels[i]);
+
+	ptr += sizeof(*tlv);
+	ptr += chan_len;
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_FIXED_STRUCT);
+	tlv->len = __cpu_to_le16(ssid_len);
+	ssids = (void *)tlv->value;
+	for (i = 0; i < arg->n_ssids; i++) {
+		ssids[i].ssid_len = __cpu_to_le32(arg->ssids[i].len);
+		memcpy(ssids[i].ssid, arg->ssids[i].ssid, arg->ssids[i].len);
+	}
+
+	ptr += sizeof(*tlv);
+	ptr += ssid_len;
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_FIXED_STRUCT);
+	tlv->len = __cpu_to_le16(bssid_len);
+	addrs = (void *)tlv->value;
+	for (i = 0; i < arg->n_bssids; i++)
+		ether_addr_copy(addrs[i].addr, arg->bssids[i].bssid);
+
+	ptr += sizeof(*tlv);
+	ptr += bssid_len;
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
+	tlv->len = __cpu_to_le16(ie_len);
+	memcpy(tlv->value, arg->ie, arg->ie_len);
+
+	ptr += sizeof(*tlv);
+	ptr += ie_len;
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv start scan\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_stop_scan(struct ath10k *ar,
+				const struct wmi_stop_scan_arg *arg)
+{
+	struct wmi_stop_scan_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	u32 scan_id;
+	u32 req_id;
+
+	if (arg->req_id > 0xFFF)
+		return ERR_PTR(-EINVAL);
+	if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF)
+		return ERR_PTR(-EINVAL);
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	scan_id = arg->u.scan_id;
+	scan_id |= WMI_HOST_SCAN_REQ_ID_PREFIX;
+
+	req_id = arg->req_id;
+	req_id |= WMI_HOST_SCAN_REQUESTOR_ID_PREFIX;
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STOP_SCAN_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->req_type = __cpu_to_le32(arg->req_type);
+	cmd->vdev_id = __cpu_to_le32(arg->u.vdev_id);
+	cmd->scan_id = __cpu_to_le32(scan_id);
+	cmd->scan_req_id = __cpu_to_le32(req_id);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv stop scan\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_create(struct ath10k *ar,
+				  u32 vdev_id,
+				  enum wmi_vdev_type vdev_type,
+				  enum wmi_vdev_subtype vdev_subtype,
+				  const u8 mac_addr[ETH_ALEN])
+{
+	struct wmi_vdev_create_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_CREATE_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+	cmd->vdev_type = __cpu_to_le32(vdev_type);
+	cmd->vdev_subtype = __cpu_to_le32(vdev_subtype);
+	ether_addr_copy(cmd->vdev_macaddr.addr, mac_addr);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev create\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_delete(struct ath10k *ar, u32 vdev_id)
+{
+	struct wmi_vdev_delete_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_DELETE_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev delete\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_start(struct ath10k *ar,
+				 const struct wmi_vdev_start_request_arg *arg,
+				 bool restart)
+{
+	struct wmi_tlv_vdev_start_cmd *cmd;
+	struct wmi_channel *ch;
+	struct wmi_p2p_noa_descriptor *noa;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	size_t len;
+	void *ptr;
+	u32 flags = 0;
+
+	if (WARN_ON(arg->ssid && arg->ssid_len == 0))
+		return ERR_PTR(-EINVAL);
+	if (WARN_ON(arg->hidden_ssid && !arg->ssid))
+		return ERR_PTR(-EINVAL);
+	if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid)))
+		return ERR_PTR(-EINVAL);
+
+	len = (sizeof(*tlv) + sizeof(*cmd)) +
+	      (sizeof(*tlv) + sizeof(*ch)) +
+	      (sizeof(*tlv) + 0);
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	if (arg->hidden_ssid)
+		flags |= WMI_VDEV_START_HIDDEN_SSID;
+	if (arg->pmf_enabled)
+		flags |= WMI_VDEV_START_PMF_ENABLED;
+
+	ptr = (void *)skb->data;
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_START_REQUEST_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
+	cmd->bcn_intval = __cpu_to_le32(arg->bcn_intval);
+	cmd->dtim_period = __cpu_to_le32(arg->dtim_period);
+	cmd->flags = __cpu_to_le32(flags);
+	cmd->bcn_tx_rate = __cpu_to_le32(arg->bcn_tx_rate);
+	cmd->bcn_tx_power = __cpu_to_le32(arg->bcn_tx_power);
+	cmd->disable_hw_ack = __cpu_to_le32(arg->disable_hw_ack);
+
+	if (arg->ssid) {
+		cmd->ssid.ssid_len = __cpu_to_le32(arg->ssid_len);
+		memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len);
+	}
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cmd);
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL);
+	tlv->len = __cpu_to_le16(sizeof(*ch));
+	ch = (void *)tlv->value;
+	ath10k_wmi_put_wmi_channel(ch, &arg->channel);
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*ch);
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+	tlv->len = 0;
+	noa = (void *)tlv->value;
+
+	/* Note: This is a nested TLV containing:
+	 * [wmi_tlv][wmi_p2p_noa_descriptor][wmi_tlv]..
+	 */
+
+	ptr += sizeof(*tlv);
+	ptr += 0;
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev start\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_stop(struct ath10k *ar, u32 vdev_id)
+{
+	struct wmi_vdev_stop_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_STOP_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev stop\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid,
+			      const u8 *bssid)
+
+{
+	struct wmi_vdev_up_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_UP_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+	cmd->vdev_assoc_id = __cpu_to_le32(aid);
+	ether_addr_copy(cmd->vdev_bssid.addr, bssid);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev up\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_down(struct ath10k *ar, u32 vdev_id)
+{
+	struct wmi_vdev_down_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_DOWN_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev down\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_set_param(struct ath10k *ar, u32 vdev_id,
+				     u32 param_id, u32 param_value)
+{
+	struct wmi_vdev_set_param_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_SET_PARAM_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+	cmd->param_id = __cpu_to_le32(param_id);
+	cmd->param_value = __cpu_to_le32(param_value);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev set param\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_install_key(struct ath10k *ar,
+				       const struct wmi_vdev_install_key_arg *arg)
+{
+	struct wmi_vdev_install_key_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	size_t len;
+	void *ptr;
+
+	if (arg->key_cipher == WMI_CIPHER_NONE && arg->key_data != NULL)
+		return ERR_PTR(-EINVAL);
+	if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL)
+		return ERR_PTR(-EINVAL);
+
+	len = sizeof(*tlv) + sizeof(*cmd) +
+	      sizeof(*tlv) + roundup(arg->key_len, sizeof(__le32));
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = (void *)skb->data;
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
+	cmd->key_idx = __cpu_to_le32(arg->key_idx);
+	cmd->key_flags = __cpu_to_le32(arg->key_flags);
+	cmd->key_cipher = __cpu_to_le32(arg->key_cipher);
+	cmd->key_len = __cpu_to_le32(arg->key_len);
+	cmd->key_txmic_len = __cpu_to_le32(arg->key_txmic_len);
+	cmd->key_rxmic_len = __cpu_to_le32(arg->key_rxmic_len);
+
+	if (arg->macaddr)
+		ether_addr_copy(cmd->peer_macaddr.addr, arg->macaddr);
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cmd);
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
+	tlv->len = __cpu_to_le16(roundup(arg->key_len, sizeof(__le32)));
+	if (arg->key_data)
+		memcpy(tlv->value, arg->key_data, arg->key_len);
+
+	ptr += sizeof(*tlv);
+	ptr += roundup(arg->key_len, sizeof(__le32));
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev install key\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
+				  const u8 peer_addr[ETH_ALEN])
+{
+	struct wmi_tlv_peer_create_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_CREATE_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+	cmd->peer_type = __cpu_to_le32(WMI_TLV_PEER_TYPE_DEFAULT); /* FIXME */
+	ether_addr_copy(cmd->peer_addr.addr, peer_addr);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer create\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_peer_delete(struct ath10k *ar, u32 vdev_id,
+				  const u8 peer_addr[ETH_ALEN])
+{
+	struct wmi_peer_delete_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_DELETE_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+	ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer delete\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_peer_flush(struct ath10k *ar, u32 vdev_id,
+				 const u8 peer_addr[ETH_ALEN], u32 tid_bitmap)
+{
+	struct wmi_peer_flush_tids_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_FLUSH_TIDS_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+	cmd->peer_tid_bitmap = __cpu_to_le32(tid_bitmap);
+	ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer flush\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_peer_set_param(struct ath10k *ar, u32 vdev_id,
+				     const u8 *peer_addr,
+				     enum wmi_peer_param param_id,
+				     u32 param_value)
+{
+	struct wmi_peer_set_param_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_SET_PARAM_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+	cmd->param_id = __cpu_to_le32(param_id);
+	cmd->param_value = __cpu_to_le32(param_value);
+	ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer set param\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_peer_assoc(struct ath10k *ar,
+				 const struct wmi_peer_assoc_complete_arg *arg)
+{
+	struct wmi_tlv_peer_assoc_cmd *cmd;
+	struct wmi_vht_rate_set *vht_rate;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	size_t len, legacy_rate_len, ht_rate_len;
+	void *ptr;
+
+	if (arg->peer_mpdu_density > 16)
+		return ERR_PTR(-EINVAL);
+	if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
+		return ERR_PTR(-EINVAL);
+	if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
+		return ERR_PTR(-EINVAL);
+
+	legacy_rate_len = roundup(arg->peer_legacy_rates.num_rates,
+				  sizeof(__le32));
+	ht_rate_len = roundup(arg->peer_ht_rates.num_rates, sizeof(__le32));
+	len = (sizeof(*tlv) + sizeof(*cmd)) +
+	      (sizeof(*tlv) + legacy_rate_len) +
+	      (sizeof(*tlv) + ht_rate_len) +
+	      (sizeof(*tlv) + sizeof(*vht_rate));
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = (void *)skb->data;
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_ASSOC_COMPLETE_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+
+	cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
+	cmd->new_assoc = __cpu_to_le32(arg->peer_reassoc ? 0 : 1);
+	cmd->assoc_id = __cpu_to_le32(arg->peer_aid);
+	cmd->flags = __cpu_to_le32(arg->peer_flags);
+	cmd->caps = __cpu_to_le32(arg->peer_caps);
+	cmd->listen_intval = __cpu_to_le32(arg->peer_listen_intval);
+	cmd->ht_caps = __cpu_to_le32(arg->peer_ht_caps);
+	cmd->max_mpdu = __cpu_to_le32(arg->peer_max_mpdu);
+	cmd->mpdu_density = __cpu_to_le32(arg->peer_mpdu_density);
+	cmd->rate_caps = __cpu_to_le32(arg->peer_rate_caps);
+	cmd->nss = __cpu_to_le32(arg->peer_num_spatial_streams);
+	cmd->vht_caps = __cpu_to_le32(arg->peer_vht_caps);
+	cmd->phy_mode = __cpu_to_le32(arg->peer_phymode);
+	cmd->num_legacy_rates = __cpu_to_le32(arg->peer_legacy_rates.num_rates);
+	cmd->num_ht_rates = __cpu_to_le32(arg->peer_ht_rates.num_rates);
+	ether_addr_copy(cmd->mac_addr.addr, arg->addr);
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cmd);
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
+	tlv->len = __cpu_to_le16(legacy_rate_len);
+	memcpy(tlv->value, arg->peer_legacy_rates.rates,
+	       arg->peer_legacy_rates.num_rates);
+
+	ptr += sizeof(*tlv);
+	ptr += legacy_rate_len;
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
+	tlv->len = __cpu_to_le16(ht_rate_len);
+	memcpy(tlv->value, arg->peer_ht_rates.rates,
+	       arg->peer_ht_rates.num_rates);
+
+	ptr += sizeof(*tlv);
+	ptr += ht_rate_len;
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VHT_RATE_SET);
+	tlv->len = __cpu_to_le16(sizeof(*vht_rate));
+	vht_rate = (void *)tlv->value;
+
+	vht_rate->rx_max_rate = __cpu_to_le32(arg->peer_vht_rates.rx_max_rate);
+	vht_rate->rx_mcs_set = __cpu_to_le32(arg->peer_vht_rates.rx_mcs_set);
+	vht_rate->tx_max_rate = __cpu_to_le32(arg->peer_vht_rates.tx_max_rate);
+	vht_rate->tx_mcs_set = __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set);
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*vht_rate);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer assoc\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id,
+				 enum wmi_sta_ps_mode psmode)
+{
+	struct wmi_sta_powersave_mode_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_POWERSAVE_MODE_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+	cmd->sta_ps_mode = __cpu_to_le32(psmode);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set psmode\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_set_sta_ps(struct ath10k *ar, u32 vdev_id,
+				 enum wmi_sta_powersave_param param_id,
+				 u32 param_value)
+{
+	struct wmi_sta_powersave_param_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_POWERSAVE_PARAM_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+	cmd->param_id = __cpu_to_le32(param_id);
+	cmd->param_value = __cpu_to_le32(param_value);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set sta ps\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_set_ap_ps(struct ath10k *ar, u32 vdev_id, const u8 *mac,
+				enum wmi_ap_ps_peer_param param_id, u32 value)
+{
+	struct wmi_ap_ps_peer_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	if (!mac)
+		return ERR_PTR(-EINVAL);
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_AP_PS_PEER_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+	cmd->param_id = __cpu_to_le32(param_id);
+	cmd->param_value = __cpu_to_le32(value);
+	ether_addr_copy(cmd->peer_macaddr.addr, mac);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv ap ps param\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_scan_chan_list(struct ath10k *ar,
+				     const struct wmi_scan_chan_list_arg *arg)
+{
+	struct wmi_tlv_scan_chan_list_cmd *cmd;
+	struct wmi_channel *ci;
+	struct wmi_channel_arg *ch;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	size_t chans_len, len;
+	int i;
+	void *ptr, *chans;
+
+	chans_len = arg->n_channels * (sizeof(*tlv) + sizeof(*ci));
+	len = (sizeof(*tlv) + sizeof(*cmd)) +
+	      (sizeof(*tlv) + chans_len);
+
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = (void *)skb->data;
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_SCAN_CHAN_LIST_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->num_scan_chans = __cpu_to_le32(arg->n_channels);
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cmd);
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+	tlv->len = __cpu_to_le16(chans_len);
+	chans = (void *)tlv->value;
+
+	for (i = 0; i < arg->n_channels; i++) {
+		ch = &arg->channels[i];
+
+		tlv = chans;
+		tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL);
+		tlv->len = __cpu_to_le16(sizeof(*ci));
+		ci = (void *)tlv->value;
+
+		ath10k_wmi_put_wmi_channel(ci, ch);
+
+		chans += sizeof(*tlv);
+		chans += sizeof(*ci);
+	}
+
+	ptr += sizeof(*tlv);
+	ptr += chans_len;
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv scan chan list\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_beacon_dma(struct ath10k_vif *arvif)
+{
+	struct ath10k *ar = arvif->ar;
+	struct wmi_bcn_tx_ref_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	struct sk_buff *beacon = arvif->beacon;
+	struct ieee80211_hdr *hdr;
+	u16 fc;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	hdr = (struct ieee80211_hdr *)beacon->data;
+	fc = le16_to_cpu(hdr->frame_control);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_SEND_FROM_HOST_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = __cpu_to_le32(arvif->vdev_id);
+	cmd->data_len = __cpu_to_le32(beacon->len);
+	cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr);
+	cmd->msdu_id = 0;
+	cmd->frame_control = __cpu_to_le32(fc);
+	cmd->flags = 0;
+
+	if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero)
+		cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO);
+
+	if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab)
+		cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv beacon dma\n");
+	return skb;
+}
+
+static void *ath10k_wmi_tlv_put_wmm(void *ptr,
+				    const struct wmi_wmm_params_arg *arg)
+{
+	struct wmi_wmm_params *wmm;
+	struct wmi_tlv *tlv;
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WMM_PARAMS);
+	tlv->len = __cpu_to_le16(sizeof(*wmm));
+	wmm = (void *)tlv->value;
+	ath10k_wmi_pdev_set_wmm_param(wmm, arg);
+
+	return ptr + sizeof(*tlv) + sizeof(*wmm);
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pdev_set_wmm(struct ath10k *ar,
+				   const struct wmi_pdev_set_wmm_params_arg *arg)
+{
+	struct wmi_tlv_pdev_set_wmm_cmd *cmd;
+	struct wmi_wmm_params *wmm;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	size_t len;
+	void *ptr;
+
+	len = (sizeof(*tlv) + sizeof(*cmd)) +
+	      (4 * (sizeof(*tlv) + sizeof(*wmm)));
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = (void *)skb->data;
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_WMM_PARAMS_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+
+	/* nothing to set here */
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cmd);
+
+	ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_be);
+	ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_bk);
+	ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vi);
+	ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vo);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set wmm\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar,
+				    enum wmi_stats_id stats_id)
+{
+	struct wmi_request_stats_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->stats_id = __cpu_to_le32(stats_id);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv request stats\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_force_fw_hang(struct ath10k *ar,
+				    enum wmi_force_fw_hang_type type,
+				    u32 delay_ms)
+{
+	struct wmi_force_fw_hang_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	tlv = (void *)skb->data;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_FORCE_FW_HANG_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->type = __cpu_to_le32(type);
+	cmd->delay_ms = __cpu_to_le32(delay_ms);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv force fw hang\n");
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable)
+{
+	struct wmi_tlv_dbglog_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	size_t len, bmap_len;
+	u32 value;
+	void *ptr;
+
+	if (module_enable) {
+		value = WMI_TLV_DBGLOG_LOG_LEVEL_VALUE(
+				module_enable,
+				WMI_TLV_DBGLOG_LOG_LEVEL_VERBOSE);
+	} else {
+		value = WMI_TLV_DBGLOG_LOG_LEVEL_VALUE(
+				WMI_TLV_DBGLOG_ALL_MODULES,
+				WMI_TLV_DBGLOG_LOG_LEVEL_WARN);
+	}
+
+	bmap_len = 0;
+	len = sizeof(*tlv) + sizeof(*cmd) + sizeof(*tlv) + bmap_len;
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = (void *)skb->data;
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_DEBUG_LOG_CONFIG_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->param = __cpu_to_le32(WMI_TLV_DBGLOG_PARAM_LOG_LEVEL);
+	cmd->value = __cpu_to_le32(value);
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cmd);
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32);
+	tlv->len = __cpu_to_le16(bmap_len);
+
+	/* nothing to do here */
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(bmap_len);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv dbglog value 0x%08x\n", value);
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pktlog_enable(struct ath10k *ar, u32 filter)
+{
+	struct wmi_tlv_pktlog_enable *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	void *ptr;
+	size_t len;
+
+	len = sizeof(*tlv) + sizeof(*cmd);
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = (void *)skb->data;
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_ENABLE_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->filter = __cpu_to_le32(filter);
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cmd);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pktlog enable filter 0x%08x\n",
+		   filter);
+	return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pktlog_disable(struct ath10k *ar)
+{
+	struct wmi_tlv_pktlog_disable *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	void *ptr;
+	size_t len;
+
+	len = sizeof(*tlv) + sizeof(*cmd);
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = (void *)skb->data;
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_DISABLE_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cmd);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pktlog disable\n");
+	return skb;
+}
+
+/****************/
+/* TLV mappings */
+/****************/
+
+static struct wmi_cmd_map wmi_tlv_cmd_map = {
+	.init_cmdid = WMI_TLV_INIT_CMDID,
+	.start_scan_cmdid = WMI_TLV_START_SCAN_CMDID,
+	.stop_scan_cmdid = WMI_TLV_STOP_SCAN_CMDID,
+	.scan_chan_list_cmdid = WMI_TLV_SCAN_CHAN_LIST_CMDID,
+	.scan_sch_prio_tbl_cmdid = WMI_TLV_SCAN_SCH_PRIO_TBL_CMDID,
+	.pdev_set_regdomain_cmdid = WMI_TLV_PDEV_SET_REGDOMAIN_CMDID,
+	.pdev_set_channel_cmdid = WMI_TLV_PDEV_SET_CHANNEL_CMDID,
+	.pdev_set_param_cmdid = WMI_TLV_PDEV_SET_PARAM_CMDID,
+	.pdev_pktlog_enable_cmdid = WMI_TLV_PDEV_PKTLOG_ENABLE_CMDID,
+	.pdev_pktlog_disable_cmdid = WMI_TLV_PDEV_PKTLOG_DISABLE_CMDID,
+	.pdev_set_wmm_params_cmdid = WMI_TLV_PDEV_SET_WMM_PARAMS_CMDID,
+	.pdev_set_ht_cap_ie_cmdid = WMI_TLV_PDEV_SET_HT_CAP_IE_CMDID,
+	.pdev_set_vht_cap_ie_cmdid = WMI_TLV_PDEV_SET_VHT_CAP_IE_CMDID,
+	.pdev_set_dscp_tid_map_cmdid = WMI_TLV_PDEV_SET_DSCP_TID_MAP_CMDID,
+	.pdev_set_quiet_mode_cmdid = WMI_TLV_PDEV_SET_QUIET_MODE_CMDID,
+	.pdev_green_ap_ps_enable_cmdid = WMI_TLV_PDEV_GREEN_AP_PS_ENABLE_CMDID,
+	.pdev_get_tpc_config_cmdid = WMI_TLV_PDEV_GET_TPC_CONFIG_CMDID,
+	.pdev_set_base_macaddr_cmdid = WMI_TLV_PDEV_SET_BASE_MACADDR_CMDID,
+	.vdev_create_cmdid = WMI_TLV_VDEV_CREATE_CMDID,
+	.vdev_delete_cmdid = WMI_TLV_VDEV_DELETE_CMDID,
+	.vdev_start_request_cmdid = WMI_TLV_VDEV_START_REQUEST_CMDID,
+	.vdev_restart_request_cmdid = WMI_TLV_VDEV_RESTART_REQUEST_CMDID,
+	.vdev_up_cmdid = WMI_TLV_VDEV_UP_CMDID,
+	.vdev_stop_cmdid = WMI_TLV_VDEV_STOP_CMDID,
+	.vdev_down_cmdid = WMI_TLV_VDEV_DOWN_CMDID,
+	.vdev_set_param_cmdid = WMI_TLV_VDEV_SET_PARAM_CMDID,
+	.vdev_install_key_cmdid = WMI_TLV_VDEV_INSTALL_KEY_CMDID,
+	.peer_create_cmdid = WMI_TLV_PEER_CREATE_CMDID,
+	.peer_delete_cmdid = WMI_TLV_PEER_DELETE_CMDID,
+	.peer_flush_tids_cmdid = WMI_TLV_PEER_FLUSH_TIDS_CMDID,
+	.peer_set_param_cmdid = WMI_TLV_PEER_SET_PARAM_CMDID,
+	.peer_assoc_cmdid = WMI_TLV_PEER_ASSOC_CMDID,
+	.peer_add_wds_entry_cmdid = WMI_TLV_PEER_ADD_WDS_ENTRY_CMDID,
+	.peer_remove_wds_entry_cmdid = WMI_TLV_PEER_REMOVE_WDS_ENTRY_CMDID,
+	.peer_mcast_group_cmdid = WMI_TLV_PEER_MCAST_GROUP_CMDID,
+	.bcn_tx_cmdid = WMI_TLV_BCN_TX_CMDID,
+	.pdev_send_bcn_cmdid = WMI_TLV_PDEV_SEND_BCN_CMDID,
+	.bcn_tmpl_cmdid = WMI_TLV_BCN_TMPL_CMDID,
+	.bcn_filter_rx_cmdid = WMI_TLV_BCN_FILTER_RX_CMDID,
+	.prb_req_filter_rx_cmdid = WMI_TLV_PRB_REQ_FILTER_RX_CMDID,
+	.mgmt_tx_cmdid = WMI_TLV_MGMT_TX_CMDID,
+	.prb_tmpl_cmdid = WMI_TLV_PRB_TMPL_CMDID,
+	.addba_clear_resp_cmdid = WMI_TLV_ADDBA_CLEAR_RESP_CMDID,
+	.addba_send_cmdid = WMI_TLV_ADDBA_SEND_CMDID,
+	.addba_status_cmdid = WMI_TLV_ADDBA_STATUS_CMDID,
+	.delba_send_cmdid = WMI_TLV_DELBA_SEND_CMDID,
+	.addba_set_resp_cmdid = WMI_TLV_ADDBA_SET_RESP_CMDID,
+	.send_singleamsdu_cmdid = WMI_TLV_SEND_SINGLEAMSDU_CMDID,
+	.sta_powersave_mode_cmdid = WMI_TLV_STA_POWERSAVE_MODE_CMDID,
+	.sta_powersave_param_cmdid = WMI_TLV_STA_POWERSAVE_PARAM_CMDID,
+	.sta_mimo_ps_mode_cmdid = WMI_TLV_STA_MIMO_PS_MODE_CMDID,
+	.pdev_dfs_enable_cmdid = WMI_TLV_PDEV_DFS_ENABLE_CMDID,
+	.pdev_dfs_disable_cmdid = WMI_TLV_PDEV_DFS_DISABLE_CMDID,
+	.roam_scan_mode = WMI_TLV_ROAM_SCAN_MODE,
+	.roam_scan_rssi_threshold = WMI_TLV_ROAM_SCAN_RSSI_THRESHOLD,
+	.roam_scan_period = WMI_TLV_ROAM_SCAN_PERIOD,
+	.roam_scan_rssi_change_threshold =
+				WMI_TLV_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+	.roam_ap_profile = WMI_TLV_ROAM_AP_PROFILE,
+	.ofl_scan_add_ap_profile = WMI_TLV_ROAM_AP_PROFILE,
+	.ofl_scan_remove_ap_profile = WMI_TLV_OFL_SCAN_REMOVE_AP_PROFILE,
+	.ofl_scan_period = WMI_TLV_OFL_SCAN_PERIOD,
+	.p2p_dev_set_device_info = WMI_TLV_P2P_DEV_SET_DEVICE_INFO,
+	.p2p_dev_set_discoverability = WMI_TLV_P2P_DEV_SET_DISCOVERABILITY,
+	.p2p_go_set_beacon_ie = WMI_TLV_P2P_GO_SET_BEACON_IE,
+	.p2p_go_set_probe_resp_ie = WMI_TLV_P2P_GO_SET_PROBE_RESP_IE,
+	.p2p_set_vendor_ie_data_cmdid = WMI_TLV_P2P_SET_VENDOR_IE_DATA_CMDID,
+	.ap_ps_peer_param_cmdid = WMI_TLV_AP_PS_PEER_PARAM_CMDID,
+	.ap_ps_peer_uapsd_coex_cmdid = WMI_TLV_AP_PS_PEER_UAPSD_COEX_CMDID,
+	.peer_rate_retry_sched_cmdid = WMI_TLV_PEER_RATE_RETRY_SCHED_CMDID,
+	.wlan_profile_trigger_cmdid = WMI_TLV_WLAN_PROFILE_TRIGGER_CMDID,
+	.wlan_profile_set_hist_intvl_cmdid =
+				WMI_TLV_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+	.wlan_profile_get_profile_data_cmdid =
+				WMI_TLV_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+	.wlan_profile_enable_profile_id_cmdid =
+				WMI_TLV_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+	.wlan_profile_list_profile_id_cmdid =
+				WMI_TLV_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+	.pdev_suspend_cmdid = WMI_TLV_PDEV_SUSPEND_CMDID,
+	.pdev_resume_cmdid = WMI_TLV_PDEV_RESUME_CMDID,
+	.add_bcn_filter_cmdid = WMI_TLV_ADD_BCN_FILTER_CMDID,
+	.rmv_bcn_filter_cmdid = WMI_TLV_RMV_BCN_FILTER_CMDID,
+	.wow_add_wake_pattern_cmdid = WMI_TLV_WOW_ADD_WAKE_PATTERN_CMDID,
+	.wow_del_wake_pattern_cmdid = WMI_TLV_WOW_DEL_WAKE_PATTERN_CMDID,
+	.wow_enable_disable_wake_event_cmdid =
+				WMI_TLV_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
+	.wow_enable_cmdid = WMI_TLV_WOW_ENABLE_CMDID,
+	.wow_hostwakeup_from_sleep_cmdid =
+				WMI_TLV_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
+	.rtt_measreq_cmdid = WMI_TLV_RTT_MEASREQ_CMDID,
+	.rtt_tsf_cmdid = WMI_TLV_RTT_TSF_CMDID,
+	.vdev_spectral_scan_configure_cmdid = WMI_TLV_SPECTRAL_SCAN_CONF_CMDID,
+	.vdev_spectral_scan_enable_cmdid = WMI_TLV_SPECTRAL_SCAN_ENABLE_CMDID,
+	.request_stats_cmdid = WMI_TLV_REQUEST_STATS_CMDID,
+	.set_arp_ns_offload_cmdid = WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID,
+	.network_list_offload_config_cmdid =
+				WMI_TLV_NETWORK_LIST_OFFLOAD_CONFIG_CMDID,
+	.gtk_offload_cmdid = WMI_TLV_GTK_OFFLOAD_CMDID,
+	.csa_offload_enable_cmdid = WMI_TLV_CSA_OFFLOAD_ENABLE_CMDID,
+	.csa_offload_chanswitch_cmdid = WMI_TLV_CSA_OFFLOAD_CHANSWITCH_CMDID,
+	.chatter_set_mode_cmdid = WMI_TLV_CHATTER_SET_MODE_CMDID,
+	.peer_tid_addba_cmdid = WMI_TLV_PEER_TID_ADDBA_CMDID,
+	.peer_tid_delba_cmdid = WMI_TLV_PEER_TID_DELBA_CMDID,
+	.sta_dtim_ps_method_cmdid = WMI_TLV_STA_DTIM_PS_METHOD_CMDID,
+	.sta_uapsd_auto_trig_cmdid = WMI_TLV_STA_UAPSD_AUTO_TRIG_CMDID,
+	.sta_keepalive_cmd = WMI_TLV_STA_KEEPALIVE_CMDID,
+	.echo_cmdid = WMI_TLV_ECHO_CMDID,
+	.pdev_utf_cmdid = WMI_TLV_PDEV_UTF_CMDID,
+	.dbglog_cfg_cmdid = WMI_TLV_DBGLOG_CFG_CMDID,
+	.pdev_qvit_cmdid = WMI_TLV_PDEV_QVIT_CMDID,
+	.pdev_ftm_intg_cmdid = WMI_TLV_PDEV_FTM_INTG_CMDID,
+	.vdev_set_keepalive_cmdid = WMI_TLV_VDEV_SET_KEEPALIVE_CMDID,
+	.vdev_get_keepalive_cmdid = WMI_TLV_VDEV_GET_KEEPALIVE_CMDID,
+	.force_fw_hang_cmdid = WMI_TLV_FORCE_FW_HANG_CMDID,
+	.gpio_config_cmdid = WMI_TLV_GPIO_CONFIG_CMDID,
+	.gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID,
+};
+
+static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = {
+	.tx_chain_mask = WMI_TLV_PDEV_PARAM_TX_CHAIN_MASK,
+	.rx_chain_mask = WMI_TLV_PDEV_PARAM_RX_CHAIN_MASK,
+	.txpower_limit2g = WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT2G,
+	.txpower_limit5g = WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT5G,
+	.txpower_scale = WMI_TLV_PDEV_PARAM_TXPOWER_SCALE,
+	.beacon_gen_mode = WMI_TLV_PDEV_PARAM_BEACON_GEN_MODE,
+	.beacon_tx_mode = WMI_TLV_PDEV_PARAM_BEACON_TX_MODE,
+	.resmgr_offchan_mode = WMI_TLV_PDEV_PARAM_RESMGR_OFFCHAN_MODE,
+	.protection_mode = WMI_TLV_PDEV_PARAM_PROTECTION_MODE,
+	.dynamic_bw = WMI_TLV_PDEV_PARAM_DYNAMIC_BW,
+	.non_agg_sw_retry_th = WMI_TLV_PDEV_PARAM_NON_AGG_SW_RETRY_TH,
+	.agg_sw_retry_th = WMI_TLV_PDEV_PARAM_AGG_SW_RETRY_TH,
+	.sta_kickout_th = WMI_TLV_PDEV_PARAM_STA_KICKOUT_TH,
+	.ac_aggrsize_scaling = WMI_TLV_PDEV_PARAM_AC_AGGRSIZE_SCALING,
+	.ltr_enable = WMI_TLV_PDEV_PARAM_LTR_ENABLE,
+	.ltr_ac_latency_be = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BE,
+	.ltr_ac_latency_bk = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BK,
+	.ltr_ac_latency_vi = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VI,
+	.ltr_ac_latency_vo = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VO,
+	.ltr_ac_latency_timeout = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT,
+	.ltr_sleep_override = WMI_TLV_PDEV_PARAM_LTR_SLEEP_OVERRIDE,
+	.ltr_rx_override = WMI_TLV_PDEV_PARAM_LTR_RX_OVERRIDE,
+	.ltr_tx_activity_timeout = WMI_TLV_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT,
+	.l1ss_enable = WMI_TLV_PDEV_PARAM_L1SS_ENABLE,
+	.dsleep_enable = WMI_TLV_PDEV_PARAM_DSLEEP_ENABLE,
+	.pcielp_txbuf_flush = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_FLUSH,
+	.pcielp_txbuf_watermark = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN,
+	.pcielp_txbuf_tmo_en = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN,
+	.pcielp_txbuf_tmo_value = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE,
+	.pdev_stats_update_period = WMI_TLV_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD,
+	.vdev_stats_update_period = WMI_TLV_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD,
+	.peer_stats_update_period = WMI_TLV_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD,
+	.bcnflt_stats_update_period =
+				WMI_TLV_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
+	.pmf_qos = WMI_TLV_PDEV_PARAM_PMF_QOS,
+	.arp_ac_override = WMI_TLV_PDEV_PARAM_ARP_AC_OVERRIDE,
+	.dcs = WMI_TLV_PDEV_PARAM_DCS,
+	.ani_enable = WMI_TLV_PDEV_PARAM_ANI_ENABLE,
+	.ani_poll_period = WMI_TLV_PDEV_PARAM_ANI_POLL_PERIOD,
+	.ani_listen_period = WMI_TLV_PDEV_PARAM_ANI_LISTEN_PERIOD,
+	.ani_ofdm_level = WMI_TLV_PDEV_PARAM_ANI_OFDM_LEVEL,
+	.ani_cck_level = WMI_TLV_PDEV_PARAM_ANI_CCK_LEVEL,
+	.dyntxchain = WMI_TLV_PDEV_PARAM_DYNTXCHAIN,
+	.proxy_sta = WMI_TLV_PDEV_PARAM_PROXY_STA,
+	.idle_ps_config = WMI_TLV_PDEV_PARAM_IDLE_PS_CONFIG,
+	.power_gating_sleep = WMI_TLV_PDEV_PARAM_POWER_GATING_SLEEP,
+	.fast_channel_reset = WMI_TLV_PDEV_PARAM_UNSUPPORTED,
+	.burst_dur = WMI_TLV_PDEV_PARAM_BURST_DUR,
+	.burst_enable = WMI_TLV_PDEV_PARAM_BURST_ENABLE,
+};
+
+static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = {
+	.rts_threshold = WMI_TLV_VDEV_PARAM_RTS_THRESHOLD,
+	.fragmentation_threshold = WMI_TLV_VDEV_PARAM_FRAGMENTATION_THRESHOLD,
+	.beacon_interval = WMI_TLV_VDEV_PARAM_BEACON_INTERVAL,
+	.listen_interval = WMI_TLV_VDEV_PARAM_LISTEN_INTERVAL,
+	.multicast_rate = WMI_TLV_VDEV_PARAM_MULTICAST_RATE,
+	.mgmt_tx_rate = WMI_TLV_VDEV_PARAM_MGMT_TX_RATE,
+	.slot_time = WMI_TLV_VDEV_PARAM_SLOT_TIME,
+	.preamble = WMI_TLV_VDEV_PARAM_PREAMBLE,
+	.swba_time = WMI_TLV_VDEV_PARAM_SWBA_TIME,
+	.wmi_vdev_stats_update_period = WMI_TLV_VDEV_STATS_UPDATE_PERIOD,
+	.wmi_vdev_pwrsave_ageout_time = WMI_TLV_VDEV_PWRSAVE_AGEOUT_TIME,
+	.wmi_vdev_host_swba_interval = WMI_TLV_VDEV_HOST_SWBA_INTERVAL,
+	.dtim_period = WMI_TLV_VDEV_PARAM_DTIM_PERIOD,
+	.wmi_vdev_oc_scheduler_air_time_limit =
+				WMI_TLV_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT,
+	.wds = WMI_TLV_VDEV_PARAM_WDS,
+	.atim_window = WMI_TLV_VDEV_PARAM_ATIM_WINDOW,
+	.bmiss_count_max = WMI_TLV_VDEV_PARAM_BMISS_COUNT_MAX,
+	.bmiss_first_bcnt = WMI_TLV_VDEV_PARAM_BMISS_FIRST_BCNT,
+	.bmiss_final_bcnt = WMI_TLV_VDEV_PARAM_BMISS_FINAL_BCNT,
+	.feature_wmm = WMI_TLV_VDEV_PARAM_FEATURE_WMM,
+	.chwidth = WMI_TLV_VDEV_PARAM_CHWIDTH,
+	.chextoffset = WMI_TLV_VDEV_PARAM_CHEXTOFFSET,
+	.disable_htprotection =	WMI_TLV_VDEV_PARAM_DISABLE_HTPROTECTION,
+	.sta_quickkickout = WMI_TLV_VDEV_PARAM_STA_QUICKKICKOUT,
+	.mgmt_rate = WMI_TLV_VDEV_PARAM_MGMT_RATE,
+	.protection_mode = WMI_TLV_VDEV_PARAM_PROTECTION_MODE,
+	.fixed_rate = WMI_TLV_VDEV_PARAM_FIXED_RATE,
+	.sgi = WMI_TLV_VDEV_PARAM_SGI,
+	.ldpc = WMI_TLV_VDEV_PARAM_LDPC,
+	.tx_stbc = WMI_TLV_VDEV_PARAM_TX_STBC,
+	.rx_stbc = WMI_TLV_VDEV_PARAM_RX_STBC,
+	.intra_bss_fwd = WMI_TLV_VDEV_PARAM_INTRA_BSS_FWD,
+	.def_keyid = WMI_TLV_VDEV_PARAM_DEF_KEYID,
+	.nss = WMI_TLV_VDEV_PARAM_NSS,
+	.bcast_data_rate = WMI_TLV_VDEV_PARAM_BCAST_DATA_RATE,
+	.mcast_data_rate = WMI_TLV_VDEV_PARAM_MCAST_DATA_RATE,
+	.mcast_indicate = WMI_TLV_VDEV_PARAM_MCAST_INDICATE,
+	.dhcp_indicate = WMI_TLV_VDEV_PARAM_DHCP_INDICATE,
+	.unknown_dest_indicate = WMI_TLV_VDEV_PARAM_UNKNOWN_DEST_INDICATE,
+	.ap_keepalive_min_idle_inactive_time_secs =
+		WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS,
+	.ap_keepalive_max_idle_inactive_time_secs =
+		WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS,
+	.ap_keepalive_max_unresponsive_time_secs =
+		WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS,
+	.ap_enable_nawds = WMI_TLV_VDEV_PARAM_AP_ENABLE_NAWDS,
+	.mcast2ucast_set = WMI_TLV_VDEV_PARAM_UNSUPPORTED,
+	.enable_rtscts = WMI_TLV_VDEV_PARAM_ENABLE_RTSCTS,
+	.txbf = WMI_TLV_VDEV_PARAM_TXBF,
+	.packet_powersave = WMI_TLV_VDEV_PARAM_PACKET_POWERSAVE,
+	.drop_unencry = WMI_TLV_VDEV_PARAM_DROP_UNENCRY,
+	.tx_encap_type = WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE,
+	.ap_detect_out_of_sync_sleeping_sta_time_secs =
+					WMI_TLV_VDEV_PARAM_UNSUPPORTED,
+};
+
+static const struct wmi_ops wmi_tlv_ops = {
+	.rx = ath10k_wmi_tlv_op_rx,
+	.map_svc = wmi_tlv_svc_map,
+
+	.pull_scan = ath10k_wmi_tlv_op_pull_scan_ev,
+	.pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev,
+	.pull_ch_info = ath10k_wmi_tlv_op_pull_ch_info_ev,
+	.pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev,
+	.pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev,
+	.pull_swba = ath10k_wmi_tlv_op_pull_swba_ev,
+	.pull_phyerr = ath10k_wmi_tlv_op_pull_phyerr_ev,
+	.pull_svc_rdy = ath10k_wmi_tlv_op_pull_svc_rdy_ev,
+	.pull_rdy = ath10k_wmi_tlv_op_pull_rdy_ev,
+	.pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats,
+
+	.gen_pdev_suspend = ath10k_wmi_tlv_op_gen_pdev_suspend,
+	.gen_pdev_resume = ath10k_wmi_tlv_op_gen_pdev_resume,
+	.gen_pdev_set_rd = ath10k_wmi_tlv_op_gen_pdev_set_rd,
+	.gen_pdev_set_param = ath10k_wmi_tlv_op_gen_pdev_set_param,
+	.gen_init = ath10k_wmi_tlv_op_gen_init,
+	.gen_start_scan = ath10k_wmi_tlv_op_gen_start_scan,
+	.gen_stop_scan = ath10k_wmi_tlv_op_gen_stop_scan,
+	.gen_vdev_create = ath10k_wmi_tlv_op_gen_vdev_create,
+	.gen_vdev_delete = ath10k_wmi_tlv_op_gen_vdev_delete,
+	.gen_vdev_start = ath10k_wmi_tlv_op_gen_vdev_start,
+	.gen_vdev_stop = ath10k_wmi_tlv_op_gen_vdev_stop,
+	.gen_vdev_up = ath10k_wmi_tlv_op_gen_vdev_up,
+	.gen_vdev_down = ath10k_wmi_tlv_op_gen_vdev_down,
+	.gen_vdev_set_param = ath10k_wmi_tlv_op_gen_vdev_set_param,
+	.gen_vdev_install_key = ath10k_wmi_tlv_op_gen_vdev_install_key,
+	.gen_peer_create = ath10k_wmi_tlv_op_gen_peer_create,
+	.gen_peer_delete = ath10k_wmi_tlv_op_gen_peer_delete,
+	.gen_peer_flush = ath10k_wmi_tlv_op_gen_peer_flush,
+	.gen_peer_set_param = ath10k_wmi_tlv_op_gen_peer_set_param,
+	.gen_peer_assoc = ath10k_wmi_tlv_op_gen_peer_assoc,
+	.gen_set_psmode = ath10k_wmi_tlv_op_gen_set_psmode,
+	.gen_set_sta_ps = ath10k_wmi_tlv_op_gen_set_sta_ps,
+	.gen_set_ap_ps = ath10k_wmi_tlv_op_gen_set_ap_ps,
+	.gen_scan_chan_list = ath10k_wmi_tlv_op_gen_scan_chan_list,
+	.gen_beacon_dma = ath10k_wmi_tlv_op_gen_beacon_dma,
+	.gen_pdev_set_wmm = ath10k_wmi_tlv_op_gen_pdev_set_wmm,
+	.gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats,
+	.gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
+	/* .gen_mgmt_tx = not implemented; HTT is used */
+	.gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg,
+	.gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
+	.gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,
+};
+
+/************/
+/* TLV init */
+/************/
+
+void ath10k_wmi_tlv_attach(struct ath10k *ar)
+{
+	ar->wmi.cmd = &wmi_tlv_cmd_map;
+	ar->wmi.vdev_param = &wmi_tlv_vdev_param_map;
+	ar->wmi.pdev_param = &wmi_tlv_pdev_param_map;
+	ar->wmi.ops = &wmi_tlv_ops;
+}
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
new file mode 100644
index 0000000..54ffa12
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -0,0 +1,1380 @@
+/*
+ * Copyright (c) 2005-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _WMI_TLV_H
+#define _WMI_TLV_H
+
+#define WMI_TLV_CMD(grp_id) (((grp_id) << 12) | 0x1)
+#define WMI_TLV_EV(grp_id) (((grp_id) << 12) | 0x1)
+#define WMI_TLV_CMD_UNSUPPORTED 0
+#define WMI_TLV_PDEV_PARAM_UNSUPPORTED 0
+#define WMI_TLV_VDEV_PARAM_UNSUPPORTED 0
+
+enum wmi_tlv_grp_id {
+	WMI_TLV_GRP_START = 0x3,
+	WMI_TLV_GRP_SCAN = WMI_TLV_GRP_START,
+	WMI_TLV_GRP_PDEV,
+	WMI_TLV_GRP_VDEV,
+	WMI_TLV_GRP_PEER,
+	WMI_TLV_GRP_MGMT,
+	WMI_TLV_GRP_BA_NEG,
+	WMI_TLV_GRP_STA_PS,
+	WMI_TLV_GRP_DFS,
+	WMI_TLV_GRP_ROAM,
+	WMI_TLV_GRP_OFL_SCAN,
+	WMI_TLV_GRP_P2P,
+	WMI_TLV_GRP_AP_PS,
+	WMI_TLV_GRP_RATECTL,
+	WMI_TLV_GRP_PROFILE,
+	WMI_TLV_GRP_SUSPEND,
+	WMI_TLV_GRP_BCN_FILTER,
+	WMI_TLV_GRP_WOW,
+	WMI_TLV_GRP_RTT,
+	WMI_TLV_GRP_SPECTRAL,
+	WMI_TLV_GRP_STATS,
+	WMI_TLV_GRP_ARP_NS_OFL,
+	WMI_TLV_GRP_NLO_OFL,
+	WMI_TLV_GRP_GTK_OFL,
+	WMI_TLV_GRP_CSA_OFL,
+	WMI_TLV_GRP_CHATTER,
+	WMI_TLV_GRP_TID_ADDBA,
+	WMI_TLV_GRP_MISC,
+	WMI_TLV_GRP_GPIO,
+	WMI_TLV_GRP_FWTEST,
+	WMI_TLV_GRP_TDLS,
+	WMI_TLV_GRP_RESMGR,
+	WMI_TLV_GRP_STA_SMPS,
+	WMI_TLV_GRP_WLAN_HB,
+	WMI_TLV_GRP_RMC,
+	WMI_TLV_GRP_MHF_OFL,
+	WMI_TLV_GRP_LOCATION_SCAN,
+	WMI_TLV_GRP_OEM,
+	WMI_TLV_GRP_NAN,
+	WMI_TLV_GRP_COEX,
+	WMI_TLV_GRP_OBSS_OFL,
+	WMI_TLV_GRP_LPI,
+	WMI_TLV_GRP_EXTSCAN,
+	WMI_TLV_GRP_DHCP_OFL,
+	WMI_TLV_GRP_IPA,
+	WMI_TLV_GRP_MDNS_OFL,
+	WMI_TLV_GRP_SAP_OFL,
+};
+
+enum wmi_tlv_cmd_id {
+	WMI_TLV_INIT_CMDID = 0x1,
+	WMI_TLV_START_SCAN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SCAN),
+	WMI_TLV_STOP_SCAN_CMDID,
+	WMI_TLV_SCAN_CHAN_LIST_CMDID,
+	WMI_TLV_SCAN_SCH_PRIO_TBL_CMDID,
+	WMI_TLV_SCAN_UPDATE_REQUEST_CMDID,
+	WMI_TLV_SCAN_PROB_REQ_OUI_CMDID,
+	WMI_TLV_PDEV_SET_REGDOMAIN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PDEV),
+	WMI_TLV_PDEV_SET_CHANNEL_CMDID,
+	WMI_TLV_PDEV_SET_PARAM_CMDID,
+	WMI_TLV_PDEV_PKTLOG_ENABLE_CMDID,
+	WMI_TLV_PDEV_PKTLOG_DISABLE_CMDID,
+	WMI_TLV_PDEV_SET_WMM_PARAMS_CMDID,
+	WMI_TLV_PDEV_SET_HT_CAP_IE_CMDID,
+	WMI_TLV_PDEV_SET_VHT_CAP_IE_CMDID,
+	WMI_TLV_PDEV_SET_DSCP_TID_MAP_CMDID,
+	WMI_TLV_PDEV_SET_QUIET_MODE_CMDID,
+	WMI_TLV_PDEV_GREEN_AP_PS_ENABLE_CMDID,
+	WMI_TLV_PDEV_GET_TPC_CONFIG_CMDID,
+	WMI_TLV_PDEV_SET_BASE_MACADDR_CMDID,
+	WMI_TLV_PDEV_DUMP_CMDID,
+	WMI_TLV_PDEV_SET_LED_CONFIG_CMDID,
+	WMI_TLV_PDEV_GET_TEMPERATURE_CMDID,
+	WMI_TLV_PDEV_SET_LED_FLASHING_CMDID,
+	WMI_TLV_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_VDEV),
+	WMI_TLV_VDEV_DELETE_CMDID,
+	WMI_TLV_VDEV_START_REQUEST_CMDID,
+	WMI_TLV_VDEV_RESTART_REQUEST_CMDID,
+	WMI_TLV_VDEV_UP_CMDID,
+	WMI_TLV_VDEV_STOP_CMDID,
+	WMI_TLV_VDEV_DOWN_CMDID,
+	WMI_TLV_VDEV_SET_PARAM_CMDID,
+	WMI_TLV_VDEV_INSTALL_KEY_CMDID,
+	WMI_TLV_VDEV_WNM_SLEEPMODE_CMDID,
+	WMI_TLV_VDEV_WMM_ADDTS_CMDID,
+	WMI_TLV_VDEV_WMM_DELTS_CMDID,
+	WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID,
+	WMI_TLV_VDEV_SET_GTX_PARAMS_CMDID,
+	WMI_TLV_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID,
+	WMI_TLV_VDEV_PLMREQ_START_CMDID,
+	WMI_TLV_VDEV_PLMREQ_STOP_CMDID,
+	WMI_TLV_PEER_CREATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PEER),
+	WMI_TLV_PEER_DELETE_CMDID,
+	WMI_TLV_PEER_FLUSH_TIDS_CMDID,
+	WMI_TLV_PEER_SET_PARAM_CMDID,
+	WMI_TLV_PEER_ASSOC_CMDID,
+	WMI_TLV_PEER_ADD_WDS_ENTRY_CMDID,
+	WMI_TLV_PEER_REMOVE_WDS_ENTRY_CMDID,
+	WMI_TLV_PEER_MCAST_GROUP_CMDID,
+	WMI_TLV_PEER_INFO_REQ_CMDID,
+	WMI_TLV_PEER_GET_ESTIMATED_LINKSPEED_CMDID,
+	WMI_TLV_BCN_TX_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MGMT),
+	WMI_TLV_PDEV_SEND_BCN_CMDID,
+	WMI_TLV_BCN_TMPL_CMDID,
+	WMI_TLV_BCN_FILTER_RX_CMDID,
+	WMI_TLV_PRB_REQ_FILTER_RX_CMDID,
+	WMI_TLV_MGMT_TX_CMDID,
+	WMI_TLV_PRB_TMPL_CMDID,
+	WMI_TLV_ADDBA_CLEAR_RESP_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BA_NEG),
+	WMI_TLV_ADDBA_SEND_CMDID,
+	WMI_TLV_ADDBA_STATUS_CMDID,
+	WMI_TLV_DELBA_SEND_CMDID,
+	WMI_TLV_ADDBA_SET_RESP_CMDID,
+	WMI_TLV_SEND_SINGLEAMSDU_CMDID,
+	WMI_TLV_STA_POWERSAVE_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STA_PS),
+	WMI_TLV_STA_POWERSAVE_PARAM_CMDID,
+	WMI_TLV_STA_MIMO_PS_MODE_CMDID,
+	WMI_TLV_PDEV_DFS_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_DFS),
+	WMI_TLV_PDEV_DFS_DISABLE_CMDID,
+	WMI_TLV_DFS_PHYERR_FILTER_ENA_CMDID,
+	WMI_TLV_DFS_PHYERR_FILTER_DIS_CMDID,
+	WMI_TLV_ROAM_SCAN_MODE = WMI_TLV_CMD(WMI_TLV_GRP_ROAM),
+	WMI_TLV_ROAM_SCAN_RSSI_THRESHOLD,
+	WMI_TLV_ROAM_SCAN_PERIOD,
+	WMI_TLV_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+	WMI_TLV_ROAM_AP_PROFILE,
+	WMI_TLV_ROAM_CHAN_LIST,
+	WMI_TLV_ROAM_SCAN_CMD,
+	WMI_TLV_ROAM_SYNCH_COMPLETE,
+	WMI_TLV_ROAM_SET_RIC_REQUEST_CMDID,
+	WMI_TLV_ROAM_INVOKE_CMDID,
+	WMI_TLV_OFL_SCAN_ADD_AP_PROFILE = WMI_TLV_CMD(WMI_TLV_GRP_OFL_SCAN),
+	WMI_TLV_OFL_SCAN_REMOVE_AP_PROFILE,
+	WMI_TLV_OFL_SCAN_PERIOD,
+	WMI_TLV_P2P_DEV_SET_DEVICE_INFO = WMI_TLV_CMD(WMI_TLV_GRP_P2P),
+	WMI_TLV_P2P_DEV_SET_DISCOVERABILITY,
+	WMI_TLV_P2P_GO_SET_BEACON_IE,
+	WMI_TLV_P2P_GO_SET_PROBE_RESP_IE,
+	WMI_TLV_P2P_SET_VENDOR_IE_DATA_CMDID,
+	WMI_TLV_P2P_DISC_OFFLOAD_CONFIG_CMDID,
+	WMI_TLV_P2P_DISC_OFFLOAD_APPIE_CMDID,
+	WMI_TLV_P2P_DISC_OFFLOAD_PATTERN_CMDID,
+	WMI_TLV_P2P_SET_OPPPS_PARAM_CMDID,
+	WMI_TLV_AP_PS_PEER_PARAM_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_AP_PS),
+	WMI_TLV_AP_PS_PEER_UAPSD_COEX_CMDID,
+	WMI_TLV_PEER_RATE_RETRY_SCHED_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RATECTL),
+	WMI_TLV_WLAN_PROFILE_TRIGGER_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PROFILE),
+	WMI_TLV_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+	WMI_TLV_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+	WMI_TLV_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+	WMI_TLV_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+	WMI_TLV_PDEV_SUSPEND_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SUSPEND),
+	WMI_TLV_PDEV_RESUME_CMDID,
+	WMI_TLV_ADD_BCN_FILTER_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BCN_FILTER),
+	WMI_TLV_RMV_BCN_FILTER_CMDID,
+	WMI_TLV_WOW_ADD_WAKE_PATTERN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_WOW),
+	WMI_TLV_WOW_DEL_WAKE_PATTERN_CMDID,
+	WMI_TLV_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
+	WMI_TLV_WOW_ENABLE_CMDID,
+	WMI_TLV_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
+	WMI_TLV_WOW_ACER_IOAC_ADD_KEEPALIVE_CMDID,
+	WMI_TLV_WOW_ACER_IOAC_DEL_KEEPALIVE_CMDID,
+	WMI_TLV_WOW_ACER_IOAC_ADD_WAKE_PATTERN_CMDID,
+	WMI_TLV_WOW_ACER_IOAC_DEL_WAKE_PATTERN_CMDID,
+	WMI_TLV_D0_WOW_ENABLE_DISABLE_CMDID,
+	WMI_TLV_EXTWOW_ENABLE_CMDID,
+	WMI_TLV_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID,
+	WMI_TLV_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID,
+	WMI_TLV_RTT_MEASREQ_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RTT),
+	WMI_TLV_RTT_TSF_CMDID,
+	WMI_TLV_SPECTRAL_SCAN_CONF_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SPECTRAL),
+	WMI_TLV_SPECTRAL_SCAN_ENABLE_CMDID,
+	WMI_TLV_REQUEST_STATS_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STATS),
+	WMI_TLV_MCC_SCHED_TRAFFIC_STATS_CMDID,
+	WMI_TLV_REQUEST_STATS_EXT_CMDID,
+	WMI_TLV_REQUEST_LINK_STATS_CMDID,
+	WMI_TLV_START_LINK_STATS_CMDID,
+	WMI_TLV_CLEAR_LINK_STATS_CMDID,
+	WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_ARP_NS_OFL),
+	WMI_TLV_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID,
+	WMI_TLV_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID,
+	WMI_TLV_NETWORK_LIST_OFFLOAD_CONFIG_CMDID =
+			WMI_TLV_CMD(WMI_TLV_GRP_NLO_OFL),
+	WMI_TLV_APFIND_CMDID,
+	WMI_TLV_GTK_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_GTK_OFL),
+	WMI_TLV_CSA_OFFLOAD_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_CSA_OFL),
+	WMI_TLV_CSA_OFFLOAD_CHANSWITCH_CMDID,
+	WMI_TLV_CHATTER_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_CHATTER),
+	WMI_TLV_CHATTER_ADD_COALESCING_FILTER_CMDID,
+	WMI_TLV_CHATTER_DELETE_COALESCING_FILTER_CMDID,
+	WMI_TLV_CHATTER_COALESCING_QUERY_CMDID,
+	WMI_TLV_PEER_TID_ADDBA_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_TID_ADDBA),
+	WMI_TLV_PEER_TID_DELBA_CMDID,
+	WMI_TLV_STA_DTIM_PS_METHOD_CMDID,
+	WMI_TLV_STA_UAPSD_AUTO_TRIG_CMDID,
+	WMI_TLV_STA_KEEPALIVE_CMDID,
+	WMI_TLV_BA_REQ_SSN_CMDID,
+	WMI_TLV_ECHO_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MISC),
+	WMI_TLV_PDEV_UTF_CMDID,
+	WMI_TLV_DBGLOG_CFG_CMDID,
+	WMI_TLV_PDEV_QVIT_CMDID,
+	WMI_TLV_PDEV_FTM_INTG_CMDID,
+	WMI_TLV_VDEV_SET_KEEPALIVE_CMDID,
+	WMI_TLV_VDEV_GET_KEEPALIVE_CMDID,
+	WMI_TLV_FORCE_FW_HANG_CMDID,
+	WMI_TLV_SET_MCASTBCAST_FILTER_CMDID,
+	WMI_TLV_THERMAL_MGMT_CMDID,
+	WMI_TLV_HOST_AUTO_SHUTDOWN_CFG_CMDID,
+	WMI_TLV_TPC_CHAINMASK_CONFIG_CMDID,
+	WMI_TLV_SET_ANTENNA_DIVERSITY_CMDID,
+	WMI_TLV_GPIO_CONFIG_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_GPIO),
+	WMI_TLV_GPIO_OUTPUT_CMDID,
+	WMI_TLV_TXBF_CMDID,
+	WMI_TLV_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID =
+			WMI_TLV_CMD(WMI_TLV_GRP_FWTEST),
+	WMI_TLV_FWTEST_P2P_SET_NOA_PARAM_CMDID,
+	WMI_TLV_UNIT_TEST_CMDID,
+	WMI_TLV_TDLS_SET_STATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_TDLS),
+	WMI_TLV_TDLS_PEER_UPDATE_CMDID,
+	WMI_TLV_TDLS_SET_OFFCHAN_MODE_CMDID,
+	WMI_TLV_RESMGR_ADAPTIVE_OCS_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RESMGR),
+	WMI_TLV_RESMGR_SET_CHAN_TIME_QUOTA_CMDID,
+	WMI_TLV_RESMGR_SET_CHAN_LATENCY_CMDID,
+	WMI_TLV_STA_SMPS_FORCE_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STA_SMPS),
+	WMI_TLV_STA_SMPS_PARAM_CMDID,
+	WMI_TLV_HB_SET_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_WLAN_HB),
+	WMI_TLV_HB_SET_TCP_PARAMS_CMDID,
+	WMI_TLV_HB_SET_TCP_PKT_FILTER_CMDID,
+	WMI_TLV_HB_SET_UDP_PARAMS_CMDID,
+	WMI_TLV_HB_SET_UDP_PKT_FILTER_CMDID,
+	WMI_TLV_RMC_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RMC),
+	WMI_TLV_RMC_SET_ACTION_PERIOD_CMDID,
+	WMI_TLV_RMC_CONFIG_CMDID,
+	WMI_TLV_MHF_OFFLOAD_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MHF_OFL),
+	WMI_TLV_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID,
+	WMI_TLV_BATCH_SCAN_ENABLE_CMDID =
+			WMI_TLV_CMD(WMI_TLV_GRP_LOCATION_SCAN),
+	WMI_TLV_BATCH_SCAN_DISABLE_CMDID,
+	WMI_TLV_BATCH_SCAN_TRIGGER_RESULT_CMDID,
+	WMI_TLV_OEM_REQ_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_OEM),
+	WMI_TLV_NAN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_NAN),
+	WMI_TLV_MODEM_POWER_STATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_COEX),
+	WMI_TLV_CHAN_AVOID_UPDATE_CMDID,
+	WMI_TLV_OBSS_SCAN_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_OBSS_OFL),
+	WMI_TLV_OBSS_SCAN_DISABLE_CMDID,
+	WMI_TLV_LPI_MGMT_SNOOPING_CONFIG_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_LPI),
+	WMI_TLV_LPI_START_SCAN_CMDID,
+	WMI_TLV_LPI_STOP_SCAN_CMDID,
+	WMI_TLV_EXTSCAN_START_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_EXTSCAN),
+	WMI_TLV_EXTSCAN_STOP_CMDID,
+	WMI_TLV_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID,
+	WMI_TLV_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID,
+	WMI_TLV_EXTSCAN_GET_CACHED_RESULTS_CMDID,
+	WMI_TLV_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID,
+	WMI_TLV_EXTSCAN_SET_CAPABILITIES_CMDID,
+	WMI_TLV_EXTSCAN_GET_CAPABILITIES_CMDID,
+	WMI_TLV_SET_DHCP_SERVER_OFFLOAD_CMDID =
+			WMI_TLV_CMD(WMI_TLV_GRP_DHCP_OFL),
+	WMI_TLV_IPA_OFFLOAD_ENABLE_DISABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_IPA),
+	WMI_TLV_MDNS_OFFLOAD_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MDNS_OFL),
+	WMI_TLV_MDNS_SET_FQDN_CMDID,
+	WMI_TLV_MDNS_SET_RESPONSE_CMDID,
+	WMI_TLV_MDNS_GET_STATS_CMDID,
+	WMI_TLV_SAP_OFL_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SAP_OFL),
+};
+
+enum wmi_tlv_event_id {
+	WMI_TLV_SERVICE_READY_EVENTID = 0x1,
+	WMI_TLV_READY_EVENTID,
+	WMI_TLV_SCAN_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SCAN),
+	WMI_TLV_PDEV_TPC_CONFIG_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PDEV),
+	WMI_TLV_CHAN_INFO_EVENTID,
+	WMI_TLV_PHYERR_EVENTID,
+	WMI_TLV_PDEV_DUMP_EVENTID,
+	WMI_TLV_TX_PAUSE_EVENTID,
+	WMI_TLV_DFS_RADAR_EVENTID,
+	WMI_TLV_PDEV_L1SS_TRACK_EVENTID,
+	WMI_TLV_PDEV_TEMPERATURE_EVENTID,
+	WMI_TLV_VDEV_START_RESP_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_VDEV),
+	WMI_TLV_VDEV_STOPPED_EVENTID,
+	WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID,
+	WMI_TLV_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID,
+	WMI_TLV_PEER_STA_KICKOUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PEER),
+	WMI_TLV_PEER_INFO_EVENTID,
+	WMI_TLV_PEER_TX_FAIL_CNT_THR_EVENTID,
+	WMI_TLV_PEER_ESTIMATED_LINKSPEED_EVENTID,
+	WMI_TLV_PEER_STATE_EVENTID,
+	WMI_TLV_MGMT_RX_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MGMT),
+	WMI_TLV_HOST_SWBA_EVENTID,
+	WMI_TLV_TBTTOFFSET_UPDATE_EVENTID,
+	WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID,
+	WMI_TLV_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID,
+	WMI_TLV_TX_DELBA_COMPLETE_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_BA_NEG),
+	WMI_TLV_TX_ADDBA_COMPLETE_EVENTID,
+	WMI_TLV_BA_RSP_SSN_EVENTID,
+	WMI_TLV_AGGR_STATE_TRIG_EVENTID,
+	WMI_TLV_ROAM_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_ROAM),
+	WMI_TLV_PROFILE_MATCH,
+	WMI_TLV_ROAM_SYNCH_EVENTID,
+	WMI_TLV_P2P_DISC_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_P2P),
+	WMI_TLV_P2P_NOA_EVENTID,
+	WMI_TLV_PDEV_RESUME_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SUSPEND),
+	WMI_TLV_WOW_WAKEUP_HOST_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_WOW),
+	WMI_TLV_D0_WOW_DISABLE_ACK_EVENTID,
+	WMI_TLV_RTT_MEASUREMENT_REPORT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_RTT),
+	WMI_TLV_TSF_MEASUREMENT_REPORT_EVENTID,
+	WMI_TLV_RTT_ERROR_REPORT_EVENTID,
+	WMI_TLV_STATS_EXT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_STATS),
+	WMI_TLV_IFACE_LINK_STATS_EVENTID,
+	WMI_TLV_PEER_LINK_STATS_EVENTID,
+	WMI_TLV_RADIO_LINK_STATS_EVENTID,
+	WMI_TLV_NLO_MATCH_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_NLO_OFL),
+	WMI_TLV_NLO_SCAN_COMPLETE_EVENTID,
+	WMI_TLV_APFIND_EVENTID,
+	WMI_TLV_GTK_OFFLOAD_STATUS_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_GTK_OFL),
+	WMI_TLV_GTK_REKEY_FAIL_EVENTID,
+	WMI_TLV_CSA_HANDLING_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_CSA_OFL),
+	WMI_TLV_CHATTER_PC_QUERY_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_CHATTER),
+	WMI_TLV_ECHO_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MISC),
+	WMI_TLV_PDEV_UTF_EVENTID,
+	WMI_TLV_DEBUG_MESG_EVENTID,
+	WMI_TLV_UPDATE_STATS_EVENTID,
+	WMI_TLV_DEBUG_PRINT_EVENTID,
+	WMI_TLV_DCS_INTERFERENCE_EVENTID,
+	WMI_TLV_PDEV_QVIT_EVENTID,
+	WMI_TLV_WLAN_PROFILE_DATA_EVENTID,
+	WMI_TLV_PDEV_FTM_INTG_EVENTID,
+	WMI_TLV_WLAN_FREQ_AVOID_EVENTID,
+	WMI_TLV_VDEV_GET_KEEPALIVE_EVENTID,
+	WMI_TLV_THERMAL_MGMT_EVENTID,
+	WMI_TLV_DIAG_DATA_CONTAINER_EVENTID,
+	WMI_TLV_HOST_AUTO_SHUTDOWN_EVENTID,
+	WMI_TLV_UPDATE_WHAL_MIB_STATS_EVENTID,
+	WMI_TLV_UPDATE_VDEV_RATE_STATS_EVENTID,
+	WMI_TLV_DIAG_EVENTID,
+	WMI_TLV_GPIO_INPUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_GPIO),
+	WMI_TLV_UPLOADH_EVENTID,
+	WMI_TLV_CAPTUREH_EVENTID,
+	WMI_TLV_RFKILL_STATE_CHANGE_EVENTID,
+	WMI_TLV_TDLS_PEER_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_TDLS),
+	WMI_TLV_BATCH_SCAN_ENABLED_EVENTID =
+			WMI_TLV_EV(WMI_TLV_GRP_LOCATION_SCAN),
+	WMI_TLV_BATCH_SCAN_RESULT_EVENTID,
+	WMI_TLV_OEM_CAPABILITY_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_OEM),
+	WMI_TLV_OEM_MEASUREMENT_REPORT_EVENTID,
+	WMI_TLV_OEM_ERROR_REPORT_EVENTID,
+	WMI_TLV_NAN_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_NAN),
+	WMI_TLV_LPI_RESULT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_LPI),
+	WMI_TLV_LPI_STATUS_EVENTID,
+	WMI_TLV_LPI_HANDOFF_EVENTID,
+	WMI_TLV_EXTSCAN_START_STOP_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_EXTSCAN),
+	WMI_TLV_EXTSCAN_OPERATION_EVENTID,
+	WMI_TLV_EXTSCAN_TABLE_USAGE_EVENTID,
+	WMI_TLV_EXTSCAN_CACHED_RESULTS_EVENTID,
+	WMI_TLV_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID,
+	WMI_TLV_EXTSCAN_HOTLIST_MATCH_EVENTID,
+	WMI_TLV_EXTSCAN_CAPABILITIES_EVENTID,
+	WMI_TLV_MDNS_STATS_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MDNS_OFL),
+	WMI_TLV_SAP_OFL_ADD_STA_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SAP_OFL),
+	WMI_TLV_SAP_OFL_DEL_STA_EVENTID,
+};
+
+enum wmi_tlv_pdev_param {
+	WMI_TLV_PDEV_PARAM_TX_CHAIN_MASK = 0x1,
+	WMI_TLV_PDEV_PARAM_RX_CHAIN_MASK,
+	WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT2G,
+	WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT5G,
+	WMI_TLV_PDEV_PARAM_TXPOWER_SCALE,
+	WMI_TLV_PDEV_PARAM_BEACON_GEN_MODE,
+	WMI_TLV_PDEV_PARAM_BEACON_TX_MODE,
+	WMI_TLV_PDEV_PARAM_RESMGR_OFFCHAN_MODE,
+	WMI_TLV_PDEV_PARAM_PROTECTION_MODE,
+	WMI_TLV_PDEV_PARAM_DYNAMIC_BW,
+	WMI_TLV_PDEV_PARAM_NON_AGG_SW_RETRY_TH,
+	WMI_TLV_PDEV_PARAM_AGG_SW_RETRY_TH,
+	WMI_TLV_PDEV_PARAM_STA_KICKOUT_TH,
+	WMI_TLV_PDEV_PARAM_AC_AGGRSIZE_SCALING,
+	WMI_TLV_PDEV_PARAM_LTR_ENABLE,
+	WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BE,
+	WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BK,
+	WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VI,
+	WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VO,
+	WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT,
+	WMI_TLV_PDEV_PARAM_LTR_SLEEP_OVERRIDE,
+	WMI_TLV_PDEV_PARAM_LTR_RX_OVERRIDE,
+	WMI_TLV_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT,
+	WMI_TLV_PDEV_PARAM_L1SS_ENABLE,
+	WMI_TLV_PDEV_PARAM_DSLEEP_ENABLE,
+	WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_FLUSH,
+	WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_WATERMARK,
+	WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN,
+	WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE,
+	WMI_TLV_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD,
+	WMI_TLV_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD,
+	WMI_TLV_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD,
+	WMI_TLV_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
+	WMI_TLV_PDEV_PARAM_PMF_QOS,
+	WMI_TLV_PDEV_PARAM_ARP_AC_OVERRIDE,
+	WMI_TLV_PDEV_PARAM_DCS,
+	WMI_TLV_PDEV_PARAM_ANI_ENABLE,
+	WMI_TLV_PDEV_PARAM_ANI_POLL_PERIOD,
+	WMI_TLV_PDEV_PARAM_ANI_LISTEN_PERIOD,
+	WMI_TLV_PDEV_PARAM_ANI_OFDM_LEVEL,
+	WMI_TLV_PDEV_PARAM_ANI_CCK_LEVEL,
+	WMI_TLV_PDEV_PARAM_DYNTXCHAIN,
+	WMI_TLV_PDEV_PARAM_PROXY_STA,
+	WMI_TLV_PDEV_PARAM_IDLE_PS_CONFIG,
+	WMI_TLV_PDEV_PARAM_POWER_GATING_SLEEP,
+	WMI_TLV_PDEV_PARAM_RFKILL_ENABLE,
+	WMI_TLV_PDEV_PARAM_BURST_DUR,
+	WMI_TLV_PDEV_PARAM_BURST_ENABLE,
+	WMI_TLV_PDEV_PARAM_HW_RFKILL_CONFIG,
+	WMI_TLV_PDEV_PARAM_LOW_POWER_RF_ENABLE,
+	WMI_TLV_PDEV_PARAM_L1SS_TRACK,
+	WMI_TLV_PDEV_PARAM_HYST_EN,
+	WMI_TLV_PDEV_PARAM_POWER_COLLAPSE_ENABLE,
+	WMI_TLV_PDEV_PARAM_LED_SYS_STATE,
+	WMI_TLV_PDEV_PARAM_LED_ENABLE,
+	WMI_TLV_PDEV_PARAM_AUDIO_OVER_WLAN_LATENCY,
+	WMI_TLV_PDEV_PARAM_AUDIO_OVER_WLAN_ENABLE,
+	WMI_TLV_PDEV_PARAM_WHAL_MIB_STATS_UPDATE_ENABLE,
+	WMI_TLV_PDEV_PARAM_VDEV_RATE_STATS_UPDATE_PERIOD,
+	WMI_TLV_PDEV_PARAM_TXPOWER_REASON_NONE,
+	WMI_TLV_PDEV_PARAM_TXPOWER_REASON_SAR,
+	WMI_TLV_PDEV_PARAM_TXPOWER_REASON_MAX,
+};
+
+enum wmi_tlv_vdev_param {
+	WMI_TLV_VDEV_PARAM_RTS_THRESHOLD = 0x1,
+	WMI_TLV_VDEV_PARAM_FRAGMENTATION_THRESHOLD,
+	WMI_TLV_VDEV_PARAM_BEACON_INTERVAL,
+	WMI_TLV_VDEV_PARAM_LISTEN_INTERVAL,
+	WMI_TLV_VDEV_PARAM_MULTICAST_RATE,
+	WMI_TLV_VDEV_PARAM_MGMT_TX_RATE,
+	WMI_TLV_VDEV_PARAM_SLOT_TIME,
+	WMI_TLV_VDEV_PARAM_PREAMBLE,
+	WMI_TLV_VDEV_PARAM_SWBA_TIME,
+	WMI_TLV_VDEV_STATS_UPDATE_PERIOD,
+	WMI_TLV_VDEV_PWRSAVE_AGEOUT_TIME,
+	WMI_TLV_VDEV_HOST_SWBA_INTERVAL,
+	WMI_TLV_VDEV_PARAM_DTIM_PERIOD,
+	WMI_TLV_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT,
+	WMI_TLV_VDEV_PARAM_WDS,
+	WMI_TLV_VDEV_PARAM_ATIM_WINDOW,
+	WMI_TLV_VDEV_PARAM_BMISS_COUNT_MAX,
+	WMI_TLV_VDEV_PARAM_BMISS_FIRST_BCNT,
+	WMI_TLV_VDEV_PARAM_BMISS_FINAL_BCNT,
+	WMI_TLV_VDEV_PARAM_FEATURE_WMM,
+	WMI_TLV_VDEV_PARAM_CHWIDTH,
+	WMI_TLV_VDEV_PARAM_CHEXTOFFSET,
+	WMI_TLV_VDEV_PARAM_DISABLE_HTPROTECTION,
+	WMI_TLV_VDEV_PARAM_STA_QUICKKICKOUT,
+	WMI_TLV_VDEV_PARAM_MGMT_RATE,
+	WMI_TLV_VDEV_PARAM_PROTECTION_MODE,
+	WMI_TLV_VDEV_PARAM_FIXED_RATE,
+	WMI_TLV_VDEV_PARAM_SGI,
+	WMI_TLV_VDEV_PARAM_LDPC,
+	WMI_TLV_VDEV_PARAM_TX_STBC,
+	WMI_TLV_VDEV_PARAM_RX_STBC,
+	WMI_TLV_VDEV_PARAM_INTRA_BSS_FWD,
+	WMI_TLV_VDEV_PARAM_DEF_KEYID,
+	WMI_TLV_VDEV_PARAM_NSS,
+	WMI_TLV_VDEV_PARAM_BCAST_DATA_RATE,
+	WMI_TLV_VDEV_PARAM_MCAST_DATA_RATE,
+	WMI_TLV_VDEV_PARAM_MCAST_INDICATE,
+	WMI_TLV_VDEV_PARAM_DHCP_INDICATE,
+	WMI_TLV_VDEV_PARAM_UNKNOWN_DEST_INDICATE,
+	WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS,
+	WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS,
+	WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS,
+	WMI_TLV_VDEV_PARAM_AP_ENABLE_NAWDS,
+	WMI_TLV_VDEV_PARAM_ENABLE_RTSCTS,
+	WMI_TLV_VDEV_PARAM_TXBF,
+	WMI_TLV_VDEV_PARAM_PACKET_POWERSAVE,
+	WMI_TLV_VDEV_PARAM_DROP_UNENCRY,
+	WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE,
+	WMI_TLV_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS,
+	WMI_TLV_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE,
+	WMI_TLV_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM,
+	WMI_TLV_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE,
+	WMI_TLV_VDEV_PARAM_EARLY_RX_SLOP_STEP,
+	WMI_TLV_VDEV_PARAM_EARLY_RX_INIT_SLOP,
+	WMI_TLV_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE,
+	WMI_TLV_VDEV_PARAM_TX_PWRLIMIT,
+	WMI_TLV_VDEV_PARAM_SNR_NUM_FOR_CAL,
+	WMI_TLV_VDEV_PARAM_ROAM_FW_OFFLOAD,
+	WMI_TLV_VDEV_PARAM_ENABLE_RMC,
+	WMI_TLV_VDEV_PARAM_IBSS_MAX_BCN_LOST_MS,
+	WMI_TLV_VDEV_PARAM_MAX_RATE,
+	WMI_TLV_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE,
+	WMI_TLV_VDEV_PARAM_SET_IBSS_TX_FAIL_CNT_THR,
+	WMI_TLV_VDEV_PARAM_EBT_RESYNC_TIMEOUT,
+	WMI_TLV_VDEV_PARAM_AGGR_TRIG_EVENT_ENABLE,
+	WMI_TLV_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED,
+	WMI_TLV_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED,
+	WMI_TLV_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED,
+	WMI_TLV_VDEV_PARAM_INACTIVITY_CNT,
+	WMI_TLV_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS,
+	WMI_TLV_VDEV_PARAM_DTIM_POLICY,
+	WMI_TLV_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS,
+	WMI_TLV_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE,
+};
+
+enum wmi_tlv_tag {
+	WMI_TLV_TAG_LAST_RESERVED = 15,
+
+	WMI_TLV_TAG_FIRST_ARRAY_ENUM,
+	WMI_TLV_TAG_ARRAY_UINT32 = WMI_TLV_TAG_FIRST_ARRAY_ENUM,
+	WMI_TLV_TAG_ARRAY_BYTE,
+	WMI_TLV_TAG_ARRAY_STRUCT,
+	WMI_TLV_TAG_ARRAY_FIXED_STRUCT,
+	WMI_TLV_TAG_LAST_ARRAY_ENUM = 31,
+
+	WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT,
+	WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES,
+	WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ,
+	WMI_TLV_TAG_STRUCT_READY_EVENT,
+	WMI_TLV_TAG_STRUCT_SCAN_EVENT,
+	WMI_TLV_TAG_STRUCT_PDEV_TPC_CONFIG_EVENT,
+	WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT,
+	WMI_TLV_TAG_STRUCT_COMB_PHYERR_RX_HDR,
+	WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT,
+	WMI_TLV_TAG_STRUCT_VDEV_STOPPED_EVENT,
+	WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_COMPLETE_EVENT,
+	WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT,
+	WMI_TLV_TAG_STRUCT_MGMT_RX_HDR,
+	WMI_TLV_TAG_STRUCT_TBTT_OFFSET_EVENT,
+	WMI_TLV_TAG_STRUCT_TX_DELBA_COMPLETE_EVENT,
+	WMI_TLV_TAG_STRUCT_TX_ADDBA_COMPLETE_EVENT,
+	WMI_TLV_TAG_STRUCT_ROAM_EVENT,
+	WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO,
+	WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO_SECTION_BITMAP,
+	WMI_TLV_TAG_STRUCT_RTT_EVENT_HEADER,
+	WMI_TLV_TAG_STRUCT_RTT_ERROR_REPORT_EVENT,
+	WMI_TLV_TAG_STRUCT_RTT_MEAS_EVENT,
+	WMI_TLV_TAG_STRUCT_ECHO_EVENT,
+	WMI_TLV_TAG_STRUCT_FTM_INTG_EVENT,
+	WMI_TLV_TAG_STRUCT_VDEV_GET_KEEPALIVE_EVENT,
+	WMI_TLV_TAG_STRUCT_GPIO_INPUT_EVENT,
+	WMI_TLV_TAG_STRUCT_CSA_EVENT,
+	WMI_TLV_TAG_STRUCT_GTK_OFFLOAD_STATUS_EVENT,
+	WMI_TLV_TAG_STRUCT_IGTK_INFO,
+	WMI_TLV_TAG_STRUCT_DCS_INTERFERENCE_EVENT,
+	WMI_TLV_TAG_STRUCT_ATH_DCS_CW_INT,
+	WMI_TLV_TAG_STRUCT_ATH_DCS_WLAN_INT_STAT,
+	WMI_TLV_TAG_STRUCT_WLAN_PROFILE_CTX_T,
+	WMI_TLV_TAG_STRUCT_WLAN_PROFILE_T,
+	WMI_TLV_TAG_STRUCT_PDEV_QVIT_EVENT,
+	WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT,
+	WMI_TLV_TAG_STRUCT_TIM_INFO,
+	WMI_TLV_TAG_STRUCT_P2P_NOA_INFO,
+	WMI_TLV_TAG_STRUCT_STATS_EVENT,
+	WMI_TLV_TAG_STRUCT_AVOID_FREQ_RANGES_EVENT,
+	WMI_TLV_TAG_STRUCT_AVOID_FREQ_RANGE_DESC,
+	WMI_TLV_TAG_STRUCT_GTK_REKEY_FAIL_EVENT,
+	WMI_TLV_TAG_STRUCT_INIT_CMD,
+	WMI_TLV_TAG_STRUCT_RESOURCE_CONFIG,
+	WMI_TLV_TAG_STRUCT_WLAN_HOST_MEMORY_CHUNK,
+	WMI_TLV_TAG_STRUCT_START_SCAN_CMD,
+	WMI_TLV_TAG_STRUCT_STOP_SCAN_CMD,
+	WMI_TLV_TAG_STRUCT_SCAN_CHAN_LIST_CMD,
+	WMI_TLV_TAG_STRUCT_CHANNEL,
+	WMI_TLV_TAG_STRUCT_PDEV_SET_REGDOMAIN_CMD,
+	WMI_TLV_TAG_STRUCT_PDEV_SET_PARAM_CMD,
+	WMI_TLV_TAG_STRUCT_PDEV_SET_WMM_PARAMS_CMD,
+	WMI_TLV_TAG_STRUCT_WMM_PARAMS,
+	WMI_TLV_TAG_STRUCT_PDEV_SET_QUIET_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_CREATE_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_DELETE_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_START_REQUEST_CMD,
+	WMI_TLV_TAG_STRUCT_P2P_NOA_DESCRIPTOR,
+	WMI_TLV_TAG_STRUCT_P2P_GO_SET_BEACON_IE,
+	WMI_TLV_TAG_STRUCT_GTK_OFFLOAD_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_UP_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_STOP_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_DOWN_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_SET_PARAM_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_CMD,
+	WMI_TLV_TAG_STRUCT_PEER_CREATE_CMD,
+	WMI_TLV_TAG_STRUCT_PEER_DELETE_CMD,
+	WMI_TLV_TAG_STRUCT_PEER_FLUSH_TIDS_CMD,
+	WMI_TLV_TAG_STRUCT_PEER_SET_PARAM_CMD,
+	WMI_TLV_TAG_STRUCT_PEER_ASSOC_COMPLETE_CMD,
+	WMI_TLV_TAG_STRUCT_VHT_RATE_SET,
+	WMI_TLV_TAG_STRUCT_BCN_TMPL_CMD,
+	WMI_TLV_TAG_STRUCT_PRB_TMPL_CMD,
+	WMI_TLV_TAG_STRUCT_BCN_PRB_INFO,
+	WMI_TLV_TAG_STRUCT_PEER_TID_ADDBA_CMD,
+	WMI_TLV_TAG_STRUCT_PEER_TID_DELBA_CMD,
+	WMI_TLV_TAG_STRUCT_STA_POWERSAVE_MODE_CMD,
+	WMI_TLV_TAG_STRUCT_STA_POWERSAVE_PARAM_CMD,
+	WMI_TLV_TAG_STRUCT_STA_DTIM_PS_METHOD_CMD,
+	WMI_TLV_TAG_STRUCT_ROAM_SCAN_MODE,
+	WMI_TLV_TAG_STRUCT_ROAM_SCAN_RSSI_THRESHOLD,
+	WMI_TLV_TAG_STRUCT_ROAM_SCAN_PERIOD,
+	WMI_TLV_TAG_STRUCT_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+	WMI_TLV_TAG_STRUCT_PDEV_SUSPEND_CMD,
+	WMI_TLV_TAG_STRUCT_PDEV_RESUME_CMD,
+	WMI_TLV_TAG_STRUCT_ADD_BCN_FILTER_CMD,
+	WMI_TLV_TAG_STRUCT_RMV_BCN_FILTER_CMD,
+	WMI_TLV_TAG_STRUCT_WOW_ENABLE_CMD,
+	WMI_TLV_TAG_STRUCT_WOW_HOSTWAKEUP_FROM_SLEEP_CMD,
+	WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_CMD,
+	WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_PARAM,
+	WMI_TLV_TAG_STRUCT_SET_ARP_NS_OFFLOAD_CMD,
+	WMI_TLV_TAG_STRUCT_ARP_OFFLOAD_TUPLE,
+	WMI_TLV_TAG_STRUCT_NS_OFFLOAD_TUPLE,
+	WMI_TLV_TAG_STRUCT_FTM_INTG_CMD,
+	WMI_TLV_TAG_STRUCT_STA_KEEPALIVE_CMD,
+	WMI_TLV_TAG_STRUCT_STA_KEEPALVE_ARP_RESPONSE,
+	WMI_TLV_TAG_STRUCT_P2P_SET_VENDOR_IE_DATA_CMD,
+	WMI_TLV_TAG_STRUCT_AP_PS_PEER_CMD,
+	WMI_TLV_TAG_STRUCT_PEER_RATE_RETRY_SCHED_CMD,
+	WMI_TLV_TAG_STRUCT_WLAN_PROFILE_TRIGGER_CMD,
+	WMI_TLV_TAG_STRUCT_WLAN_PROFILE_SET_HIST_INTVL_CMD,
+	WMI_TLV_TAG_STRUCT_WLAN_PROFILE_GET_PROF_DATA_CMD,
+	WMI_TLV_TAG_STRUCT_WLAN_PROFILE_ENABLE_PROFILE_ID_CMD,
+	WMI_TLV_TAG_STRUCT_WOW_DEL_PATTERN_CMD,
+	WMI_TLV_TAG_STRUCT_WOW_ADD_DEL_EVT_CMD,
+	WMI_TLV_TAG_STRUCT_RTT_MEASREQ_HEAD,
+	WMI_TLV_TAG_STRUCT_RTT_MEASREQ_BODY,
+	WMI_TLV_TAG_STRUCT_RTT_TSF_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_SPECTRAL_CONFIGURE_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_SPECTRAL_ENABLE_CMD,
+	WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD,
+	WMI_TLV_TAG_STRUCT_NLO_CONFIG_CMD,
+	WMI_TLV_TAG_STRUCT_NLO_CONFIGURED_PARAMETERS,
+	WMI_TLV_TAG_STRUCT_CSA_OFFLOAD_ENABLE_CMD,
+	WMI_TLV_TAG_STRUCT_CSA_OFFLOAD_CHANSWITCH_CMD,
+	WMI_TLV_TAG_STRUCT_CHATTER_SET_MODE_CMD,
+	WMI_TLV_TAG_STRUCT_ECHO_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_SET_KEEPALIVE_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_GET_KEEPALIVE_CMD,
+	WMI_TLV_TAG_STRUCT_FORCE_FW_HANG_CMD,
+	WMI_TLV_TAG_STRUCT_GPIO_CONFIG_CMD,
+	WMI_TLV_TAG_STRUCT_GPIO_OUTPUT_CMD,
+	WMI_TLV_TAG_STRUCT_PEER_ADD_WDS_ENTRY_CMD,
+	WMI_TLV_TAG_STRUCT_PEER_REMOVE_WDS_ENTRY_CMD,
+	WMI_TLV_TAG_STRUCT_BCN_TX_HDR,
+	WMI_TLV_TAG_STRUCT_BCN_SEND_FROM_HOST_CMD,
+	WMI_TLV_TAG_STRUCT_MGMT_TX_HDR,
+	WMI_TLV_TAG_STRUCT_ADDBA_CLEAR_RESP_CMD,
+	WMI_TLV_TAG_STRUCT_ADDBA_SEND_CMD,
+	WMI_TLV_TAG_STRUCT_DELBA_SEND_CMD,
+	WMI_TLV_TAG_STRUCT_ADDBA_SETRESPONSE_CMD,
+	WMI_TLV_TAG_STRUCT_SEND_SINGLEAMSDU_CMD,
+	WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_ENABLE_CMD,
+	WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_DISABLE_CMD,
+	WMI_TLV_TAG_STRUCT_PDEV_SET_HT_IE_CMD,
+	WMI_TLV_TAG_STRUCT_PDEV_SET_VHT_IE_CMD,
+	WMI_TLV_TAG_STRUCT_PDEV_SET_DSCP_TID_MAP_CMD,
+	WMI_TLV_TAG_STRUCT_PDEV_GREEN_AP_PS_ENABLE_CMD,
+	WMI_TLV_TAG_STRUCT_PDEV_GET_TPC_CONFIG_CMD,
+	WMI_TLV_TAG_STRUCT_PDEV_SET_BASE_MACADDR_CMD,
+	WMI_TLV_TAG_STRUCT_PEER_MCAST_GROUP_CMD,
+	WMI_TLV_TAG_STRUCT_ROAM_AP_PROFILE,
+	WMI_TLV_TAG_STRUCT_AP_PROFILE,
+	WMI_TLV_TAG_STRUCT_SCAN_SCH_PRIORITY_TABLE_CMD,
+	WMI_TLV_TAG_STRUCT_PDEV_DFS_ENABLE_CMD,
+	WMI_TLV_TAG_STRUCT_PDEV_DFS_DISABLE_CMD,
+	WMI_TLV_TAG_STRUCT_WOW_ADD_PATTERN_CMD,
+	WMI_TLV_TAG_STRUCT_WOW_BITMAP_PATTERN_T,
+	WMI_TLV_TAG_STRUCT_WOW_IPV4_SYNC_PATTERN_T,
+	WMI_TLV_TAG_STRUCT_WOW_IPV6_SYNC_PATTERN_T,
+	WMI_TLV_TAG_STRUCT_WOW_MAGIC_PATTERN_CMD,
+	WMI_TLV_TAG_STRUCT_SCAN_UPDATE_REQUEST_CMD,
+	WMI_TLV_TAG_STRUCT_CHATTER_PKT_COALESCING_FILTER,
+	WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_ADD_FILTER_CMD,
+	WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_DELETE_FILTER_CMD,
+	WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_QUERY_CMD,
+	WMI_TLV_TAG_STRUCT_TXBF_CMD,
+	WMI_TLV_TAG_STRUCT_DEBUG_LOG_CONFIG_CMD,
+	WMI_TLV_TAG_STRUCT_NLO_EVENT,
+	WMI_TLV_TAG_STRUCT_CHATTER_QUERY_REPLY_EVENT,
+	WMI_TLV_TAG_STRUCT_UPLOAD_H_HDR,
+	WMI_TLV_TAG_STRUCT_CAPTURE_H_EVENT_HDR,
+	WMI_TLV_TAG_STRUCT_VDEV_WNM_SLEEPMODE_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_WMM_ADDTS_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_WMM_DELTS_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_SET_WMM_PARAMS_CMD,
+	WMI_TLV_TAG_STRUCT_TDLS_SET_STATE_CMD,
+	WMI_TLV_TAG_STRUCT_TDLS_PEER_UPDATE_CMD,
+	WMI_TLV_TAG_STRUCT_TDLS_PEER_EVENT,
+	WMI_TLV_TAG_STRUCT_TDLS_PEER_CAPABILITIES,
+	WMI_TLV_TAG_STRUCT_VDEV_MCC_SET_TBTT_MODE_CMD,
+	WMI_TLV_TAG_STRUCT_ROAM_CHAN_LIST,
+	WMI_TLV_TAG_STRUCT_VDEV_MCC_BCN_INTVL_CHANGE_EVENT,
+	WMI_TLV_TAG_STRUCT_RESMGR_ADAPTIVE_OCS_CMD,
+	WMI_TLV_TAG_STRUCT_RESMGR_SET_CHAN_TIME_QUOTA_CMD,
+	WMI_TLV_TAG_STRUCT_RESMGR_SET_CHAN_LATENCY_CMD,
+	WMI_TLV_TAG_STRUCT_BA_REQ_SSN_CMD,
+	WMI_TLV_TAG_STRUCT_BA_RSP_SSN_EVENT,
+	WMI_TLV_TAG_STRUCT_STA_SMPS_FORCE_MODE_CMD,
+	WMI_TLV_TAG_STRUCT_SET_MCASTBCAST_FILTER_CMD,
+	WMI_TLV_TAG_STRUCT_P2P_SET_OPPPS_CMD,
+	WMI_TLV_TAG_STRUCT_P2P_SET_NOA_CMD,
+	WMI_TLV_TAG_STRUCT_BA_REQ_SSN_CMD_SUB_STRUCT_PARAM,
+	WMI_TLV_TAG_STRUCT_BA_REQ_SSN_EVENT_SUB_STRUCT_PARAM,
+	WMI_TLV_TAG_STRUCT_STA_SMPS_PARAM_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_SET_GTX_PARAMS_CMD,
+	WMI_TLV_TAG_STRUCT_MCC_SCHED_TRAFFIC_STATS_CMD,
+	WMI_TLV_TAG_STRUCT_MCC_SCHED_STA_TRAFFIC_STATS,
+	WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT,
+	WMI_TLV_TAG_STRUCT_P2P_NOA_EVENT,
+	WMI_TLV_TAG_STRUCT_HB_SET_ENABLE_CMD,
+	WMI_TLV_TAG_STRUCT_HB_SET_TCP_PARAMS_CMD,
+	WMI_TLV_TAG_STRUCT_HB_SET_TCP_PKT_FILTER_CMD,
+	WMI_TLV_TAG_STRUCT_HB_SET_UDP_PARAMS_CMD,
+	WMI_TLV_TAG_STRUCT_HB_SET_UDP_PKT_FILTER_CMD,
+	WMI_TLV_TAG_STRUCT_HB_IND_EVENT,
+	WMI_TLV_TAG_STRUCT_TX_PAUSE_EVENT,
+	WMI_TLV_TAG_STRUCT_RFKILL_EVENT,
+	WMI_TLV_TAG_STRUCT_DFS_RADAR_EVENT,
+	WMI_TLV_TAG_STRUCT_DFS_PHYERR_FILTER_ENA_CMD,
+	WMI_TLV_TAG_STRUCT_DFS_PHYERR_FILTER_DIS_CMD,
+	WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_SCAN_LIST,
+	WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_NETWORK_INFO,
+	WMI_TLV_TAG_STRUCT_BATCH_SCAN_ENABLE_CMD,
+	WMI_TLV_TAG_STRUCT_BATCH_SCAN_DISABLE_CMD,
+	WMI_TLV_TAG_STRUCT_BATCH_SCAN_TRIGGER_RESULT_CMD,
+	WMI_TLV_TAG_STRUCT_BATCH_SCAN_ENABLED_EVENT,
+	WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_EVENT,
+	WMI_TLV_TAG_STRUCT_VDEV_PLMREQ_START_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_PLMREQ_STOP_CMD,
+	WMI_TLV_TAG_STRUCT_THERMAL_MGMT_CMD,
+	WMI_TLV_TAG_STRUCT_THERMAL_MGMT_EVENT,
+	WMI_TLV_TAG_STRUCT_PEER_INFO_REQ_CMD,
+	WMI_TLV_TAG_STRUCT_PEER_INFO_EVENT,
+	WMI_TLV_TAG_STRUCT_PEER_INFO,
+	WMI_TLV_TAG_STRUCT_PEER_TX_FAIL_CNT_THR_EVENT,
+	WMI_TLV_TAG_STRUCT_RMC_SET_MODE_CMD,
+	WMI_TLV_TAG_STRUCT_RMC_SET_ACTION_PERIOD_CMD,
+	WMI_TLV_TAG_STRUCT_RMC_CONFIG_CMD,
+	WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_SET_MODE_CMD,
+	WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_PLUMB_ROUTING_TABLE_CMD,
+	WMI_TLV_TAG_STRUCT_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD,
+	WMI_TLV_TAG_STRUCT_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD,
+	WMI_TLV_TAG_STRUCT_NAN_CMD_PARAM,
+	WMI_TLV_TAG_STRUCT_NAN_EVENT_HDR,
+	WMI_TLV_TAG_STRUCT_PDEV_L1SS_TRACK_EVENT,
+	WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT,
+	WMI_TLV_TAG_STRUCT_MODEM_POWER_STATE_CMD_PARAM,
+	WMI_TLV_TAG_STRUCT_PEER_GET_ESTIMATED_LINKSPEED_CMD,
+	WMI_TLV_TAG_STRUCT_PEER_ESTIMATED_LINKSPEED_EVENT,
+	WMI_TLV_TAG_STRUCT_AGGR_STATE_TRIG_EVENT,
+	WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_ROUTING_TABLE_ENTRY,
+	WMI_TLV_TAG_STRUCT_ROAM_SCAN_CMD,
+	WMI_TLV_TAG_STRUCT_REQ_STATS_EXT_CMD,
+	WMI_TLV_TAG_STRUCT_STATS_EXT_EVENT,
+	WMI_TLV_TAG_STRUCT_OBSS_SCAN_ENABLE_CMD,
+	WMI_TLV_TAG_STRUCT_OBSS_SCAN_DISABLE_CMD,
+	WMI_TLV_TAG_STRUCT_OFFLOAD_PRB_RSP_TX_STATUS_EVENT,
+	WMI_TLV_TAG_STRUCT_PDEV_SET_LED_CONFIG_CMD,
+	WMI_TLV_TAG_STRUCT_HOST_AUTO_SHUTDOWN_CFG_CMD,
+	WMI_TLV_TAG_STRUCT_HOST_AUTO_SHUTDOWN_EVENT,
+	WMI_TLV_TAG_STRUCT_UPDATE_WHAL_MIB_STATS_EVENT,
+	WMI_TLV_TAG_STRUCT_CHAN_AVOID_UPDATE_CMD_PARAM,
+	WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_PKT_PATTERN_T,
+	WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_TMR_PATTERN_T,
+	WMI_TLV_TAG_STRUCT_WOW_IOAC_ADD_KEEPALIVE_CMD,
+	WMI_TLV_TAG_STRUCT_WOW_IOAC_DEL_KEEPALIVE_CMD,
+	WMI_TLV_TAG_STRUCT_WOW_IOAC_KEEPALIVE_T,
+	WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_ADD_PATTERN_CMD,
+	WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_DEL_PATTERN_CMD,
+	WMI_TLV_TAG_STRUCT_START_LINK_STATS_CMD,
+	WMI_TLV_TAG_STRUCT_CLEAR_LINK_STATS_CMD,
+	WMI_TLV_TAG_STRUCT_REQUEST_LINK_STATS_CMD,
+	WMI_TLV_TAG_STRUCT_IFACE_LINK_STATS_EVENT,
+	WMI_TLV_TAG_STRUCT_RADIO_LINK_STATS_EVENT,
+	WMI_TLV_TAG_STRUCT_PEER_STATS_EVENT,
+	WMI_TLV_TAG_STRUCT_CHANNEL_STATS,
+	WMI_TLV_TAG_STRUCT_RADIO_LINK_STATS,
+	WMI_TLV_TAG_STRUCT_RATE_STATS,
+	WMI_TLV_TAG_STRUCT_PEER_LINK_STATS,
+	WMI_TLV_TAG_STRUCT_WMM_AC_STATS,
+	WMI_TLV_TAG_STRUCT_IFACE_LINK_STATS,
+	WMI_TLV_TAG_STRUCT_LPI_MGMT_SNOOPING_CONFIG_CMD,
+	WMI_TLV_TAG_STRUCT_LPI_START_SCAN_CMD,
+	WMI_TLV_TAG_STRUCT_LPI_STOP_SCAN_CMD,
+	WMI_TLV_TAG_STRUCT_LPI_RESULT_EVENT,
+	WMI_TLV_TAG_STRUCT_PEER_STATE_EVENT,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_BUCKET_CMD,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_BUCKET_CHANNEL_EVENT,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_START_CMD,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_STOP_CMD,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMD,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_BSSID_PARAM_CMD,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMD,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_GET_CACHED_RESULTS_CMD,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMD,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_SET_CAPABILITIES_CMD,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_GET_CAPABILITIES_CMD,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_OPERATION_EVENT,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_START_STOP_EVENT,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_TABLE_USAGE_EVENT,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_DESCRIPTOR_EVENT,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_RSSI_INFO_EVENT,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_CACHED_RESULTS_EVENT,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_RESULTS_EVENT,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_RESULT_BSSID_EVENT,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_HOTLIST_MATCH_EVENT,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_CAPABILITIES_EVENT,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_CACHE_CAPABILITIES_EVENT,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_MONITOR_CAPABILITIES_EVENT,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_HOTLIST_MONITOR_CAPABILITIES_EVENT,
+	WMI_TLV_TAG_STRUCT_D0_WOW_ENABLE_DISABLE_CMD,
+	WMI_TLV_TAG_STRUCT_D0_WOW_DISABLE_ACK_EVENT,
+	WMI_TLV_TAG_STRUCT_UNIT_TEST_CMD,
+	WMI_TLV_TAG_STRUCT_ROAM_OFFLOAD_TLV_PARAM,
+	WMI_TLV_TAG_STRUCT_ROAM_11I_OFFLOAD_TLV_PARAM,
+	WMI_TLV_TAG_STRUCT_ROAM_11R_OFFLOAD_TLV_PARAM,
+	WMI_TLV_TAG_STRUCT_ROAM_ESE_OFFLOAD_TLV_PARAM,
+	WMI_TLV_TAG_STRUCT_ROAM_SYNCH_EVENT,
+	WMI_TLV_TAG_STRUCT_ROAM_SYNCH_COMPLETE,
+	WMI_TLV_TAG_STRUCT_EXTWOW_ENABLE_CMD,
+	WMI_TLV_TAG_STRUCT_EXTWOW_SET_APP_TYPE1_PARAMS_CMD,
+	WMI_TLV_TAG_STRUCT_EXTWOW_SET_APP_TYPE2_PARAMS_CMD,
+	WMI_TLV_TAG_STRUCT_LPI_STATUS_EVENT,
+	WMI_TLV_TAG_STRUCT_LPI_HANDOFF_EVENT,
+	WMI_TLV_TAG_STRUCT_VDEV_RATE_STATS_EVENT,
+	WMI_TLV_TAG_STRUCT_VDEV_RATE_HT_INFO,
+	WMI_TLV_TAG_STRUCT_RIC_REQUEST,
+	WMI_TLV_TAG_STRUCT_PDEV_GET_TEMPERATURE_CMD,
+	WMI_TLV_TAG_STRUCT_PDEV_TEMPERATURE_EVENT,
+	WMI_TLV_TAG_STRUCT_SET_DHCP_SERVER_OFFLOAD_CMD,
+	WMI_TLV_TAG_STRUCT_TPC_CHAINMASK_CONFIG_CMD,
+	WMI_TLV_TAG_STRUCT_RIC_TSPEC,
+	WMI_TLV_TAG_STRUCT_TPC_CHAINMASK_CONFIG,
+	WMI_TLV_TAG_STRUCT_IPA_OFFLOAD_CMD,
+	WMI_TLV_TAG_STRUCT_SCAN_PROB_REQ_OUI_CMD,
+	WMI_TLV_TAG_STRUCT_KEY_MATERIAL,
+	WMI_TLV_TAG_STRUCT_TDLS_SET_OFFCHAN_MODE_CMD,
+	WMI_TLV_TAG_STRUCT_SET_LED_FLASHING_CMD,
+	WMI_TLV_TAG_STRUCT_MDNS_OFFLOAD_CMD,
+	WMI_TLV_TAG_STRUCT_MDNS_SET_FQDN_CMD,
+	WMI_TLV_TAG_STRUCT_MDNS_SET_RESP_CMD,
+	WMI_TLV_TAG_STRUCT_MDNS_GET_STATS_CMD,
+	WMI_TLV_TAG_STRUCT_MDNS_STATS_EVENT,
+	WMI_TLV_TAG_STRUCT_ROAM_INVOKE_CMD,
+	WMI_TLV_TAG_STRUCT_PDEV_RESUME_EVENT,
+	WMI_TLV_TAG_STRUCT_PDEV_SET_ANTENNA_DIVERSITY_CMD,
+	WMI_TLV_TAG_STRUCT_SAP_OFL_ENABLE_CMD,
+	WMI_TLV_TAG_STRUCT_SAP_OFL_ADD_STA_EVENT,
+	WMI_TLV_TAG_STRUCT_SAP_OFL_DEL_STA_EVENT,
+	WMI_TLV_TAG_STRUCT_APFIND_CMD_PARAM,
+	WMI_TLV_TAG_STRUCT_APFIND_EVENT_HDR,
+
+	WMI_TLV_TAG_MAX
+};
+
+enum wmi_tlv_service {
+	WMI_TLV_SERVICE_BEACON_OFFLOAD = 0,
+	WMI_TLV_SERVICE_SCAN_OFFLOAD,
+	WMI_TLV_SERVICE_ROAM_SCAN_OFFLOAD,
+	WMI_TLV_SERVICE_BCN_MISS_OFFLOAD,
+	WMI_TLV_SERVICE_STA_PWRSAVE,
+	WMI_TLV_SERVICE_STA_ADVANCED_PWRSAVE,
+	WMI_TLV_SERVICE_AP_UAPSD,
+	WMI_TLV_SERVICE_AP_DFS,
+	WMI_TLV_SERVICE_11AC,
+	WMI_TLV_SERVICE_BLOCKACK,
+	WMI_TLV_SERVICE_PHYERR,
+	WMI_TLV_SERVICE_BCN_FILTER,
+	WMI_TLV_SERVICE_RTT,
+	WMI_TLV_SERVICE_WOW,
+	WMI_TLV_SERVICE_RATECTRL_CACHE,
+	WMI_TLV_SERVICE_IRAM_TIDS,
+	WMI_TLV_SERVICE_ARPNS_OFFLOAD,
+	WMI_TLV_SERVICE_NLO,
+	WMI_TLV_SERVICE_GTK_OFFLOAD,
+	WMI_TLV_SERVICE_SCAN_SCH,
+	WMI_TLV_SERVICE_CSA_OFFLOAD,
+	WMI_TLV_SERVICE_CHATTER,
+	WMI_TLV_SERVICE_COEX_FREQAVOID,
+	WMI_TLV_SERVICE_PACKET_POWER_SAVE,
+	WMI_TLV_SERVICE_FORCE_FW_HANG,
+	WMI_TLV_SERVICE_GPIO,
+	WMI_TLV_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+	WMI_TLV_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+	WMI_TLV_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+	WMI_TLV_SERVICE_STA_KEEP_ALIVE,
+	WMI_TLV_SERVICE_TX_ENCAP,
+	WMI_TLV_SERVICE_AP_PS_DETECT_OUT_OF_SYNC,
+	WMI_TLV_SERVICE_EARLY_RX,
+	WMI_TLV_SERVICE_STA_SMPS,
+	WMI_TLV_SERVICE_FWTEST,
+	WMI_TLV_SERVICE_STA_WMMAC,
+	WMI_TLV_SERVICE_TDLS,
+	WMI_TLV_SERVICE_BURST,
+	WMI_TLV_SERVICE_MCC_BCN_INTERVAL_CHANGE,
+	WMI_TLV_SERVICE_ADAPTIVE_OCS,
+	WMI_TLV_SERVICE_BA_SSN_SUPPORT,
+	WMI_TLV_SERVICE_FILTER_IPSEC_NATKEEPALIVE,
+	WMI_TLV_SERVICE_WLAN_HB,
+	WMI_TLV_SERVICE_LTE_ANT_SHARE_SUPPORT,
+	WMI_TLV_SERVICE_BATCH_SCAN,
+	WMI_TLV_SERVICE_QPOWER,
+	WMI_TLV_SERVICE_PLMREQ,
+	WMI_TLV_SERVICE_THERMAL_MGMT,
+	WMI_TLV_SERVICE_RMC,
+	WMI_TLV_SERVICE_MHF_OFFLOAD,
+	WMI_TLV_SERVICE_COEX_SAR,
+	WMI_TLV_SERVICE_BCN_TXRATE_OVERRIDE,
+	WMI_TLV_SERVICE_NAN,
+	WMI_TLV_SERVICE_L1SS_STAT,
+	WMI_TLV_SERVICE_ESTIMATE_LINKSPEED,
+	WMI_TLV_SERVICE_OBSS_SCAN,
+	WMI_TLV_SERVICE_TDLS_OFFCHAN,
+	WMI_TLV_SERVICE_TDLS_UAPSD_BUFFER_STA,
+	WMI_TLV_SERVICE_TDLS_UAPSD_SLEEP_STA,
+	WMI_TLV_SERVICE_IBSS_PWRSAVE,
+	WMI_TLV_SERVICE_LPASS,
+	WMI_TLV_SERVICE_EXTSCAN,
+	WMI_TLV_SERVICE_D0WOW,
+	WMI_TLV_SERVICE_HSOFFLOAD,
+	WMI_TLV_SERVICE_ROAM_HO_OFFLOAD,
+	WMI_TLV_SERVICE_RX_FULL_REORDER,
+	WMI_TLV_SERVICE_DHCP_OFFLOAD,
+	WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
+	WMI_TLV_SERVICE_MDNS_OFFLOAD,
+	WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD,
+};
+
+#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \
+	((svc_id) < (len) && \
+	 __le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
+	 BIT((svc_id)%(sizeof(u32))))
+
+#define SVCMAP(x, y, len) \
+	do { \
+		if (WMI_SERVICE_IS_ENABLED((in), (x), (len))) \
+			__set_bit(y, out); \
+	} while (0)
+
+static inline void
+wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len)
+{
+	SVCMAP(WMI_TLV_SERVICE_BEACON_OFFLOAD,
+	       WMI_SERVICE_BEACON_OFFLOAD, len);
+	SVCMAP(WMI_TLV_SERVICE_SCAN_OFFLOAD,
+	       WMI_SERVICE_SCAN_OFFLOAD, len);
+	SVCMAP(WMI_TLV_SERVICE_ROAM_SCAN_OFFLOAD,
+	       WMI_SERVICE_ROAM_SCAN_OFFLOAD, len);
+	SVCMAP(WMI_TLV_SERVICE_BCN_MISS_OFFLOAD,
+	       WMI_SERVICE_BCN_MISS_OFFLOAD, len);
+	SVCMAP(WMI_TLV_SERVICE_STA_PWRSAVE,
+	       WMI_SERVICE_STA_PWRSAVE, len);
+	SVCMAP(WMI_TLV_SERVICE_STA_ADVANCED_PWRSAVE,
+	       WMI_SERVICE_STA_ADVANCED_PWRSAVE, len);
+	SVCMAP(WMI_TLV_SERVICE_AP_UAPSD,
+	       WMI_SERVICE_AP_UAPSD, len);
+	SVCMAP(WMI_TLV_SERVICE_AP_DFS,
+	       WMI_SERVICE_AP_DFS, len);
+	SVCMAP(WMI_TLV_SERVICE_11AC,
+	       WMI_SERVICE_11AC, len);
+	SVCMAP(WMI_TLV_SERVICE_BLOCKACK,
+	       WMI_SERVICE_BLOCKACK, len);
+	SVCMAP(WMI_TLV_SERVICE_PHYERR,
+	       WMI_SERVICE_PHYERR, len);
+	SVCMAP(WMI_TLV_SERVICE_BCN_FILTER,
+	       WMI_SERVICE_BCN_FILTER, len);
+	SVCMAP(WMI_TLV_SERVICE_RTT,
+	       WMI_SERVICE_RTT, len);
+	SVCMAP(WMI_TLV_SERVICE_WOW,
+	       WMI_SERVICE_WOW, len);
+	SVCMAP(WMI_TLV_SERVICE_RATECTRL_CACHE,
+	       WMI_SERVICE_RATECTRL_CACHE, len);
+	SVCMAP(WMI_TLV_SERVICE_IRAM_TIDS,
+	       WMI_SERVICE_IRAM_TIDS, len);
+	SVCMAP(WMI_TLV_SERVICE_ARPNS_OFFLOAD,
+	       WMI_SERVICE_ARPNS_OFFLOAD, len);
+	SVCMAP(WMI_TLV_SERVICE_NLO,
+	       WMI_SERVICE_NLO, len);
+	SVCMAP(WMI_TLV_SERVICE_GTK_OFFLOAD,
+	       WMI_SERVICE_GTK_OFFLOAD, len);
+	SVCMAP(WMI_TLV_SERVICE_SCAN_SCH,
+	       WMI_SERVICE_SCAN_SCH, len);
+	SVCMAP(WMI_TLV_SERVICE_CSA_OFFLOAD,
+	       WMI_SERVICE_CSA_OFFLOAD, len);
+	SVCMAP(WMI_TLV_SERVICE_CHATTER,
+	       WMI_SERVICE_CHATTER, len);
+	SVCMAP(WMI_TLV_SERVICE_COEX_FREQAVOID,
+	       WMI_SERVICE_COEX_FREQAVOID, len);
+	SVCMAP(WMI_TLV_SERVICE_PACKET_POWER_SAVE,
+	       WMI_SERVICE_PACKET_POWER_SAVE, len);
+	SVCMAP(WMI_TLV_SERVICE_FORCE_FW_HANG,
+	       WMI_SERVICE_FORCE_FW_HANG, len);
+	SVCMAP(WMI_TLV_SERVICE_GPIO,
+	       WMI_SERVICE_GPIO, len);
+	SVCMAP(WMI_TLV_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+	       WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, len);
+	SVCMAP(WMI_TLV_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+	       WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len);
+	SVCMAP(WMI_TLV_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+	       WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len);
+	SVCMAP(WMI_TLV_SERVICE_STA_KEEP_ALIVE,
+	       WMI_SERVICE_STA_KEEP_ALIVE, len);
+	SVCMAP(WMI_TLV_SERVICE_TX_ENCAP,
+	       WMI_SERVICE_TX_ENCAP, len);
+	SVCMAP(WMI_TLV_SERVICE_AP_PS_DETECT_OUT_OF_SYNC,
+	       WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, len);
+	SVCMAP(WMI_TLV_SERVICE_EARLY_RX,
+	       WMI_SERVICE_EARLY_RX, len);
+	SVCMAP(WMI_TLV_SERVICE_STA_SMPS,
+	       WMI_SERVICE_STA_SMPS, len);
+	SVCMAP(WMI_TLV_SERVICE_FWTEST,
+	       WMI_SERVICE_FWTEST, len);
+	SVCMAP(WMI_TLV_SERVICE_STA_WMMAC,
+	       WMI_SERVICE_STA_WMMAC, len);
+	SVCMAP(WMI_TLV_SERVICE_TDLS,
+	       WMI_SERVICE_TDLS, len);
+	SVCMAP(WMI_TLV_SERVICE_BURST,
+	       WMI_SERVICE_BURST, len);
+	SVCMAP(WMI_TLV_SERVICE_MCC_BCN_INTERVAL_CHANGE,
+	       WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE, len);
+	SVCMAP(WMI_TLV_SERVICE_ADAPTIVE_OCS,
+	       WMI_SERVICE_ADAPTIVE_OCS, len);
+	SVCMAP(WMI_TLV_SERVICE_BA_SSN_SUPPORT,
+	       WMI_SERVICE_BA_SSN_SUPPORT, len);
+	SVCMAP(WMI_TLV_SERVICE_FILTER_IPSEC_NATKEEPALIVE,
+	       WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE, len);
+	SVCMAP(WMI_TLV_SERVICE_WLAN_HB,
+	       WMI_SERVICE_WLAN_HB, len);
+	SVCMAP(WMI_TLV_SERVICE_LTE_ANT_SHARE_SUPPORT,
+	       WMI_SERVICE_LTE_ANT_SHARE_SUPPORT, len);
+	SVCMAP(WMI_TLV_SERVICE_BATCH_SCAN,
+	       WMI_SERVICE_BATCH_SCAN, len);
+	SVCMAP(WMI_TLV_SERVICE_QPOWER,
+	       WMI_SERVICE_QPOWER, len);
+	SVCMAP(WMI_TLV_SERVICE_PLMREQ,
+	       WMI_SERVICE_PLMREQ, len);
+	SVCMAP(WMI_TLV_SERVICE_THERMAL_MGMT,
+	       WMI_SERVICE_THERMAL_MGMT, len);
+	SVCMAP(WMI_TLV_SERVICE_RMC,
+	       WMI_SERVICE_RMC, len);
+	SVCMAP(WMI_TLV_SERVICE_MHF_OFFLOAD,
+	       WMI_SERVICE_MHF_OFFLOAD, len);
+	SVCMAP(WMI_TLV_SERVICE_COEX_SAR,
+	       WMI_SERVICE_COEX_SAR, len);
+	SVCMAP(WMI_TLV_SERVICE_BCN_TXRATE_OVERRIDE,
+	       WMI_SERVICE_BCN_TXRATE_OVERRIDE, len);
+	SVCMAP(WMI_TLV_SERVICE_NAN,
+	       WMI_SERVICE_NAN, len);
+	SVCMAP(WMI_TLV_SERVICE_L1SS_STAT,
+	       WMI_SERVICE_L1SS_STAT, len);
+	SVCMAP(WMI_TLV_SERVICE_ESTIMATE_LINKSPEED,
+	       WMI_SERVICE_ESTIMATE_LINKSPEED, len);
+	SVCMAP(WMI_TLV_SERVICE_OBSS_SCAN,
+	       WMI_SERVICE_OBSS_SCAN, len);
+	SVCMAP(WMI_TLV_SERVICE_TDLS_OFFCHAN,
+	       WMI_SERVICE_TDLS_OFFCHAN, len);
+	SVCMAP(WMI_TLV_SERVICE_TDLS_UAPSD_BUFFER_STA,
+	       WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, len);
+	SVCMAP(WMI_TLV_SERVICE_TDLS_UAPSD_SLEEP_STA,
+	       WMI_SERVICE_TDLS_UAPSD_SLEEP_STA, len);
+	SVCMAP(WMI_TLV_SERVICE_IBSS_PWRSAVE,
+	       WMI_SERVICE_IBSS_PWRSAVE, len);
+	SVCMAP(WMI_TLV_SERVICE_LPASS,
+	       WMI_SERVICE_LPASS, len);
+	SVCMAP(WMI_TLV_SERVICE_EXTSCAN,
+	       WMI_SERVICE_EXTSCAN, len);
+	SVCMAP(WMI_TLV_SERVICE_D0WOW,
+	       WMI_SERVICE_D0WOW, len);
+	SVCMAP(WMI_TLV_SERVICE_HSOFFLOAD,
+	       WMI_SERVICE_HSOFFLOAD, len);
+	SVCMAP(WMI_TLV_SERVICE_ROAM_HO_OFFLOAD,
+	       WMI_SERVICE_ROAM_HO_OFFLOAD, len);
+	SVCMAP(WMI_TLV_SERVICE_RX_FULL_REORDER,
+	       WMI_SERVICE_RX_FULL_REORDER, len);
+	SVCMAP(WMI_TLV_SERVICE_DHCP_OFFLOAD,
+	       WMI_SERVICE_DHCP_OFFLOAD, len);
+	SVCMAP(WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
+	       WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, len);
+	SVCMAP(WMI_TLV_SERVICE_MDNS_OFFLOAD,
+	       WMI_SERVICE_MDNS_OFFLOAD, len);
+	SVCMAP(WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD,
+	       WMI_SERVICE_SAP_AUTH_OFFLOAD, len);
+}
+
+#undef SVCMAP
+
+struct wmi_tlv {
+	__le16 len;
+	__le16 tag;
+	u8 value[0];
+} __packed;
+
+#define WMI_TLV_MGMT_RX_NUM_RSSI 4
+
+struct wmi_tlv_mgmt_rx_ev {
+	__le32 channel;
+	__le32 snr;
+	__le32 rate;
+	__le32 phy_mode;
+	__le32 buf_len;
+	__le32 status;
+	__le32 rssi[WMI_TLV_MGMT_RX_NUM_RSSI];
+} __packed;
+
+struct wmi_tlv_abi_version {
+	__le32 abi_ver0;
+	__le32 abi_ver1;
+	__le32 abi_ver_ns0;
+	__le32 abi_ver_ns1;
+	__le32 abi_ver_ns2;
+	__le32 abi_ver_ns3;
+} __packed;
+
+enum wmi_tlv_hw_bd_id {
+	WMI_TLV_HW_BD_LEGACY = 0,
+	WMI_TLV_HW_BD_QCA6174 = 1,
+	WMI_TLV_HW_BD_QCA2582 = 2,
+};
+
+struct wmi_tlv_hw_bd_info {
+	u8 rev;
+	u8 project_id;
+	u8 custom_id;
+	u8 reference_design_id;
+} __packed;
+
+struct wmi_tlv_svc_rdy_ev {
+	__le32 fw_build_vers;
+	struct wmi_tlv_abi_version abi;
+	__le32 phy_capability;
+	__le32 max_frag_entry;
+	__le32 num_rf_chains;
+	__le32 ht_cap_info;
+	__le32 vht_cap_info;
+	__le32 vht_supp_mcs;
+	__le32 hw_min_tx_power;
+	__le32 hw_max_tx_power;
+	__le32 sys_cap_info;
+	__le32 min_pkt_size_enable;
+	__le32 max_bcn_ie_size;
+	__le32 num_mem_reqs;
+	__le32 max_num_scan_chans;
+	__le32 hw_bd_id; /* 0 means hw_bd_info is invalid */
+	struct wmi_tlv_hw_bd_info hw_bd_info[5];
+} __packed;
+
+struct wmi_tlv_rdy_ev {
+	struct wmi_tlv_abi_version abi;
+	struct wmi_mac_addr mac_addr;
+	__le32 status;
+} __packed;
+
+struct wmi_tlv_resource_config {
+	__le32 num_vdevs;
+	__le32 num_peers;
+	__le32 num_offload_peers;
+	__le32 num_offload_reorder_bufs;
+	__le32 num_peer_keys;
+	__le32 num_tids;
+	__le32 ast_skid_limit;
+	__le32 tx_chain_mask;
+	__le32 rx_chain_mask;
+	__le32 rx_timeout_pri[4];
+	__le32 rx_decap_mode;
+	__le32 scan_max_pending_reqs;
+	__le32 bmiss_offload_max_vdev;
+	__le32 roam_offload_max_vdev;
+	__le32 roam_offload_max_ap_profiles;
+	__le32 num_mcast_groups;
+	__le32 num_mcast_table_elems;
+	__le32 mcast2ucast_mode;
+	__le32 tx_dbg_log_size;
+	__le32 num_wds_entries;
+	__le32 dma_burst_size;
+	__le32 mac_aggr_delim;
+	__le32 rx_skip_defrag_timeout_dup_detection_check;
+	__le32 vow_config;
+	__le32 gtk_offload_max_vdev;
+	__le32 num_msdu_desc;
+	__le32 max_frag_entries;
+	__le32 num_tdls_vdevs;
+	__le32 num_tdls_conn_table_entries;
+	__le32 beacon_tx_offload_max_vdev;
+	__le32 num_multicast_filter_entries;
+	__le32 num_wow_filters;
+	__le32 num_keep_alive_pattern;
+	__le32 keep_alive_pattern_size;
+	__le32 max_tdls_concurrent_sleep_sta;
+	__le32 max_tdls_concurrent_buffer_sta;
+} __packed;
+
+struct wmi_tlv_init_cmd {
+	struct wmi_tlv_abi_version abi;
+	__le32 num_host_mem_chunks;
+} __packed;
+
+struct wmi_tlv_pdev_set_param_cmd {
+	__le32 pdev_id; /* not used yet */
+	__le32 param_id;
+	__le32 param_value;
+} __packed;
+
+struct wmi_tlv_pdev_set_rd_cmd {
+	__le32 pdev_id; /* not used yet */
+	__le32 regd;
+	__le32 regd_2ghz;
+	__le32 regd_5ghz;
+	__le32 conform_limit_2ghz;
+	__le32 conform_limit_5ghz;
+} __packed;
+
+struct wmi_tlv_scan_chan_list_cmd {
+	__le32 num_scan_chans;
+} __packed;
+
+struct wmi_tlv_start_scan_cmd {
+	struct wmi_start_scan_common common;
+	__le32 burst_duration_ms;
+	__le32 num_channels;
+	__le32 num_bssids;
+	__le32 num_ssids;
+	__le32 ie_len;
+	__le32 num_probes;
+} __packed;
+
+struct wmi_tlv_vdev_start_cmd {
+	__le32 vdev_id;
+	__le32 requestor_id;
+	__le32 bcn_intval;
+	__le32 dtim_period;
+	__le32 flags;
+	struct wmi_ssid ssid;
+	__le32 bcn_tx_rate;
+	__le32 bcn_tx_power;
+	__le32 num_noa_descr;
+	__le32 disable_hw_ack;
+} __packed;
+
+enum {
+	WMI_TLV_PEER_TYPE_DEFAULT = 0, /* generic / non-BSS / self-peer */
+	WMI_TLV_PEER_TYPE_BSS = 1,
+	WMI_TLV_PEER_TYPE_TDLS = 2,
+	WMI_TLV_PEER_TYPE_HOST_MAX = 127,
+	WMI_TLV_PEER_TYPE_ROAMOFFLOAD_TMP = 128,
+};
+
+struct wmi_tlv_peer_create_cmd {
+	__le32 vdev_id;
+	struct wmi_mac_addr peer_addr;
+	__le32 peer_type;
+} __packed;
+
+struct wmi_tlv_peer_assoc_cmd {
+	struct wmi_mac_addr mac_addr;
+	__le32 vdev_id;
+	__le32 new_assoc;
+	__le32 assoc_id;
+	__le32 flags;
+	__le32 caps;
+	__le32 listen_intval;
+	__le32 ht_caps;
+	__le32 max_mpdu;
+	__le32 mpdu_density;
+	__le32 rate_caps;
+	__le32 nss;
+	__le32 vht_caps;
+	__le32 phy_mode;
+	__le32 ht_info[2];
+	__le32 num_legacy_rates;
+	__le32 num_ht_rates;
+} __packed;
+
+struct wmi_tlv_pdev_suspend {
+	__le32 pdev_id; /* not used yet */
+	__le32 opt;
+} __packed;
+
+struct wmi_tlv_pdev_set_wmm_cmd {
+	__le32 pdev_id; /* not used yet */
+	__le32 dg_type; /* no idea.. */
+} __packed;
+
+struct wmi_tlv_phyerr_ev {
+	__le32 num_phyerrs;
+	__le32 tsf_l32;
+	__le32 tsf_u32;
+	__le32 buf_len;
+} __packed;
+
+enum wmi_tlv_dbglog_param {
+	WMI_TLV_DBGLOG_PARAM_LOG_LEVEL = 1,
+	WMI_TLV_DBGLOG_PARAM_VDEV_ENABLE,
+	WMI_TLV_DBGLOG_PARAM_VDEV_DISABLE,
+	WMI_TLV_DBGLOG_PARAM_VDEV_ENABLE_BITMAP,
+	WMI_TLV_DBGLOG_PARAM_VDEV_DISABLE_BITMAP,
+};
+
+enum wmi_tlv_dbglog_log_level {
+	WMI_TLV_DBGLOG_LOG_LEVEL_VERBOSE = 0,
+	WMI_TLV_DBGLOG_LOG_LEVEL_INFO,
+	WMI_TLV_DBGLOG_LOG_LEVEL_INFO_LVL_1,
+	WMI_TLV_DBGLOG_LOG_LEVEL_INFO_LVL_2,
+	WMI_TLV_DBGLOG_LOG_LEVEL_WARN,
+	WMI_TLV_DBGLOG_LOG_LEVEL_ERR,
+};
+
+#define WMI_TLV_DBGLOG_BITMAP_MAX_IDS 512
+#define WMI_TLV_DBGLOG_BITMAP_MAX_WORDS (WMI_TLV_DBGLOG_BITMAP_MAX_IDS / \
+					 sizeof(__le32))
+#define WMI_TLV_DBGLOG_ALL_MODULES 0xffff
+#define WMI_TLV_DBGLOG_LOG_LEVEL_VALUE(module_id, log_level) \
+		(((module_id << 16) & 0xffff0000) | \
+		 ((log_level <<  0) & 0x000000ff))
+
+struct wmi_tlv_dbglog_cmd {
+	__le32 param;
+	__le32 value;
+} __packed;
+
+struct wmi_tlv_resume_cmd {
+	__le32 reserved;
+} __packed;
+
+struct wmi_tlv_req_stats_cmd {
+	__le32 stats_id; /* wmi_stats_id */
+	__le32 vdev_id;
+	struct wmi_mac_addr peer_macaddr;
+} __packed;
+
+struct wmi_tlv_vdev_stats {
+	__le32 vdev_id;
+	__le32 beacon_snr;
+	__le32 data_snr;
+	__le32 num_tx_frames[4]; /* per-AC */
+	__le32 num_rx_frames;
+	__le32 num_tx_frames_retries[4];
+	__le32 num_tx_frames_failures[4];
+	__le32 num_rts_fail;
+	__le32 num_rts_success;
+	__le32 num_rx_err;
+	__le32 num_rx_discard;
+	__le32 num_tx_not_acked;
+	__le32 tx_rate_history[10];
+	__le32 beacon_rssi_history[10];
+} __packed;
+
+struct wmi_tlv_pktlog_enable {
+	__le32 reserved;
+	__le32 filter;
+} __packed;
+
+struct wmi_tlv_pktlog_disable {
+	__le32 reserved;
+} __packed;
+
+void ath10k_wmi_tlv_attach(struct ath10k *ar);
+
+#endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index e2dbe39..0ed29af 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -22,6 +22,7 @@
 #include "htc.h"
 #include "debug.h"
 #include "wmi.h"
+#include "wmi-tlv.h"
 #include "mac.h"
 #include "testmode.h"
 #include "wmi-ops.h"
@@ -2735,13 +2736,14 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb)
 	}
 
 	ath10k_dbg(ar, ATH10K_DBG_WMI,
-		   "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n",
+		   "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x fw_build 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n",
 		   __le32_to_cpu(arg.min_tx_power),
 		   __le32_to_cpu(arg.max_tx_power),
 		   __le32_to_cpu(arg.ht_cap),
 		   __le32_to_cpu(arg.vht_cap),
 		   __le32_to_cpu(arg.sw_ver0),
 		   __le32_to_cpu(arg.sw_ver1),
+		   __le32_to_cpu(arg.fw_build),
 		   __le32_to_cpu(arg.phy_capab),
 		   __le32_to_cpu(arg.num_rf_chains),
 		   __le32_to_cpu(arg.eeprom_rd),
@@ -4754,6 +4756,8 @@ int ath10k_wmi_attach(struct ath10k *ar)
 
 		ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
 		ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
+	} else if (test_bit(ATH10K_FW_FEATURE_WMI_TLV, ar->fw_features)) {
+		ath10k_wmi_tlv_attach(ar);
 	} else {
 		ar->wmi.cmd = &wmi_cmd_map;
 		ar->wmi.vdev_param = &wmi_vdev_param_map;
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index bdb87dd..dc862cb 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -109,6 +109,45 @@ enum wmi_service {
 	WMI_SERVICE_BURST,
 	WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT,
 	WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+	WMI_SERVICE_ROAM_SCAN_OFFLOAD,
+	WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC,
+	WMI_SERVICE_EARLY_RX,
+	WMI_SERVICE_STA_SMPS,
+	WMI_SERVICE_FWTEST,
+	WMI_SERVICE_STA_WMMAC,
+	WMI_SERVICE_TDLS,
+	WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE,
+	WMI_SERVICE_ADAPTIVE_OCS,
+	WMI_SERVICE_BA_SSN_SUPPORT,
+	WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE,
+	WMI_SERVICE_WLAN_HB,
+	WMI_SERVICE_LTE_ANT_SHARE_SUPPORT,
+	WMI_SERVICE_BATCH_SCAN,
+	WMI_SERVICE_QPOWER,
+	WMI_SERVICE_PLMREQ,
+	WMI_SERVICE_THERMAL_MGMT,
+	WMI_SERVICE_RMC,
+	WMI_SERVICE_MHF_OFFLOAD,
+	WMI_SERVICE_COEX_SAR,
+	WMI_SERVICE_BCN_TXRATE_OVERRIDE,
+	WMI_SERVICE_NAN,
+	WMI_SERVICE_L1SS_STAT,
+	WMI_SERVICE_ESTIMATE_LINKSPEED,
+	WMI_SERVICE_OBSS_SCAN,
+	WMI_SERVICE_TDLS_OFFCHAN,
+	WMI_SERVICE_TDLS_UAPSD_BUFFER_STA,
+	WMI_SERVICE_TDLS_UAPSD_SLEEP_STA,
+	WMI_SERVICE_IBSS_PWRSAVE,
+	WMI_SERVICE_LPASS,
+	WMI_SERVICE_EXTSCAN,
+	WMI_SERVICE_D0WOW,
+	WMI_SERVICE_HSOFFLOAD,
+	WMI_SERVICE_ROAM_HO_OFFLOAD,
+	WMI_SERVICE_RX_FULL_REORDER,
+	WMI_SERVICE_DHCP_OFFLOAD,
+	WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
+	WMI_SERVICE_MDNS_OFFLOAD,
+	WMI_SERVICE_SAP_AUTH_OFFLOAD,
 
 	/* keep last */
 	WMI_SERVICE_MAX,
@@ -215,6 +254,42 @@ static inline char *wmi_service_name(int service_id)
 	SVCSTR(WMI_SERVICE_BURST);
 	SVCSTR(WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT);
 	SVCSTR(WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT);
+	SVCSTR(WMI_SERVICE_ROAM_SCAN_OFFLOAD);
+	SVCSTR(WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC);
+	SVCSTR(WMI_SERVICE_EARLY_RX);
+	SVCSTR(WMI_SERVICE_STA_SMPS);
+	SVCSTR(WMI_SERVICE_FWTEST);
+	SVCSTR(WMI_SERVICE_STA_WMMAC);
+	SVCSTR(WMI_SERVICE_TDLS);
+	SVCSTR(WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE);
+	SVCSTR(WMI_SERVICE_ADAPTIVE_OCS);
+	SVCSTR(WMI_SERVICE_BA_SSN_SUPPORT);
+	SVCSTR(WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE);
+	SVCSTR(WMI_SERVICE_WLAN_HB);
+	SVCSTR(WMI_SERVICE_LTE_ANT_SHARE_SUPPORT);
+	SVCSTR(WMI_SERVICE_BATCH_SCAN);
+	SVCSTR(WMI_SERVICE_QPOWER);
+	SVCSTR(WMI_SERVICE_PLMREQ);
+	SVCSTR(WMI_SERVICE_THERMAL_MGMT);
+	SVCSTR(WMI_SERVICE_RMC);
+	SVCSTR(WMI_SERVICE_MHF_OFFLOAD);
+	SVCSTR(WMI_SERVICE_COEX_SAR);
+	SVCSTR(WMI_SERVICE_BCN_TXRATE_OVERRIDE);
+	SVCSTR(WMI_SERVICE_NAN);
+	SVCSTR(WMI_SERVICE_L1SS_STAT);
+	SVCSTR(WMI_SERVICE_ESTIMATE_LINKSPEED);
+	SVCSTR(WMI_SERVICE_OBSS_SCAN);
+	SVCSTR(WMI_SERVICE_TDLS_OFFCHAN);
+	SVCSTR(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA);
+	SVCSTR(WMI_SERVICE_TDLS_UAPSD_SLEEP_STA);
+	SVCSTR(WMI_SERVICE_IBSS_PWRSAVE);
+	SVCSTR(WMI_SERVICE_LPASS);
+	SVCSTR(WMI_SERVICE_EXTSCAN);
+	SVCSTR(WMI_SERVICE_D0WOW);
+	SVCSTR(WMI_SERVICE_HSOFFLOAD);
+	SVCSTR(WMI_SERVICE_ROAM_HO_OFFLOAD);
+	SVCSTR(WMI_SERVICE_RX_FULL_REORDER);
+	SVCSTR(WMI_SERVICE_DHCP_OFFLOAD);
 	default:
 		return NULL;
 	}
@@ -4626,6 +4701,7 @@ struct wmi_svc_rdy_ev_arg {
 	__le32 vht_cap;
 	__le32 sw_ver0;
 	__le32 sw_ver1;
+	__le32 fw_build;
 	__le32 phy_capab;
 	__le32 num_rf_chains;
 	__le32 eeprom_rd;
-- 
1.8.5.3



From michal.kazior at tieto.com  Thu Nov 27 02:09:38 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 27 Nov 2014 11:09:38 +0100
Subject: [PATCH 3/3] ath10k: prevent pci tx/rx starvation
In-Reply-To: <1417082978-1701-1-git-send-email-michal.kazior@tieto.com>
References: <1417082978-1701-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1417082978-1701-3-git-send-email-michal.kazior@tieto.com>

In theory it was possible to starve the system if
a tx/rx handler could implicitly trigger more
tx/rx pci events.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 95e9066..7abb836 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -823,20 +823,24 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
 	struct ath10k *ar = ce_state->ar;
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
-	void *transfer_context;
+	struct sk_buff_head list;
+	struct sk_buff *skb;
 	u32 ce_data;
 	unsigned int nbytes;
 	unsigned int transfer_id;
 
-	while (ath10k_ce_completed_send_next(ce_state, &transfer_context,
-					     &ce_data, &nbytes,
-					     &transfer_id) == 0) {
+	__skb_queue_head_init(&list);
+	while (ath10k_ce_completed_send_next(ce_state, (void **)&skb, &ce_data,
+					     &nbytes, &transfer_id) == 0) {
 		/* no need to call tx completion for NULL pointers */
-		if (transfer_context == NULL)
+		if (skb == NULL)
 			continue;
 
-		cb->tx_completion(ar, transfer_context);
+		__skb_queue_tail(&list, skb);
 	}
+
+	while ((skb = __skb_dequeue(&list)))
+		cb->tx_completion(ar, skb);
 }
 
 /* Called by lower (CE) layer when data is received from the Target. */
@@ -847,12 +851,14 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
 	struct ath10k_pci_pipe *pipe_info =  &ar_pci->pipe_info[ce_state->id];
 	struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
 	struct sk_buff *skb;
+	struct sk_buff_head list;
 	void *transfer_context;
 	u32 ce_data;
 	unsigned int nbytes, max_nbytes;
 	unsigned int transfer_id;
 	unsigned int flags;
 
+	__skb_queue_head_init(&list);
 	while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
 					     &ce_data, &nbytes, &transfer_id,
 					     &flags) == 0) {
@@ -869,7 +875,10 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
 		}
 
 		skb_put(skb, nbytes);
+		__skb_queue_tail(&list, skb);
+	}
 
+	while ((skb = __skb_dequeue(&list))) {
 		ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n",
 			   ce_state->id, skb->len);
 		ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ",
-- 
1.8.5.3



From michal.kazior at tieto.com  Thu Nov 27 02:09:37 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 27 Nov 2014 11:09:37 +0100
Subject: [PATCH 2/3] ath10k: remove callback argument
In-Reply-To: <1417082978-1701-1-git-send-email-michal.kazior@tieto.com>
References: <1417082978-1701-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1417082978-1701-2-git-send-email-michal.kazior@tieto.com>

Pass the eid argument via skbuff control buffer.
This will make it possible to work with queues of
HTC event buffers.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.h |  1 +
 drivers/net/wireless/ath/ath10k/hif.h  |  3 +--
 drivers/net/wireless/ath/ath10k/htc.c  | 10 +++++++---
 drivers/net/wireless/ath/ath10k/pci.c  |  4 ++--
 4 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 4a29498..226b2d2 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -79,6 +79,7 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus)
 
 struct ath10k_skb_cb {
 	dma_addr_t paddr;
+	u8 eid;
 	u8 vdev_id;
 
 	struct {
diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
index 91d24a5..0c92e02 100644
--- a/drivers/net/wireless/ath/ath10k/hif.h
+++ b/drivers/net/wireless/ath/ath10k/hif.h
@@ -32,8 +32,7 @@ struct ath10k_hif_sg_item {
 
 struct ath10k_hif_cb {
 	int (*tx_completion)(struct ath10k *ar,
-			     struct sk_buff *wbuf,
-			     unsigned transfer_id);
+			     struct sk_buff *wbuf);
 	int (*rx_completion)(struct ath10k *ar,
 			     struct sk_buff *wbuf);
 };
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index e245e34..f1946a6 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -160,6 +160,7 @@ int ath10k_htc_send(struct ath10k_htc *htc,
 
 	ath10k_htc_prepare_tx_skb(ep, skb);
 
+	skb_cb->eid = eid;
 	skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);
 	ret = dma_mapping_error(dev, skb_cb->paddr);
 	if (ret)
@@ -197,15 +198,18 @@ err_pull:
 }
 
 static int ath10k_htc_tx_completion_handler(struct ath10k *ar,
-					    struct sk_buff *skb,
-					    unsigned int eid)
+					    struct sk_buff *skb)
 {
 	struct ath10k_htc *htc = &ar->htc;
-	struct ath10k_htc_ep *ep = &htc->endpoint[eid];
+	struct ath10k_skb_cb *skb_cb;
+	struct ath10k_htc_ep *ep;
 
 	if (WARN_ON_ONCE(!skb))
 		return 0;
 
+	skb_cb = ATH10K_SKB_CB(skb);
+	ep = &htc->endpoint[skb_cb->eid];
+
 	ath10k_htc_notify_tx_completion(ep, skb);
 	/* the skb now belongs to the completion handler */
 
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 541f3bc..95e9066 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -835,7 +835,7 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
 		if (transfer_context == NULL)
 			continue;
 
-		cb->tx_completion(ar, transfer_context, transfer_id);
+		cb->tx_completion(ar, transfer_context);
 	}
 }
 
@@ -1263,7 +1263,7 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe)
 		id = MS(__le16_to_cpu(ce_desc[i].flags),
 			CE_DESC_FLAGS_META_DATA);
 
-		ar_pci->msg_callbacks_current.tx_completion(ar, skb, id);
+		ar_pci->msg_callbacks_current.tx_completion(ar, skb);
 	}
 }
 
-- 
1.8.5.3



From michal.kazior at tieto.com  Thu Nov 27 02:09:36 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 27 Nov 2014 11:09:36 +0100
Subject: [PATCH 1/3] ath10k: remove unused callback argument
Message-ID: <1417082978-1701-1-git-send-email-michal.kazior@tieto.com>

This wasn't used since forever and there are no
plans on using it.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/hif.h | 3 +--
 drivers/net/wireless/ath/ath10k/htc.c | 3 +--
 drivers/net/wireless/ath/ath10k/pci.c | 2 +-
 3 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
index 6ac5523..91d24a5 100644
--- a/drivers/net/wireless/ath/ath10k/hif.h
+++ b/drivers/net/wireless/ath/ath10k/hif.h
@@ -35,8 +35,7 @@ struct ath10k_hif_cb {
 			     struct sk_buff *wbuf,
 			     unsigned transfer_id);
 	int (*rx_completion)(struct ath10k *ar,
-			     struct sk_buff *wbuf,
-			     u8 pipe_id);
+			     struct sk_buff *wbuf);
 };
 
 struct ath10k_hif_ops {
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 676bd4e..e245e34 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -317,8 +317,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
 }
 
 static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
-					    struct sk_buff *skb,
-					    u8 pipe_id)
+					    struct sk_buff *skb)
 {
 	int status = 0;
 	struct ath10k_htc *htc = &ar->htc;
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 0816098..541f3bc 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -875,7 +875,7 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
 		ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ",
 				skb->data, skb->len);
 
-		cb->rx_completion(ar, skb, pipe_info->pipe_num);
+		cb->rx_completion(ar, skb);
 	}
 
 	ath10k_pci_rx_post_pipe(pipe_info);
-- 
1.8.5.3



From michal.kazior at tieto.com  Thu Nov 27 02:12:43 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Thu, 27 Nov 2014 11:12:43 +0100
Subject: [PATCH] ath10k: simplify rx ring size/fill calculation
Message-ID: <1417083163-2962-1-git-send-email-michal.kazior@tieto.com>

Don't bother with fancy arithmetic and just
hardcode the final values.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/htt.h    |  3 +
 drivers/net/wireless/ath/ath10k/htt_rx.c | 98 +++-----------------------------
 2 files changed, 12 insertions(+), 89 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 17ca6ac..1bd5545 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -158,6 +158,9 @@ enum htt_rx_ring_flags {
 	HTT_RX_RING_FLAGS_PHY_DATA_RX  = 1 << 15
 };
 
+#define HTT_RX_RING_SIZE_MIN 128
+#define HTT_RX_RING_SIZE_MAX 2048
+
 struct htt_rx_ring_setup_ring {
 	__le32 fw_idx_shadow_reg_paddr;
 	__le32 rx_ring_base_paddr;
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 85910b2..9c782a4 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -25,19 +25,8 @@
 
 #include <linux/log2.h>
 
-/* slightly larger than one large A-MPDU */
-#define HTT_RX_RING_SIZE_MIN 128
-
-/* roughly 20 ms @ 1 Gbps of 1500B MSDUs */
-#define HTT_RX_RING_SIZE_MAX 2048
-
-#define HTT_RX_AVG_FRM_BYTES 1000
-
-/* ms, very conservative */
-#define HTT_RX_HOST_LATENCY_MAX_MS 20
-
-/* ms, conservative */
-#define HTT_RX_HOST_LATENCY_WORST_LIKELY_MS 10
+#define HTT_RX_RING_SIZE 1024
+#define HTT_RX_RING_FILL_LEVEL 1000
 
 /* when under memory pressure rx ring refill may fail and needs a retry */
 #define HTT_RX_RING_REFILL_RETRY_MS 50
@@ -45,68 +34,6 @@
 static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb);
 static void ath10k_htt_txrx_compl_task(unsigned long ptr);
 
-static int ath10k_htt_rx_ring_size(struct ath10k_htt *htt)
-{
-	int size;
-
-	/*
-	 * It is expected that the host CPU will typically be able to
-	 * service the rx indication from one A-MPDU before the rx
-	 * indication from the subsequent A-MPDU happens, roughly 1-2 ms
-	 * later. However, the rx ring should be sized very conservatively,
-	 * to accomodate the worst reasonable delay before the host CPU
-	 * services a rx indication interrupt.
-	 *
-	 * The rx ring need not be kept full of empty buffers. In theory,
-	 * the htt host SW can dynamically track the low-water mark in the
-	 * rx ring, and dynamically adjust the level to which the rx ring
-	 * is filled with empty buffers, to dynamically meet the desired
-	 * low-water mark.
-	 *
-	 * In contrast, it's difficult to resize the rx ring itself, once
-	 * it's in use. Thus, the ring itself should be sized very
-	 * conservatively, while the degree to which the ring is filled
-	 * with empty buffers should be sized moderately conservatively.
-	 */
-
-	/* 1e6 bps/mbps / 1e3 ms per sec = 1000 */
-	size =
-	    htt->max_throughput_mbps +
-	    1000  /
-	    (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_MAX_MS;
-
-	if (size < HTT_RX_RING_SIZE_MIN)
-		size = HTT_RX_RING_SIZE_MIN;
-
-	if (size > HTT_RX_RING_SIZE_MAX)
-		size = HTT_RX_RING_SIZE_MAX;
-
-	size = roundup_pow_of_two(size);
-
-	return size;
-}
-
-static int ath10k_htt_rx_ring_fill_level(struct ath10k_htt *htt)
-{
-	int size;
-
-	/* 1e6 bps/mbps / 1e3 ms per sec = 1000 */
-	size =
-	    htt->max_throughput_mbps *
-	    1000  /
-	    (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_WORST_LIKELY_MS;
-
-	/*
-	 * Make sure the fill level is at least 1 less than the ring size.
-	 * Leaving 1 element empty allows the SW to easily distinguish
-	 * between a full ring vs. an empty ring.
-	 */
-	if (size >= htt->rx_ring.size)
-		size = htt->rx_ring.size - 1;
-
-	return size;
-}
-
 static void ath10k_htt_rx_ring_free(struct ath10k_htt *htt)
 {
 	struct sk_buff *skb;
@@ -462,25 +389,18 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
 
 	htt->rx_confused = false;
 
-	htt->rx_ring.size = ath10k_htt_rx_ring_size(htt);
+	/* XXX: The fill level could be changed during runtime in response to
+	 * the host processing latency. Is this really worth it?
+	 */
+	htt->rx_ring.size = HTT_RX_RING_SIZE;
+	htt->rx_ring.size_mask = htt->rx_ring.size - 1;
+	htt->rx_ring.fill_level = HTT_RX_RING_FILL_LEVEL;
+
 	if (!is_power_of_2(htt->rx_ring.size)) {
 		ath10k_warn(ar, "htt rx ring size is not power of 2\n");
 		return -EINVAL;
 	}
 
-	htt->rx_ring.size_mask = htt->rx_ring.size - 1;
-
-	/*
-	 * Set the initial value for the level to which the rx ring
-	 * should be filled, based on the max throughput and the
-	 * worst likely latency for the host to fill the rx ring
-	 * with new buffers. In theory, this fill level can be
-	 * dynamically adjusted from the initial value set here, to
-	 * reflect the actual host latency rather than a
-	 * conservative assumption about the host latency.
-	 */
-	htt->rx_ring.fill_level = ath10k_htt_rx_ring_fill_level(htt);
-
 	htt->rx_ring.netbufs_ring =
 		kzalloc(htt->rx_ring.size * sizeof(struct sk_buff *),
 			GFP_KERNEL);
-- 
1.8.5.3



From kvalo at qca.qualcomm.com  Thu Nov 27 02:40:26 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Thu, 27 Nov 2014 12:40:26 +0200
Subject: [PATCH V2] ath10k: read calibration data from Device Tree
In-Reply-To: <1415823056-10876-1-git-send-email-toshik@chromium.org> (Toshi
 Kikuchi's message of "Wed, 12 Nov 2014 12:10:56 -0800")
References: <1415823056-10876-1-git-send-email-toshik@chromium.org>
Message-ID: <878uixudt1.fsf@kamboji.qca.qualcomm.com>

Toshi Kikuchi <toshik at chromium.org> writes:

> --- a/drivers/net/wireless/ath/ath10k/core.c
> +++ b/drivers/net/wireless/ath/ath10k/core.c
> @@ -27,6 +28,7 @@
>  #include "debug.h"
>  #include "htt.h"
>  #include "testmode.h"
> +#include "pci.h"
>  
>  unsigned int ath10k_debug_mask;
>  static bool uart_print;
> @@ -244,6 +246,66 @@ static int ath10k_download_cal_file(struct ath10k *ar)
>  	return 0;
>  }
>  
> +static int ath10k_download_cal_dt(struct ath10k *ar)
> +{
> +	struct device_node *node;
> +	int data_len;
> +	void *data;
> +	int ret;
> +
> +	node = pci_device_to_OF_node(ath10k_pci_priv(ar)->pdev);

The problem here is that core.c cannot include pci.h, but we can get the
same node like this:

	node = ar->dev->of_node;

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Thu Nov 27 04:00:14 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Thu, 27 Nov 2014 14:00:14 +0200
Subject: [PATCH v3 0/2] ath10k: device tree support
Message-ID: <20141127115922.28539.9482.stgit@potku.adurom.net>

Hi,

here's ath10k device tree support which Toshi and me have been working
on. Please review.

Device tree maintainers: please review the bindings document
carefully, this is the first time I have written one.

v3:

* add a debug message to ath10k

* write bindings file

* use ar->dev.of_node instead of pci_device_to_OF_node()

v2:

* fixed a bug that returns an uninitialized value if the node is not
  found

---

Kalle Valo (1):
      dt: bindings: add ath10k wireless device

Toshi Kikuchi (1):
      ath10k: read calibration data from Device Tree


 .../bindings/net/wireless/qcom,ath10k.txt          |   30 +++++++++
 drivers/net/wireless/ath/ath10k/core.c             |   70 ++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/core.h             |    3 +
 3 files changed, 102 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt



From kvalo at qca.qualcomm.com  Thu Nov 27 04:00:23 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Thu, 27 Nov 2014 14:00:23 +0200
Subject: [PATCH v3 1/2] dt: bindings: add ath10k wireless device
In-Reply-To: <20141127115922.28539.9482.stgit@potku.adurom.net>
References: <20141127115922.28539.9482.stgit@potku.adurom.net>
Message-ID: <20141127120023.28539.68895.stgit@potku.adurom.net>

Document how calibration data can be provided to ath10k via Device Tree.

Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>
---
 .../bindings/net/wireless/qcom,ath10k.txt          |   30 ++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt

diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
new file mode 100644
index 000000000000..edefc26c6204
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
@@ -0,0 +1,30 @@
+* Qualcomm Atheros ath10k wireless devices
+
+For ath10k devices the calibration data can be provided through Device
+Tree. The node is a child node of the PCI controller.
+
+Required properties:
+-compatible : Should be "qcom,ath10k"
+
+Optional properties:
+- qcom,ath10k-calibration-data : calibration data as an array, the
+				 length can vary between hw versions
+
+
+Example:
+
+pci {
+	pcie at 0 {
+		reg = <0 0 0 0 0>;
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		device_type = "pci";
+
+		ath10k at 0,0 {
+			reg = <0 0 0 0 0>;
+			device_type = "pci";
+			qcom,ath10k-calibration-data = [ 01 02 03 ... ];
+		};
+	};
+};



From kvalo at qca.qualcomm.com  Thu Nov 27 04:00:39 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Thu, 27 Nov 2014 14:00:39 +0200
Subject: [PATCH v3 2/2] ath10k: read calibration data from Device Tree
In-Reply-To: <20141127115922.28539.9482.stgit@potku.adurom.net>
References: <20141127115922.28539.9482.stgit@potku.adurom.net>
Message-ID: <20141127120039.28539.90373.stgit@potku.adurom.net>

From: Toshi Kikuchi <toshik at chromium.org>

This patch adds support for reading calibration data from Device Tree.
It looks for the calibration data in Device Tree if it can't find it
in a file. If there's no node in Device Tree, ath10k will try to find the
calibration data from OTP.

The node for the calibration data should be defined like this:

pci {
        pcie at 0 {
                reg = <0 0 0 0 0>;
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
                device_type = "pci";

                ath10k at 0,0 {
                        reg = <0 0 0 0 0>;
                        device_type = "pci";
                        qcom,ath10k-calibration-data = [ 01 02 03 ... ];
                };
        };
};

Signed-off-by: Toshi Kikuchi <toshik at chromium.org>
Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.c |   70 ++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/core.h |    3 +
 2 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 7762061a1944..6165f2735b35 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -17,6 +17,7 @@
 
 #include <linux/module.h>
 #include <linux/firmware.h>
+#include <linux/of.h>
 
 #include "core.h"
 #include "mac.h"
@@ -249,6 +250,63 @@ static int ath10k_download_cal_file(struct ath10k *ar)
 	return 0;
 }
 
+static int ath10k_download_cal_dt(struct ath10k *ar)
+{
+	struct device_node *node;
+	int data_len;
+	void *data;
+	int ret;
+
+	node = ar->dev->of_node;
+	if (!node)
+		/* Device Tree is optional, don't print any warnings if
+		 * there's no node for ath10k.
+		 */
+		return -ENOENT;
+
+	if (!of_get_property(node, "qcom,ath10k-calibration-data",
+			     &data_len)) {
+		/* The calibration data node is optional */
+		return -ENOENT;
+	}
+
+	if (data_len != QCA988X_CAL_DATA_LEN) {
+		ath10k_warn(ar, "invalid calibration data length in DT: %d\n",
+			    data_len);
+		ret = -EMSGSIZE;
+		goto out;
+	}
+
+	data = kmalloc(data_len, GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = of_property_read_u8_array(node, "qcom,ath10k-calibration-data",
+					data, data_len);
+	if (ret) {
+		ath10k_warn(ar, "failed to read calibration data from DT: %d\n",
+			    ret);
+		goto out_free;
+	}
+
+	ret = ath10k_download_board_data(ar, data, data_len);
+	if (ret) {
+		ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n",
+			    ret);
+		goto out_free;
+	}
+
+	ret = 0;
+
+out_free:
+	kfree(data);
+
+out:
+	return ret;
+}
+
 static int ath10k_download_and_run_otp(struct ath10k *ar)
 {
 	u32 result, address = ar->hw_params.patch_load_addr;
@@ -662,7 +720,17 @@ static int ath10k_download_cal_data(struct ath10k *ar)
 	}
 
 	ath10k_dbg(ar, ATH10K_DBG_BOOT,
-		   "boot did not find a calibration file, try OTP next: %d\n",
+		   "boot did not find a calibration file, try DT next: %d\n",
+		   ret);
+
+	ret = ath10k_download_cal_dt(ar);
+	if (ret == 0) {
+		ar->cal_mode = ATH10K_CAL_MODE_DT;
+		goto done;
+	}
+
+	ath10k_dbg(ar, ATH10K_DBG_BOOT,
+		   "boot did not find DT entry, try OTP next: %d\n",
 		   ret);
 
 	ret = ath10k_download_and_run_otp(ar);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 4a294987736c..2dd1bb05a3fc 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -400,6 +400,7 @@ enum ath10k_dev_flags {
 enum ath10k_cal_mode {
 	ATH10K_CAL_MODE_FILE,
 	ATH10K_CAL_MODE_OTP,
+	ATH10K_CAL_MODE_DT,
 };
 
 static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
@@ -409,6 +410,8 @@ static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
 		return "file";
 	case ATH10K_CAL_MODE_OTP:
 		return "otp";
+	case ATH10K_CAL_MODE_DT:
+		return "dt";
 	}
 
 	return "unknown";



From kvalo at qca.qualcomm.com  Thu Nov 27 04:04:53 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Thu, 27 Nov 2014 14:04:53 +0200
Subject: [PATCH v3 0/2] ath10k: device tree support
In-Reply-To: <20141127115922.28539.9482.stgit@potku.adurom.net> (Kalle Valo's
 message of "Thu, 27 Nov 2014 14:00:14 +0200")
References: <20141127115922.28539.9482.stgit@potku.adurom.net>
Message-ID: <87y4qwu9wa.fsf@kamboji.qca.qualcomm.com>

Kalle Valo <kvalo at qca.qualcomm.com> writes:

> here's ath10k device tree support which Toshi and me have been working
> on. Please review.
>
> Device tree maintainers: please review the bindings document
> carefully, this is the first time I have written one.

Argh, I again used the old devicetree mailing list address. Please
ignore this one, I'll resend using the correct address.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Thu Nov 27 04:08:47 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Thu, 27 Nov 2014 14:08:47 +0200
Subject: [PATCH v4 0/2] ath10k: device tree support
Message-ID: <20141127120727.17546.61202.stgit@potku.adurom.net>

Hi,

here's providing ath10k calibration data via device tree support which
Toshi and me have been working on. Please review.

Device tree maintainers: please review the bindings document
carefully, this is the first time I have written one.

v4:

* use correct devicetree mailing list address

v3:

* add a debug message to ath10k

* write bindings file

* use ar->dev.of_node instead of pci_device_to_OF_node()

v2:

* fixed a bug that returns an uninitialized value if the node is not
  found

---

Kalle Valo (1):
      dt: bindings: add ath10k wireless device

Toshi Kikuchi (1):
      ath10k: read calibration data from Device Tree


 .../bindings/net/wireless/qcom,ath10k.txt          |   30 +++++++++
 drivers/net/wireless/ath/ath10k/core.c             |   70 ++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/core.h             |    3 +
 3 files changed, 102 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt



From kvalo at qca.qualcomm.com  Thu Nov 27 04:08:56 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Thu, 27 Nov 2014 14:08:56 +0200
Subject: [PATCH v4 1/2] dt: bindings: add ath10k wireless device
In-Reply-To: <20141127120727.17546.61202.stgit@potku.adurom.net>
References: <20141127120727.17546.61202.stgit@potku.adurom.net>
Message-ID: <20141127120856.17546.32014.stgit@potku.adurom.net>

Document how calibration data can be provided to ath10k via Device Tree.

Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>
---
 .../bindings/net/wireless/qcom,ath10k.txt          |   30 ++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt

diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
new file mode 100644
index 000000000000..edefc26c6204
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
@@ -0,0 +1,30 @@
+* Qualcomm Atheros ath10k wireless devices
+
+For ath10k devices the calibration data can be provided through Device
+Tree. The node is a child node of the PCI controller.
+
+Required properties:
+-compatible : Should be "qcom,ath10k"
+
+Optional properties:
+- qcom,ath10k-calibration-data : calibration data as an array, the
+				 length can vary between hw versions
+
+
+Example:
+
+pci {
+	pcie at 0 {
+		reg = <0 0 0 0 0>;
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		device_type = "pci";
+
+		ath10k at 0,0 {
+			reg = <0 0 0 0 0>;
+			device_type = "pci";
+			qcom,ath10k-calibration-data = [ 01 02 03 ... ];
+		};
+	};
+};



From kvalo at qca.qualcomm.com  Thu Nov 27 04:09:18 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Thu, 27 Nov 2014 14:09:18 +0200
Subject: [PATCH v4 2/2] ath10k: read calibration data from Device Tree
In-Reply-To: <20141127120727.17546.61202.stgit@potku.adurom.net>
References: <20141127120727.17546.61202.stgit@potku.adurom.net>
Message-ID: <20141127120917.17546.44254.stgit@potku.adurom.net>

From: Toshi Kikuchi <toshik at chromium.org>

This patch adds support for reading calibration data from Device Tree.
It looks for the calibration data in Device Tree if it can't find it
in a file. If there's no node in Device Tree, ath10k will try to find the
calibration data from OTP.

The node for the calibration data should be defined like this:

pci {
        pcie at 0 {
                reg = <0 0 0 0 0>;
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
                device_type = "pci";

                ath10k at 0,0 {
                        reg = <0 0 0 0 0>;
                        device_type = "pci";
                        qcom,ath10k-calibration-data = [ 01 02 03 ... ];
                };
        };
};

Signed-off-by: Toshi Kikuchi <toshik at chromium.org>
Signed-off-by: Kalle Valo <kvalo at qca.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.c |   70 ++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/core.h |    3 +
 2 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 7762061a1944..6165f2735b35 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -17,6 +17,7 @@
 
 #include <linux/module.h>
 #include <linux/firmware.h>
+#include <linux/of.h>
 
 #include "core.h"
 #include "mac.h"
@@ -249,6 +250,63 @@ static int ath10k_download_cal_file(struct ath10k *ar)
 	return 0;
 }
 
+static int ath10k_download_cal_dt(struct ath10k *ar)
+{
+	struct device_node *node;
+	int data_len;
+	void *data;
+	int ret;
+
+	node = ar->dev->of_node;
+	if (!node)
+		/* Device Tree is optional, don't print any warnings if
+		 * there's no node for ath10k.
+		 */
+		return -ENOENT;
+
+	if (!of_get_property(node, "qcom,ath10k-calibration-data",
+			     &data_len)) {
+		/* The calibration data node is optional */
+		return -ENOENT;
+	}
+
+	if (data_len != QCA988X_CAL_DATA_LEN) {
+		ath10k_warn(ar, "invalid calibration data length in DT: %d\n",
+			    data_len);
+		ret = -EMSGSIZE;
+		goto out;
+	}
+
+	data = kmalloc(data_len, GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = of_property_read_u8_array(node, "qcom,ath10k-calibration-data",
+					data, data_len);
+	if (ret) {
+		ath10k_warn(ar, "failed to read calibration data from DT: %d\n",
+			    ret);
+		goto out_free;
+	}
+
+	ret = ath10k_download_board_data(ar, data, data_len);
+	if (ret) {
+		ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n",
+			    ret);
+		goto out_free;
+	}
+
+	ret = 0;
+
+out_free:
+	kfree(data);
+
+out:
+	return ret;
+}
+
 static int ath10k_download_and_run_otp(struct ath10k *ar)
 {
 	u32 result, address = ar->hw_params.patch_load_addr;
@@ -662,7 +720,17 @@ static int ath10k_download_cal_data(struct ath10k *ar)
 	}
 
 	ath10k_dbg(ar, ATH10K_DBG_BOOT,
-		   "boot did not find a calibration file, try OTP next: %d\n",
+		   "boot did not find a calibration file, try DT next: %d\n",
+		   ret);
+
+	ret = ath10k_download_cal_dt(ar);
+	if (ret == 0) {
+		ar->cal_mode = ATH10K_CAL_MODE_DT;
+		goto done;
+	}
+
+	ath10k_dbg(ar, ATH10K_DBG_BOOT,
+		   "boot did not find DT entry, try OTP next: %d\n",
 		   ret);
 
 	ret = ath10k_download_and_run_otp(ar);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 4a294987736c..2dd1bb05a3fc 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -400,6 +400,7 @@ enum ath10k_dev_flags {
 enum ath10k_cal_mode {
 	ATH10K_CAL_MODE_FILE,
 	ATH10K_CAL_MODE_OTP,
+	ATH10K_CAL_MODE_DT,
 };
 
 static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
@@ -409,6 +410,8 @@ static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
 		return "file";
 	case ATH10K_CAL_MODE_OTP:
 		return "otp";
+	case ATH10K_CAL_MODE_DT:
+		return "dt";
 	}
 
 	return "unknown";



From arnd at arndb.de  Thu Nov 27 04:28:45 2014
From: arnd at arndb.de (Arnd Bergmann)
Date: Thu, 27 Nov 2014 13:28:45 +0100
Subject: [PATCH v4 1/2] dt: bindings: add ath10k wireless device
In-Reply-To: <20141127120856.17546.32014.stgit@potku.adurom.net>
References: <20141127120727.17546.61202.stgit@potku.adurom.net>
 <20141127120856.17546.32014.stgit@potku.adurom.net>
Message-ID: <3202372.2AaH3c4qv1@wuerfel>

On Thursday 27 November 2014 14:08:56 Kalle Valo wrote:
> diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
> new file mode 100644
> index 000000000000..edefc26c6204
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
> @@ -0,0 +1,30 @@
> +* Qualcomm Atheros ath10k wireless devices
> +
> +For ath10k devices the calibration data can be provided through Device
> +Tree. The node is a child node of the PCI controller.
> +
> +Required properties:
> +-compatible : Should be "qcom,ath10k"
> +
> +Optional properties:
> +- qcom,ath10k-calibration-data : calibration data as an array, the
> +                                length can vary between hw versions
> +

Does the device always have a valid mac address in hardware? If not,
how about listing that as well using the mac-address property?

	Arnd


From kvalo at qca.qualcomm.com  Thu Nov 27 04:51:28 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Thu, 27 Nov 2014 14:51:28 +0200
Subject: [PATCH 1/3] ath10k: remove unused callback argument
In-Reply-To: <1417082978-1701-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Thu, 27 Nov 2014 11:09:36 +0100")
References: <1417082978-1701-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87tx1ku7qn.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> This wasn't used since forever and there are no
> plans on using it.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

I modified the title to get it more unique:

ath10k: remove unused callback argument from struct ath10k_hif_cb::rx_completion

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Thu Nov 27 04:59:32 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Thu, 27 Nov 2014 14:59:32 +0200
Subject: [PATCH v2 0/7] ath10k: add support for new wmi-tlv backend
In-Reply-To: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Thu, 27 Nov 2014 10:11:14 +0100")
References: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87ppc8u7d7.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> First 2 patches are simple fixes. Patch 3 isn't
> strictly related to wmi-tlv but I decided to
> include it anyway. Other patches gradually
> implement wmi-tlv.
>
> There's a bunch of false-positive checkpatch
> warnings regarding `CHECK: No space is necessary
> after a cast`.
>
> v2:
>  * a lot of fixes (see notes on patch #7)
>
> Michal Kazior (7):
>   ath10k: fix wmi svc bitmap dbg print
>   ath10k: add sanity checks for service bmap parsing
>   ath10k: make wmi service bitmap non-debug

These look ok and are now in ath-next-text.

>   ath10k: implement intermediate event args
>   ath10k: introduce wmi ops
>   ath10k: make some wmi functions public
>   ath10k: implement wmi-tlv backend

I still need to look at these more carefully.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Thu Nov 27 23:02:50 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 28 Nov 2014 09:02:50 +0200
Subject: [PATCH 1/3] ath10k: embed supported chip ids in hw_params
In-Reply-To: <CA+BoTQ=dt9fMHpCYk6ofX5W4=Ynn7C4t+vCoHHuZM1oF3Ngdtw@mail.gmail.com>
 (Michal Kazior's message of "Thu, 27 Nov 2014 08:45:38 +0100")
References: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
 <87vbm2whoz.fsf@kamboji.qca.qualcomm.com>
 <CA+BoTQ=56six2CEQ6Rzr7yMEM7UVNQ3RX9UpdgmxMEoG0+kDAA@mail.gmail.com>
 <87ppc9umm6.fsf@kamboji.qca.qualcomm.com>
 <CA+BoTQ=dt9fMHpCYk6ofX5W4=Ynn7C4t+vCoHHuZM1oF3Ngdtw@mail.gmail.com>
Message-ID: <87h9xju7s5.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> On 27 November 2014 at 08:30, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
>> Michal Kazior <michal.kazior at tieto.com> writes:
>>
>>> 2. Have a dedicatd pci-specific structure:
>>>
>>>  struct ath10k_pci_supported_chip {
>>>    u16 dev_id;
>>>    u32 chip_id;
>>>  };
>>>
>>>  struct ath10k_pci_supported_chip ath10k_pci_supported_chips[] = {
>>>    { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV },
>>>    // ...
>>>  };
>>>
>>> Probably the simplest and has least impact.
>>
>> Another idea which is a variation of this:
>>
>> In ath10k_core_register() we iterate through ath10k_hw_params_list and
>> make sure that the chip id is supported and if not, bail out. If the
>> chip id is found from the array continue the registration process like
>> in this patch. Basically this would be a whitelist check.
>
> This won't work because chip ids can overlap between different
> hardware designs and you'd get false positives.

Ah, let's forget that then.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Thu Nov 27 23:10:12 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 28 Nov 2014 09:10:12 +0200
Subject: [PATCH 1/3] ath10k: embed supported chip ids in hw_params
In-Reply-To: <CA+BoTQ=56six2CEQ6Rzr7yMEM7UVNQ3RX9UpdgmxMEoG0+kDAA@mail.gmail.com>
 (Michal Kazior's message of "Wed, 26 Nov 2014 08:54:30 +0100")
References: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
 <87vbm2whoz.fsf@kamboji.qca.qualcomm.com>
 <CA+BoTQ=56six2CEQ6Rzr7yMEM7UVNQ3RX9UpdgmxMEoG0+kDAA@mail.gmail.com>
Message-ID: <87d287u7fv.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> Hmm.. I have a couple of ideas:

[...]

> 2. Have a dedicatd pci-specific structure:
>
>  struct ath10k_pci_supported_chip {
>    u16 dev_id;
>    u32 chip_id;
>  };
>
>  struct ath10k_pci_supported_chip ath10k_pci_supported_chips[] = {
>    { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV },
>    // ...
>  };
>
> Probably the simplest and has least impact.

Yeah, this seems to be the best. Can you send v2?

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Fri Nov 28 01:54:39 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 28 Nov 2014 11:54:39 +0200
Subject: [PATCH v4 1/2] dt: bindings: add ath10k wireless device
In-Reply-To: <3202372.2AaH3c4qv1@wuerfel> (Arnd Bergmann's message of "Thu, 27
 Nov 2014 13:28:45 +0100")
References: <20141127120727.17546.61202.stgit@potku.adurom.net>
 <20141127120856.17546.32014.stgit@potku.adurom.net>
 <3202372.2AaH3c4qv1@wuerfel>
Message-ID: <87fvd3sl9c.fsf@kamboji.qca.qualcomm.com>

Arnd Bergmann <arnd at arndb.de> writes:

> On Thursday 27 November 2014 14:08:56 Kalle Valo wrote:
>> diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
>> new file mode 100644
>> index 000000000000..edefc26c6204
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
>> @@ -0,0 +1,30 @@
>> +* Qualcomm Atheros ath10k wireless devices
>> +
>> +For ath10k devices the calibration data can be provided through Device
>> +Tree. The node is a child node of the PCI controller.
>> +
>> +Required properties:
>> +-compatible : Should be "qcom,ath10k"
>> +
>> +Optional properties:
>> +- qcom,ath10k-calibration-data : calibration data as an array, the
>> +                                length can vary between hw versions
>> +
>
> Does the device always have a valid mac address in hardware? If not,
> how about listing that as well using the mac-address property?

Right now ath10k does not support that, but in the future we might want
to add mac address as well. We need to do some testing with the firmware
to make sure that we can safely change the "main" address from ath10k.

And because of Virtual AP (mBSSID) feature we actually would need to
provide multiple addresses, not just one. Maybe with addr_mask like
struct wiphy has?

 * @perm_addr: permanent MAC address of this device
 * @addr_mask: If the device supports multiple MAC addresses by masking,
 *	set this to a mask with variable bits set to 1, e.g. if the last
 *	four bits are variable then set it to 00-00-00-00-00-0f. The actual
 *	variable bits shall be determined by the interfaces added, with
 *	interfaces not matching the mask being rejected to be brought up.

	/* permanent MAC address(es) */
	u8 perm_addr[ETH_ALEN];
	u8 addr_mask[ETH_ALEN];

-- 
Kalle Valo


From arnd at arndb.de  Fri Nov 28 02:23:08 2014
From: arnd at arndb.de (Arnd Bergmann)
Date: Fri, 28 Nov 2014 11:23:08 +0100
Subject: [PATCH v4 1/2] dt: bindings: add ath10k wireless device
In-Reply-To: <87fvd3sl9c.fsf@kamboji.qca.qualcomm.com>
References: <20141127120727.17546.61202.stgit@potku.adurom.net>
 <3202372.2AaH3c4qv1@wuerfel> <87fvd3sl9c.fsf@kamboji.qca.qualcomm.com>
Message-ID: <5247714.HacITJUipJ@wuerfel>

On Friday 28 November 2014 11:54:39 Kalle Valo wrote:
> 
> Right now ath10k does not support that, but in the future we might want
> to add mac address as well. We need to do some testing with the firmware
> to make sure that we can safely change the "main" address from ath10k.

This is from Documentation/devicetree/bindings/net/ethernet.txt:

- local-mac-address: array of 6 bytes, specifies the MAC address that was
  assigned to the network device;
- mac-address: array of 6 bytes, specifies the MAC address that was last used by
  the boot program; should be used in cases where the MAC address assigned to
  the device by the boot program is different from the "local-mac-address"
  property;

If the address is fixed, you might still be able to use the local-mac-address
property to communicate the main address. Normally you only have to pass
the mac address in DT if the device itself doesn't know the address. Do you
know where the main address is stored? If it's always known to the card,
we don't need to pass it, and if the card doesn't know it, I suspect it would
be safe to change it.

> And because of Virtual AP (mBSSID) feature we actually would need to
> provide multiple addresses, not just one. Maybe with addr_mask like
> struct wiphy has?
> 
>  * @perm_addr: permanent MAC address of this device
>  * @addr_mask: If the device supports multiple MAC addresses by masking,
>  *      set this to a mask with variable bits set to 1, e.g. if the last
>  *      four bits are variable then set it to 00-00-00-00-00-0f. The actual
>  *      variable bits shall be determined by the interfaces added, with
>  *      interfaces not matching the mask being rejected to be brought up.
> 
>         /* permanent MAC address(es) */
>         u8 perm_addr[ETH_ALEN];
>         u8 addr_mask[ETH_ALEN];

We don't have a common binding for this yet, I think drivers that do this
at the moment just know how many addresses they are allowed to take.

If the mask is generally considered useful, we could probably add that to
the binding though.

	Arnd


From michal.kazior at tieto.com  Fri Nov 28 03:25:43 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 28 Nov 2014 12:25:43 +0100
Subject: [PATCH 1/3] ath10k: embed supported chip ids in hw_params
In-Reply-To: <87d287u7fv.fsf@kamboji.qca.qualcomm.com>
References: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
 <87vbm2whoz.fsf@kamboji.qca.qualcomm.com>
 <CA+BoTQ=56six2CEQ6Rzr7yMEM7UVNQ3RX9UpdgmxMEoG0+kDAA@mail.gmail.com>
 <87d287u7fv.fsf@kamboji.qca.qualcomm.com>
Message-ID: <CA+BoTQ=0929oK8msio-zPj2v2JDZ2+3trg4QqQ-vbYJszwh0CQ@mail.gmail.com>

On 28 November 2014 at 08:10, Kalle Valo <kvalo at qca.qualcomm.com> wrote:
> Michal Kazior <michal.kazior at tieto.com> writes:
>
>> Hmm.. I have a couple of ideas:
>
> [...]
>
>> 2. Have a dedicatd pci-specific structure:
>>
>>  struct ath10k_pci_supported_chip {
>>    u16 dev_id;
>>    u32 chip_id;
>>  };
>>
>>  struct ath10k_pci_supported_chip ath10k_pci_supported_chips[] = {
>>    { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV },
>>    // ...
>>  };
>>
>> Probably the simplest and has least impact.
>
> Yeah, this seems to be the best. Can you send v2?

Ok. I'll go with this approach and post a v2 when I'm done.


Micha?


From yeohchunyeow at gmail.com  Fri Nov 28 03:42:44 2014
From: yeohchunyeow at gmail.com (Yeoh Chun-Yeow)
Date: Fri, 28 Nov 2014 19:42:44 +0800
Subject: IBSS mode is now supported by CT firmware.
In-Reply-To: <CAEFj986B15pFo2WY_2x0VwEXBEBy+j0-nff2-B=Ff=qP66iP_w@mail.gmail.com>
References: <547525D4.5080701@candelatech.com>
 <CAD1M061uAfCfCnnVY1bh6kCcXXZhwOOiyww5mkU8VkxGov9DwA@mail.gmail.com>
 <CAEFj986B15pFo2WY_2x0VwEXBEBy+j0-nff2-B=Ff=qP66iP_w@mail.gmail.com>
Message-ID: <CAEFj987HmrPz1vsjmckURuC4ZYT2h6MgBT6K3yQTWy3U5s+ZtQ@mail.gmail.com>

For CT firmware, IBSS mode works, but again the Rate Control in HT20
mode is not working at all. It always stuck with 6Mbps Tx Rate.

[  196.030000] ath10k_pci 0000:00:00.0: rx skb 869a5840 len 116 peer
04:f0:21:0c:a5:44  ucast sn 95  rate_idx 0 vht_nss 0 freq 5180 band 1
flag 0x200000 fcs-err 0 mic-err 0 amsdu-more 0

For legacy mode, rate control works. rate_idx to 7 or 54Mbps.

[  156.070000] ath10k_pci 0000:00:00.0: rx skb 86af0900 len 116 peer
04:f0:21:0c:a5:1c  ucast sn 95  rate_idx 7 vht_nss 0 freq 5180 band 1
flag 0x200000 fcs-err 0 mic-err 0 amsdu-more 0

Similar to 636 firmware.

----
ChunYeow

On Thu, Nov 27, 2014 at 9:04 AM, Yeoh Chun-Yeow <yeohchunyeow at gmail.com> wrote:
> On Thu, Nov 27, 2014 at 6:36 AM, Pushpal Sidhu <psidhu at gateworks.com> wrote:
>> On Tue, Nov 25, 2014 at 4:59 PM, Ben Greear <greearb at candelatech.com> wrote:
>>> I still cannot get WPA2 encryption to work, but open authentication
>>> seems to work fine.  I still have a good bit more testing to do.
>>> I cannot get ath9k to do encryption in IBSS mode either, so I
>>> probably am mis-configuring something.
>>
>> I don't believe WPA2 is supported with adhoc (at least through
>> wpa_supplicant). However, WPA should be and while testing your
>> firmware, I found that it doesn't seem to work (They don't see each
>> other and thus don't associate).
>>
>> I also found that, like the 999.x firmware, the rate's do not go
>> higher than 54mbit/s. Is this due to the firmware not advertising
>> proper rates or..?
>
> Are you joining the adhoc network in non-HT mode? Anyway, even if you
> use HT mode, the rate control is not working for 999.x firmware and
> always stuck at 6Mbps as far as I know.
>
> -----
> Chun-Yeow


From kvalo at qca.qualcomm.com  Fri Nov 28 04:21:39 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Fri, 28 Nov 2014 14:21:39 +0200
Subject: [PATCH v4 1/2] dt: bindings: add ath10k wireless device
In-Reply-To: <5247714.HacITJUipJ@wuerfel> (Arnd Bergmann's message of "Fri, 28
 Nov 2014 11:23:08 +0100")
References: <20141127120727.17546.61202.stgit@potku.adurom.net>
 <3202372.2AaH3c4qv1@wuerfel> <87fvd3sl9c.fsf@kamboji.qca.qualcomm.com>
 <5247714.HacITJUipJ@wuerfel>
Message-ID: <874mtjsegc.fsf@kamboji.qca.qualcomm.com>

Arnd Bergmann <arnd at arndb.de> writes:

> On Friday 28 November 2014 11:54:39 Kalle Valo wrote:
>> 
>> Right now ath10k does not support that, but in the future we might want
>> to add mac address as well. We need to do some testing with the firmware
>> to make sure that we can safely change the "main" address from ath10k.
>
> This is from Documentation/devicetree/bindings/net/ethernet.txt:
>
> - local-mac-address: array of 6 bytes, specifies the MAC address that was
>   assigned to the network device;
> - mac-address: array of 6 bytes, specifies the MAC address that was last used by
>   the boot program; should be used in cases where the MAC address assigned to
>   the device by the boot program is different from the "local-mac-address"
>   property;
>
> If the address is fixed, you might still be able to use the local-mac-address
> property to communicate the main address. Normally you only have to pass
> the mac address in DT if the device itself doesn't know the address. Do you
> know where the main address is stored?

The ath10k main address is stored in the calibration data and the
firmware delivers the address to ath10k.

> If it's always known to the card, we don't need to pass it, and if the
> card doesn't know it, I suspect it would be safe to change it.

I suspect we can change the address afterwards, but I need to check to
be sure.

>> And because of Virtual AP (mBSSID) feature we actually would need to
>> provide multiple addresses, not just one. Maybe with addr_mask like
>> struct wiphy has?
>> 
>>  * @perm_addr: permanent MAC address of this device
>>  * @addr_mask: If the device supports multiple MAC addresses by masking,
>>  *      set this to a mask with variable bits set to 1, e.g. if the last
>>  *      four bits are variable then set it to 00-00-00-00-00-0f. The actual
>>  *      variable bits shall be determined by the interfaces added, with
>>  *      interfaces not matching the mask being rejected to be brought up.
>> 
>>         /* permanent MAC address(es) */
>>         u8 perm_addr[ETH_ALEN];
>>         u8 addr_mask[ETH_ALEN];
>
> We don't have a common binding for this yet, I think drivers that do this
> at the moment just know how many addresses they are allowed to take.
>
> If the mask is generally considered useful, we could probably add that to
> the binding though.

Currently ath10k supports up to 8 Virtual APs but the manufacturer can
choose to allocate any number of MAC addresses (1-8). Something like
addr_mask would be good way to inform ath10k what address range it has
available.

-- 
Kalle Valo


From michal.kazior at tieto.com  Fri Nov 28 06:39:01 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Fri, 28 Nov 2014 15:39:01 +0100
Subject: [PATCH v2 7/7] ath10k: implement wmi-tlv backend
In-Reply-To: <1417079481-22255-8-git-send-email-michal.kazior@tieto.com>
References: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
 <1417079481-22255-8-git-send-email-michal.kazior@tieto.com>
Message-ID: <CA+BoTQn=g8-=FEEoW7Ux+p6s=EBy_3rwCP3qXWk_8ijR6jXY+Q@mail.gmail.com>

On 27 November 2014 at 10:11, Michal Kazior <michal.kazior at tieto.com> wrote:
> Latest main firmware branch introduced a new WMI
> ABI called wmi-tlv. It is not a tlv strictly
> speaking but something that resembles it because
> it is ordered and may have duplicate id entries.
>
> This prepares ath10k to support new hw.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
[...]
> @@ -215,6 +254,42 @@ static inline char *wmi_service_name(int service_id)
>         SVCSTR(WMI_SERVICE_BURST);
>         SVCSTR(WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT);
>         SVCSTR(WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT);
> +       SVCSTR(WMI_SERVICE_ROAM_SCAN_OFFLOAD);
> +       SVCSTR(WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC);
> +       SVCSTR(WMI_SERVICE_EARLY_RX);
[...]
> +       SVCSTR(WMI_SERVICE_RX_FULL_REORDER);
> +       SVCSTR(WMI_SERVICE_DHCP_OFFLOAD);

I've added 3 new service enums in v2:
WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, WMI_SERVICE_MDNS_OFFLOAD,
WMI_SERVICE_SAP_AUTH_OFFLOAD but apparently I forgot to add SVCSTR()
for that..


Micha?


From greearb at candelatech.com  Fri Nov 28 08:28:34 2014
From: greearb at candelatech.com (Ben Greear)
Date: Fri, 28 Nov 2014 08:28:34 -0800
Subject: IBSS mode is now supported by CT firmware.
In-Reply-To: <CAEFj987HmrPz1vsjmckURuC4ZYT2h6MgBT6K3yQTWy3U5s+ZtQ@mail.gmail.com>
References: <547525D4.5080701@candelatech.com>
 <CAD1M061uAfCfCnnVY1bh6kCcXXZhwOOiyww5mkU8VkxGov9DwA@mail.gmail.com>
 <CAEFj986B15pFo2WY_2x0VwEXBEBy+j0-nff2-B=Ff=qP66iP_w@mail.gmail.com>
 <CAEFj987HmrPz1vsjmckURuC4ZYT2h6MgBT6K3yQTWy3U5s+ZtQ@mail.gmail.com>
Message-ID: <5478A2B2.3090402@candelatech.com>

I'll investigate the rate-control logic.  I don't know enough
about IBSS currently to know why it would use different rate-ctrl logic than
the normal sta/ap, but hopefully I can figure it out.

Can you post some details on how you configure HT20 v/s legacy mode
for IBSS interfaces?

Do you have any reason to believe the problem is in the driver or mac80211
stack, or is this all a firmware issue?

And, if anyone has a different /AC NIC that can do IBSS, I'm curious
if ath10k will receive at higher speeds?

Thanks,
Ben


On 11/28/2014 03:42 AM, Yeoh Chun-Yeow wrote:
> For CT firmware, IBSS mode works, but again the Rate Control in HT20
> mode is not working at all. It always stuck with 6Mbps Tx Rate.
>
> [  196.030000] ath10k_pci 0000:00:00.0: rx skb 869a5840 len 116 peer
> 04:f0:21:0c:a5:44  ucast sn 95  rate_idx 0 vht_nss 0 freq 5180 band 1
> flag 0x200000 fcs-err 0 mic-err 0 amsdu-more 0
>
> For legacy mode, rate control works. rate_idx to 7 or 54Mbps.
>
> [  156.070000] ath10k_pci 0000:00:00.0: rx skb 86af0900 len 116 peer
> 04:f0:21:0c:a5:1c  ucast sn 95  rate_idx 7 vht_nss 0 freq 5180 band 1
> flag 0x200000 fcs-err 0 mic-err 0 amsdu-more 0
>
> Similar to 636 firmware.
>
> ----
> ChunYeow
>
> On Thu, Nov 27, 2014 at 9:04 AM, Yeoh Chun-Yeow <yeohchunyeow at gmail.com> wrote:
>> On Thu, Nov 27, 2014 at 6:36 AM, Pushpal Sidhu <psidhu at gateworks.com> wrote:
>>> On Tue, Nov 25, 2014 at 4:59 PM, Ben Greear <greearb at candelatech.com> wrote:
>>>> I still cannot get WPA2 encryption to work, but open authentication
>>>> seems to work fine.  I still have a good bit more testing to do.
>>>> I cannot get ath9k to do encryption in IBSS mode either, so I
>>>> probably am mis-configuring something.
>>>
>>> I don't believe WPA2 is supported with adhoc (at least through
>>> wpa_supplicant). However, WPA should be and while testing your
>>> firmware, I found that it doesn't seem to work (They don't see each
>>> other and thus don't associate).
>>>
>>> I also found that, like the 999.x firmware, the rate's do not go
>>> higher than 54mbit/s. Is this due to the firmware not advertising
>>> proper rates or..?
>>
>> Are you joining the adhoc network in non-HT mode? Anyway, even if you
>> use HT mode, the rate control is not working for 999.x firmware and
>> always stuck at 6Mbps as far as I know.
>>
>> -----
>> Chun-Yeow
>
> _______________________________________________
> ath10k mailing list
> ath10k at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath10k
>

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


From xerofoify at gmail.com  Fri Nov 28 13:43:18 2014
From: xerofoify at gmail.com (nick)
Date: Fri, 28 Nov 2014 16:43:18 -0500
Subject: Fix me in htc.c relating to skb_reserve
Message-ID: <5478EC76.40102@gmail.com>

Greetings Kalle, John and others,
I am wondering why this file is complaining about the code below, if someone can explain to me the issue I would be 
very glad :).
 static struct sk_buff *ath10k_htc_build_tx_ctrl_skb(void *ar)
{
       struct sk_buff *skb;
       struct ath10k_skb_cb *skb_cb;

       skb = dev_alloc_skb(ATH10K_HTC_CONTROL_BUFFER_SIZE);
       if (!skb)
               return NULL;

  skb_reserve(skb, 20); /* FIXME: why 20 bytes? */
  WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");

  skb_cb = ATH10K_SKB_CB(skb);
  memset(skb_cb, 0, sizeof(*skb_cb));

  ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: skb %p\n", __func__, skb);
  return skb;
}


From yeohchunyeow at gmail.com  Fri Nov 28 16:25:16 2014
From: yeohchunyeow at gmail.com (Yeoh Chun-Yeow)
Date: Sat, 29 Nov 2014 08:25:16 +0800
Subject: IBSS mode is now supported by CT firmware.
In-Reply-To: <5478A2B2.3090402@candelatech.com>
References: <547525D4.5080701@candelatech.com>
 <CAD1M061uAfCfCnnVY1bh6kCcXXZhwOOiyww5mkU8VkxGov9DwA@mail.gmail.com>
 <CAEFj986B15pFo2WY_2x0VwEXBEBy+j0-nff2-B=Ff=qP66iP_w@mail.gmail.com>
 <CAEFj987HmrPz1vsjmckURuC4ZYT2h6MgBT6K3yQTWy3U5s+ZtQ@mail.gmail.com>
 <5478A2B2.3090402@candelatech.com>
Message-ID: <CAEFj987J63pkrWvxg_S6onTQDJuOMjo2Bc=5hnC2PzMTEWXEKQ@mail.gmail.com>

On Sat, Nov 29, 2014 at 12:28 AM, Ben Greear <greearb at candelatech.com> wrote:
> I'll investigate the rate-control logic.  I don't know enough
> about IBSS currently to know why it would use different rate-ctrl logic than
> the normal sta/ap, but hopefully I can figure it out.
>
> Can you post some details on how you configure HT20 v/s legacy mode
> for IBSS interfaces?

Alright, this is how I configure adhoc mode.

HT20 Mode:
iw phy0 interface add wlan0 type adhoc
ifconfig wlan0 1.1.1.1 netmask 255.255.255.0
iw wlan0 ibss join adhocnet 5180 HT20

Legacy Mode:
iw phy0 interface add wlan0 type adhoc
ifconfig wlan0 1.1.1.1 netmask 255.255.255.0
iw wlan0 ibss join adhocnet 5180

By the way, the peer in ath10k is up in legacy mode first before
updating the rate to HT20, triggered by drv_sta_rc_update in
net/mac80211/ibss.c.

Is EEE80211_RC_SUPP_RATES_CHANGED working correctly for ath10k?

>
> Do you have any reason to believe the problem is in the driver or mac80211
> stack, or is this all a firmware issue?
>

Rate control is implemented in firmware, right? So it should be
firmware issue unless we intended to use the rate control implemented
in mac80211 (minstrel).

By the way, I haven't done the testing on CT firmware. But as far as I
know, for 363 firmware, the setting of higher fixed TX rate is
possible if you configure HT20, such as follow:

iw wlanX set bitrates legacy-5 ht-mcs-5 3 vht-mcs-5
will setup HT, nss=1, mcs=3

So I think that rate control logic in firmware is not working properly
in IBSS mode.

> And, if anyone has a different /AC NIC that can do IBSS, I'm curious
> if ath10k will receive at higher speeds?
>

ath9k but the rate control is managed by mac80211.

----
ChunYeow


From kvalo at qca.qualcomm.com  Sun Nov 30 23:04:41 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 1 Dec 2014 09:04:41 +0200
Subject: [PATCH] ath10k: Do not limit RTS threshold value to 2347
In-Reply-To: <1416830240-3019-1-git-send-email-nataraja@qti.qualcomm.com>
 (Vivek Natarajan's message of "Mon, 24 Nov 2014 17:27:20 +0530")
References: <1416830240-3019-1-git-send-email-nataraja@qti.qualcomm.com>
Message-ID: <87vblvrgty.fsf@kamboji.qca.qualcomm.com>

Vivek Natarajan <nataraja at qti.qualcomm.com> writes:

> Increase the rts threshold from the legacy value of 2347 to support higher
> threshold limit.
>
> Signed-off-by: Vivek Natarajan <nataraja at qti.qualcomm.com>

Thanks, applied.

In the future, please also CC linux-wireless as documented here:

http://wireless.kernel.org/en/users/Drivers/ath10k/sources#Submitting_patches

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Sun Nov 30 23:06:45 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 1 Dec 2014 09:06:45 +0200
Subject: [PATCH] ath10k: add pointer constness to traces
In-Reply-To: <1417074131-18460-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Thu, 27 Nov 2014 08:42:11 +0100")
References: <1417074131-18460-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87r3wjrgqi.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> Traces shouldn't modified passed data. This will
> make it possible to pass const arguments to
> traces.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

Thanks, applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Sun Nov 30 23:10:59 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 1 Dec 2014 09:10:59 +0200
Subject: [PATCH v2 0/7] ath10k: add support for new wmi-tlv backend
In-Reply-To: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Thu, 27 Nov 2014 10:11:14 +0100")
References: <1417079481-22255-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87mw77rgjg.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> First 2 patches are simple fixes. Patch 3 isn't
> strictly related to wmi-tlv but I decided to
> include it anyway. Other patches gradually
> implement wmi-tlv.
>
> There's a bunch of false-positive checkpatch
> warnings regarding `CHECK: No space is necessary
> after a cast`.
>
> v2:
>  * a lot of fixes (see notes on patch #7)
>
> Michal Kazior (7):
>   ath10k: fix wmi svc bitmap dbg print
>   ath10k: add sanity checks for service bmap parsing
>   ath10k: make wmi service bitmap non-debug

These three are applied.

>   ath10k: implement intermediate event args
>   ath10k: introduce wmi ops
>   ath10k: make some wmi functions public
>   ath10k: implement wmi-tlv backend

I'm still looking at these.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Sun Nov 30 23:26:42 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 1 Dec 2014 09:26:42 +0200
Subject: [PATCH 2/3] ath10k: remove callback argument
In-Reply-To: <1417082978-1701-2-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Thu, 27 Nov 2014 11:09:37 +0100")
References: <1417082978-1701-1-git-send-email-michal.kazior@tieto.com>
 <1417082978-1701-2-git-send-email-michal.kazior@tieto.com>
Message-ID: <87iohvrft9.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> Pass the eid argument via skbuff control buffer.
> This will make it possible to work with queues of
> HTC event buffers.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

To make the title more unique I changed the title to:

ath10k: remove transfer_id from ath10k_hif_cb::tx_completion

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Sun Nov 30 23:28:07 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 1 Dec 2014 09:28:07 +0200
Subject: [PATCH 1/3] ath10k: remove unused callback argument
In-Reply-To: <1417082978-1701-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Thu, 27 Nov 2014 11:09:36 +0100")
References: <1417082978-1701-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87egsjrfqw.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> This wasn't used since forever and there are no
> plans on using it.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

Thanks, all three patches applied.

-- 
Kalle Valo


From michal.kazior at tieto.com  Sun Nov 30 23:17:44 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon,  1 Dec 2014 08:17:44 +0100
Subject: [PATCH v2 1/3] ath10k: create a chip revision whielist
In-Reply-To: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
References: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1417418266-21974-1-git-send-email-michal.kazior@tieto.com>

This will make it easier to extend and maintain
list of supported hardware.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---

Notes:
    v2:
     * create a separate chip_id whitelist array
       instead of using hw_params as discussed [Kalle]

 drivers/net/wireless/ath/ath10k/core.c | 37 ----------------------------------
 drivers/net/wireless/ath/ath10k/core.h |  1 -
 drivers/net/wireless/ath/ath10k/pci.c  | 31 ++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/pci.h  |  5 +++++
 4 files changed, 36 insertions(+), 38 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 7762061..ece8ab4 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1068,34 +1068,6 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
 	return 0;
 }
 
-static int ath10k_core_check_chip_id(struct ath10k *ar)
-{
-	u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV);
-
-	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n",
-		   ar->chip_id, hw_revision);
-
-	/* Check that we are not using hw1.0 (some of them have same pci id
-	 * as hw2.0) before doing anything else as ath10k crashes horribly
-	 * due to missing hw1.0 workarounds. */
-	switch (hw_revision) {
-	case QCA988X_HW_1_0_CHIP_ID_REV:
-		ath10k_err(ar, "ERROR: qca988x hw1.0 is not supported\n");
-		return -EOPNOTSUPP;
-
-	case QCA988X_HW_2_0_CHIP_ID_REV:
-		/* known hardware revision, continue normally */
-		return 0;
-
-	default:
-		ath10k_warn(ar, "Warning: hardware revision unknown (0x%x), expect problems\n",
-			    ar->chip_id);
-		return 0;
-	}
-
-	return 0;
-}
-
 static void ath10k_core_register_work(struct work_struct *work)
 {
 	struct ath10k *ar = container_of(work, struct ath10k, register_work);
@@ -1143,16 +1115,7 @@ err:
 
 int ath10k_core_register(struct ath10k *ar, u32 chip_id)
 {
-	int status;
-
 	ar->chip_id = chip_id;
-
-	status = ath10k_core_check_chip_id(ar);
-	if (status) {
-		ath10k_err(ar, "Unsupported chip id 0x%08x\n", ar->chip_id);
-		return status;
-	}
-
 	queue_work(ar->workqueue, &ar->register_work);
 
 	return 0;
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 4a29498..88e6c74 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -479,7 +479,6 @@ struct ath10k {
 		u32 id;
 		const char *name;
 		u32 patch_load_addr;
-
 		struct ath10k_hw_params_fw {
 			const char *dir;
 			const char *fw;
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 0816098..e55292f 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -64,6 +64,14 @@ static const struct pci_device_id ath10k_pci_id_table[] = {
 	{0}
 };
 
+static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = {
+	/* QCA988X pre 2.0 chips are not supported because they need some nasty
+	 * hacks. ath10k doesn't have them and these devices crash horribly
+	 * because of that.
+	 */
+	{ QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV },
+};
+
 static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
 static int ath10k_pci_cold_reset(struct ath10k *ar);
 static int ath10k_pci_warm_reset(struct ath10k *ar);
@@ -2467,6 +2475,23 @@ static void ath10k_pci_release(struct ath10k *ar)
 	pci_disable_device(pdev);
 }
 
+static bool ath10k_pci_chip_is_supported(u32 dev_id, u32 chip_id)
+{
+	const struct ath10k_pci_supp_chip *supp_chip;
+	int i;
+	u32 rev_id = MS(chip_id, SOC_CHIP_ID_REV);
+
+	for (i = 0; i < ARRAY_SIZE(ath10k_pci_supp_chips); i++) {
+		supp_chip = &ath10k_pci_supp_chips[i];
+
+		if (supp_chip->dev_id == dev_id &&
+		    supp_chip->rev_id == rev_id)
+			return true;
+	}
+
+	return false;
+}
+
 static int ath10k_pci_probe(struct pci_dev *pdev,
 			    const struct pci_device_id *pci_dev)
 {
@@ -2512,6 +2537,12 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
 		goto err_sleep;
 	}
 
+	if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) {
+		ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n",
+			   pdev->device, chip_id);
+		goto err_sleep;
+	}
+
 	ret = ath10k_pci_alloc_pipes(ar);
 	if (ret) {
 		ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index cf36511..ce4a1ef 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -152,6 +152,11 @@ struct ath10k_pci_pipe {
 	struct tasklet_struct intr;
 };
 
+struct ath10k_pci_supp_chip {
+	u32 dev_id;
+	u32 rev_id;
+};
+
 struct ath10k_pci {
 	struct pci_dev *pdev;
 	struct device *dev;
-- 
1.8.5.3



From michal.kazior at tieto.com  Sun Nov 30 23:17:45 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon,  1 Dec 2014 08:17:45 +0100
Subject: [PATCH v2 2/3] ath10k: put board size into hw_params
In-Reply-To: <1417418266-21974-1-git-send-email-michal.kazior@tieto.com>
References: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
 <1417418266-21974-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1417418266-21974-2-git-send-email-michal.kazior@tieto.com>

This makes it easier to extend the list of
supported hardware.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.c | 8 +++++---
 drivers/net/wireless/ath/ath10k/core.h | 2 ++
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index ece8ab4..8bb1657 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -53,6 +53,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 			.fw = QCA988X_HW_2_0_FW_FILE,
 			.otp = QCA988X_HW_2_0_OTP_FILE,
 			.board = QCA988X_HW_2_0_BOARD_DATA_FILE,
+			.board_size = QCA988X_BOARD_DATA_SZ,
+			.board_ext_size = QCA988X_BOARD_EXT_DATA_SZ,
 		},
 	},
 };
@@ -146,8 +148,8 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,
 static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data,
 				      size_t data_len)
 {
-	u32 board_data_size = QCA988X_BOARD_DATA_SZ;
-	u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ;
+	u32 board_data_size = ar->hw_params.fw.board_size;
+	u32 board_ext_data_size = ar->hw_params.fw.board_ext_size;
 	u32 board_ext_data_addr;
 	int ret;
 
@@ -193,7 +195,7 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data,
 static int ath10k_download_board_data(struct ath10k *ar, const void *data,
 				      size_t data_len)
 {
-	u32 board_data_size = QCA988X_BOARD_DATA_SZ;
+	u32 board_data_size = ar->hw_params.fw.board_size;
 	u32 address;
 	int ret;
 
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 88e6c74..f1a3edd 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -484,6 +484,8 @@ struct ath10k {
 			const char *fw;
 			const char *otp;
 			const char *board;
+			size_t board_size;
+			size_t board_ext_size;
 		} fw;
 	} hw_params;
 
-- 
1.8.5.3



From michal.kazior at tieto.com  Sun Nov 30 23:17:46 2014
From: michal.kazior at tieto.com (Michal Kazior)
Date: Mon,  1 Dec 2014 08:17:46 +0100
Subject: [PATCH v2 3/3] ath10k: move uart pin config into hw_params
In-Reply-To: <1417418266-21974-1-git-send-email-michal.kazior@tieto.com>
References: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
 <1417418266-21974-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <1417418266-21974-3-git-send-email-michal.kazior@tieto.com>

This will make it possible to easily support
different hardware with different uart pin
configuration.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 drivers/net/wireless/ath/ath10k/core.c | 3 ++-
 drivers/net/wireless/ath/ath10k/core.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 8bb1657..7c913cc 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -48,6 +48,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 		.id = QCA988X_HW_2_0_VERSION,
 		.name = "qca988x hw2.0",
 		.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
+		.uart_pin = 7,
 		.fw = {
 			.dir = QCA988X_HW_2_0_FW_DIR,
 			.fw = QCA988X_HW_2_0_FW_FILE,
@@ -698,7 +699,7 @@ static int ath10k_init_uart(struct ath10k *ar)
 	if (!uart_print)
 		return 0;
 
-	ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7);
+	ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, ar->hw_params.uart_pin);
 	if (ret) {
 		ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);
 		return ret;
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index f1a3edd..0188c84 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -479,6 +479,7 @@ struct ath10k {
 		u32 id;
 		const char *name;
 		u32 patch_load_addr;
+		int uart_pin;
 		struct ath10k_hw_params_fw {
 			const char *dir;
 			const char *fw;
-- 
1.8.5.3



From kvalo at qca.qualcomm.com  Sun Nov 30 23:31:27 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 1 Dec 2014 09:31:27 +0200
Subject: [PATCH] ath10k: simplify rx ring size/fill calculation
In-Reply-To: <1417083163-2962-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Thu, 27 Nov 2014 11:12:43 +0100")
References: <1417083163-2962-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <87a937rflc.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> Don't bother with fancy arithmetic and just
> hardcode the final values.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

Thanks, applied.

-- 
Kalle Valo


From kvalo at qca.qualcomm.com  Sun Nov 30 23:47:33 2014
From: kvalo at qca.qualcomm.com (Kalle Valo)
Date: Mon, 1 Dec 2014 09:47:33 +0200
Subject: [PATCH v2 1/3] ath10k: create a chip revision whielist
In-Reply-To: <1417418266-21974-1-git-send-email-michal.kazior@tieto.com>
 (Michal Kazior's message of "Mon, 1 Dec 2014 08:17:44 +0100")
References: <1416838646-18801-1-git-send-email-michal.kazior@tieto.com>
 <1417418266-21974-1-git-send-email-michal.kazior@tieto.com>
Message-ID: <8761dvreui.fsf@kamboji.qca.qualcomm.com>

Michal Kazior <michal.kazior at tieto.com> writes:

> This will make it easier to extend and maintain
> list of supported hardware.
>
> Signed-off-by: Michal Kazior <michal.kazior at tieto.com>

I fixed a typo: s/whielist/whitelist/

> --- a/drivers/net/wireless/ath/ath10k/core.h
> +++ b/drivers/net/wireless/ath/ath10k/core.h
> @@ -479,7 +479,6 @@ struct ath10k {
>  		u32 id;
>  		const char *name;
>  		u32 patch_load_addr;
> -
>  		struct ath10k_hw_params_fw {
>  			const char *dir;
>  			const char *fw;

I removed this unnecessary change:

https://github.com/kvalo/ath/commit/bfa7b7948acaf7063cf4d664393b7f7a1c53b2e4

Because of my change there was also a simple conflict in patch 3:

https://github.com/kvalo/ath/commit/3487683c94495b6e0bbb1f3b19b3987b4ca2ff1f

-- 
Kalle Valo


