Преглед на файлове

qcacld-3.0: Add changes to read tsf via scratch register

Read TSF via scratch registers instead of WMI commands. Added framework
to initialize/de-initialize the deferred context for register reads.

Change-Id: Id5309bf3117f04fb3d321ddd3af50e4bdf223561
CRs-Fixed: 3287534
Amit Mehta преди 2 години
родител
ревизия
8d830534f3
променени са 4 файла, в които са добавени 285 реда и са изтрити 60 реда
  1. 8 0
      core/hdd/inc/wlan_hdd_main.h
  2. 252 45
      core/hdd/src/wlan_hdd_tsf.c
  3. 5 3
      core/mac/inc/sir_api.h
  4. 20 12
      core/wma/src/wma_features.c

+ 8 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -1155,6 +1155,14 @@ struct hdd_adapter {
 	uint64_t cur_target_global_tsf_time;
 	uint64_t last_target_global_tsf_time;
 	qdf_mc_timer_t host_capture_req_timer;
+#ifdef QCA_GET_TSF_VIA_REG
+	/* TSF id as obtained from FW report */
+	int tsf_id;
+	/* mac_id as obtained from FW report */
+	int tsf_mac_id;
+	/* flag indicating whether tsf details are valid */
+	qdf_atomic_t tsf_details_valid;
+#endif
 #ifdef WLAN_FEATURE_TSF_PLUS
 	/* spin lock for read/write timestamps */
 	qdf_spinlock_t host_target_sync_lock;

+ 252 - 45
core/hdd/src/wlan_hdd_tsf.c

@@ -45,7 +45,7 @@
 static int tsf_gpio_irq_num = -1;
 #endif
 #endif
-static struct completion tsf_sync_get_completion_evt;
+static qdf_event_t tsf_sync_get_completion_evt;
 #define WLAN_TSF_SYNC_GET_TIMEOUT 2000
 #define WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS 500
 #define WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS 100
@@ -68,6 +68,29 @@ hdd_update_timestamp(struct hdd_adapter *adapter,
 #endif
 #endif
 
+#ifdef QCA_GET_TSF_VIA_REG
+static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf);
+
+/**
+ * struct hdd_tsf_report - TSF report filled in by DP layer
+ * @vdev_id: vdev id for which TSF values is to be read
+ * @tsf_id: tsf if used to read TSF report
+ * @mac_id: lmac_id for which TSF values are read
+ * @tsf: 64 bit tsf value as read from scratch registers
+ * @tsf_sync_soc_time: host qtimer time when scratch registers are read
+ *
+ * The structure is used by the upper layers to pass vdev_id, tsf_id and mac_id
+ * information to DP layer and get tsf time and host time when TSF was read.
+ */
+struct hdd_tsf_report {
+	uint32_t vdev_id;
+	uint32_t tsf_id;
+	uint32_t mac_id;
+	uint64_t tsf;
+	uint64_t tsf_sync_soc_time;
+};
+#endif
+
 /**
  * enum hdd_tsf_op_result - result of tsf operation
  *
@@ -488,10 +511,205 @@ static bool hdd_tsf_cap_sync_send(struct hdd_adapter *adapter)
 }
 #endif
 
+#ifdef WLAN_FEATURE_TSF_TIMER_SYNC
+/**
+ * hdd_convert_qtime_to_us() - convert qtime to us
+ * @time: QTIMER ticks for adrastea and us for Lithium
+ *
+ * This function converts qtime to us.
+ *
+ * Return: Time in microseconds
+ */
+static inline uint64_t
+hdd_convert_qtime_to_us(uint64_t time)
+{
+	return time;
+}
+
+#else
+static inline uint64_t
+hdd_convert_qtime_to_us(uint64_t time)
+{
+	return qdf_log_timestamp_to_usecs(time);
+}
+#endif
+
+/**
+ * hdd_capture_tsf_internal_via_wmi() - convert qtime to us
+ * @adapter: pointer to adapter
+ * @buf: in case of failure update with fail
+ * @len: buffer length
+ *
+ * Return: result of tsf operation
+ */
+static enum hdd_tsf_op_result
+hdd_capture_tsf_internal_via_wmi(struct hdd_adapter *adapter, uint32_t *buf,
+				 int len)
+{
+	int ret;
+	struct hdd_context *hddctx = adapter->hdd_ctx;
+
+	ret = wma_cli_set_command((int)adapter->vdev_id,
+				  (int)GEN_PARAM_CAPTURE_TSF,
+				  adapter->vdev_id, GEN_CMD);
+	if (ret != QDF_STATUS_SUCCESS) {
+		hdd_err("cap tsf fail");
+		buf[0] = TSF_CAPTURE_FAIL;
+		hddctx->cap_tsf_context = NULL;
+		qdf_atomic_set(&hddctx->cap_tsf_flag, 0);
+		qdf_mc_timer_stop(&adapter->host_capture_req_timer);
+		qdf_mc_timer_destroy(&adapter->host_capture_req_timer);
+	}
+	return HDD_TSF_OP_SUCC;
+}
+
+#ifndef QCA_GET_TSF_VIA_REG
+static inline
+enum hdd_tsf_op_result _hdd_capture_tsf_internal(struct hdd_adapter *adapter,
+						 uint32_t *buf, int len)
+{
+	return hdd_capture_tsf_internal_via_wmi(adapter, buf, len);
+}
+
+static inline void wlan_hdd_tsf_reg_update_details(struct hdd_adapter *adapter,
+						   struct stsf *ptsf)
+{
+}
+#else
+
+static inline int hdd_tsf_reg_is_details_valid(struct hdd_adapter *adapter)
+{
+	return qdf_atomic_read(&adapter->tsf_details_valid);
+}
+
+static inline void
+wlan_hdd_tsf_reg_update_details(struct hdd_adapter *adapter, struct stsf *ptsf)
+{
+	if (!qdf_atomic_read(&adapter->tsf_details_valid)) {
+		if (ptsf->tsf_id_valid) {
+			adapter->tsf_id = ptsf->tsf_id;
+			adapter->tsf_mac_id = ptsf->mac_id;
+			qdf_atomic_set(&adapter->tsf_details_valid, 1);
+		}
+	}
+	hdd_info("tsf_id %u tsf_id_valid %u mac_id %u mac_id_valid %u",
+		 ptsf->tsf_id, ptsf->tsf_id_valid, ptsf->mac_id,
+		 ptsf->mac_id_valid);
+}
+
+static inline
+QDF_STATUS wlan_hdd_tsf_reg_get(struct hdd_adapter *adapter,
+				struct hdd_tsf_report *tsf_report)
+{
+	ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC);
+	uint64_t tsf_time = 0;
+	uint64_t tsf_sync_soc_time = 0;
+
+	if (qdf_unlikely(!soc))
+		return QDF_STATUS_E_INVAL;
+
+	cdp_get_tsf_time(soc, tsf_report->tsf_id, tsf_report->mac_id,
+			 &tsf_time, &tsf_sync_soc_time);
+
+	/* fill in the report */
+	tsf_report->tsf = tsf_time;
+	tsf_report->tsf_sync_soc_time = tsf_sync_soc_time;
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * wlan_hdd_tsf_reg_process_report() - Process tsf report
+ * @adapter: pointer to the adapter
+ * @tsf_report: pointer to tsf report
+ *
+ * This function process the tsf report received and update tsf
+ * value received via scratch register read to adapter
+ *
+ * Return: 0 for success or 1 in case of failure
+ */
+static enum hdd_tsf_op_result
+wlan_hdd_tsf_reg_process_report(struct hdd_adapter *adapter,
+				struct hdd_tsf_report *tsf_report)
+{
+	QDF_STATUS status;
+	QDF_TIMER_STATE capture_req_timer_status;
+	qdf_mc_timer_t *capture_timer;
+
+	if (!tsf_report->tsf && !tsf_report->tsf_sync_soc_time) {
+		hdd_err("Invalid TSF report");
+		return HDD_TSF_OP_FAIL;
+	}
+
+	if (!hdd_tsf_is_initialized(adapter)) {
+		hdd_err("tsf is not init, ignore tsf event");
+		return HDD_TSF_OP_FAIL;
+	}
+
+	hdd_info("device_mode is %d", adapter->device_mode);
+
+	capture_timer = &adapter->host_capture_req_timer;
+	capture_req_timer_status =
+		qdf_mc_timer_get_current_state(capture_timer);
+	if (capture_req_timer_status == QDF_TIMER_STATE_UNUSED) {
+		hdd_warn("invalid timer status");
+		return HDD_TSF_OP_FAIL;
+	}
+
+	qdf_mc_timer_stop(capture_timer);
+	status = qdf_mc_timer_destroy(capture_timer);
+	if (status != QDF_STATUS_SUCCESS)
+		hdd_warn("destroy cap req timer fail, ret: %d", status);
+
+	adapter->cur_target_time = tsf_report->tsf;
+	adapter->cur_tsf_sync_soc_time = tsf_report->tsf_sync_soc_time *
+						NSEC_PER_USEC;
+
+	qdf_event_set(&tsf_sync_get_completion_evt);
+	hdd_update_tsf(adapter, adapter->cur_target_time);
+	hdd_info("vdev id=%u, tsf=%llu", adapter->vdev_id, tsf_report->tsf);
+	return HDD_TSF_OP_SUCC;
+}
+
+static enum hdd_tsf_op_result
+hdd_capture_tsf_internal_via_reg(struct hdd_adapter *adapter, uint32_t *buf,
+				 int len)
+{
+	struct hdd_tsf_report tsf_report;
+
+	if (!hdd_tsf_reg_is_details_valid(adapter)) {
+		hdd_warn("TSF reg details are not valid!");
+		return HDD_TSF_OP_FAIL;
+	}
+
+	qdf_mem_zero(&tsf_report, sizeof(tsf_report));
+	tsf_report.vdev_id = adapter->vdev_id;
+	tsf_report.tsf_id = adapter->tsf_id;
+	tsf_report.mac_id = adapter->tsf_mac_id;
+
+	if (wlan_hdd_tsf_reg_get(adapter, &tsf_report)) {
+		hdd_warn("Unable to get tsf report");
+		return HDD_TSF_OP_FAIL;
+	}
+
+	return wlan_hdd_tsf_reg_process_report(adapter, &tsf_report);
+}
+
+static inline
+enum hdd_tsf_op_result _hdd_capture_tsf_internal(struct hdd_adapter *adapter,
+						 uint32_t *buf, int len)
+{
+	if (!qdf_atomic_read(&adapter->tsf_details_valid))
+		return hdd_capture_tsf_internal_via_wmi(adapter, buf, len);
+	else
+		return hdd_capture_tsf_internal_via_reg(adapter, buf, len);
+}
+
+#endif /* QCA_GET_TSF_VIA_REG */
+
 static enum hdd_tsf_op_result hdd_capture_tsf_internal(
 	struct hdd_adapter *adapter, uint32_t *buf, int len)
 {
-	int ret;
+	enum hdd_tsf_op_result ret;
 	struct hdd_context *hddctx;
 	qdf_mc_timer_t *cap_timer;
 
@@ -509,6 +727,11 @@ static enum hdd_tsf_op_result hdd_capture_tsf_internal(
 		return HDD_TSF_OP_FAIL;
 	}
 
+	if (wlan_hdd_validate_context(hddctx)) {
+		hdd_err("hdd context validation failed");
+		return HDD_TSF_OP_FAIL;
+	}
+
 	if (!hdd_tsf_is_initialized(adapter)) {
 		buf[0] = TSF_NOT_READY;
 		return HDD_TSF_OP_SUCC;
@@ -538,26 +761,14 @@ static enum hdd_tsf_op_result hdd_capture_tsf_internal(
 	adapter->cur_target_time = 0;
 
 	buf[0] = TSF_RETURN;
-	init_completion(&tsf_sync_get_completion_evt);
 
 	if (hdd_tsf_cap_sync_send(adapter))
 		return HDD_TSF_OP_SUCC;
 
-	ret = wma_cli_set_command((int)adapter->vdev_id,
-				  (int)GEN_PARAM_CAPTURE_TSF,
-				  adapter->vdev_id, GEN_CMD);
-	if (QDF_STATUS_SUCCESS != ret) {
-		hdd_err("cap tsf fail");
-		buf[0] = TSF_CAPTURE_FAIL;
-		hddctx->cap_tsf_context = NULL;
-		qdf_atomic_set(&hddctx->cap_tsf_flag, 0);
-		qdf_mc_timer_stop(&adapter->host_capture_req_timer);
-		qdf_mc_timer_destroy(&adapter->host_capture_req_timer);
-
-		return HDD_TSF_OP_SUCC;
-	}
+	ret = _hdd_capture_tsf_internal(adapter, buf, len);
 	hdd_info("-ioctl return cap tsf cmd");
-	return HDD_TSF_OP_SUCC;
+
+	return ret;
 }
 
 static enum hdd_tsf_op_result hdd_indicate_tsf_internal(
@@ -2425,29 +2636,6 @@ static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx)
 }
 #endif /* WLAN_FEATURE_TSF_PTP */
 
-#ifdef WLAN_FEATURE_TSF_TIMER_SYNC
-/**
- * hdd_convert_qtime_to_us() - convert qtime to us
- * @time: QTIMER ticks for adrastea and us for Lithium
- *
- * This function converts qtime to us.
- *
- * Return: Time in microseconds
- */
-static inline uint64_t
-hdd_convert_qtime_to_us(uint64_t time)
-{
-	return time;
-}
-
-#else
-static inline uint64_t
-hdd_convert_qtime_to_us(uint64_t time)
-{
-	return qdf_log_timestamp_to_usecs(time);
-}
-#endif
-
 #ifdef WLAN_FEATURE_TSF_UPLINK_DELAY
 static int hdd_set_tsf_auto_report(struct hdd_adapter *adapter, bool ena)
 {
@@ -2635,7 +2823,10 @@ int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf)
 			ptsf->soc_timer_low);
 	adapter->cur_tsf_sync_soc_time =
 		hdd_convert_qtime_to_us(tsf_sync_soc_time) * NSEC_PER_USEC;
-	complete(&tsf_sync_get_completion_evt);
+
+	wlan_hdd_tsf_reg_update_details(adapter, ptsf);
+
+	qdf_event_set(&tsf_sync_get_completion_evt);
 	hdd_update_tsf(adapter, adapter->cur_target_time);
 	hdd_info("Vdev=%u, tsf_low=%u, tsf_high=%u ptsf->soc_timer_low=%u ptsf->soc_timer_high=%u",
 		 ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high,
@@ -2671,7 +2862,8 @@ static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
 	struct hdd_tsf_op_response tsf_op_resp;
 	struct nlattr *attr;
 	enum hdd_tsf_get_state value;
-	int status, ret;
+	int status;
+	QDF_STATUS ret;
 	struct sk_buff *reply_skb;
 	uint32_t tsf_cmd;
 
@@ -2705,6 +2897,9 @@ static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
 	status = hdd_handle_tsf_auto_report(adapter, tsf_cmd);
 	if (status != -EINVAL)
 		goto end;
+	ret = qdf_event_reset(&tsf_sync_get_completion_evt);
+	if (QDF_IS_STATUS_ERROR(ret))
+		hdd_warn("failed to reset tsf_sync_get_completion_evt");
 
 	if (tsf_cmd == QCA_TSF_CAPTURE || tsf_cmd == QCA_TSF_SYNC_GET) {
 		hdd_capture_tsf(adapter, &value, 1);
@@ -2735,9 +2930,9 @@ static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
 		goto end;
 
 	if (tsf_cmd == QCA_TSF_SYNC_GET) {
-		ret = wait_for_completion_timeout(&tsf_sync_get_completion_evt,
-			msecs_to_jiffies(WLAN_TSF_SYNC_GET_TIMEOUT));
-		if (ret == 0) {
+		ret = qdf_wait_single_event(&tsf_sync_get_completion_evt,
+					    WLAN_TSF_SYNC_GET_TIMEOUT);
+		if (QDF_IS_STATUS_ERROR(ret)) {
 			status = -ETIMEDOUT;
 			goto end;
 		}
@@ -2829,6 +3024,12 @@ void wlan_hdd_tsf_init(struct hdd_context *hdd_ctx)
 	if (hdd_tsf_is_ptp_enabled(hdd_ctx))
 		wlan_hdd_phc_init(hdd_ctx);
 
+	status = qdf_event_create(&tsf_sync_get_completion_evt);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_debug("failed to create tsf_sync_get_completion_evt");
+		goto fail;
+	}
+
 	return;
 
 fail:
@@ -2837,12 +3038,18 @@ fail:
 
 void wlan_hdd_tsf_deinit(struct hdd_context *hdd_ctx)
 {
+	QDF_STATUS status;
+
 	if (!hdd_ctx)
 		return;
 
 	if (!qdf_atomic_read(&hdd_ctx->tsf_ready_flag))
 		return;
 
+	status = qdf_event_destroy(&tsf_sync_get_completion_evt);
+	if (QDF_IS_STATUS_ERROR(status))
+		hdd_debug("failed to destroy tsf_sync_get_completion_evt");
+
 	if (hdd_tsf_is_ptp_enabled(hdd_ctx))
 		wlan_hdd_phc_deinit(hdd_ctx);
 	wlan_hdd_tsf_plus_deinit(hdd_ctx);

+ 5 - 3
core/mac/inc/sir_api.h

@@ -3882,8 +3882,10 @@ struct sir_sme_ext_cng_chan_ind {
  * @global_tsf_high: high 32bits of tsf64
  * @mac_id: MAC identifier
  * @mac_id_valid: Indicate if mac_id is valid or not
+ * @tsf_id: TSF-ID corresponding to the TSF value
+ * @tsf_id_valid: flag indicating whether TSD-ID is valid
  *
- * driver use this struct to store the tsf info
+ * Driver uses this structure to store the tsf information.
  */
 struct stsf {
 	uint32_t vdev_id;
@@ -3893,10 +3895,10 @@ struct stsf {
 	uint32_t soc_timer_high;
 	uint32_t global_tsf_low;
 	uint32_t global_tsf_high;
-#ifdef WLAN_FEATURE_TSF_UPLINK_DELAY
 	uint32_t mac_id;
 	uint32_t mac_id_valid;
-#endif
+	uint32_t tsf_id;
+	uint32_t tsf_id_valid;
 };
 
 #define SIR_BCN_FLT_MAX_ELEMS_IE_LIST 8

+ 20 - 12
core/wma/src/wma_features.c

@@ -315,22 +315,29 @@ end:
 
 #ifdef WLAN_FEATURE_TSF
 
-#ifdef WLAN_FEATURE_TSF_UPLINK_DELAY
-static void wma_vdev_tsf_set_mac_id(struct stsf *ptsf, uint32_t mac_id,
-				    uint32_t mac_id_valid)
+#if defined(WLAN_FEATURE_TSF_UPLINK_DELAY) || defined(QCA_GET_TSF_VIA_REG)
+static inline void
+wma_vdev_tsf_set_mac_id_tsf_id(struct stsf *ptsf, uint32_t mac_id,
+			       uint32_t mac_id_valid, uint32_t tsf_id,
+			       uint32_t tsf_id_valid)
 {
 	ptsf->mac_id = mac_id;
 	ptsf->mac_id_valid = mac_id_valid;
+	ptsf->tsf_id = tsf_id;
+	ptsf->tsf_id_valid = tsf_id_valid;
 
-	wma_nofl_debug("mac_id %d mac_id_valid %d", ptsf->mac_id,
-		       ptsf->mac_id_valid);
+	wma_nofl_debug("mac_id %d mac_id_valid %d tsf_id %d tsf_id_valid %d",
+		       ptsf->mac_id, ptsf->mac_id_valid, ptsf->tsf_id,
+		       ptsf->tsf_id_valid);
 }
-#else /* !WLAN_FEATURE_TSF_UPLINK_DELAY */
-static inline void wma_vdev_tsf_set_mac_id(struct stsf *ptsf, uint32_t mac_id,
-					   uint32_t mac_id_valid)
+#else /* !WLAN_FEATURE_TSF_UPLINK_DELAY || !QCA_GET_TSF_VIA_REG*/
+static inline void
+wma_vdev_tsf_set_mac_id_tsf_id(struct stsf *ptsf, uint32_t mac_id,
+			       uint32_t mac_id_valid, uint32_t tsf_id,
+			       uint32_t tsf_id_valid)
 {
 }
-#endif /* WLAN_FEATURE_TSF_UPLINK_DELAY */
+#endif /* WLAN_FEATURE_TSF_UPLINK_DELAY || QCA_GET_TSF_VIA_REG*/
 
 /**
  * wma_vdev_tsf_handler() - handle tsf event indicated by FW
@@ -372,9 +379,10 @@ int wma_vdev_tsf_handler(void *handle, uint8_t *data, uint32_t data_len)
 		       ptsf->global_tsf_low, ptsf->global_tsf_high,
 			   ptsf->soc_timer_low, ptsf->soc_timer_high);
 
-	wma_vdev_tsf_set_mac_id(ptsf, tsf_event->mac_id,
-				tsf_event->mac_id_valid);
-
+	wma_vdev_tsf_set_mac_id_tsf_id(ptsf, tsf_event->mac_id,
+				       tsf_event->mac_id_valid,
+				       tsf_event->tsf_id,
+				       tsf_event->tsf_id_valid);
 	tsf_msg.type = eWNI_SME_TSF_EVENT;
 	tsf_msg.bodyptr = ptsf;
 	tsf_msg.bodyval = 0;