Browse Source

qcacld-3.0: Add Support to offload icmp feature to fw

Add support to offload icmp feature to fw in case of
suspended state to avoid high power consumption.

Change-Id: I3ff19d71eac530c75be57e6b52b975e755ff2a53
CRs-Fixed: 3042452
Aditya Kodukula 3 years ago
parent
commit
37026bc3ff

+ 8 - 0
Kbuild

@@ -1331,6 +1331,11 @@ PMO_OBJS +=     $(PMO_DIR)/core/src/wlan_pmo_ns.o \
 		$(PMO_DIR)/dispatcher/src/wlan_pmo_tgt_ns.o
 endif
 
+ifeq ($(CONFIG_WLAN_FEATURE_ICMP_OFFLOAD), y)
+PMO_OBJS +=     $(PMO_DIR)/core/src/wlan_pmo_icmp.o \
+		$(PMO_DIR)/dispatcher/src/wlan_pmo_tgt_icmp.o
+endif
+
 $(call add-wlan-objs,pmo,$(PMO_OBJS))
 
 ########## DISA (ENCRYPTION TEST) ##########
@@ -1625,6 +1630,9 @@ endif
 ifeq ($(CONFIG_WLAN_FEATURE_PACKET_FILTERING), y)
 CLD_TARGET_IF_OBJ += $(CLD_TARGET_IF_DIR)/pmo/src/target_if_pmo_pkt_filter.o
 endif
+ifeq ($(CONFIG_WLAN_FEATURE_ICMP_OFFLOAD), y)
+CLD_TARGET_IF_OBJ += $(CLD_TARGET_IF_DIR)/pmo/src/target_if_pmo_icmp.o
+endif
 endif
 
 ifeq ($(CONFIG_WLAN_FEATURE_DSRC), y)

+ 40 - 0
components/pmo/core/inc/wlan_pmo_icmp.h

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021, 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: Declare icmp offload feature API's
+ */
+
+#ifndef _WLAN_PMO_ICMP_H_
+#define _WLAN_PMO_ICMP_H_
+
+#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD
+
+#include "wlan_pmo_obj_mgmt_public_struct.h"
+
+/**
+ * pmo_core_icmp_check_offload(): API to check if icmp offload is enabled
+ * @psoc: objmgr psoc handle
+ * @vdev_id: vdev id
+ *
+ * Return: QDF_STATUS_SUCCESS for success or error code
+ */
+QDF_STATUS pmo_core_icmp_check_offload(struct wlan_objmgr_psoc *psoc,
+				       uint8_t vdev_id);
+
+#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */
+
+#endif /* end  of _WLAN_PMO_ICMP_H_ */

+ 49 - 0
components/pmo/core/src/wlan_pmo_icmp.c

@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2021, 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 icmp offload feature API's
+ */
+
+#include "wlan_pmo_icmp.h"
+#include "wlan_pmo_main.h"
+#include "wlan_pmo_obj_mgmt_public_struct.h"
+
+QDF_STATUS pmo_core_icmp_check_offload(struct wlan_objmgr_psoc *psoc,
+				       uint8_t vdev_id)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct wlan_objmgr_vdev *vdev;
+	enum QDF_OPMODE opmode;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID);
+	if (!vdev) {
+		pmo_err("vdev is NULL. vdev_id is %d", vdev_id);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	opmode = pmo_get_vdev_opmode(vdev);
+	if (opmode != QDF_STA_MODE) {
+		pmo_debug("ICMP offload is supported in STA mode only");
+		status = QDF_STATUS_E_INVAL;
+		goto out;
+	}
+
+out:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
+	return status;
+}
+

+ 17 - 2
components/pmo/core/src/wlan_pmo_main.c

@@ -26,6 +26,7 @@
 #include "cfg_ucfg_api.h"
 #include "wlan_fwol_ucfg_api.h"
 #include "wlan_ipa_obj_mgmt_api.h"
+#include "wlan_pmo_icmp.h"
 
 static struct wlan_pmo_ctx *gp_pmo_ctx;
 
@@ -218,6 +219,21 @@ wlan_pmo_get_igmp_offload_enable_cfg(struct wlan_objmgr_psoc *psoc,
 {}
 #endif
 
+#ifdef WLAN_FEATURE_ICMP_OFFLOAD
+static void
+wlan_pmo_get_icmp_offload_enable_cfg(struct wlan_objmgr_psoc *psoc,
+				     struct pmo_psoc_cfg *psoc_cfg)
+{
+	psoc_cfg->is_icmp_offload_enable =
+			cfg_get(psoc, CFG_ENABLE_ICMP_OFFLOAD);
+}
+#else
+static inline void
+wlan_pmo_get_icmp_offload_enable_cfg(struct wlan_objmgr_psoc *psoc,
+				     struct pmo_psoc_cfg *psoc_cfg)
+{}
+#endif
+
 static void wlan_pmo_init_cfg(struct wlan_objmgr_psoc *psoc,
 			      struct pmo_psoc_cfg *psoc_cfg)
 {
@@ -275,8 +291,7 @@ static void wlan_pmo_init_cfg(struct wlan_objmgr_psoc *psoc,
 	wlan_pmo_get_igmp_offload_enable_cfg(psoc, psoc_cfg);
 	psoc_cfg->disconnect_sap_tdls_in_wow =
 			cfg_get(psoc, CFG_DISCONNECT_SAP_TDLS_IN_WOW);
-	psoc_cfg->is_icmp_offload_enable =
-			cfg_get(psoc, CFG_ENABLE_ICMP_OFFLOAD);
+	wlan_pmo_get_icmp_offload_enable_cfg(psoc, psoc_cfg);
 }
 
 QDF_STATUS pmo_psoc_open(struct wlan_objmgr_psoc *psoc)

+ 2 - 0
components/pmo/dispatcher/inc/wlan_pmo_common_cfg.h

@@ -603,6 +603,8 @@
  * This ini is used to enable/disable firmware's capability of sending ICMP
  * response to clients.
  *
+ * Supported Feature: STA
+ *
  * Usage: External
  *
  * </ini>

+ 26 - 0
components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h

@@ -285,6 +285,30 @@ enum pmo_gpio_wakeup_mode {
 	PMO_GPIO_WAKEUP_MODE_LOW,
 };
 
+#ifdef WLAN_FEATURE_ICMP_OFFLOAD
+#define ICMP_MAX_IPV6_ADDRESS 16
+
+/**
+ * pmo_icmp_offload - structure to hold icmp param
+ *
+ * @vdev_id: vdev id
+ * @enable: enable/disable
+ * @trigger: icmp offload trigger information
+ * @ipv6_count: number of host ipv6 address
+ * @ipv4_addr: host interface ipv4 address
+ * @ipv6_addr: array of host ipv6 address
+ *
+ **/
+struct pmo_icmp_offload {
+	uint8_t vdev_id;
+	bool enable;
+	enum pmo_offload_trigger trigger;
+	uint8_t ipv6_count;
+	uint8_t ipv4_addr[QDF_IPV4_ADDR_SIZE];
+	uint8_t ipv6_addr[ICMP_MAX_IPV6_ADDRESS][QDF_IPV6_ADDR_SIZE];
+};
+#endif
+
 /**
  * struct pmo_psoc_cfg - user configuration required for pmo
  * @ptrn_match_enable_all_vdev: true when pattern match is enable for all vdev
@@ -429,7 +453,9 @@ struct pmo_psoc_cfg {
 	bool igmp_offload_enable;
 #endif
 	bool disconnect_sap_tdls_in_wow;
+#ifdef WLAN_FEATURE_ICMP_OFFLOAD
 	bool is_icmp_offload_enable;
+#endif
 };
 
 /**

+ 6 - 1
components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_public_struct.h

@@ -123,6 +123,7 @@ typedef int (*pmo_pld_auto_resume_cb)(void);
  * @psoc_send_d0wow_disable_req: fp to send D0 WOW disable request
  * @psoc_send_idle_roam_suspend_mode: fp to send suspend mode for
  * idle roam  trigger to firmware.
+ * @send_icmp_offload_req: fp to send icmp offload request
  */
 struct wlan_pmo_tx_ops {
 	QDF_STATUS (*send_arp_offload_req)(struct wlan_objmgr_vdev *vdev,
@@ -233,7 +234,11 @@ struct wlan_pmo_tx_ops {
 			struct wlan_objmgr_psoc *psoc);
 	QDF_STATUS (*psoc_send_idle_roam_suspend_mode)(
 			struct wlan_objmgr_psoc *psoc, uint8_t val);
-
+#ifdef WLAN_FEATURE_ICMP_OFFLOAD
+	QDF_STATUS (*send_icmp_offload_req)(
+			struct wlan_objmgr_psoc *psoc,
+			struct pmo_icmp_offload *pmo_icmp_req);
+#endif
 };
 
 #endif /* end  of _WLAN_PMO_OBJ_MGMT_PUBLIC_STRUCT_H_ */

+ 12 - 0
components/pmo/dispatcher/inc/wlan_pmo_tgt_api.h

@@ -486,4 +486,16 @@ QDF_STATUS pmo_tgt_psoc_send_target_resume_req(struct wlan_objmgr_psoc *psoc);
 QDF_STATUS pmo_tgt_psoc_send_idle_roam_monitor(struct wlan_objmgr_psoc *psoc,
 					       uint8_t val);
 
+#ifdef WLAN_FEATURE_ICMP_OFFLOAD
+/**
+ * pmo_tgt_config_icmp_offload_req() - Configure icmp offload req to target
+ * @psoc: objmgr psoc
+ * @pmo_icmp_req: ICMP offload parameters
+ *
+ * Return: QDF status
+ */
+QDF_STATUS
+pmo_tgt_config_icmp_offload_req(struct wlan_objmgr_psoc *psoc,
+				struct pmo_icmp_offload *pmo_icmp_req);
+#endif
 #endif /* end  of _WLAN_PMO_TGT_API_H_ */

+ 51 - 0
components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h

@@ -1284,6 +1284,37 @@ uint32_t ucfg_pmo_get_moddtim_user(struct wlan_objmgr_vdev *vdev);
  */
 bool
 ucfg_pmo_get_disconnect_sap_tdls_in_wow(struct wlan_objmgr_psoc *psoc);
+
+#ifdef WLAN_FEATURE_ICMP_OFFLOAD
+/**
+ * ucfg_pmo_check_icmp_offload(): API to check if icmp offload is enabled
+ * @psoc: objmgr psoc handle
+ * @vdev_id: vdev_id
+ *
+ * Return: QDF_STATUS_SUCCESS for success or error code
+ */
+QDF_STATUS ucfg_pmo_check_icmp_offload(struct wlan_objmgr_psoc *psoc,
+				       uint8_t vdev_id);
+/**
+ * ucfg_pmo_is_icmp_offload_enabled() - Get icmp offload enable or not
+ * @psoc: pointer to psoc object
+ *
+ * Return: icmp offload enable or not
+ */
+bool
+ucfg_pmo_is_icmp_offload_enabled(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ucfg_pmo_config_icmp_offload() - API to enable icmp offload request
+ * @psoc: pointer to psoc object
+ * @pmo_icmp_req: ICMP offload parameters
+ *
+ * Return: QDF_STATUS_SUCCESS for success or error code
+ */
+QDF_STATUS
+ucfg_pmo_config_icmp_offload(struct wlan_objmgr_psoc *psoc,
+			     struct pmo_icmp_offload *pmo_icmp_req);
+#endif
 #else /* WLAN_POWER_MANAGEMENT_OFFLOAD */
 static inline QDF_STATUS
 ucfg_pmo_psoc_open(struct wlan_objmgr_psoc *psoc)
@@ -1992,6 +2023,26 @@ ucfg_pmo_get_disconnect_sap_tdls_in_wow(struct wlan_objmgr_psoc *psoc)
 {
 	return false;
 }
+
+static inline
+QDF_STATUS ucfg_pmo_check_icmp_offload(struct wlan_objmgr_psoc *psoc,
+				       uint8_t vdev_id)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline bool
+ucfg_pmo_is_icmp_offload_enabled(struct wlan_objmgr_psoc *psoc)
+{
+	return false;
+}
+
+QDF_STATUS
+ucfg_pmo_config_icmp_offload(struct wlan_objmgr_psoc *psoc,
+			     struct pmo_icmp_offload *pmo_icmp_req)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */
 
 #ifdef WLAN_FEATURE_EXTWOW_SUPPORT

+ 45 - 0
components/pmo/dispatcher/src/wlan_pmo_tgt_icmp.c

@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2021, 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 pmo to interact with target/WMI
+ */
+
+#include "wlan_pmo_tgt_api.h"
+#include "wlan_pmo_obj_mgmt_public_struct.h"
+#include "wlan_pmo_main.h"
+
+QDF_STATUS
+pmo_tgt_config_icmp_offload_req(struct wlan_objmgr_psoc *psoc,
+				struct pmo_icmp_offload *pmo_icmp_req)
+{
+	QDF_STATUS status;
+	struct wlan_pmo_tx_ops pmo_tx_ops;
+
+	pmo_debug("vdev_id: %d: ICMP offload %d", pmo_icmp_req->vdev_id,
+		  pmo_icmp_req->enable);
+
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.send_icmp_offload_req) {
+		pmo_err("send_icmp_offload_req is null");
+		status = QDF_STATUS_E_NULL_VALUE;
+		return status;
+	}
+
+	status = pmo_tx_ops.send_icmp_offload_req(psoc, pmo_icmp_req);
+
+	return status;
+}

+ 23 - 0
components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c

@@ -34,6 +34,7 @@
 #include "wlan_pmo_cfg.h"
 #include "wlan_pmo_static_config.h"
 #include "cfg_ucfg_api.h"
+#include "wlan_pmo_icmp.h"
 
 QDF_STATUS ucfg_pmo_psoc_open(struct wlan_objmgr_psoc *psoc)
 {
@@ -1000,3 +1001,25 @@ ucfg_pmo_get_disconnect_sap_tdls_in_wow(struct wlan_objmgr_psoc *psoc)
 
 	return pmo_psoc_ctx->psoc_cfg.disconnect_sap_tdls_in_wow;
 }
+
+#ifdef WLAN_FEATURE_ICMP_OFFLOAD
+QDF_STATUS ucfg_pmo_check_icmp_offload(struct wlan_objmgr_psoc *psoc,
+				       uint8_t vdev_id)
+{
+	return pmo_core_icmp_check_offload(psoc, vdev_id);
+}
+
+bool
+ucfg_pmo_is_icmp_offload_enabled(struct wlan_objmgr_psoc *psoc)
+{
+	struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc);
+
+	return pmo_psoc_ctx->psoc_cfg.is_icmp_offload_enable;
+}
+
+QDF_STATUS ucfg_pmo_config_icmp_offload(struct wlan_objmgr_psoc *psoc,
+					struct pmo_icmp_offload *pmo_icmp_req)
+{
+	return pmo_tgt_config_icmp_offload_req(psoc, pmo_icmp_req);
+}
+#endif

+ 14 - 0
components/target_if/pmo/inc/target_if_pmo.h

@@ -522,5 +522,19 @@ target_if_pmo_psoc_send_idle_monitor_cmd(struct wlan_objmgr_psoc *psoc,
  */
 void target_if_pmo_register_tx_ops(struct wlan_pmo_tx_ops *tx_ops);
 
+#ifdef WLAN_FEATURE_ICMP_OFFLOAD
+/**
+ * target_if_pmo_send_icmp_offload_req() - sends icmp request to fwr
+ * @psoc: objmgr psoc
+ * @pmo_icmp_req: icmp offload request
+ *
+ * This functions sends icmp request to fwr.
+ *
+ * Return: QDF_STATUS_SUCCESS for success or error code
+ */
+QDF_STATUS
+target_if_pmo_send_icmp_offload_req(struct wlan_objmgr_psoc *psoc,
+				    struct pmo_icmp_offload *pmo_icmp_req);
 #endif
 
+#endif

+ 49 - 0
components/target_if/pmo/src/target_if_pmo_icmp.c

@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2021, 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_if_pmo_icmp.c
+ *
+ * Target interface file for pmo component to
+ * send icmp offload related cmd and process event.
+ */
+
+#include "target_if.h"
+#include "target_if_pmo.h"
+#include "wmi_unified_api.h"
+
+QDF_STATUS
+target_if_pmo_send_icmp_offload_req(struct wlan_objmgr_psoc *psoc,
+				    struct pmo_icmp_offload *pmo_icmp_req)
+{
+	QDF_STATUS status;
+	wmi_unified_t wmi_handle;
+
+	if (!psoc) {
+		target_if_err("psoc handle is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("Invalid wmi handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	status = wmi_unified_config_icmp_offload_cmd(wmi_handle, pmo_icmp_req);
+
+	return status;
+}

+ 13 - 0
components/target_if/pmo/src/target_if_pmo_main.c

@@ -23,6 +23,7 @@
 
 #include "target_if_pmo.h"
 #include "wlan_pmo_common_public_struct.h"
+#include "wlan_pmo_icmp.h"
 
 #ifdef WLAN_FEATURE_PACKET_FILTERING
 static inline
@@ -51,6 +52,17 @@ static inline void
 update_pmo_igmp_tx_ops(struct wlan_pmo_tx_ops *pmo_tx_ops)
 {}
 #endif
+#ifdef WLAN_FEATURE_ICMP_OFFLOAD
+static void tgt_if_pmo_icmp_tx_ops(struct wlan_pmo_tx_ops *pmo_tx_ops)
+{
+	pmo_tx_ops->send_icmp_offload_req =
+		target_if_pmo_send_icmp_offload_req;
+}
+#else
+static inline void
+tgt_if_pmo_icmp_tx_ops(struct wlan_pmo_tx_ops *pmo_tx_ops)
+{}
+#endif
 void target_if_pmo_register_tx_ops(struct wlan_pmo_tx_ops *pmo_tx_ops)
 {
 	if (!pmo_tx_ops) {
@@ -138,5 +150,6 @@ void target_if_pmo_register_tx_ops(struct wlan_pmo_tx_ops *pmo_tx_ops)
 	pmo_tx_ops->psoc_send_idle_roam_suspend_mode =
 		target_if_pmo_psoc_send_idle_monitor_cmd;
 	tgt_if_pmo_reg_pkt_filter_ops(pmo_tx_ops);
+	tgt_if_pmo_icmp_tx_ops(pmo_tx_ops);
 }
 

+ 18 - 0
core/hdd/inc/wlan_hdd_power.h

@@ -636,4 +636,22 @@ QDF_STATUS wlan_hdd_get_ani_level(struct hdd_adapter *adapter,
 				  uint32_t *parsed_freqs,
 				  uint8_t num_freqs);
 #endif /* FEATURE_ANI_LEVEL_REQUEST */
+
+#ifdef WLAN_FEATURE_ICMP_OFFLOAD
+/**
+ * hdd_enable_icmp_offload() - API to enable ICMP offload
+ * @adapter: Adapter context for which ICMP offload is to be configured
+ * @trigger: trigger reason for request
+ *
+ * Return: None
+ */
+void hdd_enable_icmp_offload(struct hdd_adapter *adapter,
+			     enum pmo_offload_trigger trigger);
+#else
+static inline
+void hdd_enable_icmp_offload(struct hdd_adapter *adapter,
+			     enum pmo_offload_trigger trigger)
+{}
+#endif /* FEATURE_ICMP_OFFLOAD */
+
 #endif /* __WLAN_HDD_POWER_H */

+ 157 - 0
core/hdd/src/wlan_hdd_power.c

@@ -724,6 +724,7 @@ static void __hdd_ipv6_notifier_work_queue(struct hdd_adapter *adapter)
 		goto exit;
 
 	hdd_enable_ns_offload(adapter, pmo_ipv6_change_notify);
+	hdd_enable_icmp_offload(adapter, pmo_ipv6_change_notify);
 
 	hdd_send_ps_config_to_fw(adapter);
 exit:
@@ -1070,6 +1071,7 @@ static void __hdd_ipv4_notifier_work_queue(struct hdd_adapter *adapter)
 		goto exit;
 
 	hdd_enable_arp_offload(adapter, pmo_ipv4_change_notify);
+	hdd_enable_icmp_offload(adapter, pmo_ipv4_change_notify);
 
 	status = ucfg_mlme_get_sta_keepalive_method(hdd_ctx->psoc, &val);
 	if (QDF_IS_STATUS_ERROR(status))
@@ -1340,6 +1342,161 @@ free_req:
 	qdf_mem_free(arp_req);
 }
 
+#ifdef WLAN_FEATURE_ICMP_OFFLOAD
+/**
+ * hdd_fill_ipv4_addr() - fill IPv4 addresses
+ * @adapter: Adapter context for which ICMP offload is to be configured
+ * @pmo_icmp_req: pointer to ICMP offload request params
+ *
+ * This is the IPv4 utility function to populate address.
+ *
+ * Return: 0 on success, error number otherwise.
+ */
+static int hdd_fill_ipv4_addr(struct hdd_adapter *adapter,
+			      struct pmo_icmp_offload *pmo_icmp_req)
+{
+	struct in_ifaddr *ifa;
+	uint8_t ipv4_addr_array[QDF_IPV4_ADDR_SIZE];
+	int i;
+
+	ifa = hdd_get_ipv4_local_interface(adapter);
+	if (!ifa || !ifa->ifa_local) {
+		hdd_debug("IP Address is not assigned");
+		return -EINVAL;
+	}
+
+	/* converting u32 to IPv4 address */
+	for (i = 0; i < QDF_IPV4_ADDR_SIZE; i++)
+		ipv4_addr_array[i] = (ifa->ifa_local >> i * 8) & 0xff;
+
+	qdf_mem_copy(pmo_icmp_req->ipv4_addr, &ipv4_addr_array,
+		     QDF_IPV4_ADDR_SIZE);
+
+	return 0;
+}
+
+/**
+ * hdd_fill_ipv6_addr() - fill IPv6 addresses
+ * @adapter: Adapter context for which ICMP offload is to be configured
+ * @pmo_icmp_req: pointer to ICMP offload request params
+ *
+ * This is the IPv6 utility function to populate addresses.
+ *
+ * Return: 0 on success, error number otherwise.
+ */
+static int hdd_fill_ipv6_addr(struct hdd_adapter *adapter,
+			      struct pmo_icmp_offload *pmo_icmp_req)
+{
+	struct inet6_dev *in6_dev;
+	struct pmo_ns_req *ns_req;
+	int i, errno;
+
+	in6_dev = __in6_dev_get(adapter->dev);
+	if (!in6_dev) {
+		hdd_err_rl("IPv6 dev does not exist");
+		return -EINVAL;
+	}
+
+	ns_req = qdf_mem_malloc(sizeof(*ns_req));
+	if (!ns_req)
+		return -ENOMEM;
+
+	ns_req->count = 0;
+	/* Unicast Addresses */
+	errno = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr,
+				      ns_req->ipv6_addr_type, ns_req->scope,
+				      &ns_req->count);
+	if (errno) {
+		hdd_debug("Reached Max IPv6 supported address %d",
+			  ns_req->count);
+		goto free_req;
+	}
+	/* Anycast Addresses */
+	errno = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr,
+				      ns_req->ipv6_addr_type, ns_req->scope,
+				      &ns_req->count);
+	if (errno) {
+		hdd_debug("Reached Max IPv6 supported address %d",
+			  ns_req->count);
+		goto free_req;
+	}
+
+	pmo_icmp_req->ipv6_count = ns_req->count;
+	for (i = 0; i < pmo_icmp_req->ipv6_count; i++) {
+		qdf_mem_copy(&pmo_icmp_req->ipv6_addr[i], &ns_req->ipv6_addr[i],
+			     QDF_IPV6_ADDR_SIZE);
+	}
+
+free_req:
+	qdf_mem_free(ns_req);
+	return errno;
+}
+
+void hdd_enable_icmp_offload(struct hdd_adapter *adapter,
+			     enum pmo_offload_trigger trigger)
+{
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc;
+	struct pmo_icmp_offload *pmo_icmp_req;
+	struct wlan_objmgr_vdev *vdev;
+	bool is_icmp_enable;
+	QDF_STATUS status;
+
+	is_icmp_enable = ucfg_pmo_is_icmp_offload_enabled(psoc);
+	if (!is_icmp_enable) {
+		hdd_debug("ICMP Offload not enabled");
+		return;
+	}
+
+	pmo_icmp_req = qdf_mem_malloc(sizeof(*pmo_icmp_req));
+	if (!pmo_icmp_req)
+		return;
+
+	vdev = hdd_objmgr_get_vdev_by_user(adapter, WLAN_OSIF_POWER_ID);
+	if (!vdev) {
+		hdd_err("vdev is NULL");
+		goto free_req;
+	}
+
+	status = ucfg_pmo_check_icmp_offload(psoc, adapter->vdev_id);
+	if (QDF_IS_STATUS_ERROR(status))
+		goto put_vdev;
+
+	pmo_icmp_req->vdev_id = adapter->vdev_id;
+	pmo_icmp_req->enable = is_icmp_enable;
+	pmo_icmp_req->trigger = trigger;
+
+	switch (trigger) {
+	case pmo_ipv4_change_notify:
+		if (hdd_fill_ipv4_addr(adapter, pmo_icmp_req)) {
+			hdd_debug("Unable to populate IPv4 Address");
+			goto put_vdev;
+		}
+		break;
+	case pmo_ipv6_change_notify:
+		if (hdd_fill_ipv6_addr(adapter, pmo_icmp_req)) {
+			hdd_debug("Unable to populate IPv6 Address");
+			goto put_vdev;
+		}
+		break;
+	default:
+		QDF_DEBUG_PANIC("The trigger %d is not supported", trigger);
+		goto put_vdev;
+	}
+
+	status = ucfg_pmo_config_icmp_offload(psoc, pmo_icmp_req);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err_rl("icmp offload config in fw failed: %d", status);
+		goto put_vdev;
+	}
+
+put_vdev:
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
+free_req:
+	qdf_mem_free(pmo_icmp_req);
+}
+#endif
+
 void hdd_disable_arp_offload(struct hdd_adapter *adapter,
 		enum pmo_offload_trigger trigger)
 {