Skip to content

Commit

Permalink
wifi: iwlwifi: mvm: implement new firmware API for statistics
Browse files Browse the repository at this point in the history
The new firmware API uses a new command and notification,
the command configures in which statistics types driver is
interested and the notification is sent periodically.
An additional change in the API is that most of the statistics
data is accumulated and reported by the firmware per MLO link.
Implement new command and notification handlers and adjust to
per-link statistics.

Signed-off-by: Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20231022173519.8cc7df0ebff2.If1dcb57145841c5b3c68ed112bbfcd0201f7acc3@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
  • Loading branch information
panjaney authored and jmberg-intel committed Oct 23, 2023
1 parent ea02a20 commit b6e3d1b
Show file tree
Hide file tree
Showing 8 changed files with 451 additions and 38 deletions.
30 changes: 30 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
* @REGULATORY_AND_NVM_GROUP: regulatory/NVM group, uses command IDs from
* &enum iwl_regulatory_and_nvm_subcmd_ids
* @DEBUG_GROUP: Debug group, uses command IDs from &enum iwl_debug_cmds
* @STATISTICS_GROUP: Statistics group, uses command IDs from
* &enum iwl_statistics_subcmd_ids
*/
enum iwl_mvm_command_groups {
LEGACY_GROUP = 0x0,
Expand All @@ -44,6 +46,7 @@ enum iwl_mvm_command_groups {
PROT_OFFLOAD_GROUP = 0xb,
REGULATORY_AND_NVM_GROUP = 0xc,
DEBUG_GROUP = 0xf,
STATISTICS_GROUP = 0x10,
};

/**
Expand Down Expand Up @@ -616,10 +619,37 @@ enum iwl_system_subcmd_ids {
*/
SYSTEM_FEATURES_CONTROL_CMD = 0xd,

/**
* @SYSTEM_STATISTICS_CMD: &struct iwl_system_statistics_cmd
*/
SYSTEM_STATISTICS_CMD = 0xf,

/**
* @SYSTEM_STATISTICS_END_NOTIF: &struct iwl_system_statistics_end_notif
*/
SYSTEM_STATISTICS_END_NOTIF = 0xfd,

/**
* @RFI_DEACTIVATE_NOTIF: &struct iwl_rfi_deactivate_notif
*/
RFI_DEACTIVATE_NOTIF = 0xff,
};

/**
* enum iwl_statistics_subcmd_ids - Statistics group command IDs
*/
enum iwl_statistics_subcmd_ids {
/**
* @STATISTICS_OPER_NOTIF: Notification about operational
* statistics &struct iwl_system_statistics_notif_oper
*/
STATISTICS_OPER_NOTIF = 0x0,

/**
* @STATISTICS_OPER_PART1_NOTIF: Notification about operational part1
* statistics &struct iwl_system_statistics_part1_notif_oper
*/
STATISTICS_OPER_PART1_NOTIF = 0x1,
};

#endif /* __iwl_fw_api_commands_h__ */
153 changes: 139 additions & 14 deletions drivers/net/wireless/intel/iwlwifi/fw/api/stats.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2012-2014, 2018, 2020 - 2021 Intel Corporation
* Copyright (C) 2012-2014, 2018, 2020 - 2021, 2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
#ifndef __iwl_fw_api_stats_h__
#define __iwl_fw_api_stats_h__
#include "mac.h"
#include "mac-cfg.h"

