From da6d60c72fe2a23a0fd0fd44860c91f0ce5c3a88 Mon Sep 17 00:00:00 2001
From: "Bisht Kshitij (IFINS CSS ICW ENG SW WFSW 1)"
 <kshitij.bisht@infineon.com>
Date: Fri, 31 Mar 2023 15:01:43 +0000
Subject: [PATCH 183/301] brcmfmac: offload: add configuration infrastructure
 support using mod param

Provide offload infrastructure support using user driven power profile from
host if offload infra is implemented in firmware to start all the offloads
in a preset configuration.

Below mentioned module params can be set during insmod,
offload_prof - 1:LOW / 2:MID / 3:HIGH power
offload_feat - list of all offloads for default (LOW power) or user
	       configured power profile. Ex: ARP, ND, GTKOE, WOWLPF etc...

User doesn't have to configure parameters of different offload but only
have to provide a suitable power profile which will enable all the required
offloads in their preset configurations. It can also activate or deactivate
the offload according to the "suspend or resume" host power. An offload may
remain activated depending on the power profile.


Signed-off-by: Bisht Kshitij (IFINS CSS ICW ENG SW WFSW 1) <kshitij.bisht@infineon.com>
Signed-off-by: Shelley Yang <shelley.yang@infineon.com>
---
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 0011e0f36..09acde807 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -4688,6 +4688,12 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
 			cfg->wowl.nd_enabled = false;
 		}
 	}
+	/* During resume, disable all offload modules which are enabled
+	 * previously while entering suspend.
+	 */
+	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_OFFLOADS))
+		brcmf_generic_offload_enable(ifp, brcmf_offload_feat, false);
+
 	config->pm_state = BRCMF_CFG80211_PM_STATE_RESUMED;
 	return 0;
 }
@@ -4792,6 +4798,13 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
 	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
 		brcmf_abort_scanning(cfg);
 
+	/* Enable offload features that were not in default (LOW) or user selected
+	 * power profile but should be offloaded to fw in suspend as host goes to
+	 * sleep. These will be disabled on resume.
+	 */
+	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_OFFLOADS))
+		brcmf_generic_offload_enable(ifp, brcmf_offload_feat, true);
+
 	if (!wowl || !test_bit(BRCMF_VIF_STATUS_CONNECTED,
 			       &ifp->vif->sme_state)) {
 		brcmf_bus_wowl_config(cfg->pub->bus_if, false);
@@ -4820,6 +4833,8 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
 			/* Prevent disassociation due to inactivity with keep-alive */
 			brcmf_keepalive_start(ifp, 30);
 		}
+		if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_OFFLOADS))
+			brcmf_generic_offload_enable(ifp, BRCMF_OL_WOWLPF, true);
 	}
 
 exit:
@@ -9666,6 +9681,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
 	s32 power_mode;
 	s32 eap_restrict;
 	s32 err = 0;
+	u32 wowl_config = 0;
 
 	if (cfg->dongle_up)
 		return err;
@@ -9702,7 +9718,22 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
 	if (err)
 		goto default_conf_out;
 
