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
This commit is contained in:
Yeshwanth Sriram Guntuka 2020-06-20 10:21:34 +05:30 committed by nshrivas
parent cec526afda
commit 0c04652083
6 changed files with 275 additions and 2 deletions

1
Kbuild
View File

@ -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)

View File

@ -104,6 +104,7 @@
#include "wma_sar_public_structs.h"
#include "wlan_mlme_ucfg_api.h"
#include "pld_common.h"
#include <dp_txrx.h>
#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;
};
/**

View File

@ -75,6 +75,7 @@
#include <wlan_hdd_sysfs_ipa.h>
#include <wlan_hdd_sysfs_pkt_log.h>
#include <wlan_hdd_sysfs_policy_mgr.h>
#include <wlan_hdd_sysfs_dp_aggregation.h>
#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);

View File

@ -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 <wlan_hdd_includes.h>
#include "osif_psoc_sync.h"
#include <wlan_hdd_sysfs.h>
#include <wlan_hdd_sysfs_dp_aggregation.h>
#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);
}

View File

@ -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 */

View File

@ -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 */