struct mvm_statistics_dbg {
__le32 burst_check;
Expand Down Expand Up @@ -411,6 +412,49 @@ struct iwl_statistics_cmd {

#define MAX_BCAST_FILTER_NUM 8

/**
* enum iwl_statistics_notify_type_id - type_id used in system statistics
* command
* @IWL_STATS_NTFY_TYPE_ID_OPER: request legacy statistics
* @IWL_STATS_NTFY_TYPE_ID_OPER_PART1: request operational part1 statistics
* @IWL_STATS_NTFY_TYPE_ID_OPER_PART2: request operational part2 statistics
* @IWL_STATS_NTFY_TYPE_ID_OPER_PART3: request operational part3 statistics
* @IWL_STATS_NTFY_TYPE_ID_OPER_PART4: request operational part4 statistics
*/
enum iwl_statistics_notify_type_id {
IWL_STATS_NTFY_TYPE_ID_OPER = BIT(0),
IWL_STATS_NTFY_TYPE_ID_OPER_PART1 = BIT(1),
IWL_STATS_NTFY_TYPE_ID_OPER_PART2 = BIT(2),
IWL_STATS_NTFY_TYPE_ID_OPER_PART3 = BIT(3),
IWL_STATS_NTFY_TYPE_ID_OPER_PART4 = BIT(4),
};

/**
* enum iwl_statistics_cfg_flags - cfg_mask used in system statistics command
* @IWL_STATS_CFG_FLG_DISABLE_NTFY_MSK: 0 for enable, 1 for disable
* @IWL_STATS_CFG_FLG_ON_DEMAND_NTFY_MSK: 0 for periodic, 1 for on-demand
* @IWL_STATS_CFG_FLG_RESET_MSK: 0 for reset statistics after
* sending the notification, 1 for do not reset statistics after sending
* the notification
*/
enum iwl_statistics_cfg_flags {
IWL_STATS_CFG_FLG_DISABLE_NTFY_MSK = BIT(0),
IWL_STATS_CFG_FLG_ON_DEMAND_NTFY_MSK = BIT(1),
IWL_STATS_CFG_FLG_RESET_MSK = BIT(2),
};

/**
* struct iwl_system_statistics_cmd - system statistics command
* @cfg_mask: configuration mask, &enum iwl_statistics_cfg_flags
* @config_time_sec: time in sec for periodic notification
* @type_id_mask: type_id masks, &enum iwl_statistics_notify_type_id
*/
struct iwl_system_statistics_cmd {
__le32 cfg_mask;
__le32 config_time_sec;
__le32 type_id_mask;
} __packed; /* STATISTICS_FW_CMD_API_S_VER_1 */

/**
* enum iwl_fw_statistics_type
*
Expand Down Expand Up @@ -447,7 +491,49 @@ struct iwl_statistics_ntfy_hdr {
}; /* STATISTICS_NTFY_HDR_API_S_VER_1 */

/**
* struct iwl_statistics_ntfy_per_mac
* struct iwl_stats_ntfy_per_link
*
* @beacon_filter_average_energy: Average energy [-dBm] of the 2
* antennas.
* @air_time: air time
* @beacon_counter: all beacons (both filtered and not filtered)
* @beacon_average_energy: Average energy [-dBm] of all beacons
* (both filtered and not filtered)
* @beacon_rssi_a: beacon RSSI on antenna A
* @beacon_rssi_b: beacon RSSI on antenna B
* @rx_bytes: RX byte count
*/
struct iwl_stats_ntfy_per_link {
__le32 beacon_filter_average_energy;
__le32 air_time;
__le32 beacon_counter;
__le32 beacon_average_energy;
__le32 beacon_rssi_a;
__le32 beacon_rssi_b;
__le32 rx_bytes;
} __packed; /* STATISTICS_NTFY_PER_LINK_API_S_VER_1 */

/**
* struct iwl_stats_ntfy_part1_per_link
*
* @rx_time: rx time
* @tx_time: tx time
* @rx_action: action frames handled by FW
* @tx_action: action frames generated and transmitted by FW
* @cca_defers: cca defer count
* @beacon_filtered: filtered out beacons
*/
struct iwl_stats_ntfy_part1_per_link {
__le64 rx_time;
__le64 tx_time;
__le32 rx_action;
__le32 tx_action;
__le32 cca_defers;
__le32 beacon_filtered;
} __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_PART1_PER_LINK_API_S_VER_1 */

/**
* struct iwl_stats_ntfy_per_mac
*
* @beacon_filter_average_energy: Average energy [-dBm] of the 2
* antennas.
Expand All @@ -459,7 +545,7 @@ struct iwl_statistics_ntfy_hdr {
* @beacon_rssi_b: beacon RSSI on antenna B
* @rx_bytes: RX byte count
*/
struct iwl_statistics_ntfy_per_mac {
struct iwl_stats_ntfy_per_mac {
__le32 beacon_filter_average_energy;
__le32 air_time;
__le32 beacon_counter;
Expand All @@ -470,7 +556,7 @@ struct iwl_statistics_ntfy_per_mac {
} __packed; /* STATISTICS_NTFY_PER_MAC_API_S_VER_1 */

#define IWL_STATS_MAX_BW_INDEX 5
/** struct iwl_statistics_ntfy_per_phy
/** struct iwl_stats_ntfy_per_phy
* @channel_load: channel load
* @channel_load_by_us: device contribution to MCLM
* @channel_load_not_by_us: other devices' contribution to MCLM
Expand All @@ -485,7 +571,7 @@ struct iwl_statistics_ntfy_per_mac {
* per channel BW. note BACK counted as 1
* @last_tx_ch_width_indx: last txed frame channel width index
*/
struct iwl_statistics_ntfy_per_phy {
struct iwl_stats_ntfy_per_phy {
__le32 channel_load;
__le32 channel_load_by_us;
__le32 channel_load_not_by_us;
Expand All @@ -499,23 +585,62 @@ struct iwl_statistics_ntfy_per_phy {
} __packed; /* STATISTICS_NTFY_PER_PHY_API_S_VER_1 */

/**
* struct iwl_statistics_ntfy_per_sta
* struct iwl_stats_ntfy_per_sta
*
* @average_energy: in fact it is minus the energy..
*/
struct iwl_statistics_ntfy_per_sta {
struct iwl_stats_ntfy_per_sta {
__le32 average_energy;
} __packed; /* STATISTICS_NTFY_PER_STA_API_S_VER_1 */

#define IWL_STATS_MAX_PHY_OPERTINAL 3
#define IWL_STATS_MAX_PHY_OPERATIONAL 3
#define IWL_STATS_MAX_FW_LINKS (IWL_MVM_FW_MAX_LINK_ID + 1)

/**
* struct iwl_system_statistics_notif_oper
*
* @time_stamp: time when the notification is sent from firmware
* @per_link: per link statistics, &struct iwl_stats_ntfy_per_link
* @per_phy: per phy statistics, &struct iwl_stats_ntfy_per_phy
* @per_sta: per sta statistics, &struct iwl_stats_ntfy_per_sta
*/
struct iwl_system_statistics_notif_oper {
__le32 time_stamp;
struct iwl_stats_ntfy_per_link per_link[IWL_STATS_MAX_FW_LINKS];
struct iwl_stats_ntfy_per_phy per_phy[IWL_STATS_MAX_PHY_OPERATIONAL];
struct iwl_stats_ntfy_per_sta per_sta[IWL_MVM_STATION_COUNT_MAX];
} __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_API_S_VER_3 */

/**
* struct iwl_system_statistics_part1_notif_oper
*
* @time_stamp: time when the notification is sent from firmware
* @per_link: per link statistics &struct iwl_stats_ntfy_part1_per_link
* @per_phy_crc_error_stats: per phy crc error statistics
*/
struct iwl_system_statistics_part1_notif_oper {
__le32 time_stamp;
struct iwl_stats_ntfy_part1_per_link per_link[IWL_STATS_MAX_FW_LINKS];
__le32 per_phy_crc_error_stats[IWL_STATS_MAX_PHY_OPERATIONAL];
} __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_PART1_API_S_VER_4 */

/**
* struct iwl_system_statistics_end_notif
*
* @time_stamp: time when the notification is sent from firmware
*/
struct iwl_system_statistics_end_notif {
__le32 time_stamp;
} __packed; /* STATISTICS_FW_NTFY_END_API_S_VER_1 */

/**
* struct iwl_statistics_operational_ntfy
*
* @hdr: general statistics header
* @flags: bitmap of possible notification structures
* @per_mac_stats: per mac statistics, &struct iwl_statistics_ntfy_per_mac
* @per_phy_stats: per phy statistics, &struct iwl_statistics_ntfy_per_phy
* @per_sta_stats: per sta statistics, &struct iwl_statistics_ntfy_per_sta
* @per_mac: per mac statistics, &struct iwl_stats_ntfy_per_mac
* @per_phy: per phy statistics, &struct iwl_stats_ntfy_per_phy
* @per_sta: per sta statistics, &struct iwl_stats_ntfy_per_sta
* @rx_time: rx time
* @tx_time: usec the radio is transmitting.
* @on_time_rf: The total time in usec the RF is awake.
Expand All @@ -524,9 +649,9 @@ struct iwl_statistics_ntfy_per_sta {
struct iwl_statistics_operational_ntfy {
struct iwl_statistics_ntfy_hdr hdr;
__le32 flags;
struct iwl_statistics_ntfy_per_mac per_mac_stats[MAC_INDEX_AUX];
struct iwl_statistics_ntfy_per_phy per_phy_stats[IWL_STATS_MAX_PHY_OPERTINAL];
struct iwl_statistics_ntfy_per_sta per_sta_stats[IWL_MVM_STATION_COUNT_MAX];
struct iwl_stats_ntfy_per_mac per_mac[MAC_INDEX_AUX];
struct iwl_stats_ntfy_per_phy per_phy[IWL_STATS_MAX_PHY_OPERATIONAL];
struct iwl_stats_ntfy_per_sta per_sta[IWL_MVM_STATION_COUNT_MAX];
__le64 rx_time;
__le64 tx_time;
__le64 on_time_rf;
Expand Down
46 changes: 31 additions & 15 deletions drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -1539,6 +1539,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
int i;

mutex_lock(&mvm->mutex);

Expand All @@ -1555,8 +1556,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,

/* make sure that beacon statistics don't go backwards with FW reset */
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
mvmvif->deflink.beacon_stats.accu_num_beacons +=
mvmvif->deflink.beacon_stats.num_beacons;
for_each_mvm_vif_valid_link(mvmvif, i)
mvmvif->link[i]->beacon_stats.accu_num_beacons +=
mvmvif->link[i]->beacon_stats.num_beacons;

/* Allocate resources for the MAC context, and add it to the fw */
ret = iwl_mvm_mac_ctxt_init(mvm, vif);
Expand Down Expand Up @@ -2581,6 +2583,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
int i;

/*
* Re-calculate the tsf id, as the leader-follower relations depend
Expand Down Expand Up @@ -2627,8 +2630,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
if (vif->cfg.assoc) {
/* clear statistics to get clean beacon counter */
iwl_mvm_request_statistics(mvm, true);
memset(&mvmvif->deflink.beacon_stats, 0,
sizeof(mvmvif->deflink.beacon_stats));
for_each_mvm_vif_valid_link(mvmvif, i)
memset(&mvmvif->link[i]->beacon_stats, 0,
sizeof(mvmvif->link[i]->beacon_stats));

/* add quota for this interface */
ret = iwl_mvm_update_quotas(mvm, true, NULL);
Expand Down Expand Up @@ -5726,7 +5730,11 @@ int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret;
int ret = 0;
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,
WIDE_ID(SYSTEM_GROUP,
SYSTEM_STATISTICS_CMD),
IWL_FW_CMD_VER_UNKNOWN);

memset(survey, 0, sizeof(*survey));

Expand All @@ -5746,13 +5754,8 @@ int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
goto out;
}

survey->filled = SURVEY_INFO_TIME |
SURVEY_INFO_TIME_RX |
SURVEY_INFO_TIME_TX |
SURVEY_INFO_TIME_SCAN;
survey->time = mvm->accu_radio_stats.on_time_rf +
mvm->radio_stats.on_time_rf;
do_div(survey->time, USEC_PER_MSEC);
survey->filled = SURVEY_INFO_TIME_RX |
SURVEY_INFO_TIME_TX;

survey->time_rx = mvm->accu_radio_stats.rx_time +
mvm->radio_stats.rx_time;
Expand All @@ -5762,11 +5765,20 @@ int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
mvm->radio_stats.tx_time;
do_div(survey->time_tx, USEC_PER_MSEC);

/* the new fw api doesn't support the following fields */
if (cmd_ver != IWL_FW_CMD_VER_UNKNOWN)
goto out;

survey->filled |= SURVEY_INFO_TIME |
SURVEY_INFO_TIME_SCAN;
survey->time = mvm->accu_radio_stats.on_time_rf +
mvm->radio_stats.on_time_rf;
do_div(survey->time, USEC_PER_MSEC);

survey->time_scan = mvm->accu_radio_stats.on_time_scan +
mvm->radio_stats.on_time_scan;
do_div(survey->time_scan, USEC_PER_MSEC);

ret = 0;
out:
mutex_unlock(&mvm->mutex);
return ret;
Expand Down Expand Up @@ -5915,6 +5927,7 @@ void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
int i;

if (mvmsta->deflink.avg_energy) {
sinfo->signal_avg = -(s8)mvmsta->deflink.avg_energy;
Expand Down Expand Up @@ -5943,8 +5956,11 @@ void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
if (iwl_mvm_request_statistics(mvm, false))
goto unlock;

sinfo->rx_beacon = mvmvif->deflink.beacon_stats.num_beacons +
mvmvif->deflink.beacon_stats.accu_num_beacons;
sinfo->rx_beacon = 0;
for_each_mvm_vif_valid_link(mvmvif, i)
sinfo->rx_beacon += mvmvif->link[i]->beacon_stats.num_beacons +
mvmvif->link[i]->beacon_stats.accu_num_beacons;

sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_RX);
if (mvmvif->deflink.beacon_stats.avg_signal) {
/* firmware only reports a value after RXing a few beacons */
Expand Down
Loading

0 comments on commit b6e3d1b

Please sign in to comment.