qcacld-3.0: API to report congestion

API to report congestion to userspace.

Change-Id: I324ae6701dace590daaa2c3f80412d6633cbf8f0
CRs-Fixed: 2766432
This commit is contained in:
Min Liu 2020-08-31 18:43:18 +08:00 committed by snandini
parent f1a04e6d05
commit 47d4029c67
10 changed files with 612 additions and 2 deletions

5
Kbuild
View File

@ -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)

View File

@ -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
};
/**

View File

@ -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

View File

@ -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);

View File

@ -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)
{

View File

@ -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;

View File

@ -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

View File

@ -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)

View 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;
}

View 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) */