-	brcmf_configure_arp_nd_offload(ifp, true);
+	/* Configure user based power profile for offloads.
+	 * Default profile is LOW_PWR.
+	 */
+	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_OFFLOADS)) {
+		brcmf_generic_offload_config(ifp, brcmf_offload_feat,
+					     brcmf_offload_prof, false);
+
+		if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_ULP)) {
+			wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN;
+			err = brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
+			if (err < 0)
+				brcmf_err("wowl_flags DIS,BCN not set");
+		}
+	} else {
+		brcmf_configure_arp_nd_offload(ifp, true);
+	}
 
 	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_FAKEFRAG, 1);
 	if (err) {
@@ -9728,6 +9759,13 @@ static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
 {
 	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
 
+	/* Disable all offloads started on brcmf_config_dongle before
+	 * link is brought down.
+	 */
+	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_OFFLOADS))
+		brcmf_generic_offload_config(ifp, brcmf_offload_feat,
+					     brcmf_offload_prof, true);
+
 	/*
 	 * While going down, if associated with AP disassociate
 	 * from AP to save power
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index b9cd230b6..873bcda11 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -108,6 +108,25 @@ static int brcmf_sdio_rxf_in_kthread;
 module_param_named(sdio_rxf_thread, brcmf_sdio_rxf_in_kthread, int, 0400);
 MODULE_PARM_DESC(sdio_rxf_thread, "SDIO RX Frame in Kthread");
 
+unsigned int brcmf_offload_prof = BRCMF_OL_PROF_TYPE_LOW_PWR;
+module_param_named(offload_prof, brcmf_offload_prof, uint, 0400);
+MODULE_PARM_DESC(offload_prof,
+		 "Offload power profile: 1:low 2:mid 3:high (default:1)");
+
+unsigned int brcmf_offload_feat = BRCMF_OL_ARP |
+				  BRCMF_OL_ND |
+				  BRCMF_OL_BDO |
+				  BRCMF_OL_ICMP |
+				  BRCMF_OL_TKO |
+				  BRCMF_OL_DLTRO |
+				  BRCMF_OL_PNO |
+				  BRCMF_OL_KEEPALIVE |
+				  BRCMF_OL_GTKOE;
+module_param_named(offload_feat, brcmf_offload_feat, uint, 0400);
+MODULE_PARM_DESC(offload_feat,
+		 "Offload feat bitmap: 0:arp 1:nd 2:mdns 3:icmp 4:tcp-keepalive "
+		 "5:dhcp-renewal 6:pno 7:keepalive 8:gtk 9:wowlpf (default: 0x1FF)");
+
 static struct brcmfmac_platform_data *brcmfmac_pdata;
 struct brcmf_mp_global_t brcmf_mp_global;
 
@@ -117,6 +136,109 @@ static struct notifier_block brcmf_reboot_notifier = {
 	.priority = 1,
 };
 
+/* Offload features to firmware based on a user based power profile using module param
+ * offload_prof and offload_feat (provides flag list of all offloads).
+ * Default power profile : LowPwr with all offloads enabled.
+ */
+void brcmf_generic_offload_config(struct brcmf_if *ifp, unsigned int ol_feat,
+				  unsigned int ol_profile, bool reset)
+{
+	struct brcmf_ol_cfg_v1 ol_cfg = {0};
+	u32 ol_feat_skip = ~ol_feat;
+	int err = 0;
+
+	ol_cfg.ver = BRCMF_OL_CFG_VER_1;
+	ol_cfg.len = sizeof(ol_cfg);
+	ol_cfg.id = BRCMF_OL_CFG_ID_PROF;
+	ol_cfg.offload_skip = ol_feat_skip;
+	ol_cfg.u.ol_profile.reset = reset;
+	ol_cfg.u.ol_profile.type = ol_profile;
+
+	err = brcmf_fil_iovar_data_set(ifp, "offload_config", &ol_cfg,
+				       sizeof(ol_cfg));
+	if (err < 0)
+		brcmf_err("failed to %s generic offload profile:%u feat:0x%x, err = %d",
+			  reset ? "reset" : "set", ol_profile, ol_feat, err);
+	else
+		brcmf_info("successfully %s generic offload profile:%u feat:0x%x",
+			   reset ? "reset" : "set", ol_profile, ol_feat);
+}
+
+/* Enable specific offloads that are not enabled in a power profile but have
+ * to be enabled in suspend state as host goes to sleep.
+ */
+void brcmf_generic_offload_enable(struct brcmf_if *ifp, unsigned int ol_feat,
+				  bool enable)
+{
+	struct brcmf_ol_cfg_v1 ol_cfg = {0};
+	u32 ol_feat_skip = ~ol_feat;
+	int err = 0;
+
+	ol_cfg.ver = BRCMF_OL_CFG_VER_1;
+	ol_cfg.len = sizeof(ol_cfg);
+	ol_cfg.id = BRCMF_OL_CFG_ID_ACTIVATE;
+	ol_cfg.u.ol_activate.enable = enable;
+	ol_cfg.offload_skip = ol_feat_skip;
+
+	err = brcmf_fil_iovar_data_set(ifp, "offload_config", &ol_cfg,
+				       sizeof(ol_cfg));
+	if (err < 0)
+		brcmf_err("failed to %s generic offload feat:0x%x, err = %d",
+			  enable ? "enable" : "disable", ol_feat, err);
+	else
+		brcmf_info("successfully %s generic offload feat:0x%x",
+			   enable ? "enabled" : "disabled", ol_feat);
+}
+
+void brcmf_generic_offload_host_ipv4_update(struct brcmf_if *ifp, unsigned int ol_feat,
+					    u32 ipaddr, bool is_add)
+{
+	struct brcmf_ol_cfg_v1 ol_cfg = {0};
+	u32 ol_feat_skip = ~ol_feat;
+	int err = 0;
+
+	ol_cfg.ver = BRCMF_OL_CFG_VER_1;
+	ol_cfg.len = sizeof(ol_cfg);
+	ol_cfg.id = BRCMF_OL_CFG_ID_INET_V4;
+	ol_cfg.u.ol_inet_v4.del = !is_add;
+	memcpy(ol_cfg.u.ol_inet_v4.host_ipv4.addr, &ipaddr, sizeof(struct ipv4_addr));
+	ol_cfg.offload_skip = ol_feat_skip;
+
+	err = brcmf_fil_iovar_data_set(ifp, "offload_config", &ol_cfg,
+				       sizeof(ol_cfg));
+	if (err < 0)
+		brcmf_err("failed to %s generic offload host address %pI4, err = %d",
+			  is_add ? "add" : "del", &ipaddr, err);
+	else
+		brcmf_dbg(TRACE, "successfully %s generic offload host address %pI4",
+			  is_add ? "added" : "deleted", &ipaddr);
+}
+
+void brcmf_generic_offload_host_ipv6_update(struct brcmf_if *ifp, unsigned int ol_feat,
+					    void *ptr, u8 type, bool is_add)
+{
+	struct brcmf_ol_cfg_v1 ol_cfg = {0};
+	u32 ol_feat_skip = ~ol_feat;
+	int err = 0;
+
+	ol_cfg.ver = BRCMF_OL_CFG_VER_1;
+	ol_cfg.len = sizeof(ol_cfg);
+	ol_cfg.id = BRCMF_OL_CFG_ID_INET_V6;
+	ol_cfg.u.ol_inet_v6.del = !is_add;
+	ol_cfg.u.ol_inet_v6.type = type;
+	memcpy(ol_cfg.u.ol_inet_v6.host_ipv6.addr, ptr, sizeof(struct ipv6_addr));
+	ol_cfg.offload_skip = ol_feat_skip;
+
+	err = brcmf_fil_iovar_data_set(ifp, "offload_config", &ol_cfg,
+				       sizeof(ol_cfg));
+	if (err < 0)
+		brcmf_err("failed to %s host address %pI6 err = %d",
+			  is_add ? "add" : "del", ptr, err);
+	else
+		brcmf_dbg(TRACE, "successfully %s host address %pI6",
+			  is_add ? "add" : "del", ptr);
+}
+
 void brcmf_c_set_joinpref_default(struct brcmf_if *ifp)
 {
 	struct brcmf_pub *drvr = ifp->drvr;
@@ -630,6 +752,14 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
 	settings->pkt_prio = !!brcmf_pkt_prio_enable;
 	settings->sdio_rxf_in_kthread_enabled = !!brcmf_sdio_rxf_in_kthread;
 
+	if (brcmf_offload_prof >= BRCMF_OL_PROF_TYPE_MAX) {
+		brcmf_err("Invalid Offload power profile %u, using default profile 1",
+			  brcmf_offload_prof);
+		brcmf_offload_prof = BRCMF_OL_PROF_TYPE_LOW_PWR;
+	}
+	settings->offload_prof = brcmf_offload_prof;
+	settings->offload_feat = brcmf_offload_feat;
+
 	if (bus_type == BRCMF_BUSTYPE_SDIO)
 		settings->bus.sdio.txglomsz = brcmf_sdiod_txglomsz;
 
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
index 8a6657ab0..5a32f64a4 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
@@ -44,6 +44,8 @@ extern struct brcmf_mp_global_t brcmf_mp_global;
  * @fw_ap_select: Allow FW to select AP.
  * @disable_6ghz: Disable 6GHz operation
  * @sdio_in_isr: Handle SDIO DPC in ISR.
+ * @offload_prof: Enable offloads configuration power profile (Low,Mid,High)
+ * @offload_feat: offloads feature flags to be enabled for selected pwr profile
  * @country_codes: If available, pointer to struct for translating country codes
  * @bus: Bus specific platform data. Only SDIO at the mmoment.
  * @pkt_prio: Support customer dscp to WMM up mapping.
@@ -62,6 +64,8 @@ struct brcmf_mp_device {
 	bool		disable_6ghz;
 	bool		sdio_in_isr;
 	bool		sdio_rxf_in_kthread_enabled;
+	unsigned int	offload_prof;
+	unsigned int	offload_feat;
 	struct brcmfmac_pd_cc *country_codes;
 	const char	*board_type;
 	unsigned char	mac[ETH_ALEN];
@@ -105,4 +109,13 @@ u8 brcmf_map_prio_to_prec(void *cfg, u8 prio);
 
 u8 brcmf_map_prio_to_aci(void *cfg, u8 prio);
 
+void brcmf_generic_offload_config(struct brcmf_if *ifp, unsigned int ol_feat,
+				  unsigned int ol_profile, bool reset);
+void brcmf_generic_offload_enable(struct brcmf_if *ifp, unsigned int ol_feat,
+				  bool enable);
+void brcmf_generic_offload_host_ipv4_update(struct brcmf_if *ifp, unsigned int ol_feat,
+					    u32 ipaddr, bool is_add);
+void brcmf_generic_offload_host_ipv6_update(struct brcmf_if *ifp, unsigned int ol_feat,
+					    void *ptr, u8 type, bool is_add);
+
 #endif /* BRCMFMAC_COMMON_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index f688d627c..7c1fae306 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -1314,7 +1314,7 @@ static int brcmf_inetaddr_changed(struct notifier_block *nb,
 	struct in_ifaddr *ifa = data;
 	struct net_device *ndev = ifa->ifa_dev->dev;
 	struct brcmf_if *ifp;
-	int idx, i, ret;
+	int idx, i = 0, ret;
 	u32 val;
 	__be32 addr_table[ARPOL_MAX_ENTRIES] = {0};
 
@@ -1327,64 +1327,79 @@ static int brcmf_inetaddr_changed(struct notifier_block *nb,
 			return NOTIFY_DONE;
 	}
 
-	/* check if arp offload is supported */
-	ret = brcmf_fil_iovar_int_get(ifp, "arpoe", &val);
-	if (ret)
-		return NOTIFY_OK;
+	if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_OFFLOADS)) {
+		/* check if arp offload is supported */
+		ret = brcmf_fil_iovar_int_get(ifp, "arpoe", &val);
+		if (ret)
+			return NOTIFY_OK;
 
-	/* old version only support primary index */
-	ret = brcmf_fil_iovar_int_get(ifp, "arp_version", &val);
-	if (ret)
-		val = 1;
-	if (val == 1)
-		ifp = drvr->iflist[0];
+		/* old version only support primary index */
+		ret = brcmf_fil_iovar_int_get(ifp, "arp_version", &val);
+		if (ret)
+			val = 1;
+		if (val == 1)
+			ifp = drvr->iflist[0];
 
-	/* retrieve the table from firmware */
-	ret = brcmf_fil_iovar_data_get(ifp, "arp_hostip", addr_table,
-				       sizeof(addr_table));
-	if (ret) {
-		bphy_err(drvr, "fail to get arp ip table err:%d\n", ret);
-		return NOTIFY_OK;
-	}
+		/* retrieve the table from firmware */
+		ret = brcmf_fil_iovar_data_get(ifp, "arp_hostip", addr_table,
+					       sizeof(addr_table));
+		if (ret) {
+			bphy_err(drvr, "fail to get arp ip table err:%d\n", ret);
+			return NOTIFY_OK;
+		}
 
-	for (i = 0; i < ARPOL_MAX_ENTRIES; i++)
-		if (ifa->ifa_address == addr_table[i])
-			break;
+		for (i = 0; i < ARPOL_MAX_ENTRIES; i++)
+			if (ifa->ifa_address == addr_table[i])
+				break;
+	}
 
 	switch (action) {
 	case NETDEV_UP:
-		if (i == ARPOL_MAX_ENTRIES) {
-			brcmf_dbg(TRACE, "add %pI4 to arp table\n",
-				  &ifa->ifa_address);
-			/* set it directly */
-			ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip",
-				&ifa->ifa_address, sizeof(ifa->ifa_address));
-			if (ret)
-				bphy_err(drvr, "add arp ip err %d\n", ret);
+		if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_OFFLOADS)) {
+			brcmf_generic_offload_host_ipv4_update(ifp,
+							       BRCMF_OL_ARP | BRCMF_OL_ICMP,
+							       ifa->ifa_address, true);
+		} else {
+			if (i == ARPOL_MAX_ENTRIES) {
+				brcmf_dbg(TRACE, "add %pI4 to arp table\n",
+					  &ifa->ifa_address);
+				/* set it directly */
+				ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip",
+							       &ifa->ifa_address,
+							       sizeof(ifa->ifa_address));
+				if (ret)
+					bphy_err(drvr, "add arp ip err %d\n", ret);
+			}
 		}
 		break;
 	case NETDEV_DOWN:
