Browse Source

qcacld-3.0: add support for time stamping netbuf

Map the input target time to host time, and
time stamp netbuf with this host time.

Change-Id: I1fb298615267bb11c4f21cabe670fd4c3a12a759
CRs-Fixed: 2057693
Yu Wang 7 years ago
parent
commit
04ccd76c41
2 changed files with 180 additions and 0 deletions
  1. 37 0
      core/hdd/inc/wlan_hdd_tsf.h
  2. 143 0
      core/hdd/src/wlan_hdd_tsf.c

+ 37 - 0
core/hdd/inc/wlan_hdd_tsf.h

@@ -203,6 +203,31 @@ void hdd_tsf_notify_wlan_state_change(hdd_adapter_t *adapter,
 				      eConnectionState old_state,
 				      eConnectionState new_state);
 
+/**
+ * hdd_tx_timestamp() - time stamp TX netbuf
+ *
+ * @netbuf: pointer to a TX netbuf
+ * @target_time: TX time for the netbuf
+ *
+ * This function  get corresponding host time from target time,
+ * and time stamp the TX netbuf with this time
+ *
+ * Return: Describe the execute result of this routine
+ */
+int hdd_tx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time);
+
+/**
+ * hdd_rx_timestamp() - time stamp RX netbuf
+ *
+ * @netbuf: pointer to a RX netbuf
+ * @target_time: RX time for the netbuf
+ *
+ * This function get corresponding host time from target time,
+ * and time stamp the RX netbuf with this time
+ *
+ * Return: Describe the execute result of this routine
+ */
+int hdd_rx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time);
 #else
 static inline int hdd_start_tsf_sync(hdd_adapter_t *adapter)
 {
@@ -221,6 +246,18 @@ void hdd_tsf_notify_wlan_state_change(hdd_adapter_t *adapter,
 
 {
 }
+
+static inline
+int hdd_tx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time)
+{
+	return -ENOTSUPP;
+}
+
+static inline
+int hdd_rx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time)
+{
+	return -ENOTSUPP;
+}
 #endif
 
 #endif

+ 143 - 0
core/hdd/src/wlan_hdd_tsf.c

@@ -276,8 +276,16 @@ static enum hdd_tsf_op_result hdd_indicate_tsf_internal(
 #define HOST_TO_TARGET_TIME_RATIO NSEC_PER_USEC
 #define MAX_ALLOWED_DEVIATION_NS (20 * NSEC_PER_MSEC)
 #define MAX_CONTINUOUS_ERROR_CNT 3
+
+/* to distinguish 32-bit overflow case, this inverval should:
+ * equal or less than (1/2 * OVERFLOW_INDICATOR32 us)
+ */
 #define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 500
 #define WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS 100
+#define NORMAL_INTERVAL_TARGET \
+	((int64_t)((int64_t)WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC * \
+		NSEC_PER_SEC / HOST_TO_TARGET_TIME_RATIO))
+#define OVERFLOW_INDICATOR32 (((int64_t)0x1) << 32)
 
 /**
  * TS_STATUS - timestamp status
@@ -462,6 +470,68 @@ static void hdd_update_timestamp(hdd_adapter_t *adapter,
 		qdf_mc_timer_start(&adapter->host_target_sync_timer, interval);
 }
 
+static inline bool hdd_tsf_is_in_cap(hdd_adapter_t *adapter)
+{
+	hdd_context_t *hddctx;
+
+	hddctx = WLAN_HDD_GET_CTX(adapter);
+	if (!hddctx)
+		return false;
+
+	return qdf_atomic_read(&hddctx->cap_tsf_flag) > 0;
+}
+
+/* define 64bit plus/minus to deal with overflow */
+static inline int hdd_64bit_plus(uint64_t x, int64_t y, uint64_t *ret)
+{
+	if ((y < 0 && (-y) > x) ||
+	    (y > 0 && (y > U64_MAX - x))) {
+		*ret = 0;
+		return -EINVAL;
+	}
+
+	*ret = x + y;
+	return 0;
+}
+
+static inline int32_t hdd_get_hosttime_from_targettime(
+	hdd_adapter_t *adapter, uint64_t target_time,
+	uint64_t *host_time)
+{
+	int32_t ret = -EINVAL;
+	int64_t delta32_target;
+	bool in_cap_state;
+
+	in_cap_state = hdd_tsf_is_in_cap(adapter);
+
+	/*
+	 * To avoid check the lock when it's not capturing tsf
+	 * (the tstamp-pair won't be changed)
+	 */
+	if (in_cap_state)
+		qdf_spin_lock_bh(&adapter->host_target_sync_lock);
+
+	/* at present, target_time is only 32bit in fact */
+	delta32_target = (int64_t)((target_time & U32_MAX) -
+			(adapter->last_target_time & U32_MAX));
+
+	if (delta32_target <
+			(NORMAL_INTERVAL_TARGET - OVERFLOW_INDICATOR32))
+		delta32_target += OVERFLOW_INDICATOR32;
+	else if (delta32_target >
+			(OVERFLOW_INDICATOR32 - NORMAL_INTERVAL_TARGET))
+		delta32_target -= OVERFLOW_INDICATOR32;
+
+	ret = hdd_64bit_plus(adapter->last_host_time,
+			     HOST_TO_TARGET_TIME_RATIO * delta32_target,
+			     host_time);
+
+	if (in_cap_state)
+		qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
+
+	return ret;
+}
+
 static inline uint64_t hdd_get_monotonic_host_time(void)
 {
 	struct timespec ts;
@@ -605,6 +675,31 @@ static inline void hdd_update_tsf(hdd_adapter_t *adapter, uint64_t tsf)
 	hdd_update_timestamp(adapter, tsf, 0);
 }
 
+static inline
+enum hdd_tsf_op_result hdd_netbuf_timestamp(qdf_nbuf_t netbuf,
+					    uint64_t target_time)
+{
+	hdd_adapter_t *adapter;
+	struct net_device *net_dev = netbuf->dev;
+
+	if (!net_dev)
+		return HDD_TSF_OP_FAIL;
+
+	adapter = (hdd_adapter_t *)(netdev_priv(net_dev));
+	if (adapter && adapter->magic == WLAN_HDD_ADAPTER_MAGIC &&
+	    hdd_get_th_sync_status(adapter)) {
+		uint64_t host_time;
+		int32_t ret = hdd_get_hosttime_from_targettime(adapter,
+				target_time, &host_time);
+		if (!ret) {
+			netbuf->tstamp = ns_to_ktime(host_time);
+			return HDD_TSF_OP_SUCC;
+		}
+	}
+
+	return HDD_TSF_OP_FAIL;
+}
+
 int hdd_start_tsf_sync(hdd_adapter_t *adapter)
 {
 	enum hdd_tsf_op_result ret;
@@ -641,6 +736,54 @@ int hdd_stop_tsf_sync(hdd_adapter_t *adapter)
 	return 0;
 }
 
+int hdd_tx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time)
+{
+	struct sock *sk = netbuf->sk;
+
+	if (!sk)
+		return -EINVAL;
+
+	if ((skb_shinfo(netbuf)->tx_flags & SKBTX_SW_TSTAMP) &&
+	    !(skb_shinfo(netbuf)->tx_flags & SKBTX_IN_PROGRESS)) {
+		struct sock_exterr_skb *serr;
+		qdf_nbuf_t new_netbuf;
+		int err;
+
+		if (hdd_netbuf_timestamp(netbuf, target_time) !=
+		    HDD_TSF_OP_SUCC)
+			return -EINVAL;
+
+		new_netbuf = qdf_nbuf_clone(netbuf);
+		if (!new_netbuf)
+			return -ENOMEM;
+
+		serr = SKB_EXT_ERR(new_netbuf);
+		memset(serr, 0, sizeof(*serr));
+		serr->ee.ee_errno = ENOMSG;
+		serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
+
+		err = sock_queue_err_skb(sk, new_netbuf);
+		if (err) {
+			qdf_nbuf_free(new_netbuf);
+			return err;
+		}
+
+		return 0;
+	}
+	return -EINVAL;
+}
+
+int hdd_rx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time)
+{
+	if (hdd_netbuf_timestamp(netbuf, target_time) ==
+		HDD_TSF_OP_SUCC)
+		return 0;
+
+	/* reset tstamp when failed */
+	netbuf->tstamp = ns_to_ktime(0);
+	return -EINVAL;
+}
+
 static inline int __hdd_capture_tsf(hdd_adapter_t *adapter,
 				    uint32_t *buf, int len)
 {