Browse Source

qcacmn: Derive phase from agc gain & phase delta

Changes to derive chain phase values out of Hardware
reported agc gain and target reported AoA phase calibration
values. AoA for RCC to be supported based on target shared
capability. AoA phase delta & ibf cal values are shared by
target upon every channel change via WMI event.

Change-Id: Ic4fca3731b795e07a511388f6dbb15a46d676a77
Shwetha G K 4 years ago
parent
commit
ac4740da88

+ 14 - 0
target_if/cfr/inc/target_if_cfr.h

@@ -51,6 +51,9 @@
 #define get_u16_lsb(value) (uint16_t)(value)
 #define get_u16_msb(value) (uint16_t)(((uint32_t)value) >> 16)
 #define get_gain_db(value) ((value) & 0xFF)
+#define get_gain_table_idx(value) (((value) >> 8) & 0x3)
+
+#define INVALID_PHASE_DELTA 0xFFFF
 
 /**
  * target_if_cfr_init_pdev() - Inits cfr pdev and registers necessary handlers.
@@ -159,6 +162,17 @@ QDF_STATUS
 target_if_cfr_set_mo_marking_support(struct wlan_objmgr_psoc *psoc,
 				     uint8_t value);
 
+/**
+ * target_if_cfr_set_aoa_for_rcc_support() - Function to set AoA for RCC
+ * @psoc: pointer to psoc object
+ * @value: value to be set
+ *
+ * Return: success/failure
+ */
+QDF_STATUS
+target_if_cfr_set_aoa_for_rcc_support(struct wlan_objmgr_psoc *psoc,
+				      uint8_t value);
+
 /**
  * target_if_cfr_info_send() - Function to send cfr info to upper layers
  * @pdev: pointer to pdev object

+ 19 - 0
target_if/cfr/src/target_if_cfr.c

@@ -718,6 +718,25 @@ target_if_cfr_set_mo_marking_support(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_E_INVAL;
 }
 
+QDF_STATUS
+target_if_cfr_set_aoa_for_rcc_support(struct wlan_objmgr_psoc *psoc,
+				      uint8_t value)
+{
+	struct wlan_lmac_if_rx_ops *rx_ops;
+
+	rx_ops = wlan_psoc_get_lmac_if_rxops(psoc);
+	if (!rx_ops) {
+		cfr_err("rx_ops is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (rx_ops->cfr_rx_ops.cfr_aoa_for_rcc_support_set)
+		return rx_ops->cfr_rx_ops.cfr_aoa_for_rcc_support_set(
+						psoc, value);
+
+	return QDF_STATUS_E_INVAL;
+}
+
 void target_if_cfr_info_send(struct wlan_objmgr_pdev *pdev, void *head,
 			     size_t hlen, void *data, size_t dlen, void *tail,
 			     size_t tlen)

+ 253 - 8
target_if/cfr/src/target_if_cfr_enh.c

@@ -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, &param);
+
+	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;