-		if (i < ARPOL_MAX_ENTRIES) {
-			addr_table[i] = 0;
-			brcmf_dbg(TRACE, "remove %pI4 from arp table\n",
-				  &ifa->ifa_address);
-			/* clear the table in firmware */
-			ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear",
-						       NULL, 0);
-			if (ret) {
-				bphy_err(drvr, "fail to clear arp ip table err:%d\n",
-					 ret);
-				return NOTIFY_OK;
-			}
-			for (i = 0; i < ARPOL_MAX_ENTRIES; i++) {
-				if (addr_table[i] == 0)
-					continue;
-				ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip",
-							       &addr_table[i],
-							       sizeof(addr_table[i]));
-				if (ret)
-					bphy_err(drvr, "add arp ip err %d\n",
+		if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_OFFLOADS)) {
+			brcmf_generic_offload_host_ipv4_update(ifp,
+							       BRCMF_OL_ARP | BRCMF_OL_ICMP,
+							       ifa->ifa_address, false);
+		} else {
+			if (i < ARPOL_MAX_ENTRIES) {
+				addr_table[i] = 0;
+				brcmf_dbg(TRACE, "remove %pI4 from arp table\n",
+					  &ifa->ifa_address);
+				/* clear the table in firmware */
+				ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear",
+							       NULL, 0);
+				if (ret) {
+					bphy_err(drvr, "fail to clear arp ip table err:%d\n",
 						 ret);
+					return NOTIFY_OK;
+				}
+				for (i = 0; i < ARPOL_MAX_ENTRIES; i++) {
+					if (addr_table[i] == 0)
+						continue;
+					ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip",
+								       &addr_table[i],
+								       sizeof(addr_table[i]));
+					if (ret)
+						bphy_err(drvr, "add arp ip err %d\n",
+							 ret);
+				}
 			}
 		}
 		break;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
