diff mbox

[PATCHv3,2/2] ath10k: Allow setting coverage class

Message ID 20160825132522.30994-3-benjamin@sipsolutions.net (mailing list archive)
State Changes Requested
Delegated to: Kalle Valo
Headers show

Commit Message

Benjamin Berg Aug. 25, 2016, 1:25 p.m. UTC
Unfortunately ath10k does not generally allow modifying the coverage class
with the stock firmware and Qualcomm has so far refused to implement this
feature so that it can be properly supported in ath10k. If we however know
the registers that need to be modified for proper operation with a higher
coverage class, then we can do these modifications from the driver.

This patch implements this hack for first generation cards which are based
on a core that is similar to ath9k. The registers are modified in place and
need to be re-written every time the firmware sets them. To achieve this
the register status is verified after certain WMI events from the firmware.

The coverage class may not be modified temporarily right after the card
re-initializes the registers. This is for example the case during scanning.

Thanks to Sebastian Gottschall <s.gottschall@dd-wrt.com> for initially
working on a userspace support for this. This patch wouldn't have been
possible without this documentation.

Signed-off-by: Benjamin Berg <benjamin@sipsolutions.net>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fit.fraunhofer.de>
---
 drivers/net/wireless/ath/ath10k/core.c |  11 +++
 drivers/net/wireless/ath/ath10k/core.h |  12 +++
 drivers/net/wireless/ath/ath10k/hw.c   | 139 +++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/hw.h   |  28 ++++++-
 drivers/net/wireless/ath/ath10k/mac.c  |  19 +++++
 drivers/net/wireless/ath/ath10k/wmi.c  |  37 +++++++++
 6 files changed, 245 insertions(+), 1 deletion(-)

Comments

Ben Greear Aug. 25, 2016, 2:28 p.m. UTC | #1
On 08/25/2016 06:25 AM, Benjamin Berg wrote:
> Unfortunately ath10k does not generally allow modifying the coverage class
> with the stock firmware and Qualcomm has so far refused to implement this
> feature so that it can be properly supported in ath10k. If we however know
> the registers that need to be modified for proper operation with a higher
> coverage class, then we can do these modifications from the driver.
>
> This patch implements this hack for first generation cards which are based
> on a core that is similar to ath9k. The registers are modified in place and
> need to be re-written every time the firmware sets them. To achieve this
> the register status is verified after certain WMI events from the firmware.
>
> The coverage class may not be modified temporarily right after the card
> re-initializes the registers. This is for example the case during scanning.
>
> Thanks to Sebastian Gottschall <s.gottschall@dd-wrt.com> for initially
> working on a userspace support for this. This patch wouldn't have been
> possible without this documentation.



> diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
> index d246288..8ccc8cf 100644
> --- a/drivers/net/wireless/ath/ath10k/wmi.c
> +++ b/drivers/net/wireless/ath/ath10k/wmi.c
> @@ -4879,6 +4879,12 @@ exit:
>   	return 0;
>   }
>
> +static inline void ath10k_wmi_queue_set_coverage_class_work(struct ath10k *ar)
> +{
> +	if (ar->hw_params.hw_ops->set_coverage_class)
> +		queue_work(ar->workqueue, &ar->set_coverage_class_work);
> +}

Maybe this should first check to see if the user has specified a coverage class
before it attempts to do any work at all?

That way, if user does not set anything, then the behaviour does not change
in any significant way?

Thanks,
Ben
Benjamin Berg Aug. 25, 2016, 2:33 p.m. UTC | #2
On Do, 2016-08-25 at 07:28 -0700, Ben Greear wrote:
> 
> On 08/25/2016 06:25 AM, Benjamin Berg wrote:
> > 
> > Unfortunately ath10k does not generally allow modifying the
> > coverage class
> > with the stock firmware and Qualcomm has so far refused to
> > implement this
> > feature so that it can be properly supported in ath10k. If we
> > however know
> > the registers that need to be modified for proper operation with a
> > higher
> > coverage class, then we can do these modifications from the driver.
> > 
> > This patch implements this hack for first generation cards which
> > are based
> > on a core that is similar to ath9k. The registers are modified in
> > place and
> > need to be re-written every time the firmware sets them. To achieve
> > this
> > the register status is verified after certain WMI events from the
> > firmware.
> > 
> > The coverage class may not be modified temporarily right after the
> > card
> > re-initializes the registers. This is for example the case during
> > scanning.
> > 
> > Thanks to Sebastian Gottschall <s.gottschall@dd-wrt.com> for
> > initially
> > working on a userspace support for this. This patch wouldn't have
> > been
> > possible without this documentation.
> 
> 
> 
> > 
> > diff --git a/drivers/net/wireless/ath/ath10k/wmi.c
> > b/drivers/net/wireless/ath/ath10k/wmi.c
> > index d246288..8ccc8cf 100644
> > --- a/drivers/net/wireless/ath/ath10k/wmi.c
> > +++ b/drivers/net/wireless/ath/ath10k/wmi.c
> > @@ -4879,6 +4879,12 @@ exit:
> >   	return 0;
> >   }
> > 
> > +static inline void ath10k_wmi_queue_set_coverage_class_work(struct
> > ath10k *ar)
> > +{
> > +	if (ar->hw_params.hw_ops->set_coverage_class)
> > +		queue_work(ar->workqueue, &ar-
> > >set_coverage_class_work);
> > +}
> 
> Maybe this should first check to see if the user has specified a
> coverage class
> before it attempts to do any work at all?
> 
> That way, if user does not set anything, then the behaviour does not
> change
> in any significant way?

Hm, yes, adding a check there looks simple and I don't see any reason
why it wouldn't work.

