]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: iwlwifi: move dBm averaging function into utils
authorBenjamin Berg <benjamin.berg@intel.com>
Mon, 9 Jun 2025 18:21:18 +0000 (21:21 +0300)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Wed, 25 Jun 2025 07:57:32 +0000 (10:57 +0300)
The function really is just a simple math helper. Move it into
iwl-utils.c so that it can also be used by iwlmld.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250609211928.8cc965af6990.I09bb2137863e888efe756c92d8eb0271ec95456c@changeid
drivers/net/wireless/intel/iwlwifi/Kconfig
drivers/net/wireless/intel/iwlwifi/iwl-utils.c
drivers/net/wireless/intel/iwlwifi/iwl-utils.h
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/scan.c
drivers/net/wireless/intel/iwlwifi/mvm/tests/Makefile
drivers/net/wireless/intel/iwlwifi/tests/Makefile
drivers/net/wireless/intel/iwlwifi/tests/utils.c [moved from drivers/net/wireless/intel/iwlwifi/mvm/tests/scan.c with 63% similarity]

index 82f577da1a8b57eae1cb32c1da1ee054688c6af9..153a8368b4127d6c033f6dc2d46f2258f0387574 100644 (file)
@@ -97,6 +97,7 @@ config IWLWIFI_OPMODE_MODULAR
        default y if IWLDVM=m
        default y if IWLMVM=m
        default y if IWLMLD=m
+       default y if IWLWIFI_KUNIT_TESTS=m
 
 comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM or IWLMLD"
        depends on IWLDVM=n && IWLMVM=n && IWLMLD=n
index c5b49851e4b980fa1a9866158fe114f25bde54e8..d503544fda40cda954b088a987b1ad2e1ed9f986 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2024 Intel Corporation
+ * Copyright (C) 2024-2025 Intel Corporation
  */
 #include <net/gso.h>
 #include <linux/ieee80211.h>
@@ -82,3 +82,114 @@ int iwl_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
 }
 IWL_EXPORT_SYMBOL(iwl_tx_tso_segment);
 #endif /* CONFIG_INET */
+
+static u32 iwl_div_by_db(u32 value, u8 db)
+{
+       /*
+        * 2^32 * 10**(i / 10) for i = [1, 10], skipping 0 and simply stopping
+        * at 10 dB and looping instead of using a much larger table.
+        *
+        * Using 64 bit math is overkill, but means the helper does not require
+        * a limit on the input range.
+        */
+       static const u32 db_to_val[] = {
+               0xcb59185e, 0xa1866ba8, 0x804dce7a, 0x65ea59fe, 0x50f44d89,
+               0x404de61f, 0x331426af, 0x2892c18b, 0x203a7e5b, 0x1999999a,
+       };
+
+       while (value && db > 0) {
+               u8 change = min_t(u8, db, ARRAY_SIZE(db_to_val));
+
+               value = (((u64)value) * db_to_val[change - 1]) >> 32;
+
+               db -= change;
+       }
+
+       return value;
+}
+
+s8 iwl_average_neg_dbm(const u8 *neg_dbm_values, u8 len)
+{
+       int average_magnitude;
+       u32 average_factor;
+       int sum_magnitude = -128;
+       u32 sum_factor = 0;
+       int i, count = 0;
+
+       /*
+        * To properly average the decibel values (signal values given in dBm)
+        * we need to do the math in linear space.  Doing a linear average of
+        * dB (dBm) values is a bit annoying though due to the large range of
+        * at least -10 to -110 dBm that will not fit into a 32 bit integer.
+        *
+        * A 64 bit integer should be sufficient, but then we still have the
+        * problem that there are no directly usable utility functions
+        * available.
+        *
+        * So, lets not deal with that and instead do much of the calculation
+        * with a 16.16 fixed point integer along with a base in dBm. 16.16 bit
+        * gives us plenty of head-room for adding up a few values and even
+        * doing some math on it. And the tail should be accurate enough too
+        * (1/2^16 is somewhere around -48 dB, so effectively zero).
+        *
+        * i.e. the real value of sum is:
+        *      sum = sum_factor / 2^16 * 10^(sum_magnitude / 10) mW
+        *
+        * However, that does mean we need to be able to bring two values to
+        * a common base, so we need a helper for that.
+        *
+        * Note that this function takes an input with unsigned negative dBm
+        * values but returns a signed dBm (i.e. a negative value).
+        */
+
+       for (i = 0; i < len; i++) {
+               int val_magnitude;
+               u32 val_factor;
+
+               /* Assume invalid */
+               if (neg_dbm_values[i] == 0xff)
+                       continue;
+
+               val_factor = 0x10000;
+               val_magnitude = -neg_dbm_values[i];
+
+               if (val_magnitude <= sum_magnitude) {
+                       u8 div_db = sum_magnitude - val_magnitude;
+
+                       val_factor = iwl_div_by_db(val_factor, div_db);
+                       val_magnitude = sum_magnitude;
+               } else {
+                       u8 div_db = val_magnitude - sum_magnitude;
+
+                       sum_factor = iwl_div_by_db(sum_factor, div_db);
+                       sum_magnitude = val_magnitude;
+               }
+
+               sum_factor += val_factor;
+               count++;
+       }
+
+       /* No valid noise measurement, return a very high noise level */
+       if (count == 0)
+               return 0;
+
+       average_magnitude = sum_magnitude;
+       average_factor = sum_factor / count;
+
+       /*
+        * average_factor will be a number smaller than 1.0 (0x10000) at this
+        * point. What we need to do now is to adjust average_magnitude so that
+        * average_factor is between -0.5 dB and 0.5 dB.
+        *
+        * Just do -1 dB steps and find the point where
+        *   -0.5 dB * -i dB = 0x10000 * 10^(-0.5/10) / i dB
+        *                   = div_by_db(0xe429, i)
+        * is smaller than average_factor.
+        */
+       for (i = 0; average_factor < iwl_div_by_db(0xe429, i); i++) {
+               /* nothing */
+       }
+
+       return clamp(average_magnitude - i, -128, 0);
+}
+IWL_EXPORT_SYMBOL(iwl_average_neg_dbm);
index 8f1f11d06fbe1cf1439fdc969fa96a156169e144..5172035e4d26934d449e5575fa6249be1f1e6e67 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2024 Intel Corporation
+ * Copyright (C) 2024-2025 Intel Corporation
  */
 #ifndef __iwl_utils_h__
 #define __iwl_utils_h__
