From: Masi Osmani <mas-i@hotmail.de>
To: Christian Lamparter <chunkeey@googlemail.com>
Cc: linux-wireless@vger.kernel.org, Masi Osmani <mas-i@hotmail.de>
Subject: [PATCH 11/12] carl9170: skip cross-band channel changes during software scan
Date: Tue, 17 Mar 2026 10:10:44 +0100 [thread overview]
Message-ID: <AM7PPF5613FA0B64618E70AB9ECAA3B65FB9441A@AM7PPF5613FA0B6.EURP251.PROD.OUTLOOK.COM> (raw)
The carl9170 relies on mac80211 software scanning because it does not
implement a hw_scan callback. During a scan, mac80211 iterates all
supported channels across both bands, calling carl9170_op_config()
with IEEE80211_CONF_CHANGE_CHANNEL for each one.
Every channel change triggers a full baseband cold reset, RF bank
re-initialisation and AGC calibration via the firmware RF_INIT command
with a 200 ms timeout. Cross-band switches (2.4 GHz <-> 5 GHz) are
especially expensive and error-prone: the AGC calibration frequently
times out (firmware returns error code 2), leaving the PHY in a
degraded state. Subsequent channel changes -- even within the same
band -- then also fail, and after three consecutive failures the
driver restarts the device, causing a multi-second connectivity gap.
When the adapter is associated on a specific band, scanning channels
on the other band produces no useful roaming candidates for the
current BSS. Add sw_scan_start/sw_scan_complete callbacks to track
the scanning state and skip cross-band channel changes while a
software scan is in progress. Intentional cross-band association
changes (e.g. roaming from 2.4 GHz to 5 GHz on a dual-band SSID)
are not affected because they occur outside the scanning window.
Tested on Fritz\!WLAN N (AR9170) with 2.4 GHz association and
concurrent full-band scans: no channel change failures, no device
restarts, no PHY corruption.
Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
drivers/net/wireless/ath/carl9170/carl9170.h | 1 +
drivers/net/wireless/ath/carl9170/main.c | 42 +++++++++++++++++++
2 files changed, 43 insertions(+)
--- a/drivers/net/wireless/ath/carl9170/carl9170.h 2026-03-15 23:51:23.598565789 +0100
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h 2026-03-15 23:51:39.769123563 +0100
@@ -333,6 +333,7 @@ struct ar9170 {
/* PHY */
struct ieee80211_channel *channel;
unsigned int num_channels;
+ bool scanning;
int noise[4];
unsigned int chan_fail;
unsigned int total_chan_fail;
--- a/drivers/net/wireless/ath/carl9170/main.c 2026-03-15 23:51:23.597355728 +0100
+++ b/drivers/net/wireless/ath/carl9170/main.c 2026-03-15 23:52:02.845563524 +0100
@@ -916,6 +916,33 @@ static int carl9170_op_config(struct iee
enum nl80211_channel_type channel_type =
cfg80211_get_chandef_type(&hw->conf.chandef);
+ /*
+ * Skip cross-band channel changes during software scan.
+ *
+ * mac80211 sw_scan iterates all channels including the
+ * other band. Each channel change requires a full BB
+ * cold reset and AGC calibration via the firmware RF_INIT
+ * command (200 ms timeout). Cross-band switches
+ * frequently cause AGC calibration timeouts (firmware
+ * returns error 2), leaving the PHY in a degraded state
+ * that cascades into failures on subsequent intra-band
+ * channel changes and ultimately triggers a device
+ * restart after three consecutive failures.
+ *
+ * When associated, scanning the other band yields no
+ * useful roaming candidates for the current BSS. Skip
+ * the channel change so mac80211 advances to the next
+ * scan channel harmlessly.
+ */
+ if (ar->scanning && ar->channel &&
+ hw->conf.chandef.chan->band != ar->channel->band) {
+ wiphy_dbg(ar->hw->wiphy,
+ "skip cross-band scan: %d MHz -> %d MHz\n",
+ ar->channel->center_freq,
+ hw->conf.chandef.chan->center_freq);
+ goto out;
+ }
+
/* adjust slot time for 5 GHz */
err = carl9170_set_slot_time(ar);
if (err)
@@ -954,6 +981,27 @@ out:
return err;
}
+static void carl9170_op_sw_scan_start(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ const u8 *mac_addr)
+{
+ struct ar9170 *ar = hw->priv;
+
+ mutex_lock(&ar->mutex);
+ ar->scanning = true;
+ mutex_unlock(&ar->mutex);
+}
+
+static void carl9170_op_sw_scan_complete(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct ar9170 *ar = hw->priv;
+
+ mutex_lock(&ar->mutex);
+ ar->scanning = false;
+ mutex_unlock(&ar->mutex);
+}
+
static u64 carl9170_op_prepare_multicast(struct ieee80211_hw *hw,
struct netdev_hw_addr_list *mc_list)
{
@@ -1723,6 +1771,8 @@ static const struct ieee80211_ops carl91
.add_interface = carl9170_op_add_interface,
.remove_interface = carl9170_op_remove_interface,
.config = carl9170_op_config,
+ .sw_scan_start = carl9170_op_sw_scan_start,
+ .sw_scan_complete = carl9170_op_sw_scan_complete,
.prepare_multicast = carl9170_op_prepare_multicast,
.configure_filter = carl9170_op_configure_filter,
.conf_tx = carl9170_op_conf_tx,
next reply other threads:[~2026-03-17 9:10 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-17 9:10 Masi Osmani [this message]
-- strict thread matches above, loose matches on Subject: below --
2026-03-15 22:56 [PATCH 11/12] carl9170: skip cross-band channel changes during software scan Masi Osmani
2026-03-21 21:58 ` Christian Lamparter
2026-03-23 8:17 ` Johannes Berg
2026-03-23 8:21 ` Johannes Berg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=AM7PPF5613FA0B64618E70AB9ECAA3B65FB9441A@AM7PPF5613FA0B6.EURP251.PROD.OUTLOOK.COM \
--to=mas-i@hotmail.de \
--cc=chunkeey@googlemail.com \
--cc=linux-wireless@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox