diff --git a/Kbuild b/Kbuild index 5940ce8ad0..a0fcd88f66 100644 --- a/Kbuild +++ b/Kbuild @@ -1059,7 +1059,8 @@ FTM_TIME_SYNC_INC := -I$(WLAN_ROOT)/$(FTM_TIME_SYNC_DIR)/core/inc \ ifeq ($(CONFIG_FEATURE_WLAN_TIME_SYNC_FTM), y) FTM_TIME_SYNC_OBJS := $(FTM_TIME_SYNC_DIR)/core/src/ftm_time_sync_main.o \ - $(FTM_TIME_SYNC_DIR)/dispatcher/src/ftm_time_sync_ucfg_api.o + $(FTM_TIME_SYNC_DIR)/dispatcher/src/ftm_time_sync_ucfg_api.o \ + $(FTM_TIME_SYNC_DIR)/dispatcher/src/wlan_ftm_time_sync_tgt_api.o endif ########## CLD TARGET_IF ####### diff --git a/components/ftm_time_sync/core/inc/ftm_time_sync_main.h b/components/ftm_time_sync/core/inc/ftm_time_sync_main.h index a7d5a8df29..c78065ff52 100644 --- a/components/ftm_time_sync/core/inc/ftm_time_sync_main.h +++ b/components/ftm_time_sync/core/inc/ftm_time_sync_main.h @@ -26,6 +26,7 @@ #define _FTM_TIME_SYNC_MAIN_H_ #include +#include #include "ftm_time_sync_priv.h" #include "ftm_time_sync_objmgr.h" diff --git a/components/ftm_time_sync/core/inc/ftm_time_sync_priv.h b/components/ftm_time_sync/core/inc/ftm_time_sync_priv.h index 9619cd28fc..64e4de476a 100644 --- a/components/ftm_time_sync/core/inc/ftm_time_sync_priv.h +++ b/components/ftm_time_sync/core/inc/ftm_time_sync_priv.h @@ -61,12 +61,24 @@ struct ftm_timesync_priv { * @ftm_ts_priv: time sync private struct * @rx_ops: rx operations for ftm time sync * @tx_ops: tx operations for ftm time sync + * @ftm_time_sync_mutex: mutex to access ftm time sync priv members + * @ftm_time_sync_work: work to capture audio qtime and send it to FW + * @time_sync_interval: interval between two qtime capture + * @num_qtime_pair: number of qmaster and qslave pair derived + * @num_reads: number of times the qtime to be captured + * @valid: send qtime to FW only if this is true */ struct ftm_timesync_vdev_priv { struct wlan_objmgr_vdev *vdev; struct ftm_timesync_priv ftm_ts_priv; struct wlan_ftm_timesync_rx_ops rx_ops; struct wlan_ftm_timesync_tx_ops tx_ops; + qdf_mutex_t ftm_time_sync_mutex; + struct qdf_delayed_work ftm_time_sync_work; + uint32_t time_sync_interval; + int num_qtime_pair; + int num_reads; + bool valid; }; #endif /* End of _FTM_TIME_SYNC_PRIV_STRUCT_H_ */ diff --git a/components/ftm_time_sync/core/src/ftm_time_sync_main.c b/components/ftm_time_sync/core/src/ftm_time_sync_main.c index e16139e655..0998b36b1a 100644 --- a/components/ftm_time_sync/core/src/ftm_time_sync_main.c +++ b/components/ftm_time_sync/core/src/ftm_time_sync_main.c @@ -20,11 +20,63 @@ */ #include "ftm_time_sync_main.h" +#include "target_if_ftm_time_sync.h" +#include + +static void ftm_time_sync_work_handler(void *arg) +{ + struct ftm_timesync_vdev_priv *vdev_priv = arg; + struct wlan_objmgr_psoc *psoc; + qdf_device_t qdf_dev; + QDF_STATUS status; + uint8_t vdev_id; + uint64_t lpass_ts; + + if (!vdev_priv) { + ftm_time_sync_err("ftm vdev priv is Null"); + return; + } + + psoc = wlan_vdev_get_psoc(vdev_priv->vdev); + if (!psoc) { + ftm_time_sync_err("Failed to get psoc"); + return; + } + + vdev_id = wlan_vdev_get_id(vdev_priv->vdev); + + qdf_dev = wlan_psoc_get_qdf_dev(psoc); + pld_get_audio_wlan_timestamp(qdf_dev->dev, PLD_TRIGGER_NEGATIVE_EDGE, + &lpass_ts); + + qdf_mutex_acquire(&vdev_priv->ftm_time_sync_mutex); + + if (vdev_priv->num_reads) { + vdev_priv->num_reads--; + qdf_mutex_release(&vdev_priv->ftm_time_sync_mutex); + qdf_delayed_work_start(&vdev_priv->ftm_time_sync_work, + vdev_priv->time_sync_interval); + } else { + qdf_mutex_release(&vdev_priv->ftm_time_sync_mutex); + } + + if (vdev_priv->valid) { + status = vdev_priv->tx_ops.ftm_time_sync_send_qtime( + psoc, vdev_id, lpass_ts); + if (status != QDF_STATUS_SUCCESS) + ftm_time_sync_err("send_ftm_time_sync_qtime failed %d", + status); + vdev_priv->valid = false; + } else { + vdev_priv->valid = true; + } +} QDF_STATUS ftm_timesync_vdev_create_notification(struct wlan_objmgr_vdev *vdev, void *arg) { struct ftm_timesync_vdev_priv *vdev_priv; + struct wlan_objmgr_psoc *psoc; QDF_STATUS status; vdev_priv = qdf_mem_malloc(sizeof(*vdev_priv)); @@ -41,7 +93,29 @@ ftm_timesync_vdev_create_notification(struct wlan_objmgr_vdev *vdev, void *arg) goto free_vdev_priv; } + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + ftm_time_sync_err("Failed to get psoc"); + return QDF_STATUS_E_INVAL; + } + vdev_priv->vdev = vdev; + status = qdf_delayed_work_create(&vdev_priv->ftm_time_sync_work, + ftm_time_sync_work_handler, vdev_priv); + if (QDF_IS_STATUS_ERROR(status)) { + ftm_time_sync_err("Failed to create ftm time sync work\n"); + goto free_vdev_priv; + } + + qdf_mutex_create(&vdev_priv->ftm_time_sync_mutex); + target_if_ftm_time_sync_register_tx_ops(&vdev_priv->tx_ops); + target_if_ftm_time_sync_register_rx_ops(&vdev_priv->rx_ops); + + vdev_priv->rx_ops.ftm_timesync_register_start_stop(psoc); + vdev_priv->rx_ops.ftm_timesync_regiser_master_slave_offset(psoc); + + vdev_priv->valid = true; + goto exit; free_vdev_priv: @@ -51,6 +125,22 @@ exit: return status; } +static QDF_STATUS +ftm_time_sync_deregister_wmi_events(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + ftm_time_sync_err("Failed to get psoc"); + return QDF_STATUS_E_INVAL; + } + + status = target_if_ftm_time_sync_unregister_ev_handlers(psoc); + return status; +} + QDF_STATUS ftm_timesync_vdev_destroy_notification(struct wlan_objmgr_vdev *vdev, void *arg) { @@ -63,6 +153,11 @@ ftm_timesync_vdev_destroy_notification(struct wlan_objmgr_vdev *vdev, void *arg) goto exit; } + qdf_mutex_destroy(&vdev_priv->ftm_time_sync_mutex); + qdf_delayed_work_destroy(&vdev_priv->ftm_time_sync_work); + + ftm_time_sync_deregister_wmi_events(vdev); + status = wlan_objmgr_vdev_component_obj_detach( vdev, WLAN_UMAC_COMP_FTM_TIME_SYNC, (void *)vdev_priv); diff --git a/components/ftm_time_sync/dispatcher/inc/wlan_ftm_time_sync_tgt_api.h b/components/ftm_time_sync/dispatcher/inc/wlan_ftm_time_sync_tgt_api.h new file mode 100644 index 0000000000..17f4c57074 --- /dev/null +++ b/components/ftm_time_sync/dispatcher/inc/wlan_ftm_time_sync_tgt_api.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020, 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 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. + */ + +/** + * DOC: Declares public API for ftm time sync to interact with target/WMI + */ + +#ifndef _WLAN_FTM_TIME_SYNC_TGT_API_H_ +#define _WLAN_FTM_TIME_SYNC_TGT_API_H_ + +#include + +struct wlan_objmgr_psoc; +struct ftm_time_sync_start_stop_params; +struct ftm_time_sync_offset; + +/** + * tgt_ftm_ts_start_stop_evt() - receive start/stop ftm event + * from target if + * @psoc: objmgr psoc object + * @param: start/stop parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_ftm_ts_start_stop_evt(struct wlan_objmgr_psoc *psoc, + struct ftm_time_sync_start_stop_params *param); + +/** + * tgt_ftm_ts_offset_evt() - receive offset ftm event from target if + * @psoc: objmgr psoc object + * @param: offset parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_ftm_ts_offset_evt(struct wlan_objmgr_psoc *psoc, + struct ftm_time_sync_offset *param); + +#endif /*_WLAN_FTM_TIME_SYNC_TGT_API_H_ */ diff --git a/components/ftm_time_sync/dispatcher/src/wlan_ftm_time_sync_tgt_api.c b/components/ftm_time_sync/dispatcher/src/wlan_ftm_time_sync_tgt_api.c new file mode 100644 index 0000000000..ac574c4484 --- /dev/null +++ b/components/ftm_time_sync/dispatcher/src/wlan_ftm_time_sync_tgt_api.c @@ -0,0 +1,103 @@ +/* + *Copyright (c) 2020, 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 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. + */ + +/** + * DOC: Implements public API for ftm time sync to interact with target/WMI + */ + +#include "wlan_ftm_time_sync_tgt_api.h" +#include "ftm_time_sync_main.h" +#include "wlan_ftm_time_sync_public_struct.h" +#include + +QDF_STATUS +tgt_ftm_ts_start_stop_evt(struct wlan_objmgr_psoc *psoc, + struct ftm_time_sync_start_stop_params *param) +{ + struct wlan_objmgr_vdev *vdev; + struct ftm_timesync_vdev_priv *vdev_priv; + uint8_t vdev_id; + + vdev_id = param->vdev_id; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + FTM_TIME_SYNC_ID); + if (!vdev) { + ftm_time_sync_err("failed to get vdev"); + return QDF_STATUS_E_FAILURE; + } + + vdev_priv = ftm_timesync_vdev_get_priv(vdev); + + qdf_mutex_acquire(&vdev_priv->ftm_time_sync_mutex); + + vdev_priv->time_sync_interval = param->timer_interval; + vdev_priv->num_reads = param->num_reads * 2; + + if (vdev_priv->num_reads && vdev_priv->time_sync_interval) { + vdev_priv->num_reads--; + qdf_mutex_release(&vdev_priv->ftm_time_sync_mutex); + qdf_delayed_work_start(&vdev_priv->ftm_time_sync_work, + param->timer_interval); + } else if (vdev_priv->time_sync_interval == 0) { + qdf_mutex_release(&vdev_priv->ftm_time_sync_mutex); + vdev_priv->ftm_ts_priv.qtime_ref = param->qtime; + vdev_priv->ftm_ts_priv.mac_ref = param->mac_time; + qdf_delayed_work_stop_sync(&vdev_priv->ftm_time_sync_work); + } else { + qdf_mutex_release(&vdev_priv->ftm_time_sync_mutex); + } + + ftm_timesync_vdev_put_ref(vdev); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tgt_ftm_ts_offset_evt(struct wlan_objmgr_psoc *psoc, + struct ftm_time_sync_offset *param) +{ + struct ftm_timesync_vdev_priv *vdev_priv; + struct wlan_objmgr_vdev *vdev; + uint8_t vdev_id; + int iter; + + vdev_id = param->vdev_id; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + FTM_TIME_SYNC_ID); + if (!vdev) { + ftm_time_sync_err("failed to get vdev"); + return QDF_STATUS_E_FAILURE; + } + + vdev_priv = ftm_timesync_vdev_get_priv(vdev); + + vdev_priv->num_qtime_pair = param->num_qtime < + FTM_TIME_SYNC_QTIME_PAIR_MAX ? param->num_qtime : + FTM_TIME_SYNC_QTIME_PAIR_MAX; + + for (iter = 0; iter < vdev_priv->num_qtime_pair; iter++) { + vdev_priv->ftm_ts_priv.time_pair[iter].qtime_master = + param->pairs[iter].qtime_master; + vdev_priv->ftm_ts_priv.time_pair[iter].qtime_slave = + param->pairs[iter].qtime_slave; + } + + ftm_timesync_vdev_put_ref(vdev); + + return QDF_STATUS_SUCCESS; +} + diff --git a/components/target_if/ftm_time_sync/inc/target_if_ftm_time_sync.h b/components/target_if/ftm_time_sync/inc/target_if_ftm_time_sync.h index 566577e4af..99fa92f121 100644 --- a/components/target_if/ftm_time_sync/inc/target_if_ftm_time_sync.h +++ b/components/target_if/ftm_time_sync/inc/target_if_ftm_time_sync.h @@ -46,4 +46,14 @@ void target_if_ftm_time_sync_register_rx_ops(struct wlan_ftm_timesync_rx_ops */ void target_if_ftm_time_sync_register_tx_ops(struct wlan_ftm_timesync_tx_ops *tx_ops); + +/** + * target_if_ftm_time_sync_unregister_ev_handlers() - Unregister wmi events + * handlers + * @psoc: psoc context + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_ftm_time_sync_unregister_ev_handlers(struct wlan_objmgr_psoc *psoc); #endif /*_TARGET_IF_FTM_TIME_SYNC_H_ */ diff --git a/components/target_if/ftm_time_sync/src/target_if_ftm_time_sync.c b/components/target_if/ftm_time_sync/src/target_if_ftm_time_sync.c index 54b82943ce..c253344908 100644 --- a/components/target_if/ftm_time_sync/src/target_if_ftm_time_sync.c +++ b/components/target_if/ftm_time_sync/src/target_if_ftm_time_sync.c @@ -23,6 +23,7 @@ #include "target_if.h" #include "target_if_ftm_time_sync.h" #include "wlan_ftm_time_sync_public_struct.h" +#include "wlan_ftm_time_sync_tgt_api.h" #include static QDF_STATUS @@ -84,6 +85,8 @@ target_if_time_sync_ftm_start_stop_event_handler(ol_scn_t scn_handle, return -EINVAL; } + tgt_ftm_ts_start_stop_evt(psoc, ¶m); + return 0; } @@ -99,9 +102,10 @@ target_if_ftm_time_sync_start_stop_event(struct wlan_objmgr_psoc *psoc) return QDF_STATUS_E_INVAL; } - status = wmi_unified_register_event( + status = wmi_unified_register_event_handler( wmi_handle, wmi_wlan_time_sync_ftm_start_stop_event_id, - target_if_time_sync_ftm_start_stop_event_handler); + target_if_time_sync_ftm_start_stop_event_handler, + WMI_RX_SERIALIZER_CTX); if (status) { target_if_err("Ftm timesync start stop event register failed"); return QDF_STATUS_E_FAILURE; @@ -142,6 +146,8 @@ target_if_time_sync_master_slave_offset_event_handler(ol_scn_t scn_handle, return -EINVAL; } + tgt_ftm_ts_offset_evt(psoc, ¶m); + return 0; } @@ -157,10 +163,11 @@ target_if_ftm_time_sync_master_slave_offset(struct wlan_objmgr_psoc *psoc) return QDF_STATUS_E_INVAL; } - status = wmi_unified_register_event( + status = wmi_unified_register_event_handler( wmi_handle, wmi_wlan_time_sync_q_master_slave_offset_eventid, - target_if_time_sync_master_slave_offset_event_handler); + target_if_time_sync_master_slave_offset_event_handler, + WMI_RX_SERIALIZER_CTX); if (status) { target_if_err("Ftm timesync offset event register failed"); return QDF_STATUS_E_FAILURE; @@ -169,6 +176,40 @@ target_if_ftm_time_sync_master_slave_offset(struct wlan_objmgr_psoc *psoc) return status; } +QDF_STATUS +target_if_ftm_time_sync_unregister_ev_handlers(struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle; + int ret, status = 0; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + ret = wmi_unified_unregister_event( + wmi_handle, + wmi_wlan_time_sync_ftm_start_stop_event_id); + if (ret) { + target_if_err("failed to unregister time sync start/stop evt"); + status = ret; + } + + ret = wmi_unified_unregister_event( + wmi_handle, + wmi_wlan_time_sync_q_master_slave_offset_eventid); + if (ret) { + target_if_err("failed to unregister time sync offset evt"); + status = ret; + } + + if (status) + return QDF_STATUS_E_FAILURE; + else + return QDF_STATUS_SUCCESS; +} + void target_if_ftm_time_sync_register_rx_ops(struct wlan_ftm_timesync_rx_ops *rx_ops) {