|
@@ -724,6 +724,9 @@ 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;
|
|
|
|
|
|
if (qdf_unlikely(!pdev)) {
|
|
|
cfr_err("pdev is null\n");
|
|
@@ -841,14 +844,71 @@ void target_if_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf)
|
|
|
meta->rtt_cfo_measurement = cfr_info->rtt_cfo_measurement;
|
|
|
meta->rx_start_ts = cfr_info->rx_start_ts;
|
|
|
|
|
|
- meta->agc_gain[0] = get_gain_db(get_u16_lsb(cfr_info->agc_gain_info0));
|
|
|
- meta->agc_gain[1] = get_gain_db(get_u16_msb(cfr_info->agc_gain_info0));
|
|
|
- meta->agc_gain[2] = get_gain_db(get_u16_lsb(cfr_info->agc_gain_info1));
|
|
|
- meta->agc_gain[3] = get_gain_db(get_u16_msb(cfr_info->agc_gain_info1));
|
|
|
- meta->agc_gain[4] = get_gain_db(get_u16_lsb(cfr_info->agc_gain_info2));
|
|
|
- meta->agc_gain[5] = get_gain_db(get_u16_msb(cfr_info->agc_gain_info2));
|
|
|
- meta->agc_gain[6] = get_gain_db(get_u16_lsb(cfr_info->agc_gain_info3));
|
|
|
- meta->agc_gain[7] = get_gain_db(get_u16_msb(cfr_info->agc_gain_info3));
|
|
|
+ gain_info[0] = get_u16_lsb(cfr_info->agc_gain_info0);
|
|
|
+ gain_info[1] = get_u16_msb(cfr_info->agc_gain_info0);
|
|
|
+ gain_info[2] = get_u16_lsb(cfr_info->agc_gain_info1);
|
|
|
+ gain_info[3] = get_u16_msb(cfr_info->agc_gain_info1);
|
|
|
+ gain_info[4] = get_u16_lsb(cfr_info->agc_gain_info2);
|
|
|
+ gain_info[5] = get_u16_msb(cfr_info->agc_gain_info2);
|
|
|
+ gain_info[6] = get_u16_lsb(cfr_info->agc_gain_info3);
|
|
|
+ gain_info[7] = get_u16_msb(cfr_info->agc_gain_info3);
|
|
|
+
|
|
|
+ for (i = 0; i < HOST_MAX_CHAINS; i++) {
|
|
|
+ meta->agc_gain[i] = get_gain_db(gain_info[i]);
|
|
|
+
|
|
|
+ if (pcfr->is_aoa_for_rcc_support &&
|
|
|
+ (i < pcfr->max_aoa_chains) &&
|
|
|
+ (get_gain_table_idx(gain_info[i]) != 0)) {
|
|
|
+ cfr_debug("Invalid gain table index reported");
|
|
|
+ invalid_gain_table_idx = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (meta->agc_gain[i] > MAX_AGC_GAIN)
|
|
|
+ meta->agc_gain[i] = MAX_AGC_GAIN;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Do not derive the chain phase when capability is not set Or
|
|
|
+ * when an invalid gain table index is reported by Hardware.
|
|
|
+ */
|
|
|
+ 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 {
|
|
|
+ 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)
|
|
|
+ meta->chain_phase[i] = INVALID_PHASE_DELTA;
|
|
|
+ else
|
|
|
+ meta->chain_phase[i] = ((pcfr->ibf_cal_val[i] +
|
|
|
+ pdelta) % 1024);
|
|
|
+ }
|
|
|
+ } 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++) {
|
|
|
+ meta->chain_phase[i] = INVALID_PHASE_DELTA;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
meta->mcs_rate = cfr_info->mcs_rate;
|
|
|
meta->gi_type = cfr_info->gi_type;
|
|
@@ -1184,6 +1244,109 @@ static void dump_cfr_peer_tx_event_enh(wmi_cfr_peer_tx_event_param *event,
|
|
|
event->chain_rssi[0]);
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+target_if_pdev_aoa_phasedaelta_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;
|
|
|
+ int c, g, pc, pg;
|
|
|
+ struct wmi_cfr_phase_delta_param param = {0};
|
|
|
+ uint32_t c_mask;
|
|
|
+
|
|
|
+ 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_phase_delta_event
|
|
|
+ (wmi_handle, data, ¶m);
|
|
|
+
|
|
|
+ if (QDF_IS_STATUS_ERROR(retval)) {
|
|
|
+ cfr_err("Failed to extract phase params");
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ retval = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID);
|
|
|
+ if (retval != QDF_STATUS_SUCCESS) {
|
|
|
+ cfr_err("failed to get pdev reference");
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!pcfr->is_aoa_for_rcc_support) {
|
|
|
+ cfr_err("AoA data event from unsupported target");
|
|
|
+ }
|
|
|
+
|
|
|
+ pcfr->freq = param.freq;
|
|
|
+ pcfr->max_aoa_chains = param.max_chains;
|
|
|
+
|
|
|
+ c_mask = param.chain_phase_mask;
|
|
|
+ pc = 0;
|
|
|
+
|
|
|
+ /* populate phase delta for max chains indicated by target */
|
|
|
+ for (c = 0; c < pcfr->max_aoa_chains; c++) {
|
|
|
+ pg = 0;
|
|
|
+ if (((0x1 << c) & c_mask) && (pc < WMI_MAX_CHAINS_PHASE)) {
|
|
|
+ pcfr->ibf_cal_val[c] = param.ibf_cal_val[pc];
|
|
|
+ for (g = 0; g < MAX_AGC_GAIN; g = g + 2) {
|
|
|
+ if (pg < WMI_MAX_AOA_PHASE_DELTA) {
|
|
|
+ pcfr->phase_delta[c][g] = get_u16_lsb
|
|
|
+ (param.phase_delta[pc][pg]);
|
|
|
+ pcfr->phase_delta[c][g + 1] = get_u16_msb
|
|
|
+ (param.phase_delta[pc][pg]);
|
|
|
+ pg++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pc++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID);
|
|
|
+ wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID);
|
|
|
+
|
|
|
+ return retval;
|
|
|
+}
|
|
|
+
|
|
|
#ifdef DIRECT_BUF_RX_ENABLE
|
|
|
/**
|
|
|
* enh_prepare_cfr_header_txstatus() - Prepare CFR metadata for TX failures
|
|
@@ -1461,6 +1624,67 @@ target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+/**
|
|
|
+ * target_if_register_phase_delta_for_rcc_event_handler() - Register callback
|
|
|
+ * for WMI phase delta event
|
|
|
+ * @psoc: PSOC object
|
|
|
+ *
|
|
|
+ * Return: Success/Failure status
|
|
|
+ */
|
|
|
+static QDF_STATUS
|
|
|
+target_if_register_phase_delta_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_aoa_phasedelta_event_id,
|
|
|
+ target_if_pdev_aoa_phasedaelta_event_handler,
|
|
|
+ WMI_RX_UMAC_CTX);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Event registration is called per pdev
|
|
|
+ * Ignore erorr if event is alreday registred.
|
|
|
+ */
|
|
|
+ if (ret == QDF_STATUS_E_FAILURE)
|
|
|
+ ret = QDF_STATUS_SUCCESS;
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * target_if_unregister_phase_delta_for_rcc_event_handler() - Unregister
|
|
|
+ * call back for WMI phase delta for rcc event
|
|
|
+ * @psoc: PSOC object
|
|
|
+ *
|
|
|
+ * Return Success/Failure status
|
|
|
+ */
|
|
|
+static QDF_STATUS
|
|
|
+target_if_unregister_phase_delta_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_aoa_phasedelta_event_id);
|
|
|
+
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* target_if_register_tx_completion_enh_event_handler() - Register callback for
|
|
|
* WMI TX completion event
|
|
@@ -1739,6 +1963,12 @@ QDF_STATUS cfr_enh_init_pdev(struct wlan_objmgr_psoc *psoc,
|
|
|
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");
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+
|
|
|
pcfr->is_cfr_rcc_capable = 1;
|
|
|
pcfr->rcc_param.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
|
|
|
pcfr->rcc_param.modified_in_curr_session = MAX_RESET_CFG_ENTRY;
|
|
@@ -1748,6 +1978,17 @@ QDF_STATUS cfr_enh_init_pdev(struct wlan_objmgr_psoc *psoc,
|
|
|
pcfr->is_cap_interval_mode_sel_support =
|
|
|
cfr_sc->is_cap_interval_mode_sel_support;
|
|
|
pcfr->is_mo_marking_support = cfr_sc->is_mo_marking_support;
|
|
|
+ pcfr->is_aoa_for_rcc_support = cfr_sc->is_aoa_for_rcc_support;
|
|
|
+
|
|
|
+ if (pcfr->is_aoa_for_rcc_support) {
|
|
|
+ qdf_mem_set(pcfr->ibf_cal_val,
|
|
|
+ sizeof(uint32_t) * HOST_MAX_CHAINS,
|
|
|
+ 0);
|
|
|
+ qdf_mem_set(pcfr->phase_delta,
|
|
|
+ sizeof(uint16_t) * HOST_MAX_CHAINS * MAX_AGC_GAIN,
|
|
|
+ 0);
|
|
|
+ pcfr->max_aoa_chains = 0;
|
|
|
+ }
|
|
|
|
|
|
target_if_cfr_default_ta_ra_config(&pcfr->rcc_param,
|
|
|
true, MAX_RESET_CFG_ENTRY);
|
|
@@ -1854,6 +2095,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_phase_delta_for_rcc_event_handler(psoc);
|
|
|
+ if (status != QDF_STATUS_SUCCESS)
|
|
|
+ cfr_err("Failed to unregister phase delta handler");
|
|
|
+
|
|
|
qdf_spinlock_destroy(&pcfr->lut_lock);
|
|
|
|
|
|
return status;
|