index c4005dcc5..450807d6c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -50,6 +50,8 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = {
 	{ BRCMF_FEAT_FBT, "fbt " },
 	{ BRCMF_FEAT_OKC, "okc" },
 	{ BRCMF_FEAT_GCMP, "gcmp" },
+	{ BRCMF_FEAT_OFFLOADS, "offloads" },
+	{ BRCMF_FEAT_ULP, "ulp" },
 };
 
 #ifdef DEBUG
@@ -426,3 +428,11 @@ bool brcmf_feat_is_sdio_rxf_in_kthread(struct brcmf_pub *drvr)
 	else
 		return false;
 }
+
+bool brcmf_feat_is_offloads_enabled(struct brcmf_if *ifp)
+{
+	if (ifp && ifp->drvr)
+		return ifp->drvr->settings->offload_prof;
+
+	return false;
+}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
index eceee1129..a91554883 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
@@ -34,6 +34,11 @@
  * SAE_EXT: SAE be handled by userspace supplicant
  * GCMP: firmware has defined GCMP or not.
  * TWT: Firmware has the TWT Module Support.
+ * OFFLOADS: Firmware can do the packet processing work offloaded by
+ *	Host Driver, i.e, it can process specifc types of RX packets like
+ *	ARP, ND, etc and send out a suitable response packet from within
+ * 	Firmware.
+ * ULP: Firmware supports Ultra Low Power mode of operation.
  */
 #define BRCMF_FEAT_LIST \
 	BRCMF_FEAT_DEF(MBSS) \