Benjamin
Sebastian Gottschall Aug. 25, 2016, 3:10 p.m. UTC | #3
Am 25.08.2016 um 16:33 schrieb Benjamin Berg:
> On Do, 2016-08-25 at 07:28 -0700, Ben Greear wrote:
>> On 08/25/2016 06:25 AM, Benjamin Berg wrote:
>>> Unfortunately ath10k does not generally allow modifying the
>>> coverage class
>>> with the stock firmware and Qualcomm has so far refused to
>>> implement this
>>> feature so that it can be properly supported in ath10k. If we
>>> however know
>>> the registers that need to be modified for proper operation with a
>>> higher
>>> coverage class, then we can do these modifications from the driver.
>>>
>>> This patch implements this hack for first generation cards which
>>> are based
>>> on a core that is similar to ath9k. The registers are modified in
>>> place and
>>> need to be re-written every time the firmware sets them. To achieve
>>> this
>>> the register status is verified after certain WMI events from the
>>> firmware.
>>>
>>> The coverage class may not be modified temporarily right after the
>>> card
>>> re-initializes the registers. This is for example the case during
>>> scanning.
>>>
>>> Thanks to Sebastian Gottschall <s.gottschall@dd-wrt.com> for
>>> initially
>>> working on a userspace support for this. This patch wouldn't have
>>> been
>>> possible without this documentation.
>>
>>
>>> diff --git a/drivers/net/wireless/ath/ath10k/wmi.c
>>> b/drivers/net/wireless/ath/ath10k/wmi.c
>>> index d246288..8ccc8cf 100644
>>> --- a/drivers/net/wireless/ath/ath10k/wmi.c
>>> +++ b/drivers/net/wireless/ath/ath10k/wmi.c
>>> @@ -4879,6 +4879,12 @@ exit:
>>>    	return 0;
>>>    }
>>>
>>> +static inline void ath10k_wmi_queue_set_coverage_class_work(struct
>>> ath10k *ar)
>>> +{
>>> +	if (ar->hw_params.hw_ops->set_coverage_class)
>>> +		queue_work(ar->workqueue, &ar-
>>>> set_coverage_class_work);
>>> +}
>> Maybe this should first check to see if the user has specified a
>> coverage class
>> before it attempts to do any work at all?
>>
>> That way, if user does not set anything, then the behaviour does not
>> change
>> in any significant way?
> Hm, yes, adding a check there looks simple and I don't see any reason
> why it wouldn't work.
consider that i already implemented this in my version of the patch i 
supplied to you. however. mine doesnt use queue handling but just checks 
if the hw is ready before setting anything
>
> Benjamin
Ben Greear Oct. 16, 2017, 5:57 p.m. UTC | #4
On 08/25/2016 06:25 AM, Benjamin Berg wrote:
> Unfortunately ath10k does not generally allow modifying the coverage class
> with the stock firmware and Qualcomm has so far refused to implement this
> feature so that it can be properly supported in ath10k. If we however know
> the registers that need to be modified for proper operation with a higher
> coverage class, then we can do these modifications from the driver.
>
> This patch implements this hack for first generation cards which are based
> on a core that is similar to ath9k. The registers are modified in place and
> need to be re-written every time the firmware sets them. To achieve this
> the register status is verified after certain WMI events from the firmware.
>
> The coverage class may not be modified temporarily right after the card
> re-initializes the registers. This is for example the case during scanning.
>
> Thanks to Sebastian Gottschall <s.gottschall@dd-wrt.com> for initially
> working on a userspace support for this. This patch wouldn't have been
> possible without this documentation.

Hello,

Do you happen to know the maximum distance that can work with this
patch enabled?  The register value maximum seems to be 0x3FFF, but I
am not sure of the units (nor how exactly that applies to distance).

Thanks,
Ben
Adrian Chadd Oct. 16, 2017, 5:59 p.m. UTC | #5
On 16 October 2017 at 10:57, Ben Greear <greearb@candelatech.com> wrote:
> On 08/25/2016 06:25 AM, Benjamin Berg wrote:
>>
>> Unfortunately ath10k does not generally allow modifying the coverage class
>> with the stock firmware and Qualcomm has so far refused to implement this
>> feature so that it can be properly supported in ath10k. If we however know
>> the registers that need to be modified for proper operation with a higher
>> coverage class, then we can do these modifications from the driver.
>>
>> This patch implements this hack for first generation cards which are based
>> on a core that is similar to ath9k. The registers are modified in place
>> and
>> need to be re-written every time the firmware sets them. To achieve this
>> the register status is verified after certain WMI events from the
>> firmware.
>>
>> The coverage class may not be modified temporarily right after the card
>> re-initializes the registers. This is for example the case during
>> scanning.
>>
>> Thanks to Sebastian Gottschall <s.gottschall@dd-wrt.com> for initially
>> working on a userspace support for this. This patch wouldn't have been
>> possible without this documentation.
>
>
> Hello,
>
> Do you happen to know the maximum distance that can work with this
> patch enabled?  The register value maximum seems to be 0x3FFF, but I
> am not sure of the units (nor how exactly that applies to distance).

It's in MAC clocks still, right? So it depends on how fast the MAC
clock timer runs.



-adrian
Sebastian Gottschall Oct. 16, 2017, 7:10 p.m. UTC | #6
Am 16.10.2017 um 19:59 schrieb Adrian Chadd:
> On 16 October 2017 at 10:57, Ben Greear <greearb@candelatech.com> wrote:
>> On 08/25/2016 06:25 AM, Benjamin Berg wrote:
>>> Unfortunately ath10k does not generally allow modifying the coverage class
>>> with the stock firmware and Qualcomm has so far refused to implement this
>>> feature so that it can be properly supported in ath10k. If we however know
>>> the registers that need to be modified for proper operation with a higher
>>> coverage class, then we can do these modifications from the driver.
>>>
>>> This patch implements this hack for first generation cards which are based
>>> on a core that is similar to ath9k. The registers are modified in place
>>> and
>>> need to be re-written every time the firmware sets them. To achieve this
>>> the register status is verified after certain WMI events from the
>>> firmware.
>>>
>>> The coverage class may not be modified temporarily right after the card
>>> re-initializes the registers. This is for example the case during
>>> scanning.
>>>
>>> Thanks to Sebastian Gottschall <s.gottschall@dd-wrt.com> for initially
>>> working on a userspace support for this. This patch wouldn't have been
>>> possible without this documentation.
>>
>> Hello,
>>
>> Do you happen to know the maximum distance that can work with this
>> patch enabled?  The register value maximum seems to be 0x3FFF, but I
>> am not sure of the units (nor how exactly that applies to distance).
> It's in MAC clocks still, right? So it depends on how fast the MAC
> clock timer runs.
>
>
>
> -adrian

if someone is interested i can provide a patch witch works as well for 
998x and 9984 and usually other newer chipsets too.

but clock parameters need to be adjusted for these newer ones. the only 
problem is that its based on unoffical registers which arent documented 
and the patch for the 99xx chipsets is very different from 988x
Adrian Chadd Oct. 16, 2017, 7:12 p.m. UTC | #7
hiya,

