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:
@@ -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) */
|
||||
|
Reference in New Issue
Block a user