@@ -65,7 +70,9 @@
 	BRCMF_FEAT_DEF(FBT) \
 	BRCMF_FEAT_DEF(OKC) \
 	BRCMF_FEAT_DEF(GCMP) \
-	BRCMF_FEAT_DEF(TWT)
+	BRCMF_FEAT_DEF(TWT) \
+	BRCMF_FEAT_DEF(OFFLOADS) \
+	BRCMF_FEAT_DEF(ULP)
 
 /*
  * Quirks:
@@ -150,4 +157,14 @@ bool brcmf_feat_is_6ghz_enabled(struct brcmf_if *ifp);
  */
 bool brcmf_feat_is_sdio_rxf_in_kthread(struct brcmf_pub *drvr);
 
+/**
+ * brcmf_feat_is_offloads_enabled() - Find if offload_prof power profile
+ * is given by user
+ *
+ * @ifp: interface instance.
+ *
+ * Return: true if offloads_prof is set otherwise false.
+ */
+bool brcmf_feat_is_offloads_enabled(struct brcmf_if *ifp);
+
 #endif /* _BRCMF_FEATURE_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
index 06e24fd7e..1ce30bc49 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
@@ -145,6 +145,11 @@
 #define BRCMF_WOWL_MAXPATTERNS		16
 #define BRCMF_WOWL_MAXPATTERNSIZE	128
 
