summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@quicinc.com>2017-04-25 21:16:17 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2017-04-25 21:16:17 -0700
commit34f6c314097b1ad81f9cc5e8af9f99ea2ec378a1 (patch)
tree636c43f93c3f961ebde4d7e63955344b063a8575
parentab829079c8edba8d0929c9bd8db93ca1ee929a4e (diff)
parent5eafdec8942fa8a13726db63d917a0c9b0f4fb44 (diff)
Merge "qcacld-2.0: add support for time stamping netbuf" into wlan-cld2.driver.lnx.1.0-dev
-rw-r--r--CORE/HDD/inc/wlan_hdd_tsf.h36
-rw-r--r--CORE/HDD/src/wlan_hdd_tsf.c147
2 files changed, 183 insertions, 0 deletions
diff --git a/CORE/HDD/inc/wlan_hdd_tsf.h b/CORE/HDD/inc/wlan_hdd_tsf.h
index 42d512983466..559d78e4b45e 100644
--- a/CORE/HDD/inc/wlan_hdd_tsf.h
+++ b/CORE/HDD/inc/wlan_hdd_tsf.h
@@ -150,6 +150,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(adf_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(adf_nbuf_t netbuf, uint64_t target_time);
#else
static inline int hdd_start_tsf_sync(hdd_adapter_t *adapter)
{
@@ -165,8 +190,19 @@ static inline
void hdd_tsf_notify_wlan_state_change(hdd_adapter_t *adapter,
eConnectionState old_state,
eConnectionState new_state)
+{
+}
+static inline
+int hdd_tx_timestamp(adf_nbuf_t netbuf, uint64_t target_time)
{
+ return -ENOTSUPP;
+}
+
+static inline
+int hdd_rx_timestamp(adf_nbuf_t netbuf, uint64_t target_time)
+{
+ return -ENOTSUPP;
}
#endif
diff --git a/CORE/HDD/src/wlan_hdd_tsf.c b/CORE/HDD/src/wlan_hdd_tsf.c
index 5a73407e2c0d..4d70fa744583 100644
--- a/CORE/HDD/src/wlan_hdd_tsf.c
+++ b/CORE/HDD/src/wlan_hdd_tsf.c
@@ -32,6 +32,7 @@
#include "wlan_hdd_main.h"
#include "wlan_hdd_tsf.h"
#include "wma_api.h"
+#include <linux/errqueue.h>
/**
* enum hdd_tsf_op_result - result of tsf operation
@@ -263,8 +264,19 @@ 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)
+#define MAX_UINT64 ((uint64_t)0xffffffffffffffff)
+#define MASK_UINT32 0xffffffff
/**
* TS_STATUS - timestamp status
@@ -457,6 +469,68 @@ static void hdd_update_timestamp(hdd_adapter_t *adapter,
vos_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 (adf_os_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 > MAX_UINT64 - 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)
+ spin_lock_bh(&adapter->host_target_sync_lock);
+
+ /* at present, target_time is only 32bit in fact */
+ delta32_target = (int64_t)((target_time & MASK_UINT32) -
+ (adapter->last_target_time & MASK_UINT32));
+
+ 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)
+ spin_unlock_bh(&adapter->host_target_sync_lock);
+
+ return ret;
+}
+
static inline uint64_t hdd_get_monotonic_host_time(void)
{
struct timespec ts;
@@ -609,6 +683,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(adf_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;
@@ -647,6 +746,54 @@ int hdd_stop_tsf_sync(hdd_adapter_t *adapter)
return 0;
}
+int hdd_tx_timestamp(adf_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;
+ adf_nbuf_t new_netbuf;
+ int err;
+
+ if (hdd_netbuf_timestamp(netbuf, target_time) !=
+ HDD_TSF_OP_SUCC)
+ return -EINVAL;
+
+ new_netbuf = adf_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) {
+ adf_nbuf_free(new_netbuf);
+ return err;
+ }
+
+ return 0;
+ }
+ return -EINVAL;
+}
+
+int hdd_rx_timestamp(adf_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)
{