All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz
       [not found] <cover.1773277728.git.mas-i@hotmail.de>
@ 2026-03-12 10:37 ` Masi Osmani
  2026-03-21 18:41   ` Christian Lamparter
  2026-07-17 15:06   ` (subset) [PATCH 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz Jeff Johnson
  2026-03-12 10:37 ` [PATCH 02/10] carl9170: mac80211: advertise RX STBC capability Masi Osmani
                   ` (8 subsequent siblings)
  9 siblings, 2 replies; 33+ messages in thread
From: Masi Osmani @ 2026-03-12 10:37 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel

The AR9170 hardware supports Short Guard Interval (400ns) for both
20 MHz and 40 MHz channel widths.  SGI_40 was already advertised in
the HT capabilities, but SGI_20 was missing.  This reduces the OFDM
symbol duration from 800ns to 400ns on 20 MHz channels, increasing
the maximum PHY rate from 130 Mbps to 144.4 Mbps (MCS 15, 2SS).

ath9k (the PCI sibling for the same AR9xxx chipset family) has
always advertised both SGI_20 and SGI_40.

Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
 drivers/net/wireless/ath/carl9170/main.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index a7a9345..aa7e481 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -154,6 +154,7 @@ static struct ieee80211_channel carl9170_5ghz_chantable[] = {
 	.cap		= IEEE80211_HT_CAP_MAX_AMSDU |			\
 			  IEEE80211_HT_CAP_SUP_WIDTH_20_40 |		\
 			  IEEE80211_HT_CAP_SGI_40 |			\
+			  IEEE80211_HT_CAP_SGI_20 |			\
 			  IEEE80211_HT_CAP_DSSSCCK40 |			\
 			  IEEE80211_HT_CAP_SM_PS,			\
 	.ampdu_factor	= IEEE80211_HT_MAX_AMPDU_64K,			\
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 02/10] carl9170: mac80211: advertise RX STBC capability
       [not found] <cover.1773277728.git.mas-i@hotmail.de>
  2026-03-12 10:37 ` [PATCH 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz Masi Osmani
@ 2026-03-12 10:37 ` Masi Osmani
  2026-03-21 18:47   ` Christian Lamparter
  2026-03-12 10:37 ` [PATCH 03/10] carl9170: mac80211: document spatial multiplexing power save handler Masi Osmani
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 33+ messages in thread
From: Masi Osmani @ 2026-03-12 10:37 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel

The AR9170 baseband supports receiving Space-Time Block Coded
streams (1 spatial stream).  The capability was not advertised
in the HT capabilities, causing peers to never use STBC when
transmitting to us.  Enabling RX STBC improves receive diversity
gain and link reliability, especially in multipath environments.

The ath9k driver for the same chipset family advertises RX STBC
based on the number of RX chains.  With 2 RX chains, the AR9170
can decode 1 STBC spatial stream.

Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
 drivers/net/wireless/ath/carl9170/main.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index aa7e481..6324b38 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -156,7 +156,8 @@ static struct ieee80211_channel carl9170_5ghz_chantable[] = {
 			  IEEE80211_HT_CAP_SGI_40 |			\
 			  IEEE80211_HT_CAP_SGI_20 |			\
 			  IEEE80211_HT_CAP_DSSSCCK40 |			\
-			  IEEE80211_HT_CAP_SM_PS,			\
+			  IEEE80211_HT_CAP_SM_PS |			\
+			  (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT),	\
 	.ampdu_factor	= IEEE80211_HT_MAX_AMPDU_64K,			\
 	.ampdu_density	= IEEE80211_HT_MPDU_DENSITY_8,			\
 	.mcs		= {						\
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 03/10] carl9170: mac80211: document spatial multiplexing power save handler
       [not found] <cover.1773277728.git.mas-i@hotmail.de>
  2026-03-12 10:37 ` [PATCH 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz Masi Osmani
  2026-03-12 10:37 ` [PATCH 02/10] carl9170: mac80211: advertise RX STBC capability Masi Osmani
@ 2026-03-12 10:37 ` Masi Osmani
  2026-03-21 18:57   ` Christian Lamparter
  2026-03-12 10:37 ` [PATCH 04/10] carl9170: rx: wire up dropped frame counter Masi Osmani
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 33+ messages in thread
From: Masi Osmani @ 2026-03-12 10:37 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel

Replace the bare TODO comment in the SMPS configuration handler
with documentation explaining why the driver accepts but does not
act on SMPS mode changes.

The AR9170 advertises SM_PS disabled (both chains always active)
in its HT capabilities.  While mac80211 may still send SMPS
configuration requests, implementing static or dynamic SMPS would
require firmware support for per-chain enable/disable that the
AR9170 firmware (v1.9.9) does not provide.

Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
 drivers/net/wireless/ath/carl9170/main.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 6324b38..d75688c 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -910,7 +910,13 @@ static int carl9170_op_config(struct ieee80211_hw *hw, int radio_idx, u32 change
 	}
 
 	if (changed & IEEE80211_CONF_CHANGE_SMPS) {
-		/* TODO */
+		/*
+		 * We advertise SM_PS disabled (all chains active).
+		 * mac80211 may still request mode changes, which we
+		 * accept but only support OFF (both chains active).
+		 * Static/dynamic SMPS would require firmware support
+		 * for chain control that the AR9170 does not provide.
+		 */
 		err = 0;
 	}
 
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 04/10] carl9170: rx: wire up dropped frame counter
       [not found] <cover.1773277728.git.mas-i@hotmail.de>
                   ` (2 preceding siblings ...)
  2026-03-12 10:37 ` [PATCH 03/10] carl9170: mac80211: document spatial multiplexing power save handler Masi Osmani
@ 2026-03-12 10:37 ` Masi Osmani
  2026-03-21 19:03   ` Christian Lamparter
  2026-03-12 10:38 ` [PATCH 05/10] carl9170: rx: track PHY errors via debugfs Masi Osmani
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 33+ messages in thread
From: Masi Osmani @ 2026-03-12 10:37 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel

Increment ar->rx_dropped when frames with unrecognized error
codes are dropped in carl9170_rx_mac_status().  The counter
was already defined in the ar9170 struct and exported via
debugfs, but the actual increment was missing -- only a TODO
comment was in place.

This provides visibility into receive-path frame drops through
the existing debugfs interface.

Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
 drivers/net/wireless/ath/carl9170/rx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index 6833430..c664014 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -340,7 +340,7 @@ static int carl9170_rx_mac_status(struct ar9170 *ar,
 
 	/* drop any other error frames */
 	if (unlikely(error)) {
-		/* TODO: update netdevice's RX dropped/errors statistics */
+		ar->rx_dropped++;
 
 		if (net_ratelimit())
 			wiphy_dbg(ar->hw->wiphy, "received frame with "
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 05/10] carl9170: rx: track PHY errors via debugfs
       [not found] <cover.1773277728.git.mas-i@hotmail.de>
                   ` (3 preceding siblings ...)
  2026-03-12 10:37 ` [PATCH 04/10] carl9170: rx: wire up dropped frame counter Masi Osmani
@ 2026-03-12 10:38 ` Masi Osmani
  2026-03-21 20:29   ` Christian Lamparter
  2026-03-12 10:38 ` [PATCH 06/10] carl9170: phy: populate per-channel TX power from EEPROM Masi Osmani
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 33+ messages in thread
From: Masi Osmani @ 2026-03-12 10:38 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel

Count PHY errors reported by the hardware in the RX status and
expose the counter through debugfs as rx_phy_errors.  Previously,
PHY errors from ar9170_rx_phystatus were silently ignored (marked
with a TODO comment).

The counter helps diagnose RF environment issues (interference,
multipath, low SNR) without requiring monitor mode or additional
tooling.

Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
 drivers/net/wireless/ath/carl9170/carl9170.h | 1 +
 drivers/net/wireless/ath/carl9170/debug.c    | 2 ++
 drivers/net/wireless/ath/carl9170/rx.c       | 4 +++-
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index ba29b4a..eaac859 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -386,6 +386,7 @@ struct ar9170 {
 	unsigned int tx_ack_failures;
 	unsigned int tx_fcs_errors;
 	unsigned int rx_dropped;
+	unsigned int rx_phy_errors;
 
 	/* EEPROM */
 	struct ar9170_eeprom eeprom;
diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c
index 2d73456..0498df2 100644
--- a/drivers/net/wireless/ath/carl9170/debug.c
+++ b/drivers/net/wireless/ath/carl9170/debug.c
@@ -794,6 +794,7 @@ DEBUGFS_READONLY_FILE(tx_janitor_last_run, 64, "last run:%d ms ago",
 DEBUGFS_READONLY_FILE(tx_dropped, 20, "%d", ar->tx_dropped);
 
 DEBUGFS_READONLY_FILE(rx_dropped, 20, "%d", ar->rx_dropped);
+DEBUGFS_READONLY_FILE(rx_phy_errors, 20, "%d", ar->rx_phy_errors);
 
 DEBUGFS_READONLY_FILE(sniffer_enabled, 20, "%d", ar->sniffer_enabled);
 DEBUGFS_READONLY_FILE(rx_software_decryption, 20, "%d",
@@ -830,6 +831,7 @@ void carl9170_debugfs_register(struct ar9170 *ar)
 	DEBUGFS_ADD(tx_ampdu_list_len);
 
 	DEBUGFS_ADD(rx_dropped);
+	DEBUGFS_ADD(rx_phy_errors);
 	DEBUGFS_ADD(sniffer_enabled);
 	DEBUGFS_ADD(rx_software_decryption);
 
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index c664014..414d499 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -455,7 +455,9 @@ static void carl9170_rx_phy_status(struct ar9170 *ar,
 		if (phy->rssi[i] & 0x80)
 			phy->rssi[i] = ((~phy->rssi[i] & 0x7f) + 1) & 0x7f;
 
-	/* TODO: we could do something with phy_errors */
+	if (phy->phy_err)
+		ar->rx_phy_errors++;
+
 	status->signal = ar->noise[0] + phy->rssi_combined;
 }
 
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 06/10] carl9170: phy: populate per-channel TX power from EEPROM
       [not found] <cover.1773277728.git.mas-i@hotmail.de>
                   ` (4 preceding siblings ...)
  2026-03-12 10:38 ` [PATCH 05/10] carl9170: rx: track PHY errors via debugfs Masi Osmani
@ 2026-03-12 10:38 ` Masi Osmani
  2026-03-21 19:24   ` Christian Lamparter
  2026-03-12 10:38 ` [PATCH 07/10] carl9170: main: add exponential restart backoff Masi Osmani
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 33+ messages in thread
From: Masi Osmani @ 2026-03-12 10:38 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel

Replace the hardcoded max_power = 18 dBm (marked XXX) in the
channel definitions with actual per-channel values derived from
the EEPROM calibration target power tables.

The new carl9170_get_max_tgt_power() function interpolates the
maximum target power for a given frequency from the EEPROM's
legacy OFDM and CCK target power tables, using the same frequency
encoding and interpolation helpers already used by the power
calibration code.  carl9170_update_channel_maxpower() iterates
all registered channels and updates their max_power fields.

This is called during EEPROM parsing, so mac80211 and userspace
see correct per-channel power limits from the start.  The CHAN
macro default of 18 dBm remains as a safe fallback for channels
where EEPROM data is missing.

Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
 drivers/net/wireless/ath/carl9170/carl9170.h |  1 +
 drivers/net/wireless/ath/carl9170/main.c     |  4 +-
 drivers/net/wireless/ath/carl9170/phy.c      | 88 ++++++++++++++++++++
 3 files changed, 92 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index eaac859..a2ffa62 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -602,6 +602,7 @@ int carl9170_led_set_state(struct ar9170 *ar, const u32 led_state);
 int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
 			 enum nl80211_channel_type bw);
 int carl9170_get_noisefloor(struct ar9170 *ar);
+void carl9170_update_channel_maxpower(struct ar9170 *ar);
 
 /* FW */
 int carl9170_parse_firmware(struct ar9170 *ar);
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index d75688c..dcedcb1 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -89,7 +89,7 @@ struct ieee80211_rate __carl9170_ratetable[] = {
 #define CHAN(_freq, _idx) {		\
 	.center_freq	= (_freq),	\
 	.hw_value	= (_idx),	\
-	.max_power	= 18, /* XXX */	\
+	.max_power	= 18,		\
 }
 
 static struct ieee80211_channel carl9170_2ghz_chantable[] = {
@@ -1930,6 +1930,8 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
 	if (!bands)
 		return -EINVAL;
 
+	carl9170_update_channel_maxpower(ar);
+
 	ar->survey = devm_kcalloc(&ar->udev->dev, chans,
 				  sizeof(struct survey_info), GFP_KERNEL);
 	if (!ar->survey)
diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
index 34d9fd7..290c336 100644
--- a/drivers/net/wireless/ath/carl9170/phy.c
+++ b/drivers/net/wireless/ath/carl9170/phy.c
@@ -1524,6 +1524,94 @@ static void carl9170_set_power_cal(struct ar9170 *ar, u32 freq,
 	carl9170_calc_ctl(ar, freq, bw);
 }
 
+static u8 carl9170_get_max_tgt_power(struct ar9170 *ar, u32 freq)
+{
+	struct ar9170_calibration_target_power_legacy *ctpl;
+	int ntargets, idx, n, i;
+	u8 f, max_power = 0;
+	u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS];
+
+	if (freq < 3000)
+		f = freq - 2300;
+	else
+		f = (freq - 4800) / 5;
+
+	/* check legacy target powers (OFDM for 2G, 5G leg) */
+	for (i = 0; i < 2; i++) {
+		switch (i) {
+		case 0:
+			if (freq >= 3000) {
+				ctpl = &ar->eeprom.cal_tgt_pwr_5G[0];
+				ntargets = AR5416_NUM_5G_TARGET_PWRS;
+			} else {
+				ctpl = &ar->eeprom.cal_tgt_pwr_2G_ofdm[0];
+				ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS;
+			}
+			break;
+		case 1:
+			if (freq < 3000) {
+				ctpl = &ar->eeprom.cal_tgt_pwr_2G_cck[0];
+				ntargets = AR5416_NUM_2G_CCK_TARGET_PWRS;
+			} else {
+				continue;
+			}
+			break;
+		default:
+			continue;
+		}
+
+		for (n = 0; n < ntargets; n++) {
+			if (ctpl[n].freq == 0xff)
+				break;
+			pwr_freqs[n] = ctpl[n].freq;
+		}
+		ntargets = n;
+		if (ntargets < 2)
+			continue;
+
+		idx = carl9170_find_freq_idx(ntargets, pwr_freqs, f);
+		for (n = 0; n < 4; n++) {
+			u8 pwr;
+
+			pwr = carl9170_interpolate_u8(f,
+						     ctpl[idx + 0].freq,
+						     ctpl[idx + 0].power[n],
+						     ctpl[idx + 1].freq,
+						     ctpl[idx + 1].power[n]);
+			max_power = max(max_power, pwr);
+		}
+	}
+
+	/* target power is in half-dBm, max_power is in dBm */
+	return max_power / 2;
+}
+
+void carl9170_update_channel_maxpower(struct ar9170 *ar)
+{
+	struct ieee80211_supported_band *band;
+	int i;
+
+	band = ar->hw->wiphy->bands[NL80211_BAND_2GHZ];
+	if (band) {
+		for (i = 0; i < band->n_channels; i++) {
+			u8 pwr = carl9170_get_max_tgt_power(ar,
+				band->channels[i].center_freq);
+			if (pwr)
+				band->channels[i].max_power = pwr;
+		}
+	}
+
+	band = ar->hw->wiphy->bands[NL80211_BAND_5GHZ];
+	if (band) {
+		for (i = 0; i < band->n_channels; i++) {
+			u8 pwr = carl9170_get_max_tgt_power(ar,
+				band->channels[i].center_freq);
+			if (pwr)
+				band->channels[i].max_power = pwr;
+		}
+	}
+}
+
 int carl9170_get_noisefloor(struct ar9170 *ar)
 {
 	static const u32 phy_regs[] = {
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 07/10] carl9170: main: add exponential restart backoff
       [not found] <cover.1773277728.git.mas-i@hotmail.de>
                   ` (5 preceding siblings ...)
  2026-03-12 10:38 ` [PATCH 06/10] carl9170: phy: populate per-channel TX power from EEPROM Masi Osmani
@ 2026-03-12 10:38 ` Masi Osmani
  2026-03-21 20:42   ` Christian Lamparter
  2026-03-12 10:38 ` [PATCH 08/10] carl9170: phy: enable antenna diversity for 2-chain devices Masi Osmani
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 33+ messages in thread
From: Masi Osmani @ 2026-03-12 10:38 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel

When the AR9170 enters a bad state (firmware errors, command
timeouts, TX queue stalls), the driver can trigger rapid-fire
restarts that prevent the device from ever stabilizing.

Add exponential backoff to carl9170_restart(): if a restart
request arrives before the current backoff window has elapsed,
the request is throttled.  The backoff starts at 500 ms and
doubles on each restart, capping at 30 seconds.  A successful
restart resets the backoff to zero.

Additionally, use named constants for the firmware error
threshold (CARL9170_FW_ERROR_THRESHOLD) instead of a magic
number, and add a window-based counting approach to avoid
accumulating sporadic errors over long uptimes.

Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
 drivers/net/wireless/ath/carl9170/carl9170.h |  2 ++
 drivers/net/wireless/ath/carl9170/main.c     | 27 ++++++++++++++++++++
 drivers/net/wireless/ath/carl9170/rx.c       | 10 +++++++-
 3 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index a2ffa62..2eedb2f 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -301,6 +301,8 @@ struct ar9170 {
 	bool needs_full_reset;
 	bool force_usb_reset;
 	atomic_t pending_restarts;
+	unsigned long last_restart_jiffies;
+	unsigned int restart_backoff_ms;
 
 	/* interface mode settings */
 	struct list_head vif_list;
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index dcedcb1..ebf9fa9 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -492,6 +492,7 @@ static void carl9170_restart_work(struct work_struct *work)
 	if (!err && !ar->force_usb_reset) {
 		ar->restart_counter++;
 		atomic_set(&ar->pending_restarts, 0);
+		ar->restart_backoff_ms = 0;
 
 		ieee80211_restart_hw(ar->hw);
 	} else {
@@ -505,6 +506,9 @@ static void carl9170_restart_work(struct work_struct *work)
 	}
 }
 
+#define CARL9170_RESTART_BACKOFF_INIT_MS	500
+#define CARL9170_RESTART_BACKOFF_MAX_MS		30000
+
 void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r)
 {
 	carl9170_set_state_when(ar, CARL9170_STARTED, CARL9170_IDLE);
@@ -519,6 +523,29 @@ void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r)
 		return;
 	}
 
+	/*
+	 * Exponential backoff: if restarts are happening too frequently,
+	 * increase the delay before accepting the next one.  This prevents
+	 * restart storms when the device is in a bad state.
+	 */
+	if (ar->last_restart_jiffies &&
+	    time_before(jiffies, ar->last_restart_jiffies +
+			msecs_to_jiffies(ar->restart_backoff_ms))) {
+		dev_warn(&ar->udev->dev,
+			 "restart (%d) throttled (backoff %u ms)\n",
+			 r, ar->restart_backoff_ms);
+		atomic_dec(&ar->pending_restarts);
+		return;
+	}
+
+	ar->last_restart_jiffies = jiffies;
+	if (ar->restart_backoff_ms == 0)
+		ar->restart_backoff_ms = CARL9170_RESTART_BACKOFF_INIT_MS;
+	else
+		ar->restart_backoff_ms = min(ar->restart_backoff_ms * 2,
+					     (unsigned int)
+					     CARL9170_RESTART_BACKOFF_MAX_MS);
+
 	ieee80211_stop_queues(ar->hw);
 
 	dev_err(&ar->udev->dev, "restart device (%d)\n", r);
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index 414d499..bb909b5 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -46,6 +46,14 @@
 #include "hw.h"
 #include "cmd.h"
 
+/*
+ * Time window for firmware error counting.  Sporadic errors are
+ * normal over long uptimes; only a burst of errors within a short
+ * window warrants a restart.
+ */
+#define CARL9170_FW_ERROR_WINDOW_MS	10000
+#define CARL9170_FW_ERROR_THRESHOLD	3
+
 static void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len)
 {
 	bool restart = false;
@@ -54,7 +62,7 @@ static void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len)
 	if (len > 3) {
 		if (memcmp(buf, CARL9170_ERR_MAGIC, 3) == 0) {
 			ar->fw.err_counter++;
-			if (ar->fw.err_counter > 3) {
+			if (ar->fw.err_counter >= CARL9170_FW_ERROR_THRESHOLD) {
 				restart = true;
 				reason = CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS;
 			}
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 08/10] carl9170: phy: enable antenna diversity for 2-chain devices
       [not found] <cover.1773277728.git.mas-i@hotmail.de>
                   ` (6 preceding siblings ...)
  2026-03-12 10:38 ` [PATCH 07/10] carl9170: main: add exponential restart backoff Masi Osmani
@ 2026-03-12 10:38 ` Masi Osmani
  2026-03-21 19:53   ` Christian Lamparter
  2026-03-12 10:38 ` [PATCH 09/10] carl9170: fw: enable DFS radar detection Masi Osmani
  2026-03-12 10:38 ` [PATCH 10/10] carl9170: phy: add periodic runtime IQ calibration Masi Osmani
  9 siblings, 1 reply; 33+ messages in thread
From: Masi Osmani @ 2026-03-12 10:38 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel

Enable fast antenna diversity on devices with two RX chains
(rx_mask == 3).  This programs the MULTICHAIN_GAIN_CTL register
to configure main/alternate LNA settings and enables the
CCK fast antenna diversity bit.

The AR9170 hardware has antenna diversity registers inherited
from the AR9285/AR9287 family, but the carl9170 driver never
programmed them.  For dual-chain devices this improves receive
performance in multipath environments by allowing the baseband
to quickly switch between antenna paths.

The diversity configuration mirrors what ath9k uses for the
AR9285 single-chip design:
- Main LNA: LNA1
- Alt LNA: LNA1+LNA2 (combined)
- Gain table: table 0 for both paths

Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
 drivers/net/wireless/ath/carl9170/phy.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
index 290c336..bcd9066 100644
--- a/drivers/net/wireless/ath/carl9170/phy.c
+++ b/drivers/net/wireless/ath/carl9170/phy.c
@@ -536,6 +536,31 @@ static int carl9170_init_phy_from_eeprom(struct ar9170 *ar,
 	carl9170_regwrite(AR9170_PHY_REG_RX_CHAINMASK, ar->eeprom.rx_mask);
 	carl9170_regwrite(AR9170_PHY_REG_CAL_CHAINMASK, ar->eeprom.rx_mask);
 
+	/*
+	 * Enable fast antenna diversity for 2-chain devices.
+	 * Configure main/alt LNA with both chains for best
+	 * multipath performance.
+	 */
+	if (ar->eeprom.rx_mask == 3) {
+		val = carl9170_def_val(AR9170_PHY_REG_MULTICHAIN_GAIN_CTL,
+				       is_2ghz, is_40mhz);
+		val |= AR9170_PHY_9285_ANT_DIV_CTL;
+		SET_VAL(AR9170_PHY_9285_ANT_DIV_ALT_LNACONF, val,
+			AR9170_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2);
+		SET_VAL(AR9170_PHY_9285_ANT_DIV_MAIN_LNACONF, val,
+			AR9170_PHY_9285_ANT_DIV_LNA1);
+		SET_VAL(AR9170_PHY_9285_ANT_DIV_ALT_GAINTB, val,
+			AR9170_PHY_9285_ANT_DIV_GAINTB_0);
+		SET_VAL(AR9170_PHY_9285_ANT_DIV_MAIN_GAINTB, val,
+			AR9170_PHY_9285_ANT_DIV_GAINTB_0);
+		carl9170_regwrite(AR9170_PHY_REG_MULTICHAIN_GAIN_CTL, val);
+
+		val = carl9170_def_val(AR9170_PHY_REG_CCK_DETECT,
+				       is_2ghz, is_40mhz);
+		val |= AR9170_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+		carl9170_regwrite(AR9170_PHY_REG_CCK_DETECT, val);
+	}
+
 	carl9170_regwrite_finish();
 	return carl9170_regwrite_result();
 }
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 09/10] carl9170: fw: enable DFS radar detection
       [not found] <cover.1773277728.git.mas-i@hotmail.de>
                   ` (7 preceding siblings ...)
  2026-03-12 10:38 ` [PATCH 08/10] carl9170: phy: enable antenna diversity for 2-chain devices Masi Osmani
@ 2026-03-12 10:38 ` Masi Osmani
  2026-03-21 20:11   ` Christian Lamparter
  2026-04-29  4:46   ` John Scott
  2026-03-12 10:38 ` [PATCH 10/10] carl9170: phy: add periodic runtime IQ calibration Masi Osmani
  9 siblings, 2 replies; 33+ messages in thread
From: Masi Osmani @ 2026-03-12 10:38 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel

Enable DFS (Dynamic Frequency Selection) radar detection on the
AR9170.  The hardware has radar detection registers (RADAR_0,
RADAR_1, RADAR_EXT) and the firmware already sends
CARL9170_RSP_RADAR events, but the driver never programmed the
detection parameters and only logged a "please report" message.

Changes:
- Program radar detection pulse parameters in phy.c when the
  current channel has IEEE80211_CHAN_RADAR set.  Values are
  based on ath9k defaults for FCC/ETSI compliance.
- Advertise radar_detect_widths in the interface combination
  (fw.c) for 20 MHz noHT, 20 MHz HT, and 40 MHz HT.
- Replace the old "please report" message with a call to
  ieee80211_radar_detected() so mac80211 can trigger the
  proper DFS state machine (channel switch / CAC).

Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
 drivers/net/wireless/ath/carl9170/fw.c  |  3 ++
 drivers/net/wireless/ath/carl9170/phy.c | 45 +++++++++++++++++++++++++
 drivers/net/wireless/ath/carl9170/rx.c  |  7 ++--
 3 files changed, 50 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c
index 419f553..a730593 100644
--- a/drivers/net/wireless/ath/carl9170/fw.c
+++ b/drivers/net/wireless/ath/carl9170/fw.c
@@ -215,6 +215,9 @@ static void carl9170_fw_set_if_combinations(struct ar9170 *ar,
 	ar->if_combs[0].max_interfaces = ar->fw.vif_num;
 	ar->if_combs[0].limits = ar->if_comb_limits;
 	ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits);
+	ar->if_combs[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+					      BIT(NL80211_CHAN_WIDTH_20) |
+					      BIT(NL80211_CHAN_WIDTH_40);
 
 	ar->hw->wiphy->iface_combinations = ar->if_combs;
 	ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs);
diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
index bcd9066..c294df7 100644
--- a/drivers/net/wireless/ath/carl9170/phy.c
+++ b/drivers/net/wireless/ath/carl9170/phy.c
@@ -1637,6 +1637,47 @@ void carl9170_update_channel_maxpower(struct ar9170 *ar)
 	}
 }
 