+/* IPV4 address length */
+#define BRCMF_IPV4_ADDR_LEN             4
+/* IPV6 address length */
+#define BRCMF_IPV6_ADDR_LEN             16
+
 #define BRCMF_COUNTRY_BUF_SZ		4
 #define BRCMF_ANT_MAX			4
 
@@ -204,6 +209,43 @@
 #define WL_RSSI_EVENT_BRCM_VERSION      0
 #define WL_RSSI_EVENT_IFX_VERSION       1
 
+/* Offloads profile configuration version */
+#define BRCMF_OL_CFG_VER_1		1
+
+extern unsigned int brcmf_offload_prof;
+extern unsigned int brcmf_offload_feat;
+
+/* Packet types to be offloaded to firmware for processing */
+enum brcmf_ol_feats {
+	BRCMF_OL_ARP = BIT(0),
+	BRCMF_OL_ND = BIT(1),
+	BRCMF_OL_BDO = BIT(2),
+	BRCMF_OL_ICMP = BIT(3),
+	BRCMF_OL_TKO = BIT(4),
+	BRCMF_OL_DLTRO = BIT(5),
+	BRCMF_OL_PNO = BIT(6),
+	BRCMF_OL_KEEPALIVE = BIT(7),
+	BRCMF_OL_GTKOE = BIT(8),
+	BRCMF_OL_WOWLPF	= BIT(9)
+};
+
+enum brcmf_ol_cfg_id {
+	BRCMF_OL_CFG_ID_PROF = 1,		/* Offload Profile Update */
+	BRCMF_OL_CFG_ID_INET_V4,		/* ADD/DEL IPv4 Address */
+	BRCMF_OL_CFG_ID_INET_V6,		/* ADD/DEL IPv6 Address */
+	BRCMF_OL_CFG_ID_ACTIVATE,		/* Activate/Deactivate Offload */
+	/*  Add new type before this line */
+	BRCMF_OL_CFG_ID_MAX			/* Max Offload Config ID */
+};
+
+enum brcmf_ol_prof_type {
+	BRCMF_OL_PROF_TYPE_LOW_PWR = 1,		/* Low Power Profile */
+	BRCMF_OL_PROF_TYPE_MID_PWR = 2,		/* Mid Power Profile */
+	BRCMF_OL_PROF_TYPE_HIGH_PWR = 3,	/* High Power Profile */
+	/*  Add new type before this line */
+	BRCMF_OL_PROF_TYPE_MAX			/* Max Offload Profile */
+};
+
 /* join preference types for join_pref iovar */
 enum brcmf_join_pref_types {
 	BRCMF_JOIN_PREF_RSSI = 1,
@@ -1304,4 +1346,44 @@ struct wl_rssi_event {
 	s8 pad[2];
 };
 
+struct ipv4_addr {
+	u8 addr[BRCMF_IPV4_ADDR_LEN];
+};
+
+struct ipv6_addr {
+	u8 addr[BRCMF_IPV6_ADDR_LEN];
+};
+
+/* Offload profile configuration */
+struct brcmf_ol_cfg_v1 {
+	u16 ver;					/* version of this structure */
+	u16 len;					/* length of structure in bytes */
+	enum brcmf_ol_cfg_id id;			/* Offload Config ID */
+
+	union {
+		struct {
+			enum brcmf_ol_prof_type type;	/* offload profile type */
+			bool reset;			/* Remove profile configuration */
+			u8 pad[3];
+		} ol_profile;
+		struct {
+			struct ipv4_addr host_ipv4;
+			bool del;			/* 1:del 0:add host ipv4 address */
+			u8 pad[3];
+		} ol_inet_v4;
+		struct {
+			struct ipv6_addr host_ipv6;
+			u8 type;			/* 0:unicast 1:anycast */
+			bool del;			/* 1:del 0:add host ipv6 address */
+			u8 pad[2];
+		} ol_inet_v6;
+		struct {
+			bool enable;			/* enable/disable offload feature */
+			u8 pad[3];
+		} ol_activate;
+	} u;
+
+	u32 offload_skip;				/* Bitmap of offload to be skipped */
+};
+
 #endif /* FWIL_TYPES_H_ */