@@ -53,4 +53,6 @@ u32 iwl_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size)
        return ie - beacon;
 }
 
+s8 iwl_average_neg_dbm(const u8 *neg_dbm_values, u8 len);
+
 #endif /* __iwl_utils_h__ */
index a4f412e750d070d9b9bfeea021cd55ec39670d1d..e8419a2e4c4ba6cabea4cb2b7b56a27a384543f0 100644 (file)
@@ -2133,7 +2133,6 @@ bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif,
 
 s8 iwl_mvm_average_dbm_values(const struct iwl_umac_scan_channel_survey_notif *notif);
 
-
 extern const struct iwl_hcmd_arr iwl_mvm_groups[];
 extern const unsigned int iwl_mvm_groups_size;
 #endif
index 60bd9c7e5f03d813e9183184338b2e714c421475..5f30109ca18fae41d16d1e37865340e811b818c1 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2012-2014, 2018-2024 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2025 Intel Corporation
  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
  * Copyright (C) 2016-2017 Intel Deutschland GmbH
  */
@@ -11,6 +11,7 @@
 #include "mvm.h"
 #include "fw/api/scan.h"
 #include "iwl-io.h"
+#include "iwl-utils.h"
 
 #define IWL_DENSE_EBS_SCAN_RATIO 5
 #define IWL_SPARSE_EBS_SCAN_RATIO 1
@@ -3685,117 +3686,6 @@ static int iwl_mvm_chanidx_from_phy(struct iwl_mvm *mvm,
        return -EINVAL;
 }
 