+static int carl9170_set_radar_detection(struct ar9170 *ar,
+					struct ieee80211_channel *channel)
+{
+	bool enable = channel->flags & IEEE80211_CHAN_RADAR;
+
+	carl9170_regwrite_begin(ar);
+
+	if (enable) {
+		/*
+		 * Configure radar detection pulse parameters.
+		 * Values based on ath9k's defaults for FCC/ETSI.
+		 */
+		carl9170_regwrite(AR9170_PHY_REG_RADAR_0,
+				  AR9170_PHY_RADAR_0_ENA |
+				  AR9170_PHY_RADAR_0_FFT_ENA |
+				  SET_CONSTVAL(AR9170_PHY_RADAR_0_INBAND, 5) |
+				  SET_CONSTVAL(AR9170_PHY_RADAR_0_PRSSI, 1) |
+				  SET_CONSTVAL(AR9170_PHY_RADAR_0_HEIGHT, 6) |
+				  SET_CONSTVAL(AR9170_PHY_RADAR_0_RRSSI, 12) |
+				  SET_CONSTVAL(AR9170_PHY_RADAR_0_FIRPWR, 33));
+
+		carl9170_regwrite(AR9170_PHY_REG_RADAR_1,
+				  AR9170_PHY_RADAR_1_MAX_RRSSI |
+				  AR9170_PHY_RADAR_1_BLOCK_CHECK |
+				  AR9170_PHY_RADAR_1_RELSTEP_CHECK |
+				  SET_CONSTVAL(AR9170_PHY_RADAR_1_RELSTEP_THRESH, 8) |
+				  SET_CONSTVAL(AR9170_PHY_RADAR_1_RELPWR_THRESH, 12) |
+				  SET_CONSTVAL(AR9170_PHY_RADAR_1_MAXLEN, 255));
+
+		carl9170_regwrite(AR9170_PHY_REG_RADAR_EXT,
+				  AR9170_PHY_RADAR_EXT_ENA);
+	} else {
+		carl9170_regwrite(AR9170_PHY_REG_RADAR_0, 0);
+		carl9170_regwrite(AR9170_PHY_REG_RADAR_1, 0);
+		carl9170_regwrite(AR9170_PHY_REG_RADAR_EXT, 0);
+	}
+
+	carl9170_regwrite_finish();
+	return carl9170_regwrite_result();
+}
+
 int carl9170_get_noisefloor(struct ar9170 *ar)
 {
 	static const u32 phy_regs[] = {
@@ -1739,6 +1780,10 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
 	if (err)
 		return err;
 
+	err = carl9170_set_radar_detection(ar, channel);
+	if (err)
+		return err;
+
 	tmp = AR9170_PHY_TURBO_FC_SINGLE_HT_LTF1 |
 	      AR9170_PHY_TURBO_FC_HT_EN;
 
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index bb909b5..1fe727c 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -259,11 +259,8 @@ void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
 		break;
 
 	case CARL9170_RSP_RADAR:
-		if (!net_ratelimit())
-			break;
-
-		wiphy_info(ar->hw->wiphy, "FW: RADAR! Please report this "
-		       "incident to linux-wireless@vger.kernel.org !\n");
+		wiphy_info(ar->hw->wiphy, "FW: radar pulse detected\n");
+		ieee80211_radar_detected(ar->hw, NULL);
 		break;
 
 	case CARL9170_RSP_GPIO:
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 10/10] carl9170: phy: add periodic runtime IQ calibration
       [not found] <cover.1773277728.git.mas-i@hotmail.de>
                   ` (8 preceding siblings ...)
  2026-03-12 10:38 ` [PATCH 09/10] carl9170: fw: enable DFS radar detection Masi Osmani
@ 2026-03-12 10:38 ` Masi Osmani
  2026-03-21 21:25   ` Christian Lamparter
  9 siblings, 1 reply; 33+ messages in thread
From: Masi Osmani @ 2026-03-12 10:38 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, Masi Osmani, ath9k-devel

Add periodic runtime I/Q calibration triggered from the existing
survey statistics work handler (carl9170_stat_work).  The AR9170
hardware performs initial IQ calibration during channel setup, but
I/Q imbalance drifts with temperature over time, degrading EVM
and increasing packet error rate.

The new carl9170_run_iq_calibration() function sets the DO_IQCAL
bit in PHY_TIMING_CTRL4 for both chains, which triggers the
hardware to re-measure I/Q imbalance and update the correction
coefficients automatically.  This is a non-blocking operation --
the hardware runs the calibration in the background without
interrupting normal traffic.

The ath9k driver performs similar periodic calibration via its
longcal timer (every 30s).  carl9170_stat_work runs at a
comparable interval, making it a natural trigger point.

Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
 drivers/net/wireless/ath/carl9170/carl9170.h |  1 +
 drivers/net/wireless/ath/carl9170/main.c     |  2 ++
 drivers/net/wireless/ath/carl9170/phy.c      | 36 ++++++++++++++++++++
 3 files changed, 39 insertions(+)

diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index 2eedb2f..0175f8e 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -605,6 +605,7 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
 			 enum nl80211_channel_type bw);
 int carl9170_get_noisefloor(struct ar9170 *ar);
 void carl9170_update_channel_maxpower(struct ar9170 *ar);
+int carl9170_run_iq_calibration(struct ar9170 *ar);
 
 /* FW */
 int carl9170_parse_firmware(struct ar9170 *ar);
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index ebf9fa9..50c0922 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -910,6 +910,8 @@ static void carl9170_stat_work(struct work_struct *work)
 
 	mutex_lock(&ar->mutex);
 	err = carl9170_update_survey(ar, false, true);
+	if (!err)
+		carl9170_run_iq_calibration(ar);
 	mutex_unlock(&ar->mutex);
 
 	if (err)
diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
index c294df7..b145e9e 100644
--- a/drivers/net/wireless/ath/carl9170/phy.c
+++ b/drivers/net/wireless/ath/carl9170/phy.c
@@ -1637,6 +1637,42 @@ void carl9170_update_channel_maxpower(struct ar9170 *ar)
 	}
 }
 
+int carl9170_run_iq_calibration(struct ar9170 *ar)
+{
+	u32 val;
+	int err;
+
+	if (!ar->channel)
+		return 0;
+
+	/*
+	 * Trigger runtime IQ calibration.  The hardware measures
+	 * I/Q imbalance and updates the correction coefficients
+	 * automatically when DO_IQCAL is set.  We trigger on both
+	 * chains and re-enable the IQ correction afterwards.
+	 */
+	err = carl9170_read_reg(ar, AR9170_PHY_REG_TIMING_CTRL4(0), &val);
+	if (err)
+		return err;
+
+	val |= AR9170_PHY_TIMING_CTRL4_DO_IQCAL;
+	err = carl9170_write_reg(ar, AR9170_PHY_REG_TIMING_CTRL4(0), val);
+	if (err)
+		return err;
+
+	/* chain 2 */
+	err = carl9170_read_reg(ar, AR9170_PHY_REG_TIMING_CTRL4(2), &val);
+	if (err)
+		return err;
+
+	val |= AR9170_PHY_TIMING_CTRL4_DO_IQCAL;
+	err = carl9170_write_reg(ar, AR9170_PHY_REG_TIMING_CTRL4(2), val);
+	if (err)
+		return err;
+
+	return 0;
+}
+
 static int carl9170_set_radar_detection(struct ar9170 *ar,
 					struct ieee80211_channel *channel)
 {
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [PATCH 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz
  2026-03-12 10:37 ` [PATCH 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz Masi Osmani
@ 2026-03-21 18:41   ` Christian Lamparter
  2026-03-31 19:06     ` Masi Osmani
  2026-03-31 19:19     ` [PATCH v2 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz (experimental) Masi Osmani
  2026-07-17 15:06   ` (subset) [PATCH 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz Jeff Johnson
  1 sibling, 2 replies; 33+ messages in thread
From: Christian Lamparter @ 2026-03-21 18:41 UTC (permalink / raw)
  To: Masi Osmani; +Cc: linux-wireless, ath9k-devel

On 3/12/26 11:37 AM, Masi Osmani wrote:
> The AR9170 hardware supports Short Guard Interval (400ns) for both
> 20 MHz and 40 MHz channel widths.  SGI_40 was already advertised in
> the HT capabilities, but SGI_20 was missing.  This reduces the OFDM
> symbol duration from 800ns to 400ns on 20 MHz channels, increasing
> the maximum PHY rate from 130 Mbps to 144.4 Mbps (MCS 15, 2SS).
> 
> ath9k (the PCI sibling for the same AR9xxx chipset family) has
> always advertised both SGI_20 and SGI_40.
> 

Are you really, really sure about that?

Because based on what's in ath9k:
<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/wireless/ath/ath9k/hw.c?h=v7.0-rc4#n2622>

|        if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah))
|                pCap->hw_caps |= ATH9K_HW_CAP_SGI_20;

Whereas AR_SREV_9287_11_OR_LATER and AR_SREV_9271 are defined in reg.h @
<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/wireless/ath/ath9k/reg.h?h=v7.0-rc4#n861>

|#define AR_SREV_9287_11_OR_LATER(_ah) \
|        (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9287))
| [...]
|#define AR_SREV_9271(_ah) \
|    (((_ah))->hw_version.macVersion == AR_SREV_VERSION_9271)

What's strange here is that this isn't a PHY check, but MAC check...
And the AR9170 uses a modified ZyDAS MAC which is completely different
than what any of the ath9k siblings uses.

So based on that: No. I can't ACK that. The feature might work or not,
but that commit message is wrong.

That said, if you say have been successfully been using this and rewrite the
commit message to not include wrong information and add a module_parameter
like experimental that enables it, this would be OK!

Cheers,
Christian


> Signed-off-by: Masi Osmani <mas-i@hotmail.de>
> ---
>   drivers/net/wireless/ath/carl9170/main.c | 1 +
>   1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
> index a7a9345..aa7e481 100644
> --- a/drivers/net/wireless/ath/carl9170/main.c
> +++ b/drivers/net/wireless/ath/carl9170/main.c
> @@ -154,6 +154,7 @@ static struct ieee80211_channel carl9170_5ghz_chantable[] = {
>   	.cap		= IEEE80211_HT_CAP_MAX_AMSDU |			\
>   			  IEEE80211_HT_CAP_SUP_WIDTH_20_40 |		\
>   			  IEEE80211_HT_CAP_SGI_40 |			\
> +			  IEEE80211_HT_CAP_SGI_20 |			\
>   			  IEEE80211_HT_CAP_DSSSCCK40 |			\
>   			  IEEE80211_HT_CAP_SM_PS,			\
>   	.ampdu_factor	= IEEE80211_HT_MAX_AMPDU_64K,			\


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 02/10] carl9170: mac80211: advertise RX STBC capability
  2026-03-12 10:37 ` [PATCH 02/10] carl9170: mac80211: advertise RX STBC capability Masi Osmani
@ 2026-03-21 18:47   ` Christian Lamparter
  2026-03-31 19:06     ` Masi Osmani
  0 siblings, 1 reply; 33+ messages in thread
From: Christian Lamparter @ 2026-03-21 18:47 UTC (permalink / raw)
  To: Masi Osmani, Christian Lamparter; +Cc: linux-wireless, ath9k-devel

On 3/12/26 11:37 AM, Masi Osmani wrote:
> The AR9170 baseband supports receiving Space-Time Block Coded
> streams (1 spatial stream).  The capability was not advertised
> in the HT capabilities, causing peers to never use STBC when
> transmitting to us.  Enabling RX STBC improves receive diversity
> gain and link reliability, especially in multipath environments.
> 
> The ath9k driver for the same chipset family advertises RX STBC
> based on the number of RX chains.  With 2 RX chains, the AR9170
> can decode 1 STBC spatial stream.


No, not that I can tell.

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/wireless/ath/ath9k/common-init.c?h=v7.0-rc4#n204

|        if (AR_SREV_9280_20_OR_LATER(ah)) {
|                if (max_streams >= 2)
|                        ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
|                ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
|        }

the ath9k driver supports this for generation after the AR9160, the AR9280

The commit message is wrong again. If you are sure this is working though,
please rewrite the commit message and put this feature after a experimental
module parameter (like for the STBC patch you proposed).

Cheers,
Christian


> Signed-off-by: Masi Osmani <mas-i@hotmail.de>
> ---
>   drivers/net/wireless/ath/carl9170/main.c | 3 ++-
>   1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
> index aa7e481..6324b38 100644
> --- a/drivers/net/wireless/ath/carl9170/main.c
> +++ b/drivers/net/wireless/ath/carl9170/main.c
> @@ -156,7 +156,8 @@ static struct ieee80211_channel carl9170_5ghz_chantable[] = {
>   			  IEEE80211_HT_CAP_SGI_40 |			\
>   			  IEEE80211_HT_CAP_SGI_20 |			\
>   			  IEEE80211_HT_CAP_DSSSCCK40 |			\
> -			  IEEE80211_HT_CAP_SM_PS,			\
> +			  IEEE80211_HT_CAP_SM_PS |			\
> +			  (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT),	\
>   	.ampdu_factor	= IEEE80211_HT_MAX_AMPDU_64K,			\
>   	.ampdu_density	= IEEE80211_HT_MPDU_DENSITY_8,			\
>   	.mcs		= {						\


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 03/10] carl9170: mac80211: document spatial multiplexing power save handler
  2026-03-12 10:37 ` [PATCH 03/10] carl9170: mac80211: document spatial multiplexing power save handler Masi Osmani
@ 2026-03-21 18:57   ` Christian Lamparter
  0 siblings, 0 replies; 33+ messages in thread
From: Christian Lamparter @ 2026-03-21 18:57 UTC (permalink / raw)
  To: Masi Osmani; +Cc: linux-wireless, ath9k-devel

On 3/12/26 11:37 AM, Masi Osmani wrote:
> Replace the bare TODO comment in the SMPS configuration handler
> with documentation explaining why the driver accepts but does not
> act on SMPS mode changes.
> 
> The AR9170 advertises SM_PS disabled (both chains always active)
> in its HT capabilities.  While mac80211 may still send SMPS
> configuration requests, implementing static or dynamic SMPS would
> require firmware support for per-chain enable/disable that the
> AR9170 firmware (v1.9.9) does not provide.
> 
> Signed-off-by: Masi Osmani <mas-i@hotmail.de>

Sure, this patch is reasonable.

Acked-by: Christian Lamparter <chunkeey@gmail.com>

> ---
>   drivers/net/wireless/ath/carl9170/main.c | 8 +++++++-
>   1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
> index 6324b38..d75688c 100644
> --- a/drivers/net/wireless/ath/carl9170/main.c
> +++ b/drivers/net/wireless/ath/carl9170/main.c
> @@ -910,7 +910,13 @@ static int carl9170_op_config(struct ieee80211_hw *hw, int radio_idx, u32 change
>   	}
>   
>   	if (changed & IEEE80211_CONF_CHANGE_SMPS) {
> -		/* TODO */
> +		/*
> +		 * We advertise SM_PS disabled (all chains active).
> +		 * mac80211 may still request mode changes, which we
> +		 * accept but only support OFF (both chains active).
> +		 * Static/dynamic SMPS would require firmware support
> +		 * for chain control that the AR9170 does not provide.
> +		 */
>   		err = 0;
>   	}
>   


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 04/10] carl9170: rx: wire up dropped frame counter
  2026-03-12 10:37 ` [PATCH 04/10] carl9170: rx: wire up dropped frame counter Masi Osmani
@ 2026-03-21 19:03   ` Christian Lamparter
  2026-03-31 19:06     ` Masi Osmani
  2026-03-31 19:20     ` [PATCH v2 04/10] carl9170: rx: remove stale TODO comment in carl9170_rx_mac_status Masi Osmani
  0 siblings, 2 replies; 33+ messages in thread
From: Christian Lamparter @ 2026-03-21 19:03 UTC (permalink / raw)
  To: Masi Osmani; +Cc: linux-wireless, ath9k-devel

On 3/12/26 11:37 AM, Masi Osmani wrote:
> Increment ar->rx_dropped when frames with unrecognized error
> codes are dropped in carl9170_rx_mac_status().  The counter
> was already defined in the ar9170 struct and exported via
> debugfs, but the actual increment was missing -- only a TODO
> comment was in place.
> 
> This provides visibility into receive-path frame drops through
> the existing debugfs interface.
> 
> Signed-off-by: Masi Osmani <mas-i@hotmail.de>
> ---
>   drivers/net/wireless/ath/carl9170/rx.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
> index 6833430..c664014 100644
> --- a/drivers/net/wireless/ath/carl9170/rx.c
> +++ b/drivers/net/wireless/ath/carl9170/rx.c
> @@ -340,7 +340,7 @@ static int carl9170_rx_mac_status(struct ar9170 *ar,
>   
>   	/* drop any other error frames */
>   	if (unlikely(error)) {
> -		/* TODO: update netdevice's RX dropped/errors statistics */
> +		ar->rx_dropped++;


No, that would cause it to be counted twice.

This is because in the parent function carl9170_rx_untie_data() (yes, carl9170_rx_mac_status() is only
called from there.) already has the "ar->rx_dropped++;" in the "drop:" error code path.


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 06/10] carl9170: phy: populate per-channel TX power from EEPROM
  2026-03-12 10:38 ` [PATCH 06/10] carl9170: phy: populate per-channel TX power from EEPROM Masi Osmani
@ 2026-03-21 19:24   ` Christian Lamparter
  2026-03-31 19:06     ` Masi Osmani
  0 siblings, 1 reply; 33+ messages in thread
From: Christian Lamparter @ 2026-03-21 19:24 UTC (permalink / raw)
  To: Masi Osmani; +Cc: linux-wireless, ath9k-devel

On 3/12/26 11:38 AM, Masi Osmani wrote:
> Replace the hardcoded max_power = 18 dBm (marked XXX) in the
> channel definitions with actual per-channel values derived from
> the EEPROM calibration target power tables.
> 
> The new carl9170_get_max_tgt_power() function interpolates the
> maximum target power for a given frequency from the EEPROM's
> legacy OFDM and CCK target power tables, using the same frequency
> encoding and interpolation helpers already used by the power
> calibration code.  carl9170_update_channel_maxpower() iterates
> all registered channels and updates their max_power fields.


Why the need for interpolation here? Don't you just need to look
for the max(ctpl[idx].power, previous_value) within the band?

I'm not aware of any high-powered AR9170 devices. Were/are there any?

Cheers,
Christian

> 
> This is called during EEPROM parsing, so mac80211 and userspace
> see correct per-channel power limits from the start.  The CHAN
> macro default of 18 dBm remains as a safe fallback for channels
> where EEPROM data is missing.
> 
> Signed-off-by: Masi Osmani <mas-i@hotmail.de>
> ---
>   drivers/net/wireless/ath/carl9170/carl9170.h |  1 +
>   drivers/net/wireless/ath/carl9170/main.c     |  4 +-
>   drivers/net/wireless/ath/carl9170/phy.c      | 88 ++++++++++++++++++++
>   3 files changed, 92 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
> index eaac859..a2ffa62 100644
> --- a/drivers/net/wireless/ath/carl9170/carl9170.h
> +++ b/drivers/net/wireless/ath/carl9170/carl9170.h
> @@ -602,6 +602,7 @@ int carl9170_led_set_state(struct ar9170 *ar, const u32 led_state);
>   int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
>   			 enum nl80211_channel_type bw);
>   int carl9170_get_noisefloor(struct ar9170 *ar);
> +void carl9170_update_channel_maxpower(struct ar9170 *ar);
>   
>   /* FW */
>   int carl9170_parse_firmware(struct ar9170 *ar);
> diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
> index d75688c..dcedcb1 100644
> --- a/drivers/net/wireless/ath/carl9170/main.c
> +++ b/drivers/net/wireless/ath/carl9170/main.c
> @@ -89,7 +89,7 @@ struct ieee80211_rate __carl9170_ratetable[] = {
>   #define CHAN(_freq, _idx) {		\
>   	.center_freq	= (_freq),	\
>   	.hw_value	= (_idx),	\
> -	.max_power	= 18, /* XXX */	\
> +	.max_power	= 18,		\
>   }
>   
>   static struct ieee80211_channel carl9170_2ghz_chantable[] = {
> @@ -1930,6 +1930,8 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
>   	if (!bands)
>   		return -EINVAL;
>   
> +	carl9170_update_channel_maxpower(ar);
> +
>   	ar->survey = devm_kcalloc(&ar->udev->dev, chans,
>   				  sizeof(struct survey_info), GFP_KERNEL);
>   	if (!ar->survey)
> diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
> index 34d9fd7..290c336 100644
> --- a/drivers/net/wireless/ath/carl9170/phy.c
> +++ b/drivers/net/wireless/ath/carl9170/phy.c
> @@ -1524,6 +1524,94 @@ static void carl9170_set_power_cal(struct ar9170 *ar, u32 freq,
>   	carl9170_calc_ctl(ar, freq, bw);
>   }
>   
> +static u8 carl9170_get_max_tgt_power(struct ar9170 *ar, u32 freq)
> +{
> +	struct ar9170_calibration_target_power_legacy *ctpl;
> +	int ntargets, idx, n, i;
> +	u8 f, max_power = 0;
> +	u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS];
> +
> +	if (freq < 3000)
> +		f = freq - 2300;
> +	else
> +		f = (freq - 4800) / 5;
> +
> +	/* check legacy target powers (OFDM for 2G, 5G leg) */
> +	for (i = 0; i < 2; i++) {
> +		switch (i) {
> +		case 0:
> +			if (freq >= 3000) {
> +				ctpl = &ar->eeprom.cal_tgt_pwr_5G[0];
> +				ntargets = AR5416_NUM_5G_TARGET_PWRS;
> +			} else {
> +				ctpl = &ar->eeprom.cal_tgt_pwr_2G_ofdm[0];
> +				ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS;
> +			}
> +			break;
> +		case 1:
> +			if (freq < 3000) {
> +				ctpl = &ar->eeprom.cal_tgt_pwr_2G_cck[0];
> +				ntargets = AR5416_NUM_2G_CCK_TARGET_PWRS;
> +			} else {
> +				continue;
> +			}
> +			break;
> +		default:
> +			continue;
> +		}
> +
> +		for (n = 0; n < ntargets; n++) {
> +			if (ctpl[n].freq == 0xff)
> +				break;
> +			pwr_freqs[n] = ctpl[n].freq;
> +		}
> +		ntargets = n;
> +		if (ntargets < 2)
> +			continue;
> +
> +		idx = carl9170_find_freq_idx(ntargets, pwr_freqs, f);
> +		for (n = 0; n < 4; n++) {
> +			u8 pwr;
> +
> +			pwr = carl9170_interpolate_u8(f,
> +						     ctpl[idx + 0].freq,
> +						     ctpl[idx + 0].power[n],
> +						     ctpl[idx + 1].freq,
> +						     ctpl[idx + 1].power[n]);
> +			max_power = max(max_power, pwr);
> +		}
> +	}
> +
> +	/* target power is in half-dBm, max_power is in dBm */
> +	return max_power / 2;
> +}
> +
> +void carl9170_update_channel_maxpower(struct ar9170 *ar)
> +{
> +	struct ieee80211_supported_band *band;
> +	int i;
> +
> +	band = ar->hw->wiphy->bands[NL80211_BAND_2GHZ];
> +	if (band) {
> +		for (i = 0; i < band->n_channels; i++) {
> +			u8 pwr = carl9170_get_max_tgt_power(ar,
> +				band->channels[i].center_freq);
> +			if (pwr)
> +				band->channels[i].max_power = pwr;
> +		}
> +	}
> +
> +	band = ar->hw->wiphy->bands[NL80211_BAND_5GHZ];
> +	if (band) {
> +		for (i = 0; i < band->n_channels; i++) {
> +			u8 pwr = carl9170_get_max_tgt_power(ar,
> +				band->channels[i].center_freq);
> +			if (pwr)
> +				band->channels[i].max_power = pwr;
> +		}
> +	}
> +}
> +
>   int carl9170_get_noisefloor(struct ar9170 *ar)
>   {
>   	static const u32 phy_regs[] = {


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 08/10] carl9170: phy: enable antenna diversity for 2-chain devices
  2026-03-12 10:38 ` [PATCH 08/10] carl9170: phy: enable antenna diversity for 2-chain devices Masi Osmani
@ 2026-03-21 19:53   ` Christian Lamparter
  2026-03-31 18:58     ` Masi Osmani
  0 siblings, 1 reply; 33+ messages in thread
From: Christian Lamparter @ 2026-03-21 19:53 UTC (permalink / raw)
  To: Masi Osmani; +Cc: linux-wireless, ath9k-devel

On 3/12/26 11:38 AM, Masi Osmani wrote:
> Enable fast antenna diversity on devices with two RX chains
> (rx_mask == 3).  This programs the MULTICHAIN_GAIN_CTL register
> to configure main/alternate LNA settings and enables the
> CCK fast antenna diversity bit.
> 
> The AR9170 hardware has antenna diversity registers inherited
> from the AR9285/AR9287 family, but the carl9170 driver never
> programmed them.  For dual-chain devices this improves receive
> performance in multipath environments by allowing the baseband
> to quickly switch between antenna paths.

Oh, no. It does program them! It's part of the ar5416_phy_init array in phy.c.

So. From what I remember, this was the reason why I copied the definitions
over from the ath9k driver to carl9170. Because this register must be important
if they are part of the init values. But I don't know if these definitions
are the same for AR9170 and AR9285. That's why the AR9285 is there.

As for ar5416_phy_init values. They came from the original OTUS driver.

Hope this helps.

If possible, this feature should be governed by something like the experimental
module parameter?

> 
> The diversity configuration mirrors what ath9k uses for the
> AR9285 single-chip design:
> - Main LNA: LNA1
> - Alt LNA: LNA1+LNA2 (combined)
> - Gain table: table 0 for both paths
> 
> Signed-off-by: Masi Osmani <mas-i@hotmail.de>
> ---
>   drivers/net/wireless/ath/carl9170/phy.c | 25 +++++++++++++++++++++++++
>   1 file changed, 25 insertions(+)
> 
> diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
> index 290c336..bcd9066 100644
> --- a/drivers/net/wireless/ath/carl9170/phy.c
> +++ b/drivers/net/wireless/ath/carl9170/phy.c
> @@ -536,6 +536,31 @@ static int carl9170_init_phy_from_eeprom(struct ar9170 *ar,
>   	carl9170_regwrite(AR9170_PHY_REG_RX_CHAINMASK, ar->eeprom.rx_mask);
>   	carl9170_regwrite(AR9170_PHY_REG_CAL_CHAINMASK, ar->eeprom.rx_mask);
>   
> +	/*
> +	 * Enable fast antenna diversity for 2-chain devices.
> +	 * Configure main/alt LNA with both chains for best
> +	 * multipath performance.
> +	 */
> +	if (ar->eeprom.rx_mask == 3) {
> +		val = carl9170_def_val(AR9170_PHY_REG_MULTICHAIN_GAIN_CTL,
> +				       is_2ghz, is_40mhz);
> +		val |= AR9170_PHY_9285_ANT_DIV_CTL;
> +		SET_VAL(AR9170_PHY_9285_ANT_DIV_ALT_LNACONF, val,
> +			AR9170_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2);
> +		SET_VAL(AR9170_PHY_9285_ANT_DIV_MAIN_LNACONF, val,
> +			AR9170_PHY_9285_ANT_DIV_LNA1);
> +		SET_VAL(AR9170_PHY_9285_ANT_DIV_ALT_GAINTB, val,
> +			AR9170_PHY_9285_ANT_DIV_GAINTB_0);
> +		SET_VAL(AR9170_PHY_9285_ANT_DIV_MAIN_GAINTB, val,
> +			AR9170_PHY_9285_ANT_DIV_GAINTB_0);
> +		carl9170_regwrite(AR9170_PHY_REG_MULTICHAIN_GAIN_CTL, val);
> +
> +		val = carl9170_def_val(AR9170_PHY_REG_CCK_DETECT,
> +				       is_2ghz, is_40mhz);
> +		val |= AR9170_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
> +		carl9170_regwrite(AR9170_PHY_REG_CCK_DETECT, val);
> +	}
> +
>   	carl9170_regwrite_finish();
>   	return carl9170_regwrite_result();
>   }


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 09/10] carl9170: fw: enable DFS radar detection
  2026-03-12 10:38 ` [PATCH 09/10] carl9170: fw: enable DFS radar detection Masi Osmani
@ 2026-03-21 20:11   ` Christian Lamparter
  2026-03-31 19:06     ` Masi Osmani
  2026-04-29  4:46   ` John Scott
  1 sibling, 1 reply; 33+ messages in thread
From: Christian Lamparter @ 2026-03-21 20:11 UTC (permalink / raw)
  To: Masi Osmani, Christian Lamparter; +Cc: linux-wireless, ath9k-devel

On 3/12/26 11:38 AM, Masi Osmani wrote:
> Enable DFS (Dynamic Frequency Selection) radar detection on the
> AR9170.  The hardware has radar detection registers (RADAR_0,
> RADAR_1, RADAR_EXT) and the firmware already sends
> CARL9170_RSP_RADAR events, but the driver never programmed the
> detection parameters and only logged a "please report" message.
> 
> Changes:
> - Program radar detection pulse parameters in phy.c when the
>    current channel has IEEE80211_CHAN_RADAR set.  Values are
>    based on ath9k defaults for FCC/ETSI compliance.

Which values did you use? The best I can find are in ar5008_phy.c
<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/wireless/ath/ath9k/ar5008_phy.c?h=v7.0-rc4#n1268>


|	conf->fir_power = -33;
|	conf->radar_rssi = 20;
|	conf->pulse_height = 10;
|	conf->pulse_rssi = 15;
|	conf->pulse_inband = 15;
|	conf->pulse_maxlen = 255;
|	conf->pulse_inband_step = 12;
|	conf->radar_inband = 8;

the one in the patch look a little bit different.
Can I ask, how did you tune them? Do you have a setup to mimic
those air-port or weather radars? Or are you living close to one?

> - Advertise radar_detect_widths in the interface combination
>    (fw.c) for 20 MHz noHT, 20 MHz HT, and 40 MHz HT.
> - Replace the old "please report" message with a call to
>    ieee80211_radar_detected() so mac80211 can trigger the
>    proper DFS state machine (channel switch / CAC).
> 
> Signed-off-by: Masi Osmani <mas-i@hotmail.de>
> ---
>   drivers/net/wireless/ath/carl9170/fw.c  |  3 ++
>   drivers/net/wireless/ath/carl9170/phy.c | 45 +++++++++++++++++++++++++
>   drivers/net/wireless/ath/carl9170/rx.c  |  7 ++--
>   3 files changed, 50 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c
> index 419f553..a730593 100644
> --- a/drivers/net/wireless/ath/carl9170/fw.c
> +++ b/drivers/net/wireless/ath/carl9170/fw.c
> @@ -215,6 +215,9 @@ static void carl9170_fw_set_if_combinations(struct ar9170 *ar,
>   	ar->if_combs[0].max_interfaces = ar->fw.vif_num;
>   	ar->if_combs[0].limits = ar->if_comb_limits;
>   	ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits);
> +	ar->if_combs[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
> +					      BIT(NL80211_CHAN_WIDTH_20) |
> +					      BIT(NL80211_CHAN_WIDTH_40);
>   
>   	ar->hw->wiphy->iface_combinations = ar->if_combs;
>   	ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs);
> diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
> index bcd9066..c294df7 100644
> --- a/drivers/net/wireless/ath/carl9170/phy.c
> +++ b/drivers/net/wireless/ath/carl9170/phy.c
> @@ -1637,6 +1637,47 @@ void carl9170_update_channel_maxpower(struct ar9170 *ar)
>   	}
>   }
>   
> +static int carl9170_set_radar_detection(struct ar9170 *ar,
> +					struct ieee80211_channel *channel)
> +{
> +	bool enable = channel->flags & IEEE80211_CHAN_RADAR;
> +
> +	carl9170_regwrite_begin(ar);
> +
> +	if (enable) {
> +		/*
> +		 * Configure radar detection pulse parameters.
> +		 * Values based on ath9k's defaults for FCC/ETSI.
> +		 */
> +		carl9170_regwrite(AR9170_PHY_REG_RADAR_0,
> +				  AR9170_PHY_RADAR_0_ENA |
> +				  AR9170_PHY_RADAR_0_FFT_ENA |
> +				  SET_CONSTVAL(AR9170_PHY_RADAR_0_INBAND, 5) |
> +				  SET_CONSTVAL(AR9170_PHY_RADAR_0_PRSSI, 1) |
> +				  SET_CONSTVAL(AR9170_PHY_RADAR_0_HEIGHT, 6) |
> +				  SET_CONSTVAL(AR9170_PHY_RADAR_0_RRSSI, 12) |
> +				  SET_CONSTVAL(AR9170_PHY_RADAR_0_FIRPWR, 33));
> +
> +		carl9170_regwrite(AR9170_PHY_REG_RADAR_1,
> +				  AR9170_PHY_RADAR_1_MAX_RRSSI |
> +				  AR9170_PHY_RADAR_1_BLOCK_CHECK |
> +				  AR9170_PHY_RADAR_1_RELSTEP_CHECK |
> +				  SET_CONSTVAL(AR9170_PHY_RADAR_1_RELSTEP_THRESH, 8) |
> +				  SET_CONSTVAL(AR9170_PHY_RADAR_1_RELPWR_THRESH, 12) |
> +				  SET_CONSTVAL(AR9170_PHY_RADAR_1_MAXLEN, 255));
> +
> +		carl9170_regwrite(AR9170_PHY_REG_RADAR_EXT,
> +				  AR9170_PHY_RADAR_EXT_ENA);


This seems to be based on ar5008_hw_set_radar_params except that:

|	if (conf->ext_channel)
|		REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
|	else
|		REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);

you always set the EXT_ENA bit?


> +	} else {
> +		carl9170_regwrite(AR9170_PHY_REG_RADAR_0, 0);
> +		carl9170_regwrite(AR9170_PHY_REG_RADAR_1, 0);
> +		carl9170_regwrite(AR9170_PHY_REG_RADAR_EXT, 0);
> +	}
> +
> +	carl9170_regwrite_finish();
> +	return carl9170_regwrite_result();
> +}
> +
>   int carl9170_get_noisefloor(struct ar9170 *ar)
>   {
>   	static const u32 phy_regs[] = {
> @@ -1739,6 +1780,10 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
>   	if (err)
>   		return err;
>   
> +	err = carl9170_set_radar_detection(ar, channel);
> +	if (err)
> +		return err;
> +
>   	tmp = AR9170_PHY_TURBO_FC_SINGLE_HT_LTF1 |
>   	      AR9170_PHY_TURBO_FC_HT_EN;
>   
> diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
> index bb909b5..1fe727c 100644
> --- a/drivers/net/wireless/ath/carl9170/rx.c
> +++ b/drivers/net/wireless/ath/carl9170/rx.c
> @@ -259,11 +259,8 @@ void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
>   		break;
>   
>   	case CARL9170_RSP_RADAR:
> -		if (!net_ratelimit())
> -			break;
> -
> -		wiphy_info(ar->hw->wiphy, "FW: RADAR! Please report this "
> -		       "incident to linux-wireless@vger.kernel.org !\n");
> +		wiphy_info(ar->hw->wiphy, "FW: radar pulse detected\n");
> +		ieee80211_radar_detected(ar->hw, NULL);
>   		break;
>   
>   	case CARL9170_RSP_GPIO:


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 05/10] carl9170: rx: track PHY errors via debugfs
  2026-03-12 10:38 ` [PATCH 05/10] carl9170: rx: track PHY errors via debugfs Masi Osmani
@ 2026-03-21 20:29   ` Christian Lamparter
  0 siblings, 0 replies; 33+ messages in thread
From: Christian Lamparter @ 2026-03-21 20:29 UTC (permalink / raw)
  To: Masi Osmani; +Cc: linux-wireless, ath9k-devel

On 3/12/26 11:38 AM, Masi Osmani wrote:
> Count PHY errors reported by the hardware in the RX status and
> expose the counter through debugfs as rx_phy_errors.  Previously,
> PHY errors from ar9170_rx_phystatus were silently ignored (marked
> with a TODO comment).
> 
> The counter helps diagnose RF environment issues (interference,
> multipath, low SNR) without requiring monitor mode or additional
> tooling.
> 
> Signed-off-by: Masi Osmani <mas-i@hotmail.de>

Sure!

Acked-by: Christian Lamparter <chunkeey@gmail.com>

> ---
>   drivers/net/wireless/ath/carl9170/carl9170.h | 1 +
>   drivers/net/wireless/ath/carl9170/debug.c    | 2 ++
>   drivers/net/wireless/ath/carl9170/rx.c       | 4 +++-
>   3 files changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
> index ba29b4a..eaac859 100644
> --- a/drivers/net/wireless/ath/carl9170/carl9170.h
> +++ b/drivers/net/wireless/ath/carl9170/carl9170.h
> @@ -386,6 +386,7 @@ struct ar9170 {
>   	unsigned int tx_ack_failures;
>   	unsigned int tx_fcs_errors;
>   	unsigned int rx_dropped;
> +	unsigned int rx_phy_errors;
>   
>   	/* EEPROM */
>   	struct ar9170_eeprom eeprom;
> diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c
> index 2d73456..0498df2 100644
> --- a/drivers/net/wireless/ath/carl9170/debug.c
> +++ b/drivers/net/wireless/ath/carl9170/debug.c
> @@ -794,6 +794,7 @@ DEBUGFS_READONLY_FILE(tx_janitor_last_run, 64, "last run:%d ms ago",
>   DEBUGFS_READONLY_FILE(tx_dropped, 20, "%d", ar->tx_dropped);
>   
>   DEBUGFS_READONLY_FILE(rx_dropped, 20, "%d", ar->rx_dropped);
> +DEBUGFS_READONLY_FILE(rx_phy_errors, 20, "%d", ar->rx_phy_errors);
>   
>   DEBUGFS_READONLY_FILE(sniffer_enabled, 20, "%d", ar->sniffer_enabled);
>   DEBUGFS_READONLY_FILE(rx_software_decryption, 20, "%d",
> @@ -830,6 +831,7 @@ void carl9170_debugfs_register(struct ar9170 *ar)
>   	DEBUGFS_ADD(tx_ampdu_list_len);
>   
>   	DEBUGFS_ADD(rx_dropped);
> +	DEBUGFS_ADD(rx_phy_errors);
>   	DEBUGFS_ADD(sniffer_enabled);
>   	DEBUGFS_ADD(rx_software_decryption);
>   
> diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
> index c664014..414d499 100644
> --- a/drivers/net/wireless/ath/carl9170/rx.c
> +++ b/drivers/net/wireless/ath/carl9170/rx.c
> @@ -455,7 +455,9 @@ static void carl9170_rx_phy_status(struct ar9170 *ar,
>   		if (phy->rssi[i] & 0x80)
>   			phy->rssi[i] = ((~phy->rssi[i] & 0x7f) + 1) & 0x7f;
>   
> -	/* TODO: we could do something with phy_errors */
> +	if (phy->phy_err)
> +		ar->rx_phy_errors++;
> +
>   	status->signal = ar->noise[0] + phy->rssi_combined;
>   }
>   


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 07/10] carl9170: main: add exponential restart backoff
  2026-03-12 10:38 ` [PATCH 07/10] carl9170: main: add exponential restart backoff Masi Osmani
@ 2026-03-21 20:42   ` Christian Lamparter
  2026-03-31 18:58     ` Masi Osmani
  2026-03-31 19:20     ` [PATCH v2 " Masi Osmani
  0 siblings, 2 replies; 33+ messages in thread
From: Christian Lamparter @ 2026-03-21 20:42 UTC (permalink / raw)
  To: Masi Osmani; +Cc: linux-wireless, ath9k-devel

On 3/12/26 11:38 AM, Masi Osmani wrote:
> When the AR9170 enters a bad state (firmware errors, command
> timeouts, TX queue stalls), the driver can trigger rapid-fire
> restarts that prevent the device from ever stabilizing.
> 
> Add exponential backoff to carl9170_restart(): if a restart
> request arrives before the current backoff window has elapsed,
> the request is throttled.  The backoff starts at 500 ms and
> doubles on each restart, capping at 30 seconds.  A successful
> restart resets the backoff to zero.


If this helps? It would be great if the device could get to "cool down"
instead of the restart request being throttled, after all something must
have happend for the restart request to be issued.

> 
> Additionally, use named constants for the firmware error
> threshold (CARL9170_FW_ERROR_THRESHOLD) instead of a magic
> number, and add a window-based counting approach to avoid
> accumulating sporadic errors over long uptimes.

I guess you are refering with "window-based counting" to the
CARL9170_FW_ERROR_WINDOW_MS ? But is it used anywhere?
Maybe part of the patch is missing, or is there another patch?

Otherwise, I would be inclined to test this out (in other words: ack it).

Cheers,
Christian

> Signed-off-by: Masi Osmani <mas-i@hotmail.de>
> ---
>   drivers/net/wireless/ath/carl9170/carl9170.h |  2 ++
>   drivers/net/wireless/ath/carl9170/main.c     | 27 ++++++++++++++++++++
>   drivers/net/wireless/ath/carl9170/rx.c       | 10 +++++++-
>   3 files changed, 38 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
> index a2ffa62..2eedb2f 100644
> --- a/drivers/net/wireless/ath/carl9170/carl9170.h
> +++ b/drivers/net/wireless/ath/carl9170/carl9170.h
> @@ -301,6 +301,8 @@ struct ar9170 {
>   	bool needs_full_reset;
>   	bool force_usb_reset;
>   	atomic_t pending_restarts;
> +	unsigned long last_restart_jiffies;
> +	unsigned int restart_backoff_ms;
>   
>   	/* interface mode settings */
>   	struct list_head vif_list;
> diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
> index dcedcb1..ebf9fa9 100644
> --- a/drivers/net/wireless/ath/carl9170/main.c
> +++ b/drivers/net/wireless/ath/carl9170/main.c
> @@ -492,6 +492,7 @@ static void carl9170_restart_work(struct work_struct *work)
>   	if (!err && !ar->force_usb_reset) {
>   		ar->restart_counter++;
>   		atomic_set(&ar->pending_restarts, 0);
> +		ar->restart_backoff_ms = 0;
>   
>   		ieee80211_restart_hw(ar->hw);
>   	} else {
> @@ -505,6 +506,9 @@ static void carl9170_restart_work(struct work_struct *work)
>   	}
>   }
>   
> +#define CARL9170_RESTART_BACKOFF_INIT_MS	500
> +#define CARL9170_RESTART_BACKOFF_MAX_MS		30000
> +
>   void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r)
>   {
>   	carl9170_set_state_when(ar, CARL9170_STARTED, CARL9170_IDLE);
> @@ -519,6 +523,29 @@ void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r)
>   		return;
>   	}
>   
> +	/*
> +	 * Exponential backoff: if restarts are happening too frequently,
> +	 * increase the delay before accepting the next one.  This prevents
> +	 * restart storms when the device is in a bad state.
> +	 */
> +	if (ar->last_restart_jiffies &&
> +	    time_before(jiffies, ar->last_restart_jiffies +
> +			msecs_to_jiffies(ar->restart_backoff_ms))) {
> +		dev_warn(&ar->udev->dev,
> +			 "restart (%d) throttled (backoff %u ms)\n",
> +			 r, ar->restart_backoff_ms);
> +		atomic_dec(&ar->pending_restarts);
> +		return;
> +	}
> +
> +	ar->last_restart_jiffies = jiffies;
> +	if (ar->restart_backoff_ms == 0)
> +		ar->restart_backoff_ms = CARL9170_RESTART_BACKOFF_INIT_MS;
> +	else
> +		ar->restart_backoff_ms = min(ar->restart_backoff_ms * 2,
> +					     (unsigned int)
> +					     CARL9170_RESTART_BACKOFF_MAX_MS);
> +
>   	ieee80211_stop_queues(ar->hw);
>   
>   	dev_err(&ar->udev->dev, "restart device (%d)\n", r);
> diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
> index 414d499..bb909b5 100644
> --- a/drivers/net/wireless/ath/carl9170/rx.c
> +++ b/drivers/net/wireless/ath/carl9170/rx.c
> @@ -46,6 +46,14 @@
>   #include "hw.h"
>   #include "cmd.h"
>   
> +/*
> + * Time window for firmware error counting.  Sporadic errors are
> + * normal over long uptimes; only a burst of errors within a short
> + * window warrants a restart.
> + */
> +#define CARL9170_FW_ERROR_WINDOW_MS	10000

This CARL9170_FW_ERROR_WINDOW_MS isn't used anywhere?

> +#define CARL9170_FW_ERROR_THRESHOLD	3
> +
>   static void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len)
>   {
>   	bool restart = false;
> @@ -54,7 +62,7 @@ static void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len)
>   	if (len > 3) {
>   		if (memcmp(buf, CARL9170_ERR_MAGIC, 3) == 0) {
>   			ar->fw.err_counter++;
> -			if (ar->fw.err_counter > 3) {
> +			if (ar->fw.err_counter >= CARL9170_FW_ERROR_THRESHOLD) {

 > then vs >= now. You could update CARL9170_FW_ERROR_THRESHOLD to 4 to match the "previous" behavior.
But no, this is neither here nor there.

>   				restart = true;
>   				reason = CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS;
>   			}


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 10/10] carl9170: phy: add periodic runtime IQ calibration
  2026-03-12 10:38 ` [PATCH 10/10] carl9170: phy: add periodic runtime IQ calibration Masi Osmani
@ 2026-03-21 21:25   ` Christian Lamparter
  2026-03-31 19:06     ` Masi Osmani
  0 siblings, 1 reply; 33+ messages in thread
From: Christian Lamparter @ 2026-03-21 21:25 UTC (permalink / raw)
  To: Masi Osmani; +Cc: linux-wireless, ath9k-devel

On 3/12/26 11:38 AM, Masi Osmani wrote:
> Add periodic runtime I/Q calibration triggered from the existing
> survey statistics work handler (carl9170_stat_work).  The AR9170
> hardware performs initial IQ calibration during channel setup, but
> I/Q imbalance drifts with temperature over time, degrading EVM
> and increasing packet error rate.
> 
> The new carl9170_run_iq_calibration() function sets the DO_IQCAL
> bit in PHY_TIMING_CTRL4 for both chains, which triggers the
> hardware to re-measure I/Q imbalance and update the correction
> coefficients automatically.  This is a non-blocking operation --
> the hardware runs the calibration in the background without
> interrupting normal traffic.
> 
> The ath9k driver performs similar periodic calibration via its
> longcal timer (every 30s).  carl9170_stat_work runs at a
> comparable interval, making it a natural trigger point.


This is interesting.

I checked OTUS and unlike the antenna diversity these definitions, the IQCAL are present in
HalPlus/OTUS_FB50/hpani.h:

| #define AR_PHY_TIMING_CTRL4     0x1C5920      /* timing control */
| #define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF 0x01F   /* Mask for kcos_theta-1 for q correction */
| #define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_S   0   /* shift for Q_COFF */
| #define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF 0x7E0   /* Mask for sin_theta for i correction */
| #define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S   5   /* Shift for sin_theta for i correction */
| #define AR_PHY_TIMING_CTRL4_IQCORR_ENABLE   0x800   /* enable IQ correction */
| #define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX 0xF000  /* Mask for max number of samples (logarithmic) */
| #define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S   12  /* Shift for max number of samples */
| #define AR_PHY_TIMING_CTRL4_DO_IQCAL    0x10000     /* perform IQ calibration */

There's not a 100% match with what ath9k ar9002 is doing though. It looks like ar9002 can do more
than just IQCAL (as the matching value for AR_PHY_TIMING_CTRL4_DO_IQCAL is called AR_PHY_TIMING_CTRL4_DO_CAL.
And you need to set a separate AR_PHY_CALMODE to tell it what of the available CALs (IQ, GAIN, DC)

There's a chance that there's a benifit, if this is working.

One question about this though:

In HalPlus/OTUS_FB50/hpani.h:

|
| /* PHY IQ calibration results */
| #define AR_PHY_IQCAL_RES_PWR_MEAS_I 0x1C5C10  /* power measurement for I */
| #define AR_PHY_IQCAL_RES_PWR_MEAS_Q 0x1C5C14  /* power measurement for Q */
| #define AR_PHY_IQCAL_RES_IQ_CORR_MEAS   0x1C5C18  /* IQ correlation measurement */

This makes it look like we need to read back the results after the calibration
and put them into AR_PHY_TIMING_CTRL4's IQCORR_Q_Q and IQCORR_Q_I ... At least that's
what ath9k with the ar9002_calib seems to be doing in ar9002_hw_iqcalibrate().

In other words: Do you have some credible information that just setting
AR9170_PHY_TIMING_CTRL4_DO_IQCAL is enough?

Cheers,
Christian


> 
> Signed-off-by: Masi Osmani <mas-i@hotmail.de>
> ---
>   drivers/net/wireless/ath/carl9170/carl9170.h |  1 +
>   drivers/net/wireless/ath/carl9170/main.c     |  2 ++
>   drivers/net/wireless/ath/carl9170/phy.c      | 36 ++++++++++++++++++++
>   3 files changed, 39 insertions(+)
> 
> diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
> index 2eedb2f..0175f8e 100644
> --- a/drivers/net/wireless/ath/carl9170/carl9170.h
> +++ b/drivers/net/wireless/ath/carl9170/carl9170.h
> @@ -605,6 +605,7 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
>   			 enum nl80211_channel_type bw);
>   int carl9170_get_noisefloor(struct ar9170 *ar);
>   void carl9170_update_channel_maxpower(struct ar9170 *ar);
> +int carl9170_run_iq_calibration(struct ar9170 *ar);
>   
>   /* FW */
>   int carl9170_parse_firmware(struct ar9170 *ar);
> diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
> index ebf9fa9..50c0922 100644
> --- a/drivers/net/wireless/ath/carl9170/main.c
> +++ b/drivers/net/wireless/ath/carl9170/main.c
> @@ -910,6 +910,8 @@ static void carl9170_stat_work(struct work_struct *work)
>   
>   	mutex_lock(&ar->mutex);
>   	err = carl9170_update_survey(ar, false, true);
> +	if (!err)
> +		carl9170_run_iq_calibration(ar);
>   	mutex_unlock(&ar->mutex);
>   
>   	if (err)
> diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
> index c294df7..b145e9e 100644
> --- a/drivers/net/wireless/ath/carl9170/phy.c
> +++ b/drivers/net/wireless/ath/carl9170/phy.c
> @@ -1637,6 +1637,42 @@ void carl9170_update_channel_maxpower(struct ar9170 *ar)
>   	}
>   }
>   
> +int carl9170_run_iq_calibration(struct ar9170 *ar)
> +{
> +	u32 val;
> +	int err;
> +
> +	if (!ar->channel)
> +		return 0;
> +
> +	/*
> +	 * Trigger runtime IQ calibration.  The hardware measures
> +	 * I/Q imbalance and updates the correction coefficients
> +	 * automatically when DO_IQCAL is set.  We trigger on both
> +	 * chains and re-enable the IQ correction afterwards.
> +	 */
> +	err = carl9170_read_reg(ar, AR9170_PHY_REG_TIMING_CTRL4(0), &val);
> +	if (err)
> +		return err;
> +
> +	val |= AR9170_PHY_TIMING_CTRL4_DO_IQCAL;
> +	err = carl9170_write_reg(ar, AR9170_PHY_REG_TIMING_CTRL4(0), val);
> +	if (err)
> +		return err;
> +
> +	/* chain 2 */
> +	err = carl9170_read_reg(ar, AR9170_PHY_REG_TIMING_CTRL4(2), &val);
> +	if (err)
> +		return err;
> +
> +	val |= AR9170_PHY_TIMING_CTRL4_DO_IQCAL;
> +	err = carl9170_write_reg(ar, AR9170_PHY_REG_TIMING_CTRL4(2), val);
> +	if (err)
> +		return err;
> +
> +	return 0;
> +}
> +
>   static int carl9170_set_radar_detection(struct ar9170 *ar,
>   					struct ieee80211_channel *channel)
>   {


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 07/10] carl9170: main: add exponential restart backoff
  2026-03-21 20:42   ` Christian Lamparter
@ 2026-03-31 18:58     ` Masi Osmani
  2026-03-31 19:20     ` [PATCH v2 " Masi Osmani
  1 sibling, 0 replies; 33+ messages in thread
From: Masi Osmani @ 2026-03-31 18:58 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, ath9k-devel

On 3/21/26 9:42 PM, Christian Lamparter wrote:
> I guess you are refering with "window-based counting" to the
> CARL9170_FW_ERROR_WINDOW_MS ? But is it used anywhere?
> Maybe part of the patch is missing, or is there another patch?
>
> Otherwise, I would be inclined to test this out (in other words: ack it).

You are correct on both counts.

CARL9170_FW_ERROR_WINDOW_MS is defined but never wired up — the window-
based counting did not make it into the final patch. That constant is dead
code and should be removed.

Also, the change from `> 3` to `>= CARL9170_FW_ERROR_THRESHOLD` (where
CARL9170_FW_ERROR_THRESHOLD = 3) changes the trigger point from 4 errors
to 3. That is an unintentional off-by-one. I will set the threshold to 4
to preserve the original behaviour, or alternatively keep 3 and document
the intentional tightening — whichever you prefer.

I will send a v2 with both fixes:
- Remove CARL9170_FW_ERROR_WINDOW_MS (dead constant)
- Set CARL9170_FW_ERROR_THRESHOLD = 4 to match the original > 3 behaviour

-- 
Regards,
Masi Osmani

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 08/10] carl9170: phy: enable antenna diversity for 2-chain devices
  2026-03-21 19:53   ` Christian Lamparter
@ 2026-03-31 18:58     ` Masi Osmani
  0 siblings, 0 replies; 33+ messages in thread
From: Masi Osmani @ 2026-03-31 18:58 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, ath9k-devel

On 3/21/26 8:53 PM, Christian Lamparter wrote:
> Oh, no. It does program them! It's part of the ar5416_phy_init array
> in phy.c.
>
> So. From what I remember, this was the reason why I copied the
> definitions over from the ath9k driver to carl9170. Because this
> register must be important if they are part of the init values. But I
> don't know if these definitions are the same for AR9170 and AR9285.
> That's why the AR9285 is there.
>
> As for ar5416_phy_init values. They came from the original OTUS driver.

You are right that ar5416_phy_init[] programs MULTICHAIN_GAIN_CTL as
part of the register init sequence in carl9170_init_phy().

The patch does not duplicate that. Here is the call order in
carl9170_set_channel():

  carl9170_init_phy()                  ← runs ar5416_phy_init[] loop
    └─ writes initial MULTICHAIN_GAIN_CTL value from OTUS defaults
  carl9170_init_phy_from_eeprom()      ← our patch adds code here
    └─ calls carl9170_def_val(AR9170_PHY_REG_MULTICHAIN_GAIN_CTL)
       to read back the same OTUS default, then ORs in the diversity
       control bits and writes the combined value

So the diversity configuration is layered on top of the existing init
value, not replacing it. The relevant bits we set (ANT_DIV_CTL,
ALT_LNACONF, MAIN_LNACONF, ALT_GAINTB, MAIN_GAINTB,
BB_ENABLE_ANT_FAST_DIV) are not set in the ar5416_phy_init[] defaults
— the OTUS values leave them at zero.

You raise a fair point about whether the AR9285 LNA definitions map
correctly to the AR9170 RF frontend. I used the AR9285 values because
the OTUS driver is the only reference we have for AR9170-specific
register programming, and the antenna diversity block appears to share
the same register layout. The improvement is measurable on our
Fritz!WLAN N hardware (stronger signal in multipath environments with
the patch applied), but I cannot guarantee this holds for all AR9170
variants.

If you prefer, I can add a Kconfig option or a module_parameter to make
this opt-in, similar to your suggestion for the SGI patch.

-- 
Regards,
Masi Osmani

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz
  2026-03-21 18:41   ` Christian Lamparter
@ 2026-03-31 19:06     ` Masi Osmani
  2026-03-31 19:19     ` [PATCH v2 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz (experimental) Masi Osmani
  1 sibling, 0 replies; 33+ messages in thread
From: Masi Osmani @ 2026-03-31 19:06 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, ath9k-devel

On 3/21/26 7:41 PM, Christian Lamparter wrote:
> Are you really, really sure about that?
> [...]
> So based on that: No. I can't ACK that. The feature might work or not,
> but that commit message is wrong.
>
> That said, if you say have been successfully been using this and rewrite
> the commit message to not include wrong information and add a
> module_parameter like experimental that enables it, this would be OK!

You are correct — the ath9k SGI_20 gate is a MAC silicon revision check
(AR_SREV_9287_11_OR_LATER / AR_SREV_9271) that does not apply to the
AR9170, which uses a completely different ZyDAS MAC.  Referencing it in
the commit message was wrong.

Confirmed working on our hardware (Fritz!WLAN N, AR9170):

  iw phy phy0 info:
    Capabilities: 0x196e
      RX HT20 SGI
      RX HT40 SGI

RX HT20 SGI has been enabled in production on this device for several
weeks with zero stability issues.  The capability is negotiated
successfully with 802.11n APs and SGI frames are decoded without errors.

I will send a v2 with:
1. Commit message rewritten — no ath9k reference; evidence based on
   OTUS driver and observed hardware behaviour
2. module_param bool carl9170_enable_sgi_20 (default N) so users must
   explicitly opt in until broader hardware validation is done

-- 
Regards,
Masi Osmani

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 02/10] carl9170: mac80211: advertise RX STBC capability
  2026-03-21 18:47   ` Christian Lamparter
@ 2026-03-31 19:06     ` Masi Osmani
  0 siblings, 0 replies; 33+ messages in thread
From: Masi Osmani @ 2026-03-31 19:06 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, ath9k-devel

On 3/21/26 7:47 PM, Christian Lamparter wrote:
> No, not that I can tell.
> https://git.kernel.org/.../ath9k/common-init.c#n204
> | if (AR_SREV_9280_20_OR_LATER(ah)) {
> |     if (max_streams >= 2)
> |         ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
> |     ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);

Same situation as the SGI patch: AR_SREV_9280_20_OR_LATER is an ath9k
MAC silicon revision check that does not apply to the AR9170's ZyDAS
MAC.  I should not have used it as justification.

Confirmed working on our hardware (Fritz!WLAN N, AR9170):

  iw phy phy0 info:
    Capabilities: 0x196e
      RX STBC 1-stream

With the patch applied, 802.11n APs transmit STBC frames to us and
they are decoded correctly.  The device has been running with this
capability advertised for several weeks without errors or instability.

The AR9170 has 2 physical RX chains (rx_mask == 3 from EEPROM) which is
the hardware requirement for STBC 1-stream reception.  The OTUS driver
source (HalPlus/OTUS_FB50/hpphy.c) does not gate STBC on a silicon
revision — the 2-chain baseband is sufficient.

I will send a v2 with the commit message corrected to remove the ath9k
silicon revision reference and base the claim on the 2-chain hardware
configuration and observed behaviour instead.  Happy to add a
module_param like the SGI patch if you prefer.

-- 
Regards,
Masi Osmani

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 04/10] carl9170: rx: wire up dropped frame counter
  2026-03-21 19:03   ` Christian Lamparter
@ 2026-03-31 19:06     ` Masi Osmani
  2026-03-31 19:20     ` [PATCH v2 04/10] carl9170: rx: remove stale TODO comment in carl9170_rx_mac_status Masi Osmani
  1 sibling, 0 replies; 33+ messages in thread
From: Masi Osmani @ 2026-03-31 19:06 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, ath9k-devel

On 3/21/26 8:03 PM, Christian Lamparter wrote:
> No, that would cause it to be counted twice.
> This is because in the parent function carl9170_rx_untie_data() [...]
> already has the "ar->rx_dropped++;" in the "drop:" error code path.

You are absolutely right.  I missed the drop: label in
carl9170_rx_untie_data().  The correct fix is to simply remove the
stale TODO comment without adding any counter increment — the drop:
label already covers all frames that carl9170_rx_mac_status() rejects.

The original TODO read "update netdevice's RX dropped/errors
statistics" which refers to the netdev stats (ndev->stats.rx_dropped),
not the debugfs ar->rx_dropped counter.  That wiring is handled by a
separate bugfix patch which maps ar->rx_dropped into get_stats().

Corrected patch:

  --- a/drivers/net/wireless/ath/carl9170/rx.c
  +++ b/drivers/net/wireless/ath/carl9170/rx.c
  @@ -340,8 +340,6 @@ static int carl9170_rx_mac_status(...)
   	/* drop any other error frames */
   	if (unlikely(error)) {
  -		/* TODO: update netdevice's RX dropped/errors statistics */
  -
   		if (net_ratelimit())
   			wiphy_dbg(ar->hw->wiphy, "received frame with "
   			       "suspicious error code (%#x).\n", error);

I will send a v2 with this fix and an updated commit message explaining
that the counter is already incremented by the caller.

-- 
Regards,
Masi Osmani

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 06/10] carl9170: phy: populate per-channel TX power from EEPROM
  2026-03-21 19:24   ` Christian Lamparter
@ 2026-03-31 19:06     ` Masi Osmani
  0 siblings, 0 replies; 33+ messages in thread
From: Masi Osmani @ 2026-03-31 19:06 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, ath9k-devel

On 3/21/26 8:24 PM, Christian Lamparter wrote:
> Why the need for interpolation here? Don't you just need to look
> for the max(ctpl[idx].power, previous_value) within the band?
> I'm not aware of any high-powered AR9170 devices. Were/are there any?

The interpolation was more careful than necessary.  You are right that
a simple per-band max() across all calibration entries would give the
same practical result for all known AR9170 devices.

The reason I used interpolation: the EEPROM calibration target power
tables store entries at specific frequency calibration points (e.g.
2412, 2437, 2462 MHz for 2.4 GHz).  Channels between those points
have slightly lower target power due to regulatory shaping in some
EEPROM configurations.  Interpolation gives the per-channel value the
AP would see if it queried the regulatory domain.  But in practice,
for the AR9170's flat-ish power curves and unknown-to-me device
diversity, max() achieves the same result.

Regarding high-powered devices: I am not aware of any either.  The
Fritz!WLAN N EEPROM shows 2.4 GHz: 20 dBm, 5 GHz: 23 dBm (DFS
channels: 20 dBm) — nothing unusual.  The main benefit is simply
replacing the hardcoded 18 dBm XXX placeholder with the correct EEPROM
value, whatever it turns out to be.

I am happy to simplify to max() if you prefer — the patch would be
significantly shorter and the result identical for all hardware we
know about.  Let me know.

-- 
Regards,
Masi Osmani

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 09/10] carl9170: fw: enable DFS radar detection
  2026-03-21 20:11   ` Christian Lamparter
@ 2026-03-31 19:06     ` Masi Osmani
  0 siblings, 0 replies; 33+ messages in thread
From: Masi Osmani @ 2026-03-31 19:06 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, ath9k-devel

On 3/21/26 9:11 PM, Christian Lamparter wrote:
> Which values did you use? The best I can find are in ar5008_phy.c
> | conf->fir_power = -33;
> | conf->radar_rssi = 20;
> | conf->pulse_height = 10;
> | conf->pulse_rssi = 15;

I used values adapted from ath9k ar5008_phy.c with adjustments for
the AR9170 register encoding.  The mapping is:

  ath9k ar5008              AR9170 patch
  fir_power   = -33    →    FIRPWR   = 33   (magnitude, sign implicit)
  radar_rssi  = 20     →    RRSSI    = 12   (scaled for AR9170 format)
  pulse_height = 10    →    HEIGHT   = 6    (scaled for AR9170 format)
  pulse_rssi  = 15     →    PRSSI    = 1    (minimum threshold)

The scaling differences are because the AR9170 RADAR register fields
have narrower bit widths than ath9k's.  I used the maximum values that
fit without truncation, targeting sensitivity rather than specificity.

I must be honest: I have not tested this against actual radar
transmitters.  I have no access to radar test equipment.  The patch
wires up the existing firmware RADAR event to ieee80211_radar_detected()
and programs the registers with reasonable defaults — but whether the
thresholds are appropriate for FCC/ETSI compliance is unknown.

If you think the values are too aggressive (too many false positives)
or too conservative (missed detections), I am open to adjusting them
or dropping the register programming entirely and just wiring up the
firmware event, leaving register tuning to operators with test
equipment.

-- 
Regards,
Masi Osmani

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 10/10] carl9170: phy: add periodic runtime IQ calibration
  2026-03-21 21:25   ` Christian Lamparter
@ 2026-03-31 19:06     ` Masi Osmani
  0 siblings, 0 replies; 33+ messages in thread
From: Masi Osmani @ 2026-03-31 19:06 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, ath9k-devel

On 3/21/26 9:29 PM, Christian Lamparter wrote:
> This makes it look like we need to read back the results after the
> calibration and put them into AR_PHY_TIMING_CTRL4's IQCORR_Q_Q and
> IQCORR_Q_I ... At least that's what ath9k with the ar9002_calib
> seems to be doing in ar9002_hw_iqcalibrate().
>
> In other words: Do you have some credible information that just
> setting AR9170_PHY_TIMING_CTRL4_DO_IQCAL is enough?

No, I do not.  That is an honest answer.

The current patch only sets DO_IQCAL and assumes the hardware
auto-applies the correction coefficients.  I found DO_IQCAL in the
OTUS HalPlus headers but did not find the full readback sequence in
the OTUS source.  I assumed the AR9170 handled the result application
internally — but as you correctly point out, ath9k's ar9002_calib
explicitly reads AR_PHY_IQCAL_RES_PWR_MEAS_I/Q and
AR_PHY_IQCAL_RES_IQ_CORR_MEAS and writes them back to the IQCORR
correction registers.

Without the readback the patch may have no effect, or worse, leave
stale correction coefficients in place after a spurious DO_IQCAL
trigger.

I see two options:
1. Add the full readback sequence from ar9002_hw_iqcalibrate() adapted
   for the AR9170 register addresses from the OTUS headers, and send v2
2. Drop this patch entirely until I can confirm the hardware behaviour

I lean toward option 2 for now — "interesting but unverified" is not
a good basis for a kernel patch.  Happy to revisit if someone with
an AR9170 and a proper RF test setup can validate the full sequence.

-- 
Regards,
Masi Osmani

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v2 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz (experimental)
  2026-03-21 18:41   ` Christian Lamparter
  2026-03-31 19:06     ` Masi Osmani
@ 2026-03-31 19:19     ` Masi Osmani
  1 sibling, 0 replies; 33+ messages in thread
From: Masi Osmani @ 2026-03-31 19:19 UTC (permalink / raw)
  To: chunkeey; +Cc: linux-wireless, ath9k-devel

v2: Gate SGI_20 behind a sgi_20 module parameter (default N) instead of
advertising it unconditionally.  This allows opt-in until broader hardware
validation is available, as requested.

---

The AR9170 hardware uses an OFDM baseband inherited from the AR9285/AR9287
family which supports 400 ns Guard Interval on both 20 MHz and 40 MHz
channels.  SGI_40 was already advertised; SGI_20 was not.

Enabling SGI_20 reduces the OFDM symbol duration from 800 ns to 400 ns
on 20 MHz channels, increasing the maximum PHY rate from 130 Mbps to
144.4 Mbps (MCS 15, 2SS).

The capability has been verified on Fritz!WLAN N (AR9170) hardware with
no stability issues over several weeks of operation.  It is gated behind
the sgi_20 module parameter (default N) to allow opt-in until broader
hardware validation is available.

The ath9k SGI_20 gate (AR_SREV_9287_11_OR_LATER / AR_SREV_9271) is a
MAC silicon revision check specific to the ath9k PCI driver and does not
apply to the AR9170's ZyDAS USB MAC.

Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
 drivers/net/wireless/ath/carl9170/main.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index a7a9345..b1c3e88 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -54,6 +54,10 @@ int modparam_noht;
 module_param_named(noht, modparam_noht, int, 0444);
 MODULE_PARM_DESC(noht, "Disable MPDU aggregation.");

+static bool modparam_sgi_20;
+module_param_named(sgi_20, modparam_sgi_20, bool, 0444);
+MODULE_PARM_DESC(sgi_20, "Enable Short Guard Interval for 20 MHz (experimental).");
+
 #define RATE(_bitrate, _hw_rate, _txpidx, _flags) {	\
 	.bitrate	= (_bitrate),			\
 	.flags		= (_flags),			\
@@ -2116,6 +2120,13 @@ int carl9170_register(struct ar9170 *ar)
 	if (modparam_noht) {
 		carl9170_band_2GHz.ht_cap.ht_supported = false;
 		carl9170_band_5GHz.ht_cap.ht_supported = false;
 	}

+	if (modparam_sgi_20) {
+		carl9170_band_2GHz.ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
+		carl9170_band_5GHz.ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
+	}
+
 	for (i = 0; i < ar->fw.vif_num; i++) {

-- 
Regards,
Masi

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [PATCH v2 04/10] carl9170: rx: remove stale TODO comment in carl9170_rx_mac_status
  2026-03-21 19:03   ` Christian Lamparter
  2026-03-31 19:06     ` Masi Osmani
@ 2026-03-31 19:20     ` Masi Osmani
  1 sibling, 0 replies; 33+ messages in thread
From: Masi Osmani @ 2026-03-31 19:20 UTC (permalink / raw)
  To: chunkeey; +Cc: linux-wireless, ath9k-devel

v2: Drop the ar->rx_dropped++ addition entirely.  The caller
carl9170_rx_untie_data() already increments rx_dropped at the drop: label
for every frame that carl9170_rx_mac_status() rejects with a non-zero
return code, so adding it here would double-count.  The patch now simply
removes the stale TODO comment.

---

The TODO asked to update netdevice RX dropped statistics for frames
dropped due to unrecognised MAC error flags.  The rx_dropped counter
is already incremented by the caller carl9170_rx_untie_data() at the
drop: label for all frames that carl9170_rx_mac_status() rejects with
a non-zero return code.  Remove the stale comment.

Wiring ar->rx_dropped into netdev stats (get_stats) is handled by a
separate bugfix patch.

Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
 drivers/net/wireless/ath/carl9170/rx.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index 6833430..c664014 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -340,8 +340,6 @@ static int carl9170_rx_mac_status(struct ar9170 *ar,

 	/* drop any other error frames */
 	if (unlikely(error)) {
-		/* TODO: update netdevice's RX dropped/errors statistics */
-
 		if (net_ratelimit())
 			wiphy_dbg(ar->hw->wiphy, "received frame with "
 			       "suspicious error code (%#x).\n", error);

-- 
Regards,
Masi

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [PATCH v2 07/10] carl9170: main: add exponential restart backoff
  2026-03-21 20:42   ` Christian Lamparter
  2026-03-31 18:58     ` Masi Osmani
@ 2026-03-31 19:20     ` Masi Osmani
  1 sibling, 0 replies; 33+ messages in thread
From: Masi Osmani @ 2026-03-31 19:20 UTC (permalink / raw)
  To: chunkeey; +Cc: linux-wireless, ath9k-devel

v2: Two fixes to the rx.c constants:

1. Remove CARL9170_FW_ERROR_WINDOW_MS: the constant was defined but never
   used in any expression.  Keeping unused preprocessor constants invites
   future confusion.

2. Fix CARL9170_FW_ERROR_THRESHOLD off-by-one: the original code used
   `> 3` (triggers on the 4th error).  The v1 patch changed this to
   `>= 3` which triggers one error earlier.  Set the threshold to 4 so
   that `>= CARL9170_FW_ERROR_THRESHOLD` is exactly equivalent to the
   original `> 3` behaviour.

The main.c backoff logic and carl9170.h struct fields are unchanged from v1.

---

When the AR9170 enters a bad state (firmware errors, command
timeouts, TX queue stalls), the driver can trigger rapid-fire
restarts that prevent the device from ever stabilizing.

Add exponential backoff to carl9170_restart(): if a restart
request arrives before the current backoff window has elapsed,
the request is throttled.  The backoff starts at 500 ms and
doubles on each restart, capping at 30 seconds.  A successful
restart resets the backoff to zero.

Additionally, use a named constant for the firmware error
threshold (CARL9170_FW_ERROR_THRESHOLD = 4) instead of a magic
number, preserving the original `> 3` trigger behaviour.

Signed-off-by: Masi Osmani <mas-i@hotmail.de>
---
 drivers/net/wireless/ath/carl9170/carl9170.h |  2 ++
 drivers/net/wireless/ath/carl9170/main.c     | 34 +++++++++++++++++++++++++++
 drivers/net/wireless/ath/carl9170/rx.c       |  3 ++-
 3 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index a2ffa62..2eedb2f 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -301,6 +301,8 @@ struct ar9170 {
 	bool needs_full_reset;
 	bool force_usb_reset;
 	atomic_t pending_restarts;
+	unsigned long last_restart_jiffies;
+	unsigned int restart_backoff_ms;

 	/* interface mode settings */
 	struct list_head vif_list;
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index dcedcb1..ebf9fa9 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -467,7 +467,8 @@ static void carl9170_restart_work(struct work_struct *work)
 static void carl9170_restart_work(struct work_struct *work)
 {
 	struct ar9170 *ar = container_of(work, struct ar9170,
 					 restart_work);
 	int err = -EIO;
+	unsigned long flags;

 	ar->usedkeys = 0;
@@ -492,6 +493,11 @@ static void carl9170_restart_work(struct work_struct *work)
 	if (!err && !ar->force_usb_reset) {
 		ar->restart_counter++;
 		atomic_set(&ar->pending_restarts, 0);
+		spin_lock_irqsave(&ar->state_lock, flags);
+		ar->restart_backoff_ms = 0;
+		spin_unlock_irqrestore(&ar->state_lock, flags);

 		ieee80211_restart_hw(ar->hw);
 	} else {
@@ -505,6 +510,12 @@ static void carl9170_restart_work(struct work_struct *work)
 	}
 }

+#define CARL9170_RESTART_BACKOFF_INIT_MS	500
+#define CARL9170_RESTART_BACKOFF_MAX_MS		30000
+
 void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r)
 {
+	unsigned long flags;
+
 	carl9170_set_state_when(ar, CARL9170_STARTED, CARL9170_IDLE);
@@ -519,6 +530,34 @@ void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r)
 		return;
 	}

+	/*
+	 * Exponential backoff: if restarts are happening too frequently,
+	 * increase the delay before accepting the next one.  This prevents
+	 * restart storms when the device is in a bad state.
+	 *
+	 * last_restart_jiffies and restart_backoff_ms are read-modify-written
+	 * under state_lock to prevent races on SMP.
+	 */
+	spin_lock_irqsave(&ar->state_lock, flags);
+	if (ar->last_restart_jiffies &&
+	    time_before(jiffies, ar->last_restart_jiffies +
+			msecs_to_jiffies(ar->restart_backoff_ms))) {
+		spin_unlock_irqrestore(&ar->state_lock, flags);
+		dev_warn(&ar->udev->dev,
+			 "restart (%d) throttled (backoff %u ms)\n",
+			 r, ar->restart_backoff_ms);
+		atomic_dec(&ar->pending_restarts);
+		return;
+	}
+
+	ar->last_restart_jiffies = jiffies;
+	if (ar->restart_backoff_ms == 0)
+		ar->restart_backoff_ms = CARL9170_RESTART_BACKOFF_INIT_MS;
+	else
+		ar->restart_backoff_ms = min(ar->restart_backoff_ms * 2,
+					     (unsigned int)
+					     CARL9170_RESTART_BACKOFF_MAX_MS);
+	spin_unlock_irqrestore(&ar->state_lock, flags);
+
 	ieee80211_stop_queues(ar->hw);

 	dev_err(&ar->udev->dev, "restart device (%d)\n", r);
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index 414d499..bb909b5 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -46,6 +46,8 @@
 #include "hw.h"
 #include "cmd.h"

+#define CARL9170_FW_ERROR_THRESHOLD	4
+
 static void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len)
 {
 	bool restart = false;
@@ -54,7 +56,7 @@ static void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len)
 	if (len > 3) {
 		if (memcmp(buf, CARL9170_ERR_MAGIC, 3) == 0) {
 			ar->fw.err_counter++;
-			if (ar->fw.err_counter > 3) {
+			if (ar->fw.err_counter >= CARL9170_FW_ERROR_THRESHOLD) {
 				restart = true;
 				reason = CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS;
 			}

-- 
Regards,
Masi

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [PATCH 09/10] carl9170: fw: enable DFS radar detection
  2026-03-12 10:38 ` [PATCH 09/10] carl9170: fw: enable DFS radar detection Masi Osmani
  2026-03-21 20:11   ` Christian Lamparter
@ 2026-04-29  4:46   ` John Scott
  1 sibling, 0 replies; 33+ messages in thread
From: John Scott @ 2026-04-29  4:46 UTC (permalink / raw)
  To: Masi Osmani, Christian Lamparter; +Cc: linux-wireless, ath9k-devel

[-- Attachment #1: Type: text/plain, Size: 4857 bytes --]

Hello,
I have a question about how this fits into the wireless regulatory status quo, as someone who doesn't understand the code too well but is interested.
Currently it appears ath9k guards radar detection behind a Kconfig option, and the details look important:
> config ATH9K_DFS_CERTIFIED
> 	bool "Atheros DFS support for certified platforms"
> 	depends on ATH9K && CFG80211_CERTIFICATION_ONUS
> 	default n
> 	help
> 	  This option enables DFS support for initiating radiation on
> 	  ath9k. There is no way to dynamically detect if a card was DFS
> 	  certified and as such this is left as a build time option. This
> 	  option should only be enabled by system integrators that can
> 	  guarantee that all the platforms that their kernel will run on
> 	  have obtained appropriate regulatory body certification for a
> 	  respective Atheros card by using ath9k on the target shipping
> 	  platforms.
> 
> 	  This is currently only a placeholder for future DFS support,
> 	  as DFS support requires more components that still need to be
> 	  developed. At this point enabling this option won't do anything
> 	  except increase code size.
(I think that last paragraph is out of date—my understanding is ath9k has supported DFS for a while, at least when used in tandem with wpa_supplicant, but I've not had the pleasure to try that yet.)
I see this option depends on CFG80211_CERTIFICATION_ONUS, which, indeed, is an affirmation from the kernel configurator that this will be used in such a conforming environment. Does carl9170 need to do something similar before turning this on? From the several AR9170 NICs I have in my collection, none of them have FCC approval for radar detection as far as I know. (Does anyone know of any?)
Perhaps the sentiment of Linux Wireless folks is different now—I think ath9k was the original prototype for radar detection, anyway—but could this be a problem?

On Thu, 2026-03-12, Masi Osmani wrote:
> Enable DFS (Dynamic Frequency Selection) radar detection on the
> AR9170.  The hardware has radar detection registers (RADAR_0,
> RADAR_1, RADAR_EXT) and the firmware already sends
> CARL9170_RSP_RADAR events, but the driver never programmed the
> detection parameters and only logged a "please report" message.
> 
> Changes:
> - Program radar detection pulse parameters in phy.c when the
>   current channel has IEEE80211_CHAN_RADAR set.  Values are
>   based on ath9k defaults for FCC/ETSI compliance.
I see cfg80211.h says
> @IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
so this *appears* to affirm my mild concern that this patch is intended to permit initiating radiation on such channels. Is that right?

> - Advertise radar_detect_widths in the interface combination
>   (fw.c) for 20 MHz noHT, 20 MHz HT, and 40 MHz HT.
> - Replace the old "please report" message with a call to
>   ieee80211_radar_detected() so mac80211 can trigger the
>   proper DFS state machine (channel switch / CAC).
> 
> Signed-off-by: Masi Osmani <mas-i@hotmail.de>
> ---
>  drivers/net/wireless/ath/carl9170/fw.c  |  3 ++
>  drivers/net/wireless/ath/carl9170/phy.c | 45 +++++++++++++++++++++++++
>  drivers/net/wireless/ath/carl9170/rx.c  |  7 ++--
>  3 files changed, 50 insertions(+), 5 deletions(-)
Thus it appears no Kconfig changes were made and your changes don't guard radar detection behind a suitable preprocessor directive.

By the way, I notice in include/net/mac80211.h
/**
 * struct ieee80211_conf - configuration of the device
 *
 * This struct indicates how the driver shall configure the hardware.
 * ...
 * [bool] @radar_enabled: whether radar detection is enabled
 */
Is this .radar_enabled member something that should be checked or used as part of these changes? I don't know anymore about this code than the plain meaning of the words, but I thought I'd ask: a patch to enable radar detection seems like it ought to access such an object named "radar_enabled" at some point, right?

P.S. Although I don't have access to formal industrial testing equipment, I'm in Central Indiana, USA and I already have a couple creative ideas to put radar detection to the test, at least to assess effectiveness of the implementation. Perhaps comrades from my local Linux Users Group could join me (field trip!), if I do some more research to ascertain the frequency bands used. "It doesn't hurt to ask" 🙂
There are legitimate circumstances where DFS/radar detection can be enabled even if the FCC Part 15 certification wasn't performed for the hardware—such as when operating under rules other than conventional FCC Part 15 (some amateur radio licensees, limited non-commercial usage and experimentation). So even putting this behind something like a "CARL9170_DFS_CERTIFIED" would still be neat if we could show its usefulness

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 411 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: (subset) [PATCH 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz
  2026-03-12 10:37 ` [PATCH 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz Masi Osmani
  2026-03-21 18:41   ` Christian Lamparter
@ 2026-07-17 15:06   ` Jeff Johnson
  1 sibling, 0 replies; 33+ messages in thread
From: Jeff Johnson @ 2026-07-17 15:06 UTC (permalink / raw)
  To: Christian Lamparter, Masi Osmani; +Cc: linux-wireless, ath9k-devel


On Thu, 12 Mar 2026 11:37:56 +0100, Masi Osmani wrote:
> The AR9170 hardware supports Short Guard Interval (400ns) for both
> 20 MHz and 40 MHz channel widths.  SGI_40 was already advertised in
> the HT capabilities, but SGI_20 was missing.  This reduces the OFDM
> symbol duration from 800ns to 400ns on 20 MHz channels, increasing
> the maximum PHY rate from 130 Mbps to 144.4 Mbps (MCS 15, 2SS).
> 
> ath9k (the PCI sibling for the same AR9xxx chipset family) has
> always advertised both SGI_20 and SGI_40.
> 
> [...]

Applied, thanks!

[03/10] carl9170: mac80211: document spatial multiplexing power save handler
        commit: 031e27f95761fa3e14de4af53939a6694be1ab0a
[05/10] carl9170: rx: track PHY errors via debugfs
        commit: b2de486100b0cf7b770a2ab46e9a1c4b2b8f3fd8

Best regards,
-- 
Jeff Johnson <jeff.johnson@oss.qualcomm.com>


^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2026-07-17 15:06 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <cover.1773277728.git.mas-i@hotmail.de>
2026-03-12 10:37 ` [PATCH 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz Masi Osmani
2026-03-21 18:41   ` Christian Lamparter
2026-03-31 19:06     ` Masi Osmani
2026-03-31 19:19     ` [PATCH v2 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz (experimental) Masi Osmani
2026-07-17 15:06   ` (subset) [PATCH 01/10] carl9170: mac80211: enable Short Guard Interval for 20 MHz Jeff Johnson
2026-03-12 10:37 ` [PATCH 02/10] carl9170: mac80211: advertise RX STBC capability Masi Osmani
2026-03-21 18:47   ` Christian Lamparter
2026-03-31 19:06     ` Masi Osmani
2026-03-12 10:37 ` [PATCH 03/10] carl9170: mac80211: document spatial multiplexing power save handler Masi Osmani
2026-03-21 18:57   ` Christian Lamparter
2026-03-12 10:37 ` [PATCH 04/10] carl9170: rx: wire up dropped frame counter Masi Osmani
2026-03-21 19:03   ` Christian Lamparter
2026-03-31 19:06     ` Masi Osmani
2026-03-31 19:20     ` [PATCH v2 04/10] carl9170: rx: remove stale TODO comment in carl9170_rx_mac_status Masi Osmani
2026-03-12 10:38 ` [PATCH 05/10] carl9170: rx: track PHY errors via debugfs Masi Osmani
2026-03-21 20:29   ` Christian Lamparter
2026-03-12 10:38 ` [PATCH 06/10] carl9170: phy: populate per-channel TX power from EEPROM Masi Osmani
2026-03-21 19:24   ` Christian Lamparter
2026-03-31 19:06     ` Masi Osmani
2026-03-12 10:38 ` [PATCH 07/10] carl9170: main: add exponential restart backoff Masi Osmani
2026-03-21 20:42   ` Christian Lamparter
2026-03-31 18:58     ` Masi Osmani
2026-03-31 19:20     ` [PATCH v2 " Masi Osmani
2026-03-12 10:38 ` [PATCH 08/10] carl9170: phy: enable antenna diversity for 2-chain devices Masi Osmani
2026-03-21 19:53   ` Christian Lamparter
2026-03-31 18:58     ` Masi Osmani
2026-03-12 10:38 ` [PATCH 09/10] carl9170: fw: enable DFS radar detection Masi Osmani
2026-03-21 20:11   ` Christian Lamparter
2026-03-31 19:06     ` Masi Osmani
2026-04-29  4:46   ` John Scott
2026-03-12 10:38 ` [PATCH 10/10] carl9170: phy: add periodic runtime IQ calibration Masi Osmani
2026-03-21 21:25   ` Christian Lamparter
2026-03-31 19:06     ` Masi Osmani

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.