qcacld-3.0: Add support for MLO LL_STATS

As part of MLO stats feature, add support to process link layer
stats for all MLO vdevs and store them in the corresponding adapters.

Change-Id: Ia6d731c94eaa3a355a9deae61d07dd06c5d412bd
CRs-Fixed: 3181021
This commit is contained in:
Aditya Kodukula
2022-03-31 20:55:59 -07:00
committed by Madan Koyyalamudi
parent 5e5a18dc60
commit 5e19348a66
6 changed files with 196 additions and 5 deletions

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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
@@ -30,6 +31,7 @@
#include "qdf_event.h"
/* For WMI_MAX_CHAINS */
#include "wmi_unified.h"
#include "wlan_mlo_mgr_cmn.h"
#ifdef QCA_SUPPORT_MC_CP_STATS
#include "wlan_cp_stats_public_structs.h"
@@ -228,6 +230,7 @@ struct medium_assess_data {
* @vdev_id: vdev_id of request
* @pdev_id: pdev_id of request
* @peer_mac_addr: peer mac address
* @ml_vdev_info: mlo_stats_vdev_params structure
*/
struct request_info {
void *cookie;
@@ -250,6 +253,9 @@ struct request_info {
uint32_t vdev_id;
uint32_t pdev_id;
uint8_t peer_mac_addr[QDF_MAC_ADDR_SIZE];
#ifdef WLAN_FEATURE_11BE_MLO
struct mlo_stats_vdev_params ml_vdev_info;
#endif
};
/**

View File

@@ -1319,6 +1319,7 @@ struct hdd_adapter {
#endif
#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
struct hdd_mlo_adapter_info mlo_adapter_info;
struct wifi_interface_stats ll_iface_stats;
#endif
#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE
void *set_mac_addr_req_ctx;

View File

@@ -1006,6 +1006,42 @@ static void hdd_link_layer_process_peer_stats(struct hdd_adapter *adapter,
cfg80211_vendor_cmd_reply(vendor_event);
}
#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)
/**
* hdd_cache_ll_iface_stats() - Caches ll_stats received from fw to adapter
* @hdd_ctx: Pointer to hdd_context
* @if_stat: Pointer to stats data
*
* After receiving Link Layer Interface statistics from FW. This function
* converts the firmware data to the NL data and caches them to the adapter.
*
* Return: None
*/
static void
hdd_cache_ll_iface_stats(struct hdd_context *hdd_ctx,
struct wifi_interface_stats *if_stat)
{
struct hdd_adapter *adapter;
adapter = hdd_get_adapter_by_vdev(hdd_ctx, if_stat->vdev_id);
/*
* There is no need for wlan_hdd_validate_context here. This is a NB
* operation that will come with DSC synchronization. This ensures that
* no driver transition will take place as long as this operation is
* not complete. Thus the need to check validity of hdd_context is not
* required.
*/
hdd_nofl_debug("Copying iface stats into the adapter");
adapter->ll_iface_stats = *if_stat;
}
#else
static void
hdd_cache_ll_iface_stats(struct hdd_context *hdd_ctx,
struct wifi_interface_stats *if_stat)
{
}
#endif
/**
* hdd_link_layer_process_iface_stats() - This function is called after
* @adapter: Pointer to device adapter
@@ -1026,6 +1062,10 @@ hdd_link_layer_process_iface_stats(struct hdd_adapter *adapter,
struct sk_buff *vendor_event;
struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
if (if_stat->vdev_id != adapter->vdev_id) {
hdd_cache_ll_iface_stats(hdd_ctx, if_stat);
return;
}
/*
* There is no need for wlan_hdd_validate_context here. This is a NB
* operation that will come with DSC synchronization. This ensures that
@@ -1483,6 +1523,12 @@ static void hdd_process_ll_stats(tSirLLStatsResults *results,
}
qdf_mem_copy(stats->result, results->results,
sizeof(struct wifi_interface_stats));
/* Firmware doesn't send peerstats event if no peers are
* connected. HDD should not wait for any peerstats in
* this case and return the status to middleware after
* receiving iface stats
*/
if (!results->num_peers)
priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
priv->request_bitmap &= ~stats->result_param_id;
@@ -1589,6 +1635,38 @@ static void hdd_debugfs_process_ll_stats(struct hdd_adapter *adapter,
}
static void
wlan_hdd_update_ll_stats_request_bitmap(struct hdd_context *hdd_ctx,
struct osif_request *request,
tSirLLStatsResults *results)
{
struct hdd_ll_stats_priv *priv = osif_request_priv(request);
bool is_mlo_link;
/* The radio stats event is expected at the last, for MLO ll_stats */
if (priv->request_bitmap != WMI_LINK_STATS_RADIO &&
results->paramId == WMI_LINK_STATS_RADIO) {
hdd_err("req_id %d resp_id %u req_bitmap 0x%x resp_bitmap 0x%x",
priv->request_id, results->rspId,
priv->request_bitmap, results->paramId);
QDF_DEBUG_PANIC("Out of order event received for MLO_LL_STATS");
}
is_mlo_link = wlan_vdev_mlme_get_is_mlo_link(hdd_ctx->psoc,
results->ifaceId);
/* In case of MLO Connection, set the request_bitmap */
if (is_mlo_link && results->paramId == WMI_LINK_STATS_IFACE) {
/* The radio stats are received at the last, hence set
* the request_bitmap for MLO link vdev iface stats.
*/
if (!(priv->request_bitmap & results->paramId))
priv->request_bitmap |= results->paramId;
hdd_nofl_debug("MLO_LL_STATS set request_bitmap = 0x%x",
priv->request_bitmap);
}
}
void wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle,
int indication_type,
tSirLLStatsResults *results,
@@ -1629,12 +1707,14 @@ void wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle,
return;
}
adapter = hdd_get_adapter_by_vdev(hdd_ctx, priv->vdev_id);
adapter = hdd_get_adapter_by_vdev(hdd_ctx, results->ifaceId);
if (!adapter) {
hdd_err("invalid vdev %d", priv->vdev_id);
hdd_err("invalid vdev %d", results->ifaceId);
return;
}
wlan_hdd_update_ll_stats_request_bitmap(hdd_ctx, request,
results);
if (results->rspId == DEBUGFS_LLSTATS_REQID) {
hdd_debugfs_process_ll_stats(adapter, results, request);
} else {
@@ -1945,12 +2025,48 @@ static void cache_station_stats_cb(struct stats_event *ev, void *cookie)
}
}
#ifdef WLAN_FEATURE_11BE_MLO
static QDF_STATUS
wlan_hdd_set_station_stats_request_pending(struct hdd_adapter *adapter)
wlan_hdd_get_mlo_vdev_params(struct hdd_adapter *adapter,
struct request_info *req_info,
tSirLLStatsGetReq *req)
{
struct wlan_objmgr_psoc *psoc = adapter->hdd_ctx->psoc;
struct mlo_stats_vdev_params *info = &req_info->ml_vdev_info;
int i;
uint32_t bmap = 0;
QDF_STATUS status;
req->is_mlo_req = wlan_vdev_mlme_get_is_mlo_vdev(psoc,
adapter->vdev_id);
status = mlo_get_mlstats_vdev_params(psoc, info, adapter->vdev_id);
if (QDF_IS_STATUS_ERROR(status))
return status;
for (i = 0; i < info->ml_vdev_count; i++)
bmap |= (1 << info->ml_vdev_id[i]);
req->mlo_vdev_id_bitmap = bmap;
return QDF_STATUS_SUCCESS;
}
#else
static QDF_STATUS
wlan_hdd_get_mlo_vdev_params(struct hdd_adapter *adapter,
struct request_info *req_info,
tSirLLStatsGetReq *req)
{
return QDF_STATUS_SUCCESS;
}
#endif
static QDF_STATUS
wlan_hdd_set_station_stats_request_pending(struct hdd_adapter *adapter,
tSirLLStatsGetReq *req)
{
struct wlan_objmgr_peer *peer;
struct request_info info = {0};
struct wlan_objmgr_vdev *vdev;
struct wlan_objmgr_psoc *psoc = adapter->hdd_ctx->psoc;
bool is_mlo_vdev = false;
QDF_STATUS status;
if (!adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req)
return QDF_STATUS_E_INVAL;
@@ -1968,6 +2084,15 @@ wlan_hdd_set_station_stats_request_pending(struct hdd_adapter *adapter)
info.cookie = adapter;
info.u.get_station_stats_cb = cache_station_stats_cb;
info.vdev_id = adapter->vdev_id;
is_mlo_vdev = wlan_vdev_mlme_get_is_mlo_vdev(psoc, adapter->vdev_id);
if (is_mlo_vdev) {
status = wlan_hdd_get_mlo_vdev_params(adapter, &info, req);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("unable to get vdev params for mlo stats");
return status;
}
}
info.pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev));
peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_OSIF_STATS_ID);
if (!peer) {
@@ -2036,7 +2161,8 @@ static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter)
#else
static QDF_STATUS
wlan_hdd_set_station_stats_request_pending(struct hdd_adapter *adapter)
wlan_hdd_set_station_stats_request_pending(struct hdd_adapter *adapter,
tSirLLStatsGetReq *req)
{
return QDF_STATUS_SUCCESS;
}
@@ -2072,7 +2198,7 @@ static int wlan_hdd_send_ll_stats_req(struct hdd_adapter *adapter,
hdd_enter_dev(adapter->dev);
status = wlan_hdd_set_station_stats_request_pending(adapter);
status = wlan_hdd_set_station_stats_request_pending(adapter, req);
if (status == QDF_STATUS_E_ALREADY)
return qdf_status_to_os_return(status);

View File

@@ -28,6 +28,9 @@
#define WLAN_HDD_STATS_H
#include "wlan_hdd_main.h"
#ifdef WLAN_FEATURE_11BE_MLO
#include "wlan_mlo_mgr_cmn.h"
#endif
#define INVALID_MCS_IDX 255
#define MAX_HT_MCS_IDX 8

View File

@@ -2916,6 +2916,8 @@ typedef struct {
uint32_t reqId;
uint8_t staId;
uint32_t paramIdMask;
bool is_mlo_req;
uint32_t mlo_vdev_id_bitmap;
} tSirLLStatsGetReq, *tpSirLLStatsGetReq;
typedef struct {
@@ -3141,6 +3143,7 @@ struct wifi_peer_info {
* @ac_stats: per-Access Category statistics
* @num_offload_stats: @offload_stats record count
* @offload_stats: per-offload statistics
* @vdev_id: vdev id
*
* Statistics corresponding to 2nd most LSB in wifi statistics bitmap
* for getting statistics
@@ -3155,6 +3158,7 @@ struct wifi_interface_stats {
wmi_wmm_ac_stats ac_stats[WIFI_AC_MAX];
uint32_t num_offload_stats;
wmi_iface_offload_stats offload_stats[WMI_OFFLOAD_STATS_TYPE_MAX];
uint8_t vdev_id;
};
/**

View File

@@ -2614,6 +2614,46 @@ wma_send_ll_stats_get_cmd(tp_wma_handle wma_handle,
}
#endif
#ifdef WLAN_FEATURE_11BE_MLO
static QDF_STATUS
wma_update_params_for_mlo_stats(tp_wma_handle wma,
const tpSirLLStatsGetReq getReq,
struct ll_stats_get_params *cmd)
{
struct wlan_objmgr_vdev *vdev;
uint8_t *mld_addr;
cmd->is_mlo_req = getReq->is_mlo_req;
vdev = wma->interfaces[getReq->staId].vdev;
if (!vdev) {
wma_err("Failed to get vdev for vdev_%d", getReq->staId);
return QDF_STATUS_E_FAILURE;
}
if (getReq->is_mlo_req) {
cmd->vdev_id_bitmap = getReq->mlo_vdev_id_bitmap;
mld_addr = wlan_vdev_mlme_get_mldaddr(vdev);
if (!mld_addr) {
wma_err("Failed to get mld_macaddr for vdev_%d",
getReq->staId);
return QDF_STATUS_E_FAILURE;
}
qdf_mem_copy(cmd->mld_macaddr.bytes, mld_addr,
QDF_MAC_ADDR_SIZE);
}
return QDF_STATUS_SUCCESS;
}
#else
static QDF_STATUS
wma_update_params_for_mlo_stats(tp_wma_handle wma,
const tpSirLLStatsGetReq getReq,
struct ll_stats_get_params *cmd)
{
return QDF_STATUS_SUCCESS;
}
#endif
QDF_STATUS wma_process_ll_stats_get_req(tp_wma_handle wma,
const tpSirLLStatsGetReq getReq)
{
@@ -2621,6 +2661,7 @@ QDF_STATUS wma_process_ll_stats_get_req(tp_wma_handle wma,
uint8_t *addr;
struct ll_stats_get_params cmd = {0};
int ret;
QDF_STATUS status;
if (!getReq || !wma) {
wma_err("input pointer is NULL");
@@ -2647,6 +2688,13 @@ QDF_STATUS wma_process_ll_stats_get_req(tp_wma_handle wma,
return QDF_STATUS_E_FAILURE;
}
qdf_mem_copy(cmd.peer_macaddr.bytes, addr, QDF_MAC_ADDR_SIZE);
status = wma_update_params_for_mlo_stats(wma, getReq, &cmd);
if (QDF_IS_STATUS_ERROR(status)) {
wma_err("Failed to update params for mlo_stats");
return status;
}
ret = wma_send_ll_stats_get_cmd(wma, &cmd);
if (ret) {
wma_err("Failed to send get link stats request");
@@ -2807,6 +2855,9 @@ int wma_unified_link_iface_stats_event_handler(void *handle,
iface_offload_stats++;
}
/* Copying vdev_id info into the iface_stat for MLO*/
iface_stat->vdev_id = fixed_param->vdev_id;
/* call hdd callback with Link Layer Statistics
* vdev_id/ifacId in link_stats_results will be
* used to retrieve the correct HDD context