summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManjunathappa Prakash <prakashpm@codeaurora.org>2017-07-20 15:40:28 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2017-08-25 13:26:39 -0700
commitac632587f90248b4f8e9609f87111268835dcdcf (patch)
tree4bf6a8cd7b4f02f101bf4a393f5991efb9fdb54d
parentb1ed69520da4b560ceaadf9d269b123183d7d3bf (diff)
qcacld-3.0: Add GRO support for STA mode
Add GRO support and make it configurable through INI(GROEnable). GRO and LRO are mutually exclusive. Only one of them can be enabled. Make sure to disable GRO during following conditions 1) Low TPUT scenario 2) Concurrency cases 3) For Rx packets when Peer is not connected Change-Id: I15535827a03953231670d4138235c4876b16e045 CRs-Fixed: 2098772
-rw-r--r--core/cds/src/cds_api.c2
-rw-r--r--core/dp/htt/htt_internal.h9
-rw-r--r--core/hdd/inc/wlan_hdd_cfg.h32
-rw-r--r--core/hdd/inc/wlan_hdd_lro.h41
-rw-r--r--core/hdd/inc/wlan_hdd_main.h3
-rw-r--r--core/hdd/inc/wlan_hdd_tx_rx.h45
-rw-r--r--core/hdd/src/wlan_hdd_cfg.c7
-rw-r--r--core/hdd/src/wlan_hdd_lro.c123
-rw-r--r--core/hdd/src/wlan_hdd_main.c20
-rw-r--r--core/hdd/src/wlan_hdd_tx_rx.c233
-rw-r--r--core/wma/inc/wma.h8
-rw-r--r--core/wma/inc/wma_api.h2
-rw-r--r--core/wma/src/wma_data.c2
-rw-r--r--core/wma/src/wma_main.c2
14 files changed, 332 insertions, 197 deletions
diff --git a/core/cds/src/cds_api.c b/core/cds/src/cds_api.c
index 5059930fd646..0a57255bce05 100644
--- a/core/cds/src/cds_api.c
+++ b/core/cds/src/cds_api.c
@@ -508,8 +508,6 @@ QDF_STATUS cds_open(void)
goto err_sme_close;
}
- hdd_lro_create();
-
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
"%s: CDS successfully Opened", __func__);
diff --git a/core/dp/htt/htt_internal.h b/core/dp/htt/htt_internal.h
index adf35add341c..dddda0a6fd2d 100644
--- a/core/dp/htt/htt_internal.h
+++ b/core/dp/htt/htt_internal.h
@@ -182,7 +182,6 @@ static inline struct htt_host_rx_desc_base *htt_rx_desc(qdf_nbuf_t msdu)
~HTT_RX_DESC_ALIGN_MASK);
}
-#if defined(FEATURE_LRO)
/**
* htt_print_rx_desc_lro() - print LRO information in the rx
* descriptor
@@ -223,7 +222,7 @@ static inline void htt_print_rx_desc_lro(struct htt_host_rx_desc_base *rx_desc)
}
/**
- * htt_print_rx_desc_lro() - extract LRO information from the rx
+ * htt_rx_extract_lro_info() - extract LRO information from the rx
* descriptor
* @msdu: network buffer
* @rx_desc: HTT rx descriptor
@@ -265,12 +264,6 @@ static inline void htt_rx_extract_lro_info(qdf_nbuf_t msdu,
rx_desc->msdu_start.flow_id_toeplitz;
}
}
-#else
-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 */
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 409bf263fa96..63e428509792 100644
--- a/core/hdd/inc/wlan_hdd_cfg.h
+++ b/core/hdd/inc/wlan_hdd_cfg.h
@@ -8384,15 +8384,15 @@ enum hdd_link_speed_rpt_type {
/*
* <ini>
- * LROEnable - Control to enable lro feature
+ * LROEnable - Control to enable LRO
*
- * @Min: 0
+ * @Min: 0 Disable LRO
* @Max: 1
* @Default: 0
*
- * This ini is used to enable LRO feature
- *
- * Supported Feature: LRO
+ * This ini is used to enable/disable LRO
+ * If this is enabled make sure to disable GRO.
+ * LRO and GRO are mutually exclusive.
*
* Usage: Internal
*
@@ -8404,6 +8404,27 @@ enum hdd_link_speed_rpt_type {
#define CFG_LRO_ENABLED_DEFAULT (0)
/*
+ * <ini>
+ * GROEnable - Control to enable GRO
+ *
+ * @Min: 0 Disable GRO
+ * @Max: 1
+ * @Default: 0
+ *
+ * This ini is used to enable/disable GRO
+ * If this is enabled make sure to disable LRO.
+ * LRO and GRO are mutually exclusive.
+ *
+ * Usage: Internal
+ *
+ * </ini>
+ */
+#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.
* Parallel Rx paths.
@@ -12479,6 +12500,7 @@ struct hdd_config {
bool sendDeauthBeforeCon;
bool tso_enable;
bool lro_enable;
+ bool gro_enable;
bool flow_steering_enable;
bool active_mode_offload;
bool bpf_packet_filter_enable;
diff --git a/core/hdd/inc/wlan_hdd_lro.h b/core/hdd/inc/wlan_hdd_lro.h
index 740620a6ac76..c6f2fd667b9f 100644
--- a/core/hdd/inc/wlan_hdd_lro.h
+++ b/core/hdd/inc/wlan_hdd_lro.h
@@ -31,17 +31,6 @@
*
* WLAN LRO interface module headers
*/
-
-/**
- * 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)
#include <linux/inet_lro.h>
@@ -151,27 +140,20 @@ struct hdd_lro_s {
struct hdd_lro_desc_info lro_desc_info;
};
-int hdd_lro_init(hdd_context_t *hdd_ctx);
-
int hdd_lro_enable(hdd_context_t *hdd_ctx,
hdd_adapter_t *adapter);
-void hdd_lro_create(void);
-
void hdd_lro_disable(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter);
void hdd_lro_destroy(void);
-enum hdd_lro_rx_status hdd_lro_rx(hdd_context_t *hdd_ctx,
- hdd_adapter_t *adapter, struct sk_buff *skb);
+QDF_STATUS hdd_lro_rx(hdd_adapter_t *adapter, struct sk_buff *skb);
void hdd_lro_flush_all(hdd_context_t *hdd_ctx,
hdd_adapter_t *adapter);
+void hdd_lro_create(void);
void hdd_lro_display_stats(hdd_context_t *hdd_ctx);
-void hdd_enable_lro_in_concurrency(hdd_context_t *hdd_ctx);
-void hdd_disable_lro_in_concurrency(hdd_context_t *hdd_ctx);
-void hdd_disable_lro_for_low_tput(hdd_context_t *hdd_ctx, bool disable);
QDF_STATUS hdd_lro_set_reset(hdd_context_t *hdd_ctx,
hdd_adapter_t *adapter,
uint8_t enable_flag);
@@ -181,26 +163,21 @@ struct hdd_lro_s {};
static inline int hdd_lro_enable(hdd_context_t *hdd_ctx,
hdd_adapter_t *adapter)
{
- return 0;
-}
-
-static inline void hdd_lro_create(void)
-{
+ return ENOSYS;
}
-static inline enum hdd_lro_rx_status hdd_lro_rx(hdd_context_t *hdd_ctx,
- hdd_adapter_t *adapter, struct sk_buff *skb)
+static inline QDF_STATUS hdd_lro_rx(hdd_adapter_t *adapter,
+ struct sk_buff *skb)
{
- return HDD_LRO_NO_RX;
+ return QDF_STATUS_E_NOSUPPORT;
}
-static inline int hdd_lro_init(hdd_context_t *hdd_ctx)
+static inline void hdd_lro_disable(hdd_context_t *hdd_ctx,
+ hdd_adapter_t *adapter)
{
- return 0;
}
-static inline void hdd_lro_disable(hdd_context_t *hdd_ctx,
- hdd_adapter_t *adapter)
+static inline void hdd_lro_create(void)
{
}
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index e00e389ec257..1c979b39cc67 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -1922,6 +1922,7 @@ struct hdd_context_s {
qdf_work_t sap_pre_cac_work;
bool hbw_requested;
uint32_t last_nil_scan_bug_report_timestamp;
+ uint32_t ol_enable;
#ifdef WLAN_FEATURE_NAN_DATAPATH
bool nan_datapath_enabled;
#endif
@@ -1948,6 +1949,8 @@ struct hdd_context_s {
unsigned long tdls_source_bitmap;
/* tdls source timer to enable/disable TDLS on p2p listen */
qdf_mc_timer_t tdls_source_timer;
+ QDF_STATUS (*receive_offload_cb)(hdd_adapter_t *,
+ struct sk_buff *);
qdf_atomic_t disable_lro_in_concurrency;
qdf_atomic_t disable_lro_in_low_tput;
qdf_atomic_t vendor_disable_lro_flag;
diff --git a/core/hdd/inc/wlan_hdd_tx_rx.h b/core/hdd/inc/wlan_hdd_tx_rx.h
index 4bc5812f22be..ffd3ee1f9b46 100644
--- a/core/hdd/inc/wlan_hdd_tx_rx.h
+++ b/core/hdd/inc/wlan_hdd_tx_rx.h
@@ -61,6 +61,51 @@ QDF_STATUS hdd_init_tx_rx(hdd_adapter_t *pAdapter);
QDF_STATUS hdd_deinit_tx_rx(hdd_adapter_t *pAdapter);
QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf);
+/**
+ * hdd_register_rx_ol() - Allocate LRO managers via callbacks
+ *
+ * Return: none
+ */
+void hdd_register_rx_ol(void);
+
+/**
+ * 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(hdd_context_t *hdd_ctx);
+
+/**
+ * hdd_enable_rx_ol_in_concurrency() - Enable Rx offload
+ * @hdd_ctx: hdd context
+ *
+ * Enable Rx offload if for inactive concurrency is not active
+ *
+ * Return: none
+ */
+void hdd_enable_rx_ol_in_concurrency(hdd_context_t *hdd_ctx);
+
+/**
+ * hdd_disable_rx_ol_in_concurrency() - Disable Rx offload due to concurrency
+ * @hdd_ctx: hdd context
+ *
+ * Return: none
+ */
+void hdd_disable_rx_ol_in_concurrency(hdd_context_t *hdd_ctx);
+
+/**
+ * hdd_disable_rx_ol_for_low_tput() - Disable Rx offload in low TPUT scenario
+ * @hdd_ctx: hdd context
+ * @disable: 1 disable, 0 enable
+ *
+ * Return: none
+ */
+void hdd_disable_rx_ol_for_low_tput(hdd_context_t *hdd_ctx, bool disable);
+
+#define CFG_LRO_ENABLED 1
+#define CFG_GRO_ENABLED 2
+
#ifdef IPA_OFFLOAD
QDF_STATUS hdd_rx_mul_packet_cbk(void *cds_context,
qdf_nbuf_t rx_buf_list, uint8_t staId);
diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c
index 5f8085c591be..144a72ec0303 100644
--- a/core/hdd/src/wlan_hdd_cfg.c
+++ b/core/hdd/src/wlan_hdd_cfg.c
@@ -3676,6 +3676,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 6cb0887e6448..a610aea51f40 100644
--- a/core/hdd/src/wlan_hdd_lro.c
+++ b/core/hdd/src/wlan_hdd_lro.c
@@ -401,50 +401,6 @@ static void hdd_lro_flush(void *data)
}
}
-/**
- * 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(hdd_context_t *hdd_ctx)
-{
- struct wma_lro_config_cmd_t lro_config;
-
- if ((!hdd_ctx->config->lro_enable) &&
- (hdd_napi_enabled(HDD_NAPI_ANY) == 0)) {
- hdd_warn("LRO and NAPI are both 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_PSH | 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;
- }
-
- return 0;
-}
-
static void *hdd_init_lro_mgr(void)
{
struct hdd_lro_s *hdd_lro;
@@ -472,7 +428,7 @@ static void *hdd_init_lro_mgr(void)
if (NULL == lro_mem_ptr) {
hdd_err("Unable to allocate memory for LRO");
- hdd_ctx->config->lro_enable = 0;
+ hdd_ctx->ol_enable = 0;
return NULL;
}
@@ -527,10 +483,9 @@ static void *hdd_init_lro_mgr(void)
int hdd_lro_enable(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter)
{
- if (!hdd_ctx->config->lro_enable ||
+ if ((hdd_ctx->ol_enable != CFG_LRO_ENABLED) ||
QDF_STA_MODE != adapter->device_mode) {
- hdd_debug("LRO Disabled");
- return 0;
+ return EOPNOTSUPP;
}
/*
@@ -539,7 +494,7 @@ int hdd_lro_enable(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter)
* the LRO again. Keep the LRO state same as before SSR.
*/
if (qdf_atomic_read(&hdd_ctx->vendor_disable_lro_flag))
- return 0;
+ return EPERM;
adapter->dev->features |= NETIF_F_LRO;
@@ -584,7 +539,7 @@ static void hdd_deinit_lro_mgr(void *lro_info)
*/
void hdd_lro_disable(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter)
{
- if (!hdd_ctx->config->lro_enable ||
+ if ((hdd_ctx->ol_enable != CFG_LRO_ENABLED) ||
QDF_STA_MODE != adapter->device_mode)
return;
@@ -609,21 +564,17 @@ void hdd_lro_destroy(void)
*
* 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(hdd_context_t *hdd_ctx,
- hdd_adapter_t *adapter, struct sk_buff *skb)
+QDF_STATUS hdd_lro_rx(hdd_adapter_t *adapter, struct sk_buff *skb)
{
- enum hdd_lro_rx_status status = HDD_LRO_NO_RX;
+ QDF_STATUS status = QDF_STATUS_E_FAILURE;
- if (((adapter->dev->features & NETIF_F_LRO) != NETIF_F_LRO) ||
- 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))
+ if ((adapter->dev->features & NETIF_F_LRO) != NETIF_F_LRO)
return status;
- if (QDF_NBUF_CB_RX_TCP_PROTO(skb)) {
+ {
struct iphdr *iph;
struct tcphdr *tcph;
struct net_lro_desc *lro_desc = NULL;
@@ -631,6 +582,7 @@ enum hdd_lro_rx_status hdd_lro_rx(hdd_context_t *hdd_ctx,
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;
@@ -665,7 +617,7 @@ enum hdd_lro_rx_status hdd_lro_rx(hdd_context_t *hdd_ctx,
if (!hdd_lro_info.lro_desc->active)
hdd_lro_desc_free(lro_desc, lro_info);
- status = HDD_LRO_RX;
+ status = QDF_STATUS_SUCCESS;
} else {
hdd_lro_flush_pkt(lro_info->lro_mgr,
iph, tcph, lro_info);
@@ -686,51 +638,6 @@ void hdd_lro_display_stats(hdd_context_t *hdd_ctx)
}
/**
- * hdd_enable_lro_in_concurrency() - Enable LRO if concurrency is not active
- * @hdd_ctx: hdd context
- *
- * Return: none
- */
-void hdd_enable_lro_in_concurrency(hdd_context_t *hdd_ctx)
-{
- if (hdd_ctx->config->enable_tcp_delack) {
- hdd_debug("Disable TCP delack as LRO is enabled");
- hdd_ctx->config->enable_tcp_delack = 0;
- hdd_reset_tcp_delack(hdd_ctx);
- }
- qdf_atomic_set(&hdd_ctx->disable_lro_in_concurrency, 0);
-}
-
-/**
- * hdd_disable_lro_in_concurrency() - Disable LRO due to concurrency
- * @hdd_ctx: hdd context
- *
- * Return: none
- */
-void hdd_disable_lro_in_concurrency(hdd_context_t *hdd_ctx)
-{
- if (!hdd_ctx->config->enable_tcp_delack) {
- struct wlan_rx_tp_data rx_tp_data = {0};
-
- hdd_debug("Enable TCP delack as LRO disabled in concurrency");
- rx_tp_data.rx_tp_flags |= TCP_DEL_ACK_IND;
- rx_tp_data.level = hdd_ctx->cur_rx_level;
- wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
- WLAN_SVC_WLAN_TP_IND, &rx_tp_data, sizeof(rx_tp_data));
- hdd_ctx->config->enable_tcp_delack = 1;
- }
- qdf_atomic_set(&hdd_ctx->disable_lro_in_concurrency, 1);
-}
-
-void hdd_disable_lro_for_low_tput(hdd_context_t *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_lro_set_reset() - vendor command for Disable/Enable LRO
* @hdd_ctx: hdd context
* @hdd_adapter_t: adapter
@@ -746,8 +653,8 @@ hdd_lro_set_reset(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter,
qdf_atomic_set(&hdd_ctx->vendor_disable_lro_flag, 0);
hdd_lro_enable(hdd_ctx, adapter);
} else {
- 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))
return 0;
/* Disable LRO, Enable tcpdelack*/
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index 3e2f1c1ec9e2..a103c1ad71b5 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -3117,16 +3117,16 @@ QDF_STATUS hdd_init_station_mode(hdd_adapter_t *adapter)
goto error_tdls_init;
status = hdd_lro_enable(hdd_ctx, adapter);
- if (status != QDF_STATUS_SUCCESS)
- goto error_lro_enable;
+ if (status)
+ /* Err code from errno.h */
+ hdd_err("LRO is disabled either because of kernel doesnot support or disabled in INI or via vendor commandi. err code %d",
+ status);
/* rcpi info initialization */
qdf_mem_zero(&adapter->rcpi, sizeof(adapter->rcpi));
return QDF_STATUS_SUCCESS;
-error_lro_enable:
- wlan_hdd_tdls_exit(adapter);
error_tdls_init:
clear_bit(WMM_INIT_DONE, &adapter->event_flags);
hdd_wmm_adapter_close(adapter);
@@ -6293,9 +6293,9 @@ static void hdd_pld_request_bus_bandwidth(hdd_context_t *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) &&
@@ -9110,7 +9110,7 @@ static int hdd_features_init(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter)
if (hdd_ctx->config->enable_go_cts2self_for_sta)
sme_set_cts2self_for_p2p_go(hdd_ctx->hHal);
- if (hdd_lro_init(hdd_ctx))
+ if (hdd_rx_ol_init(hdd_ctx))
hdd_warn("Unable to initialize LRO in fw");
if (hdd_adaptive_dwelltime_init(hdd_ctx))
@@ -9299,10 +9299,10 @@ int hdd_configure_cds(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter)
goto hdd_features_deinit;
}
- if (hdd_ctx->config->lro_enable) {
- dp_cbacks.hdd_en_lro_in_cc_cb = hdd_enable_lro_in_concurrency;
+ if (hdd_ctx->ol_enable) {
+ dp_cbacks.hdd_en_lro_in_cc_cb = hdd_enable_rx_ol_in_concurrency;
dp_cbacks.hdd_disble_lro_in_cc_cb =
- hdd_disable_lro_in_concurrency;
+ hdd_disable_rx_ol_in_concurrency;
}
dp_cbacks.hdd_set_rx_mode_rps_cb = hdd_set_rx_mode_rps;
diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c
index 0260d0983250..11348292df13 100644
--- a/core/hdd/src/wlan_hdd_tx_rx.c
+++ b/core/hdd/src/wlan_hdd_tx_rx.c
@@ -58,6 +58,8 @@
#include "pld_common.h"
#include "wlan_hdd_power.h"
#include <wlan_hdd_tsf.h>
+#include <net/tcp.h>
+#include "wma_api.h"
#ifdef QCA_LL_TX_FLOW_CONTROL_V2
/*
@@ -1164,6 +1166,201 @@ static bool hdd_is_rx_wake_lock_needed(struct sk_buff *skb)
}
/**
+ * hdd_resolve_rx_ol_mode() - Resolve Rx offload method, LRO or GRO
+ * @hdd_ctx: pointer to HDD Station Context
+ *
+ * Return: None
+ */
+static inline void hdd_resolve_rx_ol_mode(hdd_context_t *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_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(hdd_context_t *hdd_ctx)
+{
+ struct wma_lro_config_cmd_t 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;
+}
+
+/**
+ * hdd_enable_rx_ol_in_concurrency() - Enable Rx offload
+ * @hdd_ctx: hdd context
+ *
+ * Enable Rx offload if for inactive concurrency is not active
+ *
+ * Return: none
+ */
+void hdd_enable_rx_ol_in_concurrency(hdd_context_t *hdd_ctx)
+{
+ if (hdd_ctx->config->enable_tcp_delack) {
+ hdd_debug("Disable TCP delack as Rx Offload is enabled");
+ hdd_ctx->config->enable_tcp_delack = 0;
+ hdd_reset_tcp_delack(hdd_ctx);
+ }
+ qdf_atomic_set(&hdd_ctx->disable_lro_in_concurrency, 0);
+}
+
+/**
+ * hdd_disable_rx_ol_in_concurrency() - Disable Rx offload due to concurrency
+ * @hdd_ctx: hdd context
+ *
+ * Return: none
+ */
+void hdd_disable_rx_ol_in_concurrency(hdd_context_t *hdd_ctx)
+{
+ if (!hdd_ctx->config->enable_tcp_delack) {
+ struct wlan_rx_tp_data rx_tp_data = {0};
+
+ hdd_debug("Enable TCP delack as Rx offload disabled in concurrency");
+ rx_tp_data.rx_tp_flags |= TCP_DEL_ACK_IND;
+ rx_tp_data.level = hdd_ctx->cur_rx_level;
+ wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
+ WLAN_SVC_WLAN_TP_IND, &rx_tp_data, sizeof(rx_tp_data));
+ hdd_ctx->config->enable_tcp_delack = 1;
+ }
+ qdf_atomic_set(&hdd_ctx->disable_lro_in_concurrency, 1);
+}
+
+/**
+ * hdd_disable_rx_ol_for_low_tput() - Disable Rx offload in low TPUT scenario
+ * @hdd_ctx: hdd context
+ * @disable: 1 disable, 0 enable
+ *
+ * Return: none
+ */
+void hdd_disable_rx_ol_for_low_tput(hdd_context_t *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 inline bool hdd_can_handle_receive_offload(hdd_context_t *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;
+}
+
+/**
+ * hdd_gro_rx() - Handle Rx procesing via GRO
+ * @pAdapter: pointer to adapter context
+ * @skb: pointer to sk_buff
+ *
+ * Return: QDF_STATUS_SUCCESS if processed via GRO or non zero return code
+ */
+static inline QDF_STATUS hdd_gro_rx(hdd_adapter_t *adapter,
+ struct sk_buff *skb)
+{
+ struct napi_struct *napi;
+ void *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_TOEPLITZ(skb),
+ PKT_HASH_TYPE_L4);
+
+ if (GRO_DROP != napi_gro_receive(napi, skb))
+ status = QDF_STATUS_SUCCESS;
+
+ return status;
+}
+
+/**
+ * hdd_register_rx_ol() - Allocate LRO managers via callbacks
+ *
+ * Return: none
+ */
+void hdd_register_rx_ol(void)
+{
+ hdd_context_t *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_lro_create();
+ 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");
+ }
+}
+
+/**
* hdd_rx_packet_cbk() - Receive packet handler
* @context: pointer to HDD context
* @rxBuf: pointer to rx qdf_nbuf
@@ -1179,7 +1376,8 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf)
{
hdd_adapter_t *pAdapter = NULL;
hdd_context_t *pHddCtx = NULL;
- int rxstat;
+ int rxstat = 0;
+ QDF_STATUS rx_ol_status = QDF_STATUS_E_FAILURE;
struct sk_buff *skb = NULL;
hdd_station_ctx_t *pHddStaCtx = NULL;
unsigned int cpu_index;
@@ -1304,32 +1502,31 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf)
hdd_rx_timestamp(skb, ktime_to_us(skb->tstamp));
- if (HDD_LRO_NO_RX ==
- hdd_lro_rx(pHddCtx, pAdapter, skb)) {
+ if (hdd_can_handle_receive_offload(pHddCtx, skb) &&
+ pHddCtx->receive_offload_cb)
+ rx_ol_status = pHddCtx->receive_offload_cb(pAdapter, skb);
+
+ if (rx_ol_status != QDF_STATUS_SUCCESS) {
if (hdd_napi_enabled(HDD_NAPI_ANY) &&
!pHddCtx->enableRxThread &&
!QDF_NBUF_CB_RX_PEER_CACHED_FRM(skb))
rxstat = netif_receive_skb(skb);
else
rxstat = netif_rx_ni(skb);
+ }
- if (NET_RX_SUCCESS == rxstat) {
- ++pAdapter->hdd_stats.hddTxRxStats.
- rxDelivered[cpu_index];
- if (track_arp)
- ++pAdapter->hdd_stats.hdd_arp_stats.
- rx_delivered;
- } else {
- ++pAdapter->hdd_stats.hddTxRxStats.
- rxRefused[cpu_index];
- if (track_arp)
- ++pAdapter->hdd_stats.hdd_arp_stats.
- rx_refused;
- }
-
- } else {
+ if (!rxstat) {
++pAdapter->hdd_stats.hddTxRxStats.
rxDelivered[cpu_index];
+ if (track_arp)
+ ++pAdapter->hdd_stats.hdd_arp_stats.
+ rx_delivered;
+ } else {
+ ++pAdapter->hdd_stats.hddTxRxStats.
+ rxRefused[cpu_index];
+ if (track_arp)
+ ++pAdapter->hdd_stats.hdd_arp_stats.
+ rx_refused;
}
pAdapter->dev->last_rx = jiffies;
diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h
index 33ffa83680a2..fb6d98932a8b 100644
--- a/core/wma/inc/wma.h
+++ b/core/wma/inc/wma.h
@@ -2389,16 +2389,8 @@ static inline QDF_STATUS wma_set_gateway_params(tp_wma_handle wma,
}
#endif /* FEATURE_LFR_SUBNET_DETECTION */
-#if defined(FEATURE_LRO)
QDF_STATUS wma_lro_config_cmd(tp_wma_handle wma_handle,
struct wma_lro_config_cmd_t *wma_lro_cmd);
-#else
-static inline QDF_STATUS wma_lro_config_cmd(tp_wma_handle wma_handle,
- struct wma_lro_config_cmd_t *wma_lro_cmd)
-{
- return QDF_STATUS_SUCCESS;
-}
-#endif
bool wma_is_current_hwmode_dbs(void);
void
wma_indicate_err(enum ol_rx_err_type err_type,
diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h
index 553495e9a23a..d2f07c96dbaf 100644
--- a/core/wma/inc/wma_api.h
+++ b/core/wma/inc/wma_api.h
@@ -293,9 +293,7 @@ struct wma_lro_config_cmd_t {
uint32_t toeplitz_hash_ipv6[LRO_IPV6_SEED_ARR_SZ];
};
-#if defined(FEATURE_LRO)
int wma_lro_init(struct wma_lro_config_cmd_t *lro_config);
-#endif
bool wma_is_scan_simultaneous_capable(void);
QDF_STATUS wma_remove_beacon_filter(WMA_HANDLE wma,
diff --git a/core/wma/src/wma_data.c b/core/wma/src/wma_data.c
index 3784b6533d91..ace85eeee8dc 100644
--- a/core/wma/src/wma_data.c
+++ b/core/wma/src/wma_data.c
@@ -3226,7 +3226,6 @@ void wma_tx_abort(uint8_t vdev_id)
&param);
}
-#if defined(FEATURE_LRO)
/**
* wma_lro_config_cmd() - process the LRO config command
* @wma: Pointer to WMA handle
@@ -3261,7 +3260,6 @@ QDF_STATUS wma_lro_config_cmd(tp_wma_handle wma_handle,
return wmi_unified_lro_config_cmd(wma_handle->wmi_handle,
&wmi_lro_cmd);
}
-#endif
/**
* wma_indicate_err() - indicate an error to the protocol stack
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index 60a766d5eb12..de6ce4176f24 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -8299,7 +8299,6 @@ QDF_STATUS wma_crash_inject(tp_wma_handle wma_handle, uint32_t type,
return wmi_crash_inject(wma_handle->wmi_handle, &param);
}
-#if defined(FEATURE_LRO)
/**
* wma_lro_init() - sends LRO configuration to FW
* @lro_config: pointer to the config parameters
@@ -8335,7 +8334,6 @@ int wma_lro_init(struct wma_lro_config_cmd_t *lro_config)
WMA_LOGD("sending the LRO configuration to the fw");
return 0;
}
-#endif
QDF_STATUS wma_configure_smps_params(uint32_t vdev_id, uint32_t param_id,
uint32_t param_val)