mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-10 21:14:56 -04:00
wifi: iwlwifi: move dBm averaging function into utils
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
This commit is contained in:
committed by
Miri Korenblit
parent
8ecc3928f2
commit
40840afa53
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)/../
|
||||
|
||||
|
||||
@@ -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(¬if),
|
||||
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(¬if),
|
||||
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);
|
||||
Reference in New Issue
Block a user