qcacld-3.0: API for Clear Channel Assessment

Add a vendor command to report statistics to userspace
for clear channel assessment.

Change-Id: I5c8ddc14f6661d2af7e4f3a9e1c9c844fd4cd16d
CRs-Fixed: 2773536
This commit is contained in:
Min Liu
2020-09-10 11:13:02 +08:00
committed by snandini
부모 5038ef9614
커밋 42339f116a

파일 보기

@@ -25,6 +25,7 @@
#include <osif_sync.h>
#include <wlan_hdd_main.h>
#include <wlan_hdd_object_manager.h>
#include <wlan_dcs_ucfg_api.h>
#include <wlan_cp_stats_mc_ucfg_api.h>
#include <sme_api.h>
#include <wma_api.h>
@@ -57,6 +58,9 @@
#define MEDIUM_ASSESS_MAX \
QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX
#define DEFAULT_CCA_PERIOD 10 /* seconds */
#define CCA_GET_RSSI_INTERVAL 1000 /* 1 second */
#define REPORT_DISABLE 0
#define REPORT_ENABLE 1
@@ -71,7 +75,147 @@ hdd_medium_assess_policy[MEDIUM_ASSESS_MAX + 1] = {
[CONGESTION_REPORT_INTERVAL] = {.type = NLA_U8},
};
/*
* get_cca_report_len() - Calculate length for CCA report
* to allocate skb buffer
*
* Return: skb buffer length
*/
static int get_cca_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_TOTAL_CYCLE_COUNT */
data_len += nla_total_size(sizeof(uint32_t));
/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IDLE_COUNT */
data_len += nla_total_size(sizeof(uint32_t));
/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IBSS_RX_COUNT */
data_len += nla_total_size(sizeof(uint32_t));
/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_OBSS_RX_COUNT */
data_len += nla_total_size(sizeof(uint32_t));
/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX_IBSS_RSSI */
data_len += nla_total_size(sizeof(uint32_t));
/* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MIN_IBSS_RSSI */
data_len += nla_total_size(sizeof(uint32_t));
return data_len;
}
/**
* hdd_cca_notification_cb() - cca notification callback function
* @vdev_id: vdev id
* @stats: dcs im stats
* @status: status of cca statistics
*
* Return: None
*/
static void hdd_cca_notification_cb(uint8_t vdev_id,
struct wlan_host_dcs_im_user_stats *stats,
int status)
{
struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
struct hdd_adapter *adapter;
struct sk_buff *event;
if (wlan_hdd_validate_context(hdd_ctx))
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;
}
event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
get_cca_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_CCA) ||
nla_put_u32(event, TOTAL_CYCLE_COUNT, stats->cycle_count) ||
nla_put_u32(event, IDLE_COUNT,
stats->cycle_count - stats->rxclr_count) ||
nla_put_u32(event, IBSS_RX_COUNT, stats->my_bss_rx_cycle_count) ||
nla_put_u32(event, OBSS_RX_COUNT,
stats->rx_frame_count - stats->my_bss_rx_cycle_count) ||
nla_put_u32(event, MAX_IBSS_RSSI, stats->max_rssi) ||
nla_put_u32(event, MIN_IBSS_RSSI, stats->min_rssi)) {
hdd_err("nla put failed");
kfree_skb(event);
return;
}
cfg80211_vendor_event(event, GFP_KERNEL);
}
/**
* hdd_medium_assess_cca() - clear channel assessment
* @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_cca(struct hdd_context *hdd_ctx,
struct hdd_adapter *adapter,
struct nlattr **tb)
{
struct wlan_objmgr_vdev *vdev;
uint32_t cca_period = DEFAULT_CCA_PERIOD;
uint8_t pdev_id, dcs_enable;
int status = 0;
vdev = hdd_objmgr_get_vdev(adapter);
if (!vdev)
return -EINVAL;
pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev));
dcs_enable = ucfg_get_dcs_enable(hdd_ctx->psoc, pdev_id);
if (!(dcs_enable & CAP_DCS_WLANIM)) {
hdd_err_rl("DCS_WLANIM is not enabled");
status = -EINVAL;
goto out;
}
if (qdf_atomic_read(&adapter->session.ap.acs_in_progress)) {
hdd_err_rl("ACS is in progress");
status = -EBUSY;
goto out;
}
if (tb[PERIOD])
cca_period = nla_get_u32(tb[PERIOD]);
if (cca_period == 0)
cca_period = DEFAULT_CCA_PERIOD;
ucfg_dcs_reset_user_stats(hdd_ctx->psoc, pdev_id);
ucfg_dcs_register_user_cb(hdd_ctx->psoc, pdev_id, adapter->vdev_id,
hdd_cca_notification_cb);
/* dcs is already enabled and dcs event is reported every second
* set the user request counter to collect user stats
*/
ucfg_dcs_set_user_request(hdd_ctx->psoc, pdev_id, cca_period);
out:
hdd_objmgr_put_vdev(vdev);
return status;
}
/*
* get_congestion_report_len() - Calculate length for congestion report
* to allocate skb buffer
*
@@ -277,6 +421,7 @@ static int __hdd_cfg80211_medium_assess(struct wiphy *wiphy,
switch (type) {
case QCA_WLAN_MEDIUM_ASSESS_CCA:
status = hdd_medium_assess_cca(hdd_ctx, adapter, tb);
break;
case QCA_WLAN_MEDIUM_ASSESS_CONGESTION_REPORT:
status = hdd_medium_assess_congestion_report(hdd_ctx, adapter,