I'd honestly rather see firmware changes for wave 2 chips, as I know
there's a lot more MAC changes messing up this stuff ..



-adrian


On 16 October 2017 at 12:10, Sebastian Gottschall
<s.gottschall@dd-wrt.com> wrote:
> Am 16.10.2017 um 19:59 schrieb Adrian Chadd:
>>
>> On 16 October 2017 at 10:57, Ben Greear <greearb@candelatech.com> wrote:
>>>
>>> On 08/25/2016 06:25 AM, Benjamin Berg wrote:
>>>>
>>>> Unfortunately ath10k does not generally allow modifying the coverage
>>>> class
>>>> with the stock firmware and Qualcomm has so far refused to implement
>>>> this
>>>> feature so that it can be properly supported in ath10k. If we however
>>>> know
>>>> the registers that need to be modified for proper operation with a
>>>> higher
>>>> coverage class, then we can do these modifications from the driver.
>>>>
>>>> This patch implements this hack for first generation cards which are
>>>> based
>>>> on a core that is similar to ath9k. The registers are modified in place
>>>> and
>>>> need to be re-written every time the firmware sets them. To achieve this
>>>> the register status is verified after certain WMI events from the
>>>> firmware.
>>>>
>>>> The coverage class may not be modified temporarily right after the card
>>>> re-initializes the registers. This is for example the case during
>>>> scanning.
>>>>
>>>> Thanks to Sebastian Gottschall <s.gottschall@dd-wrt.com> for initially
>>>> working on a userspace support for this. This patch wouldn't have been
>>>> possible without this documentation.
>>>
>>>
>>> Hello,
>>>
>>> Do you happen to know the maximum distance that can work with this
>>> patch enabled?  The register value maximum seems to be 0x3FFF, but I
>>> am not sure of the units (nor how exactly that applies to distance).
>>
>> It's in MAC clocks still, right? So it depends on how fast the MAC
>> clock timer runs.
>>
>>
>>
>> -adrian
>
>
> if someone is interested i can provide a patch witch works as well for 998x
> and 9984 and usually other newer chipsets too.
>
> but clock parameters need to be adjusted for these newer ones. the only
> problem is that its based on unoffical registers which arent documented and
> the patch for the 99xx chipsets is very different from 988x
>
>
>
> --
> Mit freundlichen Grüssen / Regards
>
> Sebastian Gottschall / CTO
>
> NewMedia-NET GmbH - DD-WRT
> Firmensitz:  Stubenwaldallee 21a, 64625 Bensheim
>
> Registergericht: Amtsgericht Darmstadt, HRB 25473
> Geschäftsführer: Peter Steinhäuser, Christian Scheele
> http://www.dd-wrt.com
> email: s.gottschall@dd-wrt.com
> Tel.: +496251-582650 / Fax: +496251-5826565
>
Ben Greear Oct. 16, 2017, 7:55 p.m. UTC | #8
On 10/16/2017 12:12 PM, Adrian Chadd wrote:
> hiya,
>
> I'd honestly rather see firmware changes for wave 2 chips, as I know
> there's a lot more MAC changes messing up this stuff ..

For wave-1, it appears to be quite simple to modify the firmware to set
the ack-cts register to a specific value (and re-set it after scanning,
etc).

Is the wave-2 stuff that much different?  I've recently hooked in my
CT firmware for wave-1 to support the driver's ack/cts calculations
(but without needing all the manual register twiddling).  I could probably
do the same for 9984 if it mattered.  But, that still doesn't help stock
driver/firmware users.

Thanks,
Ben

