* Re: [PATCH v2] wifi: mt76: mt7921: fix txpower reporting
From: Sean Wang @ 2026-03-12 6:38 UTC (permalink / raw)
To: Lucid Duck; +Cc: Felix Fietkau, linux-wireless
In-Reply-To: <20260309215011.96403-1-lucid_duck@justthetip.ca>
Hi Lucid,
On Mon, Mar 9, 2026 at 4:55 PM Lucid Duck <lucid_duck@justthetip.ca> wrote:
>
> Hi Felix,
>
> Friendly ping on this v2 from January 30. Life got in the way of
> following up sooner -- apologies for the delay.
>
> Since submitting, Nick (morrownr, USB-WiFi maintainer) has tested and
> confirmed the fix works on his MT7921U adapter -- 33 dBm on 2.4 GHz
> and 24 dBm on 5 GHz, both matching regulatory limits as expected.
>
> I noticed Bryam Vargas recently submitted a competing fix that updates
> txpower_cur in mt76_connac_mcu_set_rate_txpower(). That function is
> only called from mt7921_set_sar_specs(), so it wouldn't fire during
> normal AP association or channel changes. My v2 hooks
> bss_info_changed() on BSS_CHANGED_TXPOWER, which covers the common
> case.
>
The maximum value tracked in the loop inside
mt76_connac_mcu_rate_txpower_band() is close to the actual maximum power
that users generally expect to see reported.
If the value is not derived from that path, the reported txpower may not
reflect the SAR limits that are actually applied to the hardware.
mt7921_set_sar_specs() is mainly the userspace entry point for SAR
configuration. The actual SAR power update path goes through
mt7921_set_tx_sar_pwr().
If you look closely, mt7921_set_tx_sar_pwr() is invoked in several
situations, including device start and regulatory updates. Therefore it
is still part of the configuration flow that determines the effective
transmit power.
> Happy to rework if you'd prefer a different approach -- just wanted to
> make sure this wasn't lost in the shuffle.
>
> Thanks,
> Lucid Duck
>
^ permalink raw reply
* RE: [PATCH] wifi: rtw89: retry efuse physical map dump on transient failure
From: Ping-Ke Shih @ 2026-03-12 7:39 UTC (permalink / raw)
To: Christian Hewitt
Cc: Bitterblue Smith, linux-wireless@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <62487266-6846-4E3D-9947-33CB6FE408BF@gmail.com>
Christian Hewitt <christianshewitt@gmail.com> wrote:
> > On 12 Mar 2026, at 6:22 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> >
> > Christian Hewitt <christianshewitt@gmail.com> wrote:
> >>> On 11 Mar 2026, at 7:05 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> >>>
> >>> Christian Hewitt <christianshewitt@gmail.com> wrote:
> >>>>
> >>>>> On 9 Mar 2026, at 6:35 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> >>>>>
> >>>>> Christian Hewitt <christianshewitt@gmail.com> wrote:
> >>>>>>
> >>>>>>> On 2 Mar 2026, at 10:04 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> >>>>>>>
> >>>>>>> Christian Hewitt <christianshewitt@gmail.com> wrote:
> >>>>>>>>> On 2 Mar 2026, at 9:47 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> >>>>>>>>>
> >>>>>>>>> Christian Hewitt <christianshewitt@gmail.com> wrote:
> >>>>>>>>>> On Radxa Rock 5B with a RTL8852BE combo WiFi/BT card, the efuse
> >>>>>>>>>> physical map dump intermittently fails with -EBUSY during probe.
> >>>>>>>>>> The failure occurs in rtw89_dump_physical_efuse_map_ddv() where
> >>>>>>>>>> read_poll_timeout_atomic() times out waiting for the B_AX_EF_RDY
> >>>>>>>>>> bit after 1 second.
> >>>>>>>>>
> >>>>>>>>> I'm checking internally how we handle this case.
> >>>>>
> >>>>> Sorry for the late.
> >>>>>
> >>>>> We encountered WiFi/BT reading efuse at the same time causing similar
> >>>>> problem as yours. The workaround is like yours, which adds timeout
> >>>>> time.
> >>>>>
> >>>>>>>>>
> >>>>>>>>> [...]
> >>>>>>>>>
> >>>>>>>>>>
> >>>>>>>>>> For context, firmware also fails (and recovers) sometimes:
> >>>>>>>>>
> >>>>>>>>> Did you mean this doesn't always happen? sometimes?
> >>>>>>>>
> >>>>>>>> It’s another intermittent behaviour observed on this board (and not
> >>>>>>>> related to the issue this patch targets). It occurs less frequently
> >>>>>>>> than the efuse issue and the existing retry mechanism in the driver
> >>>>>>>> ensures firmware load always succeeds.
> >>>>>
> >>>>> This might be the same cause due to reading efuse in firmware.
> >>>>>
> >>>>> Though we can add more timeout and retry times as workaround, I wonder
> >>>>> if you can control loading time of WiFi and BT kernel modules?
> >>>>>
> >>>>> More, can you do experiment that you load BT module first, and then load
> >>>>> WiFi module after 10 seconds (choose a large number intentionally, or
> >>>>> even larger)?
> >>>>
> >>>> https://paste.libreelec.tv/charmed-turkey.sh
> >>>>
> >>>> I’ve run the above script ^ which removes the wifi and bt modules in
> >>>> sequence then reloads them in the reverse order with a delay between
> >>>> bt and wifi modules loading, then checks for error messages. Over 200
> >>>> test cycles with a 10s delay all were clean (no errors). I also ran
> >>>> cycles with a 2 second delay and 0 second delay before starting wifi
> >>>> module load and those were clear too. I guess that proves sequencing
> >>>> avoids the efuse contention issue? - although it’s not possible in
> >>>> the real-world so not sure there’s huge value in knowing that :)
> >>>
> >>> Thanks for the experiments.
> >>>
> >>> Still want to know is it possible to change sequence/time of loading
> >>> kernel modules at boot time from system level? I mean can you adjust
> >>> the sequence in the Rock 5B board?
> >>
> >> I’m not a kernel expert, but I’ve always understood module probe and
> >> load ordering to not be guaranteed; as many things run in parallel and
> >> are highly subjective to the specific hardware capabilities and kernel
> >> config being used.
> >
> > I have heard people about changing sequence/time of kernel modules, so
> > I'd like you can try this method.
> >
> > I did ask AI, it said it is possible to create a .conf file under
> > /etc/modprobe.d/ and use `softdep` syntax to ensure loading sequence.
> > Could you try this?
>
> I can test this, but even if it works it’s not a fix because modprobe
> confs configured in userspace are only used with loadable modules that
> have been compiled with =m, not build-in modules that are resident in
> kernel memory and compiled with =y; and distros are free to choose how
> their kernel is configured. NB: I’m not sure if there are any general
> kernel rules for this, but I’d expect there to be general principle of
> modules being resilient to transient host states and not depending on
> userspace packaging to load correctly?
I think built-in modules will be loaded sequentially (not in parallel)
by device_initicall(), so BT and WiFi drivers will not read efuse
at the same time.
>
> >> In addition, did below messages not appear in these experiments?
> >>>
> >>> [ 7.864148] rtw89_8852be 0002:21:00.0: fw security fail
> >>> [ 7.864154] rtw89_8852be 0002:21:00.0: download firmware fail
> >>
> >> No, because even if we have a 0s delay between each group of modules
> >> being loaded, they are loaded in series, so we workaround the issue.
> >> Tweaking the script to background the module load loops so both run
> >> in parallel would be closer to normal conditions, and I would expect
> >> to start seeing failures and the retry mechanisms within the modules
> >> (as added in this patch) being triggered.
> >
> > Additional question for downloading firmware. As you reported this
> > issue initially (load modules at boot time in parallel), it seems
> > appear this message by chance. Since this driver will retry to download
> > firmware, will it successfully downloads firmware finally? Or it still
> > fails to download after 5 times retry?
>
> I have only seen firmware load fail a handful of times in many hundreds
> of boots and each time one retry attempt resulted in success. To be
> clear; I have am not reporting firwmare loading as a problem, it is not
> an issue for me. I’ve mentioned it only for context, i.e. it shows that
> a simple retry mechanism is effective at handling the similar issue with
> efuse map.
I have this question because I wonder downloading firmware issue might be
also a reading efuse issue. If so, retry might resolve as well.
As your results, it looks like to retry reading efuse can resolve all
issues you found. What do you think?
Ping-Ke
^ permalink raw reply
* Re: [PATCH] wifi: rtw89: retry efuse physical map dump on transient failure
From: Christian Hewitt @ 2026-03-12 8:11 UTC (permalink / raw)
To: Ping-Ke Shih
Cc: Bitterblue Smith, linux-wireless@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <3f072307ed634e878c7d9da152801aec@realtek.com>
> On 12 Mar 2026, at 11:39 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
>
> Christian Hewitt <christianshewitt@gmail.com> wrote:
>>> On 12 Mar 2026, at 6:22 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
>>>
>>> Christian Hewitt <christianshewitt@gmail.com> wrote:
>>>>> On 11 Mar 2026, at 7:05 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
>>>>>
>>>>> Christian Hewitt <christianshewitt@gmail.com> wrote:
>>>>>>
>>>>>>> On 9 Mar 2026, at 6:35 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
>>>>>>>
>>>>>>> Christian Hewitt <christianshewitt@gmail.com> wrote:
>>>>>>>>
>>>>>>>>> On 2 Mar 2026, at 10:04 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
>>>>>>>>>
>>>>>>>>> Christian Hewitt <christianshewitt@gmail.com> wrote:
>>>>>>>>>>> On 2 Mar 2026, at 9:47 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
>>>>>>>>>>>
>>>>>>>>>>> Christian Hewitt <christianshewitt@gmail.com> wrote:
>>>>>>>>>>>> On Radxa Rock 5B with a RTL8852BE combo WiFi/BT card, the efuse
>>>>>>>>>>>> physical map dump intermittently fails with -EBUSY during probe.
>>>>>>>>>>>> The failure occurs in rtw89_dump_physical_efuse_map_ddv() where
>>>>>>>>>>>> read_poll_timeout_atomic() times out waiting for the B_AX_EF_RDY
>>>>>>>>>>>> bit after 1 second.
>>>>>>>>>>>
>>>>>>>>>>> I'm checking internally how we handle this case.
>>>>>>>
>>>>>>> Sorry for the late.
>>>>>>>
>>>>>>> We encountered WiFi/BT reading efuse at the same time causing similar
>>>>>>> problem as yours. The workaround is like yours, which adds timeout
>>>>>>> time.
>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> [...]
>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> For context, firmware also fails (and recovers) sometimes:
>>>>>>>>>>>
>>>>>>>>>>> Did you mean this doesn't always happen? sometimes?
>>>>>>>>>>
>>>>>>>>>> It’s another intermittent behaviour observed on this board (and not
>>>>>>>>>> related to the issue this patch targets). It occurs less frequently
>>>>>>>>>> than the efuse issue and the existing retry mechanism in the driver
>>>>>>>>>> ensures firmware load always succeeds.
>>>>>>>
>>>>>>> This might be the same cause due to reading efuse in firmware.
>>>>>>>
>>>>>>> Though we can add more timeout and retry times as workaround, I wonder
>>>>>>> if you can control loading time of WiFi and BT kernel modules?
>>>>>>>
>>>>>>> More, can you do experiment that you load BT module first, and then load
>>>>>>> WiFi module after 10 seconds (choose a large number intentionally, or
>>>>>>> even larger)?
>>>>>>
>>>>>> https://paste.libreelec.tv/charmed-turkey.sh
>>>>>>
>>>>>> I’ve run the above script ^ which removes the wifi and bt modules in
>>>>>> sequence then reloads them in the reverse order with a delay between
>>>>>> bt and wifi modules loading, then checks for error messages. Over 200
>>>>>> test cycles with a 10s delay all were clean (no errors). I also ran
>>>>>> cycles with a 2 second delay and 0 second delay before starting wifi
>>>>>> module load and those were clear too. I guess that proves sequencing
>>>>>> avoids the efuse contention issue? - although it’s not possible in
>>>>>> the real-world so not sure there’s huge value in knowing that :)
>>>>>
>>>>> Thanks for the experiments.
>>>>>
>>>>> Still want to know is it possible to change sequence/time of loading
>>>>> kernel modules at boot time from system level? I mean can you adjust
>>>>> the sequence in the Rock 5B board?
>>>>
>>>> I’m not a kernel expert, but I’ve always understood module probe and
>>>> load ordering to not be guaranteed; as many things run in parallel and
>>>> are highly subjective to the specific hardware capabilities and kernel
>>>> config being used.
>>>
>>> I have heard people about changing sequence/time of kernel modules, so
>>> I'd like you can try this method.
>>>
>>> I did ask AI, it said it is possible to create a .conf file under
>>> /etc/modprobe.d/ and use `softdep` syntax to ensure loading sequence.
>>> Could you try this?
>>
>> I can test this, but even if it works it’s not a fix because modprobe
>> confs configured in userspace are only used with loadable modules that
>> have been compiled with =m, not build-in modules that are resident in
>> kernel memory and compiled with =y; and distros are free to choose how
>> their kernel is configured. NB: I’m not sure if there are any general
>> kernel rules for this, but I’d expect there to be general principle of
>> modules being resilient to transient host states and not depending on
>> userspace packaging to load correctly?
>
> I think built-in modules will be loaded sequentially (not in parallel)
> by device_initicall(), so BT and WiFi drivers will not read efuse
> at the same time.
Even if built-in modules are loaded sequentially, the kernel still has
many dynamically loaded modules; and distros can configure that mix as
they like, so you still cannot predict or guarantee the outcome. That
could be changed by requiring rtw89 modules to be =y, but that goes
against the principles of a modular kernel and I’d expect appropriately
rude comments to the idea if submitted :)
>>>> In addition, did below messages not appear in these experiments?
>>>>>
>>>>> [ 7.864148] rtw89_8852be 0002:21:00.0: fw security fail
>>>>> [ 7.864154] rtw89_8852be 0002:21:00.0: download firmware fail
>>>>
>>>> No, because even if we have a 0s delay between each group of modules
>>>> being loaded, they are loaded in series, so we workaround the issue.
>>>> Tweaking the script to background the module load loops so both run
>>>> in parallel would be closer to normal conditions, and I would expect
>>>> to start seeing failures and the retry mechanisms within the modules
>>>> (as added in this patch) being triggered.
>>>
>>> Additional question for downloading firmware. As you reported this
>>> issue initially (load modules at boot time in parallel), it seems
>>> appear this message by chance. Since this driver will retry to download
>>> firmware, will it successfully downloads firmware finally? Or it still
>>> fails to download after 5 times retry?
>>
>> I have only seen firmware load fail a handful of times in many hundreds
>> of boots and each time one retry attempt resulted in success. To be
>> clear; I have am not reporting firwmare loading as a problem, it is not
>> an issue for me. I’ve mentioned it only for context, i.e. it shows that
>> a simple retry mechanism is effective at handling the similar issue with
>> efuse map.
>
> I have this question because I wonder downloading firmware issue might be
> also a reading efuse issue. If so, retry might resolve as well.
Hard to know, but it's an infrequent event and the existing retry mechanism appears to work fine.
> As your results, it looks like to retry reading efuse can resolve all
> issues you found. What do you think?
The patch submitted resolves the efuse map dump for me. If there are more
efuse accesses that need to be addressed I haven’t seen them in tests. If
you are hinting to abstract things further I’d ask you to please propose
an alternative patch that I can test for you; I’m firmly at the novice end
of kernel contributors and unlikely to spot where changes might be needed
without being spoon-fed rather explicit instructions :)
Christian
^ permalink raw reply
* Re: [PATCH wireless-next v8 2/3] wifi: cfg80211: add initial UHR support
From: Johannes Berg @ 2026-03-12 8:22 UTC (permalink / raw)
To: Harshitha Prem, linux-wireless
Cc: Karthikeyan Kathirvel, vasanthakumar.thiagarajan,
Lorenzo Bianconi, ath12k, Jeff Johnson, Ping-Ke Shih,
Manish Dharanenthiran, Jouni Malinen
In-Reply-To: <416d08f1-6b8d-4bf7-9a63-c3c68497d990@oss.qualcomm.com>
On Thu, 2026-03-12 at 11:19 +0530, Harshitha Prem wrote:
> > Yeah, maybe, then it wouldn't ever really go to a normal SET_BEACON any
> > more, maybe?
> >
> > I was thinking more for not having to change all the code in hostapd at
> > a given time, it might be more plausible to still allow SET_BEACON and
> > just keep giving the counter offsets etc., in case e.g. something "old"
> > like short-preamble changes.
> >
> > But clearly hostapd would have to manage those offsets etc. anyway, so
> > perhaps there's really not going to be any reason to support SET_BEACON
> > while updates are in progress. But in that case I'd probably argue it
> > (SET_BEACON) should be disallowed by the kernel, to catch errors.
>
> Yes, that's the idea when any MLD_BSS_UPDATE is in progress, instead of
> sending SET_BEACON rather use MODIFY_MLD_BSS_UPDATE.
I was going to say that introduces its own set of races, if it's trying
to modify the BSS update while it _just_ finished, but actually that
race exists anyway and we'd want to just reject updates (regardless of
which command is used) that refer to now-invalid cookies.
> >
> > > | | |
> > > 6 | | Beacons: 10, 9, 8... |
> > > | |-------------------------->|
> > > | | |
> > > 7 | [CSA Triggered: Link0, | |
> > > | Count 10. Sees Cookie X] | |
> > > | | |
> > > 8 | CMD_START_MLD_BSS_UPDATE | |
> > > | [Type:CSA, Link:0, Tmpls, | |
> > > | Cookie X + Offset, | |
> > > | Post Tmpl (No UHR ele)] | |
> > > |-------------------------->| |
> >
> > Not sure I understand the "No UHR ele" part - surely the post template
> > still has UHR? Or did you mean "UHR parameter update"?
> >
>
> At this point, the CSA post-beacon template would not include the
> updated UHR operation element, since hostapd needs a way to determine
> whether that element should be added. The updated UHR operation element
> is expected to be reflected only after the advance timer expires.
> In a scenario where the CSA completes before the advance timer expires,
> the CSA post-beacon may not actually require the updated UHR operation
> element.
Oh, you were thinking of the _updated_ element only? I read it as "no
UHR operation at all", which seems nonsensical since it's still UHR.
> For example, if the UHR advance timer expires before the CSA completes,
(taking this out of the paragraph)
This seems like a bit of a strange "if" though - hostapd set the timers
in beacon countdown for both, so it can trivially predict which one is
going to expire first, there's nothing that can stop that from happening
the way it was predicted.
It obviously has dependencies between them, but I don't see a way to
avoid them.
> Because of this, an event-driven approach was considered.
[...]
> it could
> notify hostapd, which could then update the CSA post-beacon template
> with the updated UHR operation element via MODIFY_MLD_BSS_UPDATE.
So I think all this is an interesting question we should really decide
on first, before we continue with the details of the design.
We have been talking a lot about templates here, and associated latency
issues, and the question of hostapd being single-threaded comes up again
later in your email, etc.
Each UHR update operation will have three pending templates:
- announcing the update will happen (counting down)
- announcing the update has happened (counting up)
- steady state after the operation
Each additional overlapping operation adds another template (another UHR
update operation is [currently] not permitted by the spec, so there's no
second "counting up"):
time
|
v
|
x <-- beacon transmission
|
| UHR update starts
| - template I: announcing update will happen
| - template II: announcing update has happened
| - template III: steady state after UHR update
|
x <-- switch current template to I, two more pending
|
...
| CSA starts
| - update current beacon I to I': include CSA
| - update template II to II': include CSA
| - update template III to III': include CSA
| (assuming CSA finishes after UHR parameter update)
| - add template IV: post UHR update and post CSA
|
x <-- current template is I' now
|
| (If now something else happens that should be reflected in
| the beacon _immediately_, all four I', II', III', IV templates
| need to be updated.)
|
...
|
x <-- UHR update takes effect, switch to II'
|
...
|
x <-- UHR update is no longer announced, switch to III'
|
...
| channel switch actually happens
|
x <-- CSA has happened, is no longer announced, template IV
|
...
(and you could have more of these overlapping, say link removal happens
at the same time, BSS color change, etc., but each new operation only
updates all the templates and adds at most a single new one, UHR updates
two new ones.)
And if that seems complex already, I haven't drawn this up for multi-
link! That would actually have an effect over all the links of the AP
MLD, since they interact with each other too, and carry some information
with counters from the other APs.
So if only _one_ link is doing updates, the number of templates just
multiplies by the number of links, and if multiple links are doing
overlapping updates you add all of those together; three links doing two
overlapping updates each would have four templates each and thus require
a total of 18 templates! (But that's "only" six overlapping operations.)
Oh and each of those templates would have a whole bunch of counter
offsets, since the counter for each operation may need to be set in
multiple places.
This is clearly a *lot* of complexity, and we haven't even really talked
about sending Probe Response, (Re)Association Response, EPP Capabilities
and Operation Parameter Response (and perhaps other) frames, some of
which may have to carry all of those (six) counters in various places.
My original thought was that yes, indeed we can manage this complexity
in the kernel - each set of these operations gets a set of counter
offsets, and we can either do that in mac80211 or have API to let
firmware fill in the counters, and even extend that so that each
operation's cookie can be given for other frames (mentioned in the
previous paragraph). It does get tedious though ...
(I was going to write something about event-driven updates here, but
another thing came to mind first.)
Considering multi-link, event-driven updates, and all the response
frames that I mentioned above, made me realise that we also need to
think about the design in terms of beacon TBTTs for multiple links. I'd
think that the spec allows having different beacon intervals for
different links, and there are TSF offsets, but there's a question here
if we actually want/need that in the implementation.
If not, and the TBTTs for multiple links are aligned, that could
simplify things quite significantly. If yes, perhaps due to the multi-HW
architecture you (Qualcomm) have, it would require a more complex design
to get it right, especially considering that you could have say 4-5
links max and need to send the response frames.
If beacon intervals are the same and TBTT aligned, then basically you
just have to update all the link beacons once each beacon interval, and
could send (handwaving a bit) the response frames with an indication
that they are expected to go out during a specific period of time, and
if that time is mispredicted by hostapd the frame would get dropped by
the driver/FW, and hostapd could send another response instead with the
updated counters etc.
In this case, you could also make the whole beacon template update
handling event-driven, and just have a single "beacons transmitted"
event to hostapd while any operations are ongoing, and hostapd would
just update all the beacon templates for all the links at that point,
including even writing all the counters itself even, it has plenty of
time (a whole beacon interval) to do that.
However, if they're not aligned, you'd need an event per link, and then
handling it on time is really only plausible if we can require the
beacons to either be at the same time or have a "minimum distance",
because otherwise you could end up with really small time intervals.
It's still maybe possible in that case, because hostapd would know which
link(s) got the beacon TX event, but it'd have to update all links for
each event, and if there are beacons close to each other that could
easily become impossible, because after any beacon TX event it has to
update _all_ links before _any_ link transmits a new beacon, and so it
doesn't work if they're only a short time apart.
I'll stop here, I think there are a couple of system design questions in
this that we need answers on first, particularly the question about
beacon alignment across multiple links. But it also affects how we send
the response frames, and it _would_ be nice to not have to offload the
counter filling in those to the kernel/driver/firmware, since that would
make it far more extensible (e.g. for the EPP frame that doesn't seem to
have been considered so far.)
> It might be possible to rely on a generic notification when this is
> started via CMD_START_MLD_BSS_UPDATE. That said, since CSA has existed
> for a long time, I was wondering whether also sending CH_SWITCH_NOTIFY
> for backward compatibility could be considered, at least initially.
Fair. I think probably easier to _not_ have it, since hostapd would
otherwise have to figure out which one to handle, but I guess TBD.
> That’s a fair point. With multiple operations potentially occurring in
> parallel, it does seem possible that this could gradually result in an
> increasing number of templates being involved.
Yes. I spelled it out more above :)
> > So I'm coming around to the idea that you have a notification and
> > hostapd has to update the templates at that point.
>
> Yes, that does seem to align with the direction here. This approach
> would still partially rely on event‑driven updates (for example,
> reacting to a UHR event) to modify the BSS via CMD_MODIFY_MLD_BSS_UPDATE
> for csa. At the same time, since such notifications would likely require
> the beacon templates to be updated fairly promptly, it does raise some
> open questions around prioritization and handling on the hostapd side,
> particularly given its single‑threaded nature.
Sure, but I think we're reaching a point where the single-threaded
nature will need to be reconsidered anyway, if only to offload longer-
running operations (such as SAE/EPPKE calculations) to another
thread/CPU.
> > > | | |
> > > 23 | | Beacons Continue... |
> > > | |-------------------------->|
> > > | | |
> > > 24 | | Probe Request |
> > > | |<--------------------------|
> > > | | [Fetch TBTT] |
> > > | send_mgmt (TBTT) | |
> > > |<--------------------------| |
> > > | | |
> > > 25 | send_mgmt (Probe Resp | |
> > > | w/ TBTT in UHR Param) | |
> > > |-------------------------->| |
> > > | | |
> >
> > Not sure I follow this part regarding the "TBTT" thing. Are you saying
> > the RX of the probe request would have a TBTT attached to it? But does
> > it matter, what matters is the TX? And that's probably impossible to get
> > right?
>
> What I was trying to describe is the handling of probe and association
> responses during an ongoing UHR CU / EHT CU.
Ah yes, see some thoughts about that above. I think the "fetch TBTT"
basically inherently leaves a race - if we want to fully solve that we
either have to have some "drop frame if it was wrong" thing like I
described above. Perhaps that could be expressed in "don't send this
frame after this TBTT" or something instead of linking to the
operations.
> In such cases, when a probe request or association request is received,
> the corresponding response may need to reflect the current countdown
> state. For example, in the case of UHR, a probe response might need to
> include an UHR parameters update element with the appropriate countdown
> value.
Right, across all the links.
> The idea was that, at the time the response is being constructed, the
> current countdown could be obtained from the relevant cookie and made
> available to user space. This would allow hostapd to build the probe or
> association response accordingly.
Yeah but it's racy anyway, and if there's anything event driven hostapd
knows the counter already. I described some thoughts above, so not going
to elaborate more here for now.
> > It's input into the kernel, so the size doesn't matter, I think? For
> > notifications that might be an issue, and dumpit is used for data going
> > _out_ of the kernel so userspace doesn't have to have arbitrarily large
> > buffers ready before it knows the data, but on input I don't see how it
> > matters.
>
> Based on the earlier discussion in the below thread, I had wondered
> whether there might be a potential bottleneck here.
>
> https://lore.kernel.org/all/c7e383a9-c291-426b-a7f1-7845fabbaeeb@oss.qualcomm.com/
>
> We will re‑check this internally to confirm whether that concern is
> still applicable.
Looks like I never replied to that point there, but I don't think it's
an issue on commands sent to the kernel - the in-kernel socket isn't
limited by the size of any command like a userspace read() or recvmsg()
call is limited to the buffer size it has allocated a priori.
There's no such huge event going to userspace in the design, but I
suppose even if there _was_ we could just mandate that hostapd increase
the recvmsg() buffer size according to the number of links or such that
it expects to handle, or even just use a huge size (a few dozen KiB) for
each call, it's not really a big deal either way IMHO.
We don't want to have such huge events (we really can't have them as
multicast events), and we generally strive to keep dump message size
reasonably small, but I don't think it's going to be a show-stopper.
johannes
^ permalink raw reply
* RE: [PATCH] wifi: rtw89: retry efuse physical map dump on transient failure
From: Ping-Ke Shih @ 2026-03-12 8:28 UTC (permalink / raw)
To: Christian Hewitt
Cc: Bitterblue Smith, linux-wireless@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <70E90B9D-4C33-46B0-92B7-46969F6AF7B0@gmail.com>
Christian Hewitt <christianshewitt@gmail.com> wrote:
>
> > On 12 Mar 2026, at 11:39 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> >
> > Christian Hewitt <christianshewitt@gmail.com> wrote:
> >>> On 12 Mar 2026, at 6:22 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> >>>
> >>> Christian Hewitt <christianshewitt@gmail.com> wrote:
> >>>>> On 11 Mar 2026, at 7:05 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> >>>>>
> >>>>> Christian Hewitt <christianshewitt@gmail.com> wrote:
> >>>>>>
> >>>>>>> On 9 Mar 2026, at 6:35 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> >>>>>>>
> >>>>>>> Christian Hewitt <christianshewitt@gmail.com> wrote:
> >>>>>>>>
> >>>>>>>>> On 2 Mar 2026, at 10:04 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> >>>>>>>>>
> >>>>>>>>> Christian Hewitt <christianshewitt@gmail.com> wrote:
> >>>>>>>>>>> On 2 Mar 2026, at 9:47 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> >>>>>>>>>>>
> >>>>>>>>>>> Christian Hewitt <christianshewitt@gmail.com> wrote:
> >>>>>>>>>>>> On Radxa Rock 5B with a RTL8852BE combo WiFi/BT card, the efuse
> >>>>>>>>>>>> physical map dump intermittently fails with -EBUSY during probe.
> >>>>>>>>>>>> The failure occurs in rtw89_dump_physical_efuse_map_ddv() where
> >>>>>>>>>>>> read_poll_timeout_atomic() times out waiting for the B_AX_EF_RDY
> >>>>>>>>>>>> bit after 1 second.
> >>>>>>>>>>>
> >>>>>>>>>>> I'm checking internally how we handle this case.
> >>>>>>>
> >>>>>>> Sorry for the late.
> >>>>>>>
> >>>>>>> We encountered WiFi/BT reading efuse at the same time causing similar
> >>>>>>> problem as yours. The workaround is like yours, which adds timeout
> >>>>>>> time.
> >>>>>>>
> >>>>>>>>>>>
> >>>>>>>>>>> [...]
> >>>>>>>>>>>
> >>>>>>>>>>>>
> >>>>>>>>>>>> For context, firmware also fails (and recovers) sometimes:
> >>>>>>>>>>>
> >>>>>>>>>>> Did you mean this doesn't always happen? sometimes?
> >>>>>>>>>>
> >>>>>>>>>> It’s another intermittent behaviour observed on this board (and not
> >>>>>>>>>> related to the issue this patch targets). It occurs less frequently
> >>>>>>>>>> than the efuse issue and the existing retry mechanism in the driver
> >>>>>>>>>> ensures firmware load always succeeds.
> >>>>>>>
> >>>>>>> This might be the same cause due to reading efuse in firmware.
> >>>>>>>
> >>>>>>> Though we can add more timeout and retry times as workaround, I wonder
> >>>>>>> if you can control loading time of WiFi and BT kernel modules?
> >>>>>>>
> >>>>>>> More, can you do experiment that you load BT module first, and then load
> >>>>>>> WiFi module after 10 seconds (choose a large number intentionally, or
> >>>>>>> even larger)?
> >>>>>>
> >>>>>> https://paste.libreelec.tv/charmed-turkey.sh
> >>>>>>
> >>>>>> I’ve run the above script ^ which removes the wifi and bt modules in
> >>>>>> sequence then reloads them in the reverse order with a delay between
> >>>>>> bt and wifi modules loading, then checks for error messages. Over 200
> >>>>>> test cycles with a 10s delay all were clean (no errors). I also ran
> >>>>>> cycles with a 2 second delay and 0 second delay before starting wifi
> >>>>>> module load and those were clear too. I guess that proves sequencing
> >>>>>> avoids the efuse contention issue? - although it’s not possible in
> >>>>>> the real-world so not sure there’s huge value in knowing that :)
> >>>>>
> >>>>> Thanks for the experiments.
> >>>>>
> >>>>> Still want to know is it possible to change sequence/time of loading
> >>>>> kernel modules at boot time from system level? I mean can you adjust
> >>>>> the sequence in the Rock 5B board?
> >>>>
> >>>> I’m not a kernel expert, but I’ve always understood module probe and
> >>>> load ordering to not be guaranteed; as many things run in parallel and
> >>>> are highly subjective to the specific hardware capabilities and kernel
> >>>> config being used.
> >>>
> >>> I have heard people about changing sequence/time of kernel modules, so
> >>> I'd like you can try this method.
> >>>
> >>> I did ask AI, it said it is possible to create a .conf file under
> >>> /etc/modprobe.d/ and use `softdep` syntax to ensure loading sequence.
> >>> Could you try this?
> >>
> >> I can test this, but even if it works it’s not a fix because modprobe
> >> confs configured in userspace are only used with loadable modules that
> >> have been compiled with =m, not build-in modules that are resident in
> >> kernel memory and compiled with =y; and distros are free to choose how
> >> their kernel is configured. NB: I’m not sure if there are any general
> >> kernel rules for this, but I’d expect there to be general principle of
> >> modules being resilient to transient host states and not depending on
> >> userspace packaging to load correctly?
> >
> > I think built-in modules will be loaded sequentially (not in parallel)
> > by device_initicall(), so BT and WiFi drivers will not read efuse
> > at the same time.
>
> Even if built-in modules are loaded sequentially, the kernel still has
> many dynamically loaded modules; and distros can configure that mix as
> they like, so you still cannot predict or guarantee the outcome. That
> could be changed by requiring rtw89 modules to be =y, but that goes
> against the principles of a modular kernel and I’d expect appropriately
> rude comments to the idea if submitted :)
As I know, dynamical modules are executed after init process, but that's
not your case. Let's clarify if /etc/modprobe.d/ with `softdep` option
can resolve your problem. I'd like to know the result. :)
>
> >>>> In addition, did below messages not appear in these experiments?
> >>>>>
> >>>>> [ 7.864148] rtw89_8852be 0002:21:00.0: fw security fail
> >>>>> [ 7.864154] rtw89_8852be 0002:21:00.0: download firmware fail
> >>>>
> >>>> No, because even if we have a 0s delay between each group of modules
> >>>> being loaded, they are loaded in series, so we workaround the issue.
> >>>> Tweaking the script to background the module load loops so both run
> >>>> in parallel would be closer to normal conditions, and I would expect
> >>>> to start seeing failures and the retry mechanisms within the modules
> >>>> (as added in this patch) being triggered.
> >>>
> >>> Additional question for downloading firmware. As you reported this
> >>> issue initially (load modules at boot time in parallel), it seems
> >>> appear this message by chance. Since this driver will retry to download
> >>> firmware, will it successfully downloads firmware finally? Or it still
> >>> fails to download after 5 times retry?
> >>
> >> I have only seen firmware load fail a handful of times in many hundreds
> >> of boots and each time one retry attempt resulted in success. To be
> >> clear; I have am not reporting firwmare loading as a problem, it is not
> >> an issue for me. I’ve mentioned it only for context, i.e. it shows that
> >> a simple retry mechanism is effective at handling the similar issue with
> >> efuse map.
> >
> > I have this question because I wonder downloading firmware issue might be
> > also a reading efuse issue. If so, retry might resolve as well.
>
> Hard to know, but it's an infrequent event and the existing retry mechanism
> appears to work fine.
>
> > As your results, it looks like to retry reading efuse can resolve all
> > issues you found. What do you think?
>
> The patch submitted resolves the efuse map dump for me. If there are more
> efuse accesses that need to be addressed I haven’t seen them in tests. If
> you are hinting to abstract things further I’d ask you to please propose
> an alternative patch that I can test for you; I’m firmly at the novice end
> of kernel contributors and unlikely to spot where changes might be needed
> without being spoon-fed rather explicit instructions :)
I will start to review this patch in detail and consider if another
alternative method.
Ping-Ke
^ permalink raw reply
* Re: [PATCH v10 00/21] wifi: nxpwifi: create nxpwifi to support
From: Jeff Chen @ 2026-03-12 8:56 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, linux-kernel, francesco, wyatt.hsu, s.hauer
In-Reply-To: <8ebc201c976f11cce4802e9e34c1f479ee190ac8.camel@sipsolutions.net>
On Wed, Mar 11, 2026 at 08:02:45 AM +0100, Johannes Berg wrote:
> On Wed, 2026-03-11 at 11:30 +0800, Jeff Chen wrote:
> > On Fri, Mar 06, 2026 at 10:19:43 AM +0100, Johannes Berg wrote:
> > > On Thu, 2026-03-05 at 22:39 +0800, Jeff Chen wrote:
> > > > This series adds a new full-MAC Wi-Fi driver `nxpwifi` to support NXP
> > > > IW611/IW612 chip family. These chips are tri-radio single-chip solutions
> > > > with Wi-Fi 6(1x1, 2.4/5 GHz), Bluetooth 5.4, and IEEE 802.15.4.
> > > > Communication with the external host is via SDIO interface. The driver is
> > > > tested on i.MX8M Mini EVK in both STA and AP mode.
> > >
> > > How exactly was it tested, it doesn't even build ;-)
> >
> > Hi Johannes,
> >
> > I’d like to double check whether it was caused by the missing IW61x SDIO IDs in sdio_ids.h:
> > #define SDIO_VENDOR_ID_NXP 0x0471
> > #define SDIO_DEVICE_ID_NXP_IW61X 0x0205
>
> Probably? I didn't really check too much what the failures were, it's on
> patchwork and you can check yourself. I just briefly checked that it
> wasn't a false report.
Hi Johannes,
Thanks for the clarification.
I checked the patchwork build checks, and the failure is indeed caused by the IW61x SDIO IDs
not being defined.
> > These definitions were not yet in wireless-next around 2026-03-06 when v10 was tested, and
> > only appeared in linux-next after 2026-03-10.
> > Could the build issue you saw be due to these two IDs not being defined at that time?
>
> Obviously that would be an issue, and they still don't appear in
> wireless-next, which tree do they actually appear in? There's usually
> very little to no cross-tree merging going on before it all hits Linus's
> tree, but it has to build before that happens, so I don't know how you
> expected this to work?
Right, understood. The IW61x SDIO IDs currently appear only in linux-next, not in wireless-next,
and the patchwork build logs confirm the build failure is exactly due to these IDs being
undefined.
For v11, I’ll add a small temporary patch with local fallback #defines (guarded with #ifndef) so
that wireless-next can build independently without relying on any cross-tree merges. I’ll drop
that patch once the IDs reach mainline.
Thanks,
Jeff
^ permalink raw reply
* ath12k: handling of HE and EHT capabilities
From: Alexander Wilhelm @ 2026-03-12 9:02 UTC (permalink / raw)
To: Jeff Johnson; +Cc: ath12k, linux-wireless, linux-kernel
Hello devs,
I’m currently trying to fix the HE and EHT capabilities handling on the
big‑endian platform. Unfortunately, I don’t fully understand how exactly
these capabilities are supposed to be defined.
For example, I use the `iw` tool to display the capabilities and their
descriptions. The code for that has the following function prototypes:
* void print_ht_capability(__u16 cap);
* void print_vht_info(__u32 capa, const __u8 *mcs);
* static void __print_he_capa(const __u16 *mac_cap,
const __u16 *phy_cap,
const __u16 *mcs_set, size_t mcs_len,
const __u8 *ppet, int ppet_len,
bool indent);
* static void __print_eht_capa(int band,
const __u8 *mac_cap,
const __u32 *phy_cap,
const __u8 *mcs_set, size_t mcs_len,
const __u8 *ppet, size_t ppet_len,
const __u16 *he_phy_cap,
bool indent);
For HE capabilites in 6 GHz band I couldn't find the respective function.
Then I looked into `include/net/cfg80211.h` and examined the structures
that define the capability data types.
struct ieee80211_sta_ht_cap {
u16 cap; /* use IEEE80211_HT_CAP_ */
bool ht_supported;
u8 ampdu_factor;
u8 ampdu_density;
struct ieee80211_mcs_info mcs;
};
struct ieee80211_sta_vht_cap {
bool vht_supported;
u32 cap; /* use IEEE80211_VHT_CAP_ */
struct ieee80211_vht_mcs_info vht_mcs;
};
The structs for HT and VHT use `u16` and `u32` data types for the `cap`
variable, matching what `iw` does. That part is consistent.
struct ieee80211_he_cap_elem {
u8 mac_cap_info[6];
u8 phy_cap_info[11];
} __packed;
struct ieee80211_he_6ghz_capa {
/* uses IEEE80211_HE_6GHZ_CAP_* below */
__le16 capa; }
__packed;
However, for HE the types differ from the `iw` implementation. Here, `u8`
arrays are used instead of `u16` for MAC and PHY capabilities. The 6 GHz
capabilities use `u16`, which is also different.
struct ieee80211_eht_cap_elem_fixed {
u8 mac_cap_info[2];
u8 phy_cap_info[9];
} __packed;
For EHT, `u8` arrays are also used for both MAC and PHY caps, instead of
`u32` for the PHY caps as in the `iw` implementation.
The current `ath12k` implementation always uses `u32` values, which does
not work on big‑endian platforms:
ath12k_pci 0001:01:00.0: BAR 0: assigned [mem 0xc00000000-0xc001fffff 64bit]
ath12k_pci 0001:01:00.0: MSI vectors: 1
ath12k_pci 0001:01:00.0: Hardware name: qcn9274 hw2.0
ath12k_pci 0001:01:00.0: qmi dma allocation failed (29360128 B type 1), will try later with small size
ath12k_pci 0001:01:00.0: memory type 10 not supported
ath12k_pci 0001:01:00.0: chip_id 0x0 chip_family 0xb board_id 0x1005 soc_id 0x401a2200
ath12k_pci 0001:01:00.0: fw_version 0x111300d6 fw_build_timestamp 2024-08-06 08:43 fw_build_id QC_IMAGE_VERSION_STRING=WLAN.WBE.1.1.1-00214-QCAHKSWPL_SILICONZ-1
ath12k_pci 0001:01:00.0: leaving PCI ASPM disabled to avoid MHI M2 problems
ath12k_pci 0001:01:00.0: Invalid module id 2
ath12k_pci 0001:01:00.0: failed to parse tlv -22
ath12k_pci 0001:01:00.0: ieee80211 registration failed: -22
ath12k_pci 0001:01:00.0: failed register the radio with mac80211: -22
ath12k_pci 0001:01:00.0: failed to create pdev core: -22
ath12k_pci 0001:01:00.0: qmi failed set mode request, mode: 4, err = -110
ath12k_pci 0001:01:00.0: qmi failed to send wlan mode off
I want to address and fix this issue. However, I cannot apply the “never
break the userspace” rule here, as it seems, it is already broken. Can
someone help clarify which datatypes are supposed to be used? Once that is
clear, I can fix the `ath12k` implementation.
Best regards
Alexander Wilhelm
^ permalink raw reply
* Re: [PATCH v10 00/21] wifi: nxpwifi: create nxpwifi to support
From: Johannes Berg @ 2026-03-12 9:13 UTC (permalink / raw)
To: Jeff Chen; +Cc: linux-wireless, linux-kernel, francesco, wyatt.hsu, s.hauer
In-Reply-To: <abJ/qONShVDAuyhI@nxpwireless-Inspiron-14-Plus-7440>
On Thu, 2026-03-12 at 16:56 +0800, Jeff Chen wrote:
>
> Right, understood. The IW61x SDIO IDs currently appear only in linux-next, not in wireless-next,
> and the patchwork build logs confirm the build failure is exactly due to these IDs being
> undefined.
>
> For v11, I’ll add a small temporary patch with local fallback #defines (guarded with #ifndef) so
> that wireless-next can build independently without relying on any cross-tree merges. I’ll drop
> that patch once the IDs reach mainline.
That seems kind of ugly too.
Ulf, do you rebase mmc.git's next branch?
For whatever reason, Jeff sent you the requisite IDs for the driver
rather than putting them into the same patchset and getting your ACK,
and you have it as commit c0b68bc25efe ("mmc: sdio: add NXP vendor and
IW61x device IDs").
It _looks_ like that's in your next branch only, not mux or fixes (but
I'm getting slightly confused by the branch structure), perhaps there's
a chance you could drop that?
Or maybe the less bad option would be to just have that commit twice in
both trees? I'm nott a fan of a local define that we have to clean up
later...
johannes
^ permalink raw reply
* Re: ath12k: handling of HE and EHT capabilities
From: Johannes Berg @ 2026-03-12 9:37 UTC (permalink / raw)
To: Alexander Wilhelm, Jeff Johnson; +Cc: ath12k, linux-wireless, linux-kernel
In-Reply-To: <abKBOp8Jc7f7U0T8@FUE-ALEWI-WINX>
Hi,
> For example, I use the `iw` tool to display the capabilities and their
> descriptions. The code for that has the following function prototypes:
>
> * void print_ht_capability(__u16 cap);
> * void print_vht_info(__u32 capa, const __u8 *mcs);
> * static void __print_he_capa(const __u16 *mac_cap,
> const __u16 *phy_cap,
> const __u16 *mcs_set, size_t mcs_len,
> const __u8 *ppet, int ppet_len,
> bool indent);
> * static void __print_eht_capa(int band,
> const __u8 *mac_cap,
> const __u32 *phy_cap,
> const __u8 *mcs_set, size_t mcs_len,
> const __u8 *ppet, size_t ppet_len,
> const __u16 *he_phy_cap,
> bool indent);
This is perhaps a bit unfortunate, but note that the HE and EHT __u16
and __u32 here are really little endian pointers, and the functions do
byte-order conversion.
> struct ieee80211_sta_ht_cap {
> u16 cap; /* use IEEE80211_HT_CAP_ */
> bool ht_supported;
> u8 ampdu_factor;
> u8 ampdu_density;
> struct ieee80211_mcs_info mcs;
> };
>
> struct ieee80211_sta_vht_cap {
> bool vht_supported;
> u32 cap; /* use IEEE80211_VHT_CAP_ */
> struct ieee80211_vht_mcs_info vht_mcs;
> };
>
> The structs for HT and VHT use `u16` and `u32` data types for the `cap`
> variable, matching what `iw` does. That part is consistent.
Careful. There are different structs used in different places, notably
HT/VHT and HE/EHT differ.
For HT and VHT, look at the start of nl80211_send_band_rateinfo(), which
sends themas individual attributes, defined in enum nl80211_band_attr,
and the values that are u16 (NL80211_BAND_ATTR_HT_CAPA) or u32
(NL80211_BAND_ATTR_VHT_CAPA) are in host byte order, though both are
actually documented misleadingly ("as in [V]HT information IE" is just
all around wrong.)
For HE/EHT, you have it in nl80211_send_iftype_data() since it's per
interface type, and all the individual values are just as they appear in
the spec, regardless of their size.
Note that spec is generally in little endian, but sometimes has strange
field lengths like MAC capabilities being 6 bytes in HE:
> struct ieee80211_he_cap_elem {
> u8 mac_cap_info[6];
> u8 phy_cap_info[11];
> } __packed;
>
> struct ieee80211_he_6ghz_capa {
> /* uses IEEE80211_HE_6GHZ_CAP_* below */
> __le16 capa; }
> __packed;
>
> However, for HE the types differ from the `iw` implementation. Here, `u8`
> arrays are used instead of `u16` for MAC and PHY capabilities. The 6 GHz
> capabilities use `u16`, which is also different.
That doesn't really matter, they're just a set of 6 or 11 bytes, and
e.g. the HE MAC capabilities are treated by the kernel as a set of 6
bytes, but by iw as a set of 3 __le16, which results in the same
interpretation, or at least should.
> struct ieee80211_eht_cap_elem_fixed {
> u8 mac_cap_info[2];
> u8 phy_cap_info[9];
> } __packed;
>
> For EHT, `u8` arrays are also used for both MAC and PHY caps, instead of
> `u32` for the PHY caps as in the `iw` implementation.
Same thing here.
> The current `ath12k` implementation always uses `u32` values, which does
> not work on big‑endian platforms:
Yeah, that seems problematic and not really fitting for something that's
6, 11, 2 or 9 bytes long?
> I want to address and fix this issue. However, I cannot apply the “never
> break the userspace” rule here, as it seems, it is already broken.
I don't think it's broken, why do you say so?
What's (clearly) broken is how ath12k puts the data into the HE/EHT
structs that the kernel expects, but per your dmesg:
> ath12k_pci 0001:01:00.0: ieee80211 registration failed: -22
> ath12k_pci 0001:01:00.0: failed register the radio with mac80211: -22
it seems that even mac80211 doesn't like the capabilities, so the byte
order issue already exists there.
It seems to me the issue is that ath12k_band_cap is in u32, converted,
but then memcpy()d.
johannes
^ permalink raw reply
* [PATCH mt76 2/6] wifi: mt76: mt7996: support critical packet mode for MT7990 chipsets
From: Shayne Chen @ 2026-03-12 9:57 UTC (permalink / raw)
To: Felix Fietkau
Cc: linux-wireless, Lorenzo Bianconi, Ryder Lee, Evelyn Tsai,
Money Wang, linux-mediatek, Howard Hsu, Shayne Chen
In-Reply-To: <20260312095724.2117448-1-shayne.chen@mediatek.com>
From: Howard Hsu <howard-yh.hsu@mediatek.com>
For MT7990 chipsets, critical packet mode must be enabled. Without this,
some higher priority packets may be placed in the wrong AC queue.
Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7996/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index e1e51c9a0767..d286dedddd9b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -56,7 +56,7 @@ static int mt7996_start(struct ieee80211_hw *hw)
mutex_lock(&dev->mt76.mutex);
ret = mt7996_mcu_set_hdr_trans(dev, true);
- if (!ret && is_mt7992(&dev->mt76)) {
+ if (!ret && !is_mt7996(&dev->mt76)) {
u8 queue = mt76_connac_lmac_mapping(IEEE80211_AC_VI);
ret = mt7996_mcu_cp_support(dev, queue);
--
2.51.0
^ permalink raw reply related
* [PATCH mt76 4/6] wifi: mt76: mt7996: adjust timeout value for boot-up calibration commands
From: Shayne Chen @ 2026-03-12 9:57 UTC (permalink / raw)
To: Felix Fietkau
Cc: linux-wireless, Lorenzo Bianconi, Ryder Lee, Evelyn Tsai,
Money Wang, linux-mediatek, Rex Lu, Shayne Chen
In-Reply-To: <20260312095724.2117448-1-shayne.chen@mediatek.com>
From: Rex Lu <rex.lu@mediatek.com>
Align the vendor driver by adjusting the timeout values for the
MCU_UNI_CMD_EFUSE_CTRL and MCU_UNI_CMD_EXT_EEPROM_CTRL commands.
Without this adjustment, false positive command timeout errors may occur,
especially on some iPA variants.
Signed-off-by: Rex Lu <rex.lu@mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index bdb9e30c54c1..2a9c59d15894 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -271,7 +271,8 @@ mt7996_mcu_set_timeout(struct mt76_dev *mdev, int cmd)
mdev->mcu.timeout = 2 * HZ;
return;
case MCU_UNI_CMD_EFUSE_CTRL:
- mdev->mcu.timeout = 20 * HZ;
+ case MCU_UNI_CMD_EXT_EEPROM_CTRL:
+ mdev->mcu.timeout = 30 * HZ;
return;
default:
break;
--
2.51.0
^ permalink raw reply related
* [PATCH mt76 3/6] wifi: mt76: mt7996: update WFSYS reset flow for MT7990 chipsets
From: Shayne Chen @ 2026-03-12 9:57 UTC (permalink / raw)
To: Felix Fietkau
Cc: linux-wireless, Lorenzo Bianconi, Ryder Lee, Evelyn Tsai,
Money Wang, linux-mediatek, Peter Chiu, Shayne Chen
In-Reply-To: <20260312095724.2117448-1-shayne.chen@mediatek.com>
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Skip WFSYS reset during bootup for MT7990 chipsets; only reset if L0.5
recovery is triggered.
Without this fix, the following kernel error may occur:
Internal error: synchronous external abort.
Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
---
.../net/wireless/mediatek/mt76/mt7996/init.c | 29 +++++++++++++++++--
.../net/wireless/mediatek/mt76/mt7996/regs.h | 8 +++++
2 files changed, 34 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
index f3239f530aea..8dfb81eabc9a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
@@ -791,11 +791,34 @@ static void mt7996_init_work(struct work_struct *work)
void mt7996_wfsys_reset(struct mt7996_dev *dev)
{
- mt76_set(dev, MT_WF_SUBSYS_RST, 0x1);
- msleep(20);
+ if (!is_mt7990(&dev->mt76)) {
+ mt76_set(dev, MT_WF_SUBSYS_RST, 0x1);
+ msleep(20);
+
+ mt76_clear(dev, MT_WF_SUBSYS_RST, 0x1);
+ msleep(20);
+
+ return;
+ }
- mt76_clear(dev, MT_WF_SUBSYS_RST, 0x1);
+ if (!dev->recovery.hw_full_reset)
+ return;
+
+ mt76_set(dev, MT_WF_SUBSYS_RST,
+ MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT |
+ MT_WF_SUBSYS_RST_BYPASS_WFDMA_SLP_PROT |
+ MT_WF_SUBSYS_RST_BYPASS_WFDMA2_SLP_PROT);
+ mt76_rmw(dev, MT_WF_SUBSYS_RST,
+ MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT_CYCLE,
+ u32_encode_bits(0x20, MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT_CYCLE));
+ mt76_clear(dev, MT_WF_L05_RST, MT_WF_L05_RST_WF_RST_MASK);
+ mt76_set(dev, MT_WF_SUBSYS_RST, MT_WF_SUBSYS_RST_WHOLE_PATH_RST);
msleep(20);
+
+ if (mt76_poll(dev, MT_WF_L05_RST, MT_WF_L05_RST_WF_RST_MASK, 0x1a, 1000))
+ return;
+
+ dev_err(dev->mt76.dev, "wfsys reset fail\n");
}
static void mt7996_rro_hw_init_v3(struct mt7996_dev *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h
index 393faae2d52b..c6379933b6c3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h
@@ -736,7 +736,15 @@ enum offs_rev {
#define MT_HW_REV 0x70010204
#define MT_HW_REV1 0x8a00
+#define MT_WF_L05_RST 0x70028550
+#define MT_WF_L05_RST_WF_RST_MASK GENMASK(4, 0)
+
#define MT_WF_SUBSYS_RST 0x70028600
+#define MT_WF_SUBSYS_RST_WHOLE_PATH_RST BIT(0)
+#define MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT BIT(5)
+#define MT_WF_SUBSYS_RST_BYPASS_WFDMA_SLP_PROT BIT(6)
+#define MT_WF_SUBSYS_RST_BYPASS_WFDMA2_SLP_PROT BIT(16)
+#define MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT_CYCLE GENMASK(15, 8)
/* PCIE MAC */
#define MT_PCIE_MAC_BASE 0x74030000
--
2.51.0
^ permalink raw reply related
* [PATCH mt76 1/6] wifi: mt76: mt7996: fix RRO EMU configuration
From: Shayne Chen @ 2026-03-12 9:57 UTC (permalink / raw)
To: Felix Fietkau
Cc: linux-wireless, Lorenzo Bianconi, Ryder Lee, Evelyn Tsai,
Money Wang, linux-mediatek, Peter Chiu, Shayne Chen
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Use the correct helper to update specific bitfields instead of
overwriting the entire register.
Fixes: eedb427eb260 ("wifi: mt76: mt7996: Enable HW RRO for MT7992 chipset")
Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7996/init.c | 3 +--
drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +-
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
index 5aaa93767109..f3239f530aea 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
@@ -873,8 +873,7 @@ void mt7996_rro_hw_init(struct mt7996_dev *dev)
}
} else {
/* set emul 3.0 function */
- mt76_wr(dev, MT_RRO_3_0_EMU_CONF,
- MT_RRO_3_0_EMU_CONF_EN_MASK);
+ mt76_set(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK);
mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE0,
dev->wed_rro.addr_elem[0].phy_addr);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index a415cc610eee..86aaf0f29e28 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -2559,7 +2559,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
mt7996_dma_start(dev, false, false);
if (!is_mt7996(&dev->mt76) && dev->mt76.hwrro_mode == MT76_HWRRO_V3)
- mt76_wr(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK);
+ mt76_set(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK);
if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
u32 wed_irq_mask = MT_INT_TX_DONE_BAND2 |
--
2.51.0
^ permalink raw reply related
* [PATCH mt76 6/6] wifi: mt76: mt7996: fix issues with manually triggered radar detection
From: Shayne Chen @ 2026-03-12 9:57 UTC (permalink / raw)
To: Felix Fietkau
Cc: linux-wireless, Lorenzo Bianconi, Ryder Lee, Evelyn Tsai,
Money Wang, linux-mediatek, StanleyYP Wang, Shayne Chen
In-Reply-To: <20260312095724.2117448-1-shayne.chen@mediatek.com>
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Disallow triggering radar detection on non-DFS channels to prevent paused
TX queues from failing to resume, as a channel switch is not performed in
this case.
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
---
.../wireless/mediatek/mt76/mt7996/debugfs.c | 22 +++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
index 76d623b2cafb..e26bed6b97e7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
@@ -226,14 +226,23 @@ mt7996_radar_trigger(void *data, u64 val)
#define RADAR_BACKGROUND 2
struct mt7996_dev *dev = data;
struct mt7996_phy *phy = mt7996_band_phy(dev, NL80211_BAND_5GHZ);
- int rdd_idx;
+ struct cfg80211_chan_def *chandef;
+ int rdd_idx, ret;
if (!phy || !val || val > RADAR_BACKGROUND)
return -EINVAL;
- if (val == RADAR_BACKGROUND && !dev->rdd2_phy) {
- dev_err(dev->mt76.dev, "Background radar is not enabled\n");
- return -EINVAL;
+ if (test_bit(MT76_SCANNING, &phy->mt76->state))
+ return -EBUSY;
+
+ if (val == RADAR_BACKGROUND) {
+ if (!dev->rdd2_phy || !cfg80211_chandef_valid(&dev->rdd2_chandef)) {
+ dev_err(dev->mt76.dev, "Background radar is not enabled\n");
+ return -EINVAL;
+ }
+ chandef = &dev->rdd2_chandef;
+ } else {
+ chandef = &phy->mt76->chandef;
}
rdd_idx = mt7996_get_rdd_idx(phy, val == RADAR_BACKGROUND);
@@ -242,6 +251,11 @@ mt7996_radar_trigger(void *data, u64 val)
return -EINVAL;
}
+ ret = cfg80211_chandef_dfs_required(dev->mt76.hw->wiphy, chandef,
+ NL80211_IFTYPE_AP);
+ if (ret <= 0)
+ return ret;
+
return mt7996_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, rdd_idx, 0);
}
--
2.51.0
^ permalink raw reply related
* [PATCH mt76 5/6] wifi: mt76: mt7996: fix the temporary buffer for calibration-free data
From: Shayne Chen @ 2026-03-12 9:57 UTC (permalink / raw)
To: Felix Fietkau
Cc: linux-wireless, Lorenzo Bianconi, Ryder Lee, Evelyn Tsai,
Money Wang, linux-mediatek, StanleyYP Wang, Shayne Chen
In-Reply-To: <20260312095724.2117448-1-shayne.chen@mediatek.com>
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Move the declaration of buf[] outside the for loop.
Fixes: 224c7c2be578 ("wifi: mt76: mt7996: apply calibration-free data from OTP")
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index 2a9c59d15894..4c733f51a03e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -4104,6 +4104,7 @@ mt7996_mcu_get_cal_free_data(struct mt7996_dev *dev)
}
for (band = 0; band < __MT_MAX_BAND; band++) {
+ u8 buf[MT7996_EEPROM_BLOCK_SIZE];
const struct cal_free_data *cal;
u16 prev_block_idx = -1;
u16 adie_base;
@@ -4126,13 +4127,13 @@ mt7996_mcu_get_cal_free_data(struct mt7996_dev *dev)
u16 eep_offset = cal[i].eep_offs;
u16 block_idx = adie_offset / MT7996_EEPROM_BLOCK_SIZE;
u16 offset = adie_offset % MT7996_EEPROM_BLOCK_SIZE;
- u8 buf[MT7996_EEPROM_BLOCK_SIZE];
if (is_mt7996(&dev->mt76) && band == MT_BAND1 &&
dev->var.type == MT7996_VAR_TYPE_444)
eep_offset -= MT_EE_7977BN_OFFSET;
if (prev_block_idx != block_idx) {
+ memset(buf, 0, sizeof(buf));
ret = mt7996_mcu_get_eeprom(dev, adie_offset, buf,
MT7996_EEPROM_BLOCK_SIZE,
EEPROM_MODE_EFUSE);
--
2.51.0
^ permalink raw reply related
* [PATCH 00/10] carl9170: 802.11n compliance and driver improvements
From: Masi Osmani @ 2026-03-12 10:37 UTC (permalink / raw)
To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel
The carl9170 driver for Atheros AR9170-based USB WiFi adapters has been
effectively unmaintained since 2016. While the hardware shipped as
Draft-N certified, several 802.11n capabilities were never advertised
to mac80211, diagnostic counters were left as TODO stubs, and some
hardware features were never wired up.
This series addresses these gaps in 10 independent patches, ordered
from simple HT capability flags to more involved PHY programming:
Patches 1-3: HT capability corrections
- Enable SGI_20 (was only SGI_40)
- Advertise RX STBC (1 spatial stream)
- Document the SMPS handler (replacing bare TODO)
Patches 4-5: Diagnostic counters
- Wire up the RX dropped frame counter
- Track PHY errors via debugfs
Patch 6: TX power calibration
- Replace hardcoded 18 dBm with per-channel EEPROM values
Patch 7: Recovery hardening
- Add exponential backoff to prevent restart storms
Patch 8: Antenna diversity
- Enable fast antenna diversity for 2-chain devices
Patch 9: DFS radar detection
- Program radar registers, call ieee80211_radar_detected()
Patch 10: Runtime IQ calibration
- Periodic I/Q recalibration via existing stat_work timer
All patches are individually compile-tested and have been verified
on real hardware (AVM Fritz!WLAN USB Stick N, AR9001U) running
kernel 6.18.12. Each patch applies and compiles independently on
top of the previous ones.
The ath9k PCI driver for the same chipset family serves as the
primary reference for register programming and capability flags.
Masi Osmani (10):
carl9170: mac80211: enable Short Guard Interval for 20 MHz
carl9170: mac80211: advertise RX STBC capability
carl9170: mac80211: document spatial multiplexing power save handler
carl9170: rx: wire up dropped frame counter
carl9170: rx: track PHY errors via debugfs
carl9170: phy: populate per-channel TX power from EEPROM
carl9170: main: add exponential restart backoff
carl9170: phy: enable antenna diversity for 2-chain devices
carl9170: fw: enable DFS radar detection
carl9170: phy: add periodic runtime IQ calibration
drivers/net/wireless/ath/carl9170/carl9170.h | 5 +
drivers/net/wireless/ath/carl9170/debug.c | 2 +
drivers/net/wireless/ath/carl9170/fw.c | 3 +
drivers/net/wireless/ath/carl9170/main.c | 45 ++++-
drivers/net/wireless/ath/carl9170/phy.c | 194 +++++++++++++++++++
drivers/net/wireless/ath/carl9170/rx.c | 23 ++-
6 files changed, 261 insertions(+), 11 deletions(-)
--
2.51.0
^ permalink raw reply
* [PATCH 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz
From: Masi Osmani @ 2026-03-12 10:37 UTC (permalink / raw)
To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel
In-Reply-To: <cover.1773277728.git.mas-i@hotmail.de>
The AR9170 hardware supports Short Guard Interval (400ns) for both
20 MHz and 40 MHz channel widths. SGI_40 was already advertised in
the HT capabilities, but SGI_20 was missing. This reduces the OFDM
symbol duration from 800ns to 400ns on 20 MHz channels, increasing
the maximum PHY rate from 130 Mbps to 144.4 Mbps (MCS 15, 2SS).
ath9k (the PCI sibling for the same AR9xxx chipset family) has
always advertised both SGI_20 and SGI_40.
Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
drivers/net/wireless/ath/carl9170/main.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index a7a9345..aa7e481 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -154,6 +154,7 @@ static struct ieee80211_channel carl9170_5ghz_chantable[] = {
.cap = IEEE80211_HT_CAP_MAX_AMSDU | \
IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
IEEE80211_HT_CAP_SGI_40 | \
+ IEEE80211_HT_CAP_SGI_20 | \
IEEE80211_HT_CAP_DSSSCCK40 | \
IEEE80211_HT_CAP_SM_PS, \
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, \
--
2.51.0
^ permalink raw reply related
* [PATCH 02/10] carl9170: mac80211: advertise RX STBC capability
From: Masi Osmani @ 2026-03-12 10:37 UTC (permalink / raw)
To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel
In-Reply-To: <cover.1773277728.git.mas-i@hotmail.de>
The AR9170 baseband supports receiving Space-Time Block Coded
streams (1 spatial stream). The capability was not advertised
in the HT capabilities, causing peers to never use STBC when
transmitting to us. Enabling RX STBC improves receive diversity
gain and link reliability, especially in multipath environments.
The ath9k driver for the same chipset family advertises RX STBC
based on the number of RX chains. With 2 RX chains, the AR9170
can decode 1 STBC spatial stream.
Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
drivers/net/wireless/ath/carl9170/main.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index aa7e481..6324b38 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -156,7 +156,8 @@ static struct ieee80211_channel carl9170_5ghz_chantable[] = {
IEEE80211_HT_CAP_SGI_40 | \
IEEE80211_HT_CAP_SGI_20 | \
IEEE80211_HT_CAP_DSSSCCK40 | \
- IEEE80211_HT_CAP_SM_PS, \
+ IEEE80211_HT_CAP_SM_PS | \
+ (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, \
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
.mcs = { \
--
2.51.0
^ permalink raw reply related
* [PATCH 03/10] carl9170: mac80211: document spatial multiplexing power save handler
From: Masi Osmani @ 2026-03-12 10:37 UTC (permalink / raw)
To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel
In-Reply-To: <cover.1773277728.git.mas-i@hotmail.de>
Replace the bare TODO comment in the SMPS configuration handler
with documentation explaining why the driver accepts but does not
act on SMPS mode changes.
The AR9170 advertises SM_PS disabled (both chains always active)
in its HT capabilities. While mac80211 may still send SMPS
configuration requests, implementing static or dynamic SMPS would
require firmware support for per-chain enable/disable that the
AR9170 firmware (v1.9.9) does not provide.
Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
drivers/net/wireless/ath/carl9170/main.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 6324b38..d75688c 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -910,7 +910,13 @@ static int carl9170_op_config(struct ieee80211_hw *hw, int radio_idx, u32 change
}
if (changed & IEEE80211_CONF_CHANGE_SMPS) {
- /* TODO */
+ /*
+ * We advertise SM_PS disabled (all chains active).
+ * mac80211 may still request mode changes, which we
+ * accept but only support OFF (both chains active).
+ * Static/dynamic SMPS would require firmware support
+ * for chain control that the AR9170 does not provide.
+ */
err = 0;
}
--
2.51.0
^ permalink raw reply related
* [PATCH 04/10] carl9170: rx: wire up dropped frame counter
From: Masi Osmani @ 2026-03-12 10:37 UTC (permalink / raw)
To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel
In-Reply-To: <cover.1773277728.git.mas-i@hotmail.de>
Increment ar->rx_dropped when frames with unrecognized error
codes are dropped in carl9170_rx_mac_status(). The counter
was already defined in the ar9170 struct and exported via
debugfs, but the actual increment was missing -- only a TODO
comment was in place.
This provides visibility into receive-path frame drops through
the existing debugfs interface.
Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
drivers/net/wireless/ath/carl9170/rx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index 6833430..c664014 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -340,7 +340,7 @@ static int carl9170_rx_mac_status(struct ar9170 *ar,
/* drop any other error frames */
if (unlikely(error)) {
- /* TODO: update netdevice's RX dropped/errors statistics */
+ ar->rx_dropped++;
if (net_ratelimit())
wiphy_dbg(ar->hw->wiphy, "received frame with "
--
2.51.0
^ permalink raw reply related
* [PATCH 05/10] carl9170: rx: track PHY errors via debugfs
From: Masi Osmani @ 2026-03-12 10:38 UTC (permalink / raw)
To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel
In-Reply-To: <cover.1773277728.git.mas-i@hotmail.de>
Count PHY errors reported by the hardware in the RX status and
expose the counter through debugfs as rx_phy_errors. Previously,
PHY errors from ar9170_rx_phystatus were silently ignored (marked
with a TODO comment).
The counter helps diagnose RF environment issues (interference,
multipath, low SNR) without requiring monitor mode or additional
tooling.
Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
drivers/net/wireless/ath/carl9170/carl9170.h | 1 +
drivers/net/wireless/ath/carl9170/debug.c | 2 ++
drivers/net/wireless/ath/carl9170/rx.c | 4 +++-
3 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index ba29b4a..eaac859 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -386,6 +386,7 @@ struct ar9170 {
unsigned int tx_ack_failures;
unsigned int tx_fcs_errors;
unsigned int rx_dropped;
+ unsigned int rx_phy_errors;
/* EEPROM */
struct ar9170_eeprom eeprom;
diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c
index 2d73456..0498df2 100644
--- a/drivers/net/wireless/ath/carl9170/debug.c
+++ b/drivers/net/wireless/ath/carl9170/debug.c
@@ -794,6 +794,7 @@ DEBUGFS_READONLY_FILE(tx_janitor_last_run, 64, "last run:%d ms ago",
DEBUGFS_READONLY_FILE(tx_dropped, 20, "%d", ar->tx_dropped);
DEBUGFS_READONLY_FILE(rx_dropped, 20, "%d", ar->rx_dropped);
+DEBUGFS_READONLY_FILE(rx_phy_errors, 20, "%d", ar->rx_phy_errors);
DEBUGFS_READONLY_FILE(sniffer_enabled, 20, "%d", ar->sniffer_enabled);
DEBUGFS_READONLY_FILE(rx_software_decryption, 20, "%d",
@@ -830,6 +831,7 @@ void carl9170_debugfs_register(struct ar9170 *ar)
DEBUGFS_ADD(tx_ampdu_list_len);
DEBUGFS_ADD(rx_dropped);
+ DEBUGFS_ADD(rx_phy_errors);
DEBUGFS_ADD(sniffer_enabled);
DEBUGFS_ADD(rx_software_decryption);
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index c664014..414d499 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -455,7 +455,9 @@ static void carl9170_rx_phy_status(struct ar9170 *ar,
if (phy->rssi[i] & 0x80)
phy->rssi[i] = ((~phy->rssi[i] & 0x7f) + 1) & 0x7f;
- /* TODO: we could do something with phy_errors */
+ if (phy->phy_err)
+ ar->rx_phy_errors++;
+
status->signal = ar->noise[0] + phy->rssi_combined;
}
--
2.51.0
^ permalink raw reply related
* [PATCH 06/10] carl9170: phy: populate per-channel TX power from EEPROM
From: Masi Osmani @ 2026-03-12 10:38 UTC (permalink / raw)
To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel
In-Reply-To: <cover.1773277728.git.mas-i@hotmail.de>
Replace the hardcoded max_power = 18 dBm (marked XXX) in the
channel definitions with actual per-channel values derived from
the EEPROM calibration target power tables.
The new carl9170_get_max_tgt_power() function interpolates the
maximum target power for a given frequency from the EEPROM's
legacy OFDM and CCK target power tables, using the same frequency
encoding and interpolation helpers already used by the power
calibration code. carl9170_update_channel_maxpower() iterates
all registered channels and updates their max_power fields.
This is called during EEPROM parsing, so mac80211 and userspace
see correct per-channel power limits from the start. The CHAN
macro default of 18 dBm remains as a safe fallback for channels
where EEPROM data is missing.
Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
drivers/net/wireless/ath/carl9170/carl9170.h | 1 +
drivers/net/wireless/ath/carl9170/main.c | 4 +-
drivers/net/wireless/ath/carl9170/phy.c | 88 ++++++++++++++++++++
3 files changed, 92 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index eaac859..a2ffa62 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -602,6 +602,7 @@ int carl9170_led_set_state(struct ar9170 *ar, const u32 led_state);
int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
enum nl80211_channel_type bw);
int carl9170_get_noisefloor(struct ar9170 *ar);
+void carl9170_update_channel_maxpower(struct ar9170 *ar);
/* FW */
int carl9170_parse_firmware(struct ar9170 *ar);
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index d75688c..dcedcb1 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -89,7 +89,7 @@ struct ieee80211_rate __carl9170_ratetable[] = {
#define CHAN(_freq, _idx) { \
.center_freq = (_freq), \
.hw_value = (_idx), \
- .max_power = 18, /* XXX */ \
+ .max_power = 18, \
}
static struct ieee80211_channel carl9170_2ghz_chantable[] = {
@@ -1930,6 +1930,8 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
if (!bands)
return -EINVAL;
+ carl9170_update_channel_maxpower(ar);
+
ar->survey = devm_kcalloc(&ar->udev->dev, chans,
sizeof(struct survey_info), GFP_KERNEL);
if (!ar->survey)
diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
index 34d9fd7..290c336 100644
--- a/drivers/net/wireless/ath/carl9170/phy.c
+++ b/drivers/net/wireless/ath/carl9170/phy.c
@@ -1524,6 +1524,94 @@ static void carl9170_set_power_cal(struct ar9170 *ar, u32 freq,
carl9170_calc_ctl(ar, freq, bw);
}
+static u8 carl9170_get_max_tgt_power(struct ar9170 *ar, u32 freq)
+{
+ struct ar9170_calibration_target_power_legacy *ctpl;
+ int ntargets, idx, n, i;
+ u8 f, max_power = 0;
+ u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS];
+
+ if (freq < 3000)
+ f = freq - 2300;
+ else
+ f = (freq - 4800) / 5;
+
+ /* check legacy target powers (OFDM for 2G, 5G leg) */
+ for (i = 0; i < 2; i++) {
+ switch (i) {
+ case 0:
+ if (freq >= 3000) {
+ ctpl = &ar->eeprom.cal_tgt_pwr_5G[0];
+ ntargets = AR5416_NUM_5G_TARGET_PWRS;
+ } else {
+ ctpl = &ar->eeprom.cal_tgt_pwr_2G_ofdm[0];
+ ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS;
+ }
+ break;
+ case 1:
+ if (freq < 3000) {
+ ctpl = &ar->eeprom.cal_tgt_pwr_2G_cck[0];
+ ntargets = AR5416_NUM_2G_CCK_TARGET_PWRS;
+ } else {
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+
+ for (n = 0; n < ntargets; n++) {
+ if (ctpl[n].freq == 0xff)
+ break;
+ pwr_freqs[n] = ctpl[n].freq;
+ }
+ ntargets = n;
+ if (ntargets < 2)
+ continue;
+
+ idx = carl9170_find_freq_idx(ntargets, pwr_freqs, f);
+ for (n = 0; n < 4; n++) {
+ u8 pwr;
+
+ pwr = carl9170_interpolate_u8(f,
+ ctpl[idx + 0].freq,
+ ctpl[idx + 0].power[n],
+ ctpl[idx + 1].freq,
+ ctpl[idx + 1].power[n]);
+ max_power = max(max_power, pwr);
+ }
+ }
+
+ /* target power is in half-dBm, max_power is in dBm */
+ return max_power / 2;
+}
+
+void carl9170_update_channel_maxpower(struct ar9170 *ar)
+{
+ struct ieee80211_supported_band *band;
+ int i;
+
+ band = ar->hw->wiphy->bands[NL80211_BAND_2GHZ];
+ if (band) {
+ for (i = 0; i < band->n_channels; i++) {
+ u8 pwr = carl9170_get_max_tgt_power(ar,
+ band->channels[i].center_freq);
+ if (pwr)
+ band->channels[i].max_power = pwr;
+ }
+ }
+
+ band = ar->hw->wiphy->bands[NL80211_BAND_5GHZ];
+ if (band) {
+ for (i = 0; i < band->n_channels; i++) {
+ u8 pwr = carl9170_get_max_tgt_power(ar,
+ band->channels[i].center_freq);
+ if (pwr)
+ band->channels[i].max_power = pwr;
+ }
+ }
+}
+
int carl9170_get_noisefloor(struct ar9170 *ar)
{
static const u32 phy_regs[] = {
--
2.51.0
^ permalink raw reply related
* [PATCH 07/10] carl9170: main: add exponential restart backoff
From: Masi Osmani @ 2026-03-12 10:38 UTC (permalink / raw)
To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel
In-Reply-To: <cover.1773277728.git.mas-i@hotmail.de>
When the AR9170 enters a bad state (firmware errors, command
timeouts, TX queue stalls), the driver can trigger rapid-fire
restarts that prevent the device from ever stabilizing.
Add exponential backoff to carl9170_restart(): if a restart
request arrives before the current backoff window has elapsed,
the request is throttled. The backoff starts at 500 ms and
doubles on each restart, capping at 30 seconds. A successful
restart resets the backoff to zero.
Additionally, use named constants for the firmware error
threshold (CARL9170_FW_ERROR_THRESHOLD) instead of a magic
number, and add a window-based counting approach to avoid
accumulating sporadic errors over long uptimes.
Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
drivers/net/wireless/ath/carl9170/carl9170.h | 2 ++
drivers/net/wireless/ath/carl9170/main.c | 27 ++++++++++++++++++++
drivers/net/wireless/ath/carl9170/rx.c | 10 +++++++-
3 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index a2ffa62..2eedb2f 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -301,6 +301,8 @@ struct ar9170 {
bool needs_full_reset;
bool force_usb_reset;
atomic_t pending_restarts;
+ unsigned long last_restart_jiffies;
+ unsigned int restart_backoff_ms;
/* interface mode settings */
struct list_head vif_list;
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index dcedcb1..ebf9fa9 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -492,6 +492,7 @@ static void carl9170_restart_work(struct work_struct *work)
if (!err && !ar->force_usb_reset) {
ar->restart_counter++;
atomic_set(&ar->pending_restarts, 0);
+ ar->restart_backoff_ms = 0;
ieee80211_restart_hw(ar->hw);
} else {
@@ -505,6 +506,9 @@ static void carl9170_restart_work(struct work_struct *work)
}
}
+#define CARL9170_RESTART_BACKOFF_INIT_MS 500
+#define CARL9170_RESTART_BACKOFF_MAX_MS 30000
+
void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r)
{
carl9170_set_state_when(ar, CARL9170_STARTED, CARL9170_IDLE);
@@ -519,6 +523,29 @@ void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r)
return;
}
+ /*
+ * Exponential backoff: if restarts are happening too frequently,
+ * increase the delay before accepting the next one. This prevents
+ * restart storms when the device is in a bad state.
+ */
+ if (ar->last_restart_jiffies &&
+ time_before(jiffies, ar->last_restart_jiffies +
+ msecs_to_jiffies(ar->restart_backoff_ms))) {
+ dev_warn(&ar->udev->dev,
+ "restart (%d) throttled (backoff %u ms)\n",
+ r, ar->restart_backoff_ms);
+ atomic_dec(&ar->pending_restarts);
+ return;
+ }
+
+ ar->last_restart_jiffies = jiffies;
+ if (ar->restart_backoff_ms == 0)
+ ar->restart_backoff_ms = CARL9170_RESTART_BACKOFF_INIT_MS;
+ else
+ ar->restart_backoff_ms = min(ar->restart_backoff_ms * 2,
+ (unsigned int)
+ CARL9170_RESTART_BACKOFF_MAX_MS);
+
ieee80211_stop_queues(ar->hw);
dev_err(&ar->udev->dev, "restart device (%d)\n", r);
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index 414d499..bb909b5 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -46,6 +46,14 @@
#include "hw.h"
#include "cmd.h"
+/*
+ * Time window for firmware error counting. Sporadic errors are
+ * normal over long uptimes; only a burst of errors within a short
+ * window warrants a restart.
+ */
+#define CARL9170_FW_ERROR_WINDOW_MS 10000
+#define CARL9170_FW_ERROR_THRESHOLD 3
+
static void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len)
{
bool restart = false;
@@ -54,7 +62,7 @@ static void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len)
if (len > 3) {
if (memcmp(buf, CARL9170_ERR_MAGIC, 3) == 0) {
ar->fw.err_counter++;
- if (ar->fw.err_counter > 3) {
+ if (ar->fw.err_counter >= CARL9170_FW_ERROR_THRESHOLD) {
restart = true;
reason = CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS;
}
--
2.51.0
^ permalink raw reply related
* [PATCH 08/10] carl9170: phy: enable antenna diversity for 2-chain devices
From: Masi Osmani @ 2026-03-12 10:38 UTC (permalink / raw)
To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel
In-Reply-To: <cover.1773277728.git.mas-i@hotmail.de>
Enable fast antenna diversity on devices with two RX chains
(rx_mask == 3). This programs the MULTICHAIN_GAIN_CTL register
to configure main/alternate LNA settings and enables the
CCK fast antenna diversity bit.
The AR9170 hardware has antenna diversity registers inherited
from the AR9285/AR9287 family, but the carl9170 driver never
programmed them. For dual-chain devices this improves receive
performance in multipath environments by allowing the baseband
to quickly switch between antenna paths.
The diversity configuration mirrors what ath9k uses for the
AR9285 single-chip design:
- Main LNA: LNA1
- Alt LNA: LNA1+LNA2 (combined)
- Gain table: table 0 for both paths
Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
drivers/net/wireless/ath/carl9170/phy.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
index 290c336..bcd9066 100644
--- a/drivers/net/wireless/ath/carl9170/phy.c
+++ b/drivers/net/wireless/ath/carl9170/phy.c
@@ -536,6 +536,31 @@ static int carl9170_init_phy_from_eeprom(struct ar9170 *ar,
carl9170_regwrite(AR9170_PHY_REG_RX_CHAINMASK, ar->eeprom.rx_mask);
carl9170_regwrite(AR9170_PHY_REG_CAL_CHAINMASK, ar->eeprom.rx_mask);
+ /*
+ * Enable fast antenna diversity for 2-chain devices.
+ * Configure main/alt LNA with both chains for best
+ * multipath performance.
+ */
+ if (ar->eeprom.rx_mask == 3) {
+ val = carl9170_def_val(AR9170_PHY_REG_MULTICHAIN_GAIN_CTL,
+ is_2ghz, is_40mhz);
+ val |= AR9170_PHY_9285_ANT_DIV_CTL;
+ SET_VAL(AR9170_PHY_9285_ANT_DIV_ALT_LNACONF, val,
+ AR9170_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2);
+ SET_VAL(AR9170_PHY_9285_ANT_DIV_MAIN_LNACONF, val,
+ AR9170_PHY_9285_ANT_DIV_LNA1);
+ SET_VAL(AR9170_PHY_9285_ANT_DIV_ALT_GAINTB, val,
+ AR9170_PHY_9285_ANT_DIV_GAINTB_0);
+ SET_VAL(AR9170_PHY_9285_ANT_DIV_MAIN_GAINTB, val,
+ AR9170_PHY_9285_ANT_DIV_GAINTB_0);
+ carl9170_regwrite(AR9170_PHY_REG_MULTICHAIN_GAIN_CTL, val);
+
+ val = carl9170_def_val(AR9170_PHY_REG_CCK_DETECT,
+ is_2ghz, is_40mhz);
+ val |= AR9170_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+ carl9170_regwrite(AR9170_PHY_REG_CCK_DETECT, val);
+ }
+
carl9170_regwrite_finish();
return carl9170_regwrite_result();
}
--
2.51.0
^ permalink raw reply related
* [PATCH 09/10] carl9170: fw: enable DFS radar detection
From: Masi Osmani @ 2026-03-12 10:38 UTC (permalink / raw)
To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel
In-Reply-To: <cover.1773277728.git.mas-i@hotmail.de>
Enable DFS (Dynamic Frequency Selection) radar detection on the
AR9170. The hardware has radar detection registers (RADAR_0,
RADAR_1, RADAR_EXT) and the firmware already sends
CARL9170_RSP_RADAR events, but the driver never programmed the
detection parameters and only logged a "please report" message.
Changes:
- Program radar detection pulse parameters in phy.c when the
current channel has IEEE80211_CHAN_RADAR set. Values are
based on ath9k defaults for FCC/ETSI compliance.
- Advertise radar_detect_widths in the interface combination
(fw.c) for 20 MHz noHT, 20 MHz HT, and 40 MHz HT.
- Replace the old "please report" message with a call to
ieee80211_radar_detected() so mac80211 can trigger the
proper DFS state machine (channel switch / CAC).
Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
drivers/net/wireless/ath/carl9170/fw.c | 3 ++
drivers/net/wireless/ath/carl9170/phy.c | 45 +++++++++++++++++++++++++
drivers/net/wireless/ath/carl9170/rx.c | 7 ++--
3 files changed, 50 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c
index 419f553..a730593 100644
--- a/drivers/net/wireless/ath/carl9170/fw.c
+++ b/drivers/net/wireless/ath/carl9170/fw.c
@@ -215,6 +215,9 @@ static void carl9170_fw_set_if_combinations(struct ar9170 *ar,
ar->if_combs[0].max_interfaces = ar->fw.vif_num;
ar->if_combs[0].limits = ar->if_comb_limits;
ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits);
+ ar->if_combs[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+ BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40);
ar->hw->wiphy->iface_combinations = ar->if_combs;
ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs);
diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
index bcd9066..c294df7 100644
--- a/drivers/net/wireless/ath/carl9170/phy.c
+++ b/drivers/net/wireless/ath/carl9170/phy.c
@@ -1637,6 +1637,47 @@ void carl9170_update_channel_maxpower(struct ar9170 *ar)
}
}
+static int carl9170_set_radar_detection(struct ar9170 *ar,
+ struct ieee80211_channel *channel)
+{
+ bool enable = channel->flags & IEEE80211_CHAN_RADAR;
+
+ carl9170_regwrite_begin(ar);
+
+ if (enable) {
+ /*
+ * Configure radar detection pulse parameters.
+ * Values based on ath9k's defaults for FCC/ETSI.
+ */
+ carl9170_regwrite(AR9170_PHY_REG_RADAR_0,
+ AR9170_PHY_RADAR_0_ENA |
+ AR9170_PHY_RADAR_0_FFT_ENA |
+ SET_CONSTVAL(AR9170_PHY_RADAR_0_INBAND, 5) |
+ SET_CONSTVAL(AR9170_PHY_RADAR_0_PRSSI, 1) |
+ SET_CONSTVAL(AR9170_PHY_RADAR_0_HEIGHT, 6) |
+ SET_CONSTVAL(AR9170_PHY_RADAR_0_RRSSI, 12) |
+ SET_CONSTVAL(AR9170_PHY_RADAR_0_FIRPWR, 33));
+
+ carl9170_regwrite(AR9170_PHY_REG_RADAR_1,
+ AR9170_PHY_RADAR_1_MAX_RRSSI |
+ AR9170_PHY_RADAR_1_BLOCK_CHECK |
+ AR9170_PHY_RADAR_1_RELSTEP_CHECK |
+ SET_CONSTVAL(AR9170_PHY_RADAR_1_RELSTEP_THRESH, 8) |
+ SET_CONSTVAL(AR9170_PHY_RADAR_1_RELPWR_THRESH, 12) |
+ SET_CONSTVAL(AR9170_PHY_RADAR_1_MAXLEN, 255));
+
+ carl9170_regwrite(AR9170_PHY_REG_RADAR_EXT,
+ AR9170_PHY_RADAR_EXT_ENA);
+ } else {
+ carl9170_regwrite(AR9170_PHY_REG_RADAR_0, 0);
+ carl9170_regwrite(AR9170_PHY_REG_RADAR_1, 0);
+ carl9170_regwrite(AR9170_PHY_REG_RADAR_EXT, 0);
+ }
+
+ carl9170_regwrite_finish();
+ return carl9170_regwrite_result();
+}
+
int carl9170_get_noisefloor(struct ar9170 *ar)
{
static const u32 phy_regs[] = {
@@ -1739,6 +1780,10 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
if (err)
return err;
+ err = carl9170_set_radar_detection(ar, channel);
+ if (err)
+ return err;
+
tmp = AR9170_PHY_TURBO_FC_SINGLE_HT_LTF1 |
AR9170_PHY_TURBO_FC_HT_EN;
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index bb909b5..1fe727c 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -259,11 +259,8 @@ void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
break;
case CARL9170_RSP_RADAR:
- if (!net_ratelimit())
- break;
-
- wiphy_info(ar->hw->wiphy, "FW: RADAR! Please report this "
- "incident to linux-wireless@vger.kernel.org !\n");
+ wiphy_info(ar->hw->wiphy, "FW: radar pulse detected\n");
+ ieee80211_radar_detected(ar->hw, NULL);
break;
case CARL9170_RSP_GPIO:
--
2.51.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox