qcacmn: Extract enhanced aoa data

Changes to extract enhanced aoa data from WMI event

CRs-Fixed: 3553725
Change-Id: I4a37fdb889cd5d461ee6ef92966a042aeed91fc8
This commit is contained in:
Shwetha G K 2023-08-02 19:26:42 +05:30 committed by Rahul Choudhary
parent 2a073ca079
commit 0536af115e
2 changed files with 461 additions and 94 deletions

View File

@ -114,8 +114,6 @@
#define STREAMFS_NUM_SUBBUF_WAIKIKI 127
#define MAX_AGC_GAIN_VALUE_WAIKIKI 64
/* Max 4 users in MU case for Spruce */
#define SPRUCE_CFR_MU_USERS 4

View File

@ -29,6 +29,7 @@
#include <target_if_direct_buf_rx_api.h>
#include <target_if_cfr_enh.h>
#include "cdp_txrx_ctrl.h"
#include <wlan_reg_services_api.h>
#define CMN_NOISE_FLOOR (-96)
#define NUM_CHAINS_FW_TO_HOST(n) ((1 << ((n) + 1)) - 1)
@ -63,7 +64,7 @@ u_int32_t snr_to_signal_strength(uint8_t snr)
#endif
/**
* tagret_if_snr_to_signal_strength() - wrapper API to snr_to_signal_strength to
* target_if_snr_to_signal_strength() - wrapper API to snr_to_signal_strength to
* consider target_type.
* @target_type: target type of the pdev
* @meta: pointer to CFR metadata
@ -942,21 +943,222 @@ bool target_if_cfr_get_11be_support_flag(uint8_t pdev_id,
}
#endif
/**
* target_if_get_max_agc_gain(): Function to get the max agc gain supported
* based on the target_type
*
* @target_type: target type to which max agc gain needed
*
* Return: max agc gain value supported on target_type
*/
#ifdef WLAN_RCC_ENHANCED_AOA_SUPPORT
static inline
uint32_t target_if_get_max_agc_gain(uint32_t target_type)
bool is_valid_gain_table_idx(uint16_t tbl_idx, struct pdev_cfr *pcfr)
{
if (target_type == TARGET_TYPE_QCN9224)
return MAX_AGC_GAIN_VALUE_WAIKIKI;
else
/* if default gain table return true */
if (!tbl_idx)
return true;
/* non zero gain table is invalid when is_enh_aoa_data is not set */
if (!pcfr->is_enh_aoa_data)
return false;
if ((tbl_idx > 0) && (tbl_idx < pcfr->max_agc_gain_tbls))
return true;
return false;
}
static inline
uint16_t get_max_agc_gain(struct wlan_objmgr_vdev *vdev,
uint16_t tbl_idx, struct pdev_cfr *pcfr,
bool supports_11be)
{
uint16_t *max_agc_gain_per_tbl = NULL;
struct wlan_channel *bss_chan;
if (!supports_11be)
return MAX_AGC_GAIN;
if (!pcfr->is_enh_aoa_data)
return INVALID_AGC_GAIN;
bss_chan = wlan_vdev_mlme_get_bss_chan(vdev);
if (wlan_reg_is_24ghz_ch_freq(bss_chan->ch_freq))
max_agc_gain_per_tbl = pcfr->max_agc_gain_per_tbl_2g;
else if (wlan_reg_is_5ghz_ch_freq(bss_chan->ch_freq))
max_agc_gain_per_tbl = pcfr->max_agc_gain_per_tbl_5g;
else if (wlan_reg_is_6ghz_chan_freq(bss_chan->ch_freq))
max_agc_gain_per_tbl = pcfr->max_agc_gain_per_tbl_6g;
if (is_valid_gain_table_idx(tbl_idx, pcfr) && max_agc_gain_per_tbl)
return max_agc_gain_per_tbl[tbl_idx];
else
return INVALID_AGC_GAIN;
}
static
void populate_enh_chain_phase(struct wlan_objmgr_vdev *vdev,
struct pdev_cfr *pcfr,
struct enh_cfr_metadata *meta,
bool invalid_gain_table_idx)
{
uint16_t *phase_array, *gain_array;
uint16_t phase_delta;
uint32_t start_ent, stop_ent, chain, tbl_idx, grp_stp_idx, found;
uint32_t data_idx, rf_chain;
if (invalid_gain_table_idx || !pcfr->is_enh_aoa_data) {
/**
* When AoA is enabled but invalid gain table index is reported
* by HW, it indicates the AoA result is not reliable. Hence,
* set the chain_phase to 0xFFFF indicating an error.
* Set invalid phase when enhanced aoa capability is not set.
*/
for (chain = 0; chain < pcfr->max_aoa_chains; chain++)
meta->chain_phase[chain] = INVALID_PHASE_DELTA;
return;
}
for (chain = 0; chain < pcfr->max_aoa_chains; chain++) {
rf_chain = (pcfr->xbar_config) ?
((pcfr->xbar_config >> (3 * chain)) & 0x07) :
chain;
data_idx = (rf_chain * pcfr->max_entries_all_table);
phase_array = &pcfr->enh_phase_delta_array[data_idx];
gain_array = &pcfr->gain_stop_index_array[data_idx];
tbl_idx = meta->agc_gain_tbl_index[chain];
start_ent = pcfr->start_ent[tbl_idx];
stop_ent = start_ent + pcfr->max_bdf_entries_per_tbl[tbl_idx];
/**
* if default gain table exceeds max_agc_gain, chain_phase needs
* to be considered as 0. Remaining gain tables would have a
* phase delta assigned with max agc gain as well
*/
if (!tbl_idx && (meta->agc_gain[chain] ==
get_max_agc_gain(vdev, tbl_idx, pcfr, true))) {
phase_delta = 0;
meta->chain_phase[chain] =
(pcfr->ibf_cal_val[rf_chain] +
phase_delta) & 0x3FF;
continue;
}
for (grp_stp_idx = start_ent, found = 0;
grp_stp_idx < stop_ent; grp_stp_idx++) {
if (meta->agc_gain[chain] <= gain_array[grp_stp_idx]) {
phase_delta = phase_array[grp_stp_idx];
found = 1;
break;
}
}
if ((!found) && (grp_stp_idx >= stop_ent))
phase_delta = 0;
meta->chain_phase[chain] = (pcfr->ibf_cal_val[rf_chain] +
phase_delta) & 0x3FF;
}
}
#else
static inline
bool is_valid_gain_table_idx(uint16_t tbl_idx, struct pdev_cfr *pcfr)
{
/* if default gain table return true */
if (!tbl_idx)
return true;
return false;
}
static inline
uint16_t get_max_agc_gain(struct wlan_objmgr_vdev *vdev,
uint16_t tbl_idx, struct pdev_cfr *pcfr,
bool supports_11be)
{
if (!supports_11be)
return MAX_AGC_GAIN;
return INVALID_AGC_GAIN;
}
static
void populate_enh_chain_phase(struct wlan_objmgr_vdev *vdev,
struct pdev_cfr *pcfr,
struct enh_cfr_metadata *meta,
bool invalid_gain_table_idx)
{
uint8_t chain;
cfr_debug("Enahced AoA not supported.. Invsetigate");
for (chain = 0; chain < pcfr->max_aoa_chains; chain++)
meta->chain_phase[chain] = INVALID_PHASE_DELTA;
}
#endif /* WLAN_RCC_ENHANCED_AOA_SUPPORT */
static
void populate_chain_phase(struct wlan_objmgr_vdev *vdev,
struct pdev_cfr *pcfr,
struct enh_cfr_metadata *meta,
bool invalid_gain_table_idx)
{
uint8_t i;
uint16_t gain, pdelta;
if (invalid_gain_table_idx) {
/**
* When AoA is enabled but invalid gain table index is reported
* by HW, it indicates the AoA result is not reliable. Hence,
* set the chain_phase to 0xFFFF indicating an error.
*/
for (i = 0; i < pcfr->max_aoa_chains; i++) {
if (wlan_vdev_mlme_is_special_vdev(vdev) &&
i == CHAIN_SHIFT_INDEX_PINE_SCAN) {
meta->chain_phase[i - 1] = INVALID_PHASE_DELTA;
break;
}
meta->chain_phase[i] = INVALID_PHASE_DELTA;
}
return;
}
for (i = 0; i < pcfr->max_aoa_chains; i++) {
/**
* phase delta stored in reverse order by FW.
* Hence, index accordingly
*/
gain = meta->agc_gain[i];
if (gain < MAX_AGC_GAIN) {
pdelta = pcfr->phase_delta[i][MAX_AGC_GAIN -
1 -
gain];
} else {
/* populate 0 for last gain index */
pdelta = 0;
}
/**
* FW sets 0xFFFF as invalid phase delta in
* invalid cases. Retain same in HOST as well.
* In case of valid phase, add the ibf cal value
* to the delta & ensure the derived phase value
* is in the range of 0 - 1024 indicating 0 - 360
* degrees
*/
if (pdelta == INVALID_PHASE_DELTA) {
if (wlan_vdev_mlme_is_special_vdev(vdev) &&
i == CHAIN_SHIFT_INDEX_PINE_SCAN) {
meta->chain_phase[i - 1] =
INVALID_PHASE_DELTA;
break;
}
meta->chain_phase[i] = INVALID_PHASE_DELTA;
} else {
if (wlan_vdev_mlme_is_special_vdev(vdev) &&
i == CHAIN_SHIFT_INDEX_PINE_SCAN) {
meta->chain_phase[i - 1] =
((pcfr->ibf_cal_val[i] +
pdelta) & 0x3FF);
break;
}
meta->chain_phase[i] = ((pcfr->ibf_cal_val[i] +
pdelta) & 0x3FF);
}
}
}
/**
@ -991,15 +1193,13 @@ void target_if_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf)
uint8_t srng_id = 0;
struct wlan_lmac_if_rx_ops *rx_ops;
uint32_t target_type;
uint16_t pdelta, gain;
uint16_t gain_info[HOST_MAX_CHAINS];
bool invalid_gain_table_idx = false;
uint32_t target_max_agc_gain = 0;
uint32_t max_agc_gain = 0;
bool supports_11be;
uint8_t pdev_id;
struct target_psoc_info *tgt_hdl;
if (qdf_unlikely(!pdev)) {
cfr_err("pdev is null\n");
qdf_nbuf_free(nbuf);
@ -1136,95 +1336,39 @@ void target_if_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf)
gain_info[6] = get_u16_lsb(cfr_info->agc_gain_info3);
gain_info[7] = get_u16_msb(cfr_info->agc_gain_info3);
target_max_agc_gain = target_if_get_max_agc_gain(target_type);
for (i = 0; i < HOST_MAX_CHAINS; i++) {
meta->agc_gain[i] = get_gain_db(gain_info[i]);
meta->agc_gain_tbl_index[i] = get_gain_table_idx(gain_info[i]);
if (pcfr->is_aoa_for_rcc_support &&
(i < pcfr->max_aoa_chains) &&
(meta->agc_gain_tbl_index[i] != 0)) {
max_agc_gain = get_max_agc_gain(vdev,
meta->agc_gain_tbl_index[i],
pcfr,
supports_11be);
if (!is_valid_gain_table_idx(meta->agc_gain_tbl_index[i],
pcfr)) {
cfr_debug("Invalid gain table index reported");
invalid_gain_table_idx = true;
}
if (meta->agc_gain[i] > target_max_agc_gain)
meta->agc_gain[i] = target_max_agc_gain;
if (meta->agc_gain[i] > max_agc_gain)
meta->agc_gain[i] = max_agc_gain;
}
if (wlan_vdev_mlme_is_special_vdev(vdev)) {
for (i = 0; i < pcfr->max_aoa_chains; i++)
meta->chain_phase[i] = INVALID_PHASE_DELTA;
}
/**
* Do not derive the chain phase when capability is not set Or
* when an invalid gain table index is reported by Hardware.
*/
if (wlan_vdev_mlme_is_special_vdev(vdev)) {
for (i = 0; i < pcfr->max_aoa_chains; i++)
meta->chain_phase[i] = INVALID_PHASE_DELTA;
}
if (pcfr->is_aoa_for_rcc_support && !invalid_gain_table_idx) {
for (i = 0; i < pcfr->max_aoa_chains; i++) {
/**
* phase delta stored in reverse order by FW.
* Hence, index accordingly
*/
gain = meta->agc_gain[i];
if (gain < MAX_AGC_GAIN) {
pdelta = pcfr->phase_delta[i][MAX_AGC_GAIN -
1 -
gain];
} else if (supports_11be &&
gain < target_max_agc_gain) {
/**
* 11be supports gain 62, 63 & gain 61's phase
* delta need to be copied to 62 & 63
*/
pdelta = pcfr->phase_delta[i][0];
if (pcfr->is_aoa_for_rcc_support) {
if (supports_11be) {
populate_enh_chain_phase(vdev, pcfr,
meta, invalid_gain_table_idx);
} else {
/* populate 0 for last gain index */
pdelta = 0;
}
/**
* FW sets 0xFFFF as invalid phase delta in
* invalid cases. Retain same in HOST as well.
* In case of valid phase, add the ibf cal value
* to the delta & ensure the derived phase value
* is in the range of 0 - 1024 indicating 0 - 360
* degrees
*/
if (pdelta == INVALID_PHASE_DELTA) {
if (wlan_vdev_mlme_is_special_vdev(vdev) &&
i == CHAIN_SHIFT_INDEX_PINE_SCAN) {
meta->chain_phase[i - 1] =
INVALID_PHASE_DELTA;
break;
}
meta->chain_phase[i] = INVALID_PHASE_DELTA;
} else {
if (wlan_vdev_mlme_is_special_vdev(vdev) &&
i == CHAIN_SHIFT_INDEX_PINE_SCAN) {
meta->chain_phase[i - 1] =
((pcfr->ibf_cal_val[i] +
pdelta) & 0x3FF);
break;
}
meta->chain_phase[i] = ((pcfr->ibf_cal_val[i] +
pdelta) & 0x3FF);
}
}
} else if (pcfr->is_aoa_for_rcc_support) {
/**
* When AoA is enabled but invalid gain table index is reported
* by HW, it indicates the AoA result is not reliable. Hence,
* set the chain_phase to 0xFFFF indicating an error.
*/
for (i = 0; i < pcfr->max_aoa_chains; i++) {
if (wlan_vdev_mlme_is_special_vdev(vdev) &&
i == CHAIN_SHIFT_INDEX_PINE_SCAN) {
meta->chain_phase[i - 1] = INVALID_PHASE_DELTA;
break;
}
meta->chain_phase[i] = INVALID_PHASE_DELTA;
populate_chain_phase(vdev, pcfr,
meta, invalid_gain_table_idx);
}
}
@ -1668,6 +1812,158 @@ target_if_pdev_aoa_phasedaelta_event_handler(ol_scn_t sc,
return retval;
}
#ifdef WLAN_RCC_ENHANCED_AOA_SUPPORT
static int
target_if_pdev_enhanced_aoa_phasedelta_event_handler(ol_scn_t sc,
uint8_t *data,
uint32_t datalen)
{
struct wmi_unified *wmi_handle;
struct wlan_objmgr_psoc *psoc;
struct wlan_objmgr_pdev *pdev;
struct pdev_cfr *pcfr;
QDF_STATUS retval = 0;
struct wmi_cfr_enh_phase_delta_param param = {0};
uint32_t dst_idx, src_idx, max_src_ent, max_dst_ent;
uint32_t num_data_chains;
uint32_t offset;
qdf_bitmap(data_chain_bmap, sizeof(uint32_t) * QDF_CHAR_BIT);
if (!sc || !data) {
cfr_err("sc or data is null");
return -EINVAL;
}
psoc = target_if_get_psoc_from_scn_hdl(sc);
if (!psoc) {
cfr_err("psoc is null");
return -EINVAL;
}
retval = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_CFR_ID);
if (QDF_IS_STATUS_ERROR(retval)) {
cfr_err("unable to get psoc reference");
return -EINVAL;
}
wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
if (!wmi_handle) {
cfr_err("wmi_handle is null");
wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
return -EINVAL;
}
retval = wmi_extract_cfr_pdev_enhanced_aoa_phasedelta_event_fixed_param
(wmi_handle, data, &param);
if (QDF_IS_STATUS_ERROR(retval)) {
cfr_err("Failed to extract phase delta fixed param tlv");
wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
return -EINVAL;
}
pdev = wlan_objmgr_get_pdev_by_id(psoc, param.pdev_id, WLAN_CFR_ID);
if (!pdev) {
cfr_err("pdev is null");
wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
return -EINVAL;
}
pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
if (!pcfr) {
cfr_err("pdev object for CFR is NULL");
wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
return -EINVAL;
}
pcfr->freq = param.freq;
pcfr->max_aoa_chains = (param.max_chains <= HOST_MAX_CHAINS) ?
param.max_chains : HOST_MAX_CHAINS;
num_data_chains = qdf_get_hweight32(param.data_for_chainmask);
if (num_data_chains != param.max_chains)
cfr_debug("data not received for all chains");
qdf_mem_zero(data_chain_bmap, sizeof(data_chain_bmap));
qdf_mem_copy(data_chain_bmap, &param.data_for_chainmask,
qdf_min(sizeof(data_chain_bmap),
sizeof(param.data_for_chainmask)));
pcfr->xbar_config = param.xbar_config;
qdf_mem_copy(pcfr->ibf_cal_val, param.ibf_cal_val,
sizeof(uint32_t) * HOST_MAX_CHAINS);
param.array_size = (pcfr->max_aoa_chains *
pcfr->max_entries_all_table * sizeof(uint16_t));
param.gain_stop_index_array = qdf_mem_malloc(param.array_size);
if (!param.gain_stop_index_array) {
cfr_err("Failed to allocate gain stop index array");
wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
return -EINVAL;
}
param.enh_phase_delta_array = qdf_mem_malloc(param.array_size);
if (!param.enh_phase_delta_array) {
cfr_err("Failed to allocate phase delta array");
qdf_mem_free(param.gain_stop_index_array);
wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
return -EINVAL;
}
qdf_mem_zero(param.gain_stop_index_array, param.array_size);
qdf_mem_zero(param.enh_phase_delta_array, param.array_size);
retval = wmi_extract_cfr_pdev_enhanced_aoa_phasedelta_event_data
(wmi_handle, data, &param);
if (QDF_IS_STATUS_ERROR(retval)) {
cfr_err("Failed to extract phase data tlv");
wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
qdf_mem_free(param.gain_stop_index_array);
qdf_mem_free(param.enh_phase_delta_array);
return -EINVAL;
}
if (!pcfr->is_aoa_for_rcc_support || !pcfr->is_enh_aoa_data)
cfr_err("AoA data event from unsupported target");
max_src_ent = param.array_size / sizeof(uint32_t);
max_dst_ent = pcfr->max_entries_all_table * pcfr->max_aoa_chains;
offset = pcfr->max_entries_all_table *
qdf_find_first_bit(data_chain_bmap,
sizeof(uint32_t) * QDF_CHAR_BIT);
for (dst_idx = (0 + offset), src_idx = 0;
((dst_idx < max_dst_ent) && (src_idx < max_src_ent));
dst_idx += 2, src_idx++) {
uint32_t data;
data = param.gain_stop_index_array[src_idx];
pcfr->gain_stop_index_array[dst_idx] = get_u16_lsb(data);
pcfr->gain_stop_index_array[dst_idx + 1] = get_u16_msb(data);
data = param.enh_phase_delta_array[src_idx];
pcfr->enh_phase_delta_array[dst_idx] = get_u16_lsb(data);
pcfr->enh_phase_delta_array[dst_idx + 1] = get_u16_msb(data);
}
wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
qdf_mem_free(param.gain_stop_index_array);
qdf_mem_free(param.enh_phase_delta_array);
return QDF_STATUS_SUCCESS;
}
#endif /* WLAN_RCC_ENHANCED_AOA_SUPPORT */
#ifdef DIRECT_BUF_RX_ENABLE
/**
* enh_prepare_cfr_header_txstatus() - Prepare CFR metadata for TX failures
@ -2012,6 +2308,69 @@ target_if_unregister_phase_delta_for_rcc_event_handler(struct wlan_objmgr_psoc
return status;
}
#ifdef WLAN_RCC_ENHANCED_AOA_SUPPORT
static QDF_STATUS
target_if_register_enh_phase_for_rcc_event_handler(struct wlan_objmgr_psoc
*psoc)
{
wmi_unified_t wmi_hdl;
QDF_STATUS ret = QDF_STATUS_SUCCESS;
wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc);
if (!wmi_hdl) {
cfr_err("Unable to get wmi handle");
return QDF_STATUS_E_NULL_VALUE;
}
ret = wmi_unified_register_event_handler
(wmi_hdl, wmi_pdev_enhanced_aoa_phasedelta_eventid,
target_if_pdev_enhanced_aoa_phasedelta_event_handler,
WMI_RX_UMAC_CTX);
/*
* Event registration is called per pdev
* Ignore error if event is already registered.
*/
if (ret == QDF_STATUS_E_FAILURE)
ret = QDF_STATUS_SUCCESS;
return ret;
}
static QDF_STATUS
target_if_unregister_enh_phase_for_rcc_event_handler(struct wlan_objmgr_psoc
*psoc)
{
wmi_unified_t wmi_hdl;
QDF_STATUS status = QDF_STATUS_SUCCESS;
wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc);
if (!wmi_hdl) {
cfr_err("Unable to get wmi handle");
return QDF_STATUS_E_NULL_VALUE;
}
status = wmi_unified_unregister_event
(wmi_hdl, wmi_pdev_enhanced_aoa_phasedelta_eventid);
return status;
}
#else
static QDF_STATUS
target_if_register_enh_phase_for_rcc_event_handler(struct wlan_objmgr_psoc
*psoc)
{
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS
target_if_unregister_enh_phase_for_rcc_event_handler(struct wlan_objmgr_psoc
*psoc)
{
return QDF_STATUS_SUCCESS;
}
#endif /* WLAN_RCC_ENHANCED_AOA_SUPPORT */
/**
* target_if_register_tx_completion_enh_event_handler() - Register callback for
* WMI TX completion event
@ -2292,6 +2651,12 @@ QDF_STATUS cfr_enh_init_pdev(struct wlan_objmgr_psoc *psoc,
return status;
}
status = target_if_register_enh_phase_for_rcc_event_handler(psoc);
if (status != QDF_STATUS_SUCCESS) {
cfr_err("Failed to register with phase delta event handler");
return status;
}
status = target_if_register_phase_delta_for_rcc_event_handler(psoc);
if (status != QDF_STATUS_SUCCESS) {
cfr_err("Failed to register with phase delta event handler");
@ -2442,6 +2807,10 @@ QDF_STATUS cfr_enh_deinit_pdev(struct wlan_objmgr_psoc *psoc,
if (status != QDF_STATUS_SUCCESS)
cfr_err("Failed to register with dbr");
status = target_if_unregister_enh_phase_for_rcc_event_handler(psoc);
if (status != QDF_STATUS_SUCCESS)
cfr_err("Failed to unregister phase delta handler");
status = target_if_unregister_phase_delta_for_rcc_event_handler(psoc);
if (status != QDF_STATUS_SUCCESS)
cfr_err("Failed to unregister phase delta handler");