>
>
>
> -adrian
>
>
> On 16 October 2017 at 12:10, Sebastian Gottschall
> <s.gottschall@dd-wrt.com> wrote:
>> Am 16.10.2017 um 19:59 schrieb Adrian Chadd:
>>>
>>> On 16 October 2017 at 10:57, Ben Greear <greearb@candelatech.com> wrote:
>>>>
>>>> On 08/25/2016 06:25 AM, Benjamin Berg wrote:
>>>>>
>>>>> Unfortunately ath10k does not generally allow modifying the coverage
>>>>> class
>>>>> with the stock firmware and Qualcomm has so far refused to implement
>>>>> this
>>>>> feature so that it can be properly supported in ath10k. If we however
>>>>> know
>>>>> the registers that need to be modified for proper operation with a
>>>>> higher
>>>>> coverage class, then we can do these modifications from the driver.
>>>>>
>>>>> This patch implements this hack for first generation cards which are
>>>>> based
>>>>> on a core that is similar to ath9k. The registers are modified in place
>>>>> and
>>>>> need to be re-written every time the firmware sets them. To achieve this
>>>>> the register status is verified after certain WMI events from the
>>>>> firmware.
>>>>>
>>>>> The coverage class may not be modified temporarily right after the card
>>>>> re-initializes the registers. This is for example the case during
>>>>> scanning.
>>>>>
>>>>> Thanks to Sebastian Gottschall <s.gottschall@dd-wrt.com> for initially
>>>>> working on a userspace support for this. This patch wouldn't have been
>>>>> possible without this documentation.
>>>>
>>>>
>>>> Hello,
>>>>
>>>> Do you happen to know the maximum distance that can work with this
>>>> patch enabled?  The register value maximum seems to be 0x3FFF, but I
>>>> am not sure of the units (nor how exactly that applies to distance).
>>>
>>> It's in MAC clocks still, right? So it depends on how fast the MAC
>>> clock timer runs.
>>>
>>>
>>>
>>> -adrian
>>
>>
>> if someone is interested i can provide a patch witch works as well for 998x
>> and 9984 and usually other newer chipsets too.
>>
>> but clock parameters need to be adjusted for these newer ones. the only
>> problem is that its based on unoffical registers which arent documented and
>> the patch for the 99xx chipsets is very different from 988x
>>
>>
>>
>> --
>> Mit freundlichen Grüssen / Regards
>>
>> Sebastian Gottschall / CTO
>>
>> NewMedia-NET GmbH - DD-WRT
>> Firmensitz:  Stubenwaldallee 21a, 64625 Bensheim
>>
>> Registergericht: Amtsgericht Darmstadt, HRB 25473
>> Geschäftsführer: Peter Steinhäuser, Christian Scheele
>> http://www.dd-wrt.com
>> email: s.gottschall@dd-wrt.com
>> Tel.: +496251-582650 / Fax: +496251-5826565
>>
>
> _______________________________________________
> ath10k mailing list
> ath10k@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/ath10k
>
Sebastian Gottschall Oct. 17, 2017, 7:56 a.m. UTC | #9
Am 16.10.2017 um 21:12 schrieb Adrian Chadd:
> hiya,
>
> I'd honestly rather see firmware changes for wave 2 chips, as I know
> there's a lot more MAC changes messing up this stuff ..
i know. but i found out how to handle it.
>
>
>
> -adrian
>
>
> On 16 October 2017 at 12:10, Sebastian Gottschall
> <s.gottschall@dd-wrt.com> wrote:
>> Am 16.10.2017 um 19:59 schrieb Adrian Chadd:
>>> On 16 October 2017 at 10:57, Ben Greear <greearb@candelatech.com> wrote:
>>>> On 08/25/2016 06:25 AM, Benjamin Berg wrote:
>>>>> Unfortunately ath10k does not generally allow modifying the coverage
>>>>> class
>>>>> with the stock firmware and Qualcomm has so far refused to implement
>>>>> this
>>>>> feature so that it can be properly supported in ath10k. If we however
>>>>> know
>>>>> the registers that need to be modified for proper operation with a
>>>>> higher
>>>>> coverage class, then we can do these modifications from the driver.
>>>>>
>>>>> This patch implements this hack for first generation cards which are
>>>>> based
>>>>> on a core that is similar to ath9k. The registers are modified in place
>>>>> and
>>>>> need to be re-written every time the firmware sets them. To achieve this
>>>>> the register status is verified after certain WMI events from the
>>>>> firmware.
>>>>>
>>>>> The coverage class may not be modified temporarily right after the card
>>>>> re-initializes the registers. This is for example the case during
>>>>> scanning.
>>>>>
>>>>> Thanks to Sebastian Gottschall <s.gottschall@dd-wrt.com> for initially
>>>>> working on a userspace support for this. This patch wouldn't have been
>>>>> possible without this documentation.
>>>>
>>>> Hello,
>>>>
>>>> Do you happen to know the maximum distance that can work with this
>>>> patch enabled?  The register value maximum seems to be 0x3FFF, but I
>>>> am not sure of the units (nor how exactly that applies to distance).
>>> It's in MAC clocks still, right? So it depends on how fast the MAC
>>> clock timer runs.
>>>
>>>
>>>
>>> -adrian
>>
>> if someone is interested i can provide a patch witch works as well for 998x
>> and 9984 and usually other newer chipsets too.
>>
>> but clock parameters need to be adjusted for these newer ones. the only
>> problem is that its based on unoffical registers which arent documented and
>> the patch for the 99xx chipsets is very different from 988x
>>
>>
>>
>> --
>> Mit freundlichen Grüssen / Regards
>>
>> Sebastian Gottschall / CTO
>>
>> NewMedia-NET GmbH - DD-WRT
>> Firmensitz:  Stubenwaldallee 21a, 64625 Bensheim
>>
>> Registergericht: Amtsgericht Darmstadt, HRB 25473
>> Geschäftsführer: Peter Steinhäuser, Christian Scheele
>> http://www.dd-wrt.com
>> email: s.gottschall@dd-wrt.com
>> Tel.: +496251-582650 / Fax: +496251-5826565
>>
Sebastian Gottschall Oct. 17, 2017, 7:57 a.m. UTC | #10
Am 16.10.2017 um 21:55 schrieb Ben Greear:
> On 10/16/2017 12:12 PM, Adrian Chadd wrote:
>> hiya,
>>
>> I'd honestly rather see firmware changes for wave 2 chips, as I know
>> there's a lot more MAC changes messing up this stuff ..
>
> For wave-1, it appears to be quite simple to modify the firmware to set
> the ack-cts register to a specific value (and re-set it after scanning,
> etc).
>
> Is the wave-2 stuff that much different?  I've recently hooked in my
> CT firmware for wave-1 to support the driver's ack/cts calculations
> (but without needing all the manual register twiddling).  I could 
> probably
> do the same for 9984 if it mattered.  But, that still doesn't help stock
> driver/firmware users.

wave 2 has nothing todo with wave 1. the registers are different


>
> Thanks,
> Ben
>
>>
>>
>>
>> -adrian
>>
>>
>> On 16 October 2017 at 12:10, Sebastian Gottschall
>> <s.gottschall@dd-wrt.com> wrote:
>>> Am 16.10.2017 um 19:59 schrieb Adrian Chadd:
>>>>
>>>> On 16 October 2017 at 10:57, Ben Greear <greearb@candelatech.com> 
>>>> wrote:
>>>>>
>>>>> On 08/25/2016 06:25 AM, Benjamin Berg wrote:
>>>>>>
>>>>>> Unfortunately ath10k does not generally allow modifying the coverage
>>>>>> class
>>>>>> with the stock firmware and Qualcomm has so far refused to implement
>>>>>> this
>>>>>> feature so that it can be properly supported in ath10k. If we 
>>>>>> however
>>>>>> know
>>>>>> the registers that need to be modified for proper operation with a
>>>>>> higher
>>>>>> coverage class, then we can do these modifications from the driver.
>>>>>>
>>>>>> This patch implements this hack for first generation cards which are
>>>>>> based
>>>>>> on a core that is similar to ath9k. The registers are modified in 
>>>>>> place
>>>>>> and
>>>>>> need to be re-written every time the firmware sets them. To 
>>>>>> achieve this
>>>>>> the register status is verified after certain WMI events from the
>>>>>> firmware.
>>>>>>
>>>>>> The coverage class may not be modified temporarily right after 
>>>>>> the card
>>>>>> re-initializes the registers. This is for example the case during
>>>>>> scanning.
>>>>>>
>>>>>> Thanks to Sebastian Gottschall <s.gottschall@dd-wrt.com> for 
>>>>>> initially
>>>>>> working on a userspace support for this. This patch wouldn't have 
>>>>>> been
>>>>>> possible without this documentation.
>>>>>
>>>>>
>>>>> Hello,
>>>>>
>>>>> Do you happen to know the maximum distance that can work with this
>>>>> patch enabled?  The register value maximum seems to be 0x3FFF, but I
>>>>> am not sure of the units (nor how exactly that applies to distance).
>>>>
>>>> It's in MAC clocks still, right? So it depends on how fast the MAC
>>>> clock timer runs.
>>>>
>>>>
>>>>
>>>> -adrian
>>>
>>>
>>> if someone is interested i can provide a patch witch works as well 
>>> for 998x
>>> and 9984 and usually other newer chipsets too.
>>>
>>> but clock parameters need to be adjusted for these newer ones. the only
>>> problem is that its based on unoffical registers which arent 
>>> documented and
>>> the patch for the 99xx chipsets is very different from 988x
>>>
>>>
>>>
>>> -- 
>>> Mit freundlichen Grüssen / Regards
>>>
>>> Sebastian Gottschall / CTO
>>>
>>> NewMedia-NET GmbH - DD-WRT
>>> Firmensitz:  Stubenwaldallee 21a, 64625 Bensheim
>>>
>>> Registergericht: Amtsgericht Darmstadt, HRB 25473
>>> Geschäftsführer: Peter Steinhäuser, Christian Scheele
>>> http://www.dd-wrt.com
>>> email: s.gottschall@dd-wrt.com
>>> Tel.: +496251-582650 / Fax: +496251-5826565
>>>
>>
>> _______________________________________________
>> ath10k mailing list
>> ath10k@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/ath10k
>>
>
>
diff mbox

