diff --git a/Kbuild b/Kbuild
index 694431f8dca7..d8914cdc0f27 100644
--- a/Kbuild
+++ b/Kbuild
@@ -277,6 +277,7 @@ CONFIG_FEATURE_TSO := y
CONFIG_TSO_DEBUG_LOG_ENABLE := y
CONFIG_DP_LFR := y
CONFIG_HTT_PADDR64 := y
+CONFIG_RX_OL := y
endif
# As per target team, build is done as follows:
@@ -526,6 +527,7 @@ ifeq ($(CONFIG_HELIUMPLUS), y)
ifneq ($(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE), y)
CONFIG_ENABLE_DEBUG_ADDRESS_MARKING := y
endif
+CONFIG_RX_OL := y
endif
ifeq ($(CONFIG_SLUB_DEBUG_ON), y)
@@ -2352,6 +2354,7 @@ cppflags-$(CONFIG_ATH_PROCFS_DIAG_SUPPORT) += -DCONFIG_ATH_PROCFS_DIAG_SUPPORT
cppflags-$(CONFIG_11AC_TXCOMPACT) += -DATH_11AC_TXCOMPACT
cppflags-$(CONFIG_HELIUMPLUS) += -DHELIUMPLUS
+cppflags-$(CONFIG_RX_OL) += -DRECEIVE_OFFLOAD
cppflags-$(CONFIG_AR900B) += -DAR900B
cppflags-$(CONFIG_HTT_PADDR64) += -DHTT_PADDR64
cppflags-$(CONFIG_OL_RX_INDICATION_RECORD) += -DOL_RX_INDICATION_RECORD
diff --git a/core/dp/htt/htt_internal.h b/core/dp/htt/htt_internal.h
index 974c31a419d7..1d7ee758ce37 100644
--- a/core/dp/htt/htt_internal.h
+++ b/core/dp/htt/htt_internal.h
@@ -179,7 +179,7 @@ static inline struct htt_host_rx_desc_base *htt_rx_desc(qdf_nbuf_t msdu)
~HTT_RX_DESC_ALIGN_MASK);
}
-#if defined(FEATURE_LRO) && defined(HELIUMPLUS)
+#if defined(HELIUMPLUS)
/**
* htt_print_rx_desc_lro() - print LRO information in the rx
* descriptor
@@ -265,7 +265,7 @@ static inline void htt_print_rx_desc_lro(struct htt_host_rx_desc_base *rx_desc)
{}
static inline void htt_rx_extract_lro_info(qdf_nbuf_t msdu,
struct htt_host_rx_desc_base *rx_desc) {}
-#endif /* FEATURE_LRO */
+#endif /* HELIUMPLUS */
static inline void htt_print_rx_desc(struct htt_host_rx_desc_base *rx_desc)
{
diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h
index 3e89ffc12a9d..907479ac53df 100644
--- a/core/hdd/inc/wlan_hdd_cfg.h
+++ b/core/hdd/inc/wlan_hdd_cfg.h
@@ -8628,6 +8628,27 @@ enum hdd_link_speed_rpt_type {
#define CFG_LRO_ENABLED_MAX (1)
#define CFG_LRO_ENABLED_DEFAULT (0)
+/*
+ *
+ * GROEnable - Control to enable gro feature
+ *
+ * @Disable: 0
+ * @Enable: 1
+ * @Default: 0
+ *
+ * This ini is used to enable GRO feature
+ *
+ * Supported Feature: GRO
+ *
+ * Usage: Internal
+ *
+ *
+ */
+#define CFG_GRO_ENABLED_NAME "GROEnable"
+#define CFG_GRO_ENABLED_MIN (0)
+#define CFG_GRO_ENABLED_MAX (1)
+#define CFG_GRO_ENABLED_DEFAULT (0)
+
/*
* Enable Rx traffic flow steering to enable Rx interrupts on multiple CEs based
* on the flows. Different CEs<==>different IRQs<==>probably different CPUs.
@@ -14794,6 +14815,7 @@ struct hdd_config {
bool send_deauth_before_con;
bool tso_enable;
bool lro_enable;
+ bool gro_enable;
bool flow_steering_enable;
uint8_t max_msdus_per_rxinorderind;
bool active_mode_offload;
diff --git a/core/hdd/inc/wlan_hdd_lro.h b/core/hdd/inc/wlan_hdd_lro.h
index 74d0aa6b52fe..a9eef0b61016 100644
--- a/core/hdd/inc/wlan_hdd_lro.h
+++ b/core/hdd/inc/wlan_hdd_lro.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018 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
@@ -26,22 +26,15 @@
struct hdd_context;
-/**
- * enum hdd_lro_rx_status - LRO receive frame status
- * @HDD_LRO_RX: frame sent over the LRO interface
- * @HDD_LRO_NO_RX: frame not sent over the LRO interface
- */
-enum hdd_lro_rx_status {
- HDD_LRO_RX = 0,
- HDD_LRO_NO_RX = 1,
-};
-
#if defined(FEATURE_LRO)
-int hdd_lro_init(struct hdd_context *hdd_ctx);
-
-enum hdd_lro_rx_status hdd_lro_rx(struct hdd_context *hdd_ctx,
- struct hdd_adapter *adapter,
- struct sk_buff *skb);
+/**
+ * hdd_lro_rx() - Handle Rx procesing via LRO
+ * @adapter: pointer to adapter context
+ * @skb: pointer to sk_buff
+ *
+ * Return: QDF_STATUS_SUCCESS if processed via LRO or non zero return code
+ */
+QDF_STATUS hdd_lro_rx(struct hdd_adapter *adapter, struct sk_buff *skb);
void hdd_lro_display_stats(struct hdd_context *hdd_ctx);
@@ -57,29 +50,16 @@ QDF_STATUS hdd_lro_set_reset(struct hdd_context *hdd_ctx,
struct hdd_adapter *adapter,
uint8_t enable_flag);
-void hdd_disable_lro_in_concurrency(bool disable);
-
-/**
- * hdd_disable_lro_for_low_tput() - enable/disable LRO based on tput
- * hdd_ctx: hdd context
- * disable: boolean to enable/disable LRO
- *
- * This API enables/disables LRO based on tput.
- *
- * Return: void
- */
-void hdd_disable_lro_for_low_tput(struct hdd_context *hdd_ctx, bool disable);
#else
static inline int hdd_lro_init(struct hdd_context *hdd_ctx)
{
return 0;
}
-static inline enum hdd_lro_rx_status hdd_lro_rx(struct hdd_context *hdd_ctx,
- struct hdd_adapter *adapter,
- struct sk_buff *skb)
+static inline QDF_STATUS hdd_lro_rx(struct hdd_adapter *adapter,
+ struct sk_buff *skb)
{
- return HDD_LRO_NO_RX;
+ return QDF_STATUS_E_NOSUPPORT;
}
static inline void hdd_lro_display_stats(struct hdd_context *hdd_ctx)
@@ -92,14 +72,5 @@ static inline QDF_STATUS hdd_lro_set_reset(struct hdd_context *hdd_ctx,
{
return 0;
}
-
-static inline void hdd_disable_lro_in_concurrency(bool disable)
-{
-}
-
-static inline void
-hdd_disable_lro_for_low_tput(struct hdd_context *hdd_ctx, bool disable)
-{
-}
#endif /* FEATURE_LRO */
#endif /* __WLAN_HDD_LRO_H__ */
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index f0ae7b6297cb..17488e41a214 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -1622,6 +1622,16 @@ enum tos {
#define HDD_AC_BIT_INDX 0
#define HDD_DWELL_TIME_INDX 1
+/**
+ * enum RX_OFFLOAD - Receive offload modes
+ * @CFG_LRO_ENABLED: Large Rx offload
+ * @CFG_GRO_ENABLED: Generic Rx Offload
+ */
+enum RX_OFFLOAD {
+ CFG_LRO_ENABLED = 1,
+ CFG_GRO_ENABLED,
+};
+
/* One per STA: 1 for BCMC_STA_ID, 1 for each SAP_SELF_STA_ID,
* 1 for WDS_STAID
*/
@@ -1821,6 +1831,7 @@ struct hdd_context {
qdf_work_t sap_pre_cac_work;
bool hbw_requested;
uint32_t last_nil_scan_bug_report_timestamp;
+ enum RX_OFFLOAD ol_enable;
#ifdef WLAN_FEATURE_NAN_DATAPATH
bool nan_datapath_enabled;
#endif
@@ -1876,6 +1887,8 @@ struct hdd_context {
bool imps_enabled;
int user_configured_pkt_filter_rules;
bool is_fils_roaming_supported;
+ QDF_STATUS (*receive_offload_cb)(struct hdd_adapter *,
+ struct sk_buff *);
qdf_atomic_t vendor_disable_lro_flag;
qdf_atomic_t disable_lro_in_concurrency;
qdf_atomic_t disable_lro_in_low_tput;
diff --git a/core/hdd/inc/wlan_hdd_tx_rx.h b/core/hdd/inc/wlan_hdd_tx_rx.h
index efa0369bf9d0..8f9adbe3edc7 100644
--- a/core/hdd/inc/wlan_hdd_tx_rx.h
+++ b/core/hdd/inc/wlan_hdd_tx_rx.h
@@ -57,6 +57,31 @@ QDF_STATUS hdd_init_tx_rx(struct hdd_adapter *adapter);
QDF_STATUS hdd_deinit_tx_rx(struct hdd_adapter *adapter);
QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf);
+/**
+ * hdd_rx_ol_init() - Initialize Rx mode(LRO or GRO) method
+ * @hdd_ctx: pointer to HDD Station Context
+ *
+ * Return: 0 on success and non zero on failure.
+ */
+int hdd_rx_ol_init(struct hdd_context *hdd_ctx);
+
+/**
+ * hdd_disable_rx_ol_in_concurrency() - Disable Rx offload due to concurrency
+ * @disable: true/false to disable/enable the Rx offload
+ *
+ * Return: none
+ */
+void hdd_disable_rx_ol_in_concurrency(bool disable);
+
+/**
+ * hdd_disable_rx_ol_for_low_tput() - Disable Rx offload in low TPUT scenario
+ * @hdd_ctx: hdd context
+ * @disable: true/false to disable/enable the Rx offload
+ *
+ * Return: none
+ */
+void hdd_disable_rx_ol_for_low_tput(struct hdd_context *hdd_ctx, bool disable);
+
QDF_STATUS hdd_get_peer_sta_id(struct hdd_station_ctx *sta_ctx,
struct qdf_mac_addr *peer_mac_addr,
uint8_t *sta_id);
diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c
index 5c75214e3ad1..f5974454be73 100644
--- a/core/hdd/src/wlan_hdd_cfg.c
+++ b/core/hdd/src/wlan_hdd_cfg.c
@@ -3457,6 +3457,13 @@ struct reg_table_entry g_registry_table[] = {
CFG_LRO_ENABLED_MIN,
CFG_LRO_ENABLED_MAX),
+ REG_VARIABLE(CFG_GRO_ENABLED_NAME, WLAN_PARAM_Integer,
+ struct hdd_config, gro_enable,
+ VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+ CFG_GRO_ENABLED_DEFAULT,
+ CFG_GRO_ENABLED_MIN,
+ CFG_GRO_ENABLED_MAX),
+
REG_VARIABLE(CFG_BPF_PACKET_FILTER_OFFLOAD, WLAN_PARAM_Integer,
struct hdd_config, bpf_packet_filter_enable,
VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
diff --git a/core/hdd/src/wlan_hdd_lro.c b/core/hdd/src/wlan_hdd_lro.c
index c25d0702e230..189f5456fe73 100644
--- a/core/hdd/src/wlan_hdd_lro.c
+++ b/core/hdd/src/wlan_hdd_lro.c
@@ -39,75 +39,11 @@
LRO_TCP_DATA_CSUM | LRO_TCP_SEQ_NUM | LRO_TCP_WIN)
#if defined(QCA_WIFI_QCA6290)
-/**
- * hdd_lro_init() - initialization for LRO
- * @hdd_ctx: HDD context
- *
- * This function sends the LRO configuration to the firmware
- * via WMA
- * Make sure that this function gets called after NAPI
- * instances have been created.
- *
- * Return: 0 - success, < 0 - failure
- */
-int hdd_lro_init(struct hdd_context *hdd_ctx)
-{
- return 0;
-}
-
static qdf_lro_ctx_t wlan_hdd_get_lro_ctx(struct sk_buff *skb)
{
return (qdf_lro_ctx_t)QDF_NBUF_CB_RX_LRO_CTX(skb);
}
#else
-/**
- * hdd_lro_init() - initialization for LRO
- * @hdd_ctx: HDD context
- *
- * This function sends the LRO configuration to the firmware
- * via WMA
- * Make sure that this function gets called after NAPI
- * instances have been created.
- *
- * Return: 0 - success, < 0 - failure
- */
-int hdd_lro_init(struct hdd_context *hdd_ctx)
-{
- struct cdp_lro_hash_config lro_config;
-
- if ((!hdd_ctx->config->lro_enable) &&
- (hdd_napi_enabled(HDD_NAPI_ANY) == 0)) {
- hdd_warn("LRO and NAPI are both disabled");
- return QDF_STATUS_E_FAILURE;
- }
-
- lro_config.lro_enable = 1;
- lro_config.tcp_flag = TCPHDR_ACK;
- lro_config.tcp_flag_mask = TCPHDR_FIN | TCPHDR_SYN | TCPHDR_RST |
- TCPHDR_ACK | TCPHDR_URG | TCPHDR_ECE | TCPHDR_CWR;
-
- get_random_bytes(lro_config.toeplitz_hash_ipv4,
- (sizeof(lro_config.toeplitz_hash_ipv4[0]) *
- LRO_IPV4_SEED_ARR_SZ));
-
- get_random_bytes(lro_config.toeplitz_hash_ipv6,
- (sizeof(lro_config.toeplitz_hash_ipv6[0]) *
- LRO_IPV6_SEED_ARR_SZ));
-
- hdd_debug("sending the LRO configuration to the fw");
- if (0 != wma_lro_init(&lro_config)) {
- hdd_err("Failed to send LRO configuration!");
- hdd_ctx->config->lro_enable = 0;
- return -EAGAIN;
- }
-
- if (hdd_ctx->config->enable_tcp_delack) {
- hdd_ctx->en_tcp_delack_no_lro = 0;
- hdd_reset_tcp_delack(hdd_ctx);
- }
- return 0;
-}
-
static qdf_lro_ctx_t wlan_hdd_get_lro_ctx(struct sk_buff *skb)
{
struct hif_opaque_softc *hif_hdl =
@@ -123,71 +59,55 @@ static qdf_lro_ctx_t wlan_hdd_get_lro_ctx(struct sk_buff *skb)
/**
* hdd_lro_rx() - LRO receive function
- * @hdd_ctx: HDD context
* @adapter: HDD adapter
* @skb: network buffer
*
* Delivers LRO eligible frames to the LRO manager
*
- * Return: HDD_LRO_RX - frame delivered to LRO manager
- * HDD_LRO_NO_RX - frame not delivered
+ * Return: QDF_STATUS_SUCCESS - frame delivered to LRO manager
+ * QDF_STATUS_E_FAILURE - frame not delivered
*/
-enum hdd_lro_rx_status hdd_lro_rx(struct hdd_context *hdd_ctx,
- struct hdd_adapter *adapter, struct sk_buff *skb)
+QDF_STATUS hdd_lro_rx(struct hdd_adapter *adapter, struct sk_buff *skb)
{
qdf_lro_ctx_t ctx;
- enum hdd_lro_rx_status status = HDD_LRO_NO_RX;
+ QDF_STATUS status = QDF_STATUS_E_FAILURE;
+ struct qdf_lro_info info;
+ struct net_lro_desc *lro_desc = NULL;
- if (((adapter->dev->features & NETIF_F_LRO) != NETIF_F_LRO) ||
- !QDF_NBUF_CB_RX_TCP_PROTO(skb) ||
- QDF_NBUF_CB_RX_PEER_CACHED_FRM(skb) ||
- qdf_atomic_read(&hdd_ctx->disable_lro_in_concurrency) ||
- qdf_atomic_read(&hdd_ctx->disable_lro_in_low_tput))
- return HDD_LRO_NO_RX;
+ if ((adapter->dev->features & NETIF_F_LRO) != NETIF_F_LRO)
+ return QDF_STATUS_E_NOSUPPORT;
- {
- struct qdf_lro_info info;
- struct net_lro_desc *lro_desc = NULL;
- struct hif_opaque_softc *hif_hdl =
- (struct hif_opaque_softc *)cds_get_context(
- QDF_MODULE_ID_HIF);
- if (hif_hdl == NULL) {
- hdd_err("hif_hdl is NULL");
- return status;
- }
+ ctx = wlan_hdd_get_lro_ctx(skb);
+ if (!ctx) {
+ hdd_err("LRO mgr is NULL");
+ return status;
+ }
- ctx = wlan_hdd_get_lro_ctx(skb);
- if (ctx == NULL) {
- hdd_err("LRO mgr is NULL, vdev could be going down");
- return status;
- }
+ info.iph = skb->data;
+ info.tcph = skb->data + QDF_NBUF_CB_RX_TCP_OFFSET(skb);
+ ctx->lro_mgr->dev = adapter->dev;
+ if (qdf_lro_get_info(ctx, skb, &info, (void **)&lro_desc)) {
+ struct net_lro_info hdd_lro_info;
- info.iph = skb->data;
- info.tcph = skb->data + QDF_NBUF_CB_RX_TCP_OFFSET(skb);
- ctx->lro_mgr->dev = adapter->dev;
- if (qdf_lro_get_info(ctx, skb, &info, (void **)&lro_desc)) {
- struct net_lro_info hdd_lro_info;
+ hdd_lro_info.valid_fields = LRO_VALID_FIELDS;
- hdd_lro_info.valid_fields = LRO_VALID_FIELDS;
+ hdd_lro_info.lro_desc = lro_desc;
+ hdd_lro_info.lro_eligible = 1;
+ hdd_lro_info.tcp_ack_num = QDF_NBUF_CB_RX_TCP_ACK_NUM(skb);
+ hdd_lro_info.tcp_data_csum =
+ csum_unfold(htons(QDF_NBUF_CB_RX_TCP_CHKSUM(skb)));
+ hdd_lro_info.tcp_seq_num = QDF_NBUF_CB_RX_TCP_SEQ_NUM(skb);
+ hdd_lro_info.tcp_win = QDF_NBUF_CB_RX_TCP_WIN(skb);
- hdd_lro_info.lro_desc = lro_desc;
- hdd_lro_info.lro_eligible = 1;
- hdd_lro_info.tcp_ack_num = QDF_NBUF_CB_RX_TCP_ACK_NUM(skb);
- hdd_lro_info.tcp_data_csum =
- csum_unfold(htons(QDF_NBUF_CB_RX_TCP_CHKSUM(skb)));
- hdd_lro_info.tcp_seq_num = QDF_NBUF_CB_RX_TCP_SEQ_NUM(skb);
- hdd_lro_info.tcp_win = QDF_NBUF_CB_RX_TCP_WIN(skb);
+ lro_receive_skb_ext(ctx->lro_mgr, skb, (void *)adapter,
+ &hdd_lro_info);
- lro_receive_skb_ext(ctx->lro_mgr, skb,
- (void *)adapter, &hdd_lro_info);
+ if (!hdd_lro_info.lro_desc->active)
+ qdf_lro_desc_free(ctx, lro_desc);
- if (!hdd_lro_info.lro_desc->active)
- qdf_lro_desc_free(ctx, lro_desc);
-
- status = HDD_LRO_RX;
- } else {
- qdf_lro_flush_pkt(ctx, &info);
- }
+ status = QDF_STATUS_SUCCESS;
+ } else {
+ qdf_lro_flush_pkt(ctx, &info);
}
return status;
}
@@ -207,8 +127,8 @@ QDF_STATUS
hdd_lro_set_reset(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter,
uint8_t enable_flag)
{
- if (!hdd_ctx->config->lro_enable ||
- QDF_STA_MODE != adapter->device_mode) {
+ if ((hdd_ctx->ol_enable != CFG_LRO_ENABLED) ||
+ (adapter->device_mode != QDF_STA_MODE)) {
hdd_debug("LRO is already Disabled");
return 0;
}
@@ -238,49 +158,4 @@ hdd_lro_set_reset(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter,
return 0;
}
-/**
- * hdd_disable_lro_in_concurrency() - Disable LRO due to concurrency
- * @disable: bool value
- *
- * Return: none
- */
-void hdd_disable_lro_in_concurrency(bool disable)
-{
- struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
- if (hdd_ctx == NULL) {
- hdd_err("hdd_ctx is NULL");
- return;
- }
-
- if (disable) {
- if (hdd_ctx->en_tcp_delack_no_lro) {
- struct wlan_rx_tp_data rx_tp_data;
-
- hdd_info("Enable TCP delack as LRO disabled in concurrency");
- rx_tp_data.rx_tp_flags = TCP_DEL_ACK_IND;
- rx_tp_data.level = GET_CUR_RX_LVL(hdd_ctx);
- wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
- WLAN_SVC_WLAN_TP_IND,
- &rx_tp_data,
- sizeof(rx_tp_data));
- hdd_ctx->en_tcp_delack_no_lro = 1;
- }
- qdf_atomic_set(&hdd_ctx->disable_lro_in_concurrency, 1);
- } else {
- if (hdd_ctx->en_tcp_delack_no_lro) {
- hdd_info("Disable TCP delack as LRO is enabled");
- hdd_ctx->en_tcp_delack_no_lro = 0;
- hdd_reset_tcp_delack(hdd_ctx);
- }
- qdf_atomic_set(&hdd_ctx->disable_lro_in_concurrency, 0);
- }
-}
-
-void hdd_disable_lro_for_low_tput(struct hdd_context *hdd_ctx, bool disable)
-{
- if (disable)
- qdf_atomic_set(&hdd_ctx->disable_lro_in_low_tput, 1);
- else
- qdf_atomic_set(&hdd_ctx->disable_lro_in_low_tput, 0);
-}
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index 94f22cca6e48..74c2036b05b7 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -4005,7 +4005,7 @@ QDF_STATUS hdd_init_station_mode(struct hdd_adapter *adapter)
* the LRO again. Keep the LRO state same as before SSR.
*/
if (!(qdf_atomic_read(&hdd_ctx->vendor_disable_lro_flag)))
- adapter->dev->features |= NETIF_F_LRO;
+ adapter->dev->features |= NETIF_F_LRO;
/* rcpi info initialization */
qdf_mem_zero(&adapter->rcpi, sizeof(adapter->rcpi));
@@ -7114,9 +7114,9 @@ static void hdd_pld_request_bus_bandwidth(struct hdd_context *hdd_ctx,
hdd_ctx->prev_rx = rx_packets;
if (temp_rx < hdd_ctx->config->busBandwidthLowThreshold)
- hdd_disable_lro_for_low_tput(hdd_ctx, true);
+ hdd_disable_rx_ol_for_low_tput(hdd_ctx, true);
else
- hdd_disable_lro_for_low_tput(hdd_ctx, false);
+ hdd_disable_rx_ol_for_low_tput(hdd_ctx, false);
if (temp_rx > hdd_ctx->config->tcpDelackThresholdHigh) {
if ((hdd_ctx->cur_rx_level != WLAN_SVC_TP_HIGH) &&
@@ -9955,8 +9955,8 @@ static int hdd_features_init(struct hdd_context *hdd_ctx, struct hdd_adapter *ad
if (sme_set_vc_mode_config(hdd_ctx->config->vc_mode_cfg_bitmap))
hdd_warn("Error in setting Voltage Corner mode config to FW");
- if (hdd_lro_init(hdd_ctx))
- hdd_err("Unable to initialize LRO in fw");
+ if (hdd_rx_ol_init(hdd_ctx))
+ hdd_err("Unable to initialize Rx LRO/GRO in fw");
if (hdd_adaptive_dwelltime_init(hdd_ctx))
hdd_err("Unable to send adaptive dwelltime setting to FW");
@@ -10094,7 +10094,7 @@ int hdd_configure_cds(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter)
uint32_t num_abg_tx_chains = 0;
uint32_t num_11b_tx_chains = 0;
uint32_t num_11ag_tx_chains = 0;
- struct policy_mgr_dp_cbacks dp_cbs;
+ struct policy_mgr_dp_cbacks dp_cbs = {0};
if (hdd_ctx->config->sifs_burst_duration) {
set_value = (SIFS_BURST_DUR_MULTIPLIER) *
@@ -10189,7 +10189,9 @@ int hdd_configure_cds(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter)
if (ret)
goto cds_disable;
- dp_cbs.hdd_disable_lro_in_concurrency = hdd_disable_lro_in_concurrency;
+ if (hdd_ctx->ol_enable)
+ dp_cbs.hdd_disable_rx_ol_in_concurrency =
+ hdd_disable_rx_ol_in_concurrency;
dp_cbs.hdd_set_rx_mode_rps_cb = hdd_set_rx_mode_rps;
dp_cbs.hdd_ipa_set_mcc_mode_cb = hdd_ipa_set_mcc_mode;
status = policy_mgr_register_dp_cb(hdd_ctx->hdd_psoc, &dp_cbs);
diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c
index 9f7abd13f1cd..9c19fa1d349c 100644
--- a/core/hdd/src/wlan_hdd_tx_rx.c
+++ b/core/hdd/src/wlan_hdd_tx_rx.c
@@ -55,6 +55,8 @@
#include "wlan_hdd_power.h"
#include "wlan_hdd_cfg80211.h"
#include
+#include
+#include "wma_api.h"
#include "wlan_hdd_nud_tracking.h"
@@ -1522,6 +1524,201 @@ static bool hdd_is_rx_wake_lock_needed(struct sk_buff *skb)
return false;
}
+#ifdef RECEIVE_OFFLOAD
+/**
+ * hdd_resolve_rx_ol_mode() - Resolve Rx offload method, LRO or GRO
+ * @hdd_ctx: pointer to HDD Station Context
+ *
+ * Return: None
+ */
+static void hdd_resolve_rx_ol_mode(struct hdd_context *hdd_ctx)
+{
+ if (!(hdd_ctx->config->lro_enable ^
+ hdd_ctx->config->gro_enable)) {
+ hdd_ctx->config->lro_enable && hdd_ctx->config->gro_enable ?
+ hdd_err("Can't enable both LRO and GRO, disabling Rx offload") :
+ hdd_debug("LRO and GRO both are disabled");
+ hdd_ctx->ol_enable = 0;
+ } else if (hdd_ctx->config->lro_enable) {
+ hdd_debug("Rx offload LRO is enabled");
+ hdd_ctx->ol_enable = CFG_LRO_ENABLED;
+ } else {
+ hdd_debug("Rx offload GRO is enabled");
+ hdd_ctx->ol_enable = CFG_GRO_ENABLED;
+ }
+}
+
+/**
+ * hdd_gro_rx() - Handle Rx procesing via GRO
+ * @adapter: pointer to adapter context
+ * @skb: pointer to sk_buff
+ *
+ * Return: QDF_STATUS_SUCCESS if processed via GRO or non zero return code
+ */
+static QDF_STATUS hdd_gro_rx(struct hdd_adapter *adapter, struct sk_buff *skb)
+{
+ struct napi_struct *napi;
+ struct qca_napi_data *napid;
+ QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+ /* Only enabling it for STA mode like LRO today */
+ if (QDF_STA_MODE != adapter->device_mode)
+ return QDF_STATUS_E_NOSUPPORT;
+
+ napid = hdd_napi_get_all();
+ napi = hif_get_napi(QDF_NBUF_CB_RX_CTX_ID(skb), napid);
+ skb_set_hash(skb, QDF_NBUF_CB_RX_FLOW_ID(skb), PKT_HASH_TYPE_L4);
+
+ if (GRO_DROP != napi_gro_receive(napi, skb))
+ status = QDF_STATUS_SUCCESS;
+
+ return status;
+}
+
+/**
+ * hdd_register_rx_ol() - Register LRO/GRO rx processing callbacks
+ *
+ * Return: none
+ */
+static void hdd_register_rx_ol(void)
+{
+ struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+
+ if (!hdd_ctx)
+ hdd_err("HDD context is NULL");
+
+ if (hdd_ctx->ol_enable == CFG_LRO_ENABLED) {
+ /* Register the flush callback */
+ hdd_ctx->receive_offload_cb = hdd_lro_rx;
+ hdd_debug("LRO is enabled");
+ } else if (hdd_ctx->ol_enable == CFG_GRO_ENABLED) {
+ hdd_ctx->receive_offload_cb = hdd_gro_rx;
+ hdd_debug("GRO is enabled");
+ }
+}
+
+int hdd_rx_ol_init(struct hdd_context *hdd_ctx)
+{
+ struct cdp_lro_hash_config lro_config = {0};
+
+ hdd_resolve_rx_ol_mode(hdd_ctx);
+
+ hdd_register_rx_ol();
+
+ /*
+ * This will enable flow steering and Toeplitz hash
+ * So enable it for LRO or GRO processing.
+ */
+ if (hdd_napi_enabled(HDD_NAPI_ANY) == 0) {
+ hdd_warn("NAPI is disabled");
+ return 0;
+ }
+
+ lro_config.lro_enable = 1;
+ lro_config.tcp_flag = TCPHDR_ACK;
+ lro_config.tcp_flag_mask = TCPHDR_FIN | TCPHDR_SYN | TCPHDR_RST |
+ TCPHDR_ACK | TCPHDR_URG | TCPHDR_ECE | TCPHDR_CWR;
+
+ get_random_bytes(lro_config.toeplitz_hash_ipv4,
+ (sizeof(lro_config.toeplitz_hash_ipv4[0]) *
+ LRO_IPV4_SEED_ARR_SZ));
+
+ get_random_bytes(lro_config.toeplitz_hash_ipv6,
+ (sizeof(lro_config.toeplitz_hash_ipv6[0]) *
+ LRO_IPV6_SEED_ARR_SZ));
+
+ if (0 != wma_lro_init(&lro_config)) {
+ hdd_err("Failed to send LRO configuration!");
+ hdd_ctx->ol_enable = 0;
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+void hdd_disable_rx_ol_in_concurrency(bool disable)
+{
+ struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+
+ if (!hdd_ctx) {
+ hdd_err("hdd_ctx is NULL");
+ return;
+ }
+
+ if (disable) {
+ if (hdd_ctx->en_tcp_delack_no_lro) {
+ struct wlan_rx_tp_data rx_tp_data;
+
+ hdd_info("Enable TCP delack as LRO disabled in concurrency");
+ rx_tp_data.rx_tp_flags = TCP_DEL_ACK_IND;
+ rx_tp_data.level = GET_CUR_RX_LVL(hdd_ctx);
+ wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
+ WLAN_SVC_WLAN_TP_IND,
+ &rx_tp_data,
+ sizeof(rx_tp_data));
+ hdd_ctx->en_tcp_delack_no_lro = 1;
+ }
+ qdf_atomic_set(&hdd_ctx->disable_lro_in_concurrency, 1);
+ } else {
+ if (hdd_ctx->en_tcp_delack_no_lro) {
+ hdd_info("Disable TCP delack as LRO is enabled");
+ hdd_ctx->en_tcp_delack_no_lro = 0;
+ hdd_reset_tcp_delack(hdd_ctx);
+ }
+ qdf_atomic_set(&hdd_ctx->disable_lro_in_concurrency, 0);
+ }
+}
+
+void hdd_disable_rx_ol_for_low_tput(struct hdd_context *hdd_ctx, bool disable)
+{
+ if (disable)
+ qdf_atomic_set(&hdd_ctx->disable_lro_in_low_tput, 1);
+ else
+ qdf_atomic_set(&hdd_ctx->disable_lro_in_low_tput, 0);
+}
+
+/**
+ * hdd_can_handle_receive_offload() - Check for dynamic disablement
+ * @hdd_ctx: hdd context
+ * @skb: pointer to sk_buff which will be processed by Rx OL
+ *
+ * Check for dynamic disablement of Rx offload
+ *
+ * Return: false if we cannot process otherwise true
+ */
+static bool hdd_can_handle_receive_offload(struct hdd_context *hdd_ctx,
+ struct sk_buff *skb)
+{
+ if (!QDF_NBUF_CB_RX_TCP_PROTO(skb) ||
+ qdf_atomic_read(&hdd_ctx->disable_lro_in_concurrency) ||
+ QDF_NBUF_CB_RX_PEER_CACHED_FRM(skb) ||
+ qdf_atomic_read(&hdd_ctx->disable_lro_in_low_tput))
+ return false;
+ else
+ return true;
+}
+#else /* RECEIVE_OFFLOAD */
+static bool hdd_can_handle_receive_offload(struct hdd_context *hdd_ctx,
+ struct sk_buff *skb)
+{
+ return false;
+}
+
+int hdd_rx_ol_init(struct hdd_context *hdd_ctx)
+{
+ hdd_err("Rx_OL, LRO/GRO not supported");
+ return -EPERM;
+}
+
+void hdd_disable_rx_ol_in_concurrency(bool disable)
+{
+}
+
+void hdd_disable_rx_ol_for_low_tput(struct hdd_context *hdd_ctx, bool disable)
+{
+}
+#endif /* RECEIVE_OFFLOAD */
+
#ifdef WLAN_FEATURE_TSF_PLUS
static inline void hdd_tsf_timestamp_rx(struct hdd_context *hdd_ctx,
qdf_nbuf_t netbuf,
@@ -1556,7 +1753,8 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf)
{
struct hdd_adapter *adapter = NULL;
struct hdd_context *hdd_ctx = NULL;
- int rxstat;
+ int rxstat = 0;
+ QDF_STATUS rx_ol_status = QDF_STATUS_E_FAILURE;
struct sk_buff *skb = NULL;
struct sk_buff *next = NULL;
struct hdd_station_ctx *sta_ctx = NULL;
@@ -1712,40 +1910,21 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf)
hdd_tsf_timestamp_rx(hdd_ctx, skb, ktime_to_us(skb->tstamp));
- if (HDD_LRO_NO_RX ==
- hdd_lro_rx(hdd_ctx, adapter, skb)) {
+ if (hdd_can_handle_receive_offload(hdd_ctx, skb) &&
+ hdd_ctx->receive_offload_cb)
+ rx_ol_status = hdd_ctx->receive_offload_cb(adapter,
+ skb);
+
+ if (rx_ol_status != QDF_STATUS_SUCCESS) {
if (hdd_napi_enabled(HDD_NAPI_ANY) &&
!hdd_ctx->enable_rxthread &&
!QDF_NBUF_CB_RX_PEER_CACHED_FRM(skb))
rxstat = netif_receive_skb(skb);
else
rxstat = netif_rx_ni(skb);
+ }
- if (NET_RX_SUCCESS == rxstat) {
- ++adapter->hdd_stats.tx_rx_stats.
- rx_delivered[cpu_index];
- if (track_arp)
- ++adapter->hdd_stats.hdd_arp_stats.
- rx_delivered;
- /* track connectivity stats */
- if (adapter->pkt_type_bitmap)
- hdd_tx_rx_collect_connectivity_stats_info(
- skb, adapter,
- PKT_TYPE_RX_DELIVERED,
- &pkt_type);
- } else {
- ++adapter->hdd_stats.tx_rx_stats.
- rx_refused[cpu_index];
- if (track_arp)
- ++adapter->hdd_stats.hdd_arp_stats.
- rx_refused;
- /* track connectivity stats */
- if (adapter->pkt_type_bitmap)
- hdd_tx_rx_collect_connectivity_stats_info(
- skb, adapter,
- PKT_TYPE_RX_REFUSED, &pkt_type);
- }
- } else {
+ if (!rxstat) {
++adapter->hdd_stats.tx_rx_stats.
rx_delivered[cpu_index];
if (track_arp)
@@ -1756,6 +1935,17 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf)
hdd_tx_rx_collect_connectivity_stats_info(
skb, adapter,
PKT_TYPE_RX_DELIVERED, &pkt_type);
+ } else {
+ ++adapter->hdd_stats.tx_rx_stats.rx_refused[cpu_index];
+ if (track_arp)
+ ++adapter->hdd_stats.hdd_arp_stats.rx_refused;
+
+ /* track connectivity stats */
+ if (adapter->pkt_type_bitmap)
+ hdd_tx_rx_collect_connectivity_stats_info(
+ skb, adapter,
+ PKT_TYPE_RX_REFUSED, &pkt_type);
+
}
}
diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h
index fecf8f76aa67..419cf94cba8e 100644
--- a/core/wma/inc/wma_api.h
+++ b/core/wma/inc/wma_api.h
@@ -190,9 +190,15 @@ int wma_unified_radio_tx_mem_free(void *handle);
QDF_STATUS wma_form_unit_test_cmd_and_send(uint32_t vdev_id,
uint32_t module_id, uint32_t arg_count, uint32_t *arg);
-#if defined(FEATURE_LRO)
+/**
+ * wma_lro_init() - sends LRO configuration to FW
+ * @lro_config: pointer to the config parameters
+ *
+ * This function ends LRO configuration to FW.
+ *
+ * Return: 0 for success or reasons for failure
+ */
int wma_lro_init(struct cdp_lro_hash_config *lro_config);
-#endif
QDF_STATUS wma_remove_beacon_filter(WMA_HANDLE wma,
struct beacon_filter_param *filter_params);
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index fb5db87c182e..80600fa7cfbb 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -8766,15 +8766,7 @@ QDF_STATUS wma_crash_inject(WMA_HANDLE wma_handle, uint32_t type,
return wmi_crash_inject(wma->wmi_handle, ¶m);
}
-#if defined(FEATURE_LRO)
-/**
- * wma_lro_init() - sends LRO configuration to FW
- * @lro_config: pointer to the config parameters
- *
- * This function ends LRO configuration to FW.
- *
- * Return: 0 for success or reasons for failure
- */
+#ifdef RECEIVE_OFFLOAD
int wma_lro_init(struct cdp_lro_hash_config *lro_config)
{
struct scheduler_msg msg = {0};