mac80211: Fix setting txpower to zero
authorBen Greear <greearb@candelatech.com>
Tue, 17 Dec 2019 18:30:57 +0000 (10:30 -0800)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 14 Feb 2020 08:57:00 +0000 (09:57 +0100)
With multiple VIFS ath10k, and probably others, tries to find the
minimum txpower for all vifs and uses that when setting txpower in
the firmware.

If a second vif is added and starts to scan, it's txpower is not
initialized yet and it set to zero.

ath10k had a patch to ignore zero values, but then it is impossible
to actually set txpower to zero.

So, instead initialize the txpower to INT_MIN in mac80211, and let
drivers know that means the power has not been set and so should
be ignored.

This should fix regression in:

commit 88407beb1b1462f706a1950a355fd086e1c450b6
Author: Ryan Hsu <ryanhsu@qca.qualcomm.com>
Date:   Tue Dec 13 14:55:19 2016 -0800

    ath10k: fix incorrect txpower set by P2P_DEVICE interface

Tested on ath10k 9984 with ath10k-ct firmware.

Signed-off-by: Ben Greear <greearb@candelatech.com>
Link: https://lore.kernel.org/r/20191217183057.24586-1-greearb@candelatech.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/xmit.c
include/net/mac80211.h
net/mac80211/iface.c
net/mac80211/main.c

index 7fee35f..2f820d4 100644 (file)
@@ -5103,7 +5103,8 @@ static int ath10k_mac_txpower_recalc(struct ath10k *ar)
        lockdep_assert_held(&ar->conf_mutex);
 
        list_for_each_entry(arvif, &ar->arvifs, list) {
-               if (arvif->txpower <= 0)
+               /* txpower not initialized yet? */
+               if (arvif->txpower == INT_MIN)
                        continue;
 
                if (txpower == -1)
index 0548aa3..983b6d6 100644 (file)
@@ -1196,6 +1196,9 @@ static void ath9k_tpc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
 {
        int *power = data;
 
+       if (vif->bss_conf.txpower == INT_MIN)
+               return;
+
        if (*power < vif->bss_conf.txpower)
                *power = vif->bss_conf.txpower;
 }
index 31e7b10..e60d473 100644 (file)
@@ -2095,10 +2095,13 @@ static void setup_frame_info(struct ieee80211_hw *hw,
 
        if (tx_info->control.vif) {
                struct ieee80211_vif *vif = tx_info->control.vif;
-
+               if (vif->bss_conf.txpower == INT_MIN)
+                       goto nonvifpower;
                txpower = 2 * vif->bss_conf.txpower;
        } else {
-               struct ath_softc *sc = hw->priv;
+               struct ath_softc *sc;
+       nonvifpower:
+               sc = hw->priv;
 
                txpower = sc->cur_chan->cur_txpower;
        }
index 6d4ea71..7287ad3 100644 (file)
@@ -574,7 +574,7 @@ struct ieee80211_ftm_responder_params {
  * @ssid: The SSID of the current vif. Valid in AP and IBSS mode.
  * @ssid_len: Length of SSID given in @ssid.
  * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode.
- * @txpower: TX power in dBm
+ * @txpower: TX power in dBm.  INT_MIN means not configured.
  * @txpower_type: TX power adjustment used to control per packet Transmit
  *     Power Control (TPC) in lower driver for the current vif. In particular
  *     TPC is enabled if value passed in %txpower_type is
index 2fb26bc..3c00408 100644 (file)
@@ -1465,6 +1465,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
        sdata->control_port_no_encrypt = false;
        sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
        sdata->vif.bss_conf.idle = true;
+       sdata->vif.bss_conf.txpower = INT_MIN; /* unset */
 
        sdata->noack_map = 0;
        sdata->hw_80211_encap = false;
index 265a31a..cae3a34 100644 (file)
@@ -146,6 +146,8 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
                        continue;
                if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                        continue;
+               if (sdata->vif.bss_conf.txpower == INT_MIN)
+                       continue;
                power = min(power, sdata->vif.bss_conf.txpower);
        }
        rcu_read_unlock();