qcacld-3.0: Support congestion report on multiple interfaces

Support congestion report on multiple interfaces

Change-Id: Iff650519c5b0e48ad63bb0a05d1c736ec40b385d
CRs-Fixed: 2832477
This commit is contained in:
Paul Zhang
2021-04-08 14:56:34 +08:00
committed by snandini
父節點 d1f7201b35
當前提交 84c234f62f
共有 9 個文件被更改,包括 441 次插入232 次删除

查看文件

@@ -204,12 +204,27 @@ struct big_data_stats_event {
uint32_t last_tx_data_rate_kbps;
};
/**
* struct medium_assess_data - medium assess data from firmware
* @part1_valid: the flag for part1 data
* @cycle_count: accumulative cycle count (total time)
* @rx_clear_count: accumulative rx clear count (busy time)
* @tx_frame_count: accumulative tx frame count (total time)
*/
struct medium_assess_data {
/* part1 data */
uint8_t part1_valid;
uint32_t cycle_count;
uint32_t rx_clear_count;
uint32_t tx_frame_count;
};
/**
* struct request_info: details of each request
* @cookie: identifier for os_if request
* @u: unified data type for callback to process tx power/peer rssi/
* station stats/mib stats/peer stats request when response comes and
* notification callback when congestion is detected.
* congestion notification callback.
* @vdev_id: vdev_id of request
* @pdev_id: pdev_id of request
* @peer_mac_addr: peer mac address
@@ -226,7 +241,7 @@ struct request_info {
void (*get_peer_stats_cb)(struct stats_event *ev,
void *cookie);
void (*congestion_notif_cb)(uint8_t vdev_id,
uint8_t congestion);
struct medium_assess_data *data);
#ifdef WLAN_FEATURE_BIG_DATA_STATS
void (*get_big_data_stats_cb)(struct big_data_stats_event *ev,
void *cookie);
@@ -274,19 +289,17 @@ struct psoc_mc_cp_stats {
/**
* struct pdev_mc_cp_stats: pdev specific stats
* @max_pwr: max tx power for pdev
* @congestion: percentage of congestion = (busy_time / total_time) * 100
* @congestion_threshold: threshold for congestion precentage of pdev
* @pdev_id: pdev id
* @rx_clear_count: accumulative rx clear count (busy time) of pdev
* @cycle_count: accumulative cycle count (total time) of pdev
* @tx_frame_count: accumulative tx frame count (total time) of pdev
*/
struct pdev_mc_cp_stats {
int32_t max_pwr;
#ifdef WLAN_FEATURE_MEDIUM_ASSESS
uint8_t congestion;
uint8_t congestion_threshold;
uint32_t pdev_id;
uint32_t rx_clear_count;
uint32_t cycle_count;
#endif
uint32_t tx_frame_count;
};
/**

查看文件

@@ -191,43 +191,6 @@ wlan_cfg80211_mc_twt_get_infra_cp_stats(struct wlan_objmgr_vdev *vdev,
QDF_STATUS ucfg_mc_cp_stats_get_tx_power(struct wlan_objmgr_vdev *vdev,
int *dbm);
#ifdef WLAN_FEATURE_MEDIUM_ASSESS
/**
* ucfg_mc_cp_stats_reset_congestion_counter() - API to reset congestion
* counter
* @vdev: pointer to vdev object
*
* Return: status of operation
*/
QDF_STATUS
ucfg_mc_cp_stats_reset_congestion_counter(struct wlan_objmgr_vdev *vdev);
/**
* ucfg_mc_cp_stats_set_congestion_threshold() - API to configure congestion
* threshold
* @vdev: pointer to vdev object
* @threshold: congestion threshold
*
* Return: status of operation
*/
QDF_STATUS
ucfg_mc_cp_stats_set_congestion_threshold(struct wlan_objmgr_vdev *vdev,
uint8_t threshold);
#else
static inline QDF_STATUS
ucfg_mc_cp_stats_reset_congestion_counter(struct wlan_objmgr_vdev *vdev)
{
return QDF_STATUS_SUCCESS;
}
static inline QDF_STATUS
ucfg_mc_cp_stats_set_congestion_threshold(struct wlan_objmgr_vdev *vdev,
uint8_t threshold)
{
return QDF_STATUS_SUCCESS;
}
#endif
/**
* ucfg_mc_cp_stats_is_req_pending() - API to tell if given request is pending
* @psoc: pointer to psoc object

查看文件

@@ -703,16 +703,12 @@ tgt_mc_cp_stats_extract_congestion_stats(struct wlan_objmgr_psoc *psoc,
struct stats_event *ev)
{
QDF_STATUS status;
uint8_t i, index;
struct request_info last_req = {0};
struct wlan_objmgr_pdev *pdev;
struct pdev_mc_cp_stats *pdev_mc_stats, *fw_pdev_stats;
struct pdev_cp_stats *pdev_cp_stats_priv;
uint32_t rx_clear_count_delta, cycle_count_delta;
uint8_t congestion = 0;
bool is_congested = false;
struct medium_assess_data data[WLAN_UMAC_MAX_RP_PID] = { {0} };
if (!ev->pdev_stats) {
cp_stats_debug("no pdev_stats");
if (!ev->num_pdev_stats) {
cp_stats_err("no congestion sta for pdev");
return;
}
@@ -724,72 +720,22 @@ tgt_mc_cp_stats_extract_congestion_stats(struct wlan_objmgr_psoc *psoc,
return;
}
/* Check if stats for the specific pdev is present */
if (last_req.pdev_id >= ev->num_pdev_stats) {
cp_stats_err("no stat for pdev %d ", last_req.pdev_id);
return;
}
pdev = wlan_objmgr_get_pdev_by_id(psoc, last_req.pdev_id,
WLAN_CP_STATS_ID);
if (!pdev) {
cp_stats_err("pdev is null");
return;
}
pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev);
if (!pdev_cp_stats_priv) {
cp_stats_err("pdev_cp_stats_priv is null");
goto out;
}
wlan_cp_stats_pdev_obj_lock(pdev_cp_stats_priv);
pdev_mc_stats = pdev_cp_stats_priv->pdev_stats;
fw_pdev_stats = &ev->pdev_stats[last_req.pdev_id];
/*
* Skip calculating deltas and congestion for the first received event
* since enabled
*/
if (pdev_mc_stats->cycle_count || pdev_mc_stats->rx_clear_count) {
if (fw_pdev_stats->rx_clear_count >=
pdev_mc_stats->rx_clear_count) {
rx_clear_count_delta = fw_pdev_stats->rx_clear_count -
pdev_mc_stats->rx_clear_count;
} else {
/* Wrap around case */
rx_clear_count_delta = U32_MAX -
pdev_mc_stats->rx_clear_count;
rx_clear_count_delta += fw_pdev_stats->rx_clear_count;
for (i = 0; (i < ev->num_pdev_stats) && (i < WLAN_UMAC_MAX_RP_PID);
i++){
index = ev->pdev_stats[i].pdev_id;
if (index >= WLAN_UMAC_MAX_RP_PID) {
cp_stats_err("part1 pdev id error");
continue;
}
if (fw_pdev_stats->cycle_count >= pdev_mc_stats->cycle_count) {
cycle_count_delta = fw_pdev_stats->cycle_count -
pdev_mc_stats->cycle_count;
} else {
/* Wrap around case */
cycle_count_delta = U32_MAX -
pdev_mc_stats->cycle_count;
cycle_count_delta += fw_pdev_stats->cycle_count;
}
if (cycle_count_delta)
pdev_mc_stats->congestion = rx_clear_count_delta * 100 /
cycle_count_delta;
else
cp_stats_err("cycle_count not increased %d",
fw_pdev_stats->cycle_count);
data[index].part1_valid = 1;
data[index].cycle_count = ev->pdev_stats[i].cycle_count;
data[index].rx_clear_count = ev->pdev_stats[i].rx_clear_count;
data[index].tx_frame_count = ev->pdev_stats[i].tx_frame_count;
}
pdev_mc_stats->rx_clear_count = fw_pdev_stats->rx_clear_count;
pdev_mc_stats->cycle_count = fw_pdev_stats->cycle_count;
if (pdev_mc_stats->congestion >= pdev_mc_stats->congestion_threshold) {
is_congested = true;
congestion = pdev_mc_stats->congestion;
}
wlan_cp_stats_pdev_obj_unlock(pdev_cp_stats_priv);
if (last_req.u.congestion_notif_cb && is_congested)
last_req.u.congestion_notif_cb(last_req.vdev_id, congestion);
if (last_req.u.congestion_notif_cb)
last_req.u.congestion_notif_cb(last_req.vdev_id, data);
out:
wlan_objmgr_pdev_release_ref(pdev, WLAN_CP_STATS_ID);
}
#else
static void

查看文件

@@ -750,55 +750,6 @@ QDF_STATUS ucfg_mc_cp_stats_get_tx_power(struct wlan_objmgr_vdev *vdev,
return QDF_STATUS_SUCCESS;
}
#ifdef WLAN_FEATURE_MEDIUM_ASSESS
QDF_STATUS
ucfg_mc_cp_stats_reset_congestion_counter(struct wlan_objmgr_vdev *vdev)
{
struct wlan_objmgr_pdev *pdev;
struct pdev_mc_cp_stats *pdev_mc_stats;
struct pdev_cp_stats *pdev_cp_stats_priv;
pdev = wlan_vdev_get_pdev(vdev);
pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev);
if (!pdev_cp_stats_priv) {
cp_stats_err("pdev cp stats object is null");
return QDF_STATUS_E_NULL_VALUE;
}
wlan_cp_stats_pdev_obj_lock(pdev_cp_stats_priv);
pdev_mc_stats = pdev_cp_stats_priv->pdev_stats;
pdev_mc_stats->congestion = 0;
pdev_mc_stats->rx_clear_count = 0;
pdev_mc_stats->cycle_count = 0;
wlan_cp_stats_pdev_obj_unlock(pdev_cp_stats_priv);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS
ucfg_mc_cp_stats_set_congestion_threshold(struct wlan_objmgr_vdev *vdev,
uint8_t threshold)
{
struct wlan_objmgr_pdev *pdev;
struct pdev_mc_cp_stats *pdev_mc_stats;
struct pdev_cp_stats *pdev_cp_stats_priv;
pdev = wlan_vdev_get_pdev(vdev);
pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev);
if (!pdev_cp_stats_priv) {
cp_stats_err("pdev cp stats object is null");
return QDF_STATUS_E_NULL_VALUE;
}
wlan_cp_stats_pdev_obj_lock(pdev_cp_stats_priv);
pdev_mc_stats = pdev_cp_stats_priv->pdev_stats;
pdev_mc_stats->congestion_threshold = threshold;
wlan_cp_stats_pdev_obj_unlock(pdev_cp_stats_priv);
return QDF_STATUS_SUCCESS;
}
#endif
bool ucfg_mc_cp_stats_is_req_pending(struct wlan_objmgr_psoc *psoc,
enum stats_req_type type)
{

查看文件

@@ -341,22 +341,6 @@ static void target_if_cp_stats_free_stats_event(struct stats_event *ev)
ev->peer_stats_info_ext = NULL;
}
#ifdef WLAN_FEATURE_MEDIUM_ASSESS
static void
target_if_cp_stats_extract_congestion(struct pdev_mc_cp_stats *pdev_stats,
wmi_host_pdev_stats *fw_pdev_stats)
{
pdev_stats->rx_clear_count = fw_pdev_stats->rx_clear_count;
pdev_stats->cycle_count = fw_pdev_stats->cycle_count;
}
#else
static void
target_if_cp_stats_extract_congestion(struct pdev_mc_cp_stats *pdev_stats,
wmi_host_pdev_stats *fw_pdev_stats)
{
}
#endif
static QDF_STATUS target_if_cp_stats_extract_pdev_stats(
struct wmi_unified *wmi_hdl,
wmi_host_stats_event *stats_param,
@@ -398,8 +382,19 @@ static QDF_STATUS target_if_cp_stats_extract_pdev_stats(
}
ev->pdev_stats[i].max_pwr = pdev_stats->chan_tx_pwr;
target_if_cp_stats_extract_congestion(&ev->pdev_stats[i],
pdev_stats);
/*
* if pdev_stats->pdev_id is 0, then the event contains all
* pdev info, else only contains 1 pdev with pdev id set.
* minus 1: align fw pdev_id and driver
*/
if (pdev_stats->pdev_id)
ev->pdev_stats[i].pdev_id = pdev_stats->pdev_id - 1;
else
ev->pdev_stats[i].pdev_id = i;
ev->pdev_stats[i].rx_clear_count = pdev_stats->rx_clear_count;
ev->pdev_stats[i].tx_frame_count = pdev_stats->tx_frame_count;
ev->pdev_stats[i].cycle_count = pdev_stats->cycle_count;
val.cdp_pdev_param_chn_noise_flr = pdev_stats->chan_nf;
cdp_txrx_set_pdev_param(soc, 0, CDP_CHAN_NOISE_FLOOR, val);
@@ -837,7 +832,6 @@ static QDF_STATUS target_if_cp_stats_extract_event(struct wmi_unified *wmi_hdl,
status = target_if_cp_stats_extract_pmf_bcn_protect_stats(wmi_hdl,
&stats_param,
ev, data);
return status;
}

查看文件

@@ -98,6 +98,7 @@
#include "wlan_if_mgr_ucfg_api.h"
#include "wlan_if_mgr_public_struct.h"
#include "wlan_hdd_bootup_marker.h"
#include "wlan_hdd_medium_assess.h"
#define ACS_SCAN_EXPIRY_TIMEOUT_S 4
@@ -1820,6 +1821,7 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
mac_handle_t mac_handle;
struct sap_config *sap_config;
struct sap_context *sap_ctx = NULL;
uint8_t pdev_id;
dev = context;
if (!dev) {
@@ -1891,6 +1893,7 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
ap_ctx->operating_chan_freq,
sap_config->ch_params.ch_width);
hdd_medium_assess_init();
sap_config->ch_params = ap_ctx->sap_context->ch_params;
sap_config->sec_ch_freq = ap_ctx->sap_context->sec_ch_freq;
@@ -2056,6 +2059,16 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
}
hdd_nofl_info("Ap stopped vid %d reason=%d", adapter->vdev_id,
ap_ctx->bss_stop_reason);
qdf_status =
policy_mgr_get_mac_id_by_session_id(hdd_ctx->psoc,
adapter->vdev_id,
&pdev_id);
if (QDF_IS_STATUS_SUCCESS(qdf_status))
hdd_medium_assess_stop_timer(pdev_id, hdd_ctx);
hdd_medium_assess_deinit();
if ((BSS_STOP_DUE_TO_MCC_SCC_SWITCH !=
ap_ctx->bss_stop_reason) &&
(BSS_STOP_DUE_TO_VENDOR_CONFIG_CHAN !=

查看文件

@@ -201,6 +201,7 @@
#include "wlan_hdd_gpio_wakeup.h"
#include "wlan_hdd_bootup_marker.h"
#include "wlan_hdd_bus_bandwidth.h"
#include "wlan_hdd_medium_assess.h"
#ifdef MODULE
#define WLAN_MODULE_NAME module_name(THIS_MODULE)
@@ -7730,6 +7731,7 @@ QDF_STATUS hdd_reset_all_adapters(struct hdd_context *hdd_ctx)
if (value &&
adapter->device_mode == QDF_SAP_MODE) {
hdd_medium_assess_ssr_enable_flag();
wlan_hdd_netif_queue_control(adapter,
WLAN_STOP_ALL_NETIF_QUEUE,
WLAN_CONTROL_PATH);

查看文件

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -29,6 +29,7 @@
#include <wlan_cp_stats_mc_ucfg_api.h>
#include <sme_api.h>
#include <wma_api.h>
#include "wlan_cmn.h"
/* define short names for get station info attributes */
#define MEDIUM_ASSESS_TYPE \
@@ -66,6 +67,12 @@
#define MAX_CONGESTION_THRESHOLD 100
#define MEDIUM_ASSESS_TIMER_INTERVAL 1000 /* 1000ms */
static qdf_mc_timer_t hdd_medium_assess_timer;
static uint8_t timer_enable, ssr_flag;
struct hdd_medium_assess_info medium_assess_info[WLAN_UMAC_MAX_RP_PID];
unsigned long stime;
const struct nla_policy
hdd_medium_assess_policy[MEDIUM_ASSESS_MAX + 1] = {
[MEDIUM_ASSESS_TYPE] = {.type = NLA_U8},
@@ -249,7 +256,48 @@ static int get_congestion_report_len(void)
*
* Return: None
*/
static void hdd_congestion_notification_cb(uint8_t vdev_id, uint8_t congestion)
static void hdd_congestion_notification_cb(uint8_t vdev_id,
struct medium_assess_data *data)
{
struct hdd_medium_assess_info *mdata;
uint8_t i;
/* the cb should not be delay more than 40 ms or drop it */
if (qdf_system_time_after(jiffies, stime)) {
hdd_debug("medium assess interference data drop");
return;
}
for (i = 0; i < WLAN_UMAC_MAX_RP_PID; i++) {
mdata = &medium_assess_info[i];
if (data[i].part1_valid) {
mdata->data[mdata->index].part1_valid = 1;
mdata->data[mdata->index].cycle_count =
data[i].cycle_count;
mdata->data[mdata->index].rx_clear_count =
data[i].rx_clear_count;
mdata->data[mdata->index].tx_frame_count =
data[i].tx_frame_count;
}
if (mdata->data[mdata->index].part1_valid) {
mdata->index++;
if (mdata->index >= MEDIUM_ASSESS_NUM)
mdata->index = 0;
mdata->data[mdata->index].part1_valid = 0;
}
}
}
/**
* hdd_congestion_notification_report() - congestion report function
* @vdev_id: vdev id
* @congestion: congestion percentage
*
* Return: None
*/
static void hdd_congestion_notification_report(uint8_t vdev_id,
uint8_t congestion)
{
struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
struct hdd_adapter *adapter;
@@ -284,6 +332,37 @@ static void hdd_congestion_notification_cb(uint8_t vdev_id, uint8_t congestion)
cfg80211_vendor_event(event, GFP_KERNEL);
}
void hdd_medium_assess_ssr_enable_flag(void)
{
ssr_flag = 1;
}
void hdd_medium_assess_stop_timer(uint8_t pdev_id, struct hdd_context *hdd_ctx)
{
struct request_info info = {0};
bool pending = false;
uint8_t i, interval = 0;
if (ssr_flag)
return;
medium_assess_info[pdev_id].config.threshold = MAX_CONGESTION_THRESHOLD;
medium_assess_info[pdev_id].config.interval = 0;
medium_assess_info[pdev_id].index = 0;
medium_assess_info[pdev_id].count = 0;
for (i = 0; i < WLAN_UMAC_MAX_RP_PID; i++)
interval += medium_assess_info[i].config.interval;
if (!interval) {
ucfg_mc_cp_stats_reset_pending_req(hdd_ctx->psoc,
TYPE_CONGESTION_STATS,
&info, &pending);
qdf_mc_timer_stop(&hdd_medium_assess_timer);
hdd_debug("medium assess atimer stop");
}
}
/**
* hdd_medium_assess_congestion_report() - congestion report
* @hdd_ctx: pointer to HDD context
@@ -296,32 +375,38 @@ static int hdd_medium_assess_congestion_report(struct hdd_context *hdd_ctx,
struct hdd_adapter *adapter,
struct nlattr **tb)
{
struct wlan_objmgr_vdev *vdev;
uint8_t enable, threshold, interval = 1;
struct request_info info = {0};
bool pending = false;
QDF_STATUS status;
struct wlan_objmgr_vdev *vdev;
uint8_t enable, threshold, interval = 0;
uint8_t pdev_id, vdev_id;
int errno = 0;
if (!tb[CONGESTION_REPORT_ENABLE]) {
hdd_err_rl("Congestion report enable is not present");
return -EINVAL;
}
vdev = hdd_objmgr_get_vdev_by_user(adapter, WLAN_CP_STATS_ID);
if (!vdev)
return -EINVAL;
if (!tb[CONGESTION_REPORT_ENABLE]) {
hdd_err_rl("Congestion report enable is not present");
errno = -EINVAL;
vdev_id = adapter->vdev_id;
status = policy_mgr_get_mac_id_by_session_id(hdd_ctx->psoc, vdev_id,
&pdev_id);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("get mac id failed");
goto out;
}
enable = nla_get_u8(tb[CONGESTION_REPORT_ENABLE]);
medium_assess_info[pdev_id].vdev_id = vdev_id;
medium_assess_info[pdev_id].pdev_id = pdev_id;
enable = nla_get_u8(tb[CONGESTION_REPORT_ENABLE]);
switch (enable) {
case REPORT_DISABLE:
ucfg_mc_cp_stats_reset_pending_req(hdd_ctx->psoc,
TYPE_CONGESTION_STATS,
&info,
&pending);
threshold = MAX_CONGESTION_THRESHOLD;
interval = 0;
hdd_debug("medium assess disable: pdev_id %d, vdev_id: %d",
pdev_id, vdev_id);
hdd_medium_assess_stop_timer(pdev_id, hdd_ctx);
break;
case REPORT_ENABLE:
if (!tb[CONGESTION_REPORT_THRESHOLD]) {
@@ -335,44 +420,32 @@ static int hdd_medium_assess_congestion_report(struct hdd_context *hdd_ctx,
errno = -EINVAL;
goto out;
}
if (tb[CONGESTION_REPORT_INTERVAL])
if (tb[CONGESTION_REPORT_INTERVAL]) {
interval = nla_get_u8(tb[CONGESTION_REPORT_INTERVAL]);
status = ucfg_mc_cp_stats_reset_congestion_counter(vdev);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("Failed to set threshold");
errno = qdf_status_to_os_return(status);
goto out;
if (interval >= MEDIUM_ASSESS_NUM)
interval = MEDIUM_ASSESS_NUM - 1;
} else {
interval = 1;
}
medium_assess_info[pdev_id].config.threshold = threshold;
medium_assess_info[pdev_id].config.interval = interval;
medium_assess_info[pdev_id].index = 0;
medium_assess_info[pdev_id].count = 0;
hdd_debug("medium assess enable: pdev_id %d, vdev_id: %d",
pdev_id, vdev_id);
if (qdf_mc_timer_get_current_state(&hdd_medium_assess_timer) ==
QDF_TIMER_STATE_STOPPED) {
hdd_debug("medium assess atimer start");
qdf_mc_timer_start(&hdd_medium_assess_timer,
MEDIUM_ASSESS_TIMER_INTERVAL);
}
break;
default:
hdd_err_rl("Invalid enable: %d", enable);
errno = -EINVAL;
goto out;
}
status = ucfg_mc_cp_stats_set_congestion_threshold(vdev, threshold);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("Failed to set threshold");
errno = qdf_status_to_os_return(status);
goto out;
}
errno = sme_cli_set_command(adapter->vdev_id,
WMI_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD,
interval * 1000, PDEV_CMD);
if (errno) {
hdd_err("Failed to set interval");
goto out;
}
if (interval) {
info.vdev_id = adapter->vdev_id;
info.pdev_id =
wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev));
info.u.congestion_notif_cb = hdd_congestion_notification_cb;
errno = ucfg_mc_cp_stats_send_stats_request(vdev,
TYPE_CONGESTION_STATS,
&info);
break;
}
out:
@@ -463,3 +536,186 @@ int hdd_cfg80211_medium_assess(struct wiphy *wiphy,
return errno;
}
/**
* hdd_congestion_notification_calculation() - medium assess congestion
* calculation.
* @info: structure hdd_medium_assess_info
*
* Return: None
*/
static void
hdd_congestion_notification_calculation(struct hdd_medium_assess_info *info)
{
struct medium_assess_data *h_data, *t_data;
int32_t h_index, t_index;
uint32_t rx_clear_count_delta, tx_frame_count_delta;
uint32_t cycle_count_delta;
uint32_t congestion = 0;
h_index = info->index - 1;
if (h_index < 0)
h_index = MEDIUM_ASSESS_NUM - 1;
if (h_index >= info->config.interval)
t_index = h_index - info->config.interval;
else
t_index = MEDIUM_ASSESS_NUM - info->config.interval - h_index;
if (h_index < 0 || h_index >= MEDIUM_ASSESS_NUM ||
t_index < 0 || t_index >= MEDIUM_ASSESS_NUM) {
hdd_err("medium assess index is not valid.");
return;
}
h_data = &info->data[h_index];
t_data = &info->data[t_index];
if (!(h_data->part1_valid || t_data->part1_valid)) {
hdd_err("medium assess data is not valid.");
return;
}
if (h_data->rx_clear_count >= t_data->rx_clear_count) {
rx_clear_count_delta = h_data->rx_clear_count -
t_data->rx_clear_count;
} else {
rx_clear_count_delta = U32_MAX - t_data->rx_clear_count;
rx_clear_count_delta += h_data->rx_clear_count;
}
if (h_data->tx_frame_count >= t_data->tx_frame_count) {
tx_frame_count_delta = h_data->tx_frame_count -
t_data->tx_frame_count;
} else {
tx_frame_count_delta = U32_MAX - t_data->tx_frame_count;
tx_frame_count_delta += h_data->tx_frame_count;
}
if (h_data->cycle_count >= t_data->cycle_count) {
cycle_count_delta = h_data->cycle_count - t_data->cycle_count;
} else {
cycle_count_delta = U32_MAX - t_data->cycle_count;
cycle_count_delta += h_data->cycle_count;
}
if (cycle_count_delta)
congestion = (rx_clear_count_delta - tx_frame_count_delta)
* 100 / cycle_count_delta;
if (congestion > 100)
congestion = 100;
hdd_debug("pdev: %d, rx_clear %u, tx_frame %u cycle %u congestion: %u",
info->pdev_id, rx_clear_count_delta, tx_frame_count_delta,
cycle_count_delta, congestion);
if (congestion >= info->config.threshold)
hdd_congestion_notification_report(info->vdev_id, congestion);
}
/**
* hdd_congestion_notification_report_multi() - medium assess report
* multi interface.
* @pdev_id: pdev id
*
* Return: None
*/
static void hdd_congestion_notification_report_multi(uint8_t pdev_id)
{
struct hdd_medium_assess_info *info;
info = &medium_assess_info[pdev_id];
info->count++;
if (info->count % info->config.interval == 0)
hdd_congestion_notification_calculation(info);
}
/**
* hdd_medium_assess_expire_handler() - timer callback
* @arg: argument
*
* Return: None
*/
static void hdd_medium_assess_expire_handler(void *arg)
{
struct wlan_objmgr_vdev *vdev;
struct request_info info = {0};
struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
struct hdd_adapter *adapter;
uint8_t vdev_id = INVALID_VDEV_ID, pdev_id;
uint8_t index, i;
if (wlan_hdd_validate_context(hdd_ctx))
return;
for (i = 0; i < WLAN_UMAC_MAX_RP_PID; i++)
if (medium_assess_info[i].config.interval != 0) {
vdev_id = medium_assess_info[i].vdev_id;
pdev_id = medium_assess_info[i].pdev_id;
hdd_congestion_notification_report_multi(pdev_id);
/* ensure events are reveived at the 'same' time */
index = medium_assess_info[i].index;
medium_assess_info[i].data[index].part1_valid = 0;
}
if (vdev_id == INVALID_VDEV_ID)
return;
adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
if (!adapter) {
hdd_err("Failed to find adapter of vdev %d", vdev_id);
return;
}
vdev = hdd_objmgr_get_vdev_by_user(adapter, WLAN_CP_STATS_ID);
if (!vdev)
return;
info.vdev_id = vdev_id;
info.pdev_id = 0;
info.u.congestion_notif_cb = hdd_congestion_notification_cb;
stime = jiffies + msecs_to_jiffies(40);
ucfg_mc_cp_stats_send_stats_request(vdev,
TYPE_CONGESTION_STATS,
&info);
hdd_objmgr_put_vdev_by_user(vdev, WLAN_CP_STATS_ID);
qdf_mc_timer_start(&hdd_medium_assess_timer,
MEDIUM_ASSESS_TIMER_INTERVAL);
}
void hdd_medium_assess_init(void)
{
QDF_STATUS status;
if (!timer_enable) {
hdd_debug("medium assess init timer");
status = qdf_mc_timer_init(&hdd_medium_assess_timer,
QDF_TIMER_TYPE_SW,
hdd_medium_assess_expire_handler,
NULL);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_debug("medium assess init timer failed");
return;
}
if (ssr_flag) {
ssr_flag = 0;
qdf_mc_timer_start(&hdd_medium_assess_timer,
MEDIUM_ASSESS_TIMER_INTERVAL);
}
}
timer_enable += 1;
}
void hdd_medium_assess_deinit(void)
{
timer_enable -= 1;
if (!timer_enable) {
hdd_debug("medium assess deinit timer");
if (qdf_mc_timer_get_current_state(&hdd_medium_assess_timer) ==
QDF_TIMER_STATE_RUNNING)
qdf_mc_timer_stop(&hdd_medium_assess_timer);
qdf_mc_timer_destroy(&hdd_medium_assess_timer);
}
}

查看文件

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -28,8 +28,44 @@
#include <net/netlink.h>
#include <net/cfg80211.h>
#include <qca_vendor.h>
#include "wlan_hdd_main.h"
#ifdef WLAN_FEATURE_MEDIUM_ASSESS
#include "wlan_cp_stats_mc_defs.h"
#define MEDIUM_ASSESS_NUM 31
/**
* struct hdd_medium_assess_config: configuration from framework
* @interval: the update period to framework. An integral multiple of 1 second,
* less or equal to 30 seconds
* @threshold: threshold for congestion percentage of pdev
*/
struct hdd_medium_assess_config {
uint8_t interval;
uint8_t threshold;
};
/**
* struct hdd_medium_assess_info: the medium assess info for pdev
* @pdev_id: pdev id
* @vdev_id: vdev id
* @config: config info from user
* @index: the data's index
* @data: the raw info from fw
* @count: the times of timer triggered
*/
struct hdd_medium_assess_info {
uint8_t pdev_id;
uint8_t vdev_id;
struct hdd_medium_assess_config config;
int32_t index;
struct medium_assess_data data[MEDIUM_ASSESS_NUM];
uint32_t count;
};
/* QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS */
extern const struct nla_policy
hdd_medium_assess_policy[QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX + 1];
@@ -65,8 +101,43 @@ int hdd_cfg80211_medium_assess(struct wiphy *wiphy,
.vendor_id = QCA_NL80211_VENDOR_ID, \
.subcmd = QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS, \
},
/**
* hdd_medium_assess_init() - medium assess init timer
*
* Return: none
*/
void hdd_medium_assess_init(void);
/**
* hdd_cfg80211_medium_deinit() - medium assess deinit timer
*
* Return: none
*/
void hdd_medium_assess_deinit(void);
/**
* hdd_medium_assess_stop_timer() - medium assess reset and stop timer
* @pdev_id: pdev id
* @hdd_ctx: hdd context
*
* Return: none
*/
void hdd_medium_assess_stop_timer(uint8_t pdev_id, struct hdd_context *hdd_ctx);
/**
* hdd_medium_assess_ssr_enable_flag() - medium assess set ssr enable flag
*
* Return: none
*/
void hdd_medium_assess_ssr_enable_flag(void);
#else
#define FEATURE_MEDIUM_ASSESS_VENDOR_COMMANDS
#define FEATURE_MEDIUM_ASSESS_VENDOR_EVENTS
static inline void hdd_medium_assess_init(void) {}
static inline void hdd_medium_assess_deinit(void) {}
static inline void hdd_medium_assess_stop_timer(uint8_t pdev_id,
struct hdd_context *hdd_ctx) {}
static inline void hdd_medium_assess_ssr_enable_flag(void) {}
#endif
#endif /* end #if !defined(__WLAN_HDD_MEDIUM_ASSESS_H) */