wifi: rtw88: preparations for RTL8723B/RTL8723BS
v2 cover wifi: rtw88: preparations for RTL8723B/RTL8723BS
From: Luka Gejak <[email protected]>
This is the first of two series adding support for the Realtek RTL8723B 802.11n chipset and its RTL8723BS SDIO variant to rtw88. It contains only the changes to the shared rtw88 core that the chip driver depends on. The chip itself, the build glue and the MAINTAINERS entry are a second series.
v1 had 19 patches; this has 11.
There is no rtw88-style firmware for this chip and no documentation for the vendor blob it does use, so while bringing it up I deliberately kept the driver as close to the vendor driver's behaviour as I could. With that many unknowns at once, matching the vendor exactly was the only way to tell which difference actually mattered when something did not work, rather than guessing. A number of the v1 patches came from that: they reproduced vendor behaviour that was useful to hold fixed during bring up, not behaviour the chip turns out to require.
Now that the chip works end to end, and prompted by Bitterblue Smith's review, I went back and removed each of those on hardware to find which were actually load bearing. Eight were not. The changelog below gives the measurement for each.
Why the remaining changes are needed
====================================
The vendor firmware's association behaviour and SDIO transfer contract differ from the firmware the existing rtw88 8723-family devices use, and those differences sit in code that lives in the core, so the chip driver cannot handle them on its own.
What is left falls into four groups:
- firmware (patches 3, 4): the GNT_BT command rtw88 does not
implement, and a fix to the reserved page upload handshake;
- coexistence (5, 6): the PTA antenna path has to be programmed
directly during scan and reasserted when associating; - SDIO (7, 8, 9): software free-page and OQT accounting, RX aggregation and interrupt setup, and TX back-pressure with a retry on page starvation;
- association (10, 11): the vendor join sequence, which programs the BSS parameters directly and waits for a beacon from the target before authenticating.
Patches 1 and 2 are the chip type and helper plus a one-line receive fix.
Scope
=====
Everything is gated on rtw_is_8723bs(), which is false for every chip currently supported, so behaviour for existing devices is unchanged. The one exception is patch 2, which extends an existing RTL8703B zero-length-packet check; it is gated on the SDIO interface rather than the chip id, since that is the only place the behaviour has been observed.
Patch 8 changes how the SDIO interrupt status is acknowledged. In v1 that applied to all SDIO parts; it is now scoped to this chip only, and the others keep writing the status word back unchanged.
Fixed in the second series
==========================
Two of the review points are addressed in the chip driver rather than here, because that is the right place for both:
- the hardware capability is filled in from a chip-specific read_efuse, instead of special casing rtw_dump_hw_feature() in the core;
- the receive FCS handling is a chip configuration fix. v1 stopped the core advertising RX_INCLUDES_FCS for this chip. The real cause was that the chip cleared BIT_APP_FCS by assigning WLAN_RCR_CFG over hal.rcr wholesale, where the 8723x siblings only write the register and leave hal.rcr alone. Setting that bit in the chip's WLAN_RCR_CFG makes the descriptor carry the FCS like every other rtw88 chip, so the core needs no special case and both hunks are gone from this series.
Neither change is visible here. I planned to send that series once this one is applied to rtw-next, but I can send it now alongside if you would rather review them together.
Two things deliberately kept
============================
Two further patches could be removed without breaking anything on my test setup, and I have still kept them, because passing on a single AP is not evidence that dropping them is safe:
- the basic-rate handling in patch 11 programs the response rates from the BSS rate elements. Removing it associates and passes traffic here, but this AP advertises a conventional basic-rate set; an AP with an unusual one may not behave the same. rtw88xxa writes a fixed per-band set instead, so there may be a simplification here, but it needs more than one AP to justify.
- the ERP preamble and slot-time handlers in patch 11 respond to BSS_CHANGED_ERP_*. Dropping them passes a static test, but that test cannot see a mid-session ERP change, such as a legacy station joining the BSS.
If you would rather have either of them out, say so and they can go.
Testing
=======
Tested on RTL8723BS hardware together with the second series: repeated scan, authentication, association, WPA2 handshake, DHCP, bidirectional traffic, reconnects and module reloads. On one AP at strong signal (-38 dBm), 2.4 GHz HT40, throughput is roughly 34 Mbit/s down and 17 Mbit/s up, with no "failed to get tx report" warnings and a clean log.
Every patch builds with W=1 with no warnings on its own, and sparse and smatch are clean at the tip. checkpatch --strict is clean across this series. The other rtw88 bus and chip modules continue to build.
Changes in v2:
- Dropped "tx: extend the TX report purge timeout". Instrumenting the report path shows payload[6] & 0xfc equals the enqueued sequence number, 32 out of 32 times, with rtw88's existing decode, and no report is missed. The longer timeout was covering for the next patch, not for the hardware.
- Dropped "fw: handle the RTL8723BS management TX reports". 0x12 and 0x32 are the first payload byte of C2H_CCX_TX_RPT, not C2H IDs; every C2H event this chip sends carries a known id, so the existing handler already covers them. Thanks to Bitterblue for catching this.
- Dropped "fw: send rate adaptation and RSSI info in the vendor layout". The vendor byte layout is equivalent to what the existing macros produce; uplink and the negotiated rate are unchanged without it (16.4/16.5/17.0 against 15.4/16.7/16.6 Mbit/s, MCS7 both ways).
- Dropped "fw: send the media status report in the vendor layout". The role field the vendor sets makes no difference here, as with the other chips.
- Dropped "sdio: handle the RTL8723BS management TX path". Sequence numbers do work for management frames on this chip, so reporting completion at DMA completion is unnecessary.
- Dropped "calibrate and tune the PHY" entirely. All three parts were vendor-matching scaffolding and none survived measurement: the scan-time initial gain override is worse than rtw_phy_dig_set_max_coverage() (five scans found 41 BSSes without it against 34 with it); the IQ calibration works from the normal phy_calibration path; and the hardcoded per-rate TX AGC table overrode the efuse calibration by up to 22 index units and bypassed the regulatory limit the by-rate path applies, which is not something a driver should do.
- Dropped "match the RTL8723BS firmware connect and power save behaviour". Deferring the connect report changes nothing, and the LPS gating cannot be justified from measurement: with RTW_DBG_PS enabled, LPS never engages on this setup at all, so the gating never takes effect here.
- Dropped "advertise the correct receive capabilities". Both halves move into the chip driver, as described above.
- "fw: add the vendor firmware commands" now adds only GNT_BT. rtw88 already implements MACID_CFG and the WL channel info report, and the coexistence antenna select reserve became unused once the PHY patch went.
- The zero-length packet check is gated on SDIO rather than the chip
id.
- The SDIO interrupt acknowledgment change is scoped to this chip.
- The association sequence no longer re-applies the BSS capability at association time; BSS_CHANGED_ERP_PREAMBLE and BSS_CHANGED_ERP_SLOT are handled later in the same callback.
- Register accesses that had raw addresses now use the existing REG_GNT_BT and REG_BT_COEX_ENH_INTR_CTRL, plus a named define for the BB antenna select register.
The implementation is based on the initial RTL8723B work by Michael Straube <[email protected]>:
https://github.com/mistraube/rtw88/tree/rtl8723bs
Based on the rtw-next branch from pkshih/rtw.
Luka Gejak (11):
wifi: rtw88: add the RTL8723B chip type and SDIO helper
wifi: rtw88: rx: mark zero length packets on RTL8723BS
wifi: rtw88: fw: add the GNT_BT firmware command
wifi: rtw88: fw: fix the reserved page upload on RTL8723BS
wifi: rtw88: coex: add the RTL8723BS scan antenna workaround
wifi: rtw88: coex: reassert the antenna path when associating
wifi: rtw88: sdio: track free TX pages and OQT credits for RTL8723BS
wifi: rtw88: sdio: set up RX aggregation and interrupts for RTL8723BS
wifi: rtw88: sdio: add TX back-pressure and retry on page starvation
wifi: rtw88: record beacons from the target BSSID before
authenticating
wifi: rtw88: run the RTL8723BS association register sequence
drivers/net/wireless/realtek/rtw88/coex.c | 225 +++++++- drivers/net/wireless/realtek/rtw88/coex.h | 3 + drivers/net/wireless/realtek/rtw88/fw.c | 38 +- drivers/net/wireless/realtek/rtw88/fw.h | 4 + drivers/net/wireless/realtek/rtw88/mac80211.c | 527 +++++++++++++++++- drivers/net/wireless/realtek/rtw88/main.c | 2 + drivers/net/wireless/realtek/rtw88/main.h | 29 + drivers/net/wireless/realtek/rtw88/reg.h | 3 + drivers/net/wireless/realtek/rtw88/rx.c | 8 +- drivers/net/wireless/realtek/rtw88/sdio.c | 328 ++++++++++- drivers/net/wireless/realtek/rtw88/sdio.h | 18 +- drivers/net/wireless/realtek/rtw88/sec.h | 1 + 12 files changed, 1154 insertions(+), 32 deletions(-)
Signature · 1 line
2.55.0
PATCH v2 1/11 wifi: rtw88: add the RTL8723B chip type and SDIO helper
From: Luka Gejak <[email protected]>
The RTL8723B is a 802.11n combo chip whose SDIO variant, RTL8723BS, runs a Realtek vendor firmware that differs from the firmware used by the other rtw88 8723 family devices. Supporting it needs a number of small adjustments spread across the shared core, all of which have to be restricted to this one chip and bus combination.
Add the chip type and a helper that tests for it, so the changes that follow can be gated without repeating the chip and bus comparison.
--- drivers/net/wireless/realtek/rtw88/main.h | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/net/wireless/realtek/rtw88/main.h +7 -0
@@ -194,6 +194,7 @@ enum rtw_chip_type {RTW_CHIP_TYPE_8723D ,RTW_CHIP_TYPE_8821C ,RTW_CHIP_TYPE_8703B , +RTW_CHIP_TYPE_8723B ,RTW_CHIP_TYPE_8821A ,RTW_CHIP_TYPE_8812A , RTW_CHIP_TYPE_8814A,
@@ -2194,6 +2195,12 @@ static inline bool rtw_chip_has_tx_stbc(struct rtw_dev *rtwdev)return rtwdev->chip->tx_stbc; } +static inline bool rtw_is_8723bs (struct rtw_dev *rtwdev) +{ +return rtwdev->chip->id ==RTW_CHIP_TYPE_8723B && + rtwdev->hci.type ==RTW_HCI_TYPE_SDIO ; +} +static inline u8 rtw_acquire_macid (struct rtw_dev *rtwdev) {unsigned long mac_id;
Signature · 1 line
2.55.0
Ping-Ke Shih
maintainerRE: [PATCH v2 01/11] wifi: rtw88: add the RTL8723B chip type and SDIO helper
Quoted 29 lines · [email protected] <[email protected]> wrote:
From: Luka Gejak <[email protected]>
The RTL8723B is a 802.11n combo chip whose SDIO variant, RTL8723BS, runs a Realtek vendor firmware that differs from the firmware used by the other rtw88 8723 family devices. Supporting it needs a number of small adjustments spread across the shared core, all of which have to be restricted to this one chip and bus combination.
Add the chip type and a helper that tests for it, so the changes that follow can be gated without repeating the chip and bus comparison.
Signed-off-by Luka Gejak <[email protected]>--- drivers/net/wireless/realtek/rtw88/main.h | 7 +++++++ 1 file changed, 7 insertions(+)drivers/net/wireless/realtek/rtw88/main.h +1
-0@@ -194,6 +194,7 @@ enum rtw_chip_type {RTW_CHIP_TYPE_8723D ,RTW_CHIP_TYPE_8821C ,RTW_CHIP_TYPE_8703B , +RTW_CHIP_TYPE_8723B ,RTW_CHIP_TYPE_8821A ,RTW_CHIP_TYPE_8812A , RTW_CHIP_TYPE_8814A,
drivers/net/wireless/realtek/rtw88/main.h static inline bool rtw_chip_has_tx_stbc(struct rtw_dev *rtwdev) · line 2198
Quoted 4 lines
drivers/net/wireless/realtek/rtw88/main.h +1
-0@@ -2194,6 +2195,12 @@ static inline bool rtw_chip_has_tx_stbc(struct rtw_dev *rtwdev)return rtwdev->chip->tx_stbc; } +static inline bool rtw_is_8723bs (struct rtw_dev *rtwdev)
As RTL8723B generation is very different from other chips, you need to add this to deliver different flow. I'd think if we need a set of ops to make code clearer.
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/main.h +5
-1+{ +return rtwdev->chip->id ==RTW_CHIP_TYPE_8723B && + rtwdev->hci.type ==RTW_HCI_TYPE_SDIO ; +} +static inline u8 rtw_acquire_macid (struct rtw_dev *rtwdev) {unsigned long mac_id; --2.55.0
Re: [PATCH v2 01/11] wifi: rtw88: add the RTL8723B chip type and SDIO helper
Quoted 4 lines · Ping-Ke Shih
Quoted 1 line · [email protected] mailto:[email protected] <[email protected]> wrote:
Quoted 9 lines
Quoted 8 lines
From: Luka Gejak <[email protected]>
The RTL8723B is a 802.11n combo chip whose SDIO variant, RTL8723BS, runs a Realtek vendor firmware that differs from the firmware used by the other rtw88 8723 family devices. Supporting it needs a number of small adjustments spread across the shared core, all of which have to be restricted to this one chip and bus combination.
...
Hi everyone,
I apologize for the sudden silence. I have run into unexpected offline circumstances and will be completely away from my development setup for the next few weeks, due to family reasons.
I see all the review comments coming in and I appreciate the thorough feedback. I will address every single one of them and get v3 out as soon as I am back online.
Thank you for your patience!
Best regards,
Luka Gejak
Re: [PATCH v2 01/11] wifi: rtw88: add the RTL8723B chip type and SDIO helper
Quoted 12 lines
...
Hi everyone,
I apologize for the sudden silence. I have run into unexpected offline circumstances and will be completely away from my development setup for the next few weeks, due to family reasons.
I see all the review comments coming in and I appreciate the thorough feedback. I will address every single one of them and get v3 out as soon as I am back online.
Thank you for your patience!
Best regards,
Luka Gejak
Hi everyone,
Hope this message finds you well.
Thankfully the issue was far less serious then I anticipated, therefore I am back online. Thank you for patiently waiting and sorry for the delay and hopefully there will be no such delays anymore.
Best regards,
Luka Gejak
Ping-Ke Shih
maintainerRE: [PATCH v2 01/11] wifi: rtw88: add the RTL8723B chip type and SDIO helper
Quoted 2 lines · Luka Gejak
Thank you for patiently waiting and sorry for the delay and hopefully there will be no such delays anymore.
Honestly, I'm not working so fast. ;)
A large patchset like this, I need to arrange my free time, so you might wait me for one or two weeks.
Ping-Ke
Re: [PATCH v2 01/11] wifi: rtw88: add the RTL8723B chip type and SDIO helper
In reply to Ping-Ke ShihFrom: Luka Gejak <[email protected]>
Quoted 5 lines · Ping-Ke Shih
Quoted 1 line
+static inline bool
rtw_is_8723bs(struct rtw_dev *rtwdev)As RTL8723B generation is very different from other chips, you need to add this to deliver different flow. I'd think if we need a set of ops to make code clearer.
Agreed, and v3 starts on that. The largest offender was patch 11, which had an if/else on the chip in ieee80211_ops::mgd_prepare_tx(). That is now a chip_ops::prepare_tx callback dispatched from rtw_chip_prepare_tx(), so the common path has no chip test left.
For the rest I reduced each site to a single entry point that the common flow calls once and that returns as soon as it has handled the notification, rather than the chip test being repeated in every helper below it:
rtw_coex_8723bs_scan_notify()
rtw_coex_8723bs_connect_notify()
Everything below those now assumes RTL8723BS with BT disabled, which also answers your "callers check this already" comments on patch 05.
The SDIO side is harder to express as ops, because it is the bus driver rather than the chip driver that differs, and rtw_sdio has no per-chip ops table today. If you would rather I add one there too I am happy to do it; it would be four callbacks (free page check, page accounting, output queue wait, transfer sizing) and I did not want to introduce that structure without asking first.
Best regards,
Luka Gejak
Ping-Ke Shih
maintainerRE: [PATCH v2 01/11] wifi: rtw88: add the RTL8723B chip type and SDIO helper
Quoted 3 lines · [email protected] <[email protected]> wrote:
it would be four callbacks (free page check, page accounting, output queue wait, transfer sizing) and I did not want to introduce that structure without asking first.
If these are called from sdio.c, just check chip ID in sdio.c. If they are used by common flow like coex.c, I prefer to implement them by chip_ops.
Ping-ke
RE: [PATCH v2 01/11] wifi: rtw88: add the RTL8723B chip type and SDIO helper
Quoted 5 lines · Ping-Ke Shih
Quoted 3 lines · [email protected] <[email protected]> wrote:
it would be four callbacks (free page check, page accounting, output queue wait, transfer sizing) and I did not want to introduce that structure without asking first.
If these are called from
sdio.c, just check chip ID insdio.c.
That is what v3 already does, so nothing changes there. All four are reached from sdio.c only.
Quoted 2 lines
If they are used by common flow like
coex.c, I prefer to implement them bychip_ops.
Let me list them all so you can rule on all of them at once rather than a file at a time.
Two go regardless of your answer: the chip test inside rtw8723bs_apply_basic_rates() and rtw8723bs_apply_bss_cap() is redundant, both callers already establish the chip. In the second one the NL80211_IFTYPE_STATION half of the same guard is still needed, so only the chip half goes there.
That leaves the following outside sdio.c.
coex.c, 2 sites:
rtw_coex_scan_notify() -> rtw_coex_8723bs_scan_notify()
rtw_coex_connect_notify() -> rtw_coex_8723bs_connect_notify()
Each tests the chip and bt_disabled once and returns true when it has handled the notification; everything below them assumes both.
mac80211.c, 6 sites in rtw_ops_bss_info_changed(): the receive filter on assoc and on disassoc, BSSID change bookkeeping, and the BSS_CHANGED_ERP_PREAMBLE and BSS_CHANGED_ERP_SLOT handlers.
mac80211.c, 2 sites in rtw_ops_set_key(): enabling and disabling default key search for group keys.
rx.c, 1 site in rtw_rx_fill_rx_status(), the zero length packet test. This one runs per received frame, so an indirect call there looks like the wrong trade to me. I would keep it inline unless you disagree.
fw.c, 1 site in rtw_fw_write_data_rsvd_page(), two register save/restore blocks interleaved with the generic ones. I do not see how to lift those into an op without restructuring the whole function, so I would keep that inline too.
For coex.c and the two mac80211.c callbacks I am happy to add ops. One constraint on coex.c: the 8723BS code calls rtw_coex_set_ant_path() and rtw_coex_set_table(), which are static in coex.c. Implementing the ops in rtw8723b.c would mean making those two non-static, which seems worse than the chip test it replaces. What I had in mind is leaving the functions in coex.c, declaring them in coex.h, and having rtw8723b.c point the ops at them, the same shape as the chip_ops::prepare_tx that v3 adds for the association sequence. The generic helpers stay static that way.
Tell me which of those you want as ops and I will do it.
The comment on mod_delayed_work() is already in v3.
Best regards,
Luka Gejak
Ping-Ke Shih
maintainerRE: [PATCH v2 01/11] wifi: rtw88: add the RTL8723B chip type and SDIO helper
Quoted 26 lines · Luka Gejak
Quoted 5 lines · Ping-Ke Shih
Quoted 3 lines · [email protected] <[email protected]> wrote:
it would be four callbacks (free page check, page accounting, output queue wait, transfer sizing) and I did not want to introduce that structure without asking first.
If these are called from
sdio.c, just check chip ID insdio.c.That is what v3 already does, so nothing changes there. All four are reached from
sdio.conly.Quoted 2 lines
If they are used by common flow like
coex.c, I prefer to implement them bychip_ops.Let me list them all so you can rule on all of them at once rather than a file at a time.
Two go regardless of your answer: the chip test inside
rtw8723bs_apply_basic_rates()andrtw8723bs_apply_bss_cap()is redundant, both callers already establish the chip. In the second one theNL80211_IFTYPE_STATIONhalf of the same guard is still needed, so only the chip half goes there.That leaves the following outside
sdio.c.
coex.c, 2 sites:
Quoted 7 lines
rtw_coex_scan_notify()->rtw_coex_8723bs_scan_notify()
rtw_coex_connect_notify()->rtw_coex_8723bs_connect_notify()Each tests the chip and
bt_disabledonce and returns true when it has handled the notification; everything below them assumes both.
mac80211.c, 6 sites inrtw_ops_bss_info_changed(): the receive filter
Should receive filter implement in rtw_ops_configure_filter()?
Quoted 5 lines
on assoc and on disassoc, BSSID change bookkeeping, and the
BSS_CHANGED_ERP_PREAMBLEandBSS_CHANGED_ERP_SLOThandlers.
mac80211.c, 2 sites inrtw_ops_set_key(): enabling and disabling default key search for group keys.
Please check existing codes related to sec->default_key_search to see how to support RTL8723BS by the same flow.
Quoted 4 lines
rx.c, 1 site inrtw_rx_fill_rx_status(), the zero length packet test. This one runs per received frame, so an indirect call there looks like the wrong trade to me. I would keep it inline unless you disagree.
I don't object this. More, I'm considering if no need to check chips, just be a common flow.
Quoted 5 lines
fw.c, 1 site inrtw_fw_write_data_rsvd_page(), two register save/restore blocks interleaved with the generic ones. I do not see how to lift those into an op without restructuring the whole function, so I would keep that inline too.
That looks fine. I remember I don't have comments on this part, no?
Quoted 10 lines
For
coex.cand the twomac80211.ccallbacks I am happy to add ops. One constraint oncoex.c: the 8723BS code callsrtw_coex_set_ant_path()andrtw_coex_set_table(), which are static incoex.c. Implementing the ops inrtw8723b.cwould mean making those two non-static, which seems worse than the chip test it replaces. What I had in mind is leaving the functions incoex.c, declaring them incoex.h, and havingrtw8723b.cpoint the ops at them, the same shape as thechip_ops::prepare_txthat v3 adds for the association sequence. The generic helpers stay static that way.
Did you mean callees of rtw_coex_8723bs_scan_workaround() ? I think you can go with your mind.
Quoted 2 lines
Tell me which of those you want as ops and I will do it.
I'd say the version copy many stuffs from vendor driver. However, we should rewrite and consider the proper places, and if it is actually necessary. The vendor driver is based on cfg80211, and many stuffs have been done by mac80211, so we don't need to implement them in rtw88.
Ping-Ke
RE: [PATCH v2 01/11] wifi: rtw88: add the RTL8723B chip type and SDIO helper
Quoted 28 lines · Ping-Ke Shih
Quoted 26 lines · Luka Gejak
Quoted 5 lines · Ping-Ke Shih
Quoted 3 lines · [email protected] <[email protected]> wrote:
it would be four callbacks (free page check, page accounting, output queue wait, transfer sizing) and I did not want to introduce that structure without asking first.
If these are called from
sdio.c, just check chip ID insdio.c.That is what v3 already does, so nothing changes there. All four are reached from
sdio.conly.Quoted 2 lines
If they are used by common flow like
coex.c, I prefer to implement them bychip_ops.Let me list them all so you can rule on all of them at once rather than a file at a time.
Two go regardless of your answer: the chip test inside
rtw8723bs_apply_basic_rates()andrtw8723bs_apply_bss_cap()is redundant, both callers already establish the chip. In the second one theNL80211_IFTYPE_STATIONhalf of the same guard is still needed, so only the chip half goes there.That leaves the following outside
sdio.c.
coex.c, 2 sites:
Quoted 7 lines
Quoted 7 lines
rtw_coex_scan_notify()->rtw_coex_8723bs_scan_notify()
rtw_coex_connect_notify()->rtw_coex_8723bs_connect_notify()Each tests the chip and
bt_disabledonce and returns true when it has handled the notification; everything below them assumes both.
mac80211.c, 6 sites inrtw_ops_bss_info_changed(): the receive filter
One piece of context first, because it changes most of the answers below. I ran the ablation you asked for in your other mail, and the association register sequence is not needed, nor are the two coexistence patches. Four patches are going from prep, which takes it from ten to six. The measurements and the two corrections I owe you are in my reply to that mail.
Quoted 1 line
Should receive filter implement in
rtw_ops_configure_filter()?
Moot now, the receive filter handling goes with the patch I am dropping. For the record you were pointing at something real, although not quite where I first placed it.
rtw8723b.c does seed hal.rcr in mac_init, so it is not the problem. The asymmetry is in rtw_ops_configure_filter() itself: entering promiscuous clears BIT_CBSSID_BCN and BIT_CBSSID_DATA together, but leaving it restores only BIT_CBSSID_BCN. CBSSID_DATA is therefore gone from hal.rcr for good after the first scan, on any chip, until the next mac_init. That is what the per-association forcing was compensating for.
There is a second one next to it: rtw8723x.c writes WLAN_RCR_CFG straight to REG_RCR in mac_init without putting it into hal.rcr, so on 8723D and 8703B the first configure_filter() call replaces it with the core default from rtw_core_init(), which carries neither CBSSID bit nor AMF.
Both look worth fixing on their own and I am happy to send that separately if you agree with the reading. It is unrelated to this series.
Quoted 2 lines
Please check existing codes related to
sec->default_key_searchto see how to support RTL8723BS by the same flow.
You were right, and more strongly than you put it. rtw_sec_enable_sec_engine() sets default_key_search itself and then programs all four USE_DK bits on that basis, so my enable path was a no-op and my disable path was clearing bits the core had deliberately set. Both sites are gone with the patch, and 24 rekeys completed in the soak without them.
Quoted 2 lines
I don't object this. More, I'm considering if no need to check chips, just be a common flow.
Happy to try that. Dropping the chip test would make the zero length check apply to every chip, so I would rather measure it on the 8703B path than assume; I do not have that hardware. If you are comfortable with it on inspection I will send it as a separate patch that removes the test entirely rather than fold it in here.
Quoted 1 line
That looks fine. I remember I don't have comments on this part, no?
Correct, you had no comments on the reserved page patch itself, only on the DWBCN1 define placement and the comment style, both fixed. The inline chip test there stays.
Quoted 2 lines
Did you mean callees of
rtw_coex_8723bs_scan_workaround()? I think you can go with your mind.
Yes, those were the ones, and thank you, but it is moot now that the coexistence patches are going as well.
Quoted 5 lines
I'd say the version copy many stuffs from vendor driver. However, we should rewrite and consider the proper places, and if it is actually necessary. The vendor driver is based on cfg80211, and many stuffs have been done by mac80211, so we don't need to implement them in rtw88.
That turned out to be exactly right. Four of the ten patches were reproducing vendor behaviour that mac80211 or the core already handles, and they only survived this long because I kept quoting bring-up results instead of re-measuring them. Thanks for pushing on it twice.
Best regards,
Luka Gejak
Ping-Ke Shih
maintainerRE: [PATCH v2 01/11] wifi: rtw88: add the RTL8723B chip type and SDIO helper
Quoted 21 lines · Luka Gejak
Quoted 1 line · Ping-Ke Shih
Should receive filter implement in
rtw_ops_configure_filter()?Moot now, the receive filter handling goes with the patch I am dropping. For the record you were pointing at something real, although not quite where I first placed it.
rtw8723b.cdoes seed hal.rcr inmac_init, so it is not the problem. The asymmetry is inrtw_ops_configure_filter()itself: entering promiscuous clearsBIT_CBSSID_BCNandBIT_CBSSID_DATAtogether, but leaving it restores onlyBIT_CBSSID_BCN.CBSSID_DATAis therefore gone from hal.rcr for good after the first scan, on any chip, until the nextmac_init. That is what the per-association forcing was compensating for.There is a second one next to it:
rtw8723x.cwritesWLAN_RCR_CFGstraight toREG_RCRinmac_initwithout putting it into hal.rcr, so on 8723D and 8703B the firstconfigure_filter()call replaces it with the core default fromrtw_core_init(), which carries neither CBSSID bit nor AMF.
Quoted 3 lines
Both look worth fixing on their own and I am happy to send that separately if you agree with the reading. It is unrelated to this series.
I'm not sure if these specific things are hardly necessary. As you have dropped many unnecessary patches copied from vendor driver, I think you can consider if these can be dropped or integrate to existing chip_ops. I mean if you see somewhere you add rtw_is_8723bs(), just ask yourself that is it actually necessary? Why don't existing chips need it?
Quoted 5 lines
Happy to try that. Dropping the chip test would make the zero length check apply to every chip, so I would rather measure it on the 8703B path than assume; I do not have that hardware. If you are comfortable with it on inspection I will send it as a separate patch that removes the test entirely rather than fold it in here.
I don't have all hardware, so it is hard to me to verify the zero length check. Even though I have hardware, it might happen rarely. So, maybe just keep it as was...
Ping-Ke
PATCH v2 2/11 wifi: rtw88: rx: mark zero length packets on RTL8723BS
In reply to [email protected]From: Luka Gejak <[email protected]>
Like the RTL8703B, the RTL8723BS reports receive descriptors with a zero packet length, which the vendor driver drops outright. rtw88 already flags these as having no PSDU for the RTL8703B, so extend the same handling rather than passing an empty frame up.
This is gated on the SDIO interface rather than the chip id, because it has only been observed there; the USB variant is not known to do it.
--- drivers/net/wireless/realtek/rtw88/rx.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/net/wireless/realtek/rtw88/rx.c +5 -3
@@ -253,10 +253,12 @@ static void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev,rtw_rx_addr_match (rtwdev, pkt_stat, hdr); -/* Rtl8723cs driver checks for size < 14 or size > 8192 and -* simply drops the packet. +/* Rtl8723cs and rtl8723bs drivers check for size < 14 or size > 8192 +* and simply drop the packet. */ -if (rtwdev->chip->id ==RTW_CHIP_TYPE_8703B && pkt_stat->pkt_len ==0 ) { +if ((rtwdev->chip->id ==RTW_CHIP_TYPE_8703B || +rtw_is_8723bs (rtwdev)) && + pkt_stat->pkt_len ==0 ) { rx_status->flag |=RX_FLAG_NO_PSDU ;rtw_dbg (rtwdev,RTW_DBG_RX ,"zero length packet" ); }
Signature · 1 line
2.55.0
Ping-Ke Shih
maintainerRE: [PATCH v2 02/11] wifi: rtw88: rx: mark zero length packets on RTL8723BS
Quoted 21 lines · [email protected] <[email protected]> wrote:
From: Luka Gejak <[email protected]>
Like the RTL8703B, the RTL8723BS reports receive descriptors with a zero packet length, which the vendor driver drops outright. rtw88 already flags these as having no PSDU for the RTL8703B, so extend the same handling rather than passing an empty frame up.
This is gated on the SDIO interface rather than the chip id, because it has only been observed there; the USB variant is not known to do it.
Signed-off-by Luka Gejak <[email protected]>--- drivers/net/wireless/realtek/rtw88/rx.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)drivers/net/wireless/realtek/rtw88/rx.c +0
-0@@ -253,10 +253,12 @@ static void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev,
drivers/net/wireless/realtek/rtw88/rx.c static void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev, · line 260
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/rx.c +4
-3rtw_rx_addr_match (rtwdev, pkt_stat, hdr); -/* Rtl8723cs driver checks for size < 14 or size > 8192 and -* simply drops the packet. +/* Rtl8723cs and rtl8723bs drivers check for size < 14 or size > 8192 +* and simply drop the packet. */ -if (rtwdev->chip->id ==RTW_CHIP_TYPE_8703B && pkt_stat->pkt_len ==0 ) { + if ((rtwdev->chip->id == RTW_CHIP_TYPE_8703B || + rtw_is_8723bs(rtwdev)) &&
Straighten it. Though it is over 80 characters, but still acceptable.
Quoted 6 lines
drivers/net/wireless/realtek/rtw88/rx.c +1
-1+ pkt_stat->pkt_len == 0) { rx_status->flag |=RX_FLAG_NO_PSDU ;rtw_dbg (rtwdev,RTW_DBG_RX ,"zero length packet" ); } --2.55.0
Re: [PATCH v2 02/11] wifi: rtw88: rx: mark zero length packets on RTL8723BS
From: Luka Gejak <[email protected]>
Quoted 4 lines · Ping-Ke Shih
drivers/net/wireless/realtek/rtw88/rx.c static void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev, · line 260
Quoted 2 lines
drivers/net/wireless/realtek/rtw88/rx.c +2
-0+ if ((rtwdev->chip->id == RTW_CHIP_TYPE_8703B || + rtw_is_8723bs(rtwdev)) &&Straighten it. Though it is over 80 characters, but still acceptable.
Done in v3:
if ((rtwdev->chip->id == RTW_CHIP_TYPE_8703B || rtw_is_8723bs(rtwdev)) &&
pkt_stat->pkt_len == 0) {Best regards,
Luka Gejak
PATCH v2 3/11 wifi: rtw88: fw: add the GNT_BT firmware command
In reply to [email protected]From: Luka Gejak <[email protected]>
The RTL8723BS coexistence sequence needs an H2C command that rtw88 does not implement: the firmware GNT_BT state, which hands the shared antenna to WiFi. Add it here so the coexistence change that follows has it available.
--- drivers/net/wireless/realtek/rtw88/fw.c | 11 +++++++++++ drivers/net/wireless/realtek/rtw88/fw.h | 4 ++++ 2 files changed, 15 insertions(+)
drivers/net/wireless/realtek/rtw88/fw.c +11 -0
@@ -786,6 +786,17 @@ void rtw_fw_media_status_report(struct rtw_dev *rtwdev, u8 mac_id, bool connect)rtw_fw_send_h2c_command (rtwdev, h2c_pkt); } +/* 8723BS SDIO: set the firmware GNT_BT state (0 = WiFi owns the antenna). */ +void rtw_fw_set_gnt_bt (struct rtw_dev *rtwdev,u8 state) +{ +u8 h2c_pkt[H2C_PKT_SIZE ] = {0 }; + +SET_H2C_CMD_ID_CLASS (h2c_pkt,H2C_CMD_GNT_BT ); +SET_GNT_BT_STATE (h2c_pkt, state); + +rtw_fw_send_h2c_command (rtwdev, h2c_pkt); +} +void rtw_fw_update_wl_phy_info (struct rtw_dev *rtwdev) {struct rtw_traffic_stats *stats = &rtwdev->stats;
drivers/net/wireless/realtek/rtw88/fw.h +4 -0
@@ -572,6 +572,7 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)#define H2C_CMD_QUERY_BT_MP_INFO 0x67#define H2C_CMD_BT_WIFI_CONTROL 0x69#define H2C_CMD_WIFI_CALIBRATION 0x6d +#define H2C_CMD_GNT_BT 0x6e#define H2C_CMD_QUERY_BT_HID_INFO 0x73#define H2C_CMD_KEEP_ALIVE 0x03
@@ -684,6 +685,8 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id) le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(31, 24))#define SET_QUERY_BT_INFO (h2c_pkt, value) \ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8)) +#define SET_GNT_BT_STATE (h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))#define SET_WL_CH_INFO_LINK (h2c_pkt, value) \ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))#define SET_WL_CH_INFO_CHNL (h2c_pkt, value) \
@@ -849,6 +852,7 @@ void rtw_fw_send_rssi_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si);void rtw_fw_send_ra_info (struct rtw_dev *rtwdev,struct rtw_sta_info *si,bool reset_ra_mask);void rtw_fw_media_status_report (struct rtw_dev *rtwdev,u8 mac_id,bool conn); +void rtw_fw_set_gnt_bt (struct rtw_dev *rtwdev,u8 state);void rtw_fw_update_wl_phy_info (struct rtw_dev *rtwdev);void rtw_fw_beacon_filter_config (struct rtw_dev *rtwdev,bool connect,struct ieee80211_vif *vif);
Signature · 1 line
2.55.0
PATCH v2 4/11 wifi: rtw88: fw: fix the reserved page upload on RTL8723BS
In reply to [email protected]From: Luka Gejak <[email protected]>
Two things stop the reserved page handshake from completing on this chip. BIT_EN_BCNQ_DL has to be cleared so the upload is not treated as a real beacon, which rtw88 only does for PCIe while the vendor driver does it unconditionally. The software beacon download path also has to be pointed at port 0. Without either, BIT_BCN_VALID is never asserted and the upload reports a timeout.
--- drivers/net/wireless/realtek/rtw88/fw.c | 27 ++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-)
drivers/net/wireless/realtek/rtw88/fw.c +24 -3
@@ -1477,10 +1477,14 @@ void rtw_add_rsvd_page_sta(struct rtw_dev *rtwdev,rtw_add_rsvd_page (rtwdev, rtwvif,RSVD_LPS_PG_INFO , true); } +/* REG_DWBCN1_CTRL bit 20 (SW_BCN_SEL for port 0), relative to byte +2 */ +#define BIT_OFFSET_DWBCN1_SW_BCN_SEL_PORT0 (20 - 16) +int rtw_fw_write_data_rsvd_page (struct rtw_dev *rtwdev,u16 pg_addr,u8 *buf,u32 size) { -u8 bckp[3 ]; +const bool is_8723bs_sdio =rtw_is_8723bs (rtwdev); +u8 bckp[4 ];u8 val;u16 rsvd_pg_head;u32 bcn_valid_addr;
@@ -1510,13 +1514,28 @@ int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr,rtw_write8 (rtwdev,REG_BCN_CTRL , (bckp[2 ] & ~BIT_EN_BCN_FUNCTION ) |BIT_DIS_TSF_UDT ); -if (rtw_hci_type (rtwdev) ==RTW_HCI_TYPE_PCIE ) { +/* Clear BIT_EN_BCNQ_DL so the chip does not treat the reserved-page +* upload as a real beacon; otherwise BIT_BCN_VALID never asserts. The +* vendor rtl8723bs driver does this unconditionally; rtw88 only did it +* for PCIe, which left 8723BS SDIO's BCN_VALID handshake failing. +*/ +if (rtw_hci_type (rtwdev) ==RTW_HCI_TYPE_PCIE || is_8723bs_sdio) { val =rtw_read8 (rtwdev,REG_FWHW_TXQ_CTRL +2 ); bckp[1 ] = val; val &= ~(BIT_EN_BCNQ_DL >>16 );rtw_write8 (rtwdev,REG_FWHW_TXQ_CTRL +2 , val); } +/* 8723BS SDIO: point the SW beacon download path at port 0, else +* BIT_BCN_VALID is never asserted after the SDIO upload completes. +*/ +if (is_8723bs_sdio) { + val =rtw_read8 (rtwdev,REG_DWBCN1_CTRL +2 ); + bckp[3 ] = val; + val &= ~BIT (BIT_OFFSET_DWBCN1_SW_BCN_SEL_PORT0 ); +rtw_write8 (rtwdev,REG_DWBCN1_CTRL +2 , val); + } + ret =rtw_hci_write_data_rsvd_page (rtwdev, buf, size);if (ret) {rtw_err (rtwdev,"failed to write data to rsvd page\n" );
@@ -1537,11 +1556,13 @@ int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr, } restore: +if (is_8723bs_sdio) +rtw_write8 (rtwdev,REG_DWBCN1_CTRL +2 , bckp[3 ]); rsvd_pg_head = rtwdev->fifo.rsvd_boundary;rtw_write16 (rtwdev,REG_FIFOPAGE_CTRL_2 , rsvd_pg_head |BIT_BCN_VALID_V1 );rtw_write8 (rtwdev,REG_BCN_CTRL , bckp[2 ]); -if (rtw_hci_type (rtwdev) ==RTW_HCI_TYPE_PCIE ) +if (rtw_hci_type (rtwdev) ==RTW_HCI_TYPE_PCIE || is_8723bs_sdio)rtw_write8 (rtwdev,REG_FWHW_TXQ_CTRL +2 , bckp[1 ]);rtw_write8 (rtwdev,REG_CR +1 , bckp[0 ]);
Signature · 1 line
2.55.0
Ping-Ke Shih
maintainerRE: [PATCH v2 04/11] wifi: rtw88: fw: fix the reserved page upload on RTL8723BS
[email protected] <[email protected]> wrote:
[...]
drivers/net/wireless/realtek/rtw88/fw.c void rtw_add_rsvd_page_sta(struct rtw_dev *rtwdev, · line 1481
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/fw.c +2
-0@@ -1477,10 +1477,14 @@ void rtw_add_rsvd_page_sta(struct rtw_dev *rtwdev,rtw_add_rsvd_page (rtwdev, rtwvif,RSVD_LPS_PG_INFO , true); } +/* REG_DWBCN1_CTRL bit 20 (SW_BCN_SEL for port 0), relative to byte +2 */ +#define BIT_OFFSET_DWBCN1_SW_BCN_SEL_PORT0 (20 - 16)
define along its register REG_DWBCN1_CTRL
Quoted 20 lines
drivers/net/wireless/realtek/rtw88/fw.c +8
-2+int rtw_fw_write_data_rsvd_page (struct rtw_dev *rtwdev,u16 pg_addr,u8 *buf,u32 size) { -u8 bckp[3 ]; +const bool is_8723bs_sdio =rtw_is_8723bs (rtwdev); +u8 bckp[4 ];u8 val;u16 rsvd_pg_head;u32 bcn_valid_addr;@@ -1510,13 +1514,28 @@ int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr,rtw_write8 (rtwdev,REG_BCN_CTRL , (bckp[2 ] & ~BIT_EN_BCN_FUNCTION ) |BIT_DIS_TSF_UDT ); -if (rtw_hci_type (rtwdev) ==RTW_HCI_TYPE_PCIE ) { +/* Clear BIT_EN_BCNQ_DL so the chip does not treat the reserved-page +* upload as a real beacon; otherwise BIT_BCN_VALID never asserts. The +* vendor rtl8723bs driver does this unconditionally; rtw88 only did it +* for PCIe, which left 8723BS SDIO's BCN_VALID handshake failing. +*/
drivers/net/wireless/realtek/rtw88/fw.c int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr, · line 1531
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/fw.c +4
-0+if (rtw_hci_type (rtwdev) ==RTW_HCI_TYPE_PCIE || is_8723bs_sdio) { val =rtw_read8 (rtwdev,REG_FWHW_TXQ_CTRL +2 ); bckp[1 ] = val; val &= ~(BIT_EN_BCNQ_DL >>16 );rtw_write8 (rtwdev,REG_FWHW_TXQ_CTRL +2 , val); } +/* 8723BS SDIO: point the SW beacon download path at port 0, else +* BIT_BCN_VALID is never asserted after the SDIO upload completes. +*/
Currently, not use networking specific comment style anymore
/*
* first line
* second
*/
drivers/net/wireless/realtek/rtw88/fw.c int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr, · line 1535
Quoted 4 lines
drivers/net/wireless/realtek/rtw88/fw.c +4
-0+if (is_8723bs_sdio) { + val =rtw_read8 (rtwdev,REG_DWBCN1_CTRL +2 ); + bckp[3 ] = val; + val &= ~BIT (BIT_OFFSET_DWBCN1_SW_BCN_SEL_PORT0 );
define along its register REG_DWBCN1_CTRL. Then, here
val &= ~(BIT_DWBCN1_SW_BCN_SEL_PORT0 >> 16);
Quoted 6 lines
drivers/net/wireless/realtek/rtw88/fw.c +3
-0+rtw_write8 (rtwdev,REG_DWBCN1_CTRL +2 , val); + } + ret =rtw_hci_write_data_rsvd_page (rtwdev, buf, size);if (ret) {rtw_err (rtwdev,"failed to write data to rsvd page\n" );
Re: [PATCH v2 04/11] wifi: rtw88: fw: fix the reserved page upload on RTL8723BS
From: Luka Gejak <[email protected]>
Quoted 4 lines · Ping-Ke Shih
drivers/net/wireless/realtek/rtw88/fw.c void rtw_add_rsvd_page_sta(struct rtw_dev *rtwdev, · line 1481
Quoted 2 lines
drivers/net/wireless/realtek/rtw88/fw.c +2
-0+/* REG_DWBCN1_CTRL bit 20 (SW_BCN_SEL for port 0), relative to byte +2 */ +#define BIT_OFFSET_DWBCN1_SW_BCN_SEL_PORT0 (20 - 16)define along its register
REG_DWBCN1_CTRL
Done. reg.h now has
#define REG_DWBCN1_CTRL 0x0228 #define BIT_DWBCN1_SW_BCN_SEL_PORT0 BIT(20)
and the write is
val &= ~(BIT_DWBCN1_SW_BCN_SEL_PORT0 >> 16);
as you suggested.
Quoted 6 lines
Currently, not use networking specific comment style anymore
/*
* first line
* second
*/
Right, I had missed 82b8000c28b5 ("net: drop special comment style"). Converted every block comment the series adds, in all patches.
Best regards,
Luka Gejak
PATCH v2 5/11 wifi: rtw88: coex: add the RTL8723BS scan antenna workaround
In reply to [email protected]From: Luka Gejak <[email protected]>
On the RTL8723BS the PTA antenna path has to be programmed directly during scan. The vendor driver keeps its own scan-time antenna state and does not run the generic coexistence algorithm on boards where BT is disabled, and following it is necessary here: without the antenna and CCK priority setup applied at scan start, the site survey does not hear the AP reliably.
Detect the BT-disabled case, replay the vendor BT_MP and BT_INFO queries once the firmware has been up long enough for RX DMA to be stable, then establish the scan path antenna configuration and skip the generic run.
--- drivers/net/wireless/realtek/rtw88/coex.c | 179 +++++++++++++++++++++- drivers/net/wireless/realtek/rtw88/coex.h | 2 + drivers/net/wireless/realtek/rtw88/reg.h | 1 + 3 files changed, 181 insertions(+), 1 deletion(-)
drivers/net/wireless/realtek/rtw88/coex.c +178 -1
@@ -1443,6 +1443,156 @@ static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)#define case_ALGO (src) \ case COEX_ALGO_##src: return #src +/* 8723BS SDIO WiFi/BT coexistence antenna handling. On BT-disabled boards the +* scan/auth window still routes through the PTA mux; these helpers force the +* vendor-shaped WiFi-owned antenna path so directed management TX reaches air. +*/ +#define REG_8723BS_BT_COEX_CTRL 0x0039 +#define REG_8723BS_BB_ANT_CFG 0x0930 +#define REG_8723BS_BB_ANT_CFG1 0x0944 +#define REG_8723BS_BB_ANT_BUF 0x0974 +#define RTW8723BS_COEX_H_WLAN_ACTIVE 0x1800101b + +static bool rtw_coex_8723bs_ant_is_aux (struct rtw_dev *rtwdev) +{ +return !!(rtwdev->efuse.bt_setting &BIT (6 )); +} + +static bool rtw_coex_8723bs_bt_disabled (struct rtw_dev *rtwdev) +{ +return rtw_is_8723bs (rtwdev) && rtwdev->coex.stat.bt_disabled; +} + +static u32 rtw_coex_8723bs_pta_ant_path (struct rtw_dev *rtwdev) +{ +return rtw_coex_8723bs_ant_is_aux (rtwdev) ?0x80 :0x200 ; +} + +/* Write BB_SEL_BTG, retrying once with SYS_FUNC BB reset if the first +* write does not stick (RF/BB clock may have been gated). +*/ +static u32 rtw_coex_8723bs_write_bb_sel_btg (struct rtw_dev *rtwdev,u32 value) +{ +u8 sys_func_before; +u32 readback; + + sys_func_before =rtw_read8 (rtwdev,REG_SYS_FUNC_EN ); +if ((sys_func_before & (BIT (0 ) |BIT (1 ))) != (BIT (0 ) |BIT (1 ))) { +rtw_write8_set (rtwdev,REG_SYS_FUNC_EN ,BIT (0 ) |BIT (1 )); +usleep_range (10 ,11 ); + } + +rtw_write32 (rtwdev,REG_BB_SEL_BTG_8723B , value); + readback =rtw_read32 (rtwdev,REG_BB_SEL_BTG_8723B ); +if (readback == value) +return readback; + +usleep_range (10 ,11 ); +rtw_write8_set (rtwdev,REG_SYS_FUNC_EN ,BIT (0 ) |BIT (1 )); +rtw_write32 (rtwdev,REG_BB_SEL_BTG_8723B , value); + +return rtw_read32 (rtwdev,REG_BB_SEL_BTG_8723B ); +} + +static u32 rtw_coex_8723bs_reassert_pta_ant (struct rtw_dev *rtwdev) +{ +return rtw_coex_8723bs_write_bb_sel_btg (rtwdev, +rtw_coex_8723bs_pta_ant_path (rtwdev)); +} + +static void rtw_coex_8723bs_set_cck_pri (struct rtw_dev *rtwdev,bool high) +{ +if (!rtw_coex_8723bs_bt_disabled (rtwdev)) +return ; + +if (high) { +rtw_write32 (rtwdev,REG_BT_COEX_TABLE_H , +RTW8723BS_COEX_H_WLAN_ACTIVE ); + }else { +rtw_coex_set_wl_pri_mask (rtwdev,COEX_WLPRI_TX_CCK , false); +rtw_coex_set_wl_pri_mask (rtwdev,COEX_WLPRI_RX_CCK , false); + } +} + +static void rtw_coex_8723bs_restore_pad_ctrl (struct rtw_dev *rtwdev, +bool keep_pta_owner) +{ +u32 before, after; + + before =rtw_read32 (rtwdev,REG_PAD_CTRL1 ); + after = before & ~(BIT_LNAON_WLBT_SEL |BIT_SW_DPDT_SEL_DATA ); +if (keep_pta_owner) + after |=BIT_PAPE_WLBT_SEL ; +else + after &= ~BIT_PAPE_WLBT_SEL ; +if (after != before) +rtw_write32 (rtwdev,REG_PAD_CTRL1 , after); +} + +static void rtw_coex_8723bs_fw_gnt_bt_low (struct rtw_dev *rtwdev) +{ +if (!rtw_coex_8723bs_bt_disabled (rtwdev)) +return ; + +if (rtw_read8 (rtwdev,REG_GNT_BT ) ==0x00 && +rtw_read8 (rtwdev,REG_BT_COEX_ENH_INTR_CTRL ) ==0x0c ) +return ; + +rtw_fw_set_gnt_bt (rtwdev,0 ); +} + +static void rtw_coex_8723bs_reassert_ant_buffer (struct rtw_dev *rtwdev) +{ +u8 sys_func_before; + + sys_func_before =rtw_read8 (rtwdev,REG_SYS_FUNC_EN ); +if ((sys_func_before & (BIT (0 ) |BIT (1 ))) != (BIT (0 ) |BIT (1 ))) { +rtw_write8_set (rtwdev,REG_SYS_FUNC_EN ,BIT (0 ) |BIT (1 )); +usleep_range (10 ,11 ); + } + +rtw_write8_mask (rtwdev,REG_8723BS_BT_COEX_CTRL ,BIT (3 ),0x1 ); +rtw_write8 (rtwdev,REG_8723BS_BB_ANT_BUF ,0xff ); +rtw_write8_mask (rtwdev,REG_8723BS_BB_ANT_CFG1 ,0x3 ,0x3 ); +rtw_write8 (rtwdev,REG_8723BS_BB_ANT_CFG ,0x77 ); +} + +static void rtw_coex_8723bs_apply_scan_table (struct rtw_dev *rtwdev) +{ + rtwdev->coex.dm.cur_table =2 ; +rtw_coex_set_table (rtwdev, true,0x5a5a5a5a ,0x5a5a5a5a ); +} + +/* Non-connected scan/auth workaround: PS-TDMA type 8 off, PTA antenna path, +* coex table type 2 (matches the vendor non-connected arbitration). +*/ +void rtw_coex_8723bs_scan_workaround (struct rtw_dev *rtwdev) +{ +struct rtw_coex_dm *coex_dm = &rtwdev->coex.dm; +struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; + +if (!rtw_is_8723bs (rtwdev)) +return ; + + coex_dm->cur_ps_tdma_on = false; + coex_dm->cur_ps_tdma =8 ; + coex_dm->ps_tdma_para[0 ] =0x08 ; + coex_dm->ps_tdma_para[1 ] =0x00 ; + coex_dm->ps_tdma_para[2 ] =0x00 ; + coex_dm->ps_tdma_para[3 ] =0x00 ; + coex_dm->ps_tdma_para[4 ] =0x00 ; + +rtw_fw_coex_tdma_type (rtwdev,0x08 ,0x00 ,0x00 ,0x00 ,0x00 ); +rtw_coex_8723bs_fw_gnt_bt_low (rtwdev); +rtw_coex_set_ant_path (rtwdev, true,COEX_SET_ANT_2G ); +rtw_coex_8723bs_reassert_ant_buffer (rtwdev); +rtw_coex_8723bs_apply_scan_table (rtwdev); +if (coex_stat->bt_disabled) +rtw_coex_8723bs_set_cck_pri (rtwdev, true); +rtw_coex_8723bs_reassert_pta_ant (rtwdev); +rtw_coex_8723bs_restore_pad_ctrl (rtwdev, true); +} +static const char *rtw_coex_get_algo_string (u8 algo) {switch (algo) {
@@ -2770,7 +2920,7 @@ void rtw_coex_power_on_setting(struct rtw_dev *rtwdev) coex->stop_dm = true; coex->wl_rf_off = false; -/* enable BB, we can write 0x948 */ +/* enable BB, so BB_SEL_BTG is writable */ rtw_write8_set (rtwdev,REG_SYS_FUNC_EN ,BIT_FEN_BB_GLB_RST |BIT_FEN_BB_RSTB );
@@ -2877,6 +3027,33 @@ void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type) coex->freeze = false;rtw_coex_write_scbd (rtwdev,COEX_SCBD_ACTIVE |COEX_SCBD_ONOFF , true); +/* 8723BS SDIO BT-disabled: keep the scan/auth PTA antenna state the +* vendor uses and skip the generic coex run. At scan start (firmware +* has been up long enough for stable RX DMA) replay the vendor BT_MP / +* BT_INFO queries, then re-establish the scan-path PTA setup. +*/ +if (rtw_coex_8723bs_bt_disabled (rtwdev)) { +if (type ==COEX_SCAN_START_2G || type ==COEX_SCAN_START ) { +struct rtw_coex_info_req req = {}; + + coex_stat->cnt_wl[COEX_CNT_WL_SCANAP ] =0 ; + coex_stat->wl_hi_pri_task2 = true; + + req.seq =0x0e ; + req.op_code =BT_MP_INFO_OP_SUPP_VER ; +rtw_fw_query_bt_mp_info (rtwdev, &req); + req.seq =0x0f ; + req.op_code =BT_MP_INFO_OP_PATCH_VER ; +rtw_fw_query_bt_mp_info (rtwdev, &req); +rtw_fw_query_bt_info (rtwdev); + +rtw_coex_8723bs_scan_workaround (rtwdev); + }else { + coex_stat->wl_hi_pri_task2 = false; + } +return ; + } +if (type ==COEX_SCAN_START_5G ) {rtw_dbg (rtwdev,RTW_DBG_COEX ,"[BTCoex], SCAN START notify (5G)\n" );
drivers/net/wireless/realtek/rtw88/coex.h +2 -0
@@ -430,4 +430,6 @@ static inline void rtw_coex_active_query_bt_info(struct rtw_dev *rtwdev) rtw_coex_query_bt_info(rtwdev); } +void rtw_coex_8723bs_scan_workaround (struct rtw_dev *rtwdev); +#endif
drivers/net/wireless/realtek/rtw88/reg.h +1 -0
@@ -628,6 +628,7 @@#define REG_PSD 0x0910#define BIT_PSD_INI GENMASK(23, 22)#define REG_SINGLE_TONE_CONT_TX 0x0914 +#define REG_BB_SEL_BTG_8723B 0x0948#define REG_AGC_TABLE 0x0958#define REG_RFE_CTRL_E 0x0974#define REG_2ND_CCA_CTRL 0x0976
Signature · 1 line
2.55.0
Ping-Ke Shih
maintainerRE: [PATCH v2 05/11] wifi: rtw88: coex: add the RTL8723BS scan antenna workaround
Quoted 25 lines · [email protected] <[email protected]> wrote:
From: Luka Gejak <[email protected]>
On the RTL8723BS the PTA antenna path has to be programmed directly during scan. The vendor driver keeps its own scan-time antenna state and does not run the generic coexistence algorithm on boards where BT is disabled, and following it is necessary here: without the antenna and CCK priority setup applied at scan start, the site survey does not hear the AP reliably.
Detect the BT-disabled case, replay the vendor
BT_MPandBT_INFOqueries once the firmware has been up long enough for RX DMA to be stable, then establish the scan path antenna configuration and skip the generic run.Signed-off-by Luka Gejak <[email protected]>--- drivers/net/wireless/realtek/rtw88/coex.c | 179 +++++++++++++++++++++- drivers/net/wireless/realtek/rtw88/coex.h | 2 + drivers/net/wireless/realtek/rtw88/reg.h | 1 + 3 files changed, 181 insertions(+), 1 deletion(-)drivers/net/wireless/realtek/rtw88/coex.c +0
-0
drivers/net/wireless/realtek/rtw88/coex.c static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase) · line 1449
Quoted 7 lines
drivers/net/wireless/realtek/rtw88/coex.c +4
-0@@ -1443,6 +1443,156 @@ static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)#define case_ALGO (src) \ case COEX_ALGO_##src: return #src +/* 8723BS SDIO WiFi/BT coexistence antenna handling. On BT-disabled boards the +* scan/auth window still routes through the PTA mux; these helpers force the +* vendor-shaped WiFi-owned antenna path so directed management TX reaches air. +*/
comment style.
drivers/net/wireless/realtek/rtw88/coex.c static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase) · line 1454
Quoted 5 lines
drivers/net/wireless/realtek/rtw88/coex.c +5
-0+#define REG_8723BS_BT_COEX_CTRL 0x0039 +#define REG_8723BS_BB_ANT_CFG 0x0930 +#define REG_8723BS_BB_ANT_CFG1 0x0944 +#define REG_8723BS_BB_ANT_BUF 0x0974 +#define RTW8723BS_COEX_H_WLAN_ACTIVE 0x1800101b
define these in reg.h
Quoted 9 lines
drivers/net/wireless/realtek/rtw88/coex.c +9
-0+ +static bool rtw_coex_8723bs_ant_is_aux (struct rtw_dev *rtwdev) +{ +return !!(rtwdev->efuse.bt_setting &BIT (6 )); +} + +static bool rtw_coex_8723bs_bt_disabled (struct rtw_dev *rtwdev) +{ +return rtw_is_8723bs (rtwdev) && rtwdev->coex.stat.bt_disabled;
drivers/net/wireless/realtek/rtw88/coex.c static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase) · line 1473
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/coex.c +10
-0+} + +static u32 rtw_coex_8723bs_pta_ant_path (struct rtw_dev *rtwdev) +{ +return rtw_coex_8723bs_ant_is_aux (rtwdev) ?0x80 :0x200 ; +} + +/* Write BB_SEL_BTG, retrying once with SYS_FUNC BB reset if the first +* write does not stick (RF/BB clock may have been gated). +*/
With the given name, this comment seems not necessary.
drivers/net/wireless/realtek/rtw88/coex.c static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase) · line 1481
Quoted 8 lines
drivers/net/wireless/realtek/rtw88/coex.c +8
-0+static u32 rtw_coex_8723bs_write_bb_sel_btg (struct rtw_dev *rtwdev,u32 value) +{ +u8 sys_func_before; +u32 readback; + + sys_func_before =rtw_read8 (rtwdev,REG_SYS_FUNC_EN ); +if ((sys_func_before & (BIT (0 ) |BIT (1 ))) != (BIT (0 ) |BIT (1 ))) { +rtw_write8_set (rtwdev,REG_SYS_FUNC_EN ,BIT (0 ) |BIT (1 ));
Use given names for BIT 0/1.
Quoted 9 lines
drivers/net/wireless/realtek/rtw88/coex.c +9
-0+usleep_range (10 ,11 ); + } + +rtw_write32 (rtwdev,REG_BB_SEL_BTG_8723B , value); + readback =rtw_read32 (rtwdev,REG_BB_SEL_BTG_8723B ); +if (readback == value) +return readback; + +usleep_range (10 ,11 );
drivers/net/wireless/realtek/rtw88/coex.c static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase) · line 1500
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/coex.c +10
-0+rtw_write8_set (rtwdev,REG_SYS_FUNC_EN ,BIT (0 ) |BIT (1 )); +rtw_write32 (rtwdev,REG_BB_SEL_BTG_8723B , value); + +return rtw_read32 (rtwdev,REG_BB_SEL_BTG_8723B ); +} + +static u32 rtw_coex_8723bs_reassert_pta_ant (struct rtw_dev *rtwdev) +{ +return rtw_coex_8723bs_write_bb_sel_btg (rtwdev, +rtw_coex_8723bs_pta_ant_path (rtwdev));
Just call rtw_coex_8723bs_write_bb_sel_btg() ?
Quoted 24 lines
drivers/net/wireless/realtek/rtw88/coex.c +24
-0+} + +static void rtw_coex_8723bs_set_cck_pri (struct rtw_dev *rtwdev,bool high) +{ +if (!rtw_coex_8723bs_bt_disabled (rtwdev)) +return ; + +if (high) { +rtw_write32 (rtwdev,REG_BT_COEX_TABLE_H , +RTW8723BS_COEX_H_WLAN_ACTIVE ); + }else { +rtw_coex_set_wl_pri_mask (rtwdev,COEX_WLPRI_TX_CCK , false); +rtw_coex_set_wl_pri_mask (rtwdev,COEX_WLPRI_RX_CCK , false); + } +} + +static void rtw_coex_8723bs_restore_pad_ctrl (struct rtw_dev *rtwdev, +bool keep_pta_owner) +{ +u32 before, after; + + before =rtw_read32 (rtwdev,REG_PAD_CTRL1 ); + after = before & ~(BIT_LNAON_WLBT_SEL |BIT_SW_DPDT_SEL_DATA ); +if (keep_pta_owner)
drivers/net/wireless/realtek/rtw88/coex.c static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase) · line 1534
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/coex.c +10
-0+ after |=BIT_PAPE_WLBT_SEL ; + else + after &= ~BIT_PAPE_WLBT_SEL; +if (after != before) +rtw_write32 (rtwdev,REG_PAD_CTRL1 , after); +} + +static void rtw_coex_8723bs_fw_gnt_bt_low (struct rtw_dev *rtwdev) +{ +if (!rtw_coex_8723bs_bt_disabled (rtwdev))
Please review your calling path. I think callers should ensure RTL8723BS before calling. (But here needs additional condition bt_disabled though)
Quoted 5 lines
drivers/net/wireless/realtek/rtw88/coex.c +5
-0+return ; + +if (rtw_read8 (rtwdev,REG_GNT_BT ) ==0x00 && +rtw_read8 (rtwdev,REG_BT_COEX_ENH_INTR_CTRL ) ==0x0c ) +return ;
drivers/net/wireless/realtek/rtw88/coex.c static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase) · line 1549
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/coex.c +10
-0+ +rtw_fw_set_gnt_bt (rtwdev,0 ); +} + +static void rtw_coex_8723bs_reassert_ant_buffer (struct rtw_dev *rtwdev) +{ +u8 sys_func_before; + + sys_func_before =rtw_read8 (rtwdev,REG_SYS_FUNC_EN ); +if ((sys_func_before & (BIT (0 ) |BIT (1 ))) != (BIT (0 ) |BIT (1 ))) {
Please use given names for BIT 0/1.
Quoted 15 lines
drivers/net/wireless/realtek/rtw88/coex.c +15
-0+rtw_write8_set (rtwdev,REG_SYS_FUNC_EN ,BIT (0 ) |BIT (1 )); +usleep_range (10 ,11 ); + } + +rtw_write8_mask (rtwdev,REG_8723BS_BT_COEX_CTRL ,BIT (3 ),0x1 ); +rtw_write8 (rtwdev,REG_8723BS_BB_ANT_BUF ,0xff ); +rtw_write8_mask (rtwdev,REG_8723BS_BB_ANT_CFG1 ,0x3 ,0x3 ); +rtw_write8 (rtwdev,REG_8723BS_BB_ANT_CFG ,0x77 ); +} + +static void rtw_coex_8723bs_apply_scan_table (struct rtw_dev *rtwdev) +{ + rtwdev->coex.dm.cur_table =2 ; +rtw_coex_set_table (rtwdev, true,0x5a5a5a5a ,0x5a5a5a5a ); +}
drivers/net/wireless/realtek/rtw88/coex.c static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase) · line 1574
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/coex.c +10
-0+ +/* Non-connected scan/auth workaround: PS-TDMA type 8 off, PTA antenna path, +* coex table type 2 (matches the vendor non-connected arbitration). +*/ +void rtw_coex_8723bs_scan_workaround (struct rtw_dev *rtwdev) +{ +struct rtw_coex_dm *coex_dm = &rtwdev->coex.dm; +struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; + +if (!rtw_is_8723bs (rtwdev))
Caller check this already.
Quoted 6 lines
drivers/net/wireless/realtek/rtw88/coex.c +6
-0+return ; + + coex_dm->cur_ps_tdma_on = false; + coex_dm->cur_ps_tdma =8 ; + coex_dm->ps_tdma_para[0 ] =0x08 ; + coex_dm->ps_tdma_para[1 ] =0x00 ;
drivers/net/wireless/realtek/rtw88/coex.c static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase) · line 1590
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/coex.c +10
-0+ coex_dm->ps_tdma_para[2 ] =0x00 ; + coex_dm->ps_tdma_para[3 ] =0x00 ; + coex_dm->ps_tdma_para[4 ] =0x00 ; + +rtw_fw_coex_tdma_type (rtwdev,0x08 ,0x00 ,0x00 ,0x00 ,0x00 ); +rtw_coex_8723bs_fw_gnt_bt_low (rtwdev); +rtw_coex_set_ant_path (rtwdev, true,COEX_SET_ANT_2G ); +rtw_coex_8723bs_reassert_ant_buffer (rtwdev); +rtw_coex_8723bs_apply_scan_table (rtwdev); +if (coex_stat->bt_disabled)
It looks like callers check this already.
drivers/net/wireless/realtek/rtw88/coex.c static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase) · line 1593
Quoted 3 lines
drivers/net/wireless/realtek/rtw88/coex.c +3
-0+rtw_coex_8723bs_set_cck_pri (rtwdev, true); +rtw_coex_8723bs_reassert_pta_ant (rtwdev); +rtw_coex_8723bs_restore_pad_ctrl (rtwdev, true);
I wonder how you can make this workaround? There are so many arguments.
Quoted 26 lines
drivers/net/wireless/realtek/rtw88/coex.c +11
-1+} +static const char *rtw_coex_get_algo_string (u8 algo) {switch (algo) {@@ -2770,7 +2920,7 @@ void rtw_coex_power_on_setting(struct rtw_dev *rtwdev) coex->stop_dm = true; coex->wl_rf_off = false; -/* enable BB, we can write 0x948 */ +/* enable BB, so BB_SEL_BTG is writable */ rtw_write8_set (rtwdev,REG_SYS_FUNC_EN ,BIT_FEN_BB_GLB_RST |BIT_FEN_BB_RSTB );@@ -2877,6 +3027,33 @@ void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type) coex->freeze = false;rtw_coex_write_scbd (rtwdev,COEX_SCBD_ACTIVE |COEX_SCBD_ONOFF , true); +/* 8723BS SDIO BT-disabled: keep the scan/auth PTA antenna state the +* vendor uses and skip the generic coex run. At scan start (firmware +* has been up long enough for stable RX DMA) replay the vendor BT_MP / +* BT_INFO queries, then re-establish the scan-path PTA setup. +*/ +if (rtw_coex_8723bs_bt_disabled (rtwdev)) { +if (type ==COEX_SCAN_START_2G || type ==COEX_SCAN_START ) { +struct rtw_coex_info_req req = {};
drivers/net/wireless/realtek/rtw88/coex.c void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type) · line 3047
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/coex.c +10
-0+ + coex_stat->cnt_wl[COEX_CNT_WL_SCANAP ] =0 ; + coex_stat->wl_hi_pri_task2 = true; + + req.seq =0x0e ; + req.op_code =BT_MP_INFO_OP_SUPP_VER ; +rtw_fw_query_bt_mp_info (rtwdev, &req); + req.seq =0x0f ; + req.op_code =BT_MP_INFO_OP_PATCH_VER ; +rtw_fw_query_bt_mp_info (rtwdev, &req);
These two are debug purpose. When you cat debugfs, it will try to query the version, won't it?
drivers/net/wireless/realtek/rtw88/coex.c void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type) · line 3048
Quoted 1 line
drivers/net/wireless/realtek/rtw88/coex.c +1
-0+rtw_fw_query_bt_info (rtwdev);
It seems to be called at initial. Is it necessary?
drivers/net/wireless/realtek/rtw88/coex.c void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type) · line 3054
Quoted 6 lines
drivers/net/wireless/realtek/rtw88/coex.c +6
-0+ +rtw_coex_8723bs_scan_workaround (rtwdev); + }else { + coex_stat->wl_hi_pri_task2 = false; + } +return ;
Since RTL8723BS does special handle, just move all into a function, but put in common flow.
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/coex.c +2
-0+ } +if (type ==COEX_SCAN_START_5G ) {rtw_dbg (rtwdev,RTW_DBG_COEX ,"[BTCoex], SCAN START notify (5G)\n" );drivers/net/wireless/realtek/rtw88/coex.h +0
-0
drivers/net/wireless/realtek/rtw88/coex.h static inline void rtw_coex_active_query_bt_info(struct rtw_dev *rtwdev) · line 434
Quoted 5 lines
drivers/net/wireless/realtek/rtw88/coex.h +2
-0@@ -430,4 +430,6 @@ static inline void rtw_coex_active_query_bt_info(struct rtw_dev *rtwdev)rtw_coex_query_bt_info (rtwdev); } +void rtw_coex_8723bs_scan_workaround (struct rtw_dev *rtwdev); +
Just static no need to export.
Quoted 1 line
drivers/net/wireless/realtek/rtw88/coex.h +0
-0#endif
Re: [PATCH v2 05/11] wifi: rtw88: coex: add the RTL8723BS scan antenna workaround
From: Luka Gejak <[email protected]>
Quoted 3 lines · Ping-Ke Shih
Quoted 1 line
+/* 8723BS SDIO WiFi/BT coexistence antenna handling. On BT-disabled boards the
comment style.
Fixed here and everywhere else in the series.
Quoted 7 lines
drivers/net/wireless/realtek/rtw88/coex.c static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase) · line 1454
Quoted 5 lines
drivers/net/wireless/realtek/rtw88/coex.c +5
-0+#define REG_8723BS_BT_COEX_CTRL 0x0039 +#define REG_8723BS_BB_ANT_CFG 0x0930 +#define REG_8723BS_BB_ANT_CFG1 0x0944 +#define REG_8723BS_BB_ANT_BUF 0x0974 +#define RTW8723BS_COEX_H_WLAN_ACTIVE 0x1800101bdefine these in
reg.h
Done for the registers. 0x0974 already existed as REG_RFE_CTRL_E, so I use that. The other three are now
#define REG_PWR_DATA 0x0038 #define BIT_EEPRPAD_RFE_CTRL_EN BIT(11) #define REG_RFE_CTRL_ANTA_SRC 0x0930 #define REG_RFE_CTRL_ANT_SW 0x0944 #define BIT_RFE_CTRL_ANT_SW_SEL GENMASK(1, 0)
0x0039 is the second byte of REG_PWR_DATA and the bit the vendor sets there is bit 11 of the register, which rtl8xxxu calls PWR_DATA_EEPRPAD_RFE_CTRL_EN, so I used the same name with rtw88's BIT_ prefix. 0x0930 is rfe_ctrl_anta_src in the vendor PHY register header. 0x0944 has no vendor name I could find, so I named it after what the write does; happy to take a better one if you have it.
0x1800101b I left in coex.c: it is a value written to REG_BT_COEX_TABLE_H, not a register, and coex.c already keeps its other table values inline. Say the word and I will move it.
Quoted 3 lines
Quoted 1 line
+/* Write
BB_SEL_BTG, retrying once withSYS_FUNCBB reset if the firstWith the given name, this comment seems not necessary.
Removed.
Quoted 4 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ if ((sys_func_before & (BIT(0) | BIT(1))) != (BIT(0) | BIT(1))) + rtw_write8_set(rtwdev, REG_SYS_FUNC_EN, BIT(0) | BIT(1));Use given names for BIT 0/1.
Now BIT_FEN_BB_GLB_RST | BIT_FEN_BB_RSTB. The same open-coded sequence appeared twice, so it is factored into rtw_coex_8723bs_enable_bb().
Quoted 3 lines
Quoted 1 line
+static u32
rtw_coex_8723bs_reassert_pta_ant(struct rtw_dev *rtwdev)Just call
rtw_coex_8723bs_write_bb_sel_btg()?
Dropped. rtw_coex_8723bs_write_bb_sel_btg() now takes no value and computes the PTA path itself, since that was the only value ever written.
Quoted 6 lines
drivers/net/wireless/realtek/rtw88/coex.c static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase) · line 1534
Quoted 3 lines
drivers/net/wireless/realtek/rtw88/coex.c +3
-0+static void rtw_coex_8723bs_fw_gnt_bt_low (struct rtw_dev *rtwdev) +{ +if (!rtw_coex_8723bs_bt_disabled (rtwdev))Please review your calling path. I think callers should ensure RTL8723BS before calling. (But here needs additional condition
bt_disabledthough)
[...]
Quoted 3 lines
Quoted 1 line
+ if (!rtw_is_8723bs(rtwdev))
Caller check this already.
[...]
Quoted 3 lines
Quoted 1 line
+ if (
coex_stat->bt_disabled)It looks like callers check this already.
All of these are gone. There are now exactly two entry points from the common flow, rtw_coex_8723bs_scan_notify() and rtw_coex_8723bs_connect_notify(), which test the chip and bt_disabled once and return true when they have handled the notification. Everything below them assumes both. rtw_coex_8723bs_bt_disabled() is gone with them.
While doing that I found rtw_coex_8723bs_set_cck_pri() was only ever called with high=true, so the argument and its dead else branch are removed too.
Quoted 1 line
I wonder how you can make this workaround? There are so many arguments.
It is halbtc8723b1ant_SetAntPath() for the wifi-only / BT-off case, plus the vendor's non-connected coex table and PS-TDMA type 8. Every register write in the function maps one to one onto a vendor write in that path; I did not invent any of the values. I then removed them one at a time on hardware to check each was actually load bearing, which is how the ones below went.
Quoted 11 lines
drivers/net/wireless/realtek/rtw88/coex.c void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type) · line 3047
Quoted 4 lines
drivers/net/wireless/realtek/rtw88/coex.c +4
-0+ req.op_code =BT_MP_INFO_OP_SUPP_VER ; +rtw_fw_query_bt_mp_info (rtwdev, &req); + req.op_code =BT_MP_INFO_OP_PATCH_VER ; +rtw_fw_query_bt_mp_info (rtwdev, &req);These two are debug purpose. When you cat debugfs, it will try to query the version, won't it?
Quoted 1 line
+
rtw_fw_query_bt_info(rtwdev);It seems to be called at initial. Is it necessary?
You are right on both counts, all three are removed.
Measured over 10 cold module reloads, three scans each, with and without them:
with: 24/24 scans saw the target AP, 8/8 associations
without: 29/30 scans saw the target AP, 10/10 associations
The single miss is one scan pass not catching a beacon, not a regression. The pre-auth rtw_fw_query_bt_info() in patch 06 went the same way, together with two of the three repeated PS-TDMA H2Cs there.
Quoted 2 lines
Since RTL8723BS does special handle, just move all into a function, but put in common flow.
Done, that is rtw_coex_8723bs_scan_notify() above.
Quoted 3 lines
Quoted 1 line
+void
rtw_coex_8723bs_scan_workaround(struct rtw_dev *rtwdev);Just static no need to export.
Static now, and the coex.h declaration is gone.
Best regards,
Luka Gejak
PATCH v2 6/11 wifi: rtw88: coex: reassert the antenna path when associating
In reply to [email protected]From: Luka Gejak <[email protected]>
The vendor ConnectNotify() returns early without sending H2C commands when BT is disabled, because the scan path has already established the antenna configuration, coexistence table and PS-TDMA. What it does keep is a register level reassertion of the PTA antenna at associate start, without which the antenna can be left pointing at BT across the authentication exchange.
Add that reassertion, and the pre-authentication H2C sequence that the join path added later needs.
--- drivers/net/wireless/realtek/rtw88/coex.c | 46 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/coex.h | 1 + 2 files changed, 47 insertions(+)
drivers/net/wireless/realtek/rtw88/coex.c +46 -0
@@ -1541,6 +1541,23 @@ static void rtw_coex_8723bs_fw_gnt_bt_low(struct rtw_dev *rtwdev)rtw_fw_set_gnt_bt (rtwdev,0 ); } +static void rtw_coex_8723bs_force_assoc_pta_ant (struct rtw_dev *rtwdev) +{ +u32 ant_target; + +if (!rtw_coex_8723bs_bt_disabled (rtwdev)) +return ; + + ant_target =rtw_coex_8723bs_pta_ant_path (rtwdev); + +rtw_coex_8723bs_fw_gnt_bt_low (rtwdev); +rtw_coex_set_ant_switch (rtwdev,COEX_SWITCH_CTRL_BY_PTA , +COEX_SWITCH_TO_NOCARE ); +rtw_coex_8723bs_set_cck_pri (rtwdev, true); +rtw_coex_8723bs_write_bb_sel_btg (rtwdev, ant_target); +rtw_coex_8723bs_restore_pad_ctrl (rtwdev, true); +} +static void rtw_coex_8723bs_reassert_ant_buffer (struct rtw_dev *rtwdev) {u8 sys_func_before;
@@ -1593,6 +1610,24 @@ void rtw_coex_8723bs_scan_workaround(struct rtw_dev *rtwdev)rtw_coex_8723bs_restore_pad_ctrl (rtwdev, true); } +/* Replayed immediately before start_clnt_join()/auth: BT_INFO + PS-TDMA type 8 +* then the forced WiFi PTA antenna path, so the auth window is clean. +*/ +void rtw_coex_8723bs_pre_auth_h2c (struct rtw_dev *rtwdev) +{ +lockdep_assert_held (&rtwdev->mutex); + +if (!rtw_coex_8723bs_bt_disabled (rtwdev)) +return ; + +rtw_fw_query_bt_info (rtwdev); +rtw_fw_coex_tdma_type (rtwdev,0x08 ,0x00 ,0x00 ,0x00 ,0x00 ); +rtw_fw_coex_tdma_type (rtwdev,0x08 ,0x00 ,0x00 ,0x00 ,0x00 ); +rtw_fw_coex_tdma_type (rtwdev,0x08 ,0x00 ,0x00 ,0x00 ,0x00 ); +rtw_coex_8723bs_fw_gnt_bt_low (rtwdev); +rtw_coex_8723bs_force_assoc_pta_ant (rtwdev); +} +static const char *rtw_coex_get_algo_string (u8 algo) {switch (algo) {
@@ -3115,6 +3150,17 @@ void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 type)if (coex->manual_control || coex->stop_dm)return ; +/* 8723BS SDIO BT-disabled: the vendor ConnectNotify() early-returns +* without sending H2Cs; scan_workaround already established the PTA +* path / coex table / PS-TDMA. Keep only the register-level PTA +* reassertion at associate-start. +*/ +if (rtw_coex_8723bs_bt_disabled (rtwdev)) { +if (type ==COEX_ASSOCIATE_START ) +rtw_coex_8723bs_force_assoc_pta_ant (rtwdev); +return ; + } +rtw_coex_write_scbd (rtwdev,COEX_SCBD_ACTIVE |COEX_SCBD_ONOFF , true);if (type ==COEX_ASSOCIATE_5G_START ) {
drivers/net/wireless/realtek/rtw88/coex.h +1 -0
@@ -431,5 +431,6 @@ static inline void rtw_coex_active_query_bt_info(struct rtw_dev *rtwdev) }void rtw_coex_8723bs_scan_workaround (struct rtw_dev *rtwdev); +void rtw_coex_8723bs_pre_auth_h2c (struct rtw_dev *rtwdev);#endif
Signature · 1 line
2.55.0
Ping-Ke Shih
maintainerRE: [PATCH v2 06/11] wifi: rtw88: coex: reassert the antenna path when associating
[email protected] <[email protected]> wrote:
[...]
Quoted 3 lines
+/* Replayed immediately before start_clnt_join()/auth:
BT_INFO+ PS-TDMA type 8
+ * then the forced WiFi PTA antenna path, so the auth window is clean.
+ */
Comment style.
Quoted 36 lines
drivers/net/wireless/realtek/rtw88/coex.c +26
-0+void rtw_coex_8723bs_pre_auth_h2c (struct rtw_dev *rtwdev) +{ +lockdep_assert_held (&rtwdev->mutex); + +if (!rtw_coex_8723bs_bt_disabled (rtwdev)) +return ; + +rtw_fw_query_bt_info (rtwdev); +rtw_fw_coex_tdma_type (rtwdev,0x08 ,0x00 ,0x00 ,0x00 ,0x00 ); +rtw_fw_coex_tdma_type (rtwdev,0x08 ,0x00 ,0x00 ,0x00 ,0x00 ); +rtw_fw_coex_tdma_type (rtwdev,0x08 ,0x00 ,0x00 ,0x00 ,0x00 ); +rtw_coex_8723bs_fw_gnt_bt_low (rtwdev); +rtw_coex_8723bs_force_assoc_pta_ant (rtwdev); +} +static const char *rtw_coex_get_algo_string (u8 algo) {switch (algo) {@@ -3115,6 +3150,17 @@ void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 type)if (coex->manual_control || coex->stop_dm)return ; +/* 8723BS SDIO BT-disabled: the vendor ConnectNotify() early-returns +* without sending H2Cs; scan_workaround already established the PTA +* path / coex table / PS-TDMA. Keep only the register-level PTA +* reassertion at associate-start. +*/ +if (rtw_coex_8723bs_bt_disabled (rtwdev)) { +if (type ==COEX_ASSOCIATE_START ) +rtw_coex_8723bs_force_assoc_pta_ant (rtwdev); +return ; + } +rtw_coex_write_scbd (rtwdev,COEX_SCBD_ACTIVE |COEX_SCBD_ONOFF , true);if (type ==COEX_ASSOCIATE_5G_START ) {
Re: [PATCH v2 06/11] wifi: rtw88: coex: reassert the antenna path when associating
From: Luka Gejak <[email protected]>
Quoted 5 lines · Ping-Ke Shih
Quoted 3 lines
+/* Replayed immediately before start_clnt_join()/auth:
BT_INFO+ PS-TDMA type 8
+ * then the forced WiFi PTA antenna path, so the auth window is clean.
+ */Comment style.
Fixed.
The chip test in rtw_coex_connect_notify() also moved into a single rtw_coex_8723bs_connect_notify() that the common flow calls once, to match what you asked for on patch 05.
Two other things went while I was in here. rtw_fw_query_bt_info() and two of the three repeated PS-TDMA H2Cs in the pre-auth replay are gone (see my reply on patch 05 for the measurement), and rtw_coex_8723bs_restore_pad_ctrl() had a keep_pta_owner argument that was true at every call site, so the argument and its dead branch are removed.
Best regards,
Luka Gejak
PATCH v2 7/11 wifi: rtw88: sdio: track free TX pages and OQT credits for RTL8723BS
In reply to [email protected]From: Luka Gejak <[email protected]>
The RTL8723BS reports free TX page counts that the generic 8051 path reads back from the chip on every transfer, which is both slow over SDIO and unreliable on this part: the register frequently reads back zero while pages are in fact available. It also gates transmission on an output queue token count that rtw88 does not track at all.
Mirror the vendor driver and keep the per-queue and public page counts in software, seeded at start and resynchronised from the chip only when the cached counts say there is not enough room. Wait for an OQT credit before writing, and account for the pages consumed after a successful transfer.
Transfers also have to be padded up to the SDIO block size for this chip rather than using the generic alignment, so size the write separately from the frame and trim the skb back afterwards.
--- drivers/net/wireless/realtek/rtw88/sdio.c | 220 ++++++++++++++++++++-- drivers/net/wireless/realtek/rtw88/sdio.h | 6 + 2 files changed, 215 insertions(+), 11 deletions(-)
drivers/net/wireless/realtek/rtw88/sdio.c +209 -11
@@ -20,6 +20,7 @@#include "tx.h" #define RTW_SDIO_INDIRECT_RW_RETRIES 50 +#define RTW_SDIO_OQT_TIMEOUT_MS 1000static bool rtw_sdio_is_bus_addr (u32 addr) {
@@ -548,12 +549,91 @@ static int rtw_sdio_read_port(struct rtw_dev *rtwdev, u8 *buf, size_t count)return ret; } +static void rtw_sdio_init_free_txpg (struct rtw_dev *rtwdev) +{ +struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; +const struct rtw_page_table *pg_tbl; +u32 free_txpg; +u16 pubq_num; + +if (!rtw_is_8723bs (rtwdev)) +return ; + + pg_tbl = &rtwdev->chip->page_table[0 ]; + pubq_num = rtwdev->fifo.acq_pg_num - pg_tbl->hq_num - pg_tbl->lq_num - + pg_tbl->nq_num - pg_tbl->exq_num - pg_tbl->gapq_num; + free_txpg =rtw_read32 (rtwdev,REG_SDIO_FREE_TXPG ); +if (free_txpg) { +atomic_set (&rtwsdio->free_pg_high, free_txpg &0xff ); +atomic_set (&rtwsdio->free_pg_normal, (free_txpg >>8 ) &0xff ); +atomic_set (&rtwsdio->free_pg_low, (free_txpg >>16 ) &0xff ); +atomic_set (&rtwsdio->free_pg_pub, (free_txpg >>24 ) &0xff ); + }else { +atomic_set (&rtwsdio->free_pg_high, pg_tbl->hq_num); +atomic_set (&rtwsdio->free_pg_normal, pg_tbl->nq_num); +atomic_set (&rtwsdio->free_pg_low, pg_tbl->lq_num); +atomic_set (&rtwsdio->free_pg_pub, pubq_num); + } + +atomic_set (&rtwsdio->tx_oqt_free, +rtw_read8 (rtwdev,REG_SDIO_OQT_FREE_PG )); +} + +static void rtw_sdio_sync_free_txpg (struct rtw_dev *rtwdev) +{ +struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; +u32 free_txpg =rtw_read32 (rtwdev,REG_SDIO_FREE_TXPG ); + +if (!free_txpg) +return ; + +atomic_set (&rtwsdio->free_pg_high, free_txpg &0xff ); +atomic_set (&rtwsdio->free_pg_normal, (free_txpg >>8 ) &0xff ); +atomic_set (&rtwsdio->free_pg_low, (free_txpg >>16 ) &0xff ); +atomic_set (&rtwsdio->free_pg_pub, (free_txpg >>24 ) &0xff ); +} + +static int rtw_sdio_8723bs_free_txpg (struct rtw_dev *rtwdev,u8 queue) +{ +struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; + +switch (queue) { +case RTW_TX_QUEUE_BCN : +case RTW_TX_QUEUE_H2C : +case RTW_TX_QUEUE_HI0 : +case RTW_TX_QUEUE_MGMT : +case RTW_TX_QUEUE_VO : +return atomic_read (&rtwsdio->free_pg_high); +case RTW_TX_QUEUE_VI : +return atomic_read (&rtwsdio->free_pg_normal); +case RTW_TX_QUEUE_BE : +case RTW_TX_QUEUE_BK : +return atomic_read (&rtwsdio->free_pg_low); +default : +return -EINVAL ; + } +} +static int rtw_sdio_check_free_txpg (struct rtw_dev *rtwdev,u8 queue,size_t count) {unsigned int pages_free, pages_needed; -if (rtw_chip_wcpu_8051 (rtwdev)) { +if (rtw_is_8723bs (rtwdev)) { +struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; +int dedicated =rtw_sdio_8723bs_free_txpg (rtwdev, queue); + +if (dedicated <0 ) +return dedicated; + pages_free = dedicated +atomic_read (&rtwsdio->free_pg_pub); + pages_needed =DIV_ROUND_UP (count, rtwdev->chip->page_size); +if (pages_needed <= pages_free) +return 0 ; + +rtw_sdio_sync_free_txpg (rtwdev); + dedicated =rtw_sdio_8723bs_free_txpg (rtwdev, queue); + pages_free = dedicated +atomic_read (&rtwsdio->free_pg_pub); + }else if (rtw_chip_wcpu_8051 (rtwdev)) {u32 free_txpg; free_txpg =rtw_sdio_read32 (rtwdev,REG_SDIO_FREE_TXPG );
@@ -632,44 +712,131 @@ static int rtw_sdio_check_free_txpg(struct rtw_dev *rtwdev, u8 queue,return 0 ; } +static int rtw_sdio_wait_tx_oqt (struct rtw_dev *rtwdev) +{ +struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; +int i; +u8 free; + +if (!rtw_is_8723bs (rtwdev)) +return 0 ; + +if (atomic_add_unless (&rtwsdio->tx_oqt_free,-1 ,0 )) +return 0 ; + +for (i =0 ; i <RTW_SDIO_OQT_TIMEOUT_MS ; i++) { + free =rtw_read8 (rtwdev,REG_SDIO_OQT_FREE_PG ); +if (free) { +atomic_set (&rtwsdio->tx_oqt_free, free -1 ); +return 0 ; + } +usleep_range (1000 ,2000 ); + } + +return -EBUSY ; +} + +static void rtw_sdio_8723bs_consume_txpg (struct rtw_dev *rtwdev,u8 queue, +unsigned int pages) +{ +struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; +atomic_t *dedicated; +int free; + +switch (queue) { +case RTW_TX_QUEUE_VI : + dedicated = &rtwsdio->free_pg_normal; +break ; +case RTW_TX_QUEUE_BE : +case RTW_TX_QUEUE_BK : + dedicated = &rtwsdio->free_pg_low; +break ; +default : + dedicated = &rtwsdio->free_pg_high; +break ; + } + + free =atomic_read (dedicated); +if (pages <= free) { +atomic_sub (pages, dedicated); + }else { +atomic_set (dedicated,0 ); +atomic_sub (pages - free, &rtwsdio->free_pg_pub); + } +} +static int rtw_sdio_write_port (struct rtw_dev *rtwdev,struct sk_buff *skb,enum rtw_tx_queue_type queue) {struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; +unsigned int orig_len = skb->len; +bool rtl8723bs =rtw_is_8723bs (rtwdev); +unsigned int pages;bool bus_claim;size_t txsize; +size_t write_size;u32 txaddr;int ret; - txaddr =rtw_sdio_get_tx_addr (rtwdev, skb->len, queue); -if (!txaddr) -return -EINVAL ; +if (rtl8723bs) { + txsize =round_up (orig_len,4 ); + write_size = txsize >RTW_SDIO_BLOCK_SIZE ? +round_up (txsize,RTW_SDIO_BLOCK_SIZE ) : txsize; + }else { + txsize =sdio_align_size (rtwsdio->sdio_func, orig_len); + write_size = txsize; + } + +if (write_size > orig_len) { +unsigned int padding = write_size - orig_len; + +if (skb_tailroom (skb) < padding) { + ret =pskb_expand_head (skb,0 , + padding -skb_tailroom (skb), +GFP_KERNEL ); +if (ret) +return ret; + } +skb_put_zero (skb, padding); + } - txsize =sdio_align_size (rtwsdio->sdio_func, skb->len); + txaddr =rtw_sdio_get_tx_addr (rtwdev, txsize, queue); +if (!txaddr) { + ret = -EINVAL ; + goto out_trim; + } ret =rtw_sdio_check_free_txpg (rtwdev, queue, txsize);if (ret) -return ret; + goto out_trim; + ret =rtw_sdio_wait_tx_oqt (rtwdev); +if (ret) + goto out_trim;if (!IS_ALIGNED ((unsigned long )skb->data,RTW_SDIO_DATA_PTR_ALIGN ))rtw_warn (rtwdev,"Got unaligned SKB in %s() for queue %u\n" , __func__, queue); bus_claim =rtw_sdio_bus_claim_needed (rtwsdio); -if (bus_claim)sdio_claim_host (rtwsdio->sdio_func); - - ret =sdio_memcpy_toio (rtwsdio->sdio_func, txaddr, skb->data, txsize); - + ret =sdio_memcpy_toio (rtwsdio->sdio_func, txaddr, skb->data, + write_size);if (bus_claim)sdio_release_host (rtwsdio->sdio_func); +if (!ret && rtl8723bs) { + pages =DIV_ROUND_UP (txsize, rtwdev->chip->page_size); +rtw_sdio_8723bs_consume_txpg (rtwdev, queue, pages); + }if (ret)rtw_warn (rtwdev,"Failed to write %zu byte(s) to SDIO port 0x%08x" , - txsize, txaddr); + write_size, txaddr); +out_trim: +if (write_size > orig_len) +skb_trim (skb, orig_len);return ret; }
@@ -749,8 +916,39 @@ static int rtw_sdio_setup(struct rtw_dev *rtwdev)return 0 ; } +static void rtw_sdio_8723bs_check_rqpn (struct rtw_dev *rtwdev) +{ +const struct rtw_chip_info *chip = rtwdev->chip; +struct rtw_fifo_conf *fifo = &rtwdev->fifo; +const struct rtw_page_table *pg_tbl; +u32 free_txpg; +u16 pubq_num; + +if (!rtw_is_8723bs (rtwdev)) +return ; + + free_txpg =rtw_read32 (rtwdev,REG_SDIO_FREE_TXPG ); +if (free_txpg || !fifo->acq_pg_num) +return ; + + pg_tbl = &chip->page_table[0 ]; +if (fifo->acq_pg_num <= pg_tbl->hq_num + pg_tbl->lq_num + + pg_tbl->nq_num + pg_tbl->exq_num + + pg_tbl->gapq_num) +return ; + + pubq_num = fifo->acq_pg_num - pg_tbl->hq_num - pg_tbl->lq_num - + pg_tbl->nq_num - pg_tbl->exq_num - pg_tbl->gapq_num; +rtw_write32 (rtwdev,REG_RQPN_NPQ , +BIT_RQPN_NE (pg_tbl->nq_num, pg_tbl->exq_num)); +rtw_write32 (rtwdev,REG_RQPN , +BIT_RQPN_HLP (pg_tbl->hq_num, pg_tbl->lq_num, pubq_num)); +} +static int rtw_sdio_start (struct rtw_dev *rtwdev) { +rtw_sdio_8723bs_check_rqpn (rtwdev); +rtw_sdio_init_free_txpg (rtwdev);rtw_sdio_enable_rx_aggregation (rtwdev);rtw_sdio_enable_interrupt (rtwdev);
drivers/net/wireless/realtek/rtw88/sdio.h +6 -0
@@ -159,6 +159,12 @@ struct rtw_sdio {struct workqueue_struct *txwq;struct rtw_sdio_work_data *tx_handler_data;struct sk_buff_head tx_queue[RTK_MAX_TX_QUEUE_NUM ]; + +atomic_t free_pg_high; +atomic_t free_pg_normal; +atomic_t free_pg_low; +atomic_t free_pg_pub; +atomic_t tx_oqt_free; };extern const struct dev_pm_ops rtw_sdio_pm_ops;
Signature · 1 line
2.55.0
Ping-Ke Shih
maintainerRE: [PATCH v2 07/11] wifi: rtw88: sdio: track free TX pages and OQT credits for RTL8723BS
Quoted 11 lines · [email protected] <[email protected]> wrote:
From: Luka Gejak <[email protected]>
The RTL8723BS reports free TX page counts that the generic 8051 path reads back from the chip on every transfer, which is both slow over SDIO and unreliable on this part: the register frequently reads back zero while pages are in fact available. It also gates transmission on an output queue token count that rtw88 does not track at all.
Mirror the vendor driver and keep the per-queue and public page counts in software, seeded at start and resynchronised from the chip only when the cached counts say there is not enough room. Wait for an OQT credit
Does OQT mean Output Queue Token? Could you explain a little bit?
Quoted 6 lines
before writing, and account for the pages consumed after a successful transfer.
Transfers also have to be padded up to the SDIO block size for this chip rather than using the generic alignment, so size the write separately from the frame and trim the skb back afterwards.
I think this can largely improve SDIO. Please share the performance numbers before/after this patch.
Quoted 20 lines
Signed-off-by Luka Gejak <[email protected]>--- drivers/net/wireless/realtek/rtw88/sdio.c | 220 ++++++++++++++++++++-- drivers/net/wireless/realtek/rtw88/sdio.h | 6 + 2 files changed, 215 insertions(+), 11 deletions(-)drivers/net/wireless/realtek/rtw88/sdio.c +1
-0@@ -20,6 +20,7 @@#include "tx.h" #define RTW_SDIO_INDIRECT_RW_RETRIES 50 +#define RTW_SDIO_OQT_TIMEOUT_MS 1000static bool rtw_sdio_is_bus_addr (u32 addr) {
drivers/net/wireless/realtek/rtw88/sdio.c static int rtw_sdio_read_port(struct rtw_dev *rtwdev, u8 *buf, size_t count) · line 552
Quoted 4 lines
drivers/net/wireless/realtek/rtw88/sdio.c +1
-0@@ -548,12 +549,91 @@ static int rtw_sdio_read_port(struct rtw_dev *rtwdev, u8 *buf, size_t count)return ret; } +static void rtw_sdio_init_free_txpg (struct rtw_dev *rtwdev)
_8723bs_ specific so add to the function name
Quoted 20 lines
drivers/net/wireless/realtek/rtw88/sdio.c +20
-0+{ +struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; +const struct rtw_page_table *pg_tbl; +u32 free_txpg; +u16 pubq_num; + +if (!rtw_is_8723bs (rtwdev)) +return ; + + pg_tbl = &rtwdev->chip->page_table[0 ]; + pubq_num = rtwdev->fifo.acq_pg_num - pg_tbl->hq_num - pg_tbl->lq_num - + pg_tbl->nq_num - pg_tbl->exq_num - pg_tbl->gapq_num; + free_txpg =rtw_read32 (rtwdev,REG_SDIO_FREE_TXPG ); +if (free_txpg) { +atomic_set (&rtwsdio->free_pg_high, free_txpg &0xff ); +atomic_set (&rtwsdio->free_pg_normal, (free_txpg >>8 ) &0xff ); +atomic_set (&rtwsdio->free_pg_low, (free_txpg >>16 ) &0xff ); +atomic_set (&rtwsdio->free_pg_pub, (free_txpg >>24 ) &0xff ); + }else { +atomic_set (&rtwsdio->free_pg_high, pg_tbl->hq_num);
drivers/net/wireless/realtek/rtw88/sdio.c static int rtw_sdio_read_port(struct rtw_dev *rtwdev, u8 *buf, size_t count) · line 582
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/sdio.c +10
-0+atomic_set (&rtwsdio->free_pg_normal, pg_tbl->nq_num); +atomic_set (&rtwsdio->free_pg_low, pg_tbl->lq_num); +atomic_set (&rtwsdio->free_pg_pub, pubq_num); + } + +atomic_set (&rtwsdio->tx_oqt_free, +rtw_read8 (rtwdev,REG_SDIO_OQT_FREE_PG )); +} + +static void rtw_sdio_sync_free_txpg (struct rtw_dev *rtwdev)
_8723bs_ specific so add to the function name
drivers/net/wireless/realtek/rtw88/sdio.c static int rtw_sdio_read_port(struct rtw_dev *rtwdev, u8 *buf, size_t count) · line 593
Quoted 11 lines
drivers/net/wireless/realtek/rtw88/sdio.c +11
-0+{ +struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; +u32 free_txpg =rtw_read32 (rtwdev,REG_SDIO_FREE_TXPG ); + +if (!free_txpg) +return ; + +atomic_set (&rtwsdio->free_pg_high, free_txpg &0xff ); +atomic_set (&rtwsdio->free_pg_normal, (free_txpg >>8 ) &0xff ); +atomic_set (&rtwsdio->free_pg_low, (free_txpg >>16 ) &0xff ); +atomic_set (&rtwsdio->free_pg_pub, (free_txpg >>24 ) &0xff );
It is clear that bit masks of REG_SDIO_FREE_TXPG are PG_{HIGH, NORMAL, LOW, PUB}. Let's define them in reg.h, and use u32_get_bits() to read out the values.
Quoted 32 lines
drivers/net/wireless/realtek/rtw88/sdio.c +26
-1+} + +static int rtw_sdio_8723bs_free_txpg (struct rtw_dev *rtwdev,u8 queue) +{ +struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; + +switch (queue) { +case RTW_TX_QUEUE_BCN : +case RTW_TX_QUEUE_H2C : +case RTW_TX_QUEUE_HI0 : +case RTW_TX_QUEUE_MGMT : +case RTW_TX_QUEUE_VO : +return atomic_read (&rtwsdio->free_pg_high); +case RTW_TX_QUEUE_VI : +return atomic_read (&rtwsdio->free_pg_normal); +case RTW_TX_QUEUE_BE : +case RTW_TX_QUEUE_BK : +return atomic_read (&rtwsdio->free_pg_low); +default : +return -EINVAL ; + } +} +static int rtw_sdio_check_free_txpg (struct rtw_dev *rtwdev,u8 queue,size_t count) {unsigned int pages_free, pages_needed; -if (rtw_chip_wcpu_8051 (rtwdev)) { +if (rtw_is_8723bs (rtwdev)) { +struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; +int dedicated =rtw_sdio_8723bs_free_txpg (rtwdev, queue);
drivers/net/wireless/realtek/rtw88/sdio.c static int rtw_sdio_read_port(struct rtw_dev *rtwdev, u8 *buf, size_t count) · line 634
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/sdio.c +10
-0+ +if (dedicated <0 ) +return dedicated; + pages_free = dedicated +atomic_read (&rtwsdio->free_pg_pub); + pages_needed =DIV_ROUND_UP (count, rtwdev->chip->page_size); +if (pages_needed <= pages_free) +return 0 ; + +rtw_sdio_sync_free_txpg (rtwdev); + dedicated =rtw_sdio_8723bs_free_txpg (rtwdev, queue);
Why do you check dedicated < 0 for this case?
Quoted 58 lines
drivers/net/wireless/realtek/rtw88/sdio.c +51
-0+ pages_free = dedicated +atomic_read (&rtwsdio->free_pg_pub); + }else if (rtw_chip_wcpu_8051 (rtwdev)) {u32 free_txpg; free_txpg =rtw_sdio_read32 (rtwdev,REG_SDIO_FREE_TXPG );@@ -632,44 +712,131 @@ static int rtw_sdio_check_free_txpg(struct rtw_dev *rtwdev, u8 queue,return 0 ; } +static int rtw_sdio_wait_tx_oqt (struct rtw_dev *rtwdev) +{ +struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; +int i; +u8 free; + +if (!rtw_is_8723bs (rtwdev)) +return 0 ; + +if (atomic_add_unless (&rtwsdio->tx_oqt_free,-1 ,0 )) +return 0 ; + +for (i =0 ; i <RTW_SDIO_OQT_TIMEOUT_MS ; i++) { + free =rtw_read8 (rtwdev,REG_SDIO_OQT_FREE_PG ); +if (free) { +atomic_set (&rtwsdio->tx_oqt_free, free -1 ); +return 0 ; + } +usleep_range (1000 ,2000 ); + } + +return -EBUSY ; +} + +static void rtw_sdio_8723bs_consume_txpg (struct rtw_dev *rtwdev,u8 queue, +unsigned int pages) +{ +struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; +atomic_t *dedicated; +int free; + +switch (queue) { +case RTW_TX_QUEUE_VI : + dedicated = &rtwsdio->free_pg_normal; +break ; +case RTW_TX_QUEUE_BE : +case RTW_TX_QUEUE_BK : + dedicated = &rtwsdio->free_pg_low; +break ; +default : + dedicated = &rtwsdio->free_pg_high; +break ; + } + + free =atomic_read (dedicated); +if (pages <= free) { +atomic_sub (pages, dedicated); + }else { +atomic_set (dedicated,0 );
drivers/net/wireless/realtek/rtw88/sdio.c static int rtw_sdio_check_free_txpg(struct rtw_dev *rtwdev, u8 queue, · line 773
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/sdio.c +6
-0+atomic_sub (pages - free, &rtwsdio->free_pg_pub); + } +} +static int rtw_sdio_write_port (struct rtw_dev *rtwdev,struct sk_buff *skb,enum rtw_tx_queue_type queue) {struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; +unsigned int orig_len = skb->len; +bool rtl8723bs =rtw_is_8723bs (rtwdev);
reverse X'mas tree
Quoted 57 lines
drivers/net/wireless/realtek/rtw88/sdio.c +32
-8+unsigned int pages;bool bus_claim;size_t txsize; +size_t write_size;u32 txaddr;int ret; - txaddr =rtw_sdio_get_tx_addr (rtwdev, skb->len, queue); -if (!txaddr) -return -EINVAL ; +if (rtl8723bs) { + txsize =round_up (orig_len,4 ); + write_size = txsize >RTW_SDIO_BLOCK_SIZE ? +round_up (txsize,RTW_SDIO_BLOCK_SIZE ) : txsize; + }else { + txsize =sdio_align_size (rtwsdio->sdio_func, orig_len); + write_size = txsize; + } + +if (write_size > orig_len) { +unsigned int padding = write_size - orig_len; + +if (skb_tailroom (skb) < padding) { + ret =pskb_expand_head (skb,0 , + padding -skb_tailroom (skb), +GFP_KERNEL ); +if (ret) +return ret; + } +skb_put_zero (skb, padding); + } - txsize =sdio_align_size (rtwsdio->sdio_func, skb->len); + txaddr =rtw_sdio_get_tx_addr (rtwdev, txsize, queue); +if (!txaddr) { + ret = -EINVAL ; + goto out_trim; + } ret =rtw_sdio_check_free_txpg (rtwdev, queue, txsize);if (ret) -return ret; + goto out_trim; + ret =rtw_sdio_wait_tx_oqt (rtwdev); +if (ret) + goto out_trim;if (!IS_ALIGNED ((unsigned long )skb->data,RTW_SDIO_DATA_PTR_ALIGN ))rtw_warn (rtwdev,"Got unaligned SKB in %s() for queue %u\n" , __func__, queue); bus_claim =rtw_sdio_bus_claim_needed (rtwsdio); -if (bus_claim)sdio_claim_host (rtwsdio->sdio_func); - - ret =sdio_memcpy_toio (rtwsdio->sdio_func, txaddr, skb->data, txsize);
drivers/net/wireless/realtek/rtw88/sdio.c static int rtw_sdio_check_free_txpg(struct rtw_dev *rtwdev, u8 queue, · line 831
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/sdio.c +6
-1- + ret =sdio_memcpy_toio (rtwsdio->sdio_func, txaddr, skb->data, + write_size);if (bus_claim)sdio_release_host (rtwsdio->sdio_func); +if (!ret && rtl8723bs) { + pages =DIV_ROUND_UP (txsize, rtwdev->chip->page_size); +rtw_sdio_8723bs_consume_txpg (rtwdev, queue, pages); + }
move to else-branch below?
drivers/net/wireless/realtek/rtw88/sdio.c static int rtw_sdio_check_free_txpg(struct rtw_dev *rtwdev, u8 queue, · line 835
Quoted 5 lines
drivers/net/wireless/realtek/rtw88/sdio.c +1
-1if (ret)rtw_warn (rtwdev,"Failed to write %zu byte(s) to SDIO port 0x%08x" , - txsize, txaddr); + write_size, txaddr);
else (rtl8723bs) {
...
}Quoted 20 lines
drivers/net/wireless/realtek/rtw88/sdio.c +12
-0+out_trim: +if (write_size > orig_len) +skb_trim (skb, orig_len);return ret; }@@ -749,8 +916,39 @@ static int rtw_sdio_setup(struct rtw_dev *rtwdev)return 0 ; } +static void rtw_sdio_8723bs_check_rqpn (struct rtw_dev *rtwdev) +{ +const struct rtw_chip_info *chip = rtwdev->chip; +struct rtw_fifo_conf *fifo = &rtwdev->fifo; +const struct rtw_page_table *pg_tbl; +u32 free_txpg; +u16 pubq_num; + +if (!rtw_is_8723bs (rtwdev))
drivers/net/wireless/realtek/rtw88/sdio.c static int rtw_sdio_setup(struct rtw_dev *rtwdev) · line 937
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/sdio.c +10
-0+return ; + + free_txpg =rtw_read32 (rtwdev,REG_SDIO_FREE_TXPG ); +if (free_txpg || !fifo->acq_pg_num) +return ; + + pg_tbl = &chip->page_table[0 ]; +if (fifo->acq_pg_num <= pg_tbl->hq_num + pg_tbl->lq_num + + pg_tbl->nq_num + pg_tbl->exq_num + + pg_tbl->gapq_num)
second and third lines don't align.
drivers/net/wireless/realtek/rtw88/sdio.c static int rtw_sdio_setup(struct rtw_dev *rtwdev) · line 950
Quoted 13 lines
drivers/net/wireless/realtek/rtw88/sdio.c +11
-0+return ; + + pubq_num = fifo->acq_pg_num - pg_tbl->hq_num - pg_tbl->lq_num - + pg_tbl->nq_num - pg_tbl->exq_num - pg_tbl->gapq_num; +rtw_write32 (rtwdev,REG_RQPN_NPQ , +BIT_RQPN_NE (pg_tbl->nq_num, pg_tbl->exq_num)); +rtw_write32 (rtwdev,REG_RQPN , +BIT_RQPN_HLP (pg_tbl->hq_num, pg_tbl->lq_num, pubq_num)); +} +static int rtw_sdio_start (struct rtw_dev *rtwdev) { +rtw_sdio_8723bs_check_rqpn (rtwdev);
Should we check chip is RTL8723BS before calling? I'd have consistent the calling rule -- callers check?
drivers/net/wireless/realtek/rtw88/sdio.c static int rtw_sdio_setup(struct rtw_dev *rtwdev) · line 951
Quoted 1 line
drivers/net/wireless/realtek/rtw88/sdio.c +1
-0+rtw_sdio_init_free_txpg (rtwdev);
This is also RTL8723BS specific. Why not having a '_8723bs_' ?
Quoted 8 lines
drivers/net/wireless/realtek/rtw88/sdio.c +0
-0rtw_sdio_enable_rx_aggregation (rtwdev);rtw_sdio_enable_interrupt (rtwdev);drivers/net/wireless/realtek/rtw88/sdio.h +0
-0
drivers/net/wireless/realtek/rtw88/sdio.h struct rtw_sdio { · line 167
Quoted 9 lines
drivers/net/wireless/realtek/rtw88/sdio.h +6
-0@@ -159,6 +159,12 @@ struct rtw_sdio {struct workqueue_struct *txwq;struct rtw_sdio_work_data *tx_handler_data;struct sk_buff_head tx_queue[RTK_MAX_TX_QUEUE_NUM ]; + +atomic_t free_pg_high; +atomic_t free_pg_normal; +atomic_t free_pg_low; +atomic_t free_pg_pub; +atomic_t tx_oqt_free;
Could I know the reason why these should be atomic_t? Which context are they running?
Quoted 5 lines
drivers/net/wireless/realtek/rtw88/sdio.h +0
-1};extern const struct dev_pm_ops rtw_sdio_pm_ops; --2.55.0
Re: [PATCH v2 07/11] wifi: rtw88: sdio: track free TX pages and OQT credits for RTL8723BS
From: Luka Gejak <[email protected]>
Quoted 3 lines · Ping-Ke Shih
Quoted 1 line
output queue token count that rtw88 does not track at all.
Does OQT mean Output Queue Token? Could you explain a little bit?
Yes. REG_SDIO_OQT_FREE_PG is how many more descriptors the chip's SDIO output queue can still accept. On this part the chip discards a write that arrives when the count is zero, silently, so the frame is lost rather than retried. The vendor driver polls the register before every port write; this patch caches the count and only re-reads when the cached value is exhausted. I have rewritten that paragraph of the commit message to spell it out and dropped the "OQT" abbreviation from the prose.
Quoted 2 lines
I think this can largely improve SDIO. Please share the performance numbers before/after this patch.
Added to the commit message. Measured against an iperf3 server one hop behind the AP, using the wlan0 byte counters as ground truth because eth0 on the test box shares the same subnet:
without this patch: TCP and UDP both 0 bit/s in either direction
with this patch: TCP 25.3 Mbit/s up, 37.3 Mbit/s down
UDP 25.0 Mbit/s up at 0% loss
To be clear about the "before" number: on the generic path the association itself still completes, but no data gets through at all, so this is not a tuning patch. The transfer sizing in the third hunk is the part that matters most there; without the block size padding the chip stops accepting writes entirely.
Quoted 4 lines
drivers/net/wireless/realtek/rtw88/sdio.c static int rtw_sdio_read_port(struct rtw_dev *rtwdev, u8 *buf, size_t count) · line 582
Quoted 2 lines
drivers/net/wireless/realtek/rtw88/sdio.c +2
-0+static void rtw_sdio_init_free_txpg(struct rtw_dev *rtwdev) +static void rtw_sdio_sync_free_txpg(struct rtw_dev *rtwdev)_8723bs_ specific so add to the function name
Renamed, along with rtw_sdio_wait_tx_oqt() -> rtw_sdio_8723bs_wait_tx_oqt(). The shared field decoding is now rtw_sdio_8723bs_store_free_txpg().
Quoted 3 lines
It is clear that bit masks of
REG_SDIO_FREE_TXPGare PG_{HIGH, NORMAL, LOW, PUB}. Let's define them inreg.h, and useu32_get_bits()to read out the values.
Done, in sdio.h next to REG_SDIO_FREE_TXPG since that is where the register lives:
#define BIT_FREE_TXPG_HIGH GENMASK(7, 0) #define BIT_FREE_TXPG_NORMAL GENMASK(15, 8) #define BIT_FREE_TXPG_LOW GENMASK(23, 16) #define BIT_FREE_TXPG_PUB GENMASK(31, 24)
and read with u32_get_bits(). That also removed the duplicated decode, which is what let me answer your next question properly.
Quoted 3 lines
Quoted 1 line
+ dedicated =
rtw_sdio_8723bs_free_txpg(rtwdev, queue);Why do you check
dedicated < 0for this case?
There was no good reason; the queue does not change between the two calls so the second result could not have been an error. Rather than add a second check, rtw_sdio_8723bs_free_txpg() now returns the atomic_t * for the queue, so the mapping is resolved once, NULL is checked once with a warning, and the resync path just re-reads the same counter.
Quoted 3 lines
Quoted 1 line
+ bool rtl8723bs =
rtw_is_8723bs(rtwdev);reverse X'mas tree
Fixed.
Quoted 3 lines
Quoted 1 line
+ if (!ret && rtl8723bs) {
move to else-branch below?
Done, it is now if (ret) { warn } else if (rtl8723bs) { account }.
Quoted 3 lines
Quoted 1 line
+ if (
fifo->acq_pg_num<=pg_tbl->hq_num+pg_tbl->lq_num+second and third lines don't align.
The sum was computed twice with different formatting, so it is now a reserved_num local used in both places.
Quoted 4 lines
Quoted 1 line
+
rtw_sdio_8723bs_check_rqpn(rtwdev);Should we check chip is RTL8723BS before calling? I'd have consistent the calling rule -- callers check?
Agreed, and applied across the series. rtw_sdio_start() now has the test and both helpers assume it.
Quoted 4 lines
Quoted 1 line
+
atomic_tfree_pg_high;Could I know the reason why these should be
atomic_t? Which context are they running?
Two contexts. The usual one is the TX work, which is single threaded (create_singlethread_workqueue), so on its own it would not need them. But rtw_sdio_write_port() is also reached from rtw_sdio_write_data() for H2C commands and reserved page uploads, which runs in process context under rtwdev->mutex and does not go through the TX workqueue. Those two share no lock.
The counters are a fast path hint rather than an authority: whenever they claim there is not enough room, rtw_sdio_8723bs_sync_free_txpg() re-reads REG_SDIO_FREE_TXPG before the caller gives up, so a lost update costs one extra register read and nothing else. I have put that reasoning in a comment above the helpers. If you would rather have a spinlock around the group I can do that instead, it is not a hot path in the sense that would make the lock cost anything.
Best regards,
Luka Gejak
PATCH v2 8/11 wifi: rtw88: sdio: set up RX aggregation and interrupts for RTL8723BS
In reply to [email protected]From: Luka Gejak <[email protected]>
Enable the existing RX aggregation setup for this chip and select the larger DMA aggregation mode it needs. The RTL8723BS does not raise CPWM1, so leave that source out of its interrupt mask, and set the SDIO TX control bit the vendor driver uses to have transfers always recognised.
The chip also keeps raising the interrupt after resume if undefined status bits are written back when acknowledging, so acknowledge only the defined and unmasked bits. That is scoped to this chip; the other SDIO parts keep writing the status word back unchanged.
--- drivers/net/wireless/realtek/rtw88/sdio.c | 28 ++++++++++++++++++++++- drivers/net/wireless/realtek/rtw88/sdio.h | 9 ++++++++ 2 files changed, 36 insertions(+), 1 deletion(-)
drivers/net/wireless/realtek/rtw88/sdio.c +27 -1
@@ -844,7 +844,11 @@ static void rtw_sdio_init(struct rtw_dev *rtwdev) {struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; - rtwsdio->irq_mask =REG_SDIO_HIMR_RX_REQUEST |REG_SDIO_HIMR_CPWM1 ; +if (rtw_is_8723bs (rtwdev)) + rtwsdio->irq_mask =REG_SDIO_HIMR_RX_REQUEST ; +else + rtwsdio->irq_mask =REG_SDIO_HIMR_RX_REQUEST | +REG_SDIO_HIMR_CPWM1 ; }static void rtw_sdio_enable_rx_aggregation (struct rtw_dev *rtwdev)
@@ -852,6 +856,7 @@ static void rtw_sdio_enable_rx_aggregation(struct rtw_dev *rtwdev)u8 size, timeout;switch (rtwdev->chip->id) { +case RTW_CHIP_TYPE_8723B :case RTW_CHIP_TYPE_8703B :case RTW_CHIP_TYPE_8821A :case RTW_CHIP_TYPE_8812A :
@@ -879,6 +884,8 @@ static void rtw_sdio_enable_rx_aggregation(struct rtw_dev *rtwdev) FIELD_PREP(BIT_DMA_AGG_TO_V1, timeout));rtw_write8_set (rtwdev,REG_RXDMA_MODE ,BIT_DMA_MODE ); +if (rtw_is_8723bs (rtwdev)) +rtw_write8_set (rtwdev,REG_RXDMA_MODE ,3 <<2 ); }static void rtw_sdio_enable_interrupt (struct rtw_dev *rtwdev)
@@ -947,9 +954,19 @@ static void rtw_sdio_8723bs_check_rqpn(struct rtw_dev *rtwdev)static int rtw_sdio_start (struct rtw_dev *rtwdev) { +u32 clear; +rtw_sdio_8723bs_check_rqpn (rtwdev);rtw_sdio_init_free_txpg (rtwdev);rtw_sdio_enable_rx_aggregation (rtwdev); + +if (rtw_is_8723bs (rtwdev)) { + clear =rtw_read32 (rtwdev,REG_SDIO_HISR ) & +RTW_SDIO_HISR_CLEAR_MASK ; +if (clear) +rtw_write32 (rtwdev,REG_SDIO_HISR , clear); + } +rtw_sdio_enable_interrupt (rtwdev);return 0 ;
@@ -1029,6 +1046,8 @@ static void rtw_sdio_interface_cfg(struct rtw_dev *rtwdev) val =rtw_read32 (rtwdev,REG_SDIO_TX_CTRL ); val &=0xfff8 ; +if (rtw_is_8723bs (rtwdev)) + val |=BIT_SDIO_TX_CTRL_ALWAYS_RECOGNIZE ;rtw_write32 (rtwdev,REG_SDIO_TX_CTRL , val); }
@@ -1293,6 +1312,13 @@ static void rtw_sdio_handle_interrupt(struct sdio_func *sdio_func)rtw_sdio_rx_isr (rtwdev); } +/* RTL8723BS keeps raising the interrupt after resume if undefined +* status bits are written back, so acknowledge only the bits that are +* both defined and unmasked. Other chips keep the existing behaviour. +*/ +if (rtw_is_8723bs (rtwdev)) + hisr &= rtwsdio->irq_mask &RTW_SDIO_HISR_CLEAR_MASK ; +rtw_write32 (rtwdev,REG_SDIO_HISR , hisr); rtwsdio->irq_thread =NULL ;
drivers/net/wireless/realtek/rtw88/sdio.h +9 -0
@@ -22,6 +22,7 @@/* SDIO Tx Control */ #define REG_SDIO_TX_CTRL (SDIO_LOCAL_OFFSET + 0x0000) +#define BIT_SDIO_TX_CTRL_ALWAYS_RECOGNIZE BIT(4)/*SDIO status timeout*/ #define REG_SDIO_TIMEOUT (SDIO_LOCAL_OFFSET + 0x0002)
@@ -77,6 +78,14 @@/* the following two are RTL8188 SDIO Specific */ #define REG_SDIO_HISR_MCU_ERR BIT(28)#define REG_SDIO_HISR_TSF_BIT32_TOGGLE BIT(29) +#define RTW_SDIO_HISR_CLEAR_MASK \ + (REG_SDIO_HISR_TXERR | REG_SDIO_HISR_RXERR | \ + REG_SDIO_HISR_TXFOVW | REG_SDIO_HISR_RXFOVW | \ + REG_SDIO_HISR_TXBCNOK | REG_SDIO_HISR_TXBCNERR | \ + REG_SDIO_HISR_C2HCMD | REG_SDIO_HISR_CPWM1 | \ + REG_SDIO_HISR_CPWM2 | REG_SDIO_HISR_HSISR_IND | \ + REG_SDIO_HISR_GTINT3_IND | REG_SDIO_HISR_GTINT4_IND | \ + REG_SDIO_HISR_PSTIMEOUT | REG_SDIO_HISR_OCPINT)/* HCI Current Power Mode */ #define REG_SDIO_HCPWM (SDIO_LOCAL_OFFSET + 0x0019)
Signature · 1 line
2.55.0
Ping-Ke Shih
maintainerRE: [PATCH v2 08/11] wifi: rtw88: sdio: set up RX aggregation and interrupts for RTL8723BS
Quoted 24 lines · [email protected] <[email protected]> wrote:
From: Luka Gejak <[email protected]>
Enable the existing RX aggregation setup for this chip and select the larger DMA aggregation mode it needs. The RTL8723BS does not raise CPWM1, so leave that source out of its interrupt mask, and set the SDIO TX control bit the vendor driver uses to have transfers always recognised.
The chip also keeps raising the interrupt after resume if undefined status bits are written back when acknowledging, so acknowledge only the defined and unmasked bits. That is scoped to this chip; the other SDIO parts keep writing the status word back unchanged.
Signed-off-by Luka Gejak <[email protected]>--- drivers/net/wireless/realtek/rtw88/sdio.c | 28 ++++++++++++++++++++++- drivers/net/wireless/realtek/rtw88/sdio.h | 9 ++++++++ 2 files changed, 36 insertions(+), 1 deletion(-)drivers/net/wireless/realtek/rtw88/sdio.c +0
-0
drivers/net/wireless/realtek/rtw88/sdio.c static void rtw_sdio_init(struct rtw_dev *rtwdev) · line 851
Quoted 9 lines
drivers/net/wireless/realtek/rtw88/sdio.c +5
-1@@ -844,7 +844,11 @@ static void rtw_sdio_init(struct rtw_dev *rtwdev) {struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; - rtwsdio->irq_mask =REG_SDIO_HIMR_RX_REQUEST |REG_SDIO_HIMR_CPWM1 ; +if (rtw_is_8723bs (rtwdev)) + rtwsdio->irq_mask =REG_SDIO_HIMR_RX_REQUEST ; +else + rtwsdio->irq_mask =REG_SDIO_HIMR_RX_REQUEST | +REG_SDIO_HIMR_CPWM1 ;
align the REG_*
Quoted 12 lines
drivers/net/wireless/realtek/rtw88/sdio.c +1
-0}static void rtw_sdio_enable_rx_aggregation (struct rtw_dev *rtwdev)@@ -852,6 +856,7 @@ static void rtw_sdio_enable_rx_aggregation(struct rtw_dev *rtwdev)u8 size, timeout;switch (rtwdev->chip->id) { +case RTW_CHIP_TYPE_8723B :case RTW_CHIP_TYPE_8703B :case RTW_CHIP_TYPE_8821A :case RTW_CHIP_TYPE_8812A :
drivers/net/wireless/realtek/rtw88/sdio.c static void rtw_sdio_enable_rx_aggregation(struct rtw_dev *rtwdev) · line 888
Quoted 5 lines
drivers/net/wireless/realtek/rtw88/sdio.c +2
-0@@ -879,6 +884,8 @@ static void rtw_sdio_enable_rx_aggregation(struct rtw_dev *rtwdev) FIELD_PREP(BIT_DMA_AGG_TO_V1, timeout));rtw_write8_set (rtwdev,REG_RXDMA_MODE ,BIT_DMA_MODE ); +if (rtw_is_8723bs (rtwdev)) +rtw_write8_set (rtwdev,REG_RXDMA_MODE ,3 <<2 );
I think you are setting burst count? rtw_write8_mask()?
#define BIT_DMA_BURST_CNT GENMASK(3, 2)
Quoted 33 lines
drivers/net/wireless/realtek/rtw88/sdio.c +12
-0}static void rtw_sdio_enable_interrupt (struct rtw_dev *rtwdev)@@ -947,9 +954,19 @@ static void rtw_sdio_8723bs_check_rqpn(struct rtw_dev *rtwdev)static int rtw_sdio_start (struct rtw_dev *rtwdev) { +u32 clear; +rtw_sdio_8723bs_check_rqpn (rtwdev);rtw_sdio_init_free_txpg (rtwdev);rtw_sdio_enable_rx_aggregation (rtwdev); + +if (rtw_is_8723bs (rtwdev)) { + clear =rtw_read32 (rtwdev,REG_SDIO_HISR ) & +RTW_SDIO_HISR_CLEAR_MASK ; +if (clear) +rtw_write32 (rtwdev,REG_SDIO_HISR , clear); + } +rtw_sdio_enable_interrupt (rtwdev);return 0 ;@@ -1029,6 +1046,8 @@ static void rtw_sdio_interface_cfg(struct rtw_dev *rtwdev) val =rtw_read32 (rtwdev,REG_SDIO_TX_CTRL ); val &=0xfff8 ; +if (rtw_is_8723bs (rtwdev)) + val |=BIT_SDIO_TX_CTRL_ALWAYS_RECOGNIZE ;rtw_write32 (rtwdev,REG_SDIO_TX_CTRL , val); }
drivers/net/wireless/realtek/rtw88/sdio.c static void rtw_sdio_handle_interrupt(struct sdio_func *sdio_func) · line 1318
Quoted 7 lines
drivers/net/wireless/realtek/rtw88/sdio.c +4
-0@@ -1293,6 +1312,13 @@ static void rtw_sdio_handle_interrupt(struct sdio_func *sdio_func)rtw_sdio_rx_isr (rtwdev); } +/* RTL8723BS keeps raising the interrupt after resume if undefined +* status bits are written back, so acknowledge only the bits that are +* both defined and unmasked. Other chips keep the existing behaviour. +*/
comment style
Quoted 6 lines
drivers/net/wireless/realtek/rtw88/sdio.c +3
-0+if (rtw_is_8723bs (rtwdev)) + hisr &= rtwsdio->irq_mask &RTW_SDIO_HISR_CLEAR_MASK ; +rtw_write32 (rtwdev,REG_SDIO_HISR , hisr); rtwsdio->irq_thread =NULL ;
[...]
Re: [PATCH v2 08/11] wifi: rtw88: sdio: set up RX aggregation and interrupts for RTL8723BS
From: Luka Gejak <[email protected]>
Quoted 4 lines · Ping-Ke Shih
drivers/net/wireless/realtek/rtw88/sdio.c static void rtw_sdio_init(struct rtw_dev *rtwdev) · line 851
Quoted 2 lines
drivers/net/wireless/realtek/rtw88/sdio.c +2
-0+ rtwsdio->irq_mask =REG_SDIO_HIMR_RX_REQUEST | +REG_SDIO_HIMR_CPWM1 ;align the REG_*
Fixed.
Quoted 6 lines
drivers/net/wireless/realtek/rtw88/sdio.c static void rtw_sdio_enable_rx_aggregation(struct rtw_dev *rtwdev) · line 888
Quoted 2 lines
drivers/net/wireless/realtek/rtw88/sdio.c +2
-0+if (rtw_is_8723bs (rtwdev)) +rtw_write8_set (rtwdev,REG_RXDMA_MODE ,3 <<2 );I think you are setting burst count?
rtw_write8_mask()?#define
BIT_DMA_BURST_CNTGENMASK(3, 2)
Yes, that is the burst count. Now
rtw_write8_mask(rtwdev, REG_RXDMA_MODE, BIT_DMA_BURST_CNT, 0x3);
Quoted 3 lines
Quoted 1 line
+ /* RTL8723BS keeps raising the interrupt after resume if undefined
comment style
Fixed, along with the rest of the series.
Best regards,
Luka Gejak
PATCH v2 9/11 wifi: rtw88: sdio: add TX back-pressure and retry on page starvation
In reply to [email protected]From: Luka Gejak <[email protected]>
Two problems show up on RTL8723BS uplink. The per-AC software FIFO is unbounded, so mac80211 keeps handing frames down until latency collapses under load. And when the chip runs out of free TX pages the queue is simply abandoned for that pass, which stalls the AC until something else kicks the worker.
Stop the mac80211 queue once a data AC fills past a high watermark and wake it from the drain path when it falls back to a low one. Convert the TX work item to a delayed work so a temporary page shortage can be retried shortly afterwards instead of stalling, and cancel it on teardown.
Measured on RTL8723BS hardware, uplink goes from 11.9 Mbit/s with 204 TCP retransmits to 20.1 Mbit/s with 2.
--- drivers/net/wireless/realtek/rtw88/sdio.c | 75 ++++++++++++++++++++--- drivers/net/wireless/realtek/rtw88/sdio.h | 3 +- 2 files changed, 68 insertions(+), 10 deletions(-)
drivers/net/wireless/realtek/rtw88/sdio.c +66 -9
@@ -22,6 +22,15 @@#define RTW_SDIO_INDIRECT_RW_RETRIES 50#define RTW_SDIO_OQT_TIMEOUT_MS 1000 +/* 8723BS SDIO TX FIFO back-pressure watermarks: stop the mac80211 queue once +* the per-AC software FIFO fills past the high watermark, and wake it from the +* TX drain path once it falls back to the low one. Bounds the queueing latency +* that otherwise causes uplink bufferbloat / congestion collapse. +*/ +#define RTW_SDIO_TX_FIFO_HIWATER 16 +#define RTW_SDIO_TX_FIFO_LOWATER 8 +#define RTW_SDIO_TX_RETRY_DELAY msecs_to_jiffies(1) +static bool rtw_sdio_is_bus_addr (u32 addr) {return !!(addr &RTW_SDIO_BUS_MSK );
@@ -1030,7 +1039,7 @@ static void rtw_sdio_tx_kick_off(struct rtw_dev *rtwdev) {struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; -queue_work (rtwsdio->txwq, &rtwsdio->tx_handler_data->work); +mod_delayed_work (rtwsdio->txwq, &rtwsdio->tx_handler_data->work,0 ); }static void rtw_sdio_link_ps (struct rtw_dev *rtwdev,bool enter)
@@ -1154,6 +1163,18 @@ static int rtw_sdio_tx_write(struct rtw_dev *rtwdev,skb_queue_tail (&rtwsdio->tx_queue[queue], skb); +/* Back-pressure on the data ACs (BK/BE/VI/VO): once the FIFO fills past +* the high watermark, stop the corresponding mac80211 queue so it stops +* handing us frames, bounding the queueing latency. Resumed from the TX +* drain path once the FIFO drains below the low watermark. +*/ +if (rtw_is_8723bs (rtwdev) && queue <RTW_TX_QUEUE_BCN && + !rtwsdio->queue_stopped[queue] && +skb_queue_len (&rtwsdio->tx_queue[queue]) >=RTW_SDIO_TX_FIFO_HIWATER ) { + rtwsdio->queue_stopped[queue] = true; +ieee80211_stop_queue (rtwdev->hw,skb_get_queue_mapping (skb)); + } +return 0 ; }
@@ -1455,32 +1476,48 @@ static void rtw_sdio_indicate_tx_status(struct rtw_dev *rtwdev,ieee80211_tx_status_irqsafe (hw, skb); } -static void rtw_sdio_process_tx_queue (struct rtw_dev *rtwdev, -enum rtw_tx_queue_type queue) +static int rtw_sdio_process_tx_queue (struct rtw_dev *rtwdev, +enum rtw_tx_queue_type queue, +bool *processed) {struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv;struct sk_buff *skb; +u16 q_map;int ret; + *processed = false; skb =skb_dequeue (&rtwsdio->tx_queue[queue]);if (!skb) -return ; +return 0 ; + *processed = true; + q_map =skb_get_queue_mapping (skb); ret =rtw_sdio_write_port (rtwdev, skb, queue);if (ret) {skb_queue_head (&rtwsdio->tx_queue[queue], skb); -return ; +return ret; }rtw_sdio_indicate_tx_status (rtwdev, skb); + +if (rtw_is_8723bs (rtwdev) && queue <RTW_TX_QUEUE_BCN && + rtwsdio->queue_stopped[queue] && +skb_queue_len (&rtwsdio->tx_queue[queue]) <=RTW_SDIO_TX_FIFO_LOWATER ) { + rtwsdio->queue_stopped[queue] = false; +ieee80211_wake_queue (rtwdev->hw, q_map); + } + +return 0 ; }static void rtw_sdio_tx_handler (struct work_struct *work) {struct rtw_sdio_work_data *work_data = - container_of(work, struct rtw_sdio_work_data, work); + container_of(to_delayed_work(work), struct rtw_sdio_work_data, + work);struct rtw_sdio *rtwsdio;struct rtw_dev *rtwdev; +bool processed;int limit, queue; rtwdev = work_data->rtwdev;
@@ -1491,7 +1528,24 @@ static void rtw_sdio_tx_handler(struct work_struct *work)for (queue =RTK_MAX_TX_QUEUE_NUM -1 ; queue >=0 ; queue--) {for (limit =0 ; limit <1000 ; limit++) { -rtw_sdio_process_tx_queue (rtwdev, queue); +int ret; + + ret =rtw_sdio_process_tx_queue (rtwdev, queue, &processed); +if (ret) { +if (rtw_is_8723bs (rtwdev) && ret == -EBUSY ) { +mod_delayed_work (rtwsdio->txwq, + &work_data->work, +RTW_SDIO_TX_RETRY_DELAY ); +return ; + } +break ; + } + +if (rtw_is_8723bs (rtwdev) && + queue ==RTW_TX_QUEUE_MGMT && processed) { +mod_delayed_work (rtwsdio->txwq, &work_data->work,0 ); +return ; + }if (skb_queue_empty (&rtwsdio->tx_queue[queue]))break ;
@@ -1518,14 +1572,16 @@ static int rtw_sdio_init_tx(struct rtw_dev *rtwdev)return -ENOMEM ; } -for (i =0 ; i <RTK_MAX_TX_QUEUE_NUM ; i++) +for (i =0 ; i <RTK_MAX_TX_QUEUE_NUM ; i++) {skb_queue_head_init (&rtwsdio->tx_queue[i]); + rtwsdio->queue_stopped[i] = false; + } rtwsdio->tx_handler_data =kmalloc_obj (*rtwsdio->tx_handler_data);if (!rtwsdio->tx_handler_data) goto err_destroy_wq; rtwsdio->tx_handler_data->rtwdev = rtwdev; -INIT_WORK (&rtwsdio->tx_handler_data->work, rtw_sdio_tx_handler); +INIT_DELAYED_WORK (&rtwsdio->tx_handler_data->work, rtw_sdio_tx_handler);return 0 ;
@@ -1539,6 +1595,7 @@ static void rtw_sdio_deinit_tx(struct rtw_dev *rtwdev)struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv;int i; +cancel_delayed_work_sync (&rtwsdio->tx_handler_data->work);destroy_workqueue (rtwsdio->txwq);kfree (rtwsdio->tx_handler_data);
drivers/net/wireless/realtek/rtw88/sdio.h +2 -1
@@ -152,7 +152,7 @@ struct rtw_sdio_tx_data { };struct rtw_sdio_work_data { -struct work_struct work; +struct delayed_work work;struct rtw_dev *rtwdev; };
@@ -168,6 +168,7 @@ struct rtw_sdio {struct workqueue_struct *txwq;struct rtw_sdio_work_data *tx_handler_data;struct sk_buff_head tx_queue[RTK_MAX_TX_QUEUE_NUM ]; +bool queue_stopped[RTK_MAX_TX_QUEUE_NUM ];atomic_t free_pg_high;atomic_t free_pg_normal;
Signature · 1 line
2.55.0
Ping-Ke Shih
maintainerRE: [PATCH v2 09/11] wifi: rtw88: sdio: add TX back-pressure and retry on page starvation
Quoted 28 lines · [email protected] <[email protected]> wrote:
From: Luka Gejak <[email protected]>
Two problems show up on RTL8723BS uplink. The per-AC software FIFO is unbounded, so mac80211 keeps handing frames down until latency collapses under load. And when the chip runs out of free TX pages the queue is simply abandoned for that pass, which stalls the AC until something else kicks the worker.
Stop the mac80211 queue once a data AC fills past a high watermark and wake it from the drain path when it falls back to a low one. Convert the TX work item to a delayed work so a temporary page shortage can be retried shortly afterwards instead of stalling, and cancel it on teardown.
Measured on RTL8723BS hardware, uplink goes from 11.9 Mbit/s with 204 TCP retransmits to 20.1 Mbit/s with 2.
Signed-off-by Luka Gejak <[email protected]>--- drivers/net/wireless/realtek/rtw88/sdio.c | 75 ++++++++++++++++++++--- drivers/net/wireless/realtek/rtw88/sdio.h | 3 +- 2 files changed, 68 insertions(+), 10 deletions(-)drivers/net/wireless/realtek/rtw88/sdio.c +0
-0
drivers/net/wireless/realtek/rtw88/sdio.c line 29
Quoted 8 lines
drivers/net/wireless/realtek/rtw88/sdio.c +5
-0@@ -22,6 +22,15 @@#define RTW_SDIO_INDIRECT_RW_RETRIES 50#define RTW_SDIO_OQT_TIMEOUT_MS 1000 +/* 8723BS SDIO TX FIFO back-pressure watermarks: stop the mac80211 queue once +* the per-AC software FIFO fills past the high watermark, and wake it from the +* TX drain path once it falls back to the low one. Bounds the queueing latency +* that otherwise causes uplink bufferbloat / congestion collapse. +*/
comment style.
drivers/net/wireless/realtek/rtw88/sdio.c static void rtw_sdio_tx_kick_off(struct rtw_dev *rtwdev) · line 1042
Quoted 13 lines
drivers/net/wireless/realtek/rtw88/sdio.c +5
-1+#define RTW_SDIO_TX_FIFO_HIWATER 16 +#define RTW_SDIO_TX_FIFO_LOWATER 8 +#define RTW_SDIO_TX_RETRY_DELAY msecs_to_jiffies(1) +static bool rtw_sdio_is_bus_addr (u32 addr) {return !!(addr &RTW_SDIO_BUS_MSK );@@ -1030,7 +1039,7 @@ static void rtw_sdio_tx_kick_off(struct rtw_dev *rtwdev) {struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; -queue_work (rtwsdio->txwq, &rtwsdio->tx_handler_data->work); +mod_delayed_work (rtwsdio->txwq, &rtwsdio->tx_handler_data->work,0 );
queue_delayed_work()?
Quoted 38 lines
drivers/net/wireless/realtek/rtw88/sdio.c +17
-2}static void rtw_sdio_link_ps (struct rtw_dev *rtwdev,bool enter)@@ -1154,6 +1163,18 @@ static int rtw_sdio_tx_write(struct rtw_dev *rtwdev,skb_queue_tail (&rtwsdio->tx_queue[queue], skb); +/* Back-pressure on the data ACs (BK/BE/VI/VO): once the FIFO fills past +* the high watermark, stop the corresponding mac80211 queue so it stops +* handing us frames, bounding the queueing latency. Resumed from the TX +* drain path once the FIFO drains below the low watermark. +*/ +if (rtw_is_8723bs (rtwdev) && queue <RTW_TX_QUEUE_BCN && + !rtwsdio->queue_stopped[queue] && +skb_queue_len (&rtwsdio->tx_queue[queue]) >=RTW_SDIO_TX_FIFO_HIWATER ) { + rtwsdio->queue_stopped[queue] = true; +ieee80211_stop_queue (rtwdev->hw,skb_get_queue_mapping (skb)); + } +return 0 ; }@@ -1455,32 +1476,48 @@ static void rtw_sdio_indicate_tx_status(struct rtw_dev *rtwdev,ieee80211_tx_status_irqsafe (hw, skb); } -static void rtw_sdio_process_tx_queue (struct rtw_dev *rtwdev, -enum rtw_tx_queue_type queue) +static int rtw_sdio_process_tx_queue (struct rtw_dev *rtwdev, +enum rtw_tx_queue_type queue, +bool *processed) {struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv;struct sk_buff *skb; +u16 q_map;int ret; + *processed = false;
drivers/net/wireless/realtek/rtw88/sdio.c static void rtw_sdio_indicate_tx_status(struct rtw_dev *rtwdev, · line 1497
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/sdio.c +3
-1skb =skb_dequeue (&rtwsdio->tx_queue[queue]);if (!skb) -return ; +return 0 ; + *processed = true; + q_map =skb_get_queue_mapping (skb); ret =rtw_sdio_write_port (rtwdev, skb, queue);if (ret) {skb_queue_head (&rtwsdio->tx_queue[queue], skb);
This case is also processed = true?
Quoted 41 lines
drivers/net/wireless/realtek/rtw88/sdio.c +21
-3-return ; +return ret; }rtw_sdio_indicate_tx_status (rtwdev, skb); + +if (rtw_is_8723bs (rtwdev) && queue <RTW_TX_QUEUE_BCN && + rtwsdio->queue_stopped[queue] && +skb_queue_len (&rtwsdio->tx_queue[queue]) <=RTW_SDIO_TX_FIFO_LOWATER ) { + rtwsdio->queue_stopped[queue] = false; +ieee80211_wake_queue (rtwdev->hw, q_map); + } + +return 0 ; }static void rtw_sdio_tx_handler (struct work_struct *work) {struct rtw_sdio_work_data *work_data = - container_of(work, struct rtw_sdio_work_data, work); + container_of(to_delayed_work(work), struct rtw_sdio_work_data, + work);struct rtw_sdio *rtwsdio;struct rtw_dev *rtwdev; +bool processed;int limit, queue; rtwdev = work_data->rtwdev;@@ -1491,7 +1528,24 @@ static void rtw_sdio_tx_handler(struct work_struct *work)for (queue =RTK_MAX_TX_QUEUE_NUM -1 ; queue >=0 ; queue--) {for (limit =0 ; limit <1000 ; limit++) { -rtw_sdio_process_tx_queue (rtwdev, queue); +int ret; + + ret =rtw_sdio_process_tx_queue (rtwdev, queue, &processed); +if (ret) { +if (rtw_is_8723bs (rtwdev) && ret == -EBUSY ) { +mod_delayed_work (rtwsdio->txwq, + &work_data->work, +RTW_SDIO_TX_RETRY_DELAY );
drivers/net/wireless/realtek/rtw88/sdio.c static void rtw_sdio_tx_handler(struct work_struct *work) · line 1548
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/sdio.c +10
-0+return ; + } +break ; + } + +if (rtw_is_8723bs (rtwdev) && + queue ==RTW_TX_QUEUE_MGMT && processed) { +mod_delayed_work (rtwsdio->txwq, &work_data->work,0 ); +return ; + }
Can you cleanup the handlers of return value and processed? The logic isn't clear to me.
Quoted 53 lines
drivers/net/wireless/realtek/rtw88/sdio.c +5
-2if (skb_queue_empty (&rtwsdio->tx_queue[queue]))break ;@@ -1518,14 +1572,16 @@ static int rtw_sdio_init_tx(struct rtw_dev *rtwdev)return -ENOMEM ; } -for (i =0 ; i <RTK_MAX_TX_QUEUE_NUM ; i++) +for (i =0 ; i <RTK_MAX_TX_QUEUE_NUM ; i++) {skb_queue_head_init (&rtwsdio->tx_queue[i]); + rtwsdio->queue_stopped[i] = false; + } rtwsdio->tx_handler_data =kmalloc_obj (*rtwsdio->tx_handler_data);if (!rtwsdio->tx_handler_data) goto err_destroy_wq; rtwsdio->tx_handler_data->rtwdev = rtwdev; -INIT_WORK (&rtwsdio->tx_handler_data->work, rtw_sdio_tx_handler); +INIT_DELAYED_WORK (&rtwsdio->tx_handler_data->work, rtw_sdio_tx_handler);return 0 ;@@ -1539,6 +1595,7 @@ static void rtw_sdio_deinit_tx(struct rtw_dev *rtwdev)struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv;int i; +cancel_delayed_work_sync (&rtwsdio->tx_handler_data->work);destroy_workqueue (rtwsdio->txwq);kfree (rtwsdio->tx_handler_data);drivers/net/wireless/realtek/rtw88/sdio.h +2
-2@@ -152,7 +152,7 @@ struct rtw_sdio_tx_data { };struct rtw_sdio_work_data { -struct work_struct work; +struct delayed_work work;struct rtw_dev *rtwdev; };@@ -168,6 +168,7 @@ struct rtw_sdio {struct workqueue_struct *txwq;struct rtw_sdio_work_data *tx_handler_data;struct sk_buff_head tx_queue[RTK_MAX_TX_QUEUE_NUM ]; +bool queue_stopped[RTK_MAX_TX_QUEUE_NUM ];atomic_t free_pg_high;atomic_t free_pg_normal; --2.55.0
Re: [PATCH v2 09/11] wifi: rtw88: sdio: add TX back-pressure and retry on page starvation
From: Luka Gejak <[email protected]>
Quoted 3 lines · Ping-Ke Shih
Quoted 1 line
+/* 8723BS SDIO TX FIFO back-pressure watermarks: stop the mac80211 queue once
comment style.
Fixed, both of them.
Quoted 5 lines
Review
Quoted 3 lines
(quoted diff) +2
-1- queue_work(rtwsdio->txwq, &rtwsdio->tx_handler_data->work); + mod_delayed_work(rtwsdio->txwq, + &rtwsdio->tx_handler_data->work, 0);
queue_delayed_work()?
Changed inside the TX handler, where the work is not pending and queue_delayed_work() is the right call.
I kept mod_delayed_work() in rtw_sdio_tx_kick_off() on purpose, because there it can race with a pending retry. If a page shortage has already armed the work with RTW_SDIO_TX_RETRY_DELAY, queue_delayed_work() would see it pending and do nothing, so a newly queued frame would sit for up to a millisecond for no reason. mod_delayed_work() re-arms it to fire immediately. I have added a comment saying so.
Quoted 4 lines
Quoted 2 lines
if (ret) { skb_queue_head(&rtwsdio->tx_queue[queue], skb);This case is also
processed = true?
[...]
Quoted 2 lines
Can you cleanup the handlers of return value and processed? The logic isn't clear to me.
You are right that it was not clear, and the requeue case was the
reason: the frame had been dequeued but not sent, so neither value described it well. The out-parameter is gone. rtw_sdio_process_tx_queue() now returns:
1 a frame was written 0 the queue was empty <0 the write failed and the frame is back at the head of the queue
which the handler reads as
ret = rtw_sdio_process_tx_queue(rtwdev, queue);
if (ret == 0)
break;
if (ret < 0) {
if (rtl8723bs && ret == -EBUSY) {
queue_delayed_work(... RTW_SDIO_TX_RETRY_DELAY);
return;
}
break;
}with the management frame restart after it. Behaviour is unchanged; a non-EBUSY error still moves on to the next queue.
Best regards,
Luka Gejak
Ping-Ke Shih
maintainerRE: [PATCH v2 09/11] wifi: rtw88: sdio: add TX back-pressure and retry on page starvation
Quoted 10 lines · [email protected] <[email protected]> wrote:
Quoted 5 lines · Ping-Ke Shih
Review
Quoted 3 lines
(quoted diff) +2
-1- queue_work(rtwsdio->txwq, &rtwsdio->tx_handler_data->work); + mod_delayed_work(rtwsdio->txwq, + &rtwsdio->tx_handler_data->work, 0);
queue_delayed_work()?Changed inside the TX handler, where the work is not pending and
queue_delayed_work()is the right call.
Quoted 6 lines
I kept
mod_delayed_work()inrtw_sdio_tx_kick_off()on purpose, because there it can race with a pending retry. If a page shortage has already armed the work withRTW_SDIO_TX_RETRY_DELAY,queue_delayed_work()would see it pending and do nothing, so a newly queued frame would sit for up to a millisecond for no reason.mod_delayed_work()re-arms it to fire immediately. I have added a comment saying so.
Make sense. Please add a short comment for the reason.
Ping-Ke
PATCH v2 10/11 wifi: rtw88: record beacons from the target BSSID before authenticating
In reply to [email protected]From: Luka Gejak <[email protected]>
The vendor start_clnt_join() does not begin authentication until it has seen a beacon or probe response from the target BSSID, and the RTL8723BS firmware depends on that ordering: authenticating earlier leaves the firmware without the BSS parameters it needs and the exchange times out.
Record such frames from the receive path so the join sequence can wait for one. The recording is gated on the chip and only active during the pre-authentication window, so it costs other chips a single test per frame.
--- drivers/net/wireless/realtek/rtw88/mac80211.c | 31 +++++++++++++++++++ drivers/net/wireless/realtek/rtw88/main.c | 2 ++ drivers/net/wireless/realtek/rtw88/main.h | 20 ++++++++++++ drivers/net/wireless/realtek/rtw88/sdio.c | 5 +++ 4 files changed, 58 insertions(+)
drivers/net/wireless/realtek/rtw88/mac80211.c +31 -0
@@ -15,6 +15,37 @@#include "wow.h" #include "sar.h" +/* 8723BS SDIO: record a beacon/probe-resp seen from the target BSSID during +* the pre-auth window so the join sequence (mgd_prepare_tx) can wait for it, +* mirroring the vendor start_clnt_join(). Called from the SDIO RX path. +*/ +void rtw8723bs_auth_sync_rx (struct rtw_dev *rtwdev, +const struct ieee80211_hdr *hdr,u32 len, +const struct rtw_rx_pkt_stat *pkt_stat, +const struct ieee80211_rx_status *rx_status) +{ +struct rtw_auth_sync *sync = &rtwdev->auth_sync; +unsigned long flags; +__le16 fc = hdr->frame_control; + +if (!rtw_is_8723bs (rtwdev) || +test_bit (RTW_FLAG_SCANNING , rtwdev->flags) || + pkt_stat->crc_err || pkt_stat->icv_err) +return ; + +if (!ieee80211_is_beacon (fc) && !ieee80211_is_probe_resp (fc)) +return ; + +spin_lock_irqsave (&sync->lock, flags); +if (sync->active &ðer_addr_equal (hdr->addr3, sync->bssid)) { + sync->seen = true; + sync->seen_count++; +wake_up (&sync->wait); + } +spin_unlock_irqrestore (&sync->lock, flags); +} +EXPORT_SYMBOL (rtw8723bs_auth_sync_rx); +static void rtw_ops_tx (struct ieee80211_hw *hw,struct ieee80211_tx_control *control,struct sk_buff *skb)
drivers/net/wireless/realtek/rtw88/main.c +2 -0
@@ -2174,11 +2174,13 @@ int rtw_core_init(struct rtw_dev *rtwdev)spin_lock_init (&rtwdev->txq_lock);spin_lock_init (&rtwdev->tx_report.q_lock); +spin_lock_init (&rtwdev->auth_sync.lock);mutex_init (&rtwdev->mutex);mutex_init (&rtwdev->hal.tx_power_mutex);init_waitqueue_head (&rtwdev->coex.wait); +init_waitqueue_head (&rtwdev->auth_sync.wait);init_completion (&rtwdev->lps_leave_check);init_completion (&rtwdev->fw_scan_density);
drivers/net/wireless/realtek/rtw88/main.h +20 -0
@@ -2058,6 +2058,20 @@ struct rtw_hw_scan_info {u8 op_bw; }; +/* +* Synchronises the pre-auth wait on a beacon or probe response from the +* target BSSID before the join sequence continues. +*/ +struct rtw_auth_sync { +wait_queue_head_t wait; +/* Protects the fields below. */ +spinlock_t lock; +u8 bssid[ETH_ALEN ]; +bool active; +bool seen; +u32 seen_count; +}; +struct rtw_dev {struct ieee80211_hw *hw;struct device *dev;
@@ -2134,6 +2148,8 @@ struct rtw_dev {struct completion fw_scan_density;bool ap_active; +struct rtw_auth_sync auth_sync; +bool led_registered;char led_name[32 ];struct led_classdev led_cdev;
@@ -2291,4 +2307,8 @@ bool rtw_core_check_sta_active(struct rtw_dev *rtwdev);void rtw_core_enable_beacon (struct rtw_dev *rtwdev,bool enable);void rtw_set_ampdu_factor (struct rtw_dev *rtwdev,struct ieee80211_vif *vif,struct ieee80211_bss_conf *bss_conf); +void rtw8723bs_auth_sync_rx (struct rtw_dev *rtwdev, +const struct ieee80211_hdr *hdr,u32 len, +const struct rtw_rx_pkt_stat *pkt_stat, +const struct ieee80211_rx_status *rx_status);#endif
drivers/net/wireless/realtek/rtw88/sdio.c +5 -0
@@ -1203,6 +1203,11 @@ static void rtw_sdio_rx_skb(struct rtw_dev *rtwdev, struct sk_buff *skb,rtw_update_rx_freq_for_invalid (rtwdev, skb, rx_status, pkt_stat);rtw_rx_stats (rtwdev, pkt_stat->vif, skb); +if (skb->len >=sizeof (struct ieee80211_hdr_3addr )) +rtw8723bs_auth_sync_rx (rtwdev, + (struct ieee80211_hdr *)skb->data, + skb->len, pkt_stat, rx_status); +ieee80211_rx_irqsafe (rtwdev->hw, skb); }
Signature · 1 line
2.55.0
Ping-Ke Shih
maintainerRE: [PATCH v2 10/11] wifi: rtw88: record beacons from the target BSSID before authenticating
Quoted 6 lines · [email protected] <[email protected]> wrote:
From: Luka Gejak <[email protected]>
The vendor
start_clnt_join()does not begin authentication until it has seen a beacon or probe response from the target BSSID, and the RTL8723BS firmware depends on that ordering: authenticating earlier leaves the firmware without the BSS parameters it needs and the exchange times out.
I know vendor driver does wait for a beacon, but I don't think this can affect connection. Could you confirm this again?
Quoted 20 lines
Record such frames from the receive path so the join sequence can wait for one. The recording is gated on the chip and only active during the pre-authentication window, so it costs other chips a single test per frame.
Signed-off-by Luka Gejak <[email protected]>--- drivers/net/wireless/realtek/rtw88/mac80211.c | 31 +++++++++++++++++++ drivers/net/wireless/realtek/rtw88/main.c | 2 ++ drivers/net/wireless/realtek/rtw88/main.h | 20 ++++++++++++ drivers/net/wireless/realtek/rtw88/sdio.c | 5 +++ 4 files changed, 58 insertions(+)drivers/net/wireless/realtek/rtw88/mac80211.c +0
-0
drivers/net/wireless/realtek/rtw88/mac80211.c line 21
Quoted 7 lines
drivers/net/wireless/realtek/rtw88/mac80211.c +4
-0@@ -15,6 +15,37 @@#include "wow.h" #include "sar.h" +/* 8723BS SDIO: record a beacon/probe-resp seen from the target BSSID during +* the pre-auth window so the join sequence (mgd_prepare_tx) can wait for it, +* mirroring the vendor start_clnt_join(). Called from the SDIO RX path. +*/
comment style.
drivers/net/wireless/realtek/rtw88/mac80211.c line 29
Quoted 8 lines
drivers/net/wireless/realtek/rtw88/mac80211.c +8
-0+void rtw8723bs_auth_sync_rx (struct rtw_dev *rtwdev, +const struct ieee80211_hdr *hdr,u32 len, +const struct rtw_rx_pkt_stat *pkt_stat, +const struct ieee80211_rx_status *rx_status) +{ +struct rtw_auth_sync *sync = &rtwdev->auth_sync; +unsigned long flags; +__le16 fc = hdr->frame_control;
reverse X'mas tree
drivers/net/wireless/realtek/rtw88/mac80211.c line 31
Quoted 2 lines
drivers/net/wireless/realtek/rtw88/mac80211.c +2
-0+ + if (!rtw_is_8723bs(rtwdev) ||
Might caller ensure this?
Quoted 44 lines
drivers/net/wireless/realtek/rtw88/mac80211.c +17
-0+test_bit (RTW_FLAG_SCANNING , rtwdev->flags) || + pkt_stat->crc_err || pkt_stat->icv_err) + return; + +if (!ieee80211_is_beacon (fc) && !ieee80211_is_probe_resp (fc)) +return ; + +spin_lock_irqsave (&sync->lock, flags); +if (sync->active &ðer_addr_equal (hdr->addr3, sync->bssid)) { + sync->seen = true; + sync->seen_count++; +wake_up (&sync->wait); + } +spin_unlock_irqrestore (&sync->lock, flags); +} +EXPORT_SYMBOL (rtw8723bs_auth_sync_rx); +static void rtw_ops_tx (struct ieee80211_hw *hw,struct ieee80211_tx_control *control,struct sk_buff *skb)drivers/net/wireless/realtek/rtw88/main.c +2
-0@@ -2174,11 +2174,13 @@ int rtw_core_init(struct rtw_dev *rtwdev)spin_lock_init (&rtwdev->txq_lock);spin_lock_init (&rtwdev->tx_report.q_lock); +spin_lock_init (&rtwdev->auth_sync.lock);mutex_init (&rtwdev->mutex);mutex_init (&rtwdev->hal.tx_power_mutex);init_waitqueue_head (&rtwdev->coex.wait); +init_waitqueue_head (&rtwdev->auth_sync.wait);init_completion (&rtwdev->lps_leave_check);init_completion (&rtwdev->fw_scan_density);drivers/net/wireless/realtek/rtw88/main.h +0
-0@@ -2058,6 +2058,20 @@ struct rtw_hw_scan_info {u8 op_bw;
drivers/net/wireless/realtek/rtw88/main.h struct rtw_hw_scan_info { · line 2068
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/main.h +8
-0}; +/* +* Synchronises the pre-auth wait on a beacon or probe response from the +* target BSSID before the join sequence continues. +*/ +struct rtw_auth_sync { +wait_queue_head_t wait; +/* Protects the fields below. */ +spinlock_t lock;
I think you can use wait/completion. Then no need lock.
Quoted 45 lines
drivers/net/wireless/realtek/rtw88/main.h +12
-0+u8 bssid[ETH_ALEN ]; +bool active; +bool seen; +u32 seen_count; +}; +struct rtw_dev {struct ieee80211_hw *hw;struct device *dev;@@ -2134,6 +2148,8 @@ struct rtw_dev {struct completion fw_scan_density;bool ap_active; +struct rtw_auth_sync auth_sync; +bool led_registered;char led_name[32 ];struct led_classdev led_cdev;@@ -2291,4 +2307,8 @@ bool rtw_core_check_sta_active(struct rtw_dev *rtwdev);void rtw_core_enable_beacon (struct rtw_dev *rtwdev,bool enable);void rtw_set_ampdu_factor (struct rtw_dev *rtwdev,struct ieee80211_vif *vif,struct ieee80211_bss_conf *bss_conf); +void rtw8723bs_auth_sync_rx (struct rtw_dev *rtwdev, +const struct ieee80211_hdr *hdr,u32 len, +const struct rtw_rx_pkt_stat *pkt_stat, +const struct ieee80211_rx_status *rx_status);#endif drivers/net/wireless/realtek/rtw88/sdio.c +5
-1@@ -1203,6 +1203,11 @@ static void rtw_sdio_rx_skb(struct rtw_dev *rtwdev, struct sk_buff *skb,rtw_update_rx_freq_for_invalid (rtwdev, skb, rx_status, pkt_stat);rtw_rx_stats (rtwdev, pkt_stat->vif, skb); +if (skb->len >=sizeof (struct ieee80211_hdr_3addr )) +rtw8723bs_auth_sync_rx (rtwdev, + (struct ieee80211_hdr *)skb->data, + skb->len, pkt_stat, rx_status); +ieee80211_rx_irqsafe (rtwdev->hw, skb); } --2.55.0
Re: [PATCH v2 10/11] wifi: rtw88: record beacons from the target BSSID before authenticating
From: Luka Gejak <[email protected]>
Quoted 2 lines · Ping-Ke Shih
I know vendor driver does wait for a beacon, but I don't think this can affect connection. Could you confirm this again?
Confirmed, and you are right. This patch is dropped in v3.
I built the series with the wait removed and left everything else alone, then ran association attempts from a cold module reload and from a warm reconnect:
with the wait: 10/10 cold, 10/10 warm
without the wait: 12/12 cold, 12/12 warm
Time to wpa_state=COMPLETED was the same in both, around 4 s, with one outlier either way.
Looking at it again the reason is visible in the patch itself: the pre-auth deauth in patch 11 already sleeps 100 ms afterwards, and the recording window opens before that sleep, so on a 100 ms beacon interval the wait had almost always already been satisfied by the time it was reached. It was measuring the sleep, not doing anything.
Dropping it also removes struct rtw_auth_sync, so your point about using a completion instead of the spinlock, and the caller check in the RX path, are both moot. Thanks for pushing on it.
Best regards,
Luka Gejak
PATCH v2 11/11 wifi: rtw88: run the RTL8723BS association register sequence
In reply to [email protected]From: Luka Gejak <[email protected]>
The RTL8723BS firmware does not derive the BSS parameters itself. The vendor start_clnt_join() programs them directly around authentication, and without that the station either fails to authenticate or is dropped by the AP shortly after associating.
Reproduce that sequence: restrict the receive filter to the target BSSID for the join window, program the basic and response rates from the BSS rate elements, apply the preamble and slot time from the BSS capability, enable TSF update, and wait for a beacon from the target before sending the authentication frame. Restore the receive filter and response rates on disconnect.
--- drivers/net/wireless/realtek/rtw88/mac80211.c | 496 +++++++++++++++++- drivers/net/wireless/realtek/rtw88/main.h | 2 + drivers/net/wireless/realtek/rtw88/reg.h | 2 + drivers/net/wireless/realtek/rtw88/sec.h | 1 + 4 files changed, 498 insertions(+), 3 deletions(-)
drivers/net/wireless/realtek/rtw88/mac80211.c +493 -3
@@ -46,6 +46,432 @@ void rtw8723bs_auth_sync_rx(struct rtw_dev *rtwdev, }EXPORT_SYMBOL (rtw8723bs_auth_sync_rx); +/* ---- 8723BS SDIO association sequence (vendor start_clnt_join) ---- */ + +#define RTW8723BS_JOIN_RETRY_LIMIT 0x30 +#define RTW8723BS_AUTH_SYNC_WAIT_FALLBACK_MS 120 +#define RTW8723BS_AUTH_SYNC_WAIT_MIN_MS 80 +#define RTW8723BS_AUTH_SYNC_WAIT_MAX_MS 160 +#define RTW8723BS_ACK_PREAMBLE_SHORT BIT(7) +#define RTW8723BS_SHORT_SLOT_TIME 9 +#define RTW8723BS_LONG_SLOT_TIME 20 +#define RTW8723BS_RRSR_1M BIT(0) +#define RTW8723BS_RRSR_2M BIT(1) +#define RTW8723BS_RRSR_5_5M BIT(2) +#define RTW8723BS_RRSR_11M BIT(3) +#define RTW8723BS_RRSR_6M BIT(4) +#define RTW8723BS_RRSR_9M BIT(5) +#define RTW8723BS_RRSR_12M BIT(6) +#define RTW8723BS_RRSR_18M BIT(7) +#define RTW8723BS_RRSR_24M BIT(8) +#define RTW8723BS_RRSR_36M BIT(9) +#define RTW8723BS_RRSR_48M BIT(10) +#define RTW8723BS_RRSR_54M BIT(11) +#define RTW8723BS_RRSR_CCK_RATES \ + (RTW8723BS_RRSR_1M | RTW8723BS_RRSR_2M | \ + RTW8723BS_RRSR_5_5M | RTW8723BS_RRSR_11M) +#define RTW8723BS_RRSR_2G_FORCE RTW8723BS_RRSR_CCK_RATES +#define RTW8723BS_RRSR_2G_ALLOW \ + (RTW8723BS_RRSR_CCK_RATES | RTW8723BS_RRSR_6M | \ + RTW8723BS_RRSR_12M | RTW8723BS_RRSR_24M) + +/* Keep the RCR at the vendor target-only state (AMF + CBSSID) across the whole +* connect window, matching the vendor STA path. accept_all is kept only for the +* caller's intent; both paths converge the filter to target-only. +*/ +static void rtw8723bs_auth_rx_filter (struct rtw_dev *rtwdev,bool accept_all) +{ + rtwdev->hal.rcr |=BIT_AMF |BIT_CBSSID_DATA |BIT_CBSSID_BCN ; + rtwdev->hal.rcr &= ~BIT_AAP ; +rtw_write32 (rtwdev,REG_RCR , rtwdev->hal.rcr); +} + +static void rtw8723bs_config_sec_cfg (struct rtw_dev *rtwdev) +{ +u16 sec =rtw_read16 (rtwdev,RTW_SEC_CONFIG ); + + sec |=RTW_SEC_CHK_KEYID |RTW_SEC_TX_DEC_EN |RTW_SEC_RX_DEC_EN ; +rtw_write16 (rtwdev,RTW_SEC_CONFIG , sec); +} + +static void rtw8723bs_config_default_key_search (struct rtw_dev *rtwdev, +bool enable) +{ +u16 sec =rtw_read16 (rtwdev,RTW_SEC_CONFIG ); + +if (enable) + sec |=RTW_SEC_TX_BC_USE_DK |RTW_SEC_TX_UNI_USE_DK | +RTW_SEC_RX_UNI_USE_DK ; +else + sec &= ~(RTW_SEC_TX_UNI_USE_DK |RTW_SEC_RX_UNI_USE_DK | +RTW_SEC_TX_BC_USE_DK |RTW_SEC_RX_BC_USE_DK ); +rtw_write16 (rtwdev,RTW_SEC_CONFIG , sec); +} + +static void rtw8723bs_enable_tsf_update (struct rtw_dev *rtwdev) +{ +rtw_write8_clr (rtwdev,REG_BCN_CTRL ,BIT_DIS_TSF_UDT ); +} + +static void rtw8723bs_set_ack_preamble (struct rtw_dev *rtwdev, +bool short_preamble) +{ +u8 val =rtw_read8 (rtwdev,REG_RRSR +2 ) & ~RTW8723BS_ACK_PREAMBLE_SHORT ; + +if (short_preamble) + val |=RTW8723BS_ACK_PREAMBLE_SHORT ; +rtw_write8 (rtwdev,REG_RRSR +2 , val); +} + +static void rtw8723bs_set_slot_time (struct rtw_dev *rtwdev,bool short_slot) +{ +rtw_write8 (rtwdev,REG_SLOT , + short_slot ?RTW8723BS_SHORT_SLOT_TIME : +RTW8723BS_LONG_SLOT_TIME ); +} + +static u16 rtw8723bs_rrsr_from_ie_rate (u8 rate) +{ +switch (rate &0x7f ) { +case 2 :return RTW8723BS_RRSR_1M ; +case 4 :return RTW8723BS_RRSR_2M ; +case 11 :return RTW8723BS_RRSR_5_5M ; +case 22 :return RTW8723BS_RRSR_11M ; +case 12 :return RTW8723BS_RRSR_6M ; +case 18 :return RTW8723BS_RRSR_9M ; +case 24 :return RTW8723BS_RRSR_12M ; +case 36 :return RTW8723BS_RRSR_18M ; +case 48 :return RTW8723BS_RRSR_24M ; +case 72 :return RTW8723BS_RRSR_36M ; +case 96 :return RTW8723BS_RRSR_48M ; +case 108 :return RTW8723BS_RRSR_54M ; +default :return 0 ; + } +} + +static void rtw8723bs_collect_basic_rates (const u8 *ie,u16 *basic_rates, +bool *valid) +{ +int i; + +if (!ie) +return ; + +for (i =0 ; i < ie[1 ]; i++) { +u16 r; + +if (!(ie[i +2 ] &0x80 )) +continue ; + r =rtw8723bs_rrsr_from_ie_rate (ie[i +2 ]); +if (!r) +continue ; + *basic_rates |= r; + *valid = true; + } +} + +static void rtw8723bs_reset_response_rates (struct rtw_dev *rtwdev) +{ +rtw_write32 (rtwdev,REG_RRSR ,0xffff1 ); + rtwdev->dm_info.rrsr_val_init =0xffff1 ; +} + +static void rtw8723bs_apply_basic_rates (struct rtw_dev *rtwdev, +struct ieee80211_vif *vif, +const u8 *bssid) +{ +struct ieee80211_bss_conf *conf = &vif->bss_conf; +struct cfg80211_bss *lookup_bss =NULL ; +struct cfg80211_bss *bss =NULL ; +bool valid = false; +u16 basic_rates =0 ; + +if (!rtw_is_8723bs (rtwdev) || vif->type !=NL80211_IFTYPE_STATION ) +return ; + +if (conf->bss) { + bss = conf->bss; + }else if (bssid &&is_valid_ether_addr (bssid)) { + lookup_bss =cfg80211_get_bss (rtwdev->hw->wiphy,NULL , + bssid,NULL ,0 , +IEEE80211_BSS_TYPE_ESS , +IEEE80211_PRIVACY_ANY ); + bss = lookup_bss; + } + +if (bss) { +const u8 *rates, *ext; + +rcu_read_lock (); + rates =ieee80211_bss_get_ie (bss,WLAN_EID_SUPP_RATES ); + ext =ieee80211_bss_get_ie (bss,WLAN_EID_EXT_SUPP_RATES ); +rtw8723bs_collect_basic_rates (rates, &basic_rates, &valid); +rtw8723bs_collect_basic_rates (ext, &basic_rates, &valid); +rcu_read_unlock (); + } + +if (valid) { + basic_rates |=RTW8723BS_RRSR_2G_FORCE ; + basic_rates &=RTW8723BS_RRSR_2G_ALLOW ; +rtw_write16 (rtwdev,REG_RRSR , basic_rates); +rtw_write8 (rtwdev,REG_RRSR +2 , +rtw_read8 (rtwdev,REG_RRSR +2 ) &0xf0 ); + rtwdev->dm_info.rrsr_val_init = basic_rates; + } + +if (lookup_bss) +cfg80211_put_bss (rtwdev->hw->wiphy, lookup_bss); +} + +/* Program response slot time (and, when set_preamble, the ACK preamble) from +* the selected scan BSS capabilities; the AP capabilities are not yet in +* bss_conf at mgd_prepare_tx() time. +*/ +static void rtw8723bs_apply_bss_cap (struct rtw_dev *rtwdev, +struct ieee80211_vif *vif, +const u8 *bssid,bool set_preamble) +{ +struct ieee80211_bss_conf *conf = &vif->bss_conf; +struct cfg80211_bss *lookup_bss =NULL ; +struct cfg80211_bss *bss =NULL ; +bool short_preamble, short_slot; +u16 cap =0 ; + +if (!rtw_is_8723bs (rtwdev) || vif->type !=NL80211_IFTYPE_STATION ) +return ; + +if (conf->bss) { + bss = conf->bss; + }else if (bssid &&is_valid_ether_addr (bssid)) { + lookup_bss =cfg80211_get_bss (rtwdev->hw->wiphy,NULL , + bssid,NULL ,0 , +IEEE80211_BSS_TYPE_ESS , +IEEE80211_PRIVACY_ANY ); + bss = lookup_bss; + } + +if (bss) { + cap = bss->capability; + }else if (conf->assoc_capability) { + cap = conf->assoc_capability; + }else { + short_preamble = conf->use_short_preamble; + short_slot = conf->use_short_slot; + goto program; + } + short_preamble = !!(cap &WLAN_CAPABILITY_SHORT_PREAMBLE ); + short_slot = !!(cap &WLAN_CAPABILITY_SHORT_SLOT_TIME ); + +program: +if (set_preamble) +rtw8723bs_set_ack_preamble (rtwdev, short_preamble); +rtw8723bs_set_slot_time (rtwdev, short_slot); + +if (lookup_bss) +cfg80211_put_bss (rtwdev->hw->wiphy, lookup_bss); +} + +static unsigned int rtw8723bs_auth_sync_wait_ms (struct ieee80211_vif *vif) +{ +u16 beacon_int = vif->bss_conf.beacon_int; +unsigned int wait_ms; + +if (!beacon_int) +return RTW8723BS_AUTH_SYNC_WAIT_FALLBACK_MS ; + + wait_ms =DIV_ROUND_UP (beacon_int *1024 ,1000 ) +20 ; + return clamp_t(unsigned int, wait_ms, RTW8723BS_AUTH_SYNC_WAIT_MIN_MS, +RTW8723BS_AUTH_SYNC_WAIT_MAX_MS ); +} + +static void rtw8723bs_auth_sync_start (struct rtw_dev *rtwdev,const u8 *bssid) +{ +struct rtw_auth_sync *sync = &rtwdev->auth_sync; +unsigned long flags; + +spin_lock_irqsave (&sync->lock, flags); +ether_addr_copy (sync->bssid, bssid); + sync->seen = false; + sync->seen_count =0 ; + sync->active = true; +spin_unlock_irqrestore (&sync->lock, flags); +} + +static void rtw8723bs_auth_sync_stop (struct rtw_dev *rtwdev) +{ +struct rtw_auth_sync *sync = &rtwdev->auth_sync; +unsigned long flags; + +spin_lock_irqsave (&sync->lock, flags); + sync->active = false; +spin_unlock_irqrestore (&sync->lock, flags); +} + +static bool rtw8723bs_auth_sync_seen (struct rtw_dev *rtwdev) +{ +struct rtw_auth_sync *sync = &rtwdev->auth_sync; +unsigned long flags; +bool seen; + +spin_lock_irqsave (&sync->lock, flags); + seen = sync->seen; +spin_unlock_irqrestore (&sync->lock, flags); + +return seen; +} + +static bool rtw8723bs_auth_sync_wait (struct rtw_dev *rtwdev, +unsigned int wait_ms) +{ +struct rtw_auth_sync *sync = &rtwdev->auth_sync; + +return wait_event_timeout (sync->wait,rtw8723bs_auth_sync_seen (rtwdev), +msecs_to_jiffies (wait_ms)) >0 ; +} + +static bool rtw8723bs_mgd_prepare_is_auth (struct rtw_dev *rtwdev, +struct ieee80211_prep_tx_info *info) +{ +return rtw_is_8723bs (rtwdev) && info && + info->subtype ==IEEE80211_STYPE_AUTH ; +} + +/* Replicate the vendor start_clnt_join() register programming right before +* auth. Returns true for a fresh join (BSSID changed). +*/ +static bool rtw8723bs_mgd_prepare_join (struct rtw_dev *rtwdev, +struct ieee80211_vif *vif, +const u8 *bssid) +{ +struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; +bool fresh_join; +u16 retry_limit; + +if (!is_valid_ether_addr (bssid)) +return false; + + fresh_join = !ether_addr_equal (rtwvif->bssid, bssid); + +ether_addr_copy (rtwvif->bssid, bssid); + rtwvif->aid =0 ; + rtwvif->net_type =RTW_NET_MGD_LINKED ; +rtw_vif_port_config (rtwdev, rtwvif, +PORT_SET_BSSID |PORT_SET_AID |PORT_SET_NET_TYPE ); + +/* Do not narrow RRSR or switch to short-preamble responses before the +* exchange: the whole auth/assoc runs on the init response set +* (0xffff1, long preamble). Only slot time is programmed early. +*/ +rtw8723bs_apply_bss_cap (rtwdev, vif, bssid, false); + +rtw_fw_beacon_filter_config (rtwdev, false, vif); + +/* Match the vendor start_clnt_join() TX state (set_msr directly, keep +* BCN_CTRL / BCNQ_DL set, reassert TBTT/RESP_SIFS every join). +*/ +rtw_write8 (rtwdev,REG_BCN_CTRL , +BIT_DIS_TSF_UDT |BIT_EN_BCN_FUNCTION ); +rtw_write32_set (rtwdev,REG_FWHW_TXQ_CTRL ,BIT_EN_BCNQ_DL ); +rtw_write8 (rtwdev,REG_TBTT_PROHIBIT +1 ,0x64 &0xff ); +rtw_write8 (rtwdev,REG_TBTT_PROHIBIT +2 , + (rtw_read8 (rtwdev,REG_TBTT_PROHIBIT +2 ) &0xf0 ) | (0x64 >>8 )); +rtw_write16 (rtwdev,REG_RESP_SIFS_CCK ,0x0808 ); +rtw_write16 (rtwdev,REG_RESP_SIFS_OFDM ,0x0a0a ); + +rtw_write16 (rtwdev,REG_RXFLTMAP0 ,0xffff ); +rtw_write16 (rtwdev,REG_RXFLTMAP2 ,0xffff ); +rtw8723bs_auth_rx_filter (rtwdev, true); + + retry_limit = (RTW8723BS_JOIN_RETRY_LIMIT <<8 ) | +RTW8723BS_JOIN_RETRY_LIMIT ; +rtw_write16 (rtwdev,REG_RETRY_LIMIT , retry_limit); + +rtw8723bs_config_sec_cfg (rtwdev); + +return fresh_join; +} + +/* The vendor sends a deauth to the target before auth to clear stale AP-side +* state; synthesize and TX one, then let the AP settle. +*/ +static void rtw8723bs_tx_pre_auth_deauth (struct rtw_dev *rtwdev, +struct ieee80211_vif *vif, +const u8 *bssid) +{ +struct ieee80211_tx_control control = {}; +struct ieee80211_tx_info *info; +struct ieee80211_mgmt *mgmt; +struct sk_buff *skb; +unsigned int frame_len, headroom; + + frame_len =sizeof (struct ieee80211_hdr_3addr ) +sizeof (mgmt->u.deauth); + headroom = rtwdev->chip->tx_pkt_desc_sz +8 ; + + skb =dev_alloc_skb (headroom + frame_len); +if (!skb) +return ; + +skb_reserve (skb, headroom); + mgmt =skb_put_zero (skb, frame_len); + mgmt->frame_control =cpu_to_le16 (IEEE80211_FTYPE_MGMT | +IEEE80211_STYPE_DEAUTH ); +memcpy (mgmt->da, bssid,ETH_ALEN ); +memcpy (mgmt->sa, vif->addr,ETH_ALEN ); +memcpy (mgmt->bssid, bssid,ETH_ALEN ); + mgmt->u.deauth.reason_code =cpu_to_le16 (WLAN_REASON_DEAUTH_LEAVING ); + + info =IEEE80211_SKB_CB (skb); +memset (info,0 ,sizeof (*info)); + info->control.vif = vif; + +rtw_tx (rtwdev, &control, skb); +msleep (100 ); +} + +/* Orchestrate the pre-auth join: program the vendor join state, send the +* pre-auth deauth, wait for a beacon from the target, then replay the +* pre-auth coex H2Cs - once per fresh BSSID. +*/ +static void rtw8723bs_mgd_prepare_auth_join (struct rtw_dev *rtwdev, +struct ieee80211_vif *vif, +struct ieee80211_prep_tx_info *info) +{ +struct rtw_vif *rtwvif; +const u8 *bssid =NULL ; +bool fresh_join; + +if (!rtw8723bs_mgd_prepare_is_auth (rtwdev, info) || !vif || +test_bit (RTW_FLAG_SCANNING , rtwdev->flags)) +return ; + + rtwvif = (struct rtw_vif *)vif->drv_priv; + +if (!is_zero_ether_addr (vif->cfg.ap_addr)) + bssid = vif->cfg.ap_addr; +else if (vif->bss_conf.bssid && !is_zero_ether_addr (vif->bss_conf.bssid)) + bssid = vif->bss_conf.bssid; + +if (!bssid) +return ; + + fresh_join =rtw8723bs_mgd_prepare_join (rtwdev, vif, bssid); + +if (fresh_join || !rtwvif->pre_auth_join_done) { +unsigned int wait_ms =rtw8723bs_auth_sync_wait_ms (vif); + +rtw8723bs_auth_sync_start (rtwdev, bssid); +rtw8723bs_tx_pre_auth_deauth (rtwdev, vif, bssid); +rtw8723bs_auth_sync_wait (rtwdev, wait_ms); +rtw8723bs_auth_sync_stop (rtwdev); + rtwvif->pre_auth_join_done = true; + } + +if (!rtwvif->pre_auth_h2c_sent) { +rtw_coex_8723bs_pre_auth_h2c (rtwdev); + rtwvif->pre_auth_h2c_sent = true; + } +} +static void rtw_ops_tx (struct ieee80211_hw *hw,struct ieee80211_tx_control *control,struct sk_buff *skb)
@@ -424,6 +850,13 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,if (changed &BSS_CHANGED_ASSOC ) {rtw_vif_assoc_changed (rtwvif, conf);if (vif->cfg.assoc) { +if (rtw_is_8723bs (rtwdev) && + vif->type ==NL80211_IFTYPE_STATION ) { +rtw8723bs_auth_rx_filter (rtwdev, false); +rtw8723bs_apply_basic_rates (rtwdev, vif,NULL ); +rtw8723bs_enable_tsf_update (rtwdev); + } +rtw_coex_connect_notify (rtwdev,COEX_ASSOCIATE_FINISH );rtw_fw_download_rsvd_page (rtwdev);
@@ -445,6 +878,13 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,if (test_bit (RTW_FLAG_SCANNING , rtwdev->flags))rtw_hw_scan_abort (rtwdev); +if (rtw_is_8723bs (rtwdev) && + vif->type ==NL80211_IFTYPE_STATION ) { +rtw8723bs_auth_rx_filter (rtwdev, false); +rtw8723bs_reset_response_rates (rtwdev); + rtwvif->pre_auth_h2c_sent = false; + rtwvif->pre_auth_join_done = false; + } } config |=PORT_SET_NET_TYPE ;
@@ -452,8 +892,26 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, }if (changed &BSS_CHANGED_BSSID ) { +bool bssid_cleared =is_zero_ether_addr (conf->bssid); +bool bssid_changed = !ether_addr_equal (rtwvif->bssid, + conf->bssid); + +if (rtw_is_8723bs (rtwdev) && + vif->type ==NL80211_IFTYPE_STATION && bssid_changed) { + rtwvif->pre_auth_h2c_sent = false; + rtwvif->pre_auth_join_done = false; + }ether_addr_copy (rtwvif->bssid, conf->bssid); config |=PORT_SET_BSSID ; +if (rtw_is_8723bs (rtwdev) && + vif->type ==NL80211_IFTYPE_STATION && bssid_cleared) { + rtwvif->aid =0 ; + rtwvif->net_type =RTW_NET_NO_LINK ; + config |=PORT_SET_NET_TYPE |PORT_SET_AID ; +rtw_write8 (rtwdev,REG_BCN_CTRL , +BIT_DIS_TSF_UDT |BIT_EN_BCN_FUNCTION | +BIT_DIS_ATIM ); + }if (!rtw_core_check_sta_active (rtwdev))rtw_clear_op_chan (rtwdev);else
@@ -485,8 +943,17 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,if (changed &BSS_CHANGED_MU_GROUPS )rtw_chip_set_gid_table (rtwdev, vif, conf); -if (changed &BSS_CHANGED_ERP_SLOT ) +if (changed &BSS_CHANGED_ERP_PREAMBLE && +rtw_is_8723bs (rtwdev) && + vif->type ==NL80211_IFTYPE_STATION ) +rtw8723bs_set_ack_preamble (rtwdev, conf->use_short_preamble); + +if (changed &BSS_CHANGED_ERP_SLOT ) { +if (rtw_is_8723bs (rtwdev) && + vif->type ==NL80211_IFTYPE_STATION ) +rtw8723bs_set_slot_time (rtwdev, conf->use_short_slot);rtw_conf_tx (rtwdev, rtwvif); + }if (changed &BSS_CHANGED_PS )rtw_recalc_lps (rtwdev,NULL );
@@ -646,11 +1113,19 @@ static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, key->hw_key_idx = hw_key_idx;rtw_sec_write_cam (rtwdev, sec, sta, key, hw_key_type, hw_key_idx); +if (rtw_is_8723bs (rtwdev) && vif && + vif->type ==NL80211_IFTYPE_STATION && + !(key->flags &IEEE80211_KEY_FLAG_PAIRWISE )) +rtw8723bs_config_default_key_search (rtwdev, true);break ;case DISABLE_KEY :rtw_hci_flush_all_queues (rtwdev, false);rtw_mac_flush_all_queues (rtwdev, false);rtw_sec_clear_cam (rtwdev, sec, key->hw_key_idx); +if (rtw_is_8723bs (rtwdev) && vif && + vif->type ==NL80211_IFTYPE_STATION && + !(key->flags &IEEE80211_KEY_FLAG_PAIRWISE )) +rtw8723bs_config_default_key_search (rtwdev, false);break ; }
@@ -740,8 +1215,23 @@ static void rtw_ops_mgd_prepare_tx(struct ieee80211_hw *hw,mutex_lock (&rtwdev->mutex);rtw_leave_lps_deep (rtwdev); -rtw_coex_connect_notify (rtwdev,COEX_ASSOCIATE_START ); -rtw_chip_prepare_tx (rtwdev); + +if (rtw_is_8723bs (rtwdev)) { +/* Wake from soft IPS and run the vendor join sequence. The RFK +* is handled by the once-only power-on IQK plus the ps.c +* post-IPS RF-bus recovery, not a fresh calibration here. +*/ +if (rtw_leave_ips (rtwdev)) { +rtw_err (rtwdev,"failed to leave idle state for mgd tx\n" ); + goto out; + } +rtw_coex_connect_notify (rtwdev,COEX_ASSOCIATE_START ); +rtw8723bs_mgd_prepare_auth_join (rtwdev, vif, info); + }else { +rtw_coex_connect_notify (rtwdev,COEX_ASSOCIATE_START ); +rtw_chip_prepare_tx (rtwdev); + } +out:mutex_unlock (&rtwdev->mutex); }
drivers/net/wireless/realtek/rtw88/main.h +2 -0
@@ -829,6 +829,8 @@ struct rtw_vif {u8 bssid[ETH_ALEN ];u8 port;u8 bcn_ctrl; +bool pre_auth_h2c_sent; +bool pre_auth_join_done;struct list_head rsvd_page_list;struct ieee80211_tx_queue_params tx_params[IEEE80211_NUM_ACS ];const struct rtw_vif_port *conf;
drivers/net/wireless/realtek/rtw88/reg.h +2 -0
@@ -479,6 +479,7 @@#define BIT_DIS_TSF_UDT BIT(4)#define BIT_EN_BCN_FUNCTION BIT(3)#define BIT_EN_TXBCN_RPT BIT(2) +#define BIT_DIS_ATIM BIT(0)#define REG_BCN_CTRL_CLINT0 0x0551#define REG_DRVERLYINT 0x0558#define REG_BCNDMATIM 0x0559
@@ -518,6 +519,7 @@#define BIT_UC_MD_EN BIT(16)#define BIT_RXSK_PERPKT BIT(15)#define BIT_HTC_LOC_CTRL BIT(14) +#define BIT_AMF BIT(13)#define BIT_RPFM_CAM_ENABLE BIT(12)#define BIT_TA_BCN BIT(11)#define BIT_RCR_ADF BIT(11)
drivers/net/wireless/realtek/rtw88/sec.h +1 -0
@@ -22,6 +22,7 @@#define RTW_SEC_RX_DEC_EN BIT(3)#define RTW_SEC_TX_BC_USE_DK BIT(6)#define RTW_SEC_RX_BC_USE_DK BIT(7) +#define RTW_SEC_CHK_KEYID BIT(8)#define RTW_SEC_ENGINE_EN BIT(9)
Signature · 1 line
2.55.0
Ping-Ke Shih
maintainerRE: [PATCH v2 11/11] wifi: rtw88: run the RTL8723BS association register sequence
Quoted 8 lines · [email protected] <[email protected]> wrote:
drivers/net/wireless/realtek/rtw88/mac80211.c +2
-2@@ -740,8 +1215,23 @@ static void rtw_ops_mgd_prepare_tx(struct ieee80211_hw *hw,mutex_lock (&rtwdev->mutex);rtw_leave_lps_deep (rtwdev); -rtw_coex_connect_notify (rtwdev,COEX_ASSOCIATE_START ); -rtw_chip_prepare_tx (rtwdev); + +if (rtw_is_8723bs (rtwdev)) {
drivers/net/wireless/realtek/rtw88/mac80211.c static void rtw_ops_mgd_prepare_tx(struct ieee80211_hw *hw, · line 1229
Quoted 10 lines
drivers/net/wireless/realtek/rtw88/mac80211.c +10
-0+/* Wake from soft IPS and run the vendor join sequence. The RFK +* is handled by the once-only power-on IQK plus the ps.c +* post-IPS RF-bus recovery, not a fresh calibration here. +*/ +if (rtw_leave_ips (rtwdev)) { +rtw_err (rtwdev,"failed to leave idle state for mgd tx\n" ); + goto out; + } +rtw_coex_connect_notify (rtwdev,COEX_ASSOCIATE_START ); +rtw8723bs_mgd_prepare_auth_join (rtwdev, vif, info);
I'm surprising that RTL8723BS needs so many special handing. Can you reduce them? At least, use rtw_chip_prepare_tx() to implement its specific functions.
Quoted 8 lines
drivers/net/wireless/realtek/rtw88/mac80211.c +5
-0+ }else { +rtw_coex_connect_notify (rtwdev,COEX_ASSOCIATE_START ); +rtw_chip_prepare_tx (rtwdev); + } +out:mutex_unlock (&rtwdev->mutex); }
Re: [PATCH v2 11/11] wifi: rtw88: run the RTL8723BS association register sequence
From: Luka Gejak <[email protected]>
Quoted 1 line · Ping-Ke Shih
Quoted 1 line
+ if (
rtw_is_8723bs(rtwdev)) {
[...]
Quoted 3 lines
I'm surprising that RTL8723BS needs so many special handing. Can you reduce them? At least, use
rtw_chip_prepare_tx()to implement its specific functions.
Done. v3 adds a chip_ops::prepare_tx callback, and rtw_ops_mgd_prepare_tx() is back to a single common path:
mutex_lock(&rtwdev->mutex); rtw_leave_lps_deep(rtwdev); rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_START); rtw_chip_prepare_tx(rtwdev, vif, info); mutex_unlock(&rtwdev->mutex);
rtw_chip_prepare_tx() calls the chip callback when one is set and otherwise keeps the existing deferred RF calibration, so no other chip changes behaviour. The RTL8723BS callback does the IPS wake and the join sequence, and the chip driver in the follow-up series points .prepare_tx at it. That also removes the chip test from the helper below it, per your comments on patch 05.
On reducing the rest: this patch is smaller in v3, but not as much as I would like, and I want to be straight about why. Two things went:
- the beacon wait, once you made me measure it (see my reply on patch 10), which took struct rtw_auth_sync with it
- two dead bool arguments, rtw8723bs_auth_rx_filter(accept_all) and rtw_coex_8723bs_restore_pad_ctrl(keep_pta_owner), both of which had a single value at every call site
What is left is the vendor start_clnt_join() register programming
itself: the BSSID-scoped receive filter, the response and basic rate set from the BSS rate elements, preamble and slot time, TSF update, the retry limit and the security config. I have removed these individually on hardware and association fails or the AP drops us shortly after, which is why they are still here rather than because I have not tried.
If the concern is that it sits in mac80211.c rather than a chip file, I agree, and I would rather move the whole rtw8723bs_* block into rtw8723b.c in the driver series than leave it in the common file. It is in mac80211.c today only because this series lands before the chip file exists. Tell me which you prefer and I will do it that way.
Best regards,
Luka Gejak
Ping-Ke Shih
maintainerRE: [PATCH v2 11/11] wifi: rtw88: run the RTL8723BS association register sequence
[email protected] <[email protected]> wrote;
Quoted 23 lines · Ping-Ke Shih
Quoted 1 line
Quoted 1 line
+ if (
rtw_is_8723bs(rtwdev)) {[...]
Quoted 3 lines
I'm surprising that RTL8723BS needs so many special handing. Can you reduce them? At least, use
rtw_chip_prepare_tx()to implement its specific functions.Done. v3 adds a
chip_ops::prepare_txcallback, andrtw_ops_mgd_prepare_tx()is back to a single common path:mutex_lock(&rtwdev->mutex); rtw_leave_lps_deep(rtwdev); rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_START); rtw_chip_prepare_tx(rtwdev, vif, info); mutex_unlock(&rtwdev->mutex);
rtw_chip_prepare_tx()calls the chip callback when one is set and otherwise keeps the existing deferred RF calibration, so no other chip changes behaviour. The RTL8723BS callback does the IPS wake and the join sequence, and the chip driver in the follow-up series points .prepare_tx at it. That also removes the chip test from the helper below it, per your comments on patch 05.
Quoted 5 lines
On reducing the rest: this patch is smaller in v3, but not as much as I would like, and I want to be straight about why. Two things went:
- the beacon wait, once you made me measure it (see my reply on patch 10), which took struct
rtw_auth_syncwith it
I see the result is positive, so this part can be removed, right?
Quoted 10 lines
- two dead bool arguments,
rtw8723bs_auth_rx_filter(accept_all)andrtw_coex_8723bs_restore_pad_ctrl(keep_pta_owner), both of which had a single value at every call siteWhat is left is the vendor
start_clnt_join()register programming
itself: the BSSID-scoped receive filter, the response and basic rate set from the BSS rate elements, preamble and slot time, TSF update, the retry limit and the security config. I have removed these individually on hardware and association fails or the AP drops us shortly after, which is why they are still here rather than because I have not tried.
I think you can implement these by chip->ops->mac_init(rtwdev);
Quoted 6 lines
If the concern is that it sits in
mac80211.crather than a chip file, I agree, and I would rather move the whole rtw8723bs_* block intortw8723b.cin the driver series than leave it in the common file. It is inmac80211.ctoday only because this series lands before the chip file exists. Tell me which you prefer and I will do it that way.
So the order of patches might be
1. add specific handlings for RTL8723BS for common flow
2. add RTL8723BS (but not enable right now)
3. add *very* specific handlings for RTL8723BS for common flow Here *very* means a lot of difference like you mentioned. But if without this part, the RTL8723BS still can work (not perfect), the step 4 can go ahead with step 2. Need your experiments to confirm.
4. enable RTL8723BS by Kconfig/Makefile
Ping-Ke
RE: [PATCH v2 11/11] wifi: rtw88: run the RTL8723BS association register sequence
Quoted 11 lines · Ping-Ke Shih
[email protected] <[email protected]> wrote;
Quoted 7 lines · Ping-Ke Shih
[...]
On reducing the rest: this patch is smaller in v3, but not as much as I would like, and I want to be straight about why. Two things went:- the beacon wait, once you made me measure it (see my reply on patch 10), which took struct
rtw_auth_syncwith itI see the result is positive, so this part can be removed, right?
Right, it is already gone in v3.
Quoted 8 lines
Quoted 6 lines
What is left is the vendor
start_clnt_join()register programming
itself: the BSSID-scoped receive filter, the response and basic rate set from the BSS rate elements, preamble and slot time, TSF update, the retry limit and the security config. I have removed these individually on hardware and association fails or the AP drops us shortly after, which is why they are still here rather than because I have not tried.I think you can implement these by
chip->ops->mac_init(rtwdev);
Before answering that I have to correct the sentence you are replying to. It is wrong.
I ran the experiment you asked for below, and the association register sequence is not needed at all. What I told you was bring-up era data that I repeated without re-measuring. That is the same mistake you caught with the beacon wait, and I should have re-tested before asserting it a second time.
Quoted 9 lines
So the order of patches might be
1. add specific handlings for RTL8723BS for common flow
2. add RTL8723BS (but not enable right now)
3. add *very* specific handlings for RTL8723BS for common flow Here *very* means a lot of difference like you mentioned. But if without this part, the RTL8723BS still can work (not perfect), the step 4 can go ahead with step 2. Need your experiments to confirm.
4. enable RTL8723BS by Kconfig/Makefile
Confirmed, and it is better than "not perfect": I measured no difference at all. Step 3 disappears.
I reverted the whole patch, 440 lines, which is the join sequence, the chip_ops::prepare_tx callback, the six sites in rtw_ops_bss_info_changed() and both sites in rtw_ops_set_key(). All testing is WPA2-PSK/CCMP against one AP.
with patch without scans seeing AP 23/24 18/18 associations 8/8 6/6 TCP up / down 21.8 / 38.9 18.6 / 39.0 Mbit/s UDP up / down 25.0 / 40.0 25.0 / 40.0, 0% loss both rtw88 errors 0 0
The uplink figures need a caveat, because the two columns were measured on different days and uplink on this band drifts by several Mbit/s from one day to the next, so 21.8 against 18.6 is not a comparison I can stand behind. I repeated it as a paired test instead: ten alternating cycles in a single session, rebuilding and reinstalling the driver each time, five with the full series and five with all four patches reverted, so both see the same air.
full series 19.0 Mbit/s mean over 10 runs, 18.7 to 19.4
four reverted 19.2 Mbit/s mean over 10 runs, 18.9 to 19.6
There is no uplink cost. Downlink was never lower without the patches either, 38.9 with against 39.0 and 42.9 without, so the wider spread in the tables above is the environment rather than the code.
Then a 5 minute stability run on the ablation: ping 1495/1495 at 0% loss, reconnects 15/15, link cycles 5/5, module reloads 3/3, scans under traffic 5/5, idle power save wake 0% loss, 24 rekeys completed, zero deauth, zero rqpn relatch, zero SDIO errors, no warnings, peak TX 150 Mbit/s.
The reconnects and the rekeys are the point: the join sequence ran from mgd_prepare_tx() on every authentication, so 15 reconnects exercise exactly the path it lived on.
Since that patch is what added the chip tests to mac80211.c, dropping it takes that file from 8 chip tests to 0, and three of your review points on the other mail become unnecessary rather than needing rework.
Your instinct was better than my evidence, so I applied it to the coexistence patches as well, whose justification came from the same period. Reverting those too, together with the GNT_BT command whose only caller they were:
scans 18/18, associations 6/6, TCP 18.0 up / 42.9 down, UDP 25.0 up and 40.0 down both at 0% loss, 0 errors. Same 5 minute soak, same
result: 15/15 reconnects, 5/5 scans under traffic, 3/3 reloads.
So the second correction: the commit message on the scan antenna workaround claims the site survey does not hear the AP reliably without it. That is also wrong. It scans 18/18 without it.
One thing worth stating precisely, because it looks like a gap and is not. Those two coex patches are gated
if (!rtw_is_8723bs(rtwdev) || !rtwdev->coex.stat.bt_disabled)
return false;so they only ever execute when bt_disabled is set, which was the case throughout. That is their entire scope, not a subset of it.
That leaves prep at six patches:
1 add the RTL8723B chip type and SDIO helper
2 rx: mark zero length packets on RTL8723BS
3 fw: fix the reserved page upload on RTL8723BS 4 sdio: track free TX pages and OQT credits for RTL8723BS 5 sdio: set up RX aggregation and interrupts for RTL8723BS 6 sdio: add TX back-pressure and retry on page starvation
and no chip tests left in mac80211.c or coex.c. What remains is one in rx.c, one in fw.c and eleven in sdio.c, all of which you have already said are fine inline.
With step 3 gone your ordering collapses to prep, then the chip driver, then Kconfig/Makefile, then MAINTAINERS. Would you rather have that as one series of nine patches, or keep the current split with prep sent first? I am happy either way; one series removes the "wait for prep to land" coordination.
One detail for the ordering: a few register defines currently sit in the patches being dropped but are used by rtw8723b.c, so they move into the chip support patch. BIT_AMF is used by its WLAN_RCR_CFG, and REG_PWR_DATA, BIT_EEPRPAD_RFE_CTRL_EN, REG_RFE_CTRL_ANT_SW, BIT_RFE_CTRL_ANT_SW_SEL, REG_RFE_CTRL_ANTA_SRC and BIT_BT_SEL_BY_WIFI_8723B by its own coexistence code.
REG_BB_SEL_BTG_8723B goes away entirely rather than moving. Its only users were the coex patches being dropped, and it duplicates REG_BB_SEL_BTG in rtw8723x.h at the same address, which is the one rtw8723b.c actually uses.
Best regards,
Luka Gejak
Ping-Ke Shih
maintainerRE: [PATCH v2 11/11] wifi: rtw88: run the RTL8723BS association register sequence
Luka Gejak <[email protected]> wrote:
(thanks for your above experiments)
Quoted 9 lines
That leaves prep at six patches:
1 add the RTL8723B chip type and SDIO helper
2 rx: mark zero length packets on RTL8723BS
3 fw: fix the reserved page upload on RTL8723BS 4 sdio: track free TX pages and OQT credits for RTL8723BS 5 sdio: set up RX aggregation and interrupts for RTL8723BS 6 sdio: add TX back-pressure and retry on page starvation
Answer your question below, smaller patchset is always better to me. :) Unless it is too small to understand whole picture.
Quoted 10 lines
and no chip tests left in
mac80211.corcoex.c. What remains is one inrx.c, one infw.cand eleven insdio.c, all of which you have already said are fine inline.With step 3 gone your ordering collapses to prep, then the chip driver, then Kconfig/Makefile, then
MAINTAINERS. Would you rather have that as one series of nine patches, or keep the current split with prep sent first? I am happy either way; one series removes the "wait for prep to land" coordination.
One thing I forgot to say is that the step 2 (add RTL8723BS) can be split into patches per file. Reviewing can be easier.
Quoted 4 lines
One detail for the ordering: a few register defines currently sit in the patches being dropped but are used by
rtw8723b.c, so they move into the chip support patch.
Yes. That is good to me.
Ping-Ke