diff --git a/Kbuild b/Kbuild index 87559801e0..d9bcd08796 100644 --- a/Kbuild +++ b/Kbuild @@ -929,12 +929,25 @@ IPA_OBJS := $(IPA_DIR)/dispatcher/src/wlan_ipa_ucfg_api.o \ endif ######## FWOL ########## -FWOL_DIR := components/fw_offload -FWOL_INC := -I$(WLAN_ROOT)/$(FWOL_DIR)/core/inc \ - -I$(WLAN_ROOT)/$(FWOL_DIR)/dispatcher/inc +FWOL_CORE_INC := components/fw_offload/core/inc +FWOL_CORE_SRC := components/fw_offload/core/src +FWOL_DISPATCHER_INC := components/fw_offload/dispatcher/inc +FWOL_DISPATCHER_SRC := components/fw_offload/dispatcher/src +FWOL_TARGET_IF_INC := components/target_if/fw_offload/inc +FWOL_TARGET_IF_SRC := components/target_if/fw_offload/src +FWOL_OS_IF_INC := os_if/fw_offload/inc +FWOL_OS_IF_SRC := os_if/fw_offload/src -FWOL_OBJS := $(FWOL_DIR)/core/src/wlan_fw_offload_main.o \ - $(FWOL_DIR)/dispatcher/src/wlan_fwol_ucfg_api.o +FWOL_INC := -I$(WLAN_ROOT)/$(FWOL_CORE_INC) \ + -I$(WLAN_ROOT)/$(FWOL_DISPATCHER_INC) \ + -I$(WLAN_ROOT)/$(FWOL_TARGET_IF_INC) \ + -I$(WLAN_ROOT)/$(FWOL_OS_IF_INC) + +FWOL_OBJS := $(FWOL_CORE_SRC)/wlan_fw_offload_main.o \ + $(FWOL_DISPATCHER_SRC)/wlan_fwol_ucfg_api.o \ + $(FWOL_DISPATCHER_SRC)/wlan_fwol_tgt_api.o \ + $(FWOL_TARGET_IF_SRC)/target_if_fwol.o \ + $(FWOL_OS_IF_SRC)/os_if_fwol.o ######## SM FRAMEWORK ############## UMAC_SM_DIR := umac/cmn_services/sm_engine @@ -1244,6 +1257,11 @@ WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_bcn_api.o WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_bcn_tlv.o endif +ifeq ($(CONFIG_WLAN_FW_OFFLOAD), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_fwol_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_fwol_tlv.o +endif + ########### FWLOG ########### FWLOG_DIR := $(WLAN_COMMON_ROOT)/utils/fwlog @@ -1980,7 +1998,9 @@ OBJS += $(PLD_OBJS) OBJS += $(UMAC_SM_OBJS) OBJS += $(UMAC_MLME_OBJS) OBJS += $(MLME_OBJS) +ifeq ($(CONFIG_WLAN_FW_OFFLOAD), y) OBJS += $(FWOL_OBJS) +endif OBJS += $(BLM_OBJS) ifeq ($(CONFIG_WLAN_FEATURE_DSRC), y) @@ -2080,6 +2100,8 @@ cppflags-$(CONFIG_FEATURE_MEMDUMP_ENABLE) += -DWLAN_FEATURE_MEMDUMP_ENABLE cppflags-$(CONFIG_FEATURE_FW_LOG_PARSING) += -DFEATURE_FW_LOG_PARSING cppflags-$(CONFIG_FEATURE_OEM_DATA) += -DFEATURE_OEM_DATA cppflags-$(CONFIG_FEATURE_MOTION_DETECTION) += -DWLAN_FEATURE_MOTION_DETECTION +cppflags-$(CONFIG_WLAN_FW_OFFLOAD) += -DWLAN_FW_OFFLOAD +cppflags-$(CONFIG_WLAN_FEATURE_ELNA) += -DWLAN_FEATURE_ELNA cppflags-$(CONFIG_PLD_SDIO_CNSS_FLAG) += -DCONFIG_PLD_SDIO_CNSS cppflags-$(CONFIG_PLD_PCIE_CNSS_FLAG) += -DCONFIG_PLD_PCIE_CNSS 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 365b53d542..0386ba8435 100644 --- a/components/fw_offload/core/inc/wlan_fw_offload_main.h +++ b/components/fw_offload/core/inc/wlan_fw_offload_main.h @@ -26,8 +26,10 @@ #include #include #include +#include #include "cfg_ucfg_api.h" +#include "wlan_fwol_public_structs.h" #define fwol_alert(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_FWOL, params) #define fwol_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_FWOL, params) @@ -46,6 +48,17 @@ #define fwol_nofl_debug(params...) \ QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_FWOL, params) +/** + * enum wlan_fwol_southbound_event - fw offload south bound event type + * @WLAN_FWOL_EVT_GET_ELNA_BYPASS_RESPONSE: get eLNA bypass response + */ +enum wlan_fwol_southbound_event { + WLAN_FWOL_EVT_INVALID = 0, + WLAN_FWOL_EVT_GET_ELNA_BYPASS_RESPONSE, + WLAN_FWOL_EVT_LAST, + WLAN_FWOL_EVT_MAX = WLAN_FWOL_EVT_LAST - 1 +}; + /** * struct wlan_fwol_three_antenna_btc - Three antenna BTC config items * @btc_mode: Config BTC mode @@ -244,9 +257,31 @@ struct wlan_fwol_cfg { /** * struct wlan_fwol_psoc_obj - FW offload psoc priv object * @cfg: cfg items + * @cbs: callback functions + * @tx_ops: tx operations for target interface + * @rx_ops: rx operations for target interface */ struct wlan_fwol_psoc_obj { struct wlan_fwol_cfg cfg; + struct wlan_fwol_callbacks cbs; + struct wlan_fwol_tx_ops tx_ops; + struct wlan_fwol_rx_ops rx_ops; +}; + +/** + * struct wlan_fwol_rx_event - event from south bound + * @psoc: psoc handle + * @event_id: event ID + * @get_elna_bypass_response: get eLNA bypass response + */ +struct wlan_fwol_rx_event { + struct wlan_objmgr_psoc *psoc; + enum wlan_fwol_southbound_event event_id; + union { +#ifdef WLAN_FEATURE_ELNA + struct get_elna_bypass_response get_elna_bypass_response; +#endif + }; }; /** @@ -277,6 +312,22 @@ QDF_STATUS fwol_cfg_on_psoc_enable(struct wlan_objmgr_psoc *psoc); */ QDF_STATUS fwol_cfg_on_psoc_disable(struct wlan_objmgr_psoc *psoc); +/** + * fwol_process_event() - API to process event from south bound + * @msg: south bound message + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS fwol_process_event(struct scheduler_msg *msg); + +/* + * fwol_release_rx_event() - Release fw offload RX event + * @event: fw offload RX event + * + * Return: none + */ +void fwol_release_rx_event(struct wlan_fwol_rx_event *event); + /* * fwol_init_neighbor_report_cfg() - Populate default neighbor report CFG values * @psoc: pointer to the psoc object 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 1e1f79c3db..16fcd33790 100644 --- a/components/fw_offload/core/src/wlan_fw_offload_main.c +++ b/components/fw_offload/core/src/wlan_fw_offload_main.c @@ -543,3 +543,97 @@ QDF_STATUS fwol_cfg_on_psoc_disable(struct wlan_objmgr_psoc *psoc) /* Clear the CFG structure */ return QDF_STATUS_SUCCESS; } + +#ifdef WLAN_FEATURE_ELNA +/** + * fwol_process_get_elna_bypass_resp() - Process get eLNA bypass response + * @event: response event + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +fwol_process_get_elna_bypass_resp(struct wlan_fwol_rx_event *event) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_psoc *psoc; + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_callbacks *cbs; + struct get_elna_bypass_response *resp; + + if (!event) { + fwol_err("Event buffer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + psoc = event->psoc; + if (!psoc) { + fwol_err("psoc is NULL"); + return QDF_STATUS_E_INVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + + cbs = &fwol_obj->cbs; + if (cbs->get_elna_bypass_callback) { + resp = &event->get_elna_bypass_response; + cbs->get_elna_bypass_callback(cbs->get_elna_bypass_context, + resp); + } else { + fwol_err("NULL pointer for callback"); + status = QDF_STATUS_E_IO; + } + + return status; +} +#else +static QDF_STATUS +fwol_process_get_elna_bypass_resp(struct wlan_fwol_rx_event *event) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_ELNA */ + +QDF_STATUS fwol_process_event(struct scheduler_msg *msg) +{ + QDF_STATUS status; + struct wlan_fwol_rx_event *event; + + fwol_debug("msg type %d", msg->type); + + if (!(msg->bodyptr)) { + fwol_err("Invalid message body"); + return QDF_STATUS_E_INVAL; + } + + event = msg->bodyptr; + msg->bodyptr = NULL; + + switch (msg->type) { + case WLAN_FWOL_EVT_GET_ELNA_BYPASS_RESPONSE: + status = fwol_process_get_elna_bypass_resp(event); + break; + default: + status = QDF_STATUS_E_INVAL; + break; + } + + fwol_release_rx_event(event); + + return status; +} + +void fwol_release_rx_event(struct wlan_fwol_rx_event *event) +{ + if (!event) { + fwol_err("event is NULL"); + return; + } + + if (event->psoc) + wlan_objmgr_psoc_release_ref(event->psoc, WLAN_FWOL_SB_ID); + qdf_mem_free(event); +} diff --git a/components/fw_offload/dispatcher/inc/cfg_fwol.h b/components/fw_offload/dispatcher/inc/cfg_fwol.h index 3e39ac484d..245d3d75c9 100644 --- a/components/fw_offload/dispatcher/inc/cfg_fwol.h +++ b/components/fw_offload/dispatcher/inc/cfg_fwol.h @@ -29,6 +29,7 @@ #include "cfg_neighbor_roam.h" #include "cfg_adaptive_dwelltime.h" +#ifdef WLAN_FW_OFFLOAD #define CFG_FWOL_ALL \ CFG_ADAPTIVE_DWELLTIME_ALL \ CFG_11K_ALL \ @@ -36,6 +37,9 @@ CFG_FWOL_GENERIC_ALL \ CFG_IE_WHITELIST \ CFG_THERMAL_TEMP_ALL +#else +#define CFG_FWOL_ALL +#endif #endif /* __CFG_FWOL_H */ diff --git a/components/fw_offload/dispatcher/inc/wlan_fwol_public_structs.h b/components/fw_offload/dispatcher/inc/wlan_fwol_public_structs.h new file mode 100644 index 0000000000..ea0863b9e4 --- /dev/null +++ b/components/fw_offload/dispatcher/inc/wlan_fwol_public_structs.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 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 + * 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: contains fw offload structure definations + */ + +#ifndef _WLAN_FWOL_PUBLIC_STRUCTS_H_ +#define _WLAN_FWOL_PUBLIC_STRUCTS_H_ + +#include "wlan_objmgr_psoc_obj.h" + +#ifdef WLAN_FEATURE_ELNA +/** + * struct set_elna_bypass_request - set eLNA bypass request + * @vdev_id: vdev id + * @en_dis: 0 - disable eLNA bypass + * 1 - enable eLNA bypass + */ +struct set_elna_bypass_request { + uint8_t vdev_id; + uint8_t en_dis; +}; + +/** + * struct get_elna_bypass_request - get eLNA bypass request + * @vdev_id: vdev id + */ +struct get_elna_bypass_request { + uint8_t vdev_id; +}; + +/** + * struct get_elna_bypass_response - get eLNA bypass response + * @vdev_id: vdev id + * @en_dis: 0 - disable eLNA bypass + * 1 - enable eLNA bypass + */ +struct get_elna_bypass_response { + uint8_t vdev_id; + uint8_t en_dis; +}; +#endif + +/** + * struct wlan_fwol_callbacks - fw offload callbacks + * @get_elna_bypass_callback: callback for get eLNA bypass + * @get_elna_bypass_context: context for get eLNA bypass + */ +struct wlan_fwol_callbacks { +#ifdef WLAN_FEATURE_ELNA + void (*get_elna_bypass_callback)(void *context, + struct get_elna_bypass_response *response); + void *get_elna_bypass_context; +#endif +}; + +/** + * struct wlan_fwol_tx_ops - structure of tx func pointers + * @set_elna_bypass: set eLNA bypass + * @get_elna_bypass: get eLNA bypass + * @reg_evt_handler: register event handler + * @unreg_evt_handler: unregister event handler + */ +struct wlan_fwol_tx_ops { +#ifdef WLAN_FEATURE_ELNA + QDF_STATUS (*set_elna_bypass)(struct wlan_objmgr_psoc *psoc, + struct set_elna_bypass_request *req); + QDF_STATUS (*get_elna_bypass)(struct wlan_objmgr_psoc *psoc, + struct get_elna_bypass_request *req); +#endif + QDF_STATUS (*reg_evt_handler)(struct wlan_objmgr_psoc *psoc, + void *arg); + QDF_STATUS (*unreg_evt_handler)(struct wlan_objmgr_psoc *psoc, + void *arg); +}; + +/** + * struct wlan_fwol_rx_ops - structure of rx func pointers + * @get_elna_bypass_resp: get eLNA bypass response + */ +struct wlan_fwol_rx_ops { +#ifdef WLAN_FEATURE_ELNA + QDF_STATUS (*get_elna_bypass_resp)(struct wlan_objmgr_psoc *psoc, + struct get_elna_bypass_response *resp); +#endif +}; + +#endif /* _WLAN_FWOL_PUBLIC_STRUCTS_H_ */ + diff --git a/components/fw_offload/dispatcher/inc/wlan_fwol_tgt_api.h b/components/fw_offload/dispatcher/inc/wlan_fwol_tgt_api.h new file mode 100644 index 0000000000..4bf88b213e --- /dev/null +++ b/components/fw_offload/dispatcher/inc/wlan_fwol_tgt_api.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 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 + * 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: fw offload south bound interface declaration + */ +#ifndef _WLAN_FWOL_TGT_API_H +#define _WLAN_FWOL_TGT_API_H + +#include "wlan_fwol_public_structs.h" + +/** + * tgt_fwol_register_ev_handler() - register south bound event handler + * @psoc: psoc handle + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS tgt_fwol_register_ev_handler(struct wlan_objmgr_psoc *psoc); + +/** + * tgt_fwol_unregister_ev_handler() - unregister south bound event handler + * @psoc: psoc handle + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS tgt_fwol_unregister_ev_handler(struct wlan_objmgr_psoc *psoc); + +/** + * tgt_fwol_register_rx_ops() - register fw offload rx operations + * @rx_ops: fps to rx operations + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS tgt_fwol_register_rx_ops(struct wlan_fwol_rx_ops *rx_ops); +#endif /* _WLAN_FWOL_TGT_API_H */ 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 bccd02a08c..c835073597 100644 --- a/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h +++ b/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h @@ -26,7 +26,9 @@ #include #include #include "wlan_fw_offload_main.h" +#include "wlan_fwol_public_structs.h" +#ifdef WLAN_FW_OFFLOAD /** * ucfg_fwol_psoc_open() - FWOL component Open * @psoc: pointer to psoc object @@ -523,4 +525,321 @@ ucfg_fwol_set_adaptive_dwelltime_config( { return fwol_set_adaptive_dwelltime_config(dwelltime_params); } + +#ifdef WLAN_FEATURE_ELNA +/** + * ucfg_fwol_set_elna_bypass() - send set eLNA bypass request + * @vdev: vdev handle + * @req: set eLNA bypass request + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_fwol_set_elna_bypass(struct wlan_objmgr_vdev *vdev, + struct set_elna_bypass_request *req); + +/** + * ucfg_fwol_get_elna_bypass() - send get eLNA bypass request + * @vdev: vdev handle + * @req: get eLNA bypass request + * @callback: get eLNA bypass response callback + * @context: request manager context + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_fwol_get_elna_bypass(struct wlan_objmgr_vdev *vdev, + struct get_elna_bypass_request *req, + void (*callback)(void *context, + struct get_elna_bypass_response *response), + void *context); +#endif /* WLAN_FEATURE_ELNA */ +#else +static inline QDF_STATUS ucfg_fwol_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void ucfg_fwol_psoc_close(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline QDF_STATUS ucfg_fwol_init(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void ucfg_fwol_deinit(void) +{ +} + +static inline QDF_STATUS +ucfg_fwol_get_coex_config_params(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_coex_config *coex_config) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_thermal_temp(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_thermal_temp *thermal_temp) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_neighbor_report_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_neighbor_report_cfg + *fwol_neighbor_report_cfg) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_is_neighbor_report_req_supported(struct wlan_objmgr_psoc *psoc, + bool *neighbor_report_req) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_ie_whitelist(struct wlan_objmgr_psoc *psoc, bool *ie_whitelist) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_set_ie_whitelist(struct wlan_objmgr_psoc *psoc, bool ie_whitelist) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_all_whitelist_params(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_ie_whitelist *whitelist) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_ani_enabled(struct wlan_objmgr_psoc *psoc, + bool *ani_enabled) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_enable_rts_sifsbursting(struct wlan_objmgr_psoc *psoc, + bool *enable_rts_sifsbursting) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_max_mpdus_inampdu(struct wlan_objmgr_psoc *psoc, + uint8_t *max_mpdus_inampdu) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_arp_ac_category(struct wlan_objmgr_psoc *psoc, + uint32_t *arp_ac_category) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_enable_phy_reg_retention(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_phy_reg_retention) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_upper_brssi_thresh(struct wlan_objmgr_psoc *psoc, + uint16_t *upper_brssi_thresh) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_lower_brssi_thresh(struct wlan_objmgr_psoc *psoc, + uint16_t *lower_brssi_thresh) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_enable_dtim_1chrx(struct wlan_objmgr_psoc *psoc, + bool *enable_dtim_1chrx) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_alternative_chainmask_enabled(struct wlan_objmgr_psoc *psoc, + bool *alternative_chainmask_enabled) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_smart_chainmask_enabled(struct wlan_objmgr_psoc *psoc, + bool *smart_chainmask_enabled) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_rts_profile(struct wlan_objmgr_psoc *psoc, + uint16_t *get_rts_profile) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_enable_fw_log_level(struct wlan_objmgr_psoc *psoc, + uint16_t *enable_fw_log_level) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_enable_fw_log_type(struct wlan_objmgr_psoc *psoc, + uint16_t *enable_fw_log_type) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_enable_fw_module_log_level( + struct wlan_objmgr_psoc *psoc, + uint8_t **enable_fw_module_log_level, + uint8_t *enable_fw_module_log_level_num) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_tsf_gpio_pin(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_gpio_pin) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_tsf_ptp_options(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_ptp_options) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_lprx_enable(struct wlan_objmgr_psoc *psoc, + bool *lprx_enable) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline bool ucfg_fwol_get_sae_enable(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline bool ucfg_fwol_get_gcmp_enable(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline QDF_STATUS +ucfg_fwol_get_enable_tx_sch_delay(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_tx_sch_delay) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_enable_secondary_rate(struct wlan_objmgr_psoc *psoc, + uint32_t *enable_secondary_rate) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_all_adaptive_dwelltime_params( + struct wlan_objmgr_psoc *psoc, + struct adaptive_dwelltime_params *dwelltime_params) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_adaptive_dwell_mode_enabled(struct wlan_objmgr_psoc *psoc, + bool *adaptive_dwell_mode_enabled) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_global_adapt_dwelltime_mode(struct wlan_objmgr_psoc *psoc, + uint8_t *global_adapt_dwelltime_mode) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_adapt_dwell_lpf_weight(struct wlan_objmgr_psoc *psoc, + uint8_t *adapt_dwell_lpf_weight) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_adapt_dwell_passive_mon_intval( + struct wlan_objmgr_psoc *psoc, + uint8_t *adapt_dwell_passive_mon_intval) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_adapt_dwell_wifi_act_threshold( + struct wlan_objmgr_psoc *psoc, + uint8_t *adapt_dwell_wifi_act_threshold) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_init_adapt_dwelltime_in_cfg( + struct wlan_objmgr_psoc *psoc, + struct adaptive_dwelltime_params *dwelltime_params) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_set_adaptive_dwelltime_config( + struct adaptive_dwelltime_params *dwelltime_params) +{ + return QDF_STATUS_E_FAILURE; +} + +#ifdef FEATURE_WLAN_RA_FILTERING +static inline QDF_STATUS +ucfg_fwol_set_is_rate_limit_enabled(struct wlan_objmgr_psoc *psoc, + bool is_rate_limit_enabled) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_is_rate_limit_enabled(struct wlan_objmgr_psoc *psoc, + bool *is_rate_limit_enabled) +{ + return QDF_STATUS_E_FAILURE; +} +#endif /* FEATURE_WLAN_RA_FILTERING */ + +#endif /* WLAN_FW_OFFLOAD */ + #endif /* _WLAN_FWOL_UCFG_API_H_ */ diff --git a/components/fw_offload/dispatcher/src/wlan_fwol_tgt_api.c b/components/fw_offload/dispatcher/src/wlan_fwol_tgt_api.c new file mode 100644 index 0000000000..8778fc6b8e --- /dev/null +++ b/components/fw_offload/dispatcher/src/wlan_fwol_tgt_api.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 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 + * 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: This file contains fw offload south bound interface definitions + */ + +#include "scheduler_api.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_global_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_fwol_public_structs.h" +#include "wlan_fwol_ucfg_api.h" +#include "wlan_fwol_tgt_api.h" +#include "wlan_fw_offload_main.h" + +QDF_STATUS tgt_fwol_register_ev_handler(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_tx_ops *tx_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!psoc) { + fwol_err("NULL psoc handle"); + return QDF_STATUS_E_INVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + + tx_ops = &fwol_obj->tx_ops; + if (tx_ops->reg_evt_handler) { + status = tx_ops->reg_evt_handler(psoc, NULL); + fwol_debug("reg_evt_handler, status:%d", status); + } else { + fwol_alert("No reg_evt_handler"); + } + + return status; +} + +QDF_STATUS tgt_fwol_unregister_ev_handler(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_tx_ops *tx_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!psoc) { + fwol_err("NNULL psoc handle"); + return QDF_STATUS_E_INVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + + tx_ops = &fwol_obj->tx_ops; + if (tx_ops->unreg_evt_handler) { + status = tx_ops->unreg_evt_handler(psoc, NULL); + fwol_debug("unreg_evt_handler, status:%d", status); + } else { + fwol_alert("No unreg_evt_handler"); + } + + return status; +} + +/** + * fwol_flush_callback() - fw offload message flush callback + * @msg: fw offload message + * + * Return: QDF_STATUS_SUCCESS on success. + */ +__attribute__((unused)) +static QDF_STATUS fwol_flush_callback(struct scheduler_msg *msg) +{ + struct wlan_fwol_rx_event *event; + + if (!msg) { + fwol_err("NULL pointer for eLNA message"); + return QDF_STATUS_E_INVAL; + } + + event = msg->bodyptr; + msg->bodyptr = NULL; + fwol_release_rx_event(event); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ELNA +/** + * tgt_fwol_get_elna_bypass_resp() - handler for get eLNA bypass response + * @psoc: psoc handle + * @resp: status for last channel config + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +tgt_fwol_get_elna_bypass_resp(struct wlan_objmgr_psoc *psoc, + struct get_elna_bypass_response *resp) +{ + QDF_STATUS status; + struct scheduler_msg msg = {0}; + struct wlan_fwol_rx_event *event; + + event = qdf_mem_malloc(sizeof(*event)); + if (!event) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_FWOL_SB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + fwol_err("Failed to get psoc ref"); + fwol_release_rx_event(event); + return status; + } + + event->psoc = psoc; + event->event_id = WLAN_FWOL_EVT_GET_ELNA_BYPASS_RESPONSE; + event->get_elna_bypass_response = *resp; + msg.type = WLAN_FWOL_EVT_GET_ELNA_BYPASS_RESPONSE; + msg.bodyptr = event; + msg.callback = fwol_process_event; + msg.flush_callback = fwol_flush_callback; + status = scheduler_post_message(QDF_MODULE_ID_FWOL, + QDF_MODULE_ID_FWOL, + QDF_MODULE_ID_TARGET_IF, &msg); + + if (QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_SUCCESS; + + fwol_err("failed to send WLAN_FWOL_GET_ELNA_BYPASS_RESPONSE msg"); + fwol_flush_callback(&msg); + + return status; +} + +static void tgt_fwol_register_elna_rx_ops(struct wlan_fwol_rx_ops *rx_ops) +{ + rx_ops->get_elna_bypass_resp = tgt_fwol_get_elna_bypass_resp; +} +#else +static void tgt_fwol_register_elna_rx_ops(struct wlan_fwol_rx_ops *rx_ops) +{ +} +#endif /* WLAN_FEATURE_ELNA */ + +QDF_STATUS tgt_fwol_register_rx_ops(struct wlan_fwol_rx_ops *rx_ops) +{ + tgt_fwol_register_elna_rx_ops(rx_ops); + + return QDF_STATUS_SUCCESS; +} 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 019fb5f9b6..961f1f0e2c 100644 --- a/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c +++ b/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c @@ -20,7 +20,11 @@ */ #include "wlan_fw_offload_main.h" +#include "wlan_fwol_public_structs.h" #include "wlan_fwol_ucfg_api.h" +#include "wlan_fwol_tgt_api.h" +#include "target_if_fwol.h" +#include "wlan_objmgr_vdev_obj.h" QDF_STATUS ucfg_fwol_psoc_open(struct wlan_objmgr_psoc *psoc) { @@ -30,12 +34,16 @@ QDF_STATUS ucfg_fwol_psoc_open(struct wlan_objmgr_psoc *psoc) if (QDF_IS_STATUS_ERROR(status)) fwol_err("Failed to initialize FWOL CFG"); + tgt_fwol_register_ev_handler(psoc); + return status; } void ucfg_fwol_psoc_close(struct wlan_objmgr_psoc *psoc) { /* Clear the FWOL CFG Structure */ + + tgt_fwol_unregister_ev_handler(psoc); } /** @@ -66,6 +74,9 @@ fwol_psoc_object_created_notification(struct wlan_objmgr_psoc *psoc, void *arg) qdf_mem_free(fwol_obj); } + tgt_fwol_register_rx_ops(&fwol_obj->rx_ops); + target_if_fwol_register_tx_ops(&fwol_obj->tx_ops); + return status; } @@ -832,3 +843,71 @@ QDF_STATUS ucfg_fwol_get_adapt_dwell_wifi_act_threshold( fwol_obj->cfg.dwelltime_params.wifi_act_threshold; return QDF_STATUS_SUCCESS; } + +#ifdef WLAN_FEATURE_ELNA +QDF_STATUS ucfg_fwol_set_elna_bypass(struct wlan_objmgr_vdev *vdev, + struct set_elna_bypass_request *req) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_tx_ops *tx_ops; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + fwol_err("NULL pointer for psoc"); + return QDF_STATUS_E_INVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + + tx_ops = &fwol_obj->tx_ops; + if (tx_ops->set_elna_bypass) + status = tx_ops->set_elna_bypass(psoc, req); + else + status = QDF_STATUS_E_IO; + + return status; +} + +QDF_STATUS ucfg_fwol_get_elna_bypass(struct wlan_objmgr_vdev *vdev, + struct get_elna_bypass_request *req, + void (*callback)(void *context, + struct get_elna_bypass_response *response), + void *context) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_tx_ops *tx_ops; + struct wlan_fwol_callbacks *cbs; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + fwol_err("NULL pointer for psoc"); + return QDF_STATUS_E_INVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + + cbs = &fwol_obj->cbs; + cbs->get_elna_bypass_callback = callback; + cbs->get_elna_bypass_context = context; + + tx_ops = &fwol_obj->tx_ops; + if (tx_ops->get_elna_bypass) + status = tx_ops->get_elna_bypass(psoc, req); + else + status = QDF_STATUS_E_IO; + + return status; +} +#endif /* WLAN_FEATURE_ELNA */ diff --git a/components/target_if/fw_offload/inc/target_if_fwol.h b/components/target_if/fw_offload/inc/target_if_fwol.h new file mode 100644 index 0000000000..7a6ab16690 --- /dev/null +++ b/components/target_if/fw_offload/inc/target_if_fwol.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 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 + * 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: target interface APIs for fw offload + * + */ + +#ifndef __TARGET_IF_FWOL_H__ +#define __TARGET_IF_FWOL_H__ + +/** + * target_if_fwol_register_event_handler() - register fw offload event handler + * @psoc: psoc object + * @arg: argument passed to lmac + * + * Return: QDF_STATUS + */ +QDF_STATUS target_if_fwol_register_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg); + +/** + * target_if_fwol_unregister_event_handler() - unregister fw offload event + * handler + * @psoc: psoc object + * @arg: argument passed to lmac + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_fwol_unregister_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg); + +/** + * target_if_fwol_register_tx_ops() - register fw offload tx ops callback + * functions + * @tx_ops: fw offload tx operations + * + * Return: QDF_STATUS + */ +QDF_STATUS target_if_fwol_register_tx_ops(struct wlan_fwol_tx_ops *tx_ops); + +#endif /* __TARGET_IF_FWOL_H__ */ diff --git a/components/target_if/fw_offload/src/target_if_fwol.c b/components/target_if/fw_offload/src/target_if_fwol.c new file mode 100644 index 0000000000..276f250a9b --- /dev/null +++ b/components/target_if/fw_offload/src/target_if_fwol.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 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 + * 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: target interface APIs for fw offload + * + */ + +#include "qdf_mem.h" +#include "target_if.h" +#include "qdf_status.h" +#include "wmi_unified_api.h" +#include "wmi_unified_priv.h" +#include "wmi_unified_param.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_utility.h" +#include "wlan_defs.h" +#include "wlan_fwol_public_structs.h" +#include "wlan_fw_offload_main.h" +#include "target_if_fwol.h" + +#ifdef WLAN_FEATURE_ELNA +/** + * target_if_fwol_set_elna_bypass() - send set eLNA bypass request to FW + * @psoc: pointer to PSOC object + * @req: set eLNA bypass request + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +target_if_fwol_set_elna_bypass(struct wlan_objmgr_psoc *psoc, + struct set_elna_bypass_request *req) +{ + QDF_STATUS status; + + status = wmi_unified_send_set_elna_bypass_cmd( + get_wmi_unified_hdl_from_psoc(psoc), + req); + if (status) + target_if_err("Failed to set eLNA bypass %d", status); + + return status; +} + +/** + * target_if_fwol_get_elna_bypass() - send get eLNA bypass request to FW + * @psoc: pointer to PSOC object + * @req: get eLNA bypass request + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +target_if_fwol_get_elna_bypass(struct wlan_objmgr_psoc *psoc, + struct get_elna_bypass_request *req) +{ + QDF_STATUS status; + + status = wmi_unified_send_get_elna_bypass_cmd( + get_wmi_unified_hdl_from_psoc(psoc), + req); + if (status) + target_if_err("Failed to set eLNA bypass %d", status); + + return status; +} + +/** + * target_if_fwol_get_elna_bypass_resp() - handler for get eLNA bypass response + * @scn: scn handle + * @event_buf: pointer to the event buffer + * @len: length of the buffer + * + * Return: 0 on success + */ +static int target_if_fwol_get_elna_bypass_resp(ol_scn_t scn, uint8_t *event_buf, + uint32_t len) +{ + QDF_STATUS status; + struct get_elna_bypass_response resp; + struct wlan_objmgr_psoc *psoc; + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_rx_ops *rx_ops; + + target_if_debug("scn:%pK, data:%pK, datalen:%d", scn, event_buf, len); + if (!scn || !event_buf) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, event_buf); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + target_if_err("Failed to get FWOL Obj"); + return -EINVAL; + } + + rx_ops = &fwol_obj->rx_ops; + if (rx_ops->get_elna_bypass_resp) { + status = wmi_extract_get_elna_bypass_resp( + get_wmi_unified_hdl_from_psoc(psoc), + event_buf, &resp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to extract eLNA bypass"); + return -EINVAL; + } + status = rx_ops->get_elna_bypass_resp(psoc, &resp); + if (status != QDF_STATUS_SUCCESS) { + target_if_err("get_elna_bypass_resp failed."); + return -EINVAL; + } + } else { + target_if_fatal("No get_elna_bypass_resp callback"); + return -EINVAL; + } + + return 0; +}; + +static void +target_if_fwol_register_elna_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + int rc; + + rc = wmi_unified_register_event(get_wmi_unified_hdl_from_psoc(psoc), + wmi_get_elna_bypass_event_id, + target_if_fwol_get_elna_bypass_resp); + if (rc) + target_if_err("Failed to register get eLNA bypass event cb"); +} + +static void +target_if_fwol_unregister_elna_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + int rc; + + rc = wmi_unified_unregister_event_handler( + get_wmi_unified_hdl_from_psoc(psoc), + wmi_get_elna_bypass_event_id); + if (rc) + target_if_err("Failed to unregister get eLNA bypass event cb"); +} + +static void +target_if_fwol_register_elna_tx_ops(struct wlan_fwol_tx_ops *tx_ops) +{ + tx_ops->set_elna_bypass = target_if_fwol_set_elna_bypass; + tx_ops->get_elna_bypass = target_if_fwol_get_elna_bypass; +} +#else +static void +target_if_fwol_register_elna_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ +} + +static void +target_if_fwol_unregister_elna_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ +} + +static void +target_if_fwol_register_elna_tx_ops(struct wlan_fwol_tx_ops *tx_ops) +{ +} +#endif /* WLAN_FEATURE_ELNA */ + +QDF_STATUS target_if_fwol_register_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + target_if_fwol_register_elna_event_handler(psoc, arg); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +target_if_fwol_unregister_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + target_if_fwol_unregister_elna_event_handler(psoc, arg); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS target_if_fwol_register_tx_ops(struct wlan_fwol_tx_ops *tx_ops) +{ + target_if_fwol_register_elna_tx_ops(tx_ops); + + tx_ops->reg_evt_handler = target_if_fwol_register_event_handler; + tx_ops->unreg_evt_handler = target_if_fwol_unregister_event_handler; + + return QDF_STATUS_SUCCESS; +} + diff --git a/configs/default_defconfig b/configs/default_defconfig index 3bd13e7de9..14e8155d63 100644 --- a/configs/default_defconfig +++ b/configs/default_defconfig @@ -905,6 +905,14 @@ CONFIG_SM_ENG_HIST := n #Enable OEM DATA feature CONFIG_FEATURE_OEM_DATA := y +#Enable FW Offload +CONFIG_WLAN_FW_OFFLOAD := y + +#Enable eLNA bypass feature +ifeq ($(CONFIG_WLAN_FW_OFFLOAD), y) +CONFIG_WLAN_FEATURE_ELNA := y +endif + ifeq (y,$(findstring y,$(CONFIG_ARCH_MSM) $(CONFIG_ARCH_QCOM))) CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH := y endif diff --git a/configs/genoa.common b/configs/genoa.common index 384fedc46a..8e7a575164 100644 --- a/configs/genoa.common +++ b/configs/genoa.common @@ -221,4 +221,8 @@ CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH := y endif CONFIG_SAP_DHCP_FW_IND := n + +#Enable FW Offload +CONFIG_WLAN_FW_OFFLOAD := y + ################################### diff --git a/configs/qca6174_defconfig b/configs/qca6174_defconfig index 10dee88978..1731a86b17 100644 --- a/configs/qca6174_defconfig +++ b/configs/qca6174_defconfig @@ -716,3 +716,7 @@ CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH := y endif CONFIG_SAP_DHCP_FW_IND := y + +#Enable FW Offload +CONFIG_WLAN_FW_OFFLOAD := y + diff --git a/configs/qca6390_defconfig b/configs/qca6390_defconfig index dede872af3..5fe7ac5fe5 100644 --- a/configs/qca6390_defconfig +++ b/configs/qca6390_defconfig @@ -750,3 +750,7 @@ endif CONFIG_FOURTH_CONNECTION := y CONFIG_SAP_DHCP_FW_IND := y + +#Enable FW Offload +CONFIG_WLAN_FW_OFFLOAD := y + diff --git a/configs/qcs40x.snoc.perf_defconfig b/configs/qcs40x.snoc.perf_defconfig index 44c853cf14..ce77021bf7 100644 --- a/configs/qcs40x.snoc.perf_defconfig +++ b/configs/qcs40x.snoc.perf_defconfig @@ -172,6 +172,9 @@ CONFIG_BUILD_TAG := y endif endif +#Enable FW Offload +CONFIG_WLAN_FW_OFFLOAD := y + CONFIG_ENABLE_SIZE_OPTIMIZE := y # configure log buffer size diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index c72b6521d7..94ccdb8df2 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -141,6 +141,7 @@ #include "wlan_blm_ucfg_api.h" #include "wlan_hdd_hw_capability.h" #include "wlan_hdd_oemdata.h" +#include "os_if_fwol.h" #define g_mode_rates_size (12) #define a_mode_rates_size (8) @@ -6108,6 +6109,7 @@ wlan_hdd_wifi_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = { [QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_ENABLE] = {.type = NLA_U8 }, [QCA_WLAN_VENDOR_ATTR_CONFIG_RSN_IE] = {.type = NLA_U8}, [QCA_WLAN_VENDOR_ATTR_CONFIG_GTX] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS] = {.type = NLA_U8}, [QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY] = {.type = NLA_U32 }, [QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST] = { .type = NLA_BINARY, @@ -7270,6 +7272,32 @@ static int hdd_config_disconnect_ies(struct hdd_adapter *adapter, return qdf_status_to_os_return(status); } +#ifdef WLAN_FEATURE_ELNA +/** + * hdd_set_elna_bypass() - Set eLNA bypass + * @adapter: Pointer to HDD adapter + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_set_elna_bypass(struct hdd_adapter *adapter, + const struct nlattr *attr) +{ + int ret; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev(adapter); + if (!vdev) + return -EINVAL; + + ret = os_if_fwol_set_elna_bypass(vdev, attr); + + hdd_objmgr_put_vdev(vdev); + + return ret; +} +#endif + /** * typedef independent_setter_fn - independent attribute handler * @adapter: The adapter being configured @@ -7356,8 +7384,135 @@ static const struct independent_setters independent_setters[] = { hdd_config_gtx}, {QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES, hdd_config_disconnect_ies}, +#ifdef WLAN_FEATURE_ELNA + {QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS, + hdd_set_elna_bypass}, +#endif }; +#ifdef WLAN_FEATURE_ELNA +/** + * hdd_get_elna_bypass() - Get eLNA bypass + * @adapter: Pointer to HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_elna_bypass(struct hdd_adapter *adapter, + struct sk_buff *skb, + const struct nlattr *attr) +{ + int ret; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev(adapter); + if (!vdev) + return -EINVAL; + + ret = os_if_fwol_get_elna_bypass(vdev, skb, attr); + + hdd_objmgr_put_vdev(vdev); + + return ret; +} +#endif + +/** + * typedef config_getter_fn - get configuration handler + * @adapter: The adapter being configured + * @skb: sk buffer to hold nl80211 attributes + * @attr: The nl80211 attribute being applied + * + * Defines the signature of functions in the attribute vtable + * + * Return: 0 if the attribute was handled successfully, otherwise an errno + */ +typedef int (*config_getter_fn)(struct hdd_adapter *adapter, + struct sk_buff *skb, + const struct nlattr *attr); + +/** + * struct config_getters + * @id: vendor attribute which this entry handles + * @cb: callback function to invoke to process the attribute when present + */ +struct config_getters { + uint32_t id; + size_t max_attr_len; + config_getter_fn cb; +}; + +/* vtable for config getters */ +static const struct config_getters config_getters[] = { +#ifdef WLAN_FEATURE_ELNA + {QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS, + sizeof(uint8_t), + hdd_get_elna_bypass}, +#endif +}; + +/** + * hdd_get_configuration() - Handle get configuration + * @adapter: adapter upon which the vendor command was received + * @tb: parsed attribute array + * + * This is a table-driven function which dispatches attributes + * in a QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION + * vendor command. + * + * Return: 0 if there were no issues, otherwise errno of the last issue + */ +static int hdd_get_configuration(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint32_t i, id; + unsigned long nl_buf_len = NLMSG_HDRLEN; + struct sk_buff *skb; + struct nlattr *attr; + config_getter_fn cb; + int errno = 0; + + for (i = 0; i < QDF_ARRAY_SIZE(config_getters); i++) { + id = config_getters[i].id; + attr = tb[id]; + if (!attr) + continue; + + nl_buf_len += NLA_HDRLEN + + NLA_ALIGN(config_getters[i].max_attr_len); + } + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + for (i = 0; i < QDF_ARRAY_SIZE(config_getters); i++) { + id = config_getters[i].id; + attr = tb[id]; + if (!attr) + continue; + + cb = config_getters[i].cb; + errno = cb(adapter, skb, attr); + if (errno) + break; + } + + if (errno) { + hdd_err("Failed to get wifi configuration, errno = %d", errno); + kfree_skb(skb); + return -EINVAL; + } + + cfg80211_vendor_cmd_reply(skb); + + return errno; +} + /** * hdd_set_independent_configuration() - Handle independent attributes * @adapter: adapter upon which the vendor command was received @@ -7536,6 +7691,88 @@ static int wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy, return errno; } +/** + * __wlan_hdd_cfg80211_wifi_configuration_get() - Wifi configuration + * vendor command + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX. + * + * Return: Error code. + */ +static int +__wlan_hdd_cfg80211_wifi_configuration_get(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1]; + int errno; + int ret; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_CONFIG_MAX, data, + data_len, wlan_hdd_wifi_config_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + + ret = hdd_get_configuration(adapter, tb); + if (ret) + errno = ret; + + return errno; +} + +/** + * wlan_hdd_cfg80211_wifi_configuration_get() - Wifi configuration + * vendor command + * + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX. + * + * Return: EOK or other error codes. + */ +static int wlan_hdd_cfg80211_wifi_configuration_get(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_wifi_configuration_get(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + /** * __wlan_hdd_cfg80211_set_wifi_test_config() - Wifi test configuration * vendor command @@ -13498,6 +13735,14 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { WIPHY_VENDOR_CMD_NEED_RUNNING, .doit = wlan_hdd_cfg80211_wifi_configuration_set }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_wifi_configuration_get + }, { .info.vendor_id = QCA_NL80211_VENDOR_ID, .info.subcmd = diff --git a/os_if/fw_offload/inc/os_if_fwol.h b/os_if/fw_offload/inc/os_if_fwol.h new file mode 100644 index 0000000000..ec8a08fc95 --- /dev/null +++ b/os_if/fw_offload/inc/os_if_fwol.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 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 + * 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: os_if_fwol.h + * + * This Header file provide declaration for OS interface API + */ + +#ifndef __OS_IF_FWOL_H__ +#define __OS_IF_FWOL_H__ + +#include "wlan_objmgr_vdev_obj.h" + +#ifdef WLAN_FEATURE_ELNA +/** + * os_if_fwol_set_elna_bypass() - Set eLNA bypass + * @vdev: Pointer to vdev + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +int os_if_fwol_set_elna_bypass(struct wlan_objmgr_vdev *vdev, + const struct nlattr *attr); + +/** + * os_if_fwol_get_elna_bypass() - Get eLNA bypass + * @vdev: Pointer to vdev + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +int os_if_fwol_get_elna_bypass(struct wlan_objmgr_vdev *vdev, + struct sk_buff *skb, + const struct nlattr *attr); +#else +static inline int os_if_fwol_set_elna_bypass(struct wlan_objmgr_vdev *vdev, + const struct nlattr *attr) +{ + return 0; +} + +static inline int os_if_fwol_get_elna_bypass(struct wlan_objmgr_vdev *vdev, + struct sk_buff *skb, + const struct nlattr *attr) +{ + return 0; +} +#endif /* WLAN_FEATURE_ELNA */ + +#endif /* __OS_IF_FWOL_H__ */ diff --git a/os_if/fw_offload/src/os_if_fwol.c b/os_if/fw_offload/src/os_if_fwol.c new file mode 100644 index 0000000000..bcb4c7d36b --- /dev/null +++ b/os_if/fw_offload/src/os_if_fwol.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 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 + * 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: defines driver functions interfacing with linux kernel + */ + +#include "wlan_cfg80211.h" +#include "wlan_osif_request_manager.h" +#include "wlan_fwol_public_structs.h" +#include "wlan_fwol_ucfg_api.h" +#include "os_if_fwol.h" + +#ifdef WLAN_FEATURE_ELNA +#define WLAN_WAIT_TIME_GET_ELNA_BYPASS 1500 + +int os_if_fwol_set_elna_bypass(struct wlan_objmgr_vdev *vdev, + const struct nlattr *attr) +{ + struct set_elna_bypass_request req; + QDF_STATUS status; + + req.vdev_id = vdev->vdev_objmgr.vdev_id; + req.en_dis = nla_get_u8(attr); + if (req.en_dis > 1) { + osif_err("Invalid elna_bypass value %d", req.en_dis); + return -EINVAL; + } + + status = ucfg_fwol_set_elna_bypass(vdev, &req); + if (!QDF_IS_STATUS_SUCCESS(status)) + osif_err("Failed to set ELNA BYPASS, %d", status); + + return qdf_status_to_os_return(status); +} + +struct osif_get_elna_bypass_priv { + uint8_t en_dis; +}; + +/** + * os_if_fwol_get_elna_bypass_callback() - Get eLNA bypass callback + * @context: Call context + * @response: Pointer to response structure + * + * Return: void + */ +static void +os_if_fwol_get_elna_bypass_callback(void *context, + struct get_elna_bypass_response *response) +{ + struct osif_request *request; + struct osif_get_elna_bypass_priv *priv; + + request = osif_request_get(context); + if (!request) { + osif_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + priv->en_dis = response->en_dis; + + osif_request_complete(request); + osif_request_put(request); +} + +int os_if_fwol_get_elna_bypass(struct wlan_objmgr_vdev *vdev, + struct sk_buff *skb, + const struct nlattr *attr) +{ + struct get_elna_bypass_request req; + void *cookie; + struct osif_request *request; + struct osif_get_elna_bypass_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_GET_ELNA_BYPASS, + }; + QDF_STATUS status; + int ret = 0; + + req.vdev_id = vdev->vdev_objmgr.vdev_id; + + request = osif_request_alloc(¶ms); + if (!request) { + osif_err("Request allocation failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + + status = ucfg_fwol_get_elna_bypass(vdev, &req, + os_if_fwol_get_elna_bypass_callback, + cookie); + if (!QDF_IS_STATUS_SUCCESS(status)) { + osif_err("Failed to get ELNA BYPASS, %d", status); + ret = qdf_status_to_os_return(status); + goto end; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + osif_err("Operation timed out"); + goto end; + } + + priv = osif_request_priv(request); + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS, + priv->en_dis)) { + osif_err("put fail"); + ret = -EINVAL; + } + +end: + osif_request_put(request); + return ret; +} +#endif /* #ifdef WLAN_FEATURE_ELNA */