-static u32 iwl_mvm_div_by_db(u32 value, u8 db)
-{
-       /*
-        * 2^32 * 10**(i / 10) for i = [1, 10], skipping 0 and simply stopping
-        * at 10 dB and looping instead of using a much larger table.
-        *
-        * Using 64 bit math is overkill, but means the helper does not require
-        * a limit on the input range.
-        */
-       static const u32 db_to_val[] = {
-               0xcb59185e, 0xa1866ba8, 0x804dce7a, 0x65ea59fe, 0x50f44d89,
-               0x404de61f, 0x331426af, 0x2892c18b, 0x203a7e5b, 0x1999999a,
-       };
-
-       while (value && db > 0) {
-               u8 change = min_t(u8, db, ARRAY_SIZE(db_to_val));
-
-               value = (((u64)value) * db_to_val[change - 1]) >> 32;
-
-               db -= change;
-       }
-
-       return value;
-}
-
-VISIBLE_IF_IWLWIFI_KUNIT s8
-iwl_mvm_average_dbm_values(const struct iwl_umac_scan_channel_survey_notif *notif)
-{
-       s8 average_magnitude;
-       u32 average_factor;
-       s8 sum_magnitude = -128;
-       u32 sum_factor = 0;
-       int i, count = 0;
-
-       /*
-        * To properly average the decibel values (signal values given in dBm)
-        * we need to do the math in linear space.  Doing a linear average of
-        * dB (dBm) values is a bit annoying though due to the large range of
-        * at least -10 to -110 dBm that will not fit into a 32 bit integer.
-        *
-        * A 64 bit integer should be sufficient, but then we still have the
-        * problem that there are no directly usable utility functions
-        * available.
-        *
-        * So, lets not deal with that and instead do much of the calculation
-        * with a 16.16 fixed point integer along with a base in dBm. 16.16 bit
-        * gives us plenty of head-room for adding up a few values and even
-        * doing some math on it. And the tail should be accurate enough too
-        * (1/2^16 is somewhere around -48 dB, so effectively zero).
-        *
-        * i.e. the real value of sum is:
-        *      sum = sum_factor / 2^16 * 10^(sum_magnitude / 10) mW
-        *
-        * However, that does mean we need to be able to bring two values to
-        * a common base, so we need a helper for that.
-        *
-        * Note that this function takes an input with unsigned negative dBm
-        * values but returns a signed dBm (i.e. a negative value).
-        */
-
-       for (i = 0; i < ARRAY_SIZE(notif->noise); i++) {
-               s8 val_magnitude;
-               u32 val_factor;
-
-               if (notif->noise[i] == 0xff)
-                       continue;
-
-               val_factor = 0x10000;
-               val_magnitude = -notif->noise[i];
-
-               if (val_magnitude <= sum_magnitude) {
-                       u8 div_db = sum_magnitude - val_magnitude;
-
-                       val_factor = iwl_mvm_div_by_db(val_factor, div_db);
-                       val_magnitude = sum_magnitude;
-               } else {
-                       u8 div_db = val_magnitude - sum_magnitude;
-
-                       sum_factor = iwl_mvm_div_by_db(sum_factor, div_db);
-                       sum_magnitude = val_magnitude;
-               }
-
-               sum_factor += val_factor;
-               count++;
-       }
-
-       /* No valid noise measurement, return a very high noise level */
-       if (count == 0)
-               return 0;
-
-       average_magnitude = sum_magnitude;
-       average_factor = sum_factor / count;
-
-       /*
-        * average_factor will be a number smaller than 1.0 (0x10000) at this
-        * point. What we need to do now is to adjust average_magnitude so that
-        * average_factor is between -0.5 dB and 0.5 dB.
-        *
-        * Just do -1 dB steps and find the point where
-        *   -0.5 dB * -i dB = 0x10000 * 10^(-0.5/10) / i dB
-        *                   = div_by_db(0xe429, i)
-        * is smaller than average_factor.
-        */
-       for (i = 0; average_factor < iwl_mvm_div_by_db(0xe429, i); i++) {
-               /* nothing */
-       }
-
-       return average_magnitude - i;
-}
-EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_average_dbm_values);
-
 void iwl_mvm_rx_channel_survey_notif(struct iwl_mvm *mvm,
                                     struct iwl_rx_cmd_buffer *rxb)
 {
@@ -3853,5 +3743,6 @@ void iwl_mvm_rx_channel_survey_notif(struct iwl_mvm *mvm,
        info->time_busy = le32_to_cpu(notif->busy_time);
        info->time_rx = le32_to_cpu(notif->rx_time);
        info->time_tx = le32_to_cpu(notif->tx_time);
-       info->noise = iwl_mvm_average_dbm_values(notif);
+       info->noise =
+               iwl_average_neg_dbm(notif->noise, ARRAY_SIZE(notif->noise));
 }
index 895d53f223e91f46ecc20c1f213941708301a2b6..bb33f4a06f1c4aed61ed39337ae53efaba85c89d 100644 (file)
@@ -1,3 +1,3 @@
-iwlmvm-tests-y += module.o links.o scan.o hcmd.o
+iwlmvm-tests-y += module.o links.o hcmd.o
 
 obj-$(CONFIG_IWLWIFI_KUNIT_TESTS) += iwlmvm-tests.o
index 84491488f5892669939514957f40d07b506f6c92..1b49241c578f4829d26f7f526dc54414aef9bb83 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 
-iwlwifi-tests-y += module.o devinfo.o
+iwlwifi-tests-y += module.o devinfo.o utils.o
 
 ccflags-y += -I$(src)/../
 
similarity index 63%
rename from drivers/net/wireless/intel/iwlwifi/mvm/tests/scan.c
rename to drivers/net/wireless/intel/iwlwifi/tests/utils.c
index 7a3275199ace2e4c51dbf22c613ba622b7c768c0..df2c3a891e7e880effcc6c2e26b2b500c5ed9704 100644 (file)
@@ -1,20 +1,19 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * KUnit tests for channel helper functions
+ * KUnit tests for utilities
  *
- * Copyright (C) 2024 Intel Corporation
+ * Copyright (C) 2024-2025 Intel Corporation
  */
-#include <net/mac80211.h>
-#include "../mvm.h"
+#include "../iwl-utils.h"
 #include <kunit/test.h>
 
-MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
+MODULE_IMPORT_NS("IWLWIFI");
 
-static const struct acs_average_db_case {
+static const struct average_neg_db_case {
        const char *desc;
        u8 neg_dbm[22];
        s8 result;
-} acs_average_db_cases[] = {
+} average_neg_db_cases[] = {
        {
                .desc = "Smallest possible value, all filled",
                .neg_dbm = {
@@ -73,38 +72,38 @@ static const struct acs_average_db_case {
        },
 };
 
-KUNIT_ARRAY_PARAM_DESC(acs_average_db, acs_average_db_cases, desc)
+KUNIT_ARRAY_PARAM_DESC(average_neg_db, average_neg_db_cases, desc)
 
-static void test_acs_average_db(struct kunit *test)
+static void test_average_neg_db(struct kunit *test)
 {
-       const struct acs_average_db_case *params = test->param_value;
-       struct iwl_umac_scan_channel_survey_notif notif;
+       const struct average_neg_db_case *params = test->param_value;
+       u8 reversed[ARRAY_SIZE(params->neg_dbm)];
        int i;
 
        /* Test the values in the given order */
-       for (i = 0; i < ARRAY_SIZE(params->neg_dbm); i++)
-               notif.noise[i] = params->neg_dbm[i];
        KUNIT_ASSERT_EQ(test,
-                       iwl_mvm_average_dbm_values(&notif),
+                       iwl_average_neg_dbm(params->neg_dbm,
+                                           ARRAY_SIZE(params->neg_dbm)),
                        params->result);
 
        /* Test in reverse order */
        for (i = 0; i < ARRAY_SIZE(params->neg_dbm); i++)
-               notif.noise[ARRAY_SIZE(params->neg_dbm) - i - 1] =
+               reversed[ARRAY_SIZE(params->neg_dbm) - i - 1] =
                        params->neg_dbm[i];
        KUNIT_ASSERT_EQ(test,
-                       iwl_mvm_average_dbm_values(&notif),
+                       iwl_average_neg_dbm(reversed,
+                                           ARRAY_SIZE(params->neg_dbm)),
                        params->result);
 }
 
-static struct kunit_case acs_average_db_case[] = {
-       KUNIT_CASE_PARAM(test_acs_average_db, acs_average_db_gen_params),
+static struct kunit_case average_db_case[] = {
+       KUNIT_CASE_PARAM(test_average_neg_db, average_neg_db_gen_params),
        {}
 };
 
-static struct kunit_suite acs_average_db = {
-       .name = "iwlmvm-acs-average-db",
-       .test_cases = acs_average_db_case,
+static struct kunit_suite average_db = {
+       .name = "iwl-average-db",
+       .test_cases = average_db_case,
 };
 
-kunit_test_suite(acs_average_db);
+kunit_test_suite(average_db);