qcacld-3.0: API to report congestion
API to report congestion to userspace. Change-Id: I324ae6701dace590daaa2c3f80412d6633cbf8f0 CRs-Fixed: 2766432
This commit is contained in:
parent
f1a04e6d05
commit
47d4029c67
5
Kbuild
5
Kbuild
@ -415,6 +415,10 @@ ifeq ($(CONFIG_FEATURE_GPIO_CFG),y)
|
||||
HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_gpio.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_WLAN_FEATURE_MEDIUM_ASSESS), y)
|
||||
HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_medium_assess.o
|
||||
endif
|
||||
|
||||
###### OSIF_SYNC ########
|
||||
SYNC_DIR := os_if/sync
|
||||
SYNC_INC_DIR := $(SYNC_DIR)/inc
|
||||
@ -2614,6 +2618,7 @@ cppflags-$(CONFIG_WLAN_CONV_SPECTRAL_ENABLE) += -DWLAN_CONV_SPECTRAL_ENABLE
|
||||
cppflags-$(CONFIG_WLAN_CFR_ENABLE) += -DWLAN_CFR_ENABLE
|
||||
cppflags-$(CONFIG_WLAN_ENH_CFR_ENABLE) += -DWLAN_ENH_CFR_ENABLE
|
||||
cppflags-$(CONFIG_WLAN_CFR_ENABLE) += -DCFR_USE_FIXED_FOLDER
|
||||
cppflags-$(CONFIG_WLAN_FEATURE_MEDIUM_ASSESS) += -DWLAN_FEATURE_MEDIUM_ASSESS
|
||||
cppflags-$(CONFIG_DIRECT_BUF_RX_ENABLE) += -DDIRECT_BUF_RX_ENABLE
|
||||
cppflags-$(CONFIG_WMI_DBR_SUPPORT) += -DWMI_DBR_SUPPORT
|
||||
ifneq ($(CONFIG_CNSS_QCA6750), y)
|
||||
|
@ -56,6 +56,7 @@
|
||||
* @TYPE_PEER_STATS: peer stats was requested
|
||||
* @TYPE_MIB_STATS: MIB stats was requested
|
||||
* @TYPE_PEER_STATS_INFO_EXT: peer stats info ext was requested
|
||||
* @TYPE_CONGESTION_STATS: congestion stats was requested
|
||||
*/
|
||||
enum stats_req_type {
|
||||
TYPE_CONNECTION_TX_POWER = 0,
|
||||
@ -63,6 +64,7 @@ enum stats_req_type {
|
||||
TYPE_PEER_STATS,
|
||||
TYPE_MIB_STATS,
|
||||
TYPE_PEER_STATS_INFO_EXT,
|
||||
TYPE_CONGESTION_STATS,
|
||||
TYPE_MAX,
|
||||
};
|
||||
|
||||
@ -174,7 +176,8 @@ struct stats_event;
|
||||
* 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 request when response comes.
|
||||
* station stats/mib stats/peer stats request when response comes and
|
||||
* notification callback when congestion is detected.
|
||||
* @vdev_id: vdev_id of request
|
||||
* @pdev_id: pdev_id of request
|
||||
* @peer_mac_addr: peer mac address
|
||||
@ -190,6 +193,7 @@ struct request_info {
|
||||
void *cookie);
|
||||
void (*get_peer_stats_cb)(struct stats_event *ev,
|
||||
void *cookie);
|
||||
void (*congestion_notif_cb)(uint8_t congestion);
|
||||
} u;
|
||||
uint32_t vdev_id;
|
||||
uint32_t pdev_id;
|
||||
@ -232,10 +236,20 @@ struct psoc_mc_cp_stats {
|
||||
|
||||
/**
|
||||
* struct pdev_mc_cp_stats: pdev specific stats
|
||||
* @max_pwr: max tx power for vdev
|
||||
* @max_pwr: max tx power for pdev
|
||||
* @congestion: percentage of congestion = (busy_time / total_time) * 100
|
||||
* @congestion_threshold: threshold for congestion precentage of pdev
|
||||
* @rx_clear_count: accumulative rx clear count (busy time) of pdev
|
||||
* @cycle_count: accumulative cycle 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 rx_clear_count;
|
||||
uint32_t cycle_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -163,6 +163,43 @@ QDF_STATUS ucfg_mc_cp_stats_send_stats_request(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
|
||||
|
@ -615,6 +615,108 @@ tgt_mc_cp_stats_extract_peer_stats_info_ext(struct wlan_objmgr_psoc *psoc,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WLAN_FEATURE_MEDIUM_ASSESS
|
||||
static void
|
||||
tgt_mc_cp_stats_extract_congestion_stats(struct wlan_objmgr_psoc *psoc,
|
||||
struct stats_event *ev)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
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;
|
||||
|
||||
if (!ev->pdev_stats) {
|
||||
cp_stats_debug("no pdev_stats");
|
||||
return;
|
||||
}
|
||||
|
||||
status = ucfg_mc_cp_stats_get_pending_req(psoc,
|
||||
TYPE_CONGESTION_STATS,
|
||||
&last_req);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed");
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
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(congestion);
|
||||
|
||||
out:
|
||||
wlan_objmgr_pdev_release_ref(pdev, WLAN_CP_STATS_ID);
|
||||
}
|
||||
#else
|
||||
static void
|
||||
tgt_mc_cp_stats_extract_congestion_stats(struct wlan_objmgr_psoc *psoc,
|
||||
struct stats_event *ev)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static void tgt_mc_cp_stats_extract_cca_stats(struct wlan_objmgr_psoc *psoc,
|
||||
struct stats_event *ev)
|
||||
{
|
||||
@ -996,6 +1098,9 @@ QDF_STATUS tgt_mc_cp_stats_process_stats_event(struct wlan_objmgr_psoc *psoc,
|
||||
if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_PEER_STATS_INFO_EXT))
|
||||
tgt_mc_cp_stats_extract_peer_stats_info_ext(psoc, ev);
|
||||
|
||||
if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_CONGESTION_STATS))
|
||||
tgt_mc_cp_stats_extract_congestion_stats(psoc, ev);
|
||||
|
||||
tgt_mc_cp_stats_extract_cca_stats(psoc, ev);
|
||||
|
||||
tgt_mc_cp_send_lost_link_stats(psoc, ev);
|
||||
|
@ -725,6 +725,55 @@ 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)
|
||||
{
|
||||
|
@ -340,6 +340,22 @@ 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,
|
||||
@ -370,6 +386,8 @@ static QDF_STATUS target_if_cp_stats_extract_pdev_stats(
|
||||
return status;
|
||||
}
|
||||
ev->pdev_stats[i].max_pwr = pdev_stats.chan_tx_pwr;
|
||||
target_if_cp_stats_extract_congestion(&ev->pdev_stats[i],
|
||||
&pdev_stats);
|
||||
}
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
@ -1119,6 +1137,7 @@ static uint32_t get_stats_id(enum stats_req_type type)
|
||||
default:
|
||||
break;
|
||||
case TYPE_CONNECTION_TX_POWER:
|
||||
case TYPE_CONGESTION_STATS:
|
||||
return WMI_REQUEST_PDEV_STAT;
|
||||
case TYPE_PEER_STATS:
|
||||
return WMI_REQUEST_PEER_STAT | WMI_REQUEST_PEER_EXTD_STAT;
|
||||
|
@ -237,6 +237,8 @@ CONFIG_WLAN_POWER_DEBUG := y
|
||||
CONFIG_FEATURE_BECN_STATS := y
|
||||
endif
|
||||
|
||||
CONFIG_WLAN_FEATURE_MEDIUM_ASSESS := y
|
||||
|
||||
#Disable the Export Symbol config
|
||||
CONFIG_WLAN_DISABLE_EXPORT_SYMBOL := y
|
||||
|
||||
|
@ -159,6 +159,7 @@
|
||||
#include "wlan_reg_ucfg_api.h"
|
||||
#include "wlan_hdd_twt.h"
|
||||
#include "wlan_hdd_gpio.h"
|
||||
#include "wlan_hdd_medium_assess.h"
|
||||
|
||||
#ifdef WLAN_FEATURE_INTERFACE_MGR
|
||||
#include "wlan_if_mgr_ucfg_api.h"
|
||||
@ -1652,6 +1653,7 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] =
|
||||
},
|
||||
|
||||
BCN_RECV_FEATURE_VENDOR_EVENTS
|
||||
FEATURE_MEDIUM_ASSESS_VENDOR_EVENTS
|
||||
[QCA_NL80211_VENDOR_SUBCMD_ROAM_INDEX] = {
|
||||
.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.subcmd = QCA_NL80211_VENDOR_SUBCMD_ROAM,
|
||||
@ -15692,6 +15694,7 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
|
||||
FEATURE_BTC_CHAIN_MODE_COMMANDS
|
||||
FEATURE_WMM_COMMANDS
|
||||
FEATURE_GPIO_CFG_VENDOR_COMMANDS
|
||||
FEATURE_MEDIUM_ASSESS_VENDOR_COMMANDS
|
||||
};
|
||||
|
||||
struct hdd_context *hdd_cfg80211_wiphy_alloc(void)
|
||||
|
304
core/hdd/src/wlan_hdd_medium_assess.c
Normal file
304
core/hdd/src/wlan_hdd_medium_assess.c
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC : wlan_hdd_medium_assess.c
|
||||
*
|
||||
* WLAN Host Device Driver medium assess related implementation
|
||||
*
|
||||
*/
|
||||
|
||||
#include "wlan_hdd_medium_assess.h"
|
||||
#include <osif_sync.h>
|
||||
#include <wlan_hdd_main.h>
|
||||
#include <wlan_hdd_object_manager.h>
|
||||
#include <wlan_cp_stats_mc_ucfg_api.h>
|
||||
#include <sme_api.h>
|
||||
#include <wma_api.h>
|
||||
|
||||
/* define short names for get station info attributes */
|
||||
#define MEDIUM_ASSESS_TYPE \
|
||||
QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE
|
||||
#define PERIOD \
|
||||
QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_PERIOD
|
||||
#define TOTAL_CYCLE_COUNT \
|
||||
QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TOTAL_CYCLE_COUNT
|
||||
#define IDLE_COUNT \
|
||||
QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IDLE_COUNT
|
||||
#define IBSS_RX_COUNT \
|
||||
QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IBSS_RX_COUNT
|
||||
#define OBSS_RX_COUNT \
|
||||
QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_OBSS_RX_COUNT
|
||||
#define MAX_IBSS_RSSI \
|
||||
QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX_IBSS_RSSI
|
||||
#define MIN_IBSS_RSSI \
|
||||
QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MIN_IBSS_RSSI
|
||||
#define CONGESTION_REPORT_ENABLE \
|
||||
QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_ENABLE
|
||||
#define CONGESTION_REPORT_THRESHOLD \
|
||||
QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_THRESHOLD
|
||||
#define CONGESTION_REPORT_INTERVAL \
|
||||
QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_INTERVAL
|
||||
#define CONGESTION_PERCENTAGE \
|
||||
QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_PERCENTAGE
|
||||
#define MEDIUM_ASSESS_MAX \
|
||||
QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX
|
||||
|
||||
#define REPORT_DISABLE 0
|
||||
#define REPORT_ENABLE 1
|
||||
|
||||
#define MAX_CONGESTION_THRESHOLD 100
|
||||
|
||||
const struct nla_policy
|
||||
hdd_medium_assess_policy[MEDIUM_ASSESS_MAX + 1] = {
|
||||
[MEDIUM_ASSESS_TYPE] = {.type = NLA_U8},
|
||||
[PERIOD] = {.type = NLA_U32},
|
||||
[CONGESTION_REPORT_ENABLE] = {.type = NLA_U8},
|
||||
[CONGESTION_REPORT_THRESHOLD] = {.type = NLA_U8},
|
||||
[CONGESTION_REPORT_INTERVAL] = {.type = NLA_U8},
|
||||
};
|
||||
|
||||
/**
|
||||
* get_congestion_report_len() - Calculate length for congestion report
|
||||
* to allocate skb buffer
|
||||
*
|
||||
* Return: skb buffer length
|
||||
*/
|
||||
static int get_congestion_report_len(void)
|
||||
{
|
||||
uint32_t data_len = NLMSG_HDRLEN;
|
||||
|
||||
/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE */
|
||||
data_len += nla_total_size(sizeof(uint8_t));
|
||||
|
||||
/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_PERCENTAGE */
|
||||
data_len += nla_total_size(sizeof(uint8_t));
|
||||
|
||||
return data_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* hdd_congestion_notification_cb() - congestion notification callback function
|
||||
* @congestion: congestion percentage
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
static void hdd_congestion_notification_cb(uint8_t congestion)
|
||||
{
|
||||
struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
|
||||
struct sk_buff *event;
|
||||
|
||||
if (wlan_hdd_validate_context(hdd_ctx))
|
||||
return;
|
||||
|
||||
event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
|
||||
get_congestion_report_len(),
|
||||
QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS_INDEX,
|
||||
GFP_KERNEL);
|
||||
if (!event) {
|
||||
hdd_err("cfg80211_vendor_event_alloc failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (nla_put_u8(event, MEDIUM_ASSESS_TYPE,
|
||||
QCA_WLAN_MEDIUM_ASSESS_CONGESTION_REPORT) ||
|
||||
nla_put_u8(event, CONGESTION_PERCENTAGE, congestion)) {
|
||||
hdd_err("nla put failed");
|
||||
kfree_skb(event);
|
||||
return;
|
||||
}
|
||||
|
||||
cfg80211_vendor_event(event, GFP_KERNEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* hdd_medium_assess_congestion_report() - congestion report
|
||||
* @hdd_ctx: pointer to HDD context
|
||||
* @adapter: pointer to adapter
|
||||
* @tb: list of attributes
|
||||
*
|
||||
* Return: success(0) or reason code for failure
|
||||
*/
|
||||
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 qdf_status;
|
||||
int status = 0;
|
||||
|
||||
vdev = hdd_objmgr_get_vdev(adapter);
|
||||
if (!vdev)
|
||||
return -EINVAL;
|
||||
|
||||
if (!tb[CONGESTION_REPORT_ENABLE]) {
|
||||
hdd_err_rl("Congestion report enable is not present");
|
||||
status = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
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;
|
||||
break;
|
||||
case REPORT_ENABLE:
|
||||
if (!tb[CONGESTION_REPORT_THRESHOLD]) {
|
||||
hdd_err_rl("Congestion threshold is not present");
|
||||
status = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
threshold = nla_get_u8(tb[CONGESTION_REPORT_THRESHOLD]);
|
||||
if (threshold > MAX_CONGESTION_THRESHOLD) {
|
||||
hdd_err_rl("Invalid threshold %d", threshold);
|
||||
status = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (tb[CONGESTION_REPORT_INTERVAL])
|
||||
interval = nla_get_u8(tb[CONGESTION_REPORT_INTERVAL]);
|
||||
qdf_status = ucfg_mc_cp_stats_reset_congestion_counter(vdev);
|
||||
if (QDF_IS_STATUS_ERROR(qdf_status)) {
|
||||
hdd_err("Failed to set threshold");
|
||||
status = qdf_status_to_os_return(qdf_status);
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
hdd_err_rl("Invalid enable: %d", enable);
|
||||
status = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
qdf_status = ucfg_mc_cp_stats_set_congestion_threshold(vdev, threshold);
|
||||
if (QDF_IS_STATUS_ERROR(qdf_status)) {
|
||||
hdd_err("Failed to set threshold");
|
||||
status = qdf_status_to_os_return(qdf_status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = sme_cli_set_command(adapter->vdev_id,
|
||||
WMI_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD,
|
||||
interval * 1000, PDEV_CMD);
|
||||
if (status) {
|
||||
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;
|
||||
status = ucfg_mc_cp_stats_send_stats_request(vdev,
|
||||
TYPE_CONGESTION_STATS,
|
||||
&info);
|
||||
}
|
||||
|
||||
out:
|
||||
hdd_objmgr_put_vdev(vdev);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* __hdd_cfg80211_medium_assess() - medium assess
|
||||
* @wiphy: pointer to wireless phy
|
||||
* @wdev: wireless device
|
||||
* @data: data
|
||||
* @data_len: data length
|
||||
*
|
||||
* Return: success(0) or reason code for failure
|
||||
*/
|
||||
static int __hdd_cfg80211_medium_assess(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data,
|
||||
int data_len)
|
||||
{
|
||||
struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
|
||||
struct net_device *dev = wdev->netdev;
|
||||
struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
|
||||
enum QDF_GLOBAL_MODE driver_mode = hdd_get_conparam();
|
||||
struct nlattr *tb[MEDIUM_ASSESS_MAX + 1];
|
||||
uint8_t type;
|
||||
int status;
|
||||
|
||||
hdd_enter_dev(dev);
|
||||
|
||||
if (driver_mode == QDF_GLOBAL_FTM_MODE ||
|
||||
driver_mode == QDF_GLOBAL_MONITOR_MODE) {
|
||||
hdd_err_rl("Command not allowed in FTM / Monitor mode");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
status = wlan_hdd_validate_context(hdd_ctx);
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
status = wlan_cfg80211_nla_parse(tb, MEDIUM_ASSESS_MAX, data, data_len,
|
||||
hdd_medium_assess_policy);
|
||||
if (status) {
|
||||
hdd_err_rl("Invalid ATTR");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!tb[MEDIUM_ASSESS_TYPE]) {
|
||||
hdd_err_rl("Medium assess type is not present");
|
||||
return -EINVAL;
|
||||
}
|
||||
type = nla_get_u8(tb[MEDIUM_ASSESS_TYPE]);
|
||||
|
||||
switch (type) {
|
||||
case QCA_WLAN_MEDIUM_ASSESS_CCA:
|
||||
break;
|
||||
case QCA_WLAN_MEDIUM_ASSESS_CONGESTION_REPORT:
|
||||
status = hdd_medium_assess_congestion_report(hdd_ctx, adapter,
|
||||
tb);
|
||||
break;
|
||||
default:
|
||||
hdd_err_rl("Invalid medium assess type: %d", type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hdd_exit();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int hdd_cfg80211_medium_assess(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data,
|
||||
int data_len)
|
||||
{
|
||||
struct osif_vdev_sync *vdev_sync;
|
||||
int errno;
|
||||
|
||||
errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
|
||||
if (errno)
|
||||
return errno;
|
||||
|
||||
errno = __hdd_cfg80211_medium_assess(wiphy, wdev, data, data_len);
|
||||
|
||||
osif_vdev_sync_op_stop(vdev_sync);
|
||||
|
||||
return errno;
|
||||
}
|
72
core/hdd/src/wlan_hdd_medium_assess.h
Normal file
72
core/hdd/src/wlan_hdd_medium_assess.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC : wlan_hdd_medium_assess.h
|
||||
*
|
||||
* WLAN Host Device Driver medium assess related implementation
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(__WLAN_HDD_MEDIUM_ASSESS_H)
|
||||
#define __WLAN_HDD_MEDIUM_ASSESS_H
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <qca_vendor.h>
|
||||
|
||||
#ifdef WLAN_FEATURE_MEDIUM_ASSESS
|
||||
/* QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS */
|
||||
extern const struct nla_policy
|
||||
hdd_medium_assess_policy[QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX + 1];
|
||||
|
||||
/**
|
||||
* hdd_cfg80211_medium_assess() - medium assess
|
||||
* @wiphy: Pointer to wiphy
|
||||
* @wdev: Pointer to wdev
|
||||
* @data: Pointer to data
|
||||
* @data_len: Data length
|
||||
*
|
||||
* Return: success(0) or reason code for failure
|
||||
*/
|
||||
int hdd_cfg80211_medium_assess(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data,
|
||||
int data_len);
|
||||
|
||||
#define FEATURE_MEDIUM_ASSESS_VENDOR_COMMANDS \
|
||||
{ \
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID, \
|
||||
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS, \
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | \
|
||||
WIPHY_VENDOR_CMD_NEED_NETDEV | \
|
||||
WIPHY_VENDOR_CMD_NEED_RUNNING, \
|
||||
.doit = hdd_cfg80211_medium_assess, \
|
||||
vendor_command_policy(hdd_medium_assess_policy, \
|
||||
QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX) \
|
||||
},
|
||||
|
||||
#define FEATURE_MEDIUM_ASSESS_VENDOR_EVENTS \
|
||||
[QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS_INDEX] = { \
|
||||
.vendor_id = QCA_NL80211_VENDOR_ID, \
|
||||
.subcmd = QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS, \
|
||||
},
|
||||
#else
|
||||
#define FEATURE_MEDIUM_ASSESS_VENDOR_COMMANDS
|
||||
#define FEATURE_MEDIUM_ASSESS_VENDOR_EVENTS
|
||||
#endif
|
||||
#endif /* end #if !defined(__WLAN_HDD_MEDIUM_ASSESS_H) */
|
Loading…
Reference in New Issue
Block a user