From 0c046520836c6112287a2e3a86ca8b3a6837cedb Mon Sep 17 00:00:00 2001 From: Yeshwanth Sriram Guntuka Date: Sat, 20 Jun 2020 10:21:34 +0530 Subject: [PATCH] qcacld-3.0: Add sysfs entry to dynamically control GRO Add dp_aggregation sysfs entry under the wifi sysfs directory to dynamically control aggregation in the rx direction. Change-Id: Ic7b13806f5fbd19fe5c56cabdf71d032b730448c CRs-Fixed: 2718131 --- Kbuild | 1 + core/hdd/inc/wlan_hdd_main.h | 7 + core/hdd/src/wlan_hdd_sysfs.c | 3 + core/hdd/src/wlan_hdd_sysfs_dp_aggregation.c | 178 +++++++++++++++++++ core/hdd/src/wlan_hdd_sysfs_dp_aggregation.h | 65 +++++++ core/hdd/src/wlan_hdd_tx_rx.c | 23 ++- 6 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 core/hdd/src/wlan_hdd_sysfs_dp_aggregation.c create mode 100644 core/hdd/src/wlan_hdd_sysfs_dp_aggregation.h diff --git a/Kbuild b/Kbuild index 6914be8875..88b25caba8 100644 --- a/Kbuild +++ b/Kbuild @@ -369,6 +369,7 @@ ifeq ($(CONFIG_REMOVE_PKT_LOG), n) HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_pktlog.o endif HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_policy_mgr.o +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_dp_aggregation.o endif ifeq ($(CONFIG_QCACLD_FEATURE_FW_STATE), y) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 193659fe37..61e3859673 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -104,6 +104,7 @@ #include "wma_sar_public_structs.h" #include "wlan_mlme_ucfg_api.h" #include "pld_common.h" +#include #ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH #include "qdf_periodic_work.h" @@ -1649,6 +1650,8 @@ struct hdd_fw_ver_info { * @dynamic_nss_chains_support: Per vdev dynamic nss chains update capability * @sar_cmd_params: SAR command params to be configured to the FW * @country_change_work: work for updating vdev when country changes + * @rx_aggregation: rx aggregation enable or disable state + * @gro_force_flush: gro force flushed indication flag */ struct hdd_context { struct wlan_objmgr_psoc *psoc; @@ -1974,6 +1977,10 @@ struct hdd_context { uint8_t dutycycle_off_percent; #endif qdf_work_t country_change_work; + struct { + qdf_atomic_t rx_aggregation; + uint8_t gro_force_flush[DP_MAX_RX_THREADS]; + } dp_agg_param; }; /** diff --git a/core/hdd/src/wlan_hdd_sysfs.c b/core/hdd/src/wlan_hdd_sysfs.c index 88fa3e22f5..919df9dbdf 100644 --- a/core/hdd/src/wlan_hdd_sysfs.c +++ b/core/hdd/src/wlan_hdd_sysfs.c @@ -75,6 +75,7 @@ #include #include #include +#include #define MAX_PSOC_ID_SIZE 10 @@ -782,12 +783,14 @@ void hdd_create_sysfs_files(struct hdd_context *hdd_ctx) hdd_sysfs_pm_cinfo_create(driver_kobject); hdd_sysfs_pm_pcl_create(driver_kobject); hdd_sysfs_pm_dbs_create(driver_kobject); + hdd_sysfs_dp_aggregation_create(driver_kobject); } } void hdd_destroy_sysfs_files(void) { if (QDF_GLOBAL_MISSION_MODE == hdd_get_conparam()) { + hdd_sysfs_dp_aggregation_destroy(driver_kobject); hdd_sysfs_pm_dbs_destroy(driver_kobject); hdd_sysfs_pm_pcl_destroy(driver_kobject); hdd_sysfs_pm_cinfo_destroy(driver_kobject); diff --git a/core/hdd/src/wlan_hdd_sysfs_dp_aggregation.c b/core/hdd/src/wlan_hdd_sysfs_dp_aggregation.c new file mode 100644 index 0000000000..e291807a07 --- /dev/null +++ b/core/hdd/src/wlan_hdd_sysfs_dp_aggregation.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dp_aggregation.c + * + * implementation for creating sysfs files: + * + * dp_aggregation + */ + +#include +#include "osif_psoc_sync.h" +#include +#include +#if defined(WLAN_SUPPORT_RX_FISA) +#include "dp_fisa_rx.h" +#endif + +#if defined(WLAN_SUPPORT_RX_FISA) +static inline +void hdd_rx_skip_fisa(ol_txrx_soc_handle dp_soc, uint32_t value) +{ + dp_rx_skip_fisa(dp_soc, value); +} +#else +static inline +void hdd_rx_skip_fisa(ol_txrx_soc_handle dp_soc, uint32_t value) +{ +} +#endif + +static ssize_t +__hdd_sysfs_dp_aggregation_show(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, char *buf) +{ + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + hdd_debug("dp_aggregation: %d", + qdf_atomic_read(&hdd_ctx->dp_agg_param.rx_aggregation)); + + return 0; +} + +static ssize_t hdd_sysfs_dp_aggregation_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dp_aggregation_show(hdd_ctx, attr, buf); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_dp_aggregation_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, const char *buf, + size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + uint32_t value; + int ret; + ol_txrx_soc_handle dp_soc = cds_get_context(QDF_MODULE_ID_SOC); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx) || !dp_soc) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + hdd_debug("dp_aggregation: %d", value); + + hdd_rx_skip_fisa(dp_soc, value); + qdf_atomic_set(&hdd_ctx->dp_agg_param.rx_aggregation, !!value); + + return count; +} + +static ssize_t +hdd_sysfs_dp_aggregation_store(struct kobject *kobj, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dp_aggregation_store(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute dp_aggregation_attribute = + __ATTR(dp_aggregation, 0664, hdd_sysfs_dp_aggregation_show, + hdd_sysfs_dp_aggregation_store); + +int hdd_sysfs_dp_aggregation_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &dp_aggregation_attribute.attr); + if (error) + hdd_err("could not create dp_aggregation sysfs file"); + + return error; +} + +void +hdd_sysfs_dp_aggregation_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + + sysfs_remove_file(driver_kobject, &dp_aggregation_attribute.attr); +} diff --git a/core/hdd/src/wlan_hdd_sysfs_dp_aggregation.h b/core/hdd/src/wlan_hdd_sysfs_dp_aggregation.h new file mode 100644 index 0000000000..ec8a9145a0 --- /dev/null +++ b/core/hdd/src/wlan_hdd_sysfs_dp_aggregation.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dp_aggregation.h + * + * implementation for creating sysfs files: + * + * dp_aggregation + */ + +#ifndef _WLAN_HDD_SYSFS_DP_AGGREGATION_H +#define _WLAN_HDD_SYSFS_DP_AGGREGATION_H + +#if defined(WLAN_SYSFS) +/** + * hdd_sysfs_dp_aggregation_create() - API to create dp aggregation + * related sysfs entry + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel/wifi/dp_aggregation + * + * usage: + * echo [0/1] > dp_aggregation + * + * Return: 0 on success and errno on failure + */ +int +hdd_sysfs_dp_aggregation_create(struct kobject *drv_kobj); + +/** + * hdd_sysfs_dp_aggregation_destroy() - API to destroy dp aggregation + * related sysfs entry + * @driver_kobject: sysfs driver kobject + * + * Return: None + */ +void +hdd_sysfs_dp_aggregation_destroy(struct kobject *drv_kobj); +#else +static inline int +hdd_sysfs_dp_aggregation_create(struct kobject *drv_kobj) +{ + return 0; +} + +static inline void +hdd_sysfs_dp_aggregation_destroy(struct kobject *drv_kobj) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_DP_AGGREGATION_H */ diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c index 5b253e0989..ead41cc293 100644 --- a/core/hdd/src/wlan_hdd_tx_rx.c +++ b/core/hdd/src/wlan_hdd_tx_rx.c @@ -1578,18 +1578,25 @@ static QDF_STATUS hdd_gro_rx_bh_disable(struct hdd_adapter *adapter, QDF_STATUS status = QDF_STATUS_SUCCESS; struct hdd_context *hdd_ctx = adapter->hdd_ctx; gro_result_t gro_ret; + uint32_t rx_aggregation; + uint8_t rx_ctx_id = QDF_NBUF_CB_RX_CTX_ID(skb); + + rx_aggregation = qdf_atomic_read(&hdd_ctx->dp_agg_param.rx_aggregation); skb_set_hash(skb, QDF_NBUF_CB_RX_FLOW_ID(skb), PKT_HASH_TYPE_L4); local_bh_disable(); gro_ret = napi_gro_receive(napi_to_use, skb); - if (hdd_get_current_throughput_level(hdd_ctx) == PLD_BUS_WIDTH_IDLE) { + if (hdd_get_current_throughput_level(hdd_ctx) == PLD_BUS_WIDTH_IDLE || + !rx_aggregation) { if (HDD_IS_EXTRA_GRO_FLUSH_NECESSARY(gro_ret)) { adapter->hdd_stats.tx_rx_stats. rx_gro_low_tput_flush++; dp_rx_napi_gro_flush(napi_to_use); } + if (!rx_aggregation) + hdd_ctx->dp_agg_param.gro_force_flush[rx_ctx_id] = 1; } local_bh_enable(); @@ -1759,6 +1766,7 @@ static void hdd_register_rx_ol_cb(struct hdd_context *hdd_ctx, hdd_ctx->receive_offload_cb = hdd_lro_rx; hdd_debug("LRO is enabled"); } else if (hdd_ctx->ol_enable == CFG_GRO_ENABLED) { + qdf_atomic_set(&hdd_ctx->dp_agg_param.rx_aggregation, 1); if (lithium_based_target) { /* no flush registration needed, it happens in DP thread */ hdd_ctx->receive_offload_cb = hdd_gro_rx_dp_thread; @@ -1992,12 +2000,14 @@ QDF_STATUS hdd_rx_deliver_to_stack(struct hdd_adapter *adapter, int status = QDF_STATUS_E_FAILURE; int netif_status; bool skb_receive_offload_ok = false; + uint8_t rx_ctx_id = QDF_NBUF_CB_RX_CTX_ID(skb); if (QDF_NBUF_CB_RX_TCP_PROTO(skb) && !QDF_NBUF_CB_RX_PEER_CACHED_FRM(skb)) skb_receive_offload_ok = true; - if (skb_receive_offload_ok && hdd_ctx->receive_offload_cb) { + if (skb_receive_offload_ok && hdd_ctx->receive_offload_cb && + !hdd_ctx->dp_agg_param.gro_force_flush[rx_ctx_id]) { status = hdd_ctx->receive_offload_cb(adapter, skb); if (QDF_IS_STATUS_SUCCESS(status)) { @@ -2011,6 +2021,15 @@ QDF_STATUS hdd_rx_deliver_to_stack(struct hdd_adapter *adapter, } } + /* + * The below case handles the scenario when rx_aggregation is + * re-enabled dynamically, in which case gro_force_flush needs + * to be reset to 0 to allow GRO. + */ + if (qdf_atomic_read(&hdd_ctx->dp_agg_param.rx_aggregation) && + hdd_ctx->dp_agg_param.gro_force_flush[rx_ctx_id]) + hdd_ctx->dp_agg_param.gro_force_flush[rx_ctx_id] = 0; + adapter->hdd_stats.tx_rx_stats.rx_non_aggregated++; /* Account for GRO/LRO ineligible packets, mostly UDP */