Patch

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 6dd42d3..c550c2f 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1552,6 +1552,15 @@  static void ath10k_core_restart(struct work_struct *work)
 	mutex_unlock(&ar->conf_mutex);
 }
 
+static void ath10k_core_set_coverage_class_work(struct work_struct *work)
+{
+	struct ath10k *ar = container_of(work, struct ath10k,
+					 set_coverage_class_work);
+
+	if (ar->hw_params.hw_ops->set_coverage_class)
+		ar->hw_params.hw_ops->set_coverage_class(ar, -1);
+}
+
 static int ath10k_core_init_firmware_features(struct ath10k *ar)
 {
 	struct ath10k_fw_file *fw_file = &ar->normal_mode_fw.fw_file;
@@ -2260,6 +2269,8 @@  struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
 
 	INIT_WORK(&ar->register_work, ath10k_core_register_work);
 	INIT_WORK(&ar->restart_work, ath10k_core_restart);
+	INIT_WORK(&ar->set_coverage_class_work,
+		  ath10k_core_set_coverage_class_work);
 
 	ret = ath10k_debug_create(ar);
 	if (ret)
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 5ace413..424ed56 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -890,6 +890,18 @@  struct ath10k {
 	struct ath10k_thermal thermal;
 	struct ath10k_wow wow;
 
+	struct work_struct set_coverage_class_work;
+	/* protected by conf_mutex */
+	struct {
+		s16 coverage_class;
+
+		u32 reg_phyclk;
+		u32 reg_slottime_conf;
+		u32 reg_slottime_orig;
+		u32 reg_ack_cts_timeout_conf;
+		u32 reg_ack_cts_timeout_orig;
+	} fw_coverage;
+
 	/* must be last */
 	u8 drv_priv[0] __aligned(sizeof(void *));
 };
diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
index c2ecb9b..688b8b3 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -17,11 +17,14 @@ 
 #include <linux/types.h>
 #include "core.h"
 #include "hw.h"
+#include "hif.h"
+#include "wmi-ops.h"
 
 const struct ath10k_hw_regs qca988x_regs = {
 	.rtc_soc_base_address		= 0x00004000,
 	.rtc_wmac_base_address		= 0x00005000,
 	.soc_core_base_address		= 0x00009000,
+	.wlan_mac_base_address		= 0x00020000,
 	.ce_wrapper_base_address	= 0x00057000,
 	.ce0_base_address		= 0x00057400,
 	.ce1_base_address		= 0x00057800,
@@ -48,6 +51,7 @@  const struct ath10k_hw_regs qca6174_regs = {
 	.rtc_soc_base_address			= 0x00000800,
 	.rtc_wmac_base_address			= 0x00001000,
 	.soc_core_base_address			= 0x0003a000,
+	.wlan_mac_base_address			= 0x00020000,
 	.ce_wrapper_base_address		= 0x00034000,
 	.ce0_base_address			= 0x00034400,
 	.ce1_base_address			= 0x00034800,
@@ -74,6 +78,7 @@  const struct ath10k_hw_regs qca99x0_regs = {
 	.rtc_soc_base_address			= 0x00080000,
 	.rtc_wmac_base_address			= 0x00000000,
 	.soc_core_base_address			= 0x00082000,
+	.wlan_mac_base_address			= 0x00030000,
 	.ce_wrapper_base_address		= 0x0004d000,
 	.ce0_base_address			= 0x0004a000,
 	.ce1_base_address			= 0x0004a400,
@@ -109,6 +114,7 @@  const struct ath10k_hw_regs qca99x0_regs = {
 const struct ath10k_hw_regs qca4019_regs = {
 	.rtc_soc_base_address                   = 0x00080000,
 	.soc_core_base_address                  = 0x00082000,
+	.wlan_mac_base_address                  = 0x00030000,
 	.ce_wrapper_base_address                = 0x0004d000,
 	.ce0_base_address                       = 0x0004a000,
 	.ce1_base_address                       = 0x0004a400,
@@ -220,7 +226,140 @@  void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
 	survey->time_busy = CCNT_TO_MSEC(ar, rcc);
 }
 
+/* The firmware does not support setting the coverage class. Instead this
+ * function monitors and modifies the corresponding MAC registers.
+ */
+static void ath10k_hw_qca988x_set_coverage_class(struct ath10k *ar,
+						 s16 value)
+{
+	u32 slottime_reg;
+	u32 slottime;
+	u32 timeout_reg;
+	u32 ack_timeout;
+	u32 cts_timeout;
+	u32 phyclk_reg;
+	u32 phyclk;
+	u64 fw_dbglog_mask;
+	u32 fw_dbglog_level;
+
+	mutex_lock(&ar->conf_mutex);
+
+	/* Only modify registers if the core is started. */
+	if ((ar->state != ATH10K_STATE_ON) &&
+	    (ar->state != ATH10K_STATE_RESTARTED))
+		goto unlock;
+
+	/* Retrieve the current values of the two registers that need to be
+	 * adjusted.
+	 */
+	slottime_reg = ath10k_hif_read32(ar, WLAN_MAC_BASE_ADDRESS +
+					     WAVE1_PCU_GBL_IFS_SLOT);
+	timeout_reg = ath10k_hif_read32(ar, WLAN_MAC_BASE_ADDRESS +
+					    WAVE1_PCU_ACK_CTS_TIMEOUT);
+	phyclk_reg = ath10k_hif_read32(ar, WLAN_MAC_BASE_ADDRESS +
+					   WAVE1_PHYCLK);
+	phyclk = MS(phyclk_reg, WAVE1_PHYCLK_USEC) + 1;
+
+	if (value < 0)
+		value = ar->fw_coverage.coverage_class;
+
+	/* Break out if the coverage class and registers have the expected
+	 * value.
+	 */
+	if (value == ar->fw_coverage.coverage_class &&
+	    slottime_reg == ar->fw_coverage.reg_slottime_conf &&
+	    timeout_reg == ar->fw_coverage.reg_ack_cts_timeout_conf &&
+	    phyclk_reg == ar->fw_coverage.reg_phyclk)
+		goto unlock;
+
+	/* Store new initial register values from the firmware. */
+	if (slottime_reg != ar->fw_coverage.reg_slottime_conf)
+		ar->fw_coverage.reg_slottime_orig = slottime_reg;
+	if (timeout_reg != ar->fw_coverage.reg_ack_cts_timeout_conf)
+		ar->fw_coverage.reg_ack_cts_timeout_orig = timeout_reg;
+	ar->fw_coverage.reg_phyclk = phyclk_reg;
+
+	/* Calculat new value based on the (original) firmware calculation. */
+	slottime_reg = ar->fw_coverage.reg_slottime_orig;
+	timeout_reg = ar->fw_coverage.reg_ack_cts_timeout_orig;
+
+	/* Do some sanity checks on the slottime register. */
+	if (unlikely(slottime_reg % phyclk)) {
+		ath10k_warn(ar,
+			    "failed to set coverage class: expected integer microsecond value in register\n");
+
+		goto store_regs;
+	}
+
+	slottime = MS(slottime_reg, WAVE1_PCU_GBL_IFS_SLOT);
+	slottime = slottime / phyclk;
+	if (unlikely(slottime != 9 && slottime != 20)) {
+		ath10k_warn(ar,
+			    "failed to set coverage class: expected slot time of 9 or 20us in HW register. It is %uus.\n",
+			    slottime);
+
+		goto store_regs;
+	}
+
+	/* Recalculate the register values by adding the additional propagation
+	 * delay (3us per coverage class).
+	 */
+
+	slottime = MS(slottime_reg, WAVE1_PCU_GBL_IFS_SLOT);
+	slottime += value * 3 * phyclk;
+	slottime = min_t(u32, slottime, WAVE1_PCU_GBL_IFS_SLOT_MAX);
+	slottime = SM(slottime, WAVE1_PCU_GBL_IFS_SLOT);
+	slottime_reg = (slottime_reg & ~WAVE1_PCU_GBL_IFS_SLOT_MASK) | slottime;
+
+	/* Update ack timeout (lower halfword). */
+	ack_timeout = MS(timeout_reg, WAVE1_PCU_ACK_CTS_TIMEOUT_ACK);
+	ack_timeout += 3 * value * phyclk;
+	ack_timeout = min_t(u32, ack_timeout, WAVE1_PCU_ACK_CTS_TIMEOUT_MAX);
+	ack_timeout = SM(ack_timeout, WAVE1_PCU_ACK_CTS_TIMEOUT_ACK);
+
+	/* Update cts timeout (upper halfword). */
+	cts_timeout = MS(timeout_reg, WAVE1_PCU_ACK_CTS_TIMEOUT_CTS);
+	cts_timeout += 3 * value * phyclk;
+	cts_timeout = min_t(u32, cts_timeout, WAVE1_PCU_ACK_CTS_TIMEOUT_MAX);
+	cts_timeout = SM(cts_timeout, WAVE1_PCU_ACK_CTS_TIMEOUT_CTS);
+
+	timeout_reg = ack_timeout | cts_timeout;
+
+	ath10k_hif_write32(ar,
+			   WLAN_MAC_BASE_ADDRESS + WAVE1_PCU_GBL_IFS_SLOT,
+			   slottime_reg);
+	ath10k_hif_write32(ar,
+			   WLAN_MAC_BASE_ADDRESS + WAVE1_PCU_ACK_CTS_TIMEOUT,
+			   timeout_reg);
+
+	/* Ensure we have a debug level of WARN set for the case that the
+	 * coverage class is larger than 0. This is important as we need to
+	 * set the registers again if the firmware does an internal reset and
+	 * this way we will be notified of the event.
+	 */
+	fw_dbglog_mask = ar->debug.fw_dbglog_mask;
+	fw_dbglog_level = ar->debug.fw_dbglog_level;
+
+	if (value > 0) {
+		if (fw_dbglog_level > ATH10K_DBGLOG_LEVEL_WARN)
+			fw_dbglog_level = ATH10K_DBGLOG_LEVEL_WARN;
+		fw_dbglog_mask = ~0;
+	}
+
+	ath10k_wmi_dbglog_cfg(ar, fw_dbglog_mask, fw_dbglog_level);
+
+store_regs:
+	/* After an error we will not retry setting the coverage class. */
+	ar->fw_coverage.coverage_class = value;
+	ar->fw_coverage.reg_slottime_conf = slottime_reg;
+	ar->fw_coverage.reg_ack_cts_timeout_conf = timeout_reg;
+
+unlock:
+	mutex_unlock(&ar->conf_mutex);
+}
+
 const struct ath10k_hw_ops qca988x_ops = {
+	.set_coverage_class = ath10k_hw_qca988x_set_coverage_class,
 };
 
 static int ath10k_qca99x0_rx_desc_get_l3_pad_bytes(struct htt_rx_desc *rxd)
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 1ef7dc6..b44f224 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -230,6 +230,7 @@  struct ath10k_hw_regs {
 	u32 rtc_soc_base_address;
 	u32 rtc_wmac_base_address;
 	u32 soc_core_base_address;
+	u32 wlan_mac_base_address;
 	u32 ce_wrapper_base_address;
 	u32 ce0_base_address;
 	u32 ce1_base_address;
@@ -418,6 +419,7 @@  struct htt_rx_desc;
 /* Defines needed for Rx descriptor abstraction */
 struct ath10k_hw_ops {
 	int (*rx_desc_get_l3_pad_bytes)(struct htt_rx_desc *rxd);
+	void (*set_coverage_class)(struct ath10k *ar, s16 value);
 };
 
 extern const struct ath10k_hw_ops qca988x_ops;
@@ -605,7 +607,7 @@  extern const struct ath10k_hw_ops qca99x0_ops;
 #define WLAN_SI_BASE_ADDRESS			0x00010000
 #define WLAN_GPIO_BASE_ADDRESS			0x00014000
 #define WLAN_ANALOG_INTF_BASE_ADDRESS		0x0001c000
-#define WLAN_MAC_BASE_ADDRESS			0x00020000
+#define WLAN_MAC_BASE_ADDRESS			ar->regs->wlan_mac_base_address
 #define EFUSE_BASE_ADDRESS			0x00030000
 #define FPGA_REG_BASE_ADDRESS			0x00039000
 #define WLAN_UART2_BASE_ADDRESS			0x00054c00
@@ -805,4 +807,28 @@  extern const struct ath10k_hw_ops qca99x0_ops;
 
 #define RTC_STATE_V_GET(x) (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB)
 
+/* Register definitions for first generation ath10k cards. These cards include
+ * a mac thich has a register allocation similar to ath9k and at least some
+ * registers including the ones relevant for modifying the coverage class are
+ * identical to the ath9k definitions.
+ * These registers are usually managed by the ath10k firmware. However by
+ * overriding them it is possible to support coverage class modifications.
+ */
+#define WAVE1_PCU_ACK_CTS_TIMEOUT		0x8014
+#define WAVE1_PCU_ACK_CTS_TIMEOUT_MAX		0x00003FFF
+#define WAVE1_PCU_ACK_CTS_TIMEOUT_ACK_MASK	0x00003FFF
+#define WAVE1_PCU_ACK_CTS_TIMEOUT_ACK_LSB	0
+#define WAVE1_PCU_ACK_CTS_TIMEOUT_CTS_MASK	0x3FFF0000
+#define WAVE1_PCU_ACK_CTS_TIMEOUT_CTS_LSB	16
+
+#define WAVE1_PCU_GBL_IFS_SLOT			0x1070
+#define WAVE1_PCU_GBL_IFS_SLOT_MASK		0x0000FFFF
+#define WAVE1_PCU_GBL_IFS_SLOT_MAX		0x0000FFFF
+#define WAVE1_PCU_GBL_IFS_SLOT_LSB		0
+#define WAVE1_PCU_GBL_IFS_SLOT_RESV0		0xFFFF0000
+
+#define WAVE1_PHYCLK				0x801C
+#define WAVE1_PHYCLK_USEC_MASK			0x0000007F
+#define WAVE1_PHYCLK_USEC_LSB			0
+
 #endif /* _HW_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 0bbd0a0..4d04e30 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -5372,6 +5372,20 @@  static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
 	mutex_unlock(&ar->conf_mutex);
 }
 
+static void ath10k_mac_op_set_coverage_class(struct ieee80211_hw *hw, s16 value)
+{
+	struct ath10k *ar = hw->priv;
+
+	/* This function should never be called if setting the coverage class
+	 * is not supported on this hardware.
+	 */
+	if (!ar->hw_params.hw_ops->mac_op_set_coverage_class) {
+		WARN_ON_ONCE(1);
+		return;
+	}
+	ar->hw_params.hw_ops->mac_op_set_coverage_class(ar, value);
+}
+
 static int ath10k_hw_scan(struct ieee80211_hw *hw,
 			  struct ieee80211_vif *vif,
 			  struct ieee80211_scan_request *hw_req)
@@ -7397,6 +7411,7 @@  static const struct ieee80211_ops ath10k_ops = {
 	.remove_interface		= ath10k_remove_interface,
 	.configure_filter		= ath10k_configure_filter,
 	.bss_info_changed		= ath10k_bss_info_changed,
+	.set_coverage_class		= ath10k_mac_op_set_coverage_class,
 	.hw_scan			= ath10k_hw_scan,
 	.cancel_hw_scan			= ath10k_cancel_hw_scan,
 	.set_key			= ath10k_set_key,
@@ -7974,6 +7989,10 @@  int ath10k_mac_register(struct ath10k *ar)
 		      ar->running_fw->fw_file.fw_features))
 		ar->ops->wake_tx_queue = NULL;
 
+	/* Disable set_coverage_class for chipsets that do not support it. */
+	if (!ar->hw_params.hw_ops->mac_op_set_coverage_class)
+		ar->ops->set_coverage_class = NULL;
+
 	ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
 			    ath10k_reg_notifier);
 	if (ret) {
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index d246288..8ccc8cf 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -4879,6 +4879,12 @@  exit:
 	return 0;
 }
 
+static inline void ath10k_wmi_queue_set_coverage_class_work(struct ath10k *ar)
+{
+	if (ar->hw_params.hw_ops->set_coverage_class)
+		queue_work(ar->workqueue, &ar->set_coverage_class_work);
+}
+
 static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_cmd_hdr *cmd_hdr;
@@ -4899,6 +4905,7 @@  static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		return;
 	case WMI_SCAN_EVENTID:
 		ath10k_wmi_event_scan(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_CHAN_INFO_EVENTID:
 		ath10k_wmi_event_chan_info(ar, skb);
@@ -4908,15 +4915,18 @@  static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	case WMI_DEBUG_MESG_EVENTID:
 		ath10k_wmi_event_debug_mesg(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_UPDATE_STATS_EVENTID:
 		ath10k_wmi_event_update_stats(ar, skb);
 		break;
 	case WMI_VDEV_START_RESP_EVENTID:
 		ath10k_wmi_event_vdev_start_resp(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_VDEV_STOPPED_EVENTID:
 		ath10k_wmi_event_vdev_stopped(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_PEER_STA_KICKOUT_EVENTID:
 		ath10k_wmi_event_peer_sta_kickout(ar, skb);
@@ -4932,12 +4942,14 @@  static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	case WMI_ROAM_EVENTID:
 		ath10k_wmi_event_roam(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_PROFILE_MATCH:
 		ath10k_wmi_event_profile_match(ar, skb);
 		break;
 	case WMI_DEBUG_PRINT_EVENTID:
 		ath10k_wmi_event_debug_print(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_PDEV_QVIT_EVENTID:
 		ath10k_wmi_event_pdev_qvit(ar, skb);
@@ -4986,6 +4998,7 @@  static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		return;
 	case WMI_READY_EVENTID:
 		ath10k_wmi_event_ready(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	default:
 		ath10k_warn(ar, "Unknown eventid: %d\n", id);
@@ -5029,6 +5042,7 @@  static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		return;
 	case WMI_10X_SCAN_EVENTID:
 		ath10k_wmi_event_scan(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10X_CHAN_INFO_EVENTID:
 		ath10k_wmi_event_chan_info(ar, skb);
@@ -5038,15 +5052,18 @@  static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	case WMI_10X_DEBUG_MESG_EVENTID:
 		ath10k_wmi_event_debug_mesg(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10X_UPDATE_STATS_EVENTID:
 		ath10k_wmi_event_update_stats(ar, skb);
 		break;
 	case WMI_10X_VDEV_START_RESP_EVENTID:
 		ath10k_wmi_event_vdev_start_resp(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10X_VDEV_STOPPED_EVENTID:
 		ath10k_wmi_event_vdev_stopped(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10X_PEER_STA_KICKOUT_EVENTID:
 		ath10k_wmi_event_peer_sta_kickout(ar, skb);
@@ -5062,12 +5079,14 @@  static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	case WMI_10X_ROAM_EVENTID:
 		ath10k_wmi_event_roam(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10X_PROFILE_MATCH:
 		ath10k_wmi_event_profile_match(ar, skb);
 		break;
 	case WMI_10X_DEBUG_PRINT_EVENTID:
 		ath10k_wmi_event_debug_print(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10X_PDEV_QVIT_EVENTID:
 		ath10k_wmi_event_pdev_qvit(ar, skb);
@@ -5107,6 +5126,7 @@  static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		return;
 	case WMI_10X_READY_EVENTID:
 		ath10k_wmi_event_ready(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10X_PDEV_UTF_EVENTID:
 		/* ignore utf events */
@@ -5140,6 +5160,7 @@  static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		return;
 	case WMI_10_2_SCAN_EVENTID:
 		ath10k_wmi_event_scan(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_2_CHAN_INFO_EVENTID:
 		ath10k_wmi_event_chan_info(ar, skb);
@@ -5149,15 +5170,18 @@  static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	case WMI_10_2_DEBUG_MESG_EVENTID:
 		ath10k_wmi_event_debug_mesg(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_2_UPDATE_STATS_EVENTID:
 		ath10k_wmi_event_update_stats(ar, skb);
 		break;
 	case WMI_10_2_VDEV_START_RESP_EVENTID:
 		ath10k_wmi_event_vdev_start_resp(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_2_VDEV_STOPPED_EVENTID:
 		ath10k_wmi_event_vdev_stopped(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_2_PEER_STA_KICKOUT_EVENTID:
 		ath10k_wmi_event_peer_sta_kickout(ar, skb);
@@ -5173,12 +5197,14 @@  static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	case WMI_10_2_ROAM_EVENTID:
 		ath10k_wmi_event_roam(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_2_PROFILE_MATCH:
 		ath10k_wmi_event_profile_match(ar, skb);
 		break;
 	case WMI_10_2_DEBUG_PRINT_EVENTID:
 		ath10k_wmi_event_debug_print(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_2_PDEV_QVIT_EVENTID:
 		ath10k_wmi_event_pdev_qvit(ar, skb);
@@ -5209,15 +5235,18 @@  static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	case WMI_10_2_VDEV_STANDBY_REQ_EVENTID:
 		ath10k_wmi_event_vdev_standby_req(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_2_VDEV_RESUME_REQ_EVENTID:
 		ath10k_wmi_event_vdev_resume_req(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_2_SERVICE_READY_EVENTID:
 		ath10k_wmi_event_service_ready(ar, skb);
 		return;
 	case WMI_10_2_READY_EVENTID:
 		ath10k_wmi_event_ready(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_2_PDEV_TEMPERATURE_EVENTID:
 		ath10k_wmi_event_temperature(ar, skb);
@@ -5267,12 +5296,14 @@  static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	case WMI_10_4_DEBUG_MESG_EVENTID:
 		ath10k_wmi_event_debug_mesg(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_4_SERVICE_READY_EVENTID:
 		ath10k_wmi_event_service_ready(ar, skb);
 		return;
 	case WMI_10_4_SCAN_EVENTID:
 		ath10k_wmi_event_scan(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_4_CHAN_INFO_EVENTID:
 		ath10k_wmi_event_chan_info(ar, skb);
@@ -5282,12 +5313,14 @@  static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	case WMI_10_4_READY_EVENTID:
 		ath10k_wmi_event_ready(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_4_PEER_STA_KICKOUT_EVENTID:
 		ath10k_wmi_event_peer_sta_kickout(ar, skb);
 		break;
 	case WMI_10_4_ROAM_EVENTID:
 		ath10k_wmi_event_roam(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_4_HOST_SWBA_EVENTID:
 		ath10k_wmi_event_host_swba(ar, skb);
@@ -5297,12 +5330,15 @@  static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
 		break;
 	case WMI_10_4_DEBUG_PRINT_EVENTID:
 		ath10k_wmi_event_debug_print(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_4_VDEV_START_RESP_EVENTID:
 		ath10k_wmi_event_vdev_start_resp(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_4_VDEV_STOPPED_EVENTID:
 		ath10k_wmi_event_vdev_stopped(ar, skb);
+		ath10k_wmi_queue_set_coverage_class_work(ar);
 		break;
 	case WMI_10_4_WOW_WAKEUP_HOST_EVENTID:
 	case WMI_10_4_PEER_RATECODE_LIST_EVENTID:
@@ -6017,6 +6053,7 @@  void ath10k_wmi_start_scan_init(struct ath10k *ar,
 		| WMI_SCAN_EVENT_COMPLETED
 		| WMI_SCAN_EVENT_BSS_CHANNEL
 		| WMI_SCAN_EVENT_FOREIGN_CHANNEL
+		| WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT
 		| WMI_SCAN_EVENT_DEQUEUED;
 	arg->scan_ctrl_flags |= WMI_SCAN_CHAN_STAT_EVENT;
 	arg->n_bssids = 1;