Pārlūkot izejas kodu

qcacld-3.0: Add support to offload igmp feature to fw

offload igmp feature to fw in case of suspended state
to avoid high power consumption.

Change-Id: I05fbf23dc2836f8f5dc6e2f45b35bf2d30c39790
CRs-Fixed: 2907644
sheenam monga 4 gadi atpakaļ
vecāks
revīzija
6e6c139e05

+ 20 - 0
components/pmo/core/inc/wlan_pmo_suspend_resume.h

@@ -372,7 +372,27 @@ QDF_STATUS pmo_core_config_forced_dtim(struct wlan_objmgr_vdev *vdev,
 void pmo_core_system_resume(struct wlan_objmgr_psoc *psoc);
 #else
 static inline void pmo_core_system_resume(struct wlan_objmgr_psoc *psoc)
+{}
+#endif
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+/**
+ * pmo_core_enable_igmp_offload() - function to offload igmp
+ * @vdev: objmgr vdev handle
+ * @pmo_igmp_req: igmp req
+ *
+ * This function to offload igmp to fw
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+pmo_core_enable_igmp_offload(struct wlan_objmgr_vdev *vdev,
+			     struct pmo_igmp_offload_req *pmo_igmp_req);
+#else
+static inline QDF_STATUS
+pmo_core_enable_igmp_offload(struct wlan_objmgr_vdev *vdev,
+			     struct pmo_igmp_offload_req *pmo_igmp_req)
 {
+	return QDF_STATUS_SUCCESS;
 }
 #endif
 #endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */

+ 39 - 0
components/pmo/core/src/wlan_pmo_suspend_resume.c

@@ -1697,6 +1697,45 @@ out:
 	return status;
 }
 
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+QDF_STATUS
+pmo_core_enable_igmp_offload(struct wlan_objmgr_vdev *vdev,
+			     struct pmo_igmp_offload_req *pmo_igmp_req)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	uint8_t vdev_id;
+	enum QDF_OPMODE op_mode;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+	uint32_t version_support;
+
+	if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS)
+		return QDF_STATUS_E_INVAL;
+
+	op_mode = pmo_get_vdev_opmode(vdev);
+	if (QDF_STA_MODE != op_mode) {
+		pmo_debug("igmp offload supported in STA mode");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	vdev_ctx = pmo_vdev_get_priv(vdev);
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.igmp_offload_enable) {
+		pmo_debug("igmp offload not supported");
+		qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+		return QDF_STATUS_E_NOSUPPORT;
+	}
+	version_support =
+		vdev_ctx->pmo_psoc_ctx->psoc_cfg.igmp_version_support;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+	vdev_id = pmo_vdev_get_id(vdev);
+	pmo_igmp_req->vdev_id = vdev_id;
+	pmo_igmp_req->version_support = version_support;
+	status = pmo_tgt_send_igmp_offload_req(vdev, pmo_igmp_req);
+
+	return status;
+}
+#endif
+
 QDF_STATUS pmo_core_config_forced_dtim(struct wlan_objmgr_vdev *vdev,
 				       uint32_t dynamic_dtim)
 {

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

@@ -51,6 +51,9 @@
 
 #define PMO_WOW_REQUIRED_CREDITS 1
 
+#define MAX_MC_IP_ADDR 10
+#define IGMP_QUERY_ADDRESS 0x10000e0
+
 /**
  * enum pmo_vdev_param_id: tell vdev param id
  * @pmo_vdev_param_listen_interval: vdev listen interval param id
@@ -425,4 +428,21 @@ struct pmo_device_caps {
 	bool li_offload;
 };
 
+/**
+ * pmo_igmp_offload_req - structure to hold igmp param
+ *
+ * @vdev_id: vdev id
+ * @enable: enable/disable
+ * @version_support: version support
+ * @num_grp_ip_address: num grp ip addr
+ * @grp_ip_address: array of grp_ip_address
+ *
+ **/
+struct pmo_igmp_offload_req {
+	uint32_t vdev_id;
+	bool enable;
+	uint32_t version_support;
+	uint32_t num_grp_ip_address;
+	uint32_t grp_ip_address[MAX_MC_IP_ADDR];
+};
 #endif /* end  of _WLAN_PMO_COMMONP_STRUCT_H_ */

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

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-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
@@ -201,6 +201,11 @@ struct wlan_pmo_tx_ops {
 	QDF_STATUS (*send_vdev_sta_ps_param_req)(
 			struct wlan_objmgr_vdev *vdev,
 			uint32_t ps_mode, uint32_t value);
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+	QDF_STATUS (*send_igmp_offload_req)(
+			struct wlan_objmgr_vdev *vdev,
+			struct pmo_igmp_offload_req *pmo_igmp_req);
+#endif
 	void (*psoc_update_wow_bus_suspend)(
 			struct wlan_objmgr_psoc *psoc, uint8_t value);
 	int (*psoc_get_host_credits)(

+ 21 - 1
components/pmo/dispatcher/inc/wlan_pmo_tgt_api.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-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
@@ -346,6 +346,26 @@ QDF_STATUS pmo_tgt_vdev_update_param_req(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS pmo_tgt_send_vdev_sta_ps_param(struct wlan_objmgr_vdev *vdev,
 		enum pmo_sta_powersave_param ps_param, uint32_t param_value);
 
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+/**
+ * pmo_tgt_send_igmp_offload_req() - Send igmp offload request to fw
+ * @vdev: objmgr vdev
+ * @pmo_igmp_req: igmp offload params
+ *
+ * Return: QDF status
+ */
+QDF_STATUS
+pmo_tgt_send_igmp_offload_req(struct wlan_objmgr_vdev *vdev,
+			      struct pmo_igmp_offload_req *pmo_igmp_req);
+#else
+static inline QDF_STATUS
+pmo_tgt_send_igmp_offload_req(struct wlan_objmgr_vdev *vdev,
+			      struct pmo_igmp_offload_req *pmo_igmp_req)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 /**
  * pmo_tgt_update_wow_bus_suspend_state() - update wow bus suspend state flag
  * @psoc: objmgr psoc

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

@@ -140,6 +140,28 @@ QDF_STATUS ucfg_pmo_psoc_set_caps(struct wlan_objmgr_psoc *psoc,
 bool
 ucfg_pmo_is_arp_offload_enabled(struct wlan_objmgr_psoc *psoc);
 
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+/**
+ * ucfg_pmo_is_igmp_offload_enabled() - Get igmp offload enable or not
+ * @psoc: pointer to psoc object
+ *
+ * Return: igmp offload enable or not
+ */
+bool
+ucfg_pmo_is_igmp_offload_enabled(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ucfg_pmo_set_igmp_offload_enabled() - Set igmp offload enable or not
+ * @psoc: pointer to psoc object
+ * @val:  enable/disable igmp offload
+ *
+ * Return: None
+ */
+void
+ucfg_pmo_set_igmp_offload_enabled(struct wlan_objmgr_psoc *psoc,
+				  bool val);
+#endif
+
 /**
  * ucfg_pmo_set_arp_offload_enabled() - Set arp offload enable or not
  * @psoc: pointer to psoc object
@@ -593,6 +615,27 @@ QDF_STATUS ucfg_pmo_flush_gtk_offload_req(struct wlan_objmgr_vdev *vdev);
  */
 QDF_STATUS ucfg_pmo_enable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev);
 
+#ifdef WLAN_FEATURE_BIG_DATA_STATS
+/**
+ * ucfg_pmo_enable_igmp_offload(): enable igmp request in fwr
+ * @vdev: objmgr vdev handle
+ * @pmo_igmp_req: struct pmo_igmp_offload_req
+ *
+ * Return QDF_STATUS_SUCCESS -in case of success else return error
+ */
+QDF_STATUS ucfg_pmo_enable_igmp_offload(
+				struct wlan_objmgr_vdev *vdev,
+				struct pmo_igmp_offload_req *pmo_igmp_req);
+#else
+static inline
+QDF_STATUS ucfg_pmo_enable_igmp_offload(
+				struct wlan_objmgr_vdev *vdev,
+				struct pmo_igmp_offload_req *pmo_igmp_req)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 /**
  * ucfg_pmo_disable_gtk_offload_in_fwr(): disable cached gtk request in fwr
  * @vdev: objmgr vdev handle
@@ -1451,6 +1494,13 @@ ucfg_pmo_enable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev)
 	return QDF_STATUS_SUCCESS;
 }
 
+static inline QDF_STATUS
+ucfg_pmo_enable_igmp_offload(struct wlan_objmgr_vdev *vdev,
+			     struct pmo_igmp_offload_req *pmo_igmp_req)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
 static inline QDF_STATUS
 ucfg_pmo_disable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev)
 {
@@ -1713,12 +1763,24 @@ ucfg_pmo_is_arp_offload_enabled(struct wlan_objmgr_psoc *psoc)
 	return false;
 }
 
+static inline bool
+ucfg_pmo_is_igmp_offload_enabled(struct wlan_objmgr_psoc *psoc)
+{
+	return false;
+}
+
 static inline void
 ucfg_pmo_set_arp_offload_enabled(struct wlan_objmgr_psoc *psoc,
 				 bool val)
 {
 }
 
+static inline void
+ucfg_pmo_set_igmp_offload_enabled(struct wlan_objmgr_psoc *psoc,
+				  bool val)
+{
+}
+
 static inline bool
 ucfg_pmo_is_wow_pulse_enabled(struct wlan_objmgr_psoc *psoc)
 {

+ 24 - 1
components/pmo/dispatcher/src/wlan_pmo_tgt_suspend_resume.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-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
@@ -51,6 +51,29 @@ out:
 	return status;
 }
 
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+QDF_STATUS
+pmo_tgt_send_igmp_offload_req(struct wlan_objmgr_vdev *vdev,
+			      struct pmo_igmp_offload_req *pmo_igmp_req)
+{
+	QDF_STATUS status;
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_pmo_tx_ops pmo_tx_ops;
+
+	psoc = pmo_vdev_get_psoc(vdev);
+
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.send_igmp_offload_req) {
+		pmo_err("send_vdev_param_set_req is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	status = pmo_tx_ops.send_igmp_offload_req(vdev, pmo_igmp_req);
+
+	return status;
+}
+#endif
+
 QDF_STATUS pmo_tgt_send_vdev_sta_ps_param(struct wlan_objmgr_vdev *vdev,
 		enum pmo_sta_powersave_param ps_param, uint32_t param_value)
 {

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

@@ -280,6 +280,14 @@ QDF_STATUS ucfg_pmo_enable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev)
 	return pmo_core_enable_gtk_offload_in_fwr(vdev);
 }
 
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+QDF_STATUS ucfg_pmo_enable_igmp_offload(struct wlan_objmgr_vdev *vdev,
+					struct pmo_igmp_offload_req *igmp_req)
+{
+	return pmo_core_enable_igmp_offload(vdev, igmp_req);
+}
+#endif
+
 QDF_STATUS ucfg_pmo_disable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev)
 {
 	return pmo_core_disable_gtk_offload_in_fwr(vdev);
@@ -547,6 +555,16 @@ ucfg_pmo_is_arp_offload_enabled(struct wlan_objmgr_psoc *psoc)
 	return pmo_psoc_ctx->psoc_cfg.arp_offload_enable;
 }
 
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+bool
+ucfg_pmo_is_igmp_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.igmp_offload_enable;
+}
+#endif
+
 void
 ucfg_pmo_set_arp_offload_enabled(struct wlan_objmgr_psoc *psoc,
 				 bool val)
@@ -556,6 +574,17 @@ ucfg_pmo_set_arp_offload_enabled(struct wlan_objmgr_psoc *psoc,
 	pmo_psoc_ctx->psoc_cfg.arp_offload_enable = val;
 }
 
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+void
+ucfg_pmo_set_igmp_offload_enabled(struct wlan_objmgr_psoc *psoc,
+				  bool val)
+{
+	struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc);
+
+	pmo_psoc_ctx->psoc_cfg.igmp_offload_enable = val;
+}
+#endif
+
 enum pmo_auto_pwr_detect_failure_mode
 ucfg_pmo_get_auto_power_fail_mode(struct wlan_objmgr_psoc *psoc)
 {

+ 23 - 1
components/target_if/pmo/inc/target_if_pmo.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-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
@@ -351,6 +351,28 @@ QDF_STATUS target_if_pmo_send_vdev_ps_param_req(
 		uint32_t param_id,
 		uint32_t param_value);
 
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+/**
+ * target_if_pmo_send_igmp_offload_req() - Send igmp offload req to fw
+ * @vdev: objmgr vdev
+ * @pmo_igmp_req: igmp req
+ *
+ * Return: QDF status
+ */
+QDF_STATUS
+target_if_pmo_send_igmp_offload_req(
+		struct wlan_objmgr_vdev *vdev,
+		struct pmo_igmp_offload_req *pmo_igmp_req);
+#else
+static inline QDF_STATUS
+target_if_pmo_send_igmp_offload_req(
+		struct wlan_objmgr_vdev *vdev,
+		struct pmo_igmp_offload_req *pmo_igmp_req)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 /**
  * target_if_pmo_psoc_update_bus_suspend() - update wmi bus suspend flag
  * @psoc: objmgr psoc

+ 16 - 4
components/target_if/pmo/src/target_if_pmo_main.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-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
@@ -34,12 +34,23 @@ void tgt_if_pmo_reg_pkt_filter_ops(struct wlan_pmo_tx_ops *pmo_tx_ops)
 		target_if_pmo_clear_pkt_filter_req;
 }
 #else
-static inline
-void tgt_if_pmo_reg_pkt_filter_ops(struct wlan_pmo_tx_ops *pmo_tx_ops)
+static inline void
+tgt_if_pmo_reg_pkt_filter_ops(struct wlan_pmo_tx_ops *pmo_tx_ops)
 {
 }
 #endif
-
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+static void
+update_pmo_igmp_tx_ops(struct wlan_pmo_tx_ops *pmo_tx_ops)
+{
+	pmo_tx_ops->send_igmp_offload_req =
+		target_if_pmo_send_igmp_offload_req;
+}
+#else
+static inline void
+update_pmo_igmp_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) {
@@ -99,6 +110,7 @@ void target_if_pmo_register_tx_ops(struct wlan_pmo_tx_ops *pmo_tx_ops)
 		target_if_pmo_psoc_update_bus_suspend;
 	pmo_tx_ops->psoc_get_host_credits =
 		target_if_pmo_psoc_get_host_credits;
+	update_pmo_igmp_tx_ops(pmo_tx_ops);
 	pmo_tx_ops->psoc_get_pending_cmnds =
 		target_if_pmo_psoc_get_pending_cmnds;
 	pmo_tx_ops->update_target_suspend_flag =

+ 30 - 0
components/target_if/pmo/src/target_if_pmo_suspend_resume.c

@@ -87,6 +87,36 @@ QDF_STATUS target_if_pmo_send_vdev_update_param_req(
 	return wmi_unified_vdev_set_param_send(wmi_handle, &param);
 }
 
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+QDF_STATUS target_if_pmo_send_igmp_offload_req(
+			struct wlan_objmgr_vdev *vdev,
+			struct pmo_igmp_offload_req *pmo_igmp_req)
+{
+	struct wlan_objmgr_psoc *psoc;
+	wmi_unified_t wmi_handle;
+
+	if (!vdev) {
+		target_if_err("vdev ptr passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	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;
+	}
+
+	return wmi_unified_send_igmp_offload_cmd(wmi_handle,
+						 pmo_igmp_req);
+}
+#endif
+
 QDF_STATUS target_if_pmo_send_vdev_ps_param_req(
 		struct wlan_objmgr_vdev *vdev,
 		uint32_t param_id,

+ 24 - 0
core/hdd/src/wlan_hdd_main.c

@@ -1659,6 +1659,26 @@ hdd_init_get_sta_in_ll_stats_config(struct hdd_adapter *adapter)
 }
 #endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */
 
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+static void
+hdd_intersect_igmp_offload_setting(struct wlan_objmgr_psoc *psoc,
+				   struct wma_tgt_services *cfg)
+{
+	bool igmp_offload_enable;
+
+	igmp_offload_enable =
+		ucfg_pmo_is_igmp_offload_enabled(psoc);
+	ucfg_pmo_set_igmp_offload_enabled(psoc,
+					  igmp_offload_enable &
+					  cfg->igmp_offload_enable);
+}
+#else
+static inline void
+hdd_intersect_igmp_offload_setting(struct wlan_objmgr_psoc *psoc,
+				   struct wma_tgt_services *cfg)
+{}
+#endif
+
 static void hdd_update_tgt_services(struct hdd_context *hdd_ctx,
 				    struct wma_tgt_services *cfg)
 {
@@ -1691,6 +1711,10 @@ static void hdd_update_tgt_services(struct hdd_context *hdd_ctx,
 			ucfg_pmo_is_arp_offload_enabled(hdd_ctx->psoc);
 	ucfg_pmo_set_arp_offload_enabled(hdd_ctx->psoc,
 					 arp_offload_enable & cfg->arp_offload);
+
+	/* Intersect igmp offload ini configuration and fw cap*/
+	hdd_intersect_igmp_offload_setting(hdd_ctx->psoc, cfg);
+
 #ifdef FEATURE_WLAN_SCAN_PNO
 	/* PNO offload */
 	hdd_debug("PNO Capability in f/w = %d", cfg->pno_offload);

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

@@ -85,6 +85,8 @@
 #include "wlan_pkt_capture_ucfg_api.h"
 #include "wlan_hdd_thermal.h"
 #include "wlan_hdd_object_manager.h"
+#include <linux/igmp.h>
+#include "qdf_types.h"
 /* Preprocessor definitions and constants */
 #ifdef QCA_WIFI_EMULATION
 #define HDD_SSR_BRING_UP_TIME 3000000
@@ -192,6 +194,96 @@ static void hdd_enable_gtk_offload(struct hdd_adapter *adapter)
 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
 }
 
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+/**
+ * hdd_send_igmp_offload_params() - enable igmp offload
+ * @adapter: pointer to the adapter
+ * @enable: enable/disable
+ *
+ * Return: nothing
+ */
+static QDF_STATUS
+hdd_send_igmp_offload_params(struct hdd_adapter *adapter,
+			     bool enable)
+{
+	struct in_device *in_dev = in_dev_get(adapter->dev);
+	struct ip_mc_list *ip_list = in_dev->mc_list;
+	struct pmo_igmp_offload_req *igmp_req = NULL;
+	int count = 0;
+	QDF_STATUS status;
+
+	if (!ip_list) {
+		hdd_debug("ip list empty");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	igmp_req = qdf_mem_malloc(sizeof(*igmp_req));
+	if (!igmp_req)
+		return QDF_STATUS_E_FAILURE;
+
+	while (ip_list && ip_list->multiaddr && enable &&
+	       count < MAX_MC_IP_ADDR) {
+		if (IGMP_QUERY_ADDRESS !=  ip_list->multiaddr) {
+			igmp_req->grp_ip_address[count] = ip_list->multiaddr;
+			count++;
+		}
+
+		ip_list = ip_list->next;
+	}
+	igmp_req->enable = enable;
+	igmp_req->num_grp_ip_address = count;
+
+	status = ucfg_pmo_enable_igmp_offload(adapter->vdev, igmp_req);
+	if (status != QDF_STATUS_SUCCESS)
+		hdd_info("Failed to enable igmp offload");
+
+	qdf_mem_free(igmp_req);
+	return status;
+}
+
+/**
+ * hdd_enable_igmp_offload() - enable GTK offload
+ * @adapter: pointer to the adapter
+ *
+ * Enable IGMP offload in suspended case to save power
+ *
+ * Return: nothing
+ */
+static void hdd_enable_igmp_offload(struct hdd_adapter *adapter)
+{
+	QDF_STATUS status;
+	struct wlan_objmgr_vdev *vdev;
+
+	vdev = hdd_objmgr_get_vdev_by_user(adapter, WLAN_OSIF_POWER_ID);
+	if (!vdev) {
+		hdd_err("vdev is NULL");
+		return;
+	}
+	status = hdd_send_igmp_offload_params(adapter, true);
+	if (status != QDF_STATUS_SUCCESS)
+		hdd_info("Failed to enable gtk offload");
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
+}
+#else
+static inline void
+hdd_enable_igmp_offload(struct hdd_adapter *adapter)
+{}
+
+static inline QDF_STATUS
+hdd_send_igmp_offload_params(struct hdd_adapter *adapter,
+			     bool enable)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS
+wlan_hdd_send_igmp_offload_params(struct hdd_adapter *adapter, bool enable,
+				  uint32_t *mc_address, uint32_t count)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 /**
  * hdd_disable_gtk_offload() - disable GTK offload
  * @adapter:   pointer to the adapter
@@ -720,6 +812,9 @@ void hdd_enable_host_offloads(struct hdd_adapter *adapter,
 	hdd_enable_arp_offload(adapter, trigger);
 	hdd_enable_ns_offload(adapter, trigger);
 	hdd_enable_mc_addr_filtering(adapter, trigger);
+	if (adapter->device_mode == QDF_STA_MODE)
+		hdd_enable_igmp_offload(adapter);
+
 	if (adapter->device_mode != QDF_NDI_MODE)
 		hdd_enable_hw_filter(adapter);
 	hdd_enable_action_frame_patterns(adapter);

+ 4 - 0
core/wma/inc/wma_tgt_cfg.h

@@ -48,6 +48,7 @@
  * @is_get_station_clubbed_in_ll_stats_req: Get station req support within ll
  *                                          stats req
  * @is_fw_therm_throt_supp: Get thermal throttling threshold
+ * @igmp_offload_enable: Get igmp offload enable or disable
  */
 struct wma_tgt_services {
 	uint32_t sta_power_save;
@@ -86,6 +87,9 @@ struct wma_tgt_services {
 	bool is_get_station_clubbed_in_ll_stats_req;
 #endif
 	bool is_fw_therm_throt_supp;
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+	bool igmp_offload_enable;
+#endif
 };
 
 /**

+ 24 - 0
core/wma/src/wma_main.c

@@ -4535,6 +4535,29 @@ static void wma_set_tx_partition_base(uint32_t value)
 }
 #endif
 
+#ifdef WLAN_FEATURE_IGMP_OFFLOAD
+/**
+ * wma_get_igmp_offload_enable() - update tgt service with igmp offload support
+ * @wmi_handle: Unified wmi handle
+ * @cfg: target services
+ *
+ * Return: none
+ */
+static inline void
+wma_get_igmp_offload_enable(struct wmi_unified *wmi_handle,
+			    struct wma_tgt_services *cfg)
+{
+	cfg->igmp_offload_enable = wmi_service_enabled(
+					wmi_handle,
+					wmi_service_igmp_offload_support);
+}
+#else
+static inline void
+wma_get_igmp_offload_enable(struct wmi_unified *wmi_handle,
+			    struct wma_tgt_services *cfg)
+{}
+#endif
+
 /**
  * wma_update_target_services() - update target services from wma handle
  * @wmi_handle: Unified wmi handle
@@ -4675,6 +4698,7 @@ static inline void wma_update_target_services(struct wmi_unified *wmi_handle,
 
 	wma_get_service_cap_club_get_sta_in_ll_stats_req(wmi_handle, cfg);
 
+	wma_get_igmp_offload_enable(wmi_handle, cfg);
 }
 
 /**