diff --git a/Kbuild b/Kbuild index 1031b3592d1e..11eed090633c 100755 --- a/Kbuild +++ b/Kbuild @@ -377,6 +377,10 @@ ifeq ($(CONFIG_QCOM_TDLS),y) HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_tdls.o endif +ifeq ($(CONFIG_WLAN_SYNC_TSF),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_tsf.o +endif + ifeq ($(CONFIG_MPC_UT_FRAMEWORK),y) HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_conc_ut.o endif @@ -1360,6 +1364,10 @@ ifeq ($(CONFIG_LINUX_QCMBR),y) CDEFINES += -DLINUX_QCMBR endif +# Enable featue sync tsf between multi devices +ifeq ($(CONFIG_WLAN_SYNC_TSF), y) +CDEFINES += -DWLAN_FEATURE_TSF +endif # Enable full rx re-order offload for adrastea ifeq (y, $(filter y, $(CONFIG_CNSS_ADRASTEA) $(CONFIG_ICNSS))) diff --git a/Kconfig b/Kconfig index 7155ea2a2b4d..39b64ed625c3 100644 --- a/Kconfig +++ b/Kconfig @@ -107,6 +107,10 @@ config WLAN_FEATURE_RX_WAKELOCK bool "Enable RX wake lock feature" default n +config WLAN_SYNC_TSF + bool "Enable QCOM sync multi devices tsf feature" + default n + config FEATURE_LFR_SUBNET_DETECTION bool "Enable LFR Subnet Change Detection" default n diff --git a/core/hdd/inc/qc_sap_ioctl.h b/core/hdd/inc/qc_sap_ioctl.h index 5a1bfbef9f48..cede160e85e8 100644 --- a/core/hdd/inc/qc_sap_ioctl.h +++ b/core/hdd/inc/qc_sap_ioctl.h @@ -131,42 +131,43 @@ typedef struct { * (regardless of the incorrect comment in wireless.h!) */ -#define QCSAP_IOCTL_SETPARAM (SIOCIWFIRSTPRIV+0) -#define QCSAP_IOCTL_GETPARAM (SIOCIWFIRSTPRIV+1) +#define QCSAP_IOCTL_SETPARAM (SIOCIWFIRSTPRIV + 0) +#define QCSAP_IOCTL_GETPARAM (SIOCIWFIRSTPRIV + 1) /* (SIOCIWFIRSTPRIV+2) is unused */ -/* (SIOCIWFIRSTPRIV+3) is unused */ -#define QCSAP_IOCTL_GET_STAWPAIE (SIOCIWFIRSTPRIV+4) -#define QCSAP_IOCTL_SETWPAIE (SIOCIWFIRSTPRIV+5) -#define QCSAP_IOCTL_STOPBSS (SIOCIWFIRSTPRIV+6) -#define QCSAP_IOCTL_VERSION (SIOCIWFIRSTPRIV+7) -#define QCSAP_IOCTL_GET_WPS_PBC_PROBE_REQ_IES (SIOCIWFIRSTPRIV+8) -#define QCSAP_IOCTL_GET_CHANNEL (SIOCIWFIRSTPRIV+9) -#define QCSAP_IOCTL_ASSOC_STA_MACADDR (SIOCIWFIRSTPRIV+10) -#define QCSAP_IOCTL_DISASSOC_STA (SIOCIWFIRSTPRIV+11) +#define QCSAP_IOCTL_SET_NONE_GET_THREE (SIOCIWFIRSTPRIV + 3) +#define WE_GET_TSF 1 +#define QCSAP_IOCTL_GET_STAWPAIE (SIOCIWFIRSTPRIV + 4) +#define QCSAP_IOCTL_SETWPAIE (SIOCIWFIRSTPRIV + 5) +#define QCSAP_IOCTL_STOPBSS (SIOCIWFIRSTPRIV + 6) +#define QCSAP_IOCTL_VERSION (SIOCIWFIRSTPRIV + 7) +#define QCSAP_IOCTL_GET_WPS_PBC_PROBE_REQ_IES (SIOCIWFIRSTPRIV + 8) +#define QCSAP_IOCTL_GET_CHANNEL (SIOCIWFIRSTPRIV + 9) +#define QCSAP_IOCTL_ASSOC_STA_MACADDR (SIOCIWFIRSTPRIV + 10) +#define QCSAP_IOCTL_DISASSOC_STA (SIOCIWFIRSTPRIV + 11) /* (SIOCIWFIRSTPRIV+12) is unused */ /* Private ioctls and their sub-ioctls */ #define QCSAP_PRIV_GET_CHAR_SET_NONE (SIOCIWFIRSTPRIV + 13) #define QCSAP_GET_STATS 1 #define QCSAP_LIST_FW_PROFILE 2 -#define QCSAP_IOCTL_CLR_STATS (SIOCIWFIRSTPRIV+14) +#define QCSAP_IOCTL_CLR_STATS (SIOCIWFIRSTPRIV + 14) -#define QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE (SIOCIWFIRSTPRIV+15) +#define QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE (SIOCIWFIRSTPRIV + 15) #define WE_SET_WLAN_DBG 1 #define WE_SET_DP_TRACE 2 #define WE_SET_SAP_CHANNELS 3 -#define QCSAP_IOCTL_PRIV_SET_VAR_INT_GET_NONE (SIOCIWFIRSTPRIV+16) +#define QCSAP_IOCTL_PRIV_SET_VAR_INT_GET_NONE (SIOCIWFIRSTPRIV + 16) #define WE_UNIT_TEST_CMD 7 -#define QCSAP_IOCTL_SET_CHANNEL_RANGE (SIOCIWFIRSTPRIV+17) +#define QCSAP_IOCTL_SET_CHANNEL_RANGE (SIOCIWFIRSTPRIV + 17) #define WE_P2P_NOA_CMD 2 -#define QCSAP_IOCTL_MODIFY_ACL (SIOCIWFIRSTPRIV+18) -#define QCSAP_IOCTL_GET_CHANNEL_LIST (SIOCIWFIRSTPRIV+19) -#define QCSAP_IOCTL_SET_TX_POWER (SIOCIWFIRSTPRIV+20) -#define QCSAP_IOCTL_GET_STA_INFO (SIOCIWFIRSTPRIV+21) -#define QCSAP_IOCTL_SET_MAX_TX_POWER (SIOCIWFIRSTPRIV+22) -#define QCSAP_IOCTL_GET_INI_CFG (SIOCIWFIRSTPRIV+25) -#define QCSAP_IOCTL_SET_INI_CFG (SIOCIWFIRSTPRIV+26) +#define QCSAP_IOCTL_MODIFY_ACL (SIOCIWFIRSTPRIV + 18) +#define QCSAP_IOCTL_GET_CHANNEL_LIST (SIOCIWFIRSTPRIV + 19) +#define QCSAP_IOCTL_SET_TX_POWER (SIOCIWFIRSTPRIV + 20) +#define QCSAP_IOCTL_GET_STA_INFO (SIOCIWFIRSTPRIV + 21) +#define QCSAP_IOCTL_SET_MAX_TX_POWER (SIOCIWFIRSTPRIV + 22) +#define QCSAP_IOCTL_GET_INI_CFG (SIOCIWFIRSTPRIV + 25) +#define QCSAP_IOCTL_SET_INI_CFG (SIOCIWFIRSTPRIV + 26) #define QCSAP_IOCTL_SET_TWO_INT_GET_NONE (SIOCIWFIRSTPRIV + 28) #ifdef DEBUG #define QCSAP_IOCTL_SET_FW_CRASH_INJECT 1 @@ -241,7 +242,9 @@ enum { QCASAP_CLEAR_STATS, QCASAP_SET_RADAR_DBG, QCSAP_GET_FW_PROFILE_DATA, - QCSAP_START_FW_PROFILING + QCSAP_START_FW_PROFILING, + QCSAP_CAP_TSF, + QCSAP_GET_TSF, }; int iw_softap_get_channel_list(struct net_device *dev, diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 39fe7e1a7d97..ab3873a552de 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -57,6 +57,7 @@ #ifdef FEATURE_WLAN_TDLS #include "wlan_hdd_tdls.h" #endif +#include "wlan_hdd_tsf.h" #include "wlan_hdd_cfg80211.h" #include #ifdef WLAN_FEATURE_MBSSID @@ -940,6 +941,14 @@ struct hdd_adapter_s { hdd_ap_ctx_t ap; } sessionCtx; +#ifdef WLAN_FEATURE_TSF + /* tsf value received from firmware */ + uint32_t tsf_low; + uint32_t tsf_high; + /* TSF capture state */ + enum hdd_tsf_capture_state tsf_state; +#endif + hdd_cfg80211_state_t cfg80211State; #ifdef WLAN_FEATURE_PACKET_FILTERING diff --git a/core/hdd/inc/wlan_hdd_tsf.h b/core/hdd/inc/wlan_hdd_tsf.h new file mode 100644 index 000000000000..f251327d7f06 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_tsf.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined WLAN_HDD_TSF_H +#define WLAN_HDD_TSF_H + +/** + * enum hdd_tsf_get_state - status of get tsf action + * @TSF_RETURN: get tsf + * @TSF_STA_NOT_CONNECTED_NO_TSF: sta not connected to ap + * @TSF_NOT_RETURNED_BY_FW: fw not returned tsf + * @TSF_CURRENT_IN_CAP_STATE: driver in capture state + * @TSF_CAPTURE_FAIL: capture fail + * @TSF_GET_FAIL: get fail + * @TSF_RESET_GPIO_FAIL: GPIO reset fail + * @TSF_SAP_NOT_STARTED_NO_TSF SAP not started + */ +enum hdd_tsf_get_state { + TSF_RETURN = 0, + TSF_STA_NOT_CONNECTED_NO_TSF, + TSF_NOT_RETURNED_BY_FW, + TSF_CURRENT_IN_CAP_STATE, + TSF_CAPTURE_FAIL, + TSF_GET_FAIL, + TSF_RESET_GPIO_FAIL, + TSF_SAP_NOT_STARTED_NO_TSF +}; + +/** + * enum hdd_tsf_capture_state - status of capture + * @TSF_IDLE: idle + * @TSF_CAP_STATE: current is in capture state + */ +enum hdd_tsf_capture_state { + TSF_IDLE = 0, + TSF_CAP_STATE +}; + +#ifdef WLAN_FEATURE_TSF +void wlan_hdd_tsf_init(struct hdd_context_s *hdd_ctx); +int hdd_capture_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len); +int hdd_indicate_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len); +#else +static inline void wlan_hdd_tsf_init(struct hdd_context_s *hdd_ctx) +{ + return; +} + +static inline int hdd_indicate_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, + int len) +{ + return -ENOTSUPP; +} + +static inline int +hdd_capture_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len) +{ + return -ENOTSUPP; +} +#endif + +#endif diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index 3e5e6406c430..597d51278731 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -75,6 +75,7 @@ #include "qdf_trace.h" #include "wlan_hdd_cfg.h" #include "cds_concurrency.h" +#include "wlan_hdd_tsf.h" #include "wlan_hdd_green_ap.h" #define IS_UP(_dev) \ @@ -3011,6 +3012,66 @@ static __iw_softap_setparam(struct net_device *dev, return ret; } +/** + * __iw_softap_get_three() - return three value to upper layer. + * @dev: pointer of net_device of this wireless card + * @info: meta data about Request sent + * @wrqu: include request info + * @extra: buf used for in/out + * + * Return: execute result + */ +static int __iw_softap_get_three(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + uint32_t *value = (uint32_t *)extra; + uint32_t sub_cmd = value[0]; + int ret = 0; /* success */ + struct hdd_context_s *hdd_ctx; + struct hdd_adapter_s *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + switch (sub_cmd) { + case QCSAP_GET_TSF: + ret = hdd_indicate_tsf(adapter, value, 3); + break; + default: + hdd_err(FL("Invalid getparam command %d"), sub_cmd); + ret = -EINVAL; + break; + } + return ret; +} + + +/** + * iw_softap_get_three() - return three value to upper layer. + * + * @dev: pointer of net_device of this wireless card + * @info: meta data about Request sent + * @wrqu: include request info + * @extra: buf used for in/Output + * + * Return: execute result + */ +static int iw_softap_get_three(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_get_three(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + int static iw_softap_setparam(struct net_device *dev, struct iw_request_info *info, @@ -3211,6 +3272,9 @@ static __iw_softap_getparam(struct net_device *dev, VDEV_CMD); break; } + case QCSAP_CAP_TSF: + ret = hdd_capture_tsf(pHostapdAdapter, (uint32_t *)value, 1); + break; case QCASAP_GET_TEMP_CMD: { hddLog(LOG1, "QCASAP_GET_TEMP_CMD"); @@ -5821,6 +5885,15 @@ static const struct iw_priv_args hostapd_private_args[] = { }, { QCASAP_NSS_CMD, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_nss" + }, { + QCSAP_CAP_TSF, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "cap_tsf" + }, { + QCSAP_IOCTL_SET_NONE_GET_THREE, 0, IW_PRIV_TYPE_INT | + IW_PRIV_SIZE_FIXED | 3, "" + }, { + QCSAP_GET_TSF, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + "get_tsf" }, { QCASAP_GET_TEMP_CMD, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_temp" @@ -5997,6 +6070,8 @@ static const iw_handler hostapd_private[] = { [QCSAP_IOCTL_SETPARAM - SIOCIWFIRSTPRIV] = iw_softap_setparam, /* get priv ioctl */ [QCSAP_IOCTL_GETPARAM - SIOCIWFIRSTPRIV] = iw_softap_getparam, + [QCSAP_IOCTL_SET_NONE_GET_THREE - SIOCIWFIRSTPRIV] = + iw_softap_get_three, /* get station genIE */ [QCSAP_IOCTL_GET_STAWPAIE - SIOCIWFIRSTPRIV] = iw_get_genie, [QCSAP_IOCTL_SETWPAIE - SIOCIWFIRSTPRIV] = iw_softap_setwpsie, diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index acf6f9de0335..730ee4e82a6b 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -101,6 +101,7 @@ #include "hif.h" #include "wma.h" #include "cds_concurrency.h" +#include "wlan_hdd_tsf.h" #include "wlan_hdd_green_ap.h" #include "platform_icnss.h" #include "bmi.h" @@ -5963,7 +5964,7 @@ int hdd_wlan_startup(struct device *dev, void *hif_sc) hdd_rssi_threshold_breached); hdd_cfg80211_link_layer_stats_init(hdd_ctx); - + wlan_hdd_tsf_init(hdd_ctx); wlan_hdd_send_all_scan_intf_info(hdd_ctx); wlan_hdd_send_version_pkg(hdd_ctx->target_fw_version, hdd_ctx->target_hw_version, diff --git a/core/hdd/src/wlan_hdd_tsf.c b/core/hdd/src/wlan_hdd_tsf.c new file mode 100644 index 000000000000..2563a94bddbd --- /dev/null +++ b/core/hdd/src/wlan_hdd_tsf.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * wlan_hdd_tsf.c - WLAN Host Device Driver tsf related implementation + */ + +#include "wlan_hdd_main.h" +#include "wma_api.h" + +/** + * hdd_capture_tsf() - capture tsf + * @adapter: pointer to adapter + * @buf: pointer to uplayer buf + * @len : the length of buf + * + * This function returns tsf value to uplayer. + * + * Return: 0 for success or non-zero negative failure code + */ +int hdd_capture_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len) +{ + int ret = 0; + hdd_station_ctx_t *hdd_sta_ctx; + + if (adapter == NULL || buf == NULL) { + hdd_err(FL("invalid pointer")); + return -EINVAL; + } + if (len != 1) + return -EINVAL; + + /* Reset TSF value for new capture */ + adapter->tsf_high = 0; + adapter->tsf_low = 0; + + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (hdd_sta_ctx->conn_info.connState != + eConnectionState_Associated) { + + hdd_err(FL("failed to cap tsf, not connect with ap")); + buf[0] = TSF_STA_NOT_CONNECTED_NO_TSF; + return ret; + } + } + if ((adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) && + !(test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags))) { + hdd_err(FL("Soft AP / P2p GO not beaconing")); + buf[0] = TSF_SAP_NOT_STARTED_NO_TSF; + return ret; + } + if (adapter->tsf_state == TSF_CAP_STATE) { + hdd_err(FL("current in capture state, pls reset")); + buf[0] = TSF_CURRENT_IN_CAP_STATE; + } else { + hdd_info(FL("Send TSF capture to FW")); + buf[0] = TSF_RETURN; + adapter->tsf_state = TSF_CAP_STATE; + ret = wma_cli_set_command((int)adapter->sessionId, + (int)GEN_PARAM_CAPTURE_TSF, + adapter->sessionId, + GEN_CMD); + + if (ret != QDF_STATUS_SUCCESS) { + hdd_err(FL("capture fail")); + buf[0] = TSF_CAPTURE_FAIL; + adapter->tsf_state = TSF_IDLE; + } + } + return ret; +} + +/** + * hdd_indicate_tsf() - return tsf to uplayer + * @adapter: pointer to adapter + * @buf: pointer to uplayer buf + * @len : the length of buf + * + * This function returns tsf value to upper layer. + * + * Return: 0 for success or non-zero negative failure code + */ +int hdd_indicate_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len) +{ + int ret = 0; + hdd_station_ctx_t *hdd_sta_ctx; + + if (adapter == NULL || buf == NULL) { + hdd_err(FL("invalid pointer")); + return -EINVAL; + } + + if (len != 3) + return -EINVAL; + + buf[1] = 0; + buf[2] = 0; + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (hdd_sta_ctx->conn_info.connState != + eConnectionState_Associated) { + + hdd_info(FL("fail to get tsf, sta in disconnected")); + buf[0] = TSF_STA_NOT_CONNECTED_NO_TSF; + return ret; + } + } + if ((adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) && + !(test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags))) { + hdd_err(FL("Soft AP / P2p GO not beaconing")); + buf[0] = TSF_SAP_NOT_STARTED_NO_TSF; + return ret; + } + if (adapter->tsf_high == 0 && adapter->tsf_low == 0) { + hdd_info(FL("TSF value not received")); + buf[0] = TSF_NOT_RETURNED_BY_FW; + } else { + buf[0] = TSF_RETURN; + buf[1] = adapter->tsf_low; + buf[2] = adapter->tsf_high; + adapter->tsf_state = TSF_IDLE; + + ret = wma_cli_set_command((int)adapter->sessionId, + (int)GEN_PARAM_RESET_TSF_GPIO, + adapter->sessionId, + GEN_CMD); + + if (0 != ret) { + hdd_err(FL("tsf get fail ")); + buf[0] = TSF_RESET_GPIO_FAIL; + } + hdd_info(FL("get tsf cmd,status=%u, tsf_low=%u, tsf_high=%u"), + buf[0], buf[1], buf[2]); + } + return ret; +} + +/** + * hdd_get_tsf_cb() - handle tsf callback + * @pcb_cxt: pointer to the hdd_contex + * @ptsf: pointer to struct stsf + * + * This function handle the event that reported by firmware at first. + * The event contains the vdev_id, current tsf value of this vdev, + * tsf value is 64bits, discripted in two varaible tsf_low and tsf_high. + * These two values each is uint32. + * + * Return: 0 for success or non-zero negative failure code + */ +static int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf) +{ + struct hdd_context_s *hddctx; + struct hdd_adapter_s *adapter; + int status; + + if (pcb_cxt == NULL || ptsf == NULL) { + hdd_err(FL("HDD context is not valid")); + return -EINVAL; + } + + hddctx = (struct hdd_context_s *)pcb_cxt; + status = wlan_hdd_validate_context(hddctx); + if (0 != status) { + hdd_err(FL("hdd context is not valid")); + return -EINVAL; + } + + adapter = hdd_get_adapter_by_vdev(hddctx, ptsf->vdev_id); + + if (NULL == adapter) { + hdd_err(FL("failed to find adapter")); + return -EINVAL; + } + + hdd_info(FL("tsf cb handle event, device_mode is %d"), + adapter->device_mode); + + adapter->tsf_low = ptsf->tsf_low; + adapter->tsf_high = ptsf->tsf_high; + + hdd_info(FL("hdd_get_tsf_cb sta=%u, tsf_low=%u, tsf_high=%u"), + ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high); + return 0; +} + +/** + * wlan_hdd_tsf_init() - set callback to handle tsf value. + * @hdd_ctx: pointer to the struct hdd_context_s + * + * This function set the callback to sme module, the callback will be + * called when a tsf event is reported by firmware + * + * Return: none + */ +void wlan_hdd_tsf_init(struct hdd_context_s *hdd_ctx) +{ + sme_set_tsfcb(hdd_ctx->hHal, hdd_get_tsf_cb, hdd_ctx); +} diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index f8f4137c4e6c..b88b01bf11ed 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -80,6 +80,7 @@ #include "sme_power_save_api.h" #include "cds_concurrency.h" #include "wlan_hdd_conc_ut.h" +#include "wlan_hdd_tsf.h" #include "wlan_hdd_ocb.h" #include "wlan_hdd_napi.h" #include "cdp_txrx_flow_ctrl_legacy.h" @@ -273,6 +274,7 @@ static const hdd_freq_chan_map_t freq_chan_map[] = { #define WE_GET_GTX_MINTPC 53 #define WE_GET_GTX_BWMASK 54 #define WE_GET_TEMPERATURE 56 +#define WE_CAP_TSF 58 /* Private ioctls and their sub-ioctls */ #define WLAN_PRIV_SET_INT_GET_INT (SIOCIWFIRSTPRIV + 2) @@ -383,7 +385,8 @@ static const hdd_freq_chan_map_t freq_chan_map[] = { /* (SIOCIWFIRSTPRIV + 10) is currently unused */ /* (SIOCIWFIRSTPRIV + 12) is currently unused */ /* (SIOCIWFIRSTPRIV + 14) is currently unused */ -/* (SIOCIWFIRSTPRIV + 15) is currently unused */ +#define WLAN_PRIV_SET_NONE_GET_THREE_INT (SIOCIWFIRSTPRIV + 15) +#define WE_GET_TSF 1 /* (SIOCIWFIRSTPRIV + 16) is currently unused */ /* (SIOCIWFIRSTPRIV + 17) is currently unused */ /* (SIOCIWFIRSTPRIV + 19) is currently unused */ @@ -6298,6 +6301,65 @@ static int iw_setint_getnone(struct net_device *dev, return ret; } +/** + * __iw_setnone_get_threeint() - return three value to up layer. + * + * @dev: pointer of net_device of this wireless card + * @info: meta data about Request sent + * @wrqu: include request info + * @extra: buf used for in/Output + * + * Return: execute result + */ +static int __iw_setnone_get_threeint(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret = 0; /* success */ + uint32_t *value = (int *)extra; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + ENTER_DEV(dev); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + hdd_info(FL("param = %d"), value[0]); + switch (value[0]) { + case WE_GET_TSF: + ret = hdd_indicate_tsf(adapter, value, 3); + break; + default: + hdd_err("Invalid IOCTL get_value command %d", value[0]); + break; + } + return ret; +} + +/** + * iw_setnone_get_threeint() - return three value to up layer. + * + * @dev: pointer of net_device of this wireless card + * @info: meta data about Request sent + * @wrqu: include request info + * @extra: buf used for in/Output + * + * Return: execute result + */ +static int iw_setnone_get_threeint(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_setnone_get_threeint(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + /** * iw_setchar_getnone() - Generic "set string" private ioctl handler * @dev: device upon which the ioctl was received @@ -6914,7 +6976,9 @@ static int __iw_setnone_getint(struct net_device *dev, QPOWER_CMD); break; } - + case WE_CAP_TSF: + ret = hdd_capture_tsf(pAdapter, (uint32_t *)value, 1); + break; case WE_GET_TEMPERATURE: { hddLog(QDF_TRACE_LEVEL_INFO, "WE_GET_TEMPERATURE"); @@ -9809,6 +9873,8 @@ static const iw_handler we_private[] = { [WLAN_PRIV_SET_NONE_GET_NONE - SIOCIWFIRSTPRIV] = iw_setnone_getnone, /* action priv ioctl */ [WLAN_PRIV_SET_VAR_INT_GET_NONE - SIOCIWFIRSTPRIV] = iw_hdd_set_var_ints_getnone, + [WLAN_PRIV_SET_NONE_GET_THREE_INT - SIOCIWFIRSTPRIV] = + iw_setnone_get_threeint, [WLAN_PRIV_ADD_TSPEC - SIOCIWFIRSTPRIV] = iw_add_tspec, [WLAN_PRIV_DEL_TSPEC - SIOCIWFIRSTPRIV] = iw_del_tspec, [WLAN_PRIV_GET_TSPEC - SIOCIWFIRSTPRIV] = iw_get_tspec, @@ -10506,6 +10572,11 @@ static const struct iw_priv_args we_private_args[] = { IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_qnodatapoll"}, + {WE_CAP_TSF, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "cap_tsf"}, + {WE_GET_TEMPERATURE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, @@ -10565,6 +10636,15 @@ static const struct iw_priv_args we_private_args[] = { IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "setsapchannels"}, + /* handlers for main ioctl */ + {WLAN_PRIV_SET_NONE_GET_THREE_INT, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + "" }, + {WE_GET_TSF, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + "get_tsf" }, {WE_SET_DUAL_MAC_SCAN_CONFIG, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index 5c5ff30e87f9..0ffc244385c7 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -5563,6 +5563,21 @@ struct sir_sme_ext_cng_chan_ind { uint8_t new_channel; }; +/** + * struct stsf - the basic stsf structure + * + * @vdev_id: vdev id + * @tsf_low: low 32bits of tsf + * @tsf_high: high 32bits of tsf + * + * driver use this struct to store the tsf info + */ +struct stsf { + uint32_t vdev_id; + uint32_t tsf_low; + uint32_t tsf_high; +}; + /** * struct egap_params - the enhanced green ap params * @vdev_id: vdev id diff --git a/core/mac/inc/wni_api.h b/core/mac/inc/wni_api.h index 23ab4d2dffe1..93aae032223e 100644 --- a/core/mac/inc/wni_api.h +++ b/core/mac/inc/wni_api.h @@ -248,6 +248,7 @@ enum eWniMsgTypes { eWNI_SME_HT40_OBSS_SCAN_IND, /* START and UPDATE OBSS SCAN Indication*/ eWNI_SME_SET_ANTENNA_MODE_REQ, eWNI_SME_SET_ANTENNA_MODE_RESP, + eWNI_SME_TSF_EVENT, eWNI_SME_MSG_TYPES_END }; diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index d836a36a0389..73ce120093e4 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -1096,6 +1096,8 @@ static inline QDF_STATUS sme_send_egap_conf_params(uint32_t enable, void sme_update_fine_time_measurement_capab(tHalHandle hal, uint32_t val); QDF_STATUS sme_ht40_stop_obss_scan(tHalHandle hHal, uint32_t vdev_id); +QDF_STATUS sme_set_tsfcb(tHalHandle hHal, + int (*cb_fn)(void *cb_ctx, struct stsf *ptsf), void *cb_ctx); QDF_STATUS sme_update_mimo_power_save(tHalHandle hHal, uint8_t is_ht_smps_enabled, diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index 9e27ba2d2307..f681208043f3 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -197,6 +197,8 @@ typedef struct tagSmeStruct { bool enableSelfRecovery; tCsrLinkStatusCallback linkStatusCallback; void *linkStatusContext; + int (*get_tsf_cb)(void *pcb_cxt, struct stsf *ptsf); + void *get_tsf_cxt; /* get temperature event context and callback */ void *pTemperatureCbContext; void (*pGetTemperatureCb)(int temperature, void *context); diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index c12aef820c50..8785b0b017b6 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -2805,6 +2805,14 @@ QDF_STATUS sme_process_msg(tHalHandle hHal, cds_msg_t *pMsg) qdf_mem_free(pMsg->bodyptr); } break; + case eWNI_SME_TSF_EVENT: + if (pMac->sme.get_tsf_cb) { + pMac->sme.get_tsf_cb(pMac->sme.get_tsf_cxt, + (struct stsf *)pMsg->bodyptr); + } + if (pMsg->bodyptr) + qdf_mem_free(pMsg->bodyptr); + break; #ifdef WLAN_FEATURE_NAN case eWNI_SME_NAN_EVENT: if (pMsg->bodyptr) { @@ -7300,6 +7308,29 @@ QDF_STATUS sme_preferred_network_found_ind(tHalHandle hHal, void *pMsg) #endif /* FEATURE_WLAN_SCAN_PNO */ +/* + * sme_set_tsfcb() - Set callback for TSF capture + * @hHal: Handler return by macOpen + * @cb_fn: Callback function pointer + * @db_ctx: Callback data + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_tsfcb(tHalHandle hHal, + int (*cb_fn)(void *cb_ctx, struct stsf *ptsf), void *cb_ctx) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->sme.get_tsf_cb = cb_fn; + pMac->sme.get_tsf_cxt = cb_ctx; + sme_release_global_lock(&pMac->sme); + } + return status; +} + QDF_STATUS sme_get_cfg_valid_channels(tHalHandle hHal, uint8_t *aValidChannels, uint32_t *len) { diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h index cec1e1e705ab..4bf40d266470 100644 --- a/core/wma/inc/wma_api.h +++ b/core/wma/inc/wma_api.h @@ -65,6 +65,8 @@ typedef enum { GEN_PARAM_DUMP_PCIE_ACCESS_LOG, #endif GEN_PARAM_MODULATED_DTIM, + GEN_PARAM_CAPTURE_TSF, + GEN_PARAM_RESET_TSF_GPIO, } GEN_PARAM; #define VDEV_CMD 1 diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index 42c2c9d6fe3f..4543eaac9113 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -1072,6 +1072,10 @@ QDF_STATUS wma_set_auto_shutdown_timer_req(tp_wma_handle wma_handle, auto_sh_cmd); #endif +int wma_vdev_tsf_handler(void *handle, uint8_t *data, uint32_t data_len); +QDF_STATUS wma_capture_tsf(tp_wma_handle wma_handle, uint32_t vdev_id); +QDF_STATUS wma_reset_tsf_gpio(tp_wma_handle wma_handle, uint32_t vdev_id); + #ifdef WLAN_FEATURE_NAN QDF_STATUS wma_nan_req(void *wma_ptr, tpNanRequest nan_req); diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index 447aa417635b..3e526e53b38b 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -267,6 +267,177 @@ end: wma_post_link_status(pGetLinkStatus, LINK_STATUS_LEGACY); } +#ifdef WLAN_FEATURE_TSF +/** + * wma_vdev_tsf_handler() - handle tsf event indicated by FW + * @handle: wma context + * @data: event buffer + * @data len: length of event buffer + * + * Return: 0 on success + */ +int wma_vdev_tsf_handler(void *handle, uint8_t *data, uint32_t data_len) +{ + cds_msg_t tsf_msg = {0}; + WMI_VDEV_TSF_REPORT_EVENTID_param_tlvs *param_buf; + wmi_vdev_tsf_report_event_fixed_param *tsf_event; + struct stsf *ptsf; + + if (data == NULL) { + WMA_LOGE("%s: invalid pointer", __func__); + return -EINVAL; + } + ptsf = qdf_mem_malloc(sizeof(*ptsf)); + if (NULL == ptsf) { + WMA_LOGE("%s: failed to allocate tsf data structure", __func__); + return -ENOMEM; + } + + param_buf = (WMI_VDEV_TSF_REPORT_EVENTID_param_tlvs *)data; + tsf_event = param_buf->fixed_param; + + ptsf->vdev_id = tsf_event->vdev_id; + ptsf->tsf_low = tsf_event->tsf_low; + ptsf->tsf_high = tsf_event->tsf_high; + + WMA_LOGD("%s: receive WMI_VDEV_TSF_REPORT_EVENTID ", __func__); + WMA_LOGD("%s: vdev_id = %u,tsf_low =%u, tsf_high = %u", __func__, + ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high); + + tsf_msg.type = eWNI_SME_TSF_EVENT; + tsf_msg.bodyptr = ptsf; + tsf_msg.bodyval = 0; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, &tsf_msg)) { + + WMA_LOGP("%s: Failed to post eWNI_SME_TSF_EVENT", __func__); + qdf_mem_free(ptsf); + return -EINVAL; + } + return 0; +} + +/** + * wma_capture_tsf() - send wmi to fw to capture tsf + * @wma_handle: wma handler + * @vdev_id: vdev id + * + * Return: wmi send state + */ +QDF_STATUS wma_capture_tsf(tp_wma_handle wma_handle, uint32_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_buf_t buf; + wmi_vdev_tsf_tstamp_action_cmd_fixed_param *cmd; + int ret; + int len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: failed to allocate memory for cap tsf cmd", + __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_vdev_tsf_tstamp_action_cmd_fixed_param *) wmi_buf_data(buf); + cmd->vdev_id = vdev_id; + cmd->tsf_action = TSF_TSTAMP_CAPTURE_REQ; + + WMA_LOGD("%s :vdev_id %u, TSF_TSTAMP_CAPTURE_REQ", __func__, + cmd->vdev_id); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_tsf_tstamp_action_cmd_fixed_param)); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_TSF_TSTAMP_ACTION_CMDID); + if (ret != EOK) { + WMA_LOGE("wmi_unified_cmd_send returned Error %d", status); + status = QDF_STATUS_E_FAILURE; + goto error; + } + + return QDF_STATUS_SUCCESS; + +error: + if (buf) + wmi_buf_free(buf); + return status; +} + +/** + * wma_reset_tsf_gpio() - send wmi to fw to reset GPIO + * @wma_handle: wma handler + * @vdev_id: vdev id + * + * Return: wmi send state + */ +QDF_STATUS wma_reset_tsf_gpio(tp_wma_handle wma_handle, uint32_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_buf_t buf; + wmi_vdev_tsf_tstamp_action_cmd_fixed_param *cmd; + int ret; + int len = sizeof(*cmd); + uint8_t *buf_ptr; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: failed to allocate memory for reset tsf gpio", + __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_vdev_tsf_tstamp_action_cmd_fixed_param *) buf_ptr; + cmd->vdev_id = vdev_id; + cmd->tsf_action = TSF_TSTAMP_CAPTURE_RESET; + + WMA_LOGD("%s :vdev_id %u, TSF_TSTAMP_CAPTURE_RESET", __func__, + cmd->vdev_id); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_tsf_tstamp_action_cmd_fixed_param)); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_TSF_TSTAMP_ACTION_CMDID); + + if (ret != EOK) { + WMA_LOGE("wmi_unified_cmd_send returned Error %d", status); + status = QDF_STATUS_E_FAILURE; + goto error; + } + return QDF_STATUS_SUCCESS; + +error: + if (buf) + wmi_buf_free(buf); + return status; +} +#else +QDF_STATUS wma_capture_tsf(tp_wma_handle wma_handle, uint32_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_reset_tsf_gpio(tp_wma_handle wma_handle, uint32_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +int wma_vdev_tsf_handler(void *handle, uint8_t *data, uint32_t data_len) +{ + return 0; +} +#endif + + + #ifdef FEATURE_WLAN_LPHB /** * wma_lphb_conf_hbenable() - enable command of LPHB configuration requests diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 723ff4921eb8..b48424401c2a 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -919,6 +919,12 @@ static void wma_process_cli_set_cmd(tp_wma_handle wma, privcmd->param_value, privcmd->param_sec_value); break; + case GEN_PARAM_CAPTURE_TSF: + ret = wma_capture_tsf(wma, privcmd->param_value); + break; + case GEN_PARAM_RESET_TSF_GPIO: + ret = wma_reset_tsf_gpio(wma, privcmd->param_value); + break; #ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG case GEN_PARAM_DUMP_PCIE_ACCESS_LOG: htc_dump(wma->htc_handle, PCIE_DUMP, false); @@ -2755,6 +2761,16 @@ QDF_STATUS wma_start(void *cds_ctx) goto end; } + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_VDEV_TSF_REPORT_EVENTID, + wma_vdev_tsf_handler, + WMA_RX_SERIALIZER_CTX); + if (0 != status) { + WMA_LOGP("%s: Failed to register tsf callback", __func__); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + /* Initialize the log flush complete event handler */ status = wmi_unified_register_event_handler(wma_handle->wmi_handle, WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID,