qcacld-3.0: Move APF context to per adapter

APF commands are using a global context and so the current
implementation can only entertain one command at a time. Since
APF in Firmware is vdev specific, simultaneous APF commands on
different vdev's should be supported.

Move APF context inside hdd adapter to support simultaneous
commands on multiple vdev's.

Change-Id: Ife148065ebc6387af3a690cc0cb788e23066e67e
CRs-Fixed: 2192408
This commit is contained in:
Nachiket Kukade 2018-06-15 19:47:37 +05:30 • committed by nshrivas
commit 5f0ce4f65d
4 changed files with 123 additions and 108 deletions

View file

@ -46,30 +46,6 @@
#define WLAN_WAIT_TIME_APF_GET_CAPS 1000
#define WLAN_WAIT_TIME_APF_READ_MEM 10000
/*
* struct hdd_apf_context - hdd Context for apf
* @magic: magic number
* @qdf_apf_event: Completion variable for APF get operations
* @capability_response: capabilities response received from fw
* @apf_enabled: True: APF Interpreter enabled, False: Disabled
* @cmd_in_progress: Flag that indicates an APF command is in progress
* @buf: Buffer to accumulate read memory chunks
* @buf_len: Length of the read memory requested
* @offset: APF work memory offset to fetch from
* @lock: APF Context lock
*/
struct hdd_apf_context {
unsigned int magic;
qdf_event_t qdf_apf_event;
struct sir_apf_get_offload capability_response;
bool apf_enabled;
bool cmd_in_progress;
uint8_t *buf;
uint32_t buf_len;
uint32_t offset;
qdf_spinlock_t lock;
};
/**
* wlan_hdd_cfg80211_apf_offload() - SSR Wrapper to APF Offload
* @wiphy: wiphy structure pointer
@ -86,21 +62,23 @@ int wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy,
/**
* hdd_apf_context_init - APF Context initialization operations
* @adapter: hdd adapter
*
* Return: None
*/
void hdd_apf_context_init(void);
void hdd_apf_context_init(struct hdd_adapter *adapter);
/**
* hdd_apf_context_destroy - APF Context de-init operations
* @adapter: hdd adapter
*
* Return: None
*/
void hdd_apf_context_destroy(void);
void hdd_apf_context_destroy(struct hdd_adapter *adapter);
/**
* hdd_get_apf_capabilities_cb() - Callback function to get APF capabilities
* @hdd_context: hdd_context
* @hdd_context: pointer to the hdd context
* @apf_get_offload: struct for get offload
*
* This function receives the response/data from the lower layer and
@ -113,11 +91,11 @@ void hdd_get_apf_capabilities_cb(void *hdd_context,
struct sir_apf_get_offload *data);
#else /* FEATURE_WLAN_APF */
static inline void hdd_apf_context_init(void)
static inline void hdd_apf_context_init(struct hdd_adapter *adapter)
{
}
static inline void hdd_apf_context_destroy(void)
static inline void hdd_apf_context_destroy(struct hdd_adapter *adapter)
{
}

View file

@ -98,6 +98,31 @@
* Preprocessor definitions and constants
*/
#ifdef FEATURE_WLAN_APF
/**
* struct hdd_apf_context - hdd Context for apf
* @magic: magic number
* @qdf_apf_event: Completion variable for APF get operations
* @capability_response: capabilities response received from fw
* @apf_enabled: True: APF Interpreter enabled, False: Disabled
* @cmd_in_progress: Flag that indicates an APF command is in progress
* @buf: Buffer to accumulate read memory chunks
* @buf_len: Length of the read memory requested
* @offset: APF work memory offset to fetch from
* @lock: APF Context lock
*/
struct hdd_apf_context {
unsigned int magic;
qdf_event_t qdf_apf_event;
bool apf_enabled;
bool cmd_in_progress;
uint8_t *buf;
uint32_t buf_len;
uint32_t offset;
qdf_spinlock_t lock;
};
#endif /* FEATURE_WLAN_APF */
/** Number of Tx Queues */
#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_HL_NETDEV_FLOW_CONTROL)
#define NUM_TX_QUEUES 5
@ -1413,6 +1438,9 @@ struct hdd_adapter {
/* rcpi information */
struct rcpi_info rcpi;
bool send_mode_change;
#ifdef FEATURE_WLAN_APF
struct hdd_apf_context apf_context;
#endif /* FEATURE_WLAN_APF */
};
#define WLAN_HDD_GET_STATION_CTX_PTR(adapter) (&(adapter)->session.station)
@ -1822,7 +1850,6 @@ struct hdd_context {
struct completion set_antenna_mode_cmpl;
/* Current number of TX X RX chains being used */
enum antenna_mode current_antenna_mode;
bool apf_enabled;
/* the radio index assigned by cnss_logger */
int radio_index;
@ -1905,6 +1932,10 @@ struct hdd_context {
#ifdef WLAN_SUPPORT_TWT
enum twt_status twt_state;
#endif
#ifdef FEATURE_WLAN_APF
bool apf_supported;
uint32_t apf_version;
#endif
};
/**

View file

@ -26,8 +26,6 @@
#include "qca_vendor.h"
#include "wlan_osif_request_manager.h"
struct hdd_apf_context apf_context;
/*
* define short names for the global vendor params
* used by __wlan_hdd_cfg80211_apf_offload()
@ -63,18 +61,19 @@ wlan_hdd_apf_offload_policy[APF_MAX + 1] = {
[APF_PROG_LEN] = {.type = NLA_U32},
};
void hdd_apf_context_init(void)
void hdd_apf_context_init(struct hdd_adapter *adapter)
{
qdf_event_create(&apf_context.qdf_apf_event);
qdf_spinlock_create(&apf_context.lock);
apf_context.apf_enabled = true;
qdf_event_create(&adapter->apf_context.qdf_apf_event);
qdf_spinlock_create(&adapter->apf_context.lock);
adapter->apf_context.apf_enabled = true;
}
void hdd_apf_context_destroy(void)
void hdd_apf_context_destroy(struct hdd_adapter *adapter)
{
qdf_event_destroy(&apf_context.qdf_apf_event);
qdf_spinlock_destroy(&apf_context.lock);
qdf_mem_zero(&apf_context, sizeof(apf_context));
qdf_event_destroy(&adapter->apf_context.qdf_apf_event);
qdf_spinlock_destroy(&adapter->apf_context.lock);
qdf_mem_zero(&adapter->apf_context,
sizeof(struct hdd_apf_context));
}
struct apf_offload_priv {
@ -99,6 +98,8 @@ void hdd_get_apf_capabilities_cb(void *context,
priv->apf_get_offload = *data;
osif_request_complete(request);
osif_request_put(request);
hdd_exit();
}
/**
@ -128,6 +129,7 @@ hdd_post_get_apf_capabilities_rsp(struct hdd_context *hdd_ctx,
return -ENOMEM;
}
hdd_ctx->apf_version = apf_get_offload->apf_version;
hdd_debug("APF Version: %u APF max bytes: %u",
apf_get_offload->apf_version,
apf_get_offload->max_bytes_for_apf_inst);
@ -315,31 +317,27 @@ fail:
/**
* hdd_enable_disable_apf - Enable or Disable the APF interpreter
* @vdev_id: VDEV id
* @hdd_ctx: Hdd context
* @adapter: HDD Adapter
* @apf_enable: true: Enable APF Int., false: disable APF Int.
*
* Return: 0 on success, errno on failure
*/
static int
hdd_enable_disable_apf(struct hdd_context *hdd_ctx, uint8_t vdev_id,
bool apf_enable)
hdd_enable_disable_apf(struct hdd_adapter *adapter, bool apf_enable)
{
QDF_STATUS status;
hdd_enter();
status = sme_set_apf_enable_disable(hdd_ctx->mac_handle,
vdev_id, apf_enable);
status = sme_set_apf_enable_disable(hdd_adapter_get_mac_handle(adapter),
adapter->session_id, apf_enable);
if (!QDF_IS_STATUS_SUCCESS(status)) {
hdd_err("Unable to post sme apf enable/disable message (status-%d)",
status);
return -EINVAL;
}
qdf_spin_lock(&apf_context.lock);
apf_context.apf_enabled = apf_enable;
qdf_spin_unlock(&apf_context.lock);
adapter->apf_context.apf_enabled = apf_enable;
hdd_exit();
return 0;
@ -347,9 +345,8 @@ hdd_enable_disable_apf(struct hdd_context *hdd_ctx, uint8_t vdev_id,
/**
* hdd_apf_write_memory - Write into the apf work memory
* @hdd_ctx: Hdd context
* @adapter: HDD Adapter
* @tb: list of attributes
* @session_id: Session id
*
* This function writes code/data into the APF work memory and
* provides program length that is passed on to the interpreter.
@ -357,23 +354,18 @@ hdd_enable_disable_apf(struct hdd_context *hdd_ctx, uint8_t vdev_id,
* Return: 0 on success, errno on failure
*/
static int
hdd_apf_write_memory(struct hdd_context *hdd_ctx, struct nlattr **tb,
uint8_t session_id)
hdd_apf_write_memory(struct hdd_adapter *adapter, struct nlattr **tb)
{
struct wmi_apf_write_memory_params write_mem_params = {0};
struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
QDF_STATUS status;
int ret = 0;
bool apf_enabled;
hdd_enter();
write_mem_params.vdev_id = session_id;
qdf_spin_lock(&apf_context.lock);
apf_enabled = apf_context.apf_enabled;
qdf_spin_unlock(&apf_context.lock);
if (apf_enabled) {
write_mem_params.vdev_id = adapter->session_id;
if (adapter->apf_context.apf_enabled) {
hdd_err("Cannot get/set when APF interpreter is enabled");
return -EINVAL;
}
@ -413,10 +405,9 @@ hdd_apf_write_memory(struct hdd_context *hdd_ctx, struct nlattr **tb,
nla_memcpy(write_mem_params.buf, tb[APF_PROGRAM],
write_mem_params.length);
write_mem_params.apf_version =
apf_context.capability_response.apf_version;
write_mem_params.apf_version = hdd_ctx->apf_version;
status = sme_apf_write_work_memory(hdd_ctx->mac_handle,
status = sme_apf_write_work_memory(hdd_adapter_get_mac_handle(adapter),
&write_mem_params);
if (!QDF_IS_STATUS_SUCCESS(status)) {
hdd_err("Unable to retrieve APF caps");
@ -434,7 +425,7 @@ hdd_apf_write_memory(struct hdd_context *hdd_ctx, struct nlattr **tb,
* hdd_apf_read_memory_callback - HDD Callback for the APF read memory
* operation
* @context: Hdd context
* @read_mem_evt: APF read memory event response parameters
* @evt: APF read memory event response parameters
*
* Return: 0 on success, errno on failure
*/
@ -443,7 +434,8 @@ hdd_apf_read_memory_callback(void *hdd_context,
struct wmi_apf_read_memory_resp_event_params *evt)
{
struct hdd_context *hdd_ctx = hdd_context;
static struct hdd_apf_context *context = &apf_context;
struct hdd_adapter *adapter;
struct hdd_apf_context *context;
uint8_t *buf_ptr;
uint32_t pkt_offset;
@ -455,16 +447,16 @@ hdd_apf_read_memory_callback(void *hdd_context,
return;
}
qdf_spin_lock(&context->lock);
adapter = hdd_get_adapter_by_vdev(hdd_ctx, evt->vdev_id);
context = &adapter->apf_context;
if (context->magic != APF_CONTEXT_MAGIC) {
/* The caller presumably timed out, nothing to do */
qdf_spin_unlock(&context->lock);
hdd_err("Caller timed out or corrupt magic, simply return");
return;
}
if (evt->offset < context->offset) {
qdf_spin_unlock(&context->lock);
hdd_err("Offset in read event(%d) smaller than offset in request(%d)!",
evt->offset, context->offset);
return;
@ -478,7 +470,6 @@ hdd_apf_read_memory_callback(void *hdd_context,
pkt_offset = evt->offset - context->offset;
if (context->buf_len < pkt_offset + evt->length) {
qdf_spin_unlock(&context->lock);
hdd_err("Read chunk exceeding allocated space");
return;
}
@ -492,24 +483,21 @@ hdd_apf_read_memory_callback(void *hdd_context,
qdf_event_set(&context->qdf_apf_event);
}
qdf_spin_unlock(&context->lock);
hdd_exit();
}
/**
* hdd_apf_read_memory - Read part of the apf work memory
* @hdd_ctx: Hdd context
* @adapter: HDD Adapter
* @tb: list of attributes
* @session_id: Session id
*
* Return: 0 on success, errno on failure
*/
static int hdd_apf_read_memory(struct hdd_context *hdd_ctx, struct nlattr **tb,
uint8_t session_id)
static int hdd_apf_read_memory(struct hdd_adapter *adapter, struct nlattr **tb)
{
struct wmi_apf_read_memory_params read_mem_params = {0};
static struct hdd_apf_context *context = &apf_context;
struct hdd_apf_context *context = &adapter->apf_context;
struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
QDF_STATUS status;
unsigned long nl_buf_len = NLMSG_HDRLEN;
int ret = 0;
@ -518,7 +506,7 @@ static int hdd_apf_read_memory(struct hdd_context *hdd_ctx, struct nlattr **tb,
hdd_enter();
read_mem_params.vdev_id = session_id;
read_mem_params.vdev_id = adapter->session_id;
/* Read APF work memory offset */
if (!tb[APF_CURRENT_OFFSET]) {
@ -543,9 +531,7 @@ static int hdd_apf_read_memory(struct hdd_context *hdd_ctx, struct nlattr **tb,
return -ENOMEM;
}
qdf_spin_lock(&context->lock);
if (context->apf_enabled) {
qdf_spin_unlock(&context->lock);
hdd_err("Cannot get/set while interpreter is enabled");
return -EINVAL;
}
@ -556,9 +542,8 @@ static int hdd_apf_read_memory(struct hdd_context *hdd_ctx, struct nlattr **tb,
context->buf = bufptr;
context->buf_len = read_mem_params.length;
context->magic = APF_CONTEXT_MAGIC;
qdf_spin_unlock(&context->lock);
status = sme_apf_read_work_memory(hdd_ctx->mac_handle,
status = sme_apf_read_work_memory(hdd_adapter_get_mac_handle(adapter),
&read_mem_params,
hdd_apf_read_memory_callback);
if (QDF_IS_STATUS_ERROR(status)) {
@ -573,9 +558,7 @@ static int hdd_apf_read_memory(struct hdd_context *hdd_ctx, struct nlattr **tb,
WLAN_WAIT_TIME_APF_READ_MEM);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("Target response timed out");
qdf_spin_lock(&context->lock);
context->magic = 0;
qdf_spin_unlock(&context->lock);
ret = -ETIMEDOUT;
goto fail;
}
@ -628,11 +611,17 @@ __wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy,
struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
struct nlattr *tb[APF_MAX + 1];
int ret_val = 0, apf_subcmd;
uint8_t session_id = adapter->session_id;
static struct hdd_apf_context *context = &apf_context;
struct hdd_apf_context *context;
hdd_enter();
if (!adapter) {
hdd_err("Adapter is null");
return -EINVAL;
}
context = &adapter->apf_context;
ret_val = wlan_hdd_validate_context(hdd_ctx);
if (ret_val)
return ret_val;
@ -642,8 +631,14 @@ __wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy,
return -EINVAL;
}
if (!hdd_ctx->apf_enabled) {
hdd_err("APF offload is not supported/enabled");
if (!hdd_ctx->apf_supported) {
hdd_err("APF is not supported or disabled through INI");
return -ENOTSUPP;
}
if (!(adapter->device_mode == QDF_STA_MODE ||
adapter->device_mode == QDF_P2P_CLIENT_MODE)) {
hdd_err("APF only supported in STA or P2P CLI modes!");
return -ENOTSUPP;
}
@ -659,16 +654,11 @@ __wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy,
}
apf_subcmd = nla_get_u32(tb[APF_SUBCMD]);
if (!(adapter->device_mode == QDF_STA_MODE ||
adapter->device_mode == QDF_P2P_CLIENT_MODE)) {
hdd_err("APF only supported in STA or P2P CLI modes!");
return -ENOTSUPP;
}
/* Do not allow simultaneous new APF commands on the same adapter */
qdf_spin_lock(&context->lock);
if (context->cmd_in_progress) {
qdf_spin_unlock(&context->lock);
hdd_err("Another APF cmd in progress, try again later!");
hdd_err("Another cmd in progress for same session!");
return -EAGAIN;
}
context->cmd_in_progress = true;
@ -686,20 +676,16 @@ __wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy,
/* APF 3.0 sub-commands */
case QCA_WLAN_WRITE_PACKET_FILTER:
ret_val = hdd_apf_write_memory(hdd_ctx, tb, session_id);
ret_val = hdd_apf_write_memory(adapter, tb);
break;
case QCA_WLAN_READ_PACKET_FILTER:
ret_val = hdd_apf_read_memory(hdd_ctx, tb, session_id);
ret_val = hdd_apf_read_memory(adapter, tb);
break;
case QCA_WLAN_ENABLE_PACKET_FILTER:
ret_val = hdd_enable_disable_apf(hdd_ctx,
session_id,
true);
ret_val = hdd_enable_disable_apf(adapter, true);
break;
case QCA_WLAN_DISABLE_PACKET_FILTER:
ret_val = hdd_enable_disable_apf(hdd_ctx,
session_id,
false);
ret_val = hdd_enable_disable_apf(adapter, false);
break;
default:
hdd_err("Unknown APF Sub-command: %d", apf_subcmd);

View file

@ -1860,6 +1860,29 @@ static int hdd_generate_macaddr_auto(struct hdd_context *hdd_ctx)
return 0;
}
#ifdef FEATURE_WLAN_APF
/**
* hdd_update_apf_support() - Update APF supported flag in hdd context
* @hdd_ctx: Pointer to hdd_ctx
* @cfg: target configuration
*
* Update the APF support flag in HDD Context using INI and target config.
*
* Return: None
*/
static void hdd_update_apf_support(struct hdd_context *hdd_ctx,
struct wma_tgt_cfg *cfg)
{
hdd_ctx->apf_supported = (cfg->apf_enabled &&
hdd_ctx->config->apf_packet_filter_enable);
}
#else
static void hdd_update_apf_support(struct hdd_context *hdd_ctx,
struct wma_tgt_cfg *cfg)
{
}
#endif
/**
* hdd_update_ra_rate_limit() - Update RA rate limit from target
* configuration to cfg_ini in HDD
@ -2027,8 +2050,6 @@ void hdd_update_tgt_cfg(hdd_handle_t hdd_handle, struct wma_tgt_cfg *cfg)
hdd_debug("Init current antenna mode: %d",
hdd_ctx->current_antenna_mode);
hdd_ctx->apf_enabled = (cfg->apf_enabled &&
hdd_ctx->config->apf_packet_filter_enable);
hdd_ctx->rcpi_enabled = cfg->rcpi_enabled;
hdd_update_ra_rate_limit(hdd_ctx, cfg);
@ -2045,6 +2066,7 @@ void hdd_update_tgt_cfg(hdd_handle_t hdd_handle, struct wma_tgt_cfg *cfg)
if (QDF_IS_STATUS_ERROR(status))
hdd_err("fw update WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED to CFG fails");
hdd_update_apf_support(hdd_ctx, cfg);
hdd_debug("Target APF %d Host APF %d 8ss fw support %d txBFCsnValue %d",
cfg->apf_enabled, hdd_ctx->config->apf_packet_filter_enable,
@ -4266,6 +4288,7 @@ static void hdd_cleanup_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter
hdd_nud_deinit_tracking(adapter);
qdf_mutex_destroy(&adapter->disconnection_status_lock);
hdd_apf_context_destroy(adapter);
hdd_debugfs_exit(adapter);
@ -4885,6 +4908,7 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio
return NULL;
}
hdd_apf_context_init(adapter);
if (QDF_STATUS_SUCCESS == status) {
policy_mgr_set_concurrency_mode(hdd_ctx->hdd_psoc,
@ -6828,8 +6852,6 @@ static int hdd_context_deinit(struct hdd_context *hdd_ctx)
qdf_list_destroy(&hdd_ctx->hdd_adapters);
hdd_apf_context_destroy();
return 0;
}
@ -8760,8 +8782,6 @@ static int hdd_context_init(struct hdd_context *hdd_ctx)
init_completion(&hdd_ctx->mc_sus_event_var);
init_completion(&hdd_ctx->ready_to_suspend);
hdd_apf_context_init();
qdf_spinlock_create(&hdd_ctx->connection_status_lock);
qdf_spinlock_create(&hdd_ctx->sta_update_info_lock);
qdf_spinlock_create(&hdd_ctx->hdd_adapter_lock);