diff --git a/Kbuild b/Kbuild index 64a02f9aa567..94de5cfab8b4 100644 --- a/Kbuild +++ b/Kbuild @@ -2209,6 +2209,8 @@ cppflags-$(CONFIG_FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL) += -DFEATURE_HL_GROUP_CR cppflags-$(CONFIG_FEATURE_HL_DBS_GROUP_CREDIT_SHARING) += -DFEATURE_HL_DBS_GROUP_CREDIT_SHARING cppflags-$(CONFIG_CREDIT_REP_THROUGH_CREDIT_UPDATE) += -DCONFIG_CREDIT_REP_THROUGH_CREDIT_UPDATE +cppflags-$(CONFIG_WLAN_SYNC_TSF_PTP) += -DWLAN_FEATURE_TSF_PTP +cppflags-$(CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_IRQ) += -DWLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ cppflags-$(CONFIG_TX_DESC_HI_PRIO_RESERVE) += -DCONFIG_TX_DESC_HI_PRIO_RESERVE #Enable FW logs through ini diff --git a/components/fw_offload/core/inc/wlan_fw_offload_main.h b/components/fw_offload/core/inc/wlan_fw_offload_main.h index 84bc8eba7eef..824afa37cad8 100644 --- a/components/fw_offload/core/inc/wlan_fw_offload_main.h +++ b/components/fw_offload/core/inc/wlan_fw_offload_main.h @@ -158,6 +158,7 @@ struct wlan_fwol_neighbor_report_cfg { * @enable_fw_module_log_level_num: enablefw module log level num * @is_rate_limit_enabled: Enable/disable RA rate limited * @tsf_gpio_pin: TSF GPIO Pin config + * @tsf_irq_host_gpio_pin: TSF GPIO Pin config * @tsf_ptp_options: TSF Plus feature options config * @lprx_enable: LPRx feature enable config * @sae_enable: SAE feature enable config @@ -196,6 +197,9 @@ struct wlan_fwol_cfg { uint32_t tsf_gpio_pin; #ifdef WLAN_FEATURE_TSF_PLUS uint32_t tsf_ptp_options; +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ + uint32_t tsf_irq_host_gpio_pin; +#endif #endif #endif bool lprx_enable; diff --git a/components/fw_offload/core/src/wlan_fw_offload_main.c b/components/fw_offload/core/src/wlan_fw_offload_main.c index 860789eef303..4a1305fc8464 100644 --- a/components/fw_offload/core/src/wlan_fw_offload_main.c +++ b/components/fw_offload/core/src/wlan_fw_offload_main.c @@ -356,6 +356,32 @@ static void ucfg_fwol_init_tsf_ptp_options(struct wlan_objmgr_psoc *psoc, } #endif +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ +/** + * ucfg_fwol_fetch_tsf_irq_host_gpio_pin: Populate the + * tsf_irq_host_gpio_pin from cfg + * @psoc: The global psoc handler + * @fwol_cfg: The cfg structure + * + * This function is used to populate the cfg value of host platform + * gpio pin configured to receive tsf interrupt from fw. + * + * Return: none + */ +static void +ucfg_fwol_fetch_tsf_irq_host_gpio_pin(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ + fwol_cfg->tsf_irq_host_gpio_pin = + cfg_get(psoc, CFG_SET_TSF_IRQ_HOST_GPIO_PIN); +} +#else +static void +ucfg_fwol_fetch_tsf_irq_host_gpio_pin(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ +} +#endif /** * ucfg_fwol_init_sae_cfg: Populate the sae control config from cfg * @psoc: The global psoc handler @@ -448,6 +474,7 @@ QDF_STATUS fwol_cfg_on_psoc_enable(struct wlan_objmgr_psoc *psoc) fwol_init_adapt_dwelltime_in_cfg(psoc, &fwol_cfg->dwelltime_params); ucfg_fwol_fetch_ra_filter(psoc, fwol_cfg); ucfg_fwol_fetch_tsf_gpio_pin(psoc, fwol_cfg); + ucfg_fwol_fetch_tsf_irq_host_gpio_pin(psoc, fwol_cfg); ucfg_fwol_fetch_dhcp_server_settings(psoc, fwol_cfg); return status; diff --git a/components/fw_offload/dispatcher/inc/cfg_fwol_generic.h b/components/fw_offload/dispatcher/inc/cfg_fwol_generic.h index b37bf19ac34c..d090008d14de 100644 --- a/components/fw_offload/dispatcher/inc/cfg_fwol_generic.h +++ b/components/fw_offload/dispatcher/inc/cfg_fwol_generic.h @@ -434,6 +434,34 @@ CFG_VALUE_OR_DEFAULT, \ "GPIO pin to toggle when capture tsf") +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ +/* + * gtsf_irq_host_gpio_pin + * @Min: 0 + * @Max: 254 + * @Default: 255 + * + * TSF irq GPIO pin of host platform + * + * Related: None + * + * Usage: Internal + * + * + */ +#define CFG_SET_TSF_IRQ_HOST_GPIO_PIN CFG_INI_INT( \ + "gtsf_irq_host_gpio_pin", \ + 0, \ + 254, \ + 255, \ + CFG_VALUE_OR_DEFAULT, \ + "TSF irq GPIO pin of host platform") + +#define __CFG_SET_TSF_IRQ_HOST_GPIO_PIN CFG(CFG_SET_TSF_IRQ_HOST_GPIO_PIN) +#else +#define __CFG_SET_TSF_IRQ_HOST_GPIO_PIN +#endif + #if defined(WLAN_FEATURE_TSF) && defined(WLAN_FEATURE_TSF_PLUS) /* * gtsf_ptp_options: TSF Plus feature options @@ -464,6 +492,7 @@ 0xf, \ CFG_VALUE_OR_DEFAULT, \ "TSF Plus feature options") + #define __CFG_SET_TSF_PTP_OPT CFG(CFG_SET_TSF_PTP_OPT) #else #define __CFG_SET_TSF_PTP_OPT @@ -655,6 +684,7 @@ CFG(CFG_ENABLE_FW_MODULE_LOG_LEVEL) \ CFG(CFG_RA_FILTER_ENABLE) \ CFG(CFG_SET_TSF_GPIO_PIN) \ + __CFG_SET_TSF_IRQ_HOST_GPIO_PIN \ __CFG_SET_TSF_PTP_OPT \ CFG(CFG_LPRX) \ __CFG_IS_SAE_ENABLED \ diff --git a/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h b/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h index a29a1615bc16..32b14db4e746 100644 --- a/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h +++ b/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h @@ -304,6 +304,19 @@ QDF_STATUS ucfg_fwol_get_is_rate_limit_enabled(struct wlan_objmgr_psoc *psoc, QDF_STATUS ucfg_fwol_get_tsf_gpio_pin(struct wlan_objmgr_psoc *psoc, uint32_t *tsf_gpio_pin); +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ +/** + * ucfg_fwol_get_tsf_irq_host_gpio_pin() - Assigns tsf_irq_host_gpio_pin value + * @psoc: pointer to the psoc object + * + * Return: QDF Status + */ + +QDF_STATUS +ucfg_fwol_get_tsf_irq_host_gpio_pin(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_irq_host_gpio_pin); +#endif + #ifdef DHCP_SERVER_OFFLOAD /** * ucfg_fwol_get_enable_dhcp_server_offload()-Assign enable_dhcp_server_offload diff --git a/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c b/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c index ed270b684fb3..fc7f59ab05f5 100644 --- a/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c +++ b/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c @@ -558,6 +558,27 @@ QDF_STATUS ucfg_fwol_get_tsf_ptp_options(struct wlan_objmgr_psoc *psoc, *tsf_ptp_options = fwol_obj->cfg.tsf_ptp_options; return QDF_STATUS_SUCCESS; } + +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ +QDF_STATUS +ucfg_fwol_get_tsf_irq_host_gpio_pin(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_irq_host_gpio_pin) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + *tsf_irq_host_gpio_pin = + cfg_default(CFG_SET_TSF_IRQ_HOST_GPIO_PIN); + return QDF_STATUS_E_FAILURE; + } + + *tsf_irq_host_gpio_pin = fwol_obj->cfg.tsf_irq_host_gpio_pin; + return QDF_STATUS_SUCCESS; +} + +#endif #endif #else QDF_STATUS ucfg_fwol_get_tsf_gpio_pin(struct wlan_objmgr_psoc *psoc, @@ -571,6 +592,7 @@ QDF_STATUS ucfg_fwol_get_tsf_ptp_options(struct wlan_objmgr_psoc *psoc, { return QDF_STATUS_E_NOSUPPORT; } + #endif QDF_STATUS ucfg_fwol_get_lprx_enable(struct wlan_objmgr_psoc *psoc, @@ -594,6 +616,7 @@ bool ucfg_fwol_get_sae_enable(struct wlan_objmgr_psoc *psoc) { return cfg_get(psoc, CFG_IS_SAE_ENABLED); } + #else bool ucfg_fwol_get_sae_enable(struct wlan_objmgr_psoc *psoc) { diff --git a/configs/genoa.pci.debug_defconfig b/configs/genoa.pci.debug_defconfig index d64cb5f7a105..d8edee435e84 100644 --- a/configs/genoa.pci.debug_defconfig +++ b/configs/genoa.pci.debug_defconfig @@ -47,6 +47,13 @@ ifeq ($(CONFIG_DEBUG_FS), y) CONFIG_WLAN_POWER_DEBUGFS := y endif +ifeq ($(CONFIG_NETWORK_PHY_TIMESTAMPING), y) + CONFIG_WLAN_SYNC_TSF_PLUS := y + CONFIG_WLAN_SYNC_TSF_PTP := y + CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_IRQ := y +endif + + ifeq ($(CONFIG_SLUB_DEBUG_ON), y) CONFIG_DESC_DUP_DETECT_DEBUG := y CONFIG_DEBUG_RX_RING_BUFFER := y diff --git a/configs/genoa.pci.perf_defconfig b/configs/genoa.pci.perf_defconfig index 0c6617e066c3..f76490c6ef1b 100644 --- a/configs/genoa.pci.perf_defconfig +++ b/configs/genoa.pci.perf_defconfig @@ -46,6 +46,12 @@ ifeq ($(CONFIG_DEBUG_FS), y) CONFIG_WLAN_POWER_DEBUGFS := n endif +ifeq ($(CONFIG_NETWORK_PHY_TIMESTAMPING), y) + CONFIG_WLAN_SYNC_TSF_PLUS := y + CONFIG_WLAN_SYNC_TSF_PTP := y + CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_IRQ := y +endif + ifeq ($(CONFIG_SLUB_DEBUG_ON), y) CONFIG_DESC_DUP_DETECT_DEBUG := n CONFIG_DEBUG_RX_RING_BUFFER := n diff --git a/configs/genoa.usb.debug_defconfig b/configs/genoa.usb.debug_defconfig index f6cd57e92e68..ca4720ef6271 100644 --- a/configs/genoa.usb.debug_defconfig +++ b/configs/genoa.usb.debug_defconfig @@ -27,6 +27,12 @@ ifeq ($(CONFIG_DEBUG_FS), y) CONFIG_WLAN_POWER_DEBUGFS := y endif +ifeq ($(CONFIG_NETWORK_PHY_TIMESTAMPING), y) + CONFIG_WLAN_SYNC_TSF_PLUS := y + CONFIG_WLAN_SYNC_TSF_PTP := y + CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_IRQ := y +endif + # Features gets enabled on slub debug CONFIG_WLAN_DEBUG_CRASH_INJECT := y CONFIG_FEATURE_MEMDUMP_ENABLE := y diff --git a/configs/genoa.usb.perf_defconfig b/configs/genoa.usb.perf_defconfig index 5cfd4ca3fc1d..de73a4affb5c 100644 --- a/configs/genoa.usb.perf_defconfig +++ b/configs/genoa.usb.perf_defconfig @@ -32,6 +32,11 @@ CONFIG_FEATURE_UNIT_TEST_SUSPEND := n CONFIG_LEAK_DETECTION := n endif +ifeq ($(CONFIG_NETWORK_PHY_TIMESTAMPING), y) + CONFIG_WLAN_SYNC_TSF_PLUS := y + CONFIG_WLAN_SYNC_TSF_PTP := y + CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_IRQ := y +endif CONFIG_ENABLE_SIZE_OPTIMIZE := y diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index d855172bf7c7..057101cd6246 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -61,6 +61,10 @@ #if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) #include #endif +#ifdef WLAN_FEATURE_TSF_PTP +#include +#include +#endif #include #include "wlan_hdd_tdls.h" #include "wlan_hdd_tsf.h" @@ -1806,6 +1810,10 @@ struct hdd_context { qdf_atomic_t cap_tsf_flag; /* the context that is capturing tsf */ struct hdd_adapter *cap_tsf_context; +#endif +#ifdef WLAN_FEATURE_TSF_PTP + struct ptp_clock_info ptp_cinfo; + struct ptp_clock *ptp_clock; #endif uint8_t bt_a2dp_active:1; uint8_t bt_vo_active:1; diff --git a/core/hdd/inc/wlan_hdd_tsf.h b/core/hdd/inc/wlan_hdd_tsf.h index 81235ecb09bc..547e19d6cc60 100644 --- a/core/hdd/inc/wlan_hdd_tsf.h +++ b/core/hdd/inc/wlan_hdd_tsf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -316,4 +316,15 @@ void hdd_capture_req_timer_expired_handler(void *arg) } #endif +#ifdef WLAN_FEATURE_TSF_PTP +/** + * wlan_get_ts_info() - return ts info to uplayer + * @dev: pointer to net_device + * @info: pointer to ethtool_ts_info + * + * Return: Describe the execute result of this routine + */ +int wlan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info); + +#endif #endif diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index 3606d98cf249..05dcdeea352c 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -36,6 +36,7 @@ #include #include #include "osif_sync.h" +#include #include #include #include "osif_sync.h" @@ -1896,6 +1897,7 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event, ap_ctx->operating_channel); hostapd_state->bss_state = BSS_START; + hdd_start_tsf_sync(adapter); /* Set default key index */ hdd_debug("default key index %hu", ap_ctx->wep_def_key_idx); @@ -2642,6 +2644,7 @@ stopbss: * re-enabled */ hostapd_state->bss_state = BSS_STOP; + hdd_stop_tsf_sync(adapter); #ifdef FEATURE_WLAN_AUTO_SHUTDOWN wlan_hdd_auto_shutdown_enable(hdd_ctx, true); @@ -3162,6 +3165,12 @@ sap_restart: } #endif +#ifdef WLAN_FEATURE_TSF_PTP +static const struct ethtool_ops wlan_hostapd_ethtool_ops = { + .get_ts_info = wlan_get_ts_info, +}; +#endif + const struct net_device_ops net_ops_struct = { .ndo_open = hdd_hostapd_open, .ndo_stop = hdd_hostapd_stop, @@ -3175,10 +3184,18 @@ const struct net_device_ops net_ops_struct = { .ndo_select_queue = hdd_select_queue, }; +#ifdef WLAN_FEATURE_TSF_PTP +void hdd_set_ap_ops(struct net_device *dev) +{ + dev->netdev_ops = &net_ops_struct; + dev->ethtool_ops = &wlan_hostapd_ethtool_ops; +} +#else void hdd_set_ap_ops(struct net_device *dev) { dev->netdev_ops = &net_ops_struct; } +#endif bool hdd_sap_create_ctx(struct hdd_adapter *adapter) { diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index c3f798ed37fc..7d6000eb4bc0 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -79,6 +79,7 @@ #include #include #include +#include #ifdef MSM_PLATFORM #include #endif @@ -3743,6 +3744,12 @@ static void hdd_set_multicast_list(struct net_device *net_dev) osif_vdev_sync_op_stop(vdev_sync); } +#ifdef WLAN_FEATURE_TSF_PTP +static const struct ethtool_ops wlan_ethtool_ops = { + .get_ts_info = wlan_get_ts_info, +}; +#endif + static const struct net_device_ops wlan_drv_ops = { .ndo_open = hdd_open, .ndo_stop = hdd_stop, @@ -3764,6 +3771,7 @@ static const struct net_device_ops wlan_mon_drv_ops = { .ndo_get_stats = hdd_get_stats, }; +#ifdef WLAN_FEATURE_TSF_PTP /** * hdd_set_station_ops() - update net_device ops for monitor mode * @dev: Handle to struct net_device to be updated. @@ -3771,17 +3779,37 @@ static const struct net_device_ops wlan_mon_drv_ops = { */ void hdd_set_station_ops(struct net_device *dev) { - if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) + if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) { + dev->netdev_ops = &wlan_mon_drv_ops; + } else { + dev->netdev_ops = &wlan_drv_ops; + dev->ethtool_ops = &wlan_ethtool_ops; + } +} +#else +void hdd_set_station_ops(struct net_device *dev) +{ + if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) dev->netdev_ops = &wlan_mon_drv_ops; else dev->netdev_ops = &wlan_drv_ops; } + +#endif +#else +#ifdef WLAN_FEATURE_TSF_PTP +void hdd_set_station_ops(struct net_device *dev) +{ + dev->netdev_ops = &wlan_drv_ops; + dev->ethtool_ops = &wlan_ethtool_ops; +} #else void hdd_set_station_ops(struct net_device *dev) { dev->netdev_ops = &wlan_drv_ops; } #endif +#endif /** * hdd_alloc_station_adapter() - allocate the station hdd adapter diff --git a/core/hdd/src/wlan_hdd_tsf.c b/core/hdd/src/wlan_hdd_tsf.c index 1cd28ad1e696..8149cca26228 100644 --- a/core/hdd/src/wlan_hdd_tsf.c +++ b/core/hdd/src/wlan_hdd_tsf.c @@ -27,6 +27,10 @@ #include "wlan_fwol_ucfg_api.h" #include #include +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ +#include +static int tsf_gpio_irq_num = -1; +#endif #include "ol_txrx_api.h" static struct completion tsf_sync_get_completion_evt; @@ -35,6 +39,16 @@ static struct completion tsf_sync_get_completion_evt; #define WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS 100 #define WLAN_HDD_SOFTAP_INTERVEL_TIMES 100 +#ifdef WLAN_FEATURE_TSF_PLUS +#ifdef WLAN_FEATURE_TSF_PLUS_NOIRQ +static void hdd_update_timestamp(struct hdd_adapter *adapter); +#else +static void +hdd_update_timestamp(struct hdd_adapter *adapter, + uint64_t target_time, uint64_t host_time); +#endif +#endif + /** * enum hdd_tsf_op_result - result of tsf operation * @@ -116,6 +130,7 @@ static bool hdd_tsf_is_initialized(struct hdd_adapter *adapter) return true; } +#if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) && defined(WLAN_FEATURE_TSF_PLUS) /** * hdd_tsf_reset_gpio() - Reset TSF GPIO used for host timer sync * @adapter: pointer to adapter @@ -125,7 +140,6 @@ static bool hdd_tsf_is_initialized(struct hdd_adapter *adapter) * * Return: TSF_RETURN on Success, TSF_RESET_GPIO_FAIL on failure */ -#if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) && defined(WLAN_FEATURE_TSF_PLUS) static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter) { /* No GPIO Host timer sync for integrated WIFI Device */ @@ -145,7 +159,54 @@ static QDF_STATUS hdd_tsf_set_gpio(struct hdd_context *hdd_ctx) { return QDF_STATUS_SUCCESS; } +#else +static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter) +{ + int ret; + ret = wma_cli_set_command((int)adapter->vdev_id, + (int)GEN_PARAM_RESET_TSF_GPIO, + adapter->vdev_id, + GEN_CMD); + + if (ret != 0) { + hdd_err("tsf reset GPIO fail "); + ret = TSF_RESET_GPIO_FAIL; + } else { + ret = TSF_RETURN; + } + return ret; +} + +/** + * hdd_tsf_set_gpio() - Set TSF GPIO used for host timer sync + * @hdd_ctx: pointer to hdd context + * + * This function check GPIO and set GPIO as IRQ to FW side on + * none Adrastea arch + * + * Return: QDF_STATUS_SUCCESS on Success, others on Failure. + */ +static QDF_STATUS hdd_tsf_set_gpio(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + uint32_t tsf_gpio_pin = TSF_GPIO_PIN_INVALID; + + status = ucfg_fwol_get_tsf_gpio_pin(hdd_ctx->psoc, &tsf_gpio_pin); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_INVAL; + + if (tsf_gpio_pin == TSF_GPIO_PIN_INVALID) + return QDF_STATUS_E_INVAL; + + status = sme_set_tsf_gpio(hdd_ctx->mac_handle, + tsf_gpio_pin); + + return status; +} +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS bool hdd_tsf_is_ptp_enabled(struct hdd_context *hdd) { uint32_t tsf_ptp_options; @@ -200,51 +261,6 @@ bool hdd_tsf_is_dbg_fs_set(struct hdd_context *hdd) else return false; } - -#else -static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter) -{ - int ret; - - ret = wma_cli_set_command((int)adapter->vdev_id, - (int)GEN_PARAM_RESET_TSF_GPIO, adapter->vdev_id, - GEN_CMD); - - if (ret != 0) { - hdd_err("tsf reset GPIO fail "); - ret = TSF_RESET_GPIO_FAIL; - } else { - ret = TSF_RETURN; - } - return ret; -} - -/** - * hdd_tsf_set_gpio() - Set TSF GPIO used for host timer sync - * @hdd_ctx: pointer to hdd context - * - * This function check GPIO and set GPIO as IRQ to FW side on - * none Adrastea arch - * - * Return: QDF_STATUS_SUCCESS on Success, others on Failure. - */ -static QDF_STATUS hdd_tsf_set_gpio(struct hdd_context *hdd_ctx) -{ - QDF_STATUS status; - uint32_t tsf_gpio_pin = TSF_GPIO_PIN_INVALID; - - status = ucfg_fwol_get_tsf_gpio_pin(hdd_ctx->psoc, &tsf_gpio_pin); - if (QDF_IS_STATUS_ERROR(status)) - return QDF_STATUS_E_INVAL; - - if (tsf_gpio_pin == TSF_GPIO_PIN_INVALID) - return QDF_STATUS_E_INVAL; - - status = sme_set_tsf_gpio(hdd_ctx->mac_handle, - tsf_gpio_pin); - - return status; -} #endif static enum hdd_tsf_op_result hdd_capture_tsf_internal( @@ -387,7 +403,11 @@ static enum hdd_tsf_op_result hdd_indicate_tsf_internal( /* to distinguish 32-bit overflow case, this inverval should: * equal or less than (1/2 * OVERFLOW_INDICATOR32 us) */ +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ +#define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 2 +#else #define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 10 +#endif #define OVERFLOW_INDICATOR32 (((int64_t)0x1) << 32) #define CAP_TSF_TIMER_FIX_SEC 1 @@ -674,6 +694,9 @@ static irqreturn_t hdd_tsf_captured_irq_handler(int irq, void *arg) if (!arg) return IRQ_NONE; + if (irq != tsf_gpio_irq_num) + return IRQ_NONE; + hdd_ctx = (struct hdd_context *)arg; host_time = hdd_get_monotonic_host_time(hdd_ctx); @@ -1344,6 +1367,99 @@ enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) return HDD_TSF_OP_SUCC; } #else +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ +static +enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx) +{ + int ret; + QDF_STATUS status; + uint32_t tsf_irq_gpio_pin = TSF_GPIO_PIN_INVALID; + + if (!hdd_tsf_is_ptp_enabled(hdd_ctx)) { + hdd_info("To enable TSF_PLUS, set gtsf_ptp_options in ini"); + goto fail; + } + + status = ucfg_fwol_get_tsf_irq_host_gpio_pin(hdd_ctx->psoc, + &tsf_irq_gpio_pin); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("tsf gpio irq host pin error"); + goto fail; + } + + if (tsf_irq_gpio_pin == TSF_GPIO_PIN_INVALID) { + hdd_err("gpio host pin is invalid"); + goto fail; + } + + ret = gpio_request(tsf_irq_gpio_pin, "wlan_tsf"); + if (ret) { + hdd_err("gpio host pin is invalid"); + goto fail; + } + + ret = gpio_direction_input(tsf_irq_gpio_pin); + if (ret) { + hdd_err("gpio host pin is invalid"); + goto fail_free_gpio; + } + + tsf_gpio_irq_num = gpio_to_irq(tsf_irq_gpio_pin); + if (tsf_gpio_irq_num < 0) { + hdd_err("fail to get irq: %d", tsf_gpio_irq_num); + goto fail_free_gpio; + } + + ret = request_irq(tsf_gpio_irq_num, hdd_tsf_captured_irq_handler, + IRQF_SHARED | IRQF_TRIGGER_RISING, "wlan_tsf", + hdd_ctx); + + if (ret) { + hdd_err("Failed to register irq handler: %d", ret); + goto fail_free_gpio; + } + + if (hdd_tsf_is_tx_set(hdd_ctx)) + ol_register_timestamp_callback(hdd_tx_timestamp); + + return HDD_TSF_OP_SUCC; + +fail_free_gpio: + gpio_free(tsf_irq_gpio_pin); +fail: + tsf_gpio_irq_num = -1; + return HDD_TSF_OP_FAIL; +} + +static +enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + uint32_t tsf_irq_gpio_pin = TSF_GPIO_PIN_INVALID; + + if (!hdd_tsf_is_ptp_enabled(hdd_ctx)) + return HDD_TSF_OP_SUCC; + + status = ucfg_fwol_get_tsf_irq_host_gpio_pin(hdd_ctx->psoc, + &tsf_irq_gpio_pin); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_INVAL; + + if (tsf_irq_gpio_pin == TSF_GPIO_PIN_INVALID) + return QDF_STATUS_E_INVAL; + + if (hdd_tsf_is_tx_set(hdd_ctx)) + ol_deregister_timestamp_callback(); + + if (tsf_gpio_irq_num >= 0) { + free_irq(tsf_gpio_irq_num, hdd_ctx); + tsf_gpio_irq_num = -1; + gpio_free(tsf_irq_gpio_pin); + } + + return HDD_TSF_OP_SUCC; +} +#else static inline enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx) { @@ -1392,6 +1508,7 @@ enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) } #endif +#endif void hdd_tsf_notify_wlan_state_change(struct hdd_adapter *adapter, eConnectionState old_state, eConnectionState new_state) @@ -1448,6 +1565,197 @@ int hdd_indicate_tsf(struct hdd_adapter *adapter, uint32_t *buf, int len) return __hdd_indicate_tsf(adapter, buf, len); } +#ifdef WLAN_FEATURE_TSF_PTP +int wlan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) + +{ + struct hdd_adapter *adapter = netdev_priv(dev); + struct osif_vdev_sync *vdev_sync; + struct hdd_context *hdd_ctx; + int errno; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return -EINVAL; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return -EAGAIN; + + info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + if (hdd_ctx->ptp_clock) + info->phc_index = ptp_clock_index(hdd_ctx->ptp_clock); + else + info->phc_index = -1; + + osif_vdev_sync_op_stop(vdev_sync); + return 0; +} + +#if (KERNEL_VERSION(4, 1, 0) > LINUX_VERSION_CODE) +/** + * wlan_ptp_gettime() - return fw ts info to uplayer + * @ptp: pointer to ptp_clock_info. + * @ts: pointer to timespec. + * + * Return: Describe the execute result of this routine + */ +static int wlan_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts) +{ + uint64_t host_time, target_time = 0; + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + uint32_t tsf_reg_read_enabled; + struct osif_psoc_sync *psoc_sync; + int errno, status = 0; + + hdd_ctx = qdf_container_of(ptp, struct hdd_context, ptp_cinfo); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return -EINVAL; + + errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync); + if (errno) + return -EAGAIN; + + adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_GO_MODE); + if (!adapter) { + adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_CLIENT_MODE); + if (!adapter) { + adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (!adapter) + adapter = hdd_get_adapter(hdd_ctx, + QDF_STA_MODE); + if (!adapter) { + status = -EOPNOTSUPP; + goto end; + } + } + } + + host_time = hdd_get_monotonic_host_time(hdd_ctx); + if (hdd_get_targettime_from_hosttime(adapter, host_time, + &target_time)) { + hdd_err("get invalid target timestamp"); + status = -EINVAL; + goto end; + } + *ts = ns_to_timespec(target_time * NSEC_PER_USEC); + +end: + osif_psoc_sync_op_stop(psoc_sync); + return status; +} + +/** + * wlan_hdd_phc_init() - phc init + * @hdd_ctx: pointer to the hdd_contex. + * + * Return: NULL + */ +static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx) +{ + hdd_ctx->ptp_cinfo.gettime = wlan_ptp_gettime; + + hdd_ctx->ptp_clock = ptp_clock_register(&hdd_ctx->ptp_cinfo, + hdd_ctx->parent_dev); +} + +/** + * wlan_hdd_phc_deinit() - phc deinit + * @hdd_ctx: pointer to the hdd_contex. + * + * Return: NULL + */ +static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx) +{ + hdd_ctx->ptp_cinfo.gettime = NULL; + + if (hdd_ctx->ptp_clock) { + ptp_clock_unregister(hdd_ctx->ptp_clock); + hdd_ctx->ptp_clock = NULL; + } +} + +#else +static int wlan_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) +{ + uint64_t host_time, target_time = 0; + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct osif_psoc_sync *psoc_sync; + int errno, status = 0; + + hdd_ctx = qdf_container_of(ptp, struct hdd_context, ptp_cinfo); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return -EINVAL; + + errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync); + if (errno) + return -EAGAIN; + + adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_GO_MODE); + if (!adapter) { + adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_CLIENT_MODE); + if (!adapter) { + adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (!adapter) + adapter = hdd_get_adapter(hdd_ctx, + QDF_STA_MODE); + if (!adapter) { + status = -EOPNOTSUPP; + goto end; + } + } + } + + host_time = hdd_get_monotonic_host_time(hdd_ctx); + if (hdd_get_targettime_from_hosttime(adapter, host_time, + &target_time)) { + hdd_err("get invalid target timestamp"); + status = -EINVAL; + goto end; + } + *ts = ns_to_timespec64(target_time * NSEC_PER_USEC); + +end: + osif_psoc_sync_op_stop(psoc_sync); + return status; +} + +static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx) +{ + hdd_ctx->ptp_cinfo.gettime64 = wlan_ptp_gettime; + hdd_ctx->ptp_clock = ptp_clock_register(&hdd_ctx->ptp_cinfo, + hdd_ctx->parent_dev); +} + +static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx) +{ + hdd_ctx->ptp_cinfo.gettime64 = NULL; + + if (hdd_ctx->ptp_clock) { + ptp_clock_unregister(hdd_ctx->ptp_clock); + hdd_ctx->ptp_clock = NULL; + } +} + +#endif +#else + +static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx) +{ +} + +static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx) +{ +} +#endif /* WLAN_FEATURE_TSF_PTP */ + /** * hdd_get_tsf_cb() - handle tsf callback * @pcb_cxt: pointer to the hdd_contex @@ -1516,6 +1824,7 @@ int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf) adapter->cur_tsf_sync_soc_time = qdf_log_timestamp_to_usecs(tsf_sync_soc_time) * NSEC_PER_USEC; + complete(&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", @@ -1550,7 +1859,7 @@ static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy, struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1]; int status, ret; struct sk_buff *reply_skb; - uint32_t tsf_op_resp[3], tsf_cmd; + uint32_t tsf_op_resp[3] = {0}, tsf_cmd; hdd_enter_dev(wdev->netdev); @@ -1699,6 +2008,8 @@ void wlan_hdd_tsf_init(struct hdd_context *hdd_ctx) if (wlan_hdd_tsf_plus_init(hdd_ctx) != HDD_TSF_OP_SUCC) goto fail; + wlan_hdd_phc_init(hdd_ctx); + return; fail: @@ -1713,6 +2024,7 @@ void wlan_hdd_tsf_deinit(struct hdd_context *hdd_ctx) if (!qdf_atomic_read(&hdd_ctx->tsf_ready_flag)) return; + wlan_hdd_phc_deinit(hdd_ctx); wlan_hdd_tsf_plus_deinit(hdd_ctx); qdf_atomic_set(&hdd_ctx->tsf_ready_flag, 0); qdf_atomic_set(&hdd_ctx->cap_tsf_flag, 0);