Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH v2 1/2] mt76: usb: fix rx A-MSDU support
From: Stanislaw Gruszka @ 2019-06-12 10:00 UTC (permalink / raw)
  To: Lorenzo Bianconi; +Cc: Lorenzo Bianconi, nbd, kvalo, linux-wireless
In-Reply-To: <20190612094519.GC8107@localhost.localdomain>

On Wed, Jun 12, 2019 at 11:45:21AM +0200, Lorenzo Bianconi wrote:
> > > +mt76u_build_rx_skb(u8 *data, int len, int buf_size,
> > > +		   int *nsgs)
> > > +{
> > > +	int data_len = min(len, MT_SKB_HEAD_LEN);

Oh, and this looks unneeded as well as for len < MT_SKB_HEAD_LEN=128
we will go through fast path.

> > mt7601u and iwlmvm just copy hdrlen + 8 and put the rest
> > of the buffer in fragment, which supose to be more efficient,
> > see comment in iwl_mvm_pass_packet_to_mac80211().
> 
> Right here we copy 128B instead of 32 but I think it is good to have L3 and L4
> header in the linear area of the skb since otherwise the stack will need to
> align them

Not sure if understand, I think aliment of L3 & L4 headers will be
the same, assuming ieee80211 header is aligned the same in fragment
buffer and in linear area. But if you think this is better to copy those
to linear area I'm ok with that.

Stanislaw

^ permalink raw reply

* Re: [PATCH v2 2/2] mt76: usb: do not always copy the first part of received frames
From: Lorenzo Bianconi @ 2019-06-12  9:53 UTC (permalink / raw)
  To: Stanislaw Gruszka; +Cc: Lorenzo Bianconi, nbd, kvalo, linux-wireless
In-Reply-To: <20190612091036.GB2965@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 1400 bytes --]

> On Fri, May 31, 2019 at 11:38:23AM +0200, Lorenzo Bianconi wrote:

[...]

> >  	}
> >  
> >  	urb->num_sgs = max_t(int, i, urb->num_sgs);
> > -	urb->transfer_buffer_length = urb->num_sgs * q->buf_size,
> > +	urb->transfer_buffer_length = urb->num_sgs * data_size;
> >  	sg_init_marker(urb->sg, urb->num_sgs);
> >  
> >  	return i ? : -ENOMEM;
> > @@ -611,8 +611,12 @@ static int mt76u_alloc_rx(struct mt76_dev *dev)
> >  	if (!q->entry)
> >  		return -ENOMEM;
> >  
> > -	q->buf_size = dev->usb.sg_en ? MT_RX_BUF_SIZE : PAGE_SIZE;
> > +	if (dev->usb.sg_en)
> > +		q->buf_size = MT_BUF_WITH_OVERHEAD(MT_RX_BUF_SIZE);
> 
> I strongly recommend to not doing this. While this should work
> in theory creating buffer with size of 2k + some bytes might
> trigger various bugs in dma mapping or other low level code.

even in practice actually :) but we can be more cautious since probably copying
the first 128B will not make any difference

> 
> And skb_shered_info is needed only in first buffer IIUC.
> 
> Also this patch seems to make first patch unnecessary except for
> non sg_en case (in which I think rx AMSDU is broken anyway),
> so I would prefer just to apply first patch.

I do not think rx AMSDU is broken for non sg_en case since the max rx value
allowed should be 3839 IIRC and we alloc one page in this case

Regards,
Lorenzo

> 
> Stanislaw
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH] wlcore/wl18xx: Add invert-irq OF property for physically inverted IRQ
From: Eugeniu Rosca @ 2019-06-12  9:45 UTC (permalink / raw)
  To: Marc Zyngier, Geert Uytterhoeven, Tony Lindgren, Kalle Valo,
	Eyal Reizer
  Cc: Simon Horman, David S. Miller, Greg Kroah-Hartman, Randy Dunlap,
	Ulf Hansson, John Stultz, linux-wireless, netdev,
	Linux Kernel Mailing List, Spyridon Papageorgiou, Joshua Frkuska,
	George G . Davis, Andrey Gusakov, Linux-Renesas, Eugeniu Rosca,
	Eugeniu Rosca, Thomas Gleixner, Jason Cooper, Linus Walleij
In-Reply-To: <08bc4755-5f47-d792-8b5a-927b5fbe7619@arm.com>

Hi,

cc: Linus Walleij

On Tue, Jun 11, 2019 at 10:00:41AM +0100, Marc Zyngier wrote:
> On 11/06/2019 09:45, Geert Uytterhoeven wrote:
> > CC irqchip
> > 
> > Original thread at
> > https://lore.kernel.org/lkml/20190607172958.20745-1-erosca@de.adit-jv.com/
> > 
> > On Mon, Jun 10, 2019 at 10:30 AM Tony Lindgren <tony@atomide.com> wrote:
> >> * Kalle Valo <kvalo@codeaurora.org> [190610 07:01]:
> >>> Eugeniu Rosca <erosca@de.adit-jv.com> writes:
> >>>
> >>>> The wl1837mod datasheet [1] says about the WL_IRQ pin:
> >>>>
> >>>>  ---8<---
> >>>> SDIO available, interrupt out. Active high. [..]
> >>>> Set to rising edge (active high) on powerup.
> >>>>  ---8<---
> >>>>
> >>>> That's the reason of seeing the interrupt configured as:
> >>>>  - IRQ_TYPE_EDGE_RISING on HiKey 960/970
> >>>>  - IRQ_TYPE_LEVEL_HIGH on a number of i.MX6 platforms
> >>>>
> >>>> We assert that all those platforms have the WL_IRQ pin connected
> >>>> to the SoC _directly_ (confirmed on HiKey 970 [2]).
> >>>>
> >>>> That's not the case for R-Car Kingfisher extension target, which carries
> >>>> a WL1837MODGIMOCT IC. There is an SN74LV1T04DBVR inverter present
> >>>> between the WLAN_IRQ pin of the WL18* chip and the SoC, effectively
> >>>> reversing the requirement quoted from [1]. IOW, in Kingfisher DTS
> >>>> configuration we would need to use IRQ_TYPE_EDGE_FALLING or
> >>>> IRQ_TYPE_LEVEL_LOW.
> >>>>
> >>>> Unfortunately, v4.2-rc1 commit bd763482c82ea2 ("wl18xx: wlan_irq:
> >>>> support platform dependent interrupt types") made a special case out
> >>>> of these interrupt types. After this commit, it is impossible to provide
> >>>> an IRQ configuration via DTS which would describe an inverter present
> >>>> between the WL18* chip and the SoC, generating the need for workarounds
> >>>> like [3].
> >>>>
> >>>> Create a boolean OF property, called "invert-irq" to specify that
> >>>> the WLAN_IRQ pin of WL18* is connected to the SoC via an inverter.
> >>>>
> >>>> This solution has been successfully tested on R-Car H3ULCB-KF-M06 using
> >>>> the DTS configuration [4] combined with the "invert-irq" property.
> >>>>
> >>>> [1] http://www.ti.com/lit/ds/symlink/wl1837mod.pdf
> >>>> [2] https://www.96boards.org/documentation/consumer/hikey/hikey970/hardware-docs/
> >>>> [3] https://github.com/CogentEmbedded/meta-rcar/blob/289fbd4f8354/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0024-wl18xx-do-not-invert-IRQ-on-WLxxxx-side.patch
> >>>> [4] https://patchwork.kernel.org/patch/10895879/
> >>>>     ("arm64: dts: ulcb-kf: Add support for TI WL1837")
> >>>>
> >>>> Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com>
> >>>
> >>> Tony&Eyal, do you agree with this?
> >>
> >> Yeah if there's some hardware between the WLAN device and the SoC
> >> inverting the interrupt, I don't think we have clear a way to deal
> >> with it short of setting up a separate irqchip that does the
> >> translation.
> > 
> > Yeah, inverting the interrupt type in DT works only for simple devices,
> > that don't need configuration.
> > A simple irqchip driver that just inverts the type sounds like a good
> > solution to me. Does something like that already exists?
> 
> We already have plenty of that in the tree, the canonical example
> probably being drivers/irqchip/irq-mtk-sysirq.c. It should be pretty
> easy to turn this driver into something more generic.

I don't think drivers/irqchip/irq-mtk-sysirq.c can serve the
use-case/purpose of this patch. The MTK driver seems to be dealing with
the polarity inversion of on-SoC interrupts which are routed to GiC,
whereas in this patch we are talking about an off-chip interrupt
wired to R-Car GPIO controller.

It looks to me that the nice DTS sketch shared by Linus Walleij in [5]
might come closer to the concept proposed by Geert? FWIW, the
infrastructure/implementation to make this possible is still not ready.

One question to the wlcore/wl18xx maintainers: Why exactly do you give
freedom to users to set the interrupt as LEVEL_LOW/EDGE_FALLING [6]?
Apparently, this:
 - complicates the wl18xx driver, thus increasing the chance for bugs
 - is not supposed to reflect any HW differences between boards using
   LEVEL_LOW/EDGE_FALLING and the boards using LEVEL_HIGH/EDGE_RISING
 - doesn't bring any obvious advantage to the users, who are expected to
   sense the same behavior regardless of the IRQ type set in DTS
 - prevent the users to set IRQ type to LEVEL_LOW/EDGE_FALLING when
   there is an inverter present between WL_IRQ and SoC
 - seems to be not used almost at all, as 99% of mainline DTS set the
   IRQ type to the canonical/NLCP LEVEL_HIGH/EDGE_RISING

[5] https://patchwork.ozlabs.org/patch/1095690/#2167076
  ("[V1,1/2] gpio: make it possible to set active-state on GPIO lines")
 --------------------8<-------------------
 gpio0: gpio {
    compatible = "foo,chip";
    gpio-controller;
    (...)
 };

 inv0: inverter {
     compatible = "inverter";
     gpio-controller;
     gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>;
 };

 consumer {
    compatible = "bar";
    gpios = <&inv0 0 GPIO_ACTIVE_HIGH>;
 };
 --------------------8<-------------------

[6] bd763482c82ea2 ("wl18xx: wlan_irq: support platform dependent interrupt types")

-- 
Best Regards,
Eugeniu.

^ permalink raw reply

* Re: [PATCH v2 1/2] mt76: usb: fix rx A-MSDU support
From: Lorenzo Bianconi @ 2019-06-12  9:45 UTC (permalink / raw)
  To: Stanislaw Gruszka; +Cc: Lorenzo Bianconi, nbd, kvalo, linux-wireless
In-Reply-To: <20190612085844.GA2965@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 3404 bytes --]

> Hi and sorry for late comment.
> 

Hi Stanislaw,

> On Fri, May 31, 2019 at 11:38:22AM +0200, Lorenzo Bianconi wrote:
> > Commit f8f527b16db5 ("mt76: usb: use EP max packet aligned buffer sizes
> > for rx") breaks A-MSDU support. When A-MSDU is enable the device can
> > receive frames up to q->buf_size but they will be discarded in
> > mt76u_process_rx_entry since there is no enough room for
> > skb_shared_info. Fix the issue reallocating the skb and copying in the
> > linear area the first 128B of the received frames and in the frag_list
> > the remaining part.
> > 
> > Fixes: f8f527b16db5 ("mt76: usb: use EP max packet aligned buffer sizes for rx")
> > Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
> > ---
> >  drivers/net/wireless/mediatek/mt76/mt76.h |  1 +
> >  drivers/net/wireless/mediatek/mt76/usb.c  | 52 +++++++++++++++++++----
> >  2 files changed, 44 insertions(+), 9 deletions(-)
> > 
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
> > index 97a1296562d0..74d4edf941d6 100644
> > --- a/drivers/net/wireless/mediatek/mt76/mt76.h
> > +++ b/drivers/net/wireless/mediatek/mt76/mt76.h
> > @@ -30,6 +30,7 @@
> >  #define MT_TX_RING_SIZE     256
> >  #define MT_MCU_RING_SIZE    32
> >  #define MT_RX_BUF_SIZE      2048
> > +#define MT_SKB_HEAD_LEN     128
> >  
> >  struct mt76_dev;
> >  struct mt76_wcid;
> > diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
> > index bbaa1365bbda..2bfc8214c0d8 100644
> > --- a/drivers/net/wireless/mediatek/mt76/usb.c
> > +++ b/drivers/net/wireless/mediatek/mt76/usb.c
> > @@ -429,6 +429,48 @@ static int mt76u_get_rx_entry_len(u8 *data, u32 data_len)
> >  	return dma_len;
> >  }
> >  
> > +static struct sk_buff *
> > +mt76u_build_rx_skb(u8 *data, int len, int buf_size,
> > +		   int *nsgs)
> > +{
> > +	int data_len = min(len, MT_SKB_HEAD_LEN);
> > +	struct sk_buff *skb;
> > +
> > +	if (SKB_WITH_OVERHEAD(buf_size) >= MT_DMA_HDR_LEN + len) {
> > +		/* fast path */
> > +		skb = build_skb(data, buf_size);
> > +		if (!skb)
> > +			return NULL;
> > +
> > +		skb_reserve(skb, MT_DMA_HDR_LEN);
> > +		__skb_put(skb, len);
> > +
> > +		return skb;
> > +	}
> > +
> > +	/* slow path, not enough space for data and
> > +	 * skb_shared_info
> > +	 */
> > +	skb = alloc_skb(data_len, GFP_ATOMIC);
> > +	if (!skb)
> > +		return NULL;
> > +
> > +	skb_put_data(skb, data + MT_DMA_HDR_LEN, data_len);
> mt7601u and iwlmvm just copy hdrlen + 8 and put the rest
> of the buffer in fragment, which supose to be more efficient,
> see comment in iwl_mvm_pass_packet_to_mac80211().

Right here we copy 128B instead of 32 but I think it is good to have L3 and L4
header in the linear area of the skb since otherwise the stack will need to
align them

>  
> > +	data += (data_len + MT_DMA_HDR_LEN);
> > +	len -= data_len;
> > +	if (len > 0) {
> > +		struct page *page = virt_to_head_page(data);
> > +		int offset = data - (u8 *)page_address(page);
> u8 cast not needed.
> 
> > +		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
> > +				page, offset, len, buf_size);
> > +	} else {
> > +		*nsgs = 0;
> This seems to be not necessary or a bug (use first buffer 2 times). 

maybe I have been a little bit too paranoid here :)

Regards,
Lorenzo

> 
> Stanislaw

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* [PATCH] mt76: mt76x02u: fix sparse warnings: should it be static?
From: Lorenzo Bianconi @ 2019-06-12  9:31 UTC (permalink / raw)
  To: nbd; +Cc: linux-wireless, lorenzo.bianconi, sgruszka

Fix following sparse warnings in mt76x02_usb_core.c

drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c:29:6: warning:
symbol 'mt76x02u_tx_complete_skb' was not declared. Should it be static?
drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c:37:5: warning:
symbol 'mt76x02u_skb_dma_info' was not declared. Should it be static?
drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c:96:52: warning:
restricted __le16 degrades to integer
drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c:74:5: warning:
symbol 'mt76x02u_tx_prepare_skb' was not declared. Should it be static?
drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c:244:6: warning:
symbol 'mt76x02u_init_beacon_config' was not declared. Should it be
static?
drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c:262:6: warning:
symbol 'mt76x02u_exit_beacon_config' was not declared. Should it be
static?

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
 drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
index f3696afc1dde..1157d905b28c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -14,7 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "mt76x02.h"
+#include "mt76x02_usb.h"
 
 static void mt76x02u_remove_dma_hdr(struct sk_buff *skb)
 {
-- 
2.21.0


^ permalink raw reply related

* Re: rtw88: M.2 RTL8822BE not working - rfe 3 isn't supported
From: Stanislaw Gruszka @ 2019-06-12  9:13 UTC (permalink / raw)
  To: g.schlmm; +Cc: linux-wireless, yhchuang
In-Reply-To: <0d0159a8-a83e-cef3-fd32-4928a2301719@gmail.com>

Cc Tony 

On Sat, Jun 08, 2019 at 02:26:51PM +0200, g.schlmm wrote:
> my RTL8822BE M.2 card is not working with linux 5.2rc3
> 
> the staging r8822be driver in linux 5.1 was working for this card
> 
> from dmesg:
> > [    8.001186] rtw_pci 0000:04:00.0: rfe 3 isn't supported                                                             
> > [    8.003870] rtw_pci 0000:04:00.0: failed to setup chip efuse info                                                   
> > [    8.006405] rtw_pci 0000:04:00.0: failed to setup chip information 
> 
> lspci:
> > 04:00.0 Unassigned class [ff00]: Realtek Semiconductor Co., Ltd. RTL8822BE 802.11a/b/g/n/ac WiFi adapter
> >         Subsystem: Lenovo RTL8822BE 802.11a/b/g/n/ac WiFi adapter
> >         Flags: fast devsel, IRQ 19
> >         I/O ports at c000 [size=256]
> >         Memory at 81200000 (64-bit, non-prefetchable) [size=64K]
> >         Capabilities: [40] Power Management version 3
> >         Capabilities: [50] MSI: Enable- Count=1/1 Maskable- 64bit+
> >         Capabilities: [70] Express Endpoint, MSI 00
> >         Capabilities: [100] Advanced Error Reporting
> >         Capabilities: [148] Device Serial Number 00-e0-4c-ff-fe-b8-22-01
> >         Capabilities: [158] Latency Tolerance Reporting
> >         Capabilities: [160] L1 PM Substates
> >         Kernel modules: rtwpci

^ permalink raw reply

* Re: [PATCH v2 2/2] mt76: usb: do not always copy the first part of received frames
From: Stanislaw Gruszka @ 2019-06-12  9:10 UTC (permalink / raw)
  To: Lorenzo Bianconi; +Cc: nbd, kvalo, linux-wireless, lorenzo.bianconi
In-Reply-To: <2ed0b595a12944a8cfea14e066bcc4fa24f0ba44.1559293385.git.lorenzo@kernel.org>

On Fri, May 31, 2019 at 11:38:23AM +0200, Lorenzo Bianconi wrote:
> Set usb buffer size taking into account skb_shared_info in order to
> not always copy the first part of received frames if A-MSDU is enabled
> for SG capable devices
> 
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
> ---
>  drivers/net/wireless/mediatek/mt76/mt76.h |  3 +++
>  drivers/net/wireless/mediatek/mt76/usb.c  | 12 ++++++++----
>  2 files changed, 11 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
> index 74d4edf941d6..7899e9b88b54 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt76.h
> @@ -32,6 +32,9 @@
>  #define MT_RX_BUF_SIZE      2048
>  #define MT_SKB_HEAD_LEN     128
>  
> +#define MT_BUF_WITH_OVERHEAD(x) \
> +	((x) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
> +
>  struct mt76_dev;
>  struct mt76_wcid;
>  
> diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
> index 2bfc8214c0d8..5081643ce701 100644
> --- a/drivers/net/wireless/mediatek/mt76/usb.c
> +++ b/drivers/net/wireless/mediatek/mt76/usb.c
> @@ -286,7 +286,7 @@ static int
>  mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76_queue *q, struct urb *urb,
>  		 int nsgs, gfp_t gfp)
>  {
> -	int i;
> +	int i, data_size = SKB_WITH_OVERHEAD(q->buf_size);
>  
>  	for (i = 0; i < nsgs; i++) {
>  		struct page *page;
> @@ -299,7 +299,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76_queue *q, struct urb *urb,
>  
>  		page = virt_to_head_page(data);
>  		offset = data - page_address(page);
> -		sg_set_page(&urb->sg[i], page, q->buf_size, offset);
> +		sg_set_page(&urb->sg[i], page, data_size, offset);
>  	}
>  
>  	if (i < nsgs) {
> @@ -311,7 +311,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76_queue *q, struct urb *urb,
>  	}
>  
>  	urb->num_sgs = max_t(int, i, urb->num_sgs);
> -	urb->transfer_buffer_length = urb->num_sgs * q->buf_size,
> +	urb->transfer_buffer_length = urb->num_sgs * data_size;
>  	sg_init_marker(urb->sg, urb->num_sgs);
>  
>  	return i ? : -ENOMEM;
> @@ -611,8 +611,12 @@ static int mt76u_alloc_rx(struct mt76_dev *dev)
>  	if (!q->entry)
>  		return -ENOMEM;
>  
> -	q->buf_size = dev->usb.sg_en ? MT_RX_BUF_SIZE : PAGE_SIZE;
> +	if (dev->usb.sg_en)
> +		q->buf_size = MT_BUF_WITH_OVERHEAD(MT_RX_BUF_SIZE);

I strongly recommend to not doing this. While this should work
in theory creating buffer with size of 2k + some bytes might
trigger various bugs in dma mapping or other low level code.

And skb_shered_info is needed only in first buffer IIUC.

Also this patch seems to make first patch unnecessary except for
non sg_en case (in which I think rx AMSDU is broken anyway),
so I would prefer just to apply first patch.

Stanislaw


^ permalink raw reply

* Re: [PATCH v2 1/2] mt76: usb: fix rx A-MSDU support
From: Stanislaw Gruszka @ 2019-06-12  8:58 UTC (permalink / raw)
  To: Lorenzo Bianconi; +Cc: nbd, kvalo, linux-wireless, lorenzo.bianconi
In-Reply-To: <52ea155d9889aa15df44b4910806b74fa2fd9056.1559293385.git.lorenzo@kernel.org>

Hi and sorry for late comment.

On Fri, May 31, 2019 at 11:38:22AM +0200, Lorenzo Bianconi wrote:
> Commit f8f527b16db5 ("mt76: usb: use EP max packet aligned buffer sizes
> for rx") breaks A-MSDU support. When A-MSDU is enable the device can
> receive frames up to q->buf_size but they will be discarded in
> mt76u_process_rx_entry since there is no enough room for
> skb_shared_info. Fix the issue reallocating the skb and copying in the
> linear area the first 128B of the received frames and in the frag_list
> the remaining part.
> 
> Fixes: f8f527b16db5 ("mt76: usb: use EP max packet aligned buffer sizes for rx")
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
> ---
>  drivers/net/wireless/mediatek/mt76/mt76.h |  1 +
>  drivers/net/wireless/mediatek/mt76/usb.c  | 52 +++++++++++++++++++----
>  2 files changed, 44 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
> index 97a1296562d0..74d4edf941d6 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt76.h
> @@ -30,6 +30,7 @@
>  #define MT_TX_RING_SIZE     256
>  #define MT_MCU_RING_SIZE    32
>  #define MT_RX_BUF_SIZE      2048
> +#define MT_SKB_HEAD_LEN     128
>  
>  struct mt76_dev;
>  struct mt76_wcid;
> diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
> index bbaa1365bbda..2bfc8214c0d8 100644
> --- a/drivers/net/wireless/mediatek/mt76/usb.c
> +++ b/drivers/net/wireless/mediatek/mt76/usb.c
> @@ -429,6 +429,48 @@ static int mt76u_get_rx_entry_len(u8 *data, u32 data_len)
>  	return dma_len;
>  }
>  
> +static struct sk_buff *
> +mt76u_build_rx_skb(u8 *data, int len, int buf_size,
> +		   int *nsgs)
> +{
> +	int data_len = min(len, MT_SKB_HEAD_LEN);
> +	struct sk_buff *skb;
> +
> +	if (SKB_WITH_OVERHEAD(buf_size) >= MT_DMA_HDR_LEN + len) {
> +		/* fast path */
> +		skb = build_skb(data, buf_size);
> +		if (!skb)
> +			return NULL;
> +
> +		skb_reserve(skb, MT_DMA_HDR_LEN);
> +		__skb_put(skb, len);
> +
> +		return skb;
> +	}
> +
> +	/* slow path, not enough space for data and
> +	 * skb_shared_info
> +	 */
> +	skb = alloc_skb(data_len, GFP_ATOMIC);
> +	if (!skb)
> +		return NULL;
> +
> +	skb_put_data(skb, data + MT_DMA_HDR_LEN, data_len);
mt7601u and iwlmvm just copy hdrlen + 8 and put the rest
of the buffer in fragment, which supose to be more efficient,
see comment in iwl_mvm_pass_packet_to_mac80211().
 
> +	data += (data_len + MT_DMA_HDR_LEN);
> +	len -= data_len;
> +	if (len > 0) {
> +		struct page *page = virt_to_head_page(data);
> +		int offset = data - (u8 *)page_address(page);
u8 cast not needed.

> +		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
> +				page, offset, len, buf_size);
> +	} else {
> +		*nsgs = 0;
This seems to be not necessary or a bug (use first buffer 2 times). 

Stanislaw

^ permalink raw reply

* Re: [RFC PATCH v2 3/3] ath11k: register HE mesh capabilities
From: Sven Eckelmann @ 2019-06-12  8:42 UTC (permalink / raw)
  To: ath11k; +Cc: Bob Copeland, linux-wireless
In-Reply-To: <1919330.hVZVHELXip@bentobox>

[-- Attachment #1: Type: text/plain, Size: 1041 bytes --]

On Tuesday, 11 June 2019 21:52:20 CEST Sven Eckelmann wrote:
[...]
> 	if (!test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
> 		rate_control_rate_init(sta);
> 
>    /* inform drivers about changes */
> 	rate_control_rate_update(local, sband, sta, changed);
> 
> Both will at least cause a call to ath11k_peer_assoc_prepare + 
> ath11k_wmi_send_peer_assoc_cmd but unfortunately the ath11k firmware hangs 
> afterwards.

The fw hang seems to be related to the not set bss_conf.he_support in 
ath11k_mac_vdev_start_restart. This has to be set when ieee80211_join_mesh 
calls ieee80211_vif_use_channel. Otherwise the firmware will set a HT/VHT mode 
in the firmware. Any sta with an higher phy mode will just hang the firmware.

So the two main problems right now are:

* set bss_conf.he_support during mesh_join before 
  ath11k_mac_vdev_start_restart is called

   - no clue what the best approach is

* let ath11k redo the association procedure with he_cap->has_he set to true 
  when wpa_supplicant is in control of the peers.

Kind regards,
	Sven

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* Re: [PATCH 2/2] mt76: mt7615: update peer's bssid when state transition changes
From: Ryder Lee @ 2019-06-12  8:37 UTC (permalink / raw)
  To: Lorenzo Bianconi
  Cc: Sean Wang, YF Luo, linux-wireless, linux-kernel, Yiwei Chung,
	linux-mediatek, Roy Luo, Lorenzo Bianconi, Felix Fietkau
In-Reply-To: <20190612082618.GA8107@localhost.localdomain>

On Wed, 2019-06-12 at 10:26 +0200, Lorenzo Bianconi wrote:
> > Driver should update peer's bssid and bss information when
> > state transition changes.
> > 
> > Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
> > ---
> >  .../net/wireless/mediatek/mt76/mt7615/main.c  |  5 +-
> >  .../net/wireless/mediatek/mt76/mt7615/mcu.c   | 49 ++++++++++---------
> >  2 files changed, 27 insertions(+), 27 deletions(-)
> > 
> 
> [...]
> 
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
> > index e82086eb8aa4..8fc12cd37906 100644
> > --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
> > +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
> > @@ -741,17 +741,6 @@ int mt7615_mcu_set_bss_info(struct mt7615_dev *dev,
> >  	u8 *buf, *data, tx_wlan_idx = 0;
> >  	struct req_hdr *hdr;
> >  
> > -	if (en) {
> > -		len += sizeof(struct bss_info_omac);
> > -		features |= BIT(BSS_INFO_OMAC);
> > -		if (mvif->omac_idx > EXT_BSSID_START) {
> > -			len += sizeof(struct bss_info_ext_bss);
> > -			features |= BIT(BSS_INFO_EXT_BSS);
> > -			ntlv++;
> > -		}
> > -		ntlv++;
> > -	}
> > -
> >  	switch (vif->type) {
> >  	case NL80211_IFTYPE_AP:
> >  	case NL80211_IFTYPE_MESH_POINT:
> > @@ -759,22 +748,23 @@ int mt7615_mcu_set_bss_info(struct mt7615_dev *dev,
> >  		conn_type = CONNECTION_INFRA_AP;
> >  		break;
> >  	case NL80211_IFTYPE_STATION: {
> > -		struct ieee80211_sta *sta;
> > -		struct mt7615_sta *msta;
> > -
> > -		rcu_read_lock();
> > -
> > -		sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
> > -		if (!sta) {
> > +		/* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */
> > +		if (en) {
> > +			struct ieee80211_sta *sta;
> > +			struct mt7615_sta *msta;
> > +
> > +			rcu_read_lock();
> > +			sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
> > +			if (!sta) {
> > +				rcu_read_unlock();
> > +				return -EINVAL;
> > +			}
> > +
> > +			msta = (struct mt7615_sta *)sta->drv_priv;
> > +			tx_wlan_idx = msta->wcid.idx;
> >  			rcu_read_unlock();
> > -			return -EINVAL;
> >  		}
> > -
> > -		msta = (struct mt7615_sta *)sta->drv_priv;
> > -		tx_wlan_idx = msta->wcid.idx;
> >  		conn_type = CONNECTION_INFRA_STA;
> > -
> > -		rcu_read_unlock();
> >  		break;
> >  	}
> >  	default:
> > @@ -782,6 +772,17 @@ int mt7615_mcu_set_bss_info(struct mt7615_dev *dev,
> >  		break;
> >  	}
> >  
> > +	if (en) {
> > +		len += sizeof(struct bss_info_omac);
> > +		features |= BIT(BSS_INFO_OMAC);
> > +		if (mvif->omac_idx > EXT_BSSID_START) {
> > +			len += sizeof(struct bss_info_ext_bss);
> > +			features |= BIT(BSS_INFO_EXT_BSS);
> > +			ntlv++;
> > +		}
> > +		ntlv++;
> > +	}
> 
> What did you move this chunk down?

Ah, my bad. I originally planned to add other conditions and it may
change 'en' so moved these stuff behind them.

Anyway I forgot to remove this part. Will fix it

Ryder.

> Regards,
> Lorenzo
> 
> > +
> >  	buf = kzalloc(len, GFP_KERNEL);
> >  	if (!buf)
> >  		return -ENOMEM;
> > -- 
> > 2.18.0
> > 
> _______________________________________________
> Linux-mediatek mailing list
> Linux-mediatek@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek



^ permalink raw reply

* Re: [PATCH v2] mt76: mt7615: add support for per-chain signal strength reporting
From: Lorenzo Bianconi @ 2019-06-12  8:37 UTC (permalink / raw)
  To: Ryder Lee
  Cc: Felix Fietkau, Lorenzo Bianconi, Roy Luo, YF Luo, Yiwei Chung,
	Sean Wang, linux-wireless, linux-mediatek, linux-kernel
In-Reply-To: <22e5caff3581dc92fd6fec2f25966d86b7276bba.1560220443.git.ryder.lee@mediatek.com>

[-- Attachment #1: Type: text/plain, Size: 2776 bytes --]

> Fill in RX status->chain_signal to avoid empty value.
> 
> Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
> ---
> Changes since v2 - correct calculation sequence
> ---
>  .../net/wireless/mediatek/mt76/mt7615/mac.c   | 30 ++++++++++++++++++-
>  .../net/wireless/mediatek/mt76/mt7615/mac.h   |  5 ++++
>  2 files changed, 34 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
> index b60d42b5923d..2f49a99e77b1 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
> @@ -13,6 +13,11 @@
>  #include "../dma.h"
>  #include "mac.h"
>  

[...]

> @@ -169,7 +175,29 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
>  
>  		status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
>  
> -		/* TODO: RSSI */
> +		status->chains = dev->mt76.antenna_mask;
> +		status->chain_signal[0] = to_rssi(MT_RXV4_RCPI0, rxdg3);
> +		status->chain_signal[1] = to_rssi(MT_RXV4_RCPI1, rxdg3);
> +		status->chain_signal[2] = to_rssi(MT_RXV4_RCPI2, rxdg3);
> +		status->chain_signal[3] = to_rssi(MT_RXV4_RCPI3, rxdg3);
> +		status->signal = status->chain_signal[0];
> +
> +		switch (status->chains) {
> +		case 0xf:
> +			status->signal = max(status->signal,
> +					     status->chain_signal[3]);
> +			/* fall through */
> +		case 0x7:
> +			status->signal = max(status->signal,
> +					     status->chain_signal[2]);
> +			/* fall through */
> +		case 0x3:
> +			status->signal = max(status->signal,
> +					     status->chain_signal[1]);
> +			break;
> +		default:
> +			break;
> +		}

is it possible to enable rx chains selectively (e.g. chain 0 and 2)?
If so we can do something like:

for (i = 1; i < hweight8(dev->mt76.antenna_mask); i++) {
	if (!(status->chains & BIT(i)))
		continue;

	status->signal = max(status->signal,
			     status->chain_signal[i]);
}

Regards,
Lorenzo

>  		rxd += 6;
>  		if ((u8 *)rxd - skb->data >= skb->len)
>  			return -EINVAL;
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
> index 18ad4b8a3807..b00ce8db58e9 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
> @@ -98,6 +98,11 @@ enum rx_pkt_type {
>  #define MT_RXV2_GROUP_ID		GENMASK(26, 21)
>  #define MT_RXV2_LENGTH			GENMASK(20, 0)
>  
> +#define MT_RXV4_RCPI3			GENMASK(31, 24)
> +#define MT_RXV4_RCPI2			GENMASK(23, 16)
> +#define MT_RXV4_RCPI1			GENMASK(15, 8)
> +#define MT_RXV4_RCPI0			GENMASK(7, 0)
> +
>  enum tx_header_format {
>  	MT_HDR_FORMAT_802_3,
>  	MT_HDR_FORMAT_CMD,
> -- 
> 2.18.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH 2/2] mt76: mt7615: update peer's bssid when state transition changes
From: Lorenzo Bianconi @ 2019-06-12  8:26 UTC (permalink / raw)
  To: Ryder Lee
  Cc: Felix Fietkau, Lorenzo Bianconi, Roy Luo, YF Luo, Yiwei Chung,
	Sean Wang, linux-wireless, linux-mediatek, linux-kernel
In-Reply-To: <449fee28c558b6f02b62275f9beefaab02b47efc.1560221172.git.ryder.lee@mediatek.com>

[-- Attachment #1: Type: text/plain, Size: 2667 bytes --]

> Driver should update peer's bssid and bss information when
> state transition changes.
> 
> Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
> ---
>  .../net/wireless/mediatek/mt76/mt7615/main.c  |  5 +-
>  .../net/wireless/mediatek/mt76/mt7615/mcu.c   | 49 ++++++++++---------
>  2 files changed, 27 insertions(+), 27 deletions(-)
> 

[...]

> diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
> index e82086eb8aa4..8fc12cd37906 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
> @@ -741,17 +741,6 @@ int mt7615_mcu_set_bss_info(struct mt7615_dev *dev,
>  	u8 *buf, *data, tx_wlan_idx = 0;
>  	struct req_hdr *hdr;
>  
> -	if (en) {
> -		len += sizeof(struct bss_info_omac);
> -		features |= BIT(BSS_INFO_OMAC);
> -		if (mvif->omac_idx > EXT_BSSID_START) {
> -			len += sizeof(struct bss_info_ext_bss);
> -			features |= BIT(BSS_INFO_EXT_BSS);
> -			ntlv++;
> -		}
> -		ntlv++;
> -	}
> -
>  	switch (vif->type) {
>  	case NL80211_IFTYPE_AP:
>  	case NL80211_IFTYPE_MESH_POINT:
> @@ -759,22 +748,23 @@ int mt7615_mcu_set_bss_info(struct mt7615_dev *dev,
>  		conn_type = CONNECTION_INFRA_AP;
>  		break;
>  	case NL80211_IFTYPE_STATION: {
> -		struct ieee80211_sta *sta;
> -		struct mt7615_sta *msta;
> -
> -		rcu_read_lock();
> -
> -		sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
> -		if (!sta) {
> +		/* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */
> +		if (en) {
> +			struct ieee80211_sta *sta;
> +			struct mt7615_sta *msta;
> +
> +			rcu_read_lock();
> +			sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
> +			if (!sta) {
> +				rcu_read_unlock();
> +				return -EINVAL;
> +			}
> +
> +			msta = (struct mt7615_sta *)sta->drv_priv;
> +			tx_wlan_idx = msta->wcid.idx;
>  			rcu_read_unlock();
> -			return -EINVAL;
>  		}
> -
> -		msta = (struct mt7615_sta *)sta->drv_priv;
> -		tx_wlan_idx = msta->wcid.idx;
>  		conn_type = CONNECTION_INFRA_STA;
> -
> -		rcu_read_unlock();
>  		break;
>  	}
>  	default:
> @@ -782,6 +772,17 @@ int mt7615_mcu_set_bss_info(struct mt7615_dev *dev,
>  		break;
>  	}
>  
> +	if (en) {
> +		len += sizeof(struct bss_info_omac);
> +		features |= BIT(BSS_INFO_OMAC);
> +		if (mvif->omac_idx > EXT_BSSID_START) {
> +			len += sizeof(struct bss_info_ext_bss);
> +			features |= BIT(BSS_INFO_EXT_BSS);
> +			ntlv++;
> +		}
> +		ntlv++;
> +	}

What did you move this chunk down?

Regards,
Lorenzo

> +
>  	buf = kzalloc(len, GFP_KERNEL);
>  	if (!buf)
>  		return -ENOMEM;
> -- 
> 2.18.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [RESEND] brcmfmac support for BCM4359 sdio on arm64 ??
From: Christian Hewitt @ 2019-06-12  8:22 UTC (permalink / raw)
  To: Arend Van Spriel
  Cc: linux-wireless, brcm80211-dev-list.pdl, brcm80211-dev-list,
	Wright.Feng, Neil Armstrong, Christoph Muellner
In-Reply-To: <37d2964d-1c2b-51bd-ac98-2cc171aa0c9c@broadcom.com>


> On 11 Jun 2019, at 1:45 pm, Arend Van Spriel <arend.vanspriel@broadcom.com> wrote:

[snip]

> The splat could be relevant. Maybe try the patch below to get actual values that are checked in the WARN_ON.

Hi Arend,

I think the patch got mangled in transit - it wouldn’t compile. Can you please resend, perhaps share via a paste site?

Christian


^ permalink raw reply

* Re: [PATCH 07/11] rtw88: 8822c: use more accurate ofdm fa counting
From: Kalle Valo @ 2019-06-12  7:42 UTC (permalink / raw)
  To: yhchuang; +Cc: linux-wireless
In-Reply-To: <1560321917-17751-8-git-send-email-yhchuang@realtek.com>

<yhchuang@realtek.com> writes:

> From: Yan-Hsuan Chuang <yhchuang@realtek.com>
>
> 8822c used to count OFDM FA count by subtracting tx count from FA count.
> But it need to substract more counters to be accurate.
>
> However, we can count it by adding up all of the FA counters we want.
> And it is simpler to add than list all of the components to substract.
>
> Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>

[...]

> --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
> +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
> @@ -1491,13 +1491,29 @@ static void rtw8822c_false_alarm_statistics(struct rtw_dev *rtwdev)
>  	u32 cck_enable;
>  	u32 cck_fa_cnt;
>  	u32 ofdm_fa_cnt;
> -	u32 ofdm_tx_counter;
> +	u32 ofdm_fa_cnt1, ofdm_fa_cnt2, ofdm_fa_cnt3, ofdm_fa_cnt4, ofdm_fa_cnt5;
> +	u16 parity_fail, rate_illegal, crc8_fail, mcs_fail, sb_search_fail,
> +	    fast_fsync, crc8_fail_vhta, mcs_fail_vht;
>  
>  	cck_enable = rtw_read32(rtwdev, REG_ENCCK) & BIT_CCK_BLK_EN;
>  	cck_fa_cnt = rtw_read16(rtwdev, REG_CCK_FACNT);
> -	ofdm_fa_cnt = rtw_read16(rtwdev, REG_OFDM_FACNT);
> -	ofdm_tx_counter = rtw_read16(rtwdev, REG_OFDM_TXCNT);
> -	ofdm_fa_cnt -= ofdm_tx_counter;
> +
> +	ofdm_fa_cnt1 = rtw_read32(rtwdev, REG_OFDM_FACNT1);
> +	ofdm_fa_cnt2 = rtw_read32(rtwdev, REG_OFDM_FACNT2);
> +	ofdm_fa_cnt3 = rtw_read32(rtwdev, REG_OFDM_FACNT3);
> +	ofdm_fa_cnt4 = rtw_read32(rtwdev, REG_OFDM_FACNT4);
> +	ofdm_fa_cnt5 = rtw_read32(rtwdev, REG_OFDM_FACNT5);
> +
> +	parity_fail = (ofdm_fa_cnt1 & 0xffff0000) >> 16;
> +	rate_illegal = (ofdm_fa_cnt2 & 0xffff);
> +	crc8_fail = (ofdm_fa_cnt2 & 0xffff0000) >> 16;
> +	crc8_fail_vhta = (ofdm_fa_cnt3 & 0xffff);
> +	mcs_fail = (ofdm_fa_cnt4 & 0xffff);
> +	mcs_fail_vht = (ofdm_fa_cnt4 & 0xffff0000) >> 16;
> +	fast_fsync = (ofdm_fa_cnt5 & 0xffff);
> +	sb_search_fail = (ofdm_fa_cnt5 & 0xffff0000) >> 16;

No magic numbers, please. IMO the cleanest way is to use create defines
using GENMASK() and FIELD_GET(), that way the values are proper
documented. An example (but not compile tested so can be buggy!):

#define OFDM_FA_CNT1_PARITY_FAIL GENMASK(31, 16)

parity_fail = FIELD_GET(OFDM_FA_CNT1_PARITY_FAIL, ofdm_fa_cnt1);

-- 
Kalle Valo

^ permalink raw reply

* Re: [BISECTED REGRESSION] b43legacy broken on G4 PowerBook
From: Christoph Hellwig @ 2019-06-12  6:55 UTC (permalink / raw)
  To: Larry Finger
  Cc: Christoph Hellwig, Aaro Koskinen, Christian Zigotzky,
	Michael Ellerman, linux-kernel, linux-wireless, linuxppc-dev
In-Reply-To: <5aaa600b-5b59-1f68-454f-20403c318f1a@lwfinger.net>

On Tue, Jun 11, 2019 at 05:20:12PM -0500, Larry Finger wrote:
> Your first patch did not work as the configuration does not have 
> CONFIG_ZONE_DMA. As a result, the initial value of min_mask always starts 
> at 32 bits and is taken down to 31 with the maximum pfn minimization. When 
> I forced the initial value of min_mask to 30 bits, the device worked.

Ooops, yes.  But I think we could just enable ZONE_DMA on 32-bit
powerpc.  Crude enablement hack below:

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 8c1c636308c8..1dd71a98b70c 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -372,7 +372,7 @@ config PPC_ADV_DEBUG_DAC_RANGE
 
 config ZONE_DMA
 	bool
-	default y if PPC_BOOK3E_64
+	default y
 
 config PGTABLE_LEVELS
 	int

^ permalink raw reply related

* [PATCH 03/11] rtw88: add beacon function setting
From: yhchuang @ 2019-06-12  6:45 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless
In-Reply-To: <1560321917-17751-1-git-send-email-yhchuang@realtek.com>

From: Chin-Yen Lee <timlee@realtek.com>

Add beacon function setting routines for each hardware port.
If beacon function is not enabled, the hardware is not able
to synchronize with AP's beacon and can miss the beacons
under some scenarios such as PS mode.

For AP and Adhoc modes that require to send beacons, do not
update the TSF, otherwise the beacon interval may be affected.

Signed-off-by: Chin-Yen Lee <timlee@realtek.com>
Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
 drivers/net/wireless/realtek/rtw88/mac80211.c | 13 +++++++++++++
 drivers/net/wireless/realtek/rtw88/main.c     |  5 +++++
 drivers/net/wireless/realtek/rtw88/main.h     |  3 +++
 3 files changed, 21 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c
index 61436bb..abe6a14 100644
--- a/drivers/net/wireless/realtek/rtw88/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
@@ -85,30 +85,35 @@ static const struct rtw_vif_port rtw_vif_port[] = {
 		.bssid		= {.addr = 0x0618},
 		.net_type	= {.addr = 0x0100, .mask = 0x30000},
 		.aid		= {.addr = 0x06a8, .mask = 0x7ff},
+		.bcn_ctrl	= {.addr = 0x0550, .mask = 0xff},
 	},
 	[1] = {
 		.mac_addr	= {.addr = 0x0700},
 		.bssid		= {.addr = 0x0708},
 		.net_type	= {.addr = 0x0100, .mask = 0xc0000},
 		.aid		= {.addr = 0x0710, .mask = 0x7ff},
+		.bcn_ctrl	= {.addr = 0x0551, .mask = 0xff},
 	},
 	[2] = {
 		.mac_addr	= {.addr = 0x1620},
 		.bssid		= {.addr = 0x1628},
 		.net_type	= {.addr = 0x1100, .mask = 0x3},
 		.aid		= {.addr = 0x1600, .mask = 0x7ff},
+		.bcn_ctrl	= {.addr = 0x0578, .mask = 0xff},
 	},
 	[3] = {
 		.mac_addr	= {.addr = 0x1630},
 		.bssid		= {.addr = 0x1638},
 		.net_type	= {.addr = 0x1100, .mask = 0xc},
 		.aid		= {.addr = 0x1604, .mask = 0x7ff},
+		.bcn_ctrl	= {.addr = 0x0579, .mask = 0xff},
 	},
 	[4] = {
 		.mac_addr	= {.addr = 0x1640},
 		.bssid		= {.addr = 0x1648},
 		.net_type	= {.addr = 0x1100, .mask = 0x30},
 		.aid		= {.addr = 0x1608, .mask = 0x7ff},
+		.bcn_ctrl	= {.addr = 0x057a, .mask = 0xff},
 	},
 };
 
@@ -120,6 +125,7 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw,
 	enum rtw_net_type net_type;
 	u32 config = 0;
 	u8 port = 0;
+	u8 bcn_ctrl = 0;
 
 	rtwvif->port = port;
 	rtwvif->vif = vif;
@@ -136,13 +142,16 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw,
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_MESH_POINT:
 		net_type = RTW_NET_AP_MODE;
+		bcn_ctrl = BIT_EN_BCN_FUNCTION | BIT_DIS_TSF_UDT;
 		break;
 	case NL80211_IFTYPE_ADHOC:
 		net_type = RTW_NET_AD_HOC;
+		bcn_ctrl = BIT_EN_BCN_FUNCTION | BIT_DIS_TSF_UDT;
 		break;
 	case NL80211_IFTYPE_STATION:
 	default:
 		net_type = RTW_NET_NO_LINK;
+		bcn_ctrl = BIT_EN_BCN_FUNCTION;
 		break;
 	}
 
@@ -150,6 +159,8 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw,
 	config |= PORT_SET_MAC_ADDR;
 	rtwvif->net_type = net_type;
 	config |= PORT_SET_NET_TYPE;
+	rtwvif->bcn_ctrl = bcn_ctrl;
+	config |= PORT_SET_BCN_CTRL;
 	rtw_vif_port_config(rtwdev, rtwvif, config);
 
 	mutex_unlock(&rtwdev->mutex);
@@ -173,6 +184,8 @@ static void rtw_ops_remove_interface(struct ieee80211_hw *hw,
 	config |= PORT_SET_MAC_ADDR;
 	rtwvif->net_type = RTW_NET_NO_LINK;
 	config |= PORT_SET_NET_TYPE;
+	rtwvif->bcn_ctrl = 0;
+	config |= PORT_SET_BCN_CTRL;
 	rtw_vif_port_config(rtwdev, rtwvif, config);
 
 	mutex_unlock(&rtwdev->mutex);
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index 306d799..b8e0519 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -308,6 +308,11 @@ void rtw_vif_port_config(struct rtw_dev *rtwdev,
 		mask = rtwvif->conf->aid.mask;
 		rtw_write32_mask(rtwdev, addr, mask, rtwvif->aid);
 	}
+	if (config & PORT_SET_BCN_CTRL) {
+		addr = rtwvif->conf->bcn_ctrl.addr;
+		mask = rtwvif->conf->bcn_ctrl.mask;
+		rtw_write8_mask(rtwdev, addr, mask, rtwvif->bcn_ctrl);
+	}
 }
 
 static u8 hw_bw_cap_to_bitamp(u8 bw_cap)
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index 00fc77f..414d21f 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -431,6 +431,7 @@ enum rtw_vif_port_set {
 	PORT_SET_BSSID		= BIT(1),
 	PORT_SET_NET_TYPE	= BIT(2),
 	PORT_SET_AID		= BIT(3),
+	PORT_SET_BCN_CTRL	= BIT(4),
 };
 
 struct rtw_vif_port {
@@ -438,6 +439,7 @@ struct rtw_vif_port {
 	struct rtw_hw_reg bssid;
 	struct rtw_hw_reg net_type;
 	struct rtw_hw_reg aid;
+	struct rtw_hw_reg bcn_ctrl;
 };
 
 struct rtw_tx_pkt_info {
@@ -591,6 +593,7 @@ struct rtw_vif {
 	u8 mac_addr[ETH_ALEN];
 	u8 bssid[ETH_ALEN];
 	u8 port;
+	u8 bcn_ctrl;
 	const struct rtw_vif_port *conf;
 
 	struct rtw_traffic_stats stats;
-- 
2.7.4


^ permalink raw reply related

* [PATCH 05/11] rtw88: 8822c: update channel and bandwidth BB setting
From: yhchuang @ 2019-06-12  6:45 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless
In-Reply-To: <1560321917-17751-1-git-send-email-yhchuang@realtek.com>

From: Chien-Hsun Liao <ben.liao@realtek.com>

In 2G channels, the cck source and rxagc should be set to different
values based on different bandwidth to increase the performance of rx
sensitivity.

To improve rx throughput performance, the values of sbd subtune and
pt_opt should be changed in different bandwidth.

Signed-off-by: Chien-Hsun Liao <ben.liao@realtek.com>
Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
 drivers/net/wireless/realtek/rtw88/rtw8822c.c | 56 +++++++++++++++++++++++----
 drivers/net/wireless/realtek/rtw88/rtw8822c.h |  7 ++++
 2 files changed, 55 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index b4f7242e..86acf60 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -1015,8 +1015,28 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
 		rtw_write32_clr(rtwdev, REG_CCKTXONLY, BIT_BB_CCK_CHECK_EN);
 		rtw_write32_mask(rtwdev, REG_CCAMSK, 0x3F000000, 0xF);
 
-		rtw_write32_mask(rtwdev, REG_RXAGCCTL0, 0x1f0, 0x0);
-		rtw_write32_mask(rtwdev, REG_RXAGCCTL, 0x1f0, 0x0);
+		switch (bw) {
+		case RTW_CHANNEL_WIDTH_20:
+			rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BIT_RXAGC_CCK,
+					 0x5);
+			rtw_write32_mask(rtwdev, REG_RXAGCCTL, BIT_RXAGC_CCK,
+					 0x5);
+			rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BIT_RXAGC_OFDM,
+					 0x6);
+			rtw_write32_mask(rtwdev, REG_RXAGCCTL, BIT_RXAGC_OFDM,
+					 0x6);
+			break;
+		case RTW_CHANNEL_WIDTH_40:
+			rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BIT_RXAGC_CCK,
+					 0x4);
+			rtw_write32_mask(rtwdev, REG_RXAGCCTL, BIT_RXAGC_CCK,
+					 0x4);
+			rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BIT_RXAGC_OFDM,
+					 0x0);
+			rtw_write32_mask(rtwdev, REG_RXAGCCTL, BIT_RXAGC_OFDM,
+					 0x0);
+			break;
+		}
 		if (channel == 13 || channel == 14)
 			rtw_write32_mask(rtwdev, REG_SCOTRK, 0xfff, 0x969);
 		else if (channel == 11 || channel == 12)
@@ -1061,14 +1081,20 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
 		rtw_write32_mask(rtwdev, REG_CCAMSK, 0x3F000000, 0x22);
 		rtw_write32_mask(rtwdev, REG_TXDFIR0, 0x70, 0x3);
 		if (channel >= 36 && channel <= 64) {
-			rtw_write32_mask(rtwdev, REG_RXAGCCTL0, 0x1f0, 0x1);
-			rtw_write32_mask(rtwdev, REG_RXAGCCTL, 0x1f0, 0x1);
+			rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BIT_RXAGC_OFDM,
+					 0x1);
+			rtw_write32_mask(rtwdev, REG_RXAGCCTL, BIT_RXAGC_OFDM,
+					 0x1);
 		} else if (channel >= 100 && channel <= 144) {
-			rtw_write32_mask(rtwdev, REG_RXAGCCTL0, 0x1f0, 0x2);
-			rtw_write32_mask(rtwdev, REG_RXAGCCTL, 0x1f0, 0x2);
+			rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BIT_RXAGC_OFDM,
+					 0x2);
+			rtw_write32_mask(rtwdev, REG_RXAGCCTL, BIT_RXAGC_OFDM,
+					 0x2);
 		} else if (channel >= 149) {
-			rtw_write32_mask(rtwdev, REG_RXAGCCTL0, 0x1f0, 0x3);
-			rtw_write32_mask(rtwdev, REG_RXAGCCTL, 0x1f0, 0x3);
+			rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BIT_RXAGC_OFDM,
+					 0x3);
+			rtw_write32_mask(rtwdev, REG_RXAGCCTL, BIT_RXAGC_OFDM,
+					 0x3);
 		}
 
 		if (channel >= 36 && channel <= 51)
@@ -1092,6 +1118,9 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
 		rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xffc0, 0x0);
 		rtw_write32_mask(rtwdev, REG_TXCLK, 0x700, 0x7);
 		rtw_write32_mask(rtwdev, REG_TXCLK, 0x700000, 0x6);
+		rtw_write32_mask(rtwdev, REG_CCK_SOURCE, BIT(30), 0x0);
+		rtw_write32_mask(rtwdev, REG_SBD, BIT_SUBTUNE, 0x1);
+		rtw_write32_mask(rtwdev, REG_PT_CHSMO, BIT_PT_OPT, 0x0);
 		break;
 	case RTW_CHANNEL_WIDTH_40:
 		rtw_write32_mask(rtwdev, REG_CCKSB, BIT(4),
@@ -1100,12 +1129,17 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
 		rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xc0, 0x0);
 		rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xff00,
 				 (primary_ch_idx | (primary_ch_idx << 4)));
+		rtw_write32_mask(rtwdev, REG_CCK_SOURCE, BIT(30), 0x1);
+		rtw_write32_mask(rtwdev, REG_SBD, BIT_SUBTUNE, 0x1);
+		rtw_write32_mask(rtwdev, REG_PT_CHSMO, BIT_PT_OPT, 0x1);
 		break;
 	case RTW_CHANNEL_WIDTH_80:
 		rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xf, 0xa);
 		rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xc0, 0x0);
 		rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xff00,
 				 (primary_ch_idx | (primary_ch_idx << 4)));
+		rtw_write32_mask(rtwdev, REG_SBD, BIT_SUBTUNE, 0x6);
+		rtw_write32_mask(rtwdev, REG_PT_CHSMO, BIT_PT_OPT, 0x1);
 		break;
 	case RTW_CHANNEL_WIDTH_5:
 		rtw_write32_mask(rtwdev, REG_DFIRBW, 0x3FF0, 0x2AB);
@@ -1113,6 +1147,9 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
 		rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xffc0, 0x1);
 		rtw_write32_mask(rtwdev, REG_TXCLK, 0x700, 0x4);
 		rtw_write32_mask(rtwdev, REG_TXCLK, 0x700000, 0x4);
+		rtw_write32_mask(rtwdev, REG_CCK_SOURCE, BIT(30), 0x0);
+		rtw_write32_mask(rtwdev, REG_SBD, BIT_SUBTUNE, 0x1);
+		rtw_write32_mask(rtwdev, REG_PT_CHSMO, BIT_PT_OPT, 0x0);
 		break;
 	case RTW_CHANNEL_WIDTH_10:
 		rtw_write32_mask(rtwdev, REG_DFIRBW, 0x3FF0, 0x2AB);
@@ -1120,6 +1157,9 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
 		rtw_write32_mask(rtwdev, REG_TXBWCTL, 0xffc0, 0x2);
 		rtw_write32_mask(rtwdev, REG_TXCLK, 0x700, 0x6);
 		rtw_write32_mask(rtwdev, REG_TXCLK, 0x700000, 0x5);
+		rtw_write32_mask(rtwdev, REG_CCK_SOURCE, BIT(30), 0x0);
+		rtw_write32_mask(rtwdev, REG_SBD, BIT_SUBTUNE, 0x1);
+		rtw_write32_mask(rtwdev, REG_PT_CHSMO, BIT_PT_OPT, 0x0);
 		break;
 	}
 }
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.h b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
index d3bd985..5fe6acb 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
@@ -133,6 +133,8 @@ struct rtw8822c_efuse {
 #define REG_DYMPRITH	0x86c
 #define REG_DYMENTH0	0x870
 #define REG_DYMENTH	0x874
+#define REG_SBD		0x88c
+#define BIT_SUBTUNE	0xf000
 #define REG_DYMTHMIN	0x8a4
 #define REG_TXBWCTL	0x9b0
 #define REG_TXCLK	0x9b4
@@ -140,12 +142,16 @@ struct rtw8822c_efuse {
 #define REG_MRCM	0xc38
 #define REG_AGCSWSH	0xc44
 #define REG_ANTWTPD	0xc54
+#define REG_PT_CHSMO	0xcbc
+#define BIT_PT_OPT		BIT(21)
 #define REG_ORITXCODE	0x1800
 #define REG_3WIRE	0x180c
 #define BIT_3WIRE_TX_EN		BIT(0)
 #define BIT_3WIRE_RX_EN		BIT(1)
 #define BIT_3WIRE_PI_ON		BIT(28)
 #define REG_RXAGCCTL0	0x18ac
+#define BIT_RXAGC_CCK	0xf000
+#define BIT_RXAGC_OFDM	0x1f0
 #define REG_CCKSB	0x1a00
 #define REG_RXCCKSEL	0x1a04
 #define REG_BGCTRL	0x1a14
@@ -164,6 +170,7 @@ struct rtw8822c_efuse {
 #define REG_TXF5	0x1aa0
 #define REG_TXF6	0x1aac
 #define REG_TXF7	0x1ab0
+#define REG_CCK_SOURCE	0x1abc
 #define REG_TXANT	0x1c28
 #define REG_ENCCK	0x1c3c
 #define BIT_CCK_BLK_EN		BIT(1)
-- 
2.7.4


^ permalink raw reply related

* [PATCH 06/11] rtw88: 8822c: disable rx clock gating before counter reset
From: yhchuang @ 2019-06-12  6:45 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless
In-Reply-To: <1560321917-17751-1-git-send-email-yhchuang@realtek.com>

From: Yan-Hsuan Chuang <yhchuang@realtek.com>

Driver Could fail to reset counter if rx clock gating is not disabled.
So we need to disable rx clock gating before resetting counters.
Otherwise counters may increase unexpected.

Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
 drivers/net/wireless/realtek/rtw88/rtw8822c.c | 4 ++++
 drivers/net/wireless/realtek/rtw88/rtw8822c.h | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index 86acf60..b9185b2 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -1508,8 +1508,12 @@ static void rtw8822c_false_alarm_statistics(struct rtw_dev *rtwdev)
 	rtw_write32_mask(rtwdev, REG_CCANRX, BIT_CCK_FA_RST, 2);
 	rtw_write32_mask(rtwdev, REG_CCANRX, BIT_OFDM_FA_RST, 0);
 	rtw_write32_mask(rtwdev, REG_CCANRX, BIT_OFDM_FA_RST, 2);
+
+	/* disable rx clk gating to reset counters */
+	rtw_write32_clr(rtwdev, REG_RX_BREAK, BIT_COM_RX_GCK_EN);
 	rtw_write32_set(rtwdev, REG_CNT_CTRL, BIT_ALL_CNT_RST);
 	rtw_write32_clr(rtwdev, REG_CNT_CTRL, BIT_ALL_CNT_RST);
+	rtw_write32_set(rtwdev, REG_RX_BREAK, BIT_COM_RX_GCK_EN);
 }
 
 static void rtw8822c_do_iqk(struct rtw_dev *rtwdev)
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.h b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
index 5fe6acb..bf41359 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
@@ -176,6 +176,8 @@ struct rtw8822c_efuse {
 #define BIT_CCK_BLK_EN		BIT(1)
 #define BIT_CCK_OFDM_BLK_EN	(BIT(0) | BIT(1))
 #define REG_CCAMSK	0x1c80
+#define REG_RX_BREAK	0x1d2c
+#define BIT_COM_RX_GCK_EN	BIT(31)
 #define REG_RXFNCTL	0x1d30
 #define REG_RXIGI	0x1d70
 #define REG_ENFN	0x1e24
-- 
2.7.4


^ permalink raw reply related

* [PATCH 09/11] rtw88: restore DACK results to save time
From: yhchuang @ 2019-06-12  6:45 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless
In-Reply-To: <1560321917-17751-1-git-send-email-yhchuang@realtek.com>

From: Yan-Hsuan Chuang <yhchuang@realtek.com>

DACK is done right after the hardware has been turned on, which
means it will be done every time we leave the IDLE state.
But it takes ~2 seconds to finish DACK.

We can back up the results and restore them. And it only takes a few
milliseconds to restore the results to the hardware, saving a lot of
time.

Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
 drivers/net/wireless/realtek/rtw88/main.h     |   8 +
 drivers/net/wireless/realtek/rtw88/rtw8822c.c | 351 +++++++++++++++++++++++++-
 drivers/net/wireless/realtek/rtw88/rtw8822c.h |   8 +
 3 files changed, 355 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index 414d21f..92730507 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -841,6 +841,9 @@ struct rtw_chip_info {
 	u32 rfe_defs_size;
 };
 
+#define DACK_MSBK_BACKUP_NUM	0xf
+#define DACK_DCK_BACKUP_NUM	0x2
+
 struct rtw_dm_info {
 	u32 cck_fa_cnt;
 	u32 ofdm_fa_cnt;
@@ -856,6 +859,11 @@ struct rtw_dm_info {
 
 	u8 cck_gi_u_bnd;
 	u8 cck_gi_l_bnd;
+
+	/* backup dack results for each path and I/Q */
+	u32 dack_adck[RTW_RF_PATH_MAX];
+	u16 dack_msbk[RTW_RF_PATH_MAX][2][DACK_MSBK_BACKUP_NUM];
+	u8 dack_dck[RTW_RF_PATH_MAX][2][DACK_DCK_BACKUP_NUM];
 };
 
 struct rtw_efuse {
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index 4896f25..8198f2e 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -203,7 +203,7 @@ static void rtw8822c_dac_iq_offset(struct rtw_dev *rtwdev, u32 *vec, u32 *val)
 	*val = t;
 }
 
-static u32 rtw8822c_get_path_base_addr(u8 path)
+static u32 rtw8822c_get_path_write_addr(u8 path)
 {
 	u32 base_addr;
 
@@ -222,6 +222,25 @@ static u32 rtw8822c_get_path_base_addr(u8 path)
 	return base_addr;
 }
 
+static u32 rtw8822c_get_path_read_addr(u8 path)
+{
+	u32 base_addr;
+
+	switch (path) {
+	case RF_PATH_A:
+		base_addr = 0x2800;
+		break;
+	case RF_PATH_B:
+		base_addr = 0x4500;
+		break;
+	default:
+		WARN_ON(1);
+		return -1;
+	}
+
+	return base_addr;
+}
+
 static bool rtw8822c_dac_iq_check(struct rtw_dev *rtwdev, u32 value)
 {
 	bool ret = true;
@@ -316,8 +335,6 @@ static void rtw8822c_dac_cal_rf_mode(struct rtw_dev *rtwdev,
 	u32 iv[DACK_SN_8822C], qv[DACK_SN_8822C];
 	u32 rf_a, rf_b;
 
-	mdelay(10);
-
 	rf_a = rtw_read_rf(rtwdev, RF_PATH_A, 0x0, RFREG_MASK);
 	rf_b = rtw_read_rf(rtwdev, RF_PATH_B, 0x0, RFREG_MASK);
 
@@ -347,6 +364,7 @@ static void rtw8822c_dac_bb_setting(struct rtw_dev *rtwdev)
 static void rtw8822c_dac_cal_adc(struct rtw_dev *rtwdev,
 				 u8 path, u32 *adc_ic, u32 *adc_qc)
 {
+	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
 	u32 ic = 0, qc = 0, temp = 0;
 	u32 base_addr;
 	u32 path_sel;
@@ -354,7 +372,7 @@ static void rtw8822c_dac_cal_adc(struct rtw_dev *rtwdev,
 
 	rtw_dbg(rtwdev, RTW_DBG_RFK, "[DACK] ADCK path(%d)\n", path);
 
-	base_addr = rtw8822c_get_path_base_addr(path);
+	base_addr = rtw8822c_get_path_write_addr(path);
 	switch (path) {
 	case RF_PATH_A:
 		path_sel = 0xa0000;
@@ -396,6 +414,7 @@ static void rtw8822c_dac_cal_adc(struct rtw_dev *rtwdev,
 		}
 		temp = (ic & 0x3ff) | ((qc & 0x3ff) << 10);
 		rtw_write32(rtwdev, base_addr + 0x68, temp);
+		dm_info->dack_adck[path] = temp;
 		rtw_dbg(rtwdev, RTW_DBG_RFK, "[DACK] ADCK 0x%08x=0x08%x\n",
 			base_addr + 0x68, temp);
 		/* check ADC DC offset */
@@ -422,10 +441,14 @@ static void rtw8822c_dac_cal_adc(struct rtw_dev *rtwdev,
 
 static void rtw8822c_dac_cal_step1(struct rtw_dev *rtwdev, u8 path)
 {
+	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
 	u32 base_addr;
+	u32 read_addr;
 
-	base_addr = rtw8822c_get_path_base_addr(path);
+	base_addr = rtw8822c_get_path_write_addr(path);
+	read_addr = rtw8822c_get_path_read_addr(path);
 
+	rtw_write32(rtwdev, base_addr + 0x68, dm_info->dack_adck[path]);
 	rtw_write32(rtwdev, base_addr + 0x0c, 0xdff00220);
 	if (path == RF_PATH_A) {
 		rtw_write32(rtwdev, base_addr + 0x60, 0xf0040ff0);
@@ -447,11 +470,13 @@ static void rtw8822c_dac_cal_step1(struct rtw_dev *rtwdev, u8 path)
 	rtw_write32(rtwdev, base_addr + 0xcc, 0x0a11fb89);
 	mdelay(1);
 	rtw_write32(rtwdev, base_addr + 0xb8, 0x62000000);
-	mdelay(20);
 	rtw_write32(rtwdev, base_addr + 0xd4, 0x62000000);
 	mdelay(20);
+	if (!check_hw_ready(rtwdev, read_addr + 0x08, 0x7fff80, 0xffff) ||
+	    !check_hw_ready(rtwdev, read_addr + 0x34, 0x7fff80, 0xffff))
+		rtw_err(rtwdev, "failed to wait for dack ready\n");
 	rtw_write32(rtwdev, base_addr + 0xb8, 0x02000000);
-	mdelay(20);
+	mdelay(1);
 	rtw_write32(rtwdev, base_addr + 0xbc, 0x0008ff87);
 	rtw_write32(rtwdev, 0x9b4, 0xdb6db600);
 	rtw_write32(rtwdev, base_addr + 0x10, 0x02d508c5);
@@ -465,7 +490,7 @@ static void rtw8822c_dac_cal_step2(struct rtw_dev *rtwdev,
 	u32 base_addr;
 	u32 ic, qc, ic_in, qc_in;
 
-	base_addr = rtw8822c_get_path_base_addr(path);
+	base_addr = rtw8822c_get_path_write_addr(path);
 	rtw_write32_mask(rtwdev, base_addr + 0xbc, 0xf0000000, 0x0);
 	rtw_write32_mask(rtwdev, base_addr + 0xc0, 0xf, 0x8);
 	rtw_write32_mask(rtwdev, base_addr + 0xd8, 0xf0000000, 0x0);
@@ -514,10 +539,12 @@ static void rtw8822c_dac_cal_step3(struct rtw_dev *rtwdev, u8 path,
 				   u32 *i_out, u32 *q_out)
 {
 	u32 base_addr;
+	u32 read_addr;
 	u32 ic, qc;
 	u32 temp;
 
-	base_addr = rtw8822c_get_path_base_addr(path);
+	base_addr = rtw8822c_get_path_write_addr(path);
+	read_addr = rtw8822c_get_path_read_addr(path);
 	ic = *ic_in;
 	qc = *qc_in;
 
@@ -542,11 +569,13 @@ static void rtw8822c_dac_cal_step3(struct rtw_dev *rtwdev, u8 path,
 	rtw_write32(rtwdev, base_addr + 0xcc, 0x0a11fb89);
 	mdelay(1);
 	rtw_write32(rtwdev, base_addr + 0xb8, 0x62000000);
-	mdelay(20);
 	rtw_write32(rtwdev, base_addr + 0xd4, 0x62000000);
 	mdelay(20);
+	if (!check_hw_ready(rtwdev, read_addr + 0x24, 0x07f80000, ic) ||
+	    !check_hw_ready(rtwdev, read_addr + 0x50, 0x07f80000, qc))
+		rtw_err(rtwdev, "failed to write IQ vector to hardware\n");
 	rtw_write32(rtwdev, base_addr + 0xb8, 0x02000000);
-	mdelay(20);
+	mdelay(1);
 	rtw_write32_mask(rtwdev, base_addr + 0xbc, 0xe, 0x3);
 	rtw_write32(rtwdev, 0x9b4, 0xdb6db600);
 
@@ -583,7 +612,7 @@ static void rtw8822c_dac_cal_step3(struct rtw_dev *rtwdev, u8 path,
 
 static void rtw8822c_dac_cal_step4(struct rtw_dev *rtwdev, u8 path)
 {
-	u32 base_addr = rtw8822c_get_path_base_addr(path);
+	u32 base_addr = rtw8822c_get_path_write_addr(path);
 
 	rtw_write32(rtwdev, base_addr + 0x68, 0x0);
 	rtw_write32(rtwdev, base_addr + 0x10, 0x02d508c4);
@@ -591,6 +620,296 @@ static void rtw8822c_dac_cal_step4(struct rtw_dev *rtwdev, u8 path)
 	rtw_write32_mask(rtwdev, base_addr + 0x30, BIT(30), 0x1);
 }
 
+static void rtw8822c_dac_cal_backup_vec(struct rtw_dev *rtwdev,
+					u8 path, u8 vec, u32 w_addr, u32 r_addr)
+{
+	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+	u16 val;
+	u32 i;
+
+	if (WARN_ON(vec >= 2))
+		return;
+
+	for (i = 0; i < DACK_MSBK_BACKUP_NUM; i++) {
+		rtw_write32_mask(rtwdev, w_addr, 0xf0000000, i);
+		val = (u16)rtw_read32_mask(rtwdev, r_addr, 0x7fc0000);
+		dm_info->dack_msbk[path][vec][i] = val;
+	}
+}
+
+static void rtw8822c_dac_cal_backup_path(struct rtw_dev *rtwdev, u8 path)
+{
+	u32 w_off = 0x1c;
+	u32 r_off = 0x2c;
+	u32 w_addr, r_addr;
+
+	if (WARN_ON(path >= 2))
+		return;
+
+	/* backup I vector */
+	w_addr = rtw8822c_get_path_write_addr(path) + 0xb0;
+	r_addr = rtw8822c_get_path_read_addr(path) + 0x10;
+	rtw8822c_dac_cal_backup_vec(rtwdev, path, 0, w_addr, r_addr);
+
+	/* backup Q vector */
+	w_addr = rtw8822c_get_path_write_addr(path) + 0xb0 + w_off;
+	r_addr = rtw8822c_get_path_read_addr(path) + 0x10 + r_off;
+	rtw8822c_dac_cal_backup_vec(rtwdev, path, 1, w_addr, r_addr);
+}
+
+static void rtw8822c_dac_cal_backup_dck(struct rtw_dev *rtwdev)
+{
+	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+	u8 val;
+
+	val = (u8)rtw_read32_mask(rtwdev, REG_DCKA_I_0, 0xf0000000);
+	dm_info->dack_dck[RF_PATH_A][0][0] = val;
+	val = (u8)rtw_read32_mask(rtwdev, REG_DCKA_I_1, 0xf);
+	dm_info->dack_dck[RF_PATH_A][0][1] = val;
+	val = (u8)rtw_read32_mask(rtwdev, REG_DCKA_Q_0, 0xf0000000);
+	dm_info->dack_dck[RF_PATH_A][1][0] = val;
+	val = (u8)rtw_read32_mask(rtwdev, REG_DCKA_Q_1, 0xf);
+	dm_info->dack_dck[RF_PATH_A][1][1] = val;
+
+	val = (u8)rtw_read32_mask(rtwdev, REG_DCKB_I_0, 0xf0000000);
+	dm_info->dack_dck[RF_PATH_B][0][0] = val;
+	val = (u8)rtw_read32_mask(rtwdev, REG_DCKB_I_1, 0xf);
+	dm_info->dack_dck[RF_PATH_B][1][0] = val;
+	val = (u8)rtw_read32_mask(rtwdev, REG_DCKB_Q_0, 0xf0000000);
+	dm_info->dack_dck[RF_PATH_B][0][1] = val;
+	val = (u8)rtw_read32_mask(rtwdev, REG_DCKB_Q_1, 0xf);
+	dm_info->dack_dck[RF_PATH_B][1][1] = val;
+}
+
+static void rtw8822c_dac_cal_backup(struct rtw_dev *rtwdev)
+{
+	u32 temp[3];
+
+	temp[0] = rtw_read32(rtwdev, 0x1860);
+	temp[1] = rtw_read32(rtwdev, 0x4160);
+	temp[2] = rtw_read32(rtwdev, 0x9b4);
+
+	/* set clock */
+	rtw_write32(rtwdev, 0x9b4, 0xdb66db00);
+
+	/* backup path-A I/Q */
+	rtw_write32_clr(rtwdev, 0x1830, BIT(30));
+	rtw_write32_mask(rtwdev, 0x1860, 0xfc000000, 0x3c);
+	rtw8822c_dac_cal_backup_path(rtwdev, RF_PATH_A);
+
+	/* backup path-B I/Q */
+	rtw_write32_clr(rtwdev, 0x4130, BIT(30));
+	rtw_write32_mask(rtwdev, 0x4160, 0xfc000000, 0x3c);
+	rtw8822c_dac_cal_backup_path(rtwdev, RF_PATH_B);
+
+	rtw8822c_dac_cal_backup_dck(rtwdev);
+	rtw_write32_set(rtwdev, 0x1830, BIT(30));
+	rtw_write32_set(rtwdev, 0x4130, BIT(30));
+
+	rtw_write32(rtwdev, 0x1860, temp[0]);
+	rtw_write32(rtwdev, 0x4160, temp[1]);
+	rtw_write32(rtwdev, 0x9b4, temp[2]);
+}
+
+static void rtw8822c_dac_cal_restore_dck(struct rtw_dev *rtwdev)
+{
+	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+	u8 val;
+
+	rtw_write32_set(rtwdev, REG_DCKA_I_0, BIT(19));
+	val = dm_info->dack_dck[RF_PATH_A][0][0];
+	rtw_write32_mask(rtwdev, REG_DCKA_I_0, 0xf0000000, val);
+	val = dm_info->dack_dck[RF_PATH_A][0][1];
+	rtw_write32_mask(rtwdev, REG_DCKA_I_1, 0xf, val);
+
+	rtw_write32_set(rtwdev, REG_DCKA_Q_0, BIT(19));
+	val = dm_info->dack_dck[RF_PATH_A][1][0];
+	rtw_write32_mask(rtwdev, REG_DCKA_Q_0, 0xf0000000, val);
+	val = dm_info->dack_dck[RF_PATH_A][1][1];
+	rtw_write32_mask(rtwdev, REG_DCKA_Q_1, 0xf, val);
+
+	rtw_write32_set(rtwdev, REG_DCKB_I_0, BIT(19));
+	val = dm_info->dack_dck[RF_PATH_B][0][0];
+	rtw_write32_mask(rtwdev, REG_DCKB_I_0, 0xf0000000, val);
+	val = dm_info->dack_dck[RF_PATH_B][0][1];
+	rtw_write32_mask(rtwdev, REG_DCKB_I_1, 0xf, val);
+
+	rtw_write32_set(rtwdev, REG_DCKB_Q_0, BIT(19));
+	val = dm_info->dack_dck[RF_PATH_B][1][0];
+	rtw_write32_mask(rtwdev, REG_DCKB_Q_0, 0xf0000000, val);
+	val = dm_info->dack_dck[RF_PATH_B][1][1];
+	rtw_write32_mask(rtwdev, REG_DCKB_Q_1, 0xf, val);
+}
+
+static void rtw8822c_dac_cal_restore_prepare(struct rtw_dev *rtwdev)
+{
+	rtw_write32(rtwdev, 0x9b4, 0xdb66db00);
+
+	rtw_write32_mask(rtwdev, 0x18b0, BIT(27), 0x0);
+	rtw_write32_mask(rtwdev, 0x18cc, BIT(27), 0x0);
+	rtw_write32_mask(rtwdev, 0x41b0, BIT(27), 0x0);
+	rtw_write32_mask(rtwdev, 0x41cc, BIT(27), 0x0);
+
+	rtw_write32_mask(rtwdev, 0x1830, BIT(30), 0x0);
+	rtw_write32_mask(rtwdev, 0x1860, 0xfc000000, 0x3c);
+	rtw_write32_mask(rtwdev, 0x18b4, BIT(0), 0x1);
+	rtw_write32_mask(rtwdev, 0x18d0, BIT(0), 0x1);
+
+	rtw_write32_mask(rtwdev, 0x4130, BIT(30), 0x0);
+	rtw_write32_mask(rtwdev, 0x4160, 0xfc000000, 0x3c);
+	rtw_write32_mask(rtwdev, 0x41b4, BIT(0), 0x1);
+	rtw_write32_mask(rtwdev, 0x41d0, BIT(0), 0x1);
+
+	rtw_write32_mask(rtwdev, 0x18b0, 0xf00, 0x0);
+	rtw_write32_mask(rtwdev, 0x18c0, BIT(14), 0x0);
+	rtw_write32_mask(rtwdev, 0x18cc, 0xf00, 0x0);
+	rtw_write32_mask(rtwdev, 0x18dc, BIT(14), 0x0);
+
+	rtw_write32_mask(rtwdev, 0x18b0, BIT(0), 0x0);
+	rtw_write32_mask(rtwdev, 0x18cc, BIT(0), 0x0);
+	rtw_write32_mask(rtwdev, 0x18b0, BIT(0), 0x1);
+	rtw_write32_mask(rtwdev, 0x18cc, BIT(0), 0x1);
+
+	rtw8822c_dac_cal_restore_dck(rtwdev);
+
+	rtw_write32_mask(rtwdev, 0x18c0, 0x38000, 0x7);
+	rtw_write32_mask(rtwdev, 0x18dc, 0x38000, 0x7);
+	rtw_write32_mask(rtwdev, 0x41c0, 0x38000, 0x7);
+	rtw_write32_mask(rtwdev, 0x41dc, 0x38000, 0x7);
+
+	rtw_write32_mask(rtwdev, 0x18b8, BIT(26) | BIT(25), 0x1);
+	rtw_write32_mask(rtwdev, 0x18d4, BIT(26) | BIT(25), 0x1);
+
+	rtw_write32_mask(rtwdev, 0x41b0, 0xf00, 0x0);
+	rtw_write32_mask(rtwdev, 0x41c0, BIT(14), 0x0);
+	rtw_write32_mask(rtwdev, 0x41cc, 0xf00, 0x0);
+	rtw_write32_mask(rtwdev, 0x41dc, BIT(14), 0x0);
+
+	rtw_write32_mask(rtwdev, 0x41b0, BIT(0), 0x0);
+	rtw_write32_mask(rtwdev, 0x41cc, BIT(0), 0x0);
+	rtw_write32_mask(rtwdev, 0x41b0, BIT(0), 0x1);
+	rtw_write32_mask(rtwdev, 0x41cc, BIT(0), 0x1);
+
+	rtw_write32_mask(rtwdev, 0x41b8, BIT(26) | BIT(25), 0x1);
+	rtw_write32_mask(rtwdev, 0x41d4, BIT(26) | BIT(25), 0x1);
+}
+
+static bool rtw8822c_dac_cal_restore_wait(struct rtw_dev *rtwdev,
+					  u32 target_addr, u32 toggle_addr)
+{
+	u32 cnt = 0;
+
+	do {
+		rtw_write32_mask(rtwdev, toggle_addr, BIT(26) | BIT(25), 0x0);
+		rtw_write32_mask(rtwdev, toggle_addr, BIT(26) | BIT(25), 0x2);
+
+		if (rtw_read32_mask(rtwdev, target_addr, 0xf) == 0x6)
+			return true;
+
+	} while (cnt++ < 100);
+
+	return false;
+}
+
+static bool rtw8822c_dac_cal_restore_path(struct rtw_dev *rtwdev, u8 path)
+{
+	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+	u32 w_off = 0x1c;
+	u32 r_off = 0x2c;
+	u32 w_i, r_i, w_q, r_q;
+	u32 value;
+	u32 i;
+
+	w_i = rtw8822c_get_path_write_addr(path) + 0xb0;
+	r_i = rtw8822c_get_path_read_addr(path) + 0x08;
+	w_q = rtw8822c_get_path_write_addr(path) + 0xb0 + w_off;
+	r_q = rtw8822c_get_path_read_addr(path) + 0x08 + r_off;
+
+	if (!rtw8822c_dac_cal_restore_wait(rtwdev, r_i, w_i + 0x8))
+		return false;
+
+	for (i = 0; i < DACK_MSBK_BACKUP_NUM; i++) {
+		rtw_write32_mask(rtwdev, w_i + 0x4, BIT(2), 0x0);
+		value = dm_info->dack_msbk[path][0][i];
+		rtw_write32_mask(rtwdev, w_i + 0x4, 0xff8, value);
+		rtw_write32_mask(rtwdev, w_i, 0xf0000000, i);
+		rtw_write32_mask(rtwdev, w_i + 0x4, BIT(2), 0x1);
+	}
+
+	rtw_write32_mask(rtwdev, w_i + 0x4, BIT(2), 0x0);
+
+	if (!rtw8822c_dac_cal_restore_wait(rtwdev, r_q, w_q + 0x8))
+		return false;
+
+	for (i = 0; i < DACK_MSBK_BACKUP_NUM; i++) {
+		rtw_write32_mask(rtwdev, w_q + 0x4, BIT(2), 0x0);
+		value = dm_info->dack_msbk[path][1][i];
+		rtw_write32_mask(rtwdev, w_q + 0x4, 0xff8, value);
+		rtw_write32_mask(rtwdev, w_q, 0xf0000000, i);
+		rtw_write32_mask(rtwdev, w_q + 0x4, BIT(2), 0x1);
+	}
+	rtw_write32_mask(rtwdev, w_q + 0x4, BIT(2), 0x0);
+
+	rtw_write32_mask(rtwdev, w_i + 0x8, BIT(26) | BIT(25), 0x0);
+	rtw_write32_mask(rtwdev, w_q + 0x8, BIT(26) | BIT(25), 0x0);
+	rtw_write32_mask(rtwdev, w_i + 0x4, BIT(0), 0x0);
+	rtw_write32_mask(rtwdev, w_q + 0x4, BIT(0), 0x0);
+
+	return true;
+}
+
+static bool __rtw8822c_dac_cal_restore(struct rtw_dev *rtwdev)
+{
+	if (!rtw8822c_dac_cal_restore_path(rtwdev, RF_PATH_A))
+		return false;
+
+	if (!rtw8822c_dac_cal_restore_path(rtwdev, RF_PATH_B))
+		return false;
+
+	return true;
+}
+
+static bool rtw8822c_dac_cal_restore(struct rtw_dev *rtwdev)
+{
+	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+	u32 temp[3];
+
+	/* sample the first element for both path's IQ vector */
+	if (dm_info->dack_msbk[RF_PATH_A][0][0] == 0 &&
+	    dm_info->dack_msbk[RF_PATH_A][1][0] == 0 &&
+	    dm_info->dack_msbk[RF_PATH_B][0][0] == 0 &&
+	    dm_info->dack_msbk[RF_PATH_B][1][0] == 0)
+		return false;
+
+	temp[0] = rtw_read32(rtwdev, 0x1860);
+	temp[1] = rtw_read32(rtwdev, 0x4160);
+	temp[2] = rtw_read32(rtwdev, 0x9b4);
+
+	rtw8822c_dac_cal_restore_prepare(rtwdev);
+	if (!check_hw_ready(rtwdev, 0x2808, 0x7fff80, 0xffff) ||
+	    !check_hw_ready(rtwdev, 0x2834, 0x7fff80, 0xffff) ||
+	    !check_hw_ready(rtwdev, 0x4508, 0x7fff80, 0xffff) ||
+	    !check_hw_ready(rtwdev, 0x4534, 0x7fff80, 0xffff))
+		return false;
+
+	if (!__rtw8822c_dac_cal_restore(rtwdev)) {
+		rtw_err(rtwdev, "failed to restore dack vectors\n");
+		return false;
+	}
+
+	rtw_write32_mask(rtwdev, 0x1830, BIT(30), 0x1);
+	rtw_write32_mask(rtwdev, 0x4130, BIT(30), 0x1);
+	rtw_write32(rtwdev, 0x1860, temp[0]);
+	rtw_write32(rtwdev, 0x4160, temp[1]);
+	rtw_write32_mask(rtwdev, 0x18b0, BIT(27), 0x1);
+	rtw_write32_mask(rtwdev, 0x18cc, BIT(27), 0x1);
+	rtw_write32_mask(rtwdev, 0x41b0, BIT(27), 0x1);
+	rtw_write32_mask(rtwdev, 0x41cc, BIT(27), 0x1);
+	rtw_write32(rtwdev, 0x9b4, temp[2]);
+
+	return true;
+}
+
 static void rtw8822c_rf_dac_cal(struct rtw_dev *rtwdev)
 {
 	struct rtw_backup_info backup_rf[DACK_RF_8822C * DACK_PATH_8822C];
@@ -600,6 +919,11 @@ static void rtw8822c_rf_dac_cal(struct rtw_dev *rtwdev)
 	u32 ic_a = 0x0, qc_a = 0x0, ic_b = 0x0, qc_b = 0x0;
 	u32 adc_ic_a = 0x0, adc_qc_a = 0x0, adc_ic_b = 0x0, adc_qc_b = 0x0;
 
+	if (rtw8822c_dac_cal_restore(rtwdev))
+		return;
+
+	/* not able to restore, do it */
+
 	rtw8822c_dac_backup_reg(rtwdev, backup, backup_rf);
 
 	rtw8822c_dac_bb_setting(rtwdev);
@@ -644,6 +968,9 @@ static void rtw8822c_rf_dac_cal(struct rtw_dev *rtwdev)
 
 	rtw8822c_dac_restore_reg(rtwdev, backup, backup_rf);
 
+	/* backup results to restore, saving a lot of time */
+	rtw8822c_dac_cal_backup(rtwdev);
+
 	rtw_dbg(rtwdev, RTW_DBG_RFK, "[DACK] path A: ic=0x%x, qc=0x%x\n", ic_a, qc_a);
 	rtw_dbg(rtwdev, RTW_DBG_RFK, "[DACK] path B: ic=0x%x, qc=0x%x\n", ic_b, qc_b);
 	rtw_dbg(rtwdev, RTW_DBG_RFK, "[DACK] path A: i=0x%x, q=0x%x\n", i_a, q_a);
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.h b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
index 62ef128..ac730e7 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
@@ -150,6 +150,10 @@ struct rtw8822c_efuse {
 #define BIT_3WIRE_RX_EN		BIT(1)
 #define BIT_3WIRE_PI_ON		BIT(28)
 #define REG_RXAGCCTL0	0x18ac
+#define REG_DCKA_I_0	0x18bc
+#define REG_DCKA_I_1	0x18c0
+#define REG_DCKA_Q_0	0x18d8
+#define REG_DCKA_Q_1	0x18dc
 #define BIT_RXAGC_CCK	0xf000
 #define BIT_RXAGC_OFDM	0x1f0
 #define REG_CCKSB	0x1a00
@@ -196,5 +200,9 @@ struct rtw8822c_efuse {
 #define REG_ORITXCODE2	0x4100
 #define REG_3WIRE2	0x410c
 #define REG_RXAGCCTL	0x41ac
+#define REG_DCKB_I_0	0x41bc
+#define REG_DCKB_I_1	0x41c0
+#define REG_DCKB_Q_0	0x41d8
+#define REG_DCKB_Q_1	0x41dc
 
 #endif
-- 
2.7.4


^ permalink raw reply related

* [PATCH 11/11] rtw88: fix typo rtw_writ16_set
From: yhchuang @ 2019-06-12  6:45 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless
In-Reply-To: <1560321917-17751-1-git-send-email-yhchuang@realtek.com>

From: Tzu-En Huang <tehuang@realtek.com>

rtw_writ16_set should be rtw_write16_set

Signed-off-by: Tzu-En Huang <tehuang@realtek.com>
Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
 drivers/net/wireless/realtek/rtw88/hci.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/realtek/rtw88/hci.h b/drivers/net/wireless/realtek/rtw88/hci.h
index 2676582..aba329c 100644
--- a/drivers/net/wireless/realtek/rtw88/hci.h
+++ b/drivers/net/wireless/realtek/rtw88/hci.h
@@ -97,7 +97,7 @@ static inline void rtw_write8_set(struct rtw_dev *rtwdev, u32 addr, u8 bit)
 	rtw_write8(rtwdev, addr, val | bit);
 }
 
-static inline void rtw_writ16_set(struct rtw_dev *rtwdev, u32 addr, u16 bit)
+static inline void rtw_write16_set(struct rtw_dev *rtwdev, u32 addr, u16 bit)
 {
 	u16 val;
 
-- 
2.7.4


^ permalink raw reply related

* [PATCH 08/11] rtw88: power on again if it was already on
From: yhchuang @ 2019-06-12  6:45 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless
In-Reply-To: <1560321917-17751-1-git-send-email-yhchuang@realtek.com>

From: Yan-Hsuan Chuang <yhchuang@realtek.com>

We could fail to power on because it was already on. If the return
value is -EALREADY, power off and then power on again to turn on the
hardware as expected.

Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
 drivers/net/wireless/realtek/rtw88/mac.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c
index 25a923b..fc14b37 100644
--- a/drivers/net/wireless/realtek/rtw88/mac.c
+++ b/drivers/net/wireless/realtek/rtw88/mac.c
@@ -285,8 +285,14 @@ int rtw_mac_power_on(struct rtw_dev *rtwdev)
 		goto err;
 
 	ret = rtw_mac_power_switch(rtwdev, true);
-	if (ret)
+	if (ret == -EALREADY) {
+		rtw_mac_power_switch(rtwdev, false);
+		ret = rtw_mac_power_switch(rtwdev, true);
+		if (ret)
+			goto err;
+	} else if (ret) {
 		goto err;
+	}
 
 	ret = rtw_mac_init_system_cfg(rtwdev);
 	if (ret)
-- 
2.7.4


^ permalink raw reply related

* [PATCH 10/11] rtw88: rsvd page should go though management queue
From: yhchuang @ 2019-06-12  6:45 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless
In-Reply-To: <1560321917-17751-1-git-send-email-yhchuang@realtek.com>

From: Yan-Hsuan Chuang <yhchuang@realtek.com>

The hardware default uses management queue to transmit frames that are
downloaded into reserved page, so we need to clearly assign the frames
to use qsel in TX_DESC_QSEL_MGMT to avoid using wrong queue.

Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
 drivers/net/wireless/realtek/rtw88/tx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c
index e32faf8..8eaa980 100644
--- a/drivers/net/wireless/realtek/rtw88/tx.c
+++ b/drivers/net/wireless/realtek/rtw88/tx.c
@@ -362,6 +362,6 @@ void rtw_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev,
 	pkt_info->bmc = bmc;
 	pkt_info->tx_pkt_size = skb->len;
 	pkt_info->offset = chip->tx_pkt_desc_sz;
-	pkt_info->qsel = skb->priority;
+	pkt_info->qsel = TX_DESC_QSEL_MGMT;
 	pkt_info->ls = true;
 }
-- 
2.7.4


^ permalink raw reply related

* [PATCH 07/11] rtw88: 8822c: use more accurate ofdm fa counting
From: yhchuang @ 2019-06-12  6:45 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless
In-Reply-To: <1560321917-17751-1-git-send-email-yhchuang@realtek.com>

From: Yan-Hsuan Chuang <yhchuang@realtek.com>

8822c used to count OFDM FA count by subtracting tx count from FA count.
But it need to substract more counters to be accurate.

However, we can count it by adding up all of the FA counters we want.
And it is simpler to add than list all of the components to substract.

Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
 drivers/net/wireless/realtek/rtw88/rtw8822c.c | 24 ++++++++++++++++++++----
 drivers/net/wireless/realtek/rtw88/rtw8822c.h |  5 +++++
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index b9185b2..4896f25 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -1491,13 +1491,29 @@ static void rtw8822c_false_alarm_statistics(struct rtw_dev *rtwdev)
 	u32 cck_enable;
 	u32 cck_fa_cnt;
 	u32 ofdm_fa_cnt;
-	u32 ofdm_tx_counter;
+	u32 ofdm_fa_cnt1, ofdm_fa_cnt2, ofdm_fa_cnt3, ofdm_fa_cnt4, ofdm_fa_cnt5;
+	u16 parity_fail, rate_illegal, crc8_fail, mcs_fail, sb_search_fail,
+	    fast_fsync, crc8_fail_vhta, mcs_fail_vht;
 
 	cck_enable = rtw_read32(rtwdev, REG_ENCCK) & BIT_CCK_BLK_EN;
 	cck_fa_cnt = rtw_read16(rtwdev, REG_CCK_FACNT);
-	ofdm_fa_cnt = rtw_read16(rtwdev, REG_OFDM_FACNT);
-	ofdm_tx_counter = rtw_read16(rtwdev, REG_OFDM_TXCNT);
-	ofdm_fa_cnt -= ofdm_tx_counter;
+
+	ofdm_fa_cnt1 = rtw_read32(rtwdev, REG_OFDM_FACNT1);
+	ofdm_fa_cnt2 = rtw_read32(rtwdev, REG_OFDM_FACNT2);
+	ofdm_fa_cnt3 = rtw_read32(rtwdev, REG_OFDM_FACNT3);
+	ofdm_fa_cnt4 = rtw_read32(rtwdev, REG_OFDM_FACNT4);
+	ofdm_fa_cnt5 = rtw_read32(rtwdev, REG_OFDM_FACNT5);
+
+	parity_fail = (ofdm_fa_cnt1 & 0xffff0000) >> 16;
+	rate_illegal = (ofdm_fa_cnt2 & 0xffff);
+	crc8_fail = (ofdm_fa_cnt2 & 0xffff0000) >> 16;
+	crc8_fail_vhta = (ofdm_fa_cnt3 & 0xffff);
+	mcs_fail = (ofdm_fa_cnt4 & 0xffff);
+	mcs_fail_vht = (ofdm_fa_cnt4 & 0xffff0000) >> 16;
+	fast_fsync = (ofdm_fa_cnt5 & 0xffff);
+	sb_search_fail = (ofdm_fa_cnt5 & 0xffff0000) >> 16;
+	ofdm_fa_cnt = parity_fail + rate_illegal + crc8_fail + crc8_fail_vhta +
+		      mcs_fail + mcs_fail_vht + fast_fsync + sb_search_fail;
 
 	dm_info->cck_fa_cnt = cck_fa_cnt;
 	dm_info->ofdm_fa_cnt = ofdm_fa_cnt;
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.h b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
index bf41359..62ef128 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
@@ -187,6 +187,11 @@ struct rtw8822c_efuse {
 #define REG_CNT_CTRL	0x1eb4
 #define BIT_ALL_CNT_RST		BIT(25)
 #define REG_OFDM_FACNT	0x2d00
+#define REG_OFDM_FACNT1	0x2d04
+#define REG_OFDM_FACNT2	0x2d08
+#define REG_OFDM_FACNT3	0x2d0c
+#define REG_OFDM_FACNT4	0x2d10
+#define REG_OFDM_FACNT5	0x2d20
 #define REG_OFDM_TXCNT	0x2de0
 #define REG_ORITXCODE2	0x4100
 #define REG_3WIRE2	0x410c
-- 
2.7.4


^ permalink raw reply related

* [PATCH 04/11] rtw88: 8822c: add rf write protection when switching channel
From: yhchuang @ 2019-06-12  6:45 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless
In-Reply-To: <1560321917-17751-1-git-send-email-yhchuang@realtek.com>

From: Chien-Hsun Liao <ben.liao@realtek.com>

Collision of writing rf registers could occur if the driver writes
rf registers by direct write while the hardware is writing other rf
registers by pi write simultaneously.

Hardware pi write can be triggered by rf calibrations sometimes, so
the driver can not always write rf registers by direct write
protection. Direct write protection can make sure that there is no
hardware pi write during the direct write.

According to some experiments, if we add direct write protection
when switching channel, the performance of rf calibration will not
be affected.

Signed-off-by: Chien-Hsun Liao <ben.liao@realtek.com>
Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
 drivers/net/wireless/realtek/rtw88/phy.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
index 4381b36..580f310 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.c
+++ b/drivers/net/wireless/realtek/rtw88/phy.c
@@ -596,14 +596,19 @@ bool rtw_phy_write_rf_reg(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
 	direct_addr = base_addr[rf_path] + (addr << 2);
 	mask &= RFREG_MASK;
 
-	rtw_write32_mask(rtwdev, REG_RSV_CTRL, BITS_RFC_DIRECT, DISABLE_PI);
-	rtw_write32_mask(rtwdev, REG_WLRF1, BITS_RFC_DIRECT, DISABLE_PI);
+	if (addr == RF_CFGCH) {
+		rtw_write32_mask(rtwdev, REG_RSV_CTRL, BITS_RFC_DIRECT, DISABLE_PI);
+		rtw_write32_mask(rtwdev, REG_WLRF1, BITS_RFC_DIRECT, DISABLE_PI);
+	}
+
 	rtw_write32_mask(rtwdev, direct_addr, mask, data);
 
 	udelay(1);
 
-	rtw_write32_mask(rtwdev, REG_RSV_CTRL, BITS_RFC_DIRECT, ENABLE_PI);
-	rtw_write32_mask(rtwdev, REG_WLRF1, BITS_RFC_DIRECT, ENABLE_PI);
+	if (addr == RF_CFGCH) {
+		rtw_write32_mask(rtwdev, REG_RSV_CTRL, BITS_RFC_DIRECT, ENABLE_PI);
+		rtw_write32_mask(rtwdev, REG_WLRF1, BITS_RFC_DIRECT, ENABLE_PI);
+	}
 
 	return true;
 }
-- 
2.7.4


^ permalink raw reply related

* [PATCH 00/11] rtw88: regular driver upgrade with minor changes
From: yhchuang @ 2019-06-12  6:45 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

From: Yan-Hsuan Chuang <yhchuang@realtek.com>

These patch set are mostly minor fixes.

Some of them are adjustments for 8822c's phy setting.

DACK reload is to speed up hardware power on.

Beacon function setting make sure the hardware to sync the TSF
for the beacon intervals (station mode). For other modes, disable
TSF sync to avoid beacon interval getting violated.

And two of them make rtw88 has two new features "fast_xmit" and
"random mac scan"

Chien-Hsun Liao (2):
  rtw88: 8822c: add rf write protection when switching channel
  rtw88: 8822c: update channel and bandwidth BB setting

Chin-Yen Lee (1):
  rtw88: add beacon function setting

Tzu-En Huang (1):
  rtw88: fix typo rtw_writ16_set

Yan-Hsuan Chuang (7):
  rtw88: add fast xmit support
  rtw88: add support for random mac scan
  rtw88: 8822c: disable rx clock gating before counter reset
  rtw88: 8822c: use more accurate ofdm fa counting
  rtw88: power on again if it was already on
  rtw88: restore DACK results to save time
  rtw88: rsvd page should go though management queue

 drivers/net/wireless/realtek/rtw88/hci.h      |   2 +-
 drivers/net/wireless/realtek/rtw88/mac.c      |   8 +-
 drivers/net/wireless/realtek/rtw88/mac80211.c |  32 ++
 drivers/net/wireless/realtek/rtw88/main.c     |   8 +
 drivers/net/wireless/realtek/rtw88/main.h     |  11 +
 drivers/net/wireless/realtek/rtw88/phy.c      |  13 +-
 drivers/net/wireless/realtek/rtw88/rtw8822c.c | 435 ++++++++++++++++++++++++--
 drivers/net/wireless/realtek/rtw88/rtw8822c.h |  22 ++
 drivers/net/wireless/realtek/rtw88/tx.c       |   2 +-
 9 files changed, 502 insertions(+), 31 deletions(-)

-- 
2.7.4


^ permalink raw reply


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