* [PATCH 11/12] carl9170: skip cross-band channel changes during software scan
@ 2026-03-15 22:56 Masi Osmani
2026-03-21 21:58 ` Christian Lamparter
0 siblings, 1 reply; 5+ messages in thread
From: Masi Osmani @ 2026-03-15 22:56 UTC (permalink / raw)
To: chunkeey; +Cc: linux-wireless, Masi Osmani
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,
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 11/12] carl9170: skip cross-band channel changes during software scan
@ 2026-03-17 9:10 Masi Osmani
0 siblings, 0 replies; 5+ messages in thread
From: Masi Osmani @ 2026-03-17 9:10 UTC (permalink / raw)
To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani
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,
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 11/12] carl9170: skip cross-band channel changes during software scan
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
0 siblings, 1 reply; 5+ messages in thread
From: Christian Lamparter @ 2026-03-21 21:58 UTC (permalink / raw)
To: Masi Osmani; +Cc: linux-wireless, Johannes Berg
On 3/15/26 11:56 PM, Masi Osmani wrote:
> 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.
Dealing with hardware misbehaving... Yeah!
I always suspected that the reason for this misbehaving are clock glitches.
This is because the whole device gets reclocked when switching between 2.4GHz (44/88MHz)
and 5GHz (40/80MHz) band and also HT40 (88/80MHz) vs HT20/Legacy(40/44MHz) too).
I do see the point here and I can confirm that to this day, this causes the
described annoyances.
@Johannes: Is this "stay within the band" something the driver should do,
or could this be moved up to mac80211/cfg80211?
(The way I did it was with wpa_supplicant since it allows one to specifiy
the scanning frequencies with scan_freq ... or even limit the frequencies
with freq_list. That said, this doesn't work great with NetworkManager
and the likes)
>
> 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,
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 11/12] carl9170: skip cross-band channel changes during software scan
2026-03-21 21:58 ` Christian Lamparter
@ 2026-03-23 8:17 ` Johannes Berg
2026-03-23 8:21 ` Johannes Berg
0 siblings, 1 reply; 5+ messages in thread
From: Johannes Berg @ 2026-03-23 8:17 UTC (permalink / raw)
To: Christian Lamparter, Masi Osmani; +Cc: linux-wireless
On Sat, 2026-03-21 at 22:58 +0100, Christian Lamparter wrote:
> >
> > When the adapter is associated on a specific band, scanning channels
> > on the other band produces no useful roaming candidates for the
> > current BSS.
This sentence is so clearly wrong, I don't really even know what to say.
> @Johannes: Is this "stay within the band" something the driver should do,
> or could this be moved up to mac80211/cfg80211?
It's something neither should do.
johannes
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 11/12] carl9170: skip cross-band channel changes during software scan
2026-03-23 8:17 ` Johannes Berg
@ 2026-03-23 8:21 ` Johannes Berg
0 siblings, 0 replies; 5+ messages in thread
From: Johannes Berg @ 2026-03-23 8:21 UTC (permalink / raw)
To: Christian Lamparter, Masi Osmani; +Cc: linux-wireless
On Mon, 2026-03-23 at 09:17 +0100, Johannes Berg wrote:
> On Sat, 2026-03-21 at 22:58 +0100, Christian Lamparter wrote:
> > >
> > > When the adapter is associated on a specific band, scanning channels
> > > on the other band produces no useful roaming candidates for the
> > > current BSS.
>
> This sentence is so clearly wrong, I don't really even know what to say.
Well, actually ... I read "current BSS" as "current ESS" since otherwise
the sentence is true but nonsense, since roaming obviously involves
leaving the current BSS and joining a different BSS in the same ESS.
johannes
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-03-23 8:21 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
-- strict thread matches above, loose matches on Subject: below --
2026-03-17 9:10 Masi Osmani
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox