diff options
| author | Linux Build Service Account <lnxbuild@quicinc.com> | 2017-04-25 21:16:17 -0700 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-04-25 21:16:17 -0700 |
| commit | 34f6c314097b1ad81f9cc5e8af9f99ea2ec378a1 (patch) | |
| tree | 636c43f93c3f961ebde4d7e63955344b063a8575 | |
| parent | ab829079c8edba8d0929c9bd8db93ca1ee929a4e (diff) | |
| parent | 5eafdec8942fa8a13726db63d917a0c9b0f4fb44 (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.h | 36 | ||||
| -rw-r--r-- | CORE/HDD/src/wlan_hdd_tsf.c | 147 |
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) { |
