diff --git a/core/hdd/inc/wlan_hdd_apf.h b/core/hdd/inc/wlan_hdd_apf.h index e7bd5a15f879..8717d1df61b3 100644 --- a/core/hdd/inc/wlan_hdd_apf.h +++ b/core/hdd/inc/wlan_hdd_apf.h @@ -31,8 +31,44 @@ #ifndef __WLAN_HDD_APF_H #define __WLAN_HDD_APF_H +#ifdef FEATURE_WLAN_APF + +#include #include "sir_api.h" #include "wlan_hdd_main.h" +#include "wmi_unified_param.h" + +#define APF_CONTEXT_MAGIC 0x4575354 + +#define MAX_APF_MEMORY_LEN 4096 + +/* APF commands wait times in msec */ +#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 @@ -47,4 +83,44 @@ int wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len); + +/** + * hdd_apf_context_init - APF Context initialization operations + * + * Return: None + */ +void hdd_apf_context_init(void); + +/** + * hdd_apf_context_destroy - APF Context de-init operations + * + * Return: None + */ +void hdd_apf_context_destroy(void); + +/** + * hdd_get_apf_capabilities_cb() - Callback function to get APF capabilities + * @hdd_context: hdd_context + * @apf_get_offload: struct for get offload + * + * This function receives the response/data from the lower layer and + * checks to see if the thread is still waiting then post the results to + * upper layer, if the request has timed out then ignore. + * + * Return: None + */ +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_destroy(void) +{ +} + +#endif /* FEATURE_WLAN_APF */ + #endif /* WLAN_HDD_APF_H */ diff --git a/core/hdd/src/wlan_hdd_apf.c b/core/hdd/src/wlan_hdd_apf.c index 432114677d01..71065f2c1257 100644 --- a/core/hdd/src/wlan_hdd_apf.c +++ b/core/hdd/src/wlan_hdd_apf.c @@ -26,13 +26,15 @@ #include "qca_vendor.h" #include "wlan_hdd_request_manager.h" +struct hdd_apf_context apf_context; + /* * define short names for the global vendor params * used by __wlan_hdd_cfg80211_apf_offload() */ #define APF_INVALID \ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_INVALID -#define APF_SET_RESET \ +#define APF_SUBCMD \ QCA_WLAN_VENDOR_ATTR_SET_RESET_PACKET_FILTER #define APF_VERSION \ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_VERSION @@ -44,25 +46,43 @@ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET #define APF_PROGRAM \ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM +#define APF_PROG_LEN \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROG_LENGTH #define APF_MAX \ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_MAX static const struct nla_policy wlan_hdd_apf_offload_policy[APF_MAX + 1] = { - [APF_SET_RESET] = {.type = NLA_U32}, + [APF_SUBCMD] = {.type = NLA_U32}, [APF_VERSION] = {.type = NLA_U32}, [APF_FILTER_ID] = {.type = NLA_U32}, [APF_PACKET_SIZE] = {.type = NLA_U32}, [APF_CURRENT_OFFSET] = {.type = NLA_U32}, - [APF_PROGRAM] = {.type = NLA_U8}, + [APF_PROGRAM] = {.type = NLA_BINARY, + .len = MAX_APF_MEMORY_LEN}, + [APF_PROG_LEN] = {.type = NLA_U32}, }; +void hdd_apf_context_init(void) +{ + qdf_event_create(&apf_context.qdf_apf_event); + qdf_spinlock_create(&apf_context.lock); + apf_context.apf_enabled = true; +} + +void hdd_apf_context_destroy(void) +{ + qdf_event_destroy(&apf_context.qdf_apf_event); + qdf_spinlock_destroy(&apf_context.lock); + qdf_mem_zero(&apf_context, sizeof(apf_context)); +} + struct apf_offload_priv { struct sir_apf_get_offload apf_get_offload; }; -static void hdd_get_apf_offload_cb(void *context, - struct sir_apf_get_offload *data) +void hdd_get_apf_capabilities_cb(void *context, + struct sir_apf_get_offload *data) { struct hdd_request *request; struct apf_offload_priv *priv; @@ -129,12 +149,12 @@ nla_put_failure: } /** - * hdd_get_apf_offload - Get APF offload Capabilities + * hdd_get_apf_capabilities - Get APF offload Capabilities * @hdd_ctx: Hdd context * * Return: 0 on success, errno on failure */ -static int hdd_get_apf_offload(struct hdd_context *hdd_ctx) +static int hdd_get_apf_capabilities(struct hdd_context *hdd_ctx) { QDF_STATUS status; int ret; @@ -155,9 +175,9 @@ static int hdd_get_apf_offload(struct hdd_context *hdd_ctx) } cookie = hdd_request_cookie(request); - status = sme_get_apf_offload_capabilities(hdd_ctx->hHal, - hdd_get_apf_offload_cb, - cookie); + status = sme_get_apf_capabilities(hdd_ctx->hHal, + hdd_get_apf_capabilities_cb, + cookie); if (!QDF_IS_STATUS_SUCCESS(status)) { hdd_err("Unable to retrieve APF caps"); ret = qdf_status_to_os_return(status); @@ -206,13 +226,10 @@ static int hdd_set_reset_apf_offload(struct hdd_context *hdd_ctx, hdd_enter(); - if (adapter->device_mode == QDF_STA_MODE || - adapter->device_mode == QDF_P2P_CLIENT_MODE) { - if (!hdd_conn_is_connected( - WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { - hdd_err("Not in Connected state!"); - return -ENOTSUPP; - } + if (!hdd_conn_is_connected( + WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_err("Not in Connected state!"); + return -ENOTSUPP; } apf_set_offload = qdf_mem_malloc(sizeof(*apf_set_offload)); @@ -296,6 +313,299 @@ fail: return ret; } +/** + * hdd_enable_disable_apf - Enable or Disable the APF interpreter + * @vdev_id: VDEV id + * @hdd_ctx: Hdd context + * @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) +{ + QDF_STATUS status; + + hdd_enter(); + + status = sme_set_apf_enable_disable(hdd_ctx->hHal, vdev_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); + + hdd_exit(); + return 0; +} + +/** + * hdd_apf_write_memory - Write into the apf work memory + * @hdd_ctx: Hdd context + * @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. + * + * 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) +{ + struct wmi_apf_write_memory_params write_mem_params = {0}; + 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) { + hdd_err("Cannot get/set when APF interpreter is enabled"); + return -EINVAL; + } + + /* Read program length */ + if (!tb[APF_PROG_LEN]) { + hdd_err("attr program length failed"); + return -EINVAL; + } + write_mem_params.program_len = nla_get_u32(tb[APF_PROG_LEN]); + + /* Read APF work memory offset */ + if (!tb[APF_CURRENT_OFFSET]) { + hdd_err("attr apf packet size failed"); + return -EINVAL; + } + write_mem_params.addr_offset = nla_get_u32(tb[APF_CURRENT_OFFSET]); + + /* Parse and fetch apf program */ + if (!tb[APF_PROGRAM]) { + hdd_err("attr apf program failed"); + return -EINVAL; + } + + write_mem_params.length = nla_len(tb[APF_PROGRAM]); + if (!write_mem_params.length) { + hdd_err("Program attr with empty data"); + return -EINVAL; + } + + write_mem_params.buf = qdf_mem_malloc(sizeof(uint8_t) + * write_mem_params.length); + if (write_mem_params.buf == NULL) { + hdd_err("failed to alloc mem for apf write mem operation"); + return -EINVAL; + } + nla_memcpy(write_mem_params.buf, tb[APF_PROGRAM], + write_mem_params.length); + + write_mem_params.apf_version = + apf_context.capability_response.apf_version; + + status = sme_apf_write_work_memory(hdd_ctx->hHal, &write_mem_params); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Unable to retrieve APF caps"); + ret = -EINVAL; + } + + if (write_mem_params.buf) + qdf_mem_free(write_mem_params.buf); + + hdd_exit(); + return ret; +} + +/** + * 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 + * + * Return: 0 on success, errno on failure + */ +static void +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; + uint8_t *buf_ptr; + uint32_t pkt_offset; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx) || !evt) { + hdd_err("HDD context is invalid or event buf(%pK) is null", + evt); + return; + } + + qdf_spin_lock(&context->lock); + 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; + } + + /* + * offset in the event is relative to the APF work memory. + * Calculate the packet offset, which gives us the relative + * location in the buffer to start copy into. + */ + 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; + } + buf_ptr = context->buf + pkt_offset; + + qdf_mem_copy(buf_ptr, evt->data, evt->length); + + if (!evt->more_data) { + /* Release the caller after last event, clear magic */ + context->magic = 0; + 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 + * @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) +{ + struct wmi_apf_read_memory_params read_mem_params = {0}; + static struct hdd_apf_context *context = &apf_context; + QDF_STATUS status; + unsigned long nl_buf_len = NLMSG_HDRLEN; + int ret = 0; + struct sk_buff *skb = NULL; + uint8_t *bufptr; + + hdd_enter(); + + read_mem_params.vdev_id = session_id; + + /* Read APF work memory offset */ + if (!tb[APF_CURRENT_OFFSET]) { + hdd_err("attr apf memory offset failed"); + return -EINVAL; + } + read_mem_params.addr_offset = nla_get_u32(tb[APF_CURRENT_OFFSET]); + + /* Read length */ + if (!tb[APF_PACKET_SIZE]) { + hdd_err("attr apf packet size failed"); + return -EINVAL; + } + read_mem_params.length = nla_get_u32(tb[APF_PACKET_SIZE]); + if (!read_mem_params.length) { + hdd_err("apf read length cannot be zero!"); + return -EINVAL; + } + bufptr = qdf_mem_malloc(read_mem_params.length); + if (bufptr == NULL) { + hdd_err("alloc failed for cumulative event buffer"); + 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; + } + + qdf_event_reset(&context->qdf_apf_event); + context->offset = read_mem_params.addr_offset; + + 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->hHal, &read_mem_params, + hdd_apf_read_memory_callback); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to post sme APF read memory message (status-%d)", + status); + ret = -EINVAL; + goto fail; + } + + /* request was sent -- wait for the response */ + status = qdf_wait_for_event_completion(&context->qdf_apf_event, + 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; + } + + nl_buf_len += sizeof(uint32_t) + NLA_HDRLEN; + nl_buf_len += context->buf_len + NLA_HDRLEN; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + ret = -ENOMEM; + goto fail; + } + + if (nla_put_u32(skb, APF_SUBCMD, QCA_WLAN_READ_PACKET_FILTER) || + nla_put(skb, APF_PROGRAM, read_mem_params.length, context->buf)) { + hdd_err("put fail"); + kfree_skb(skb); + ret = -EINVAL; + goto fail; + } + + cfg80211_vendor_cmd_reply(skb); +fail: + if (context->buf) { + qdf_mem_free(context->buf); + context->buf = NULL; + } + + hdd_exit(); + return ret; +} + /** * wlan_hdd_cfg80211_apf_offload() - Set/Reset to APF Offload * @wiphy: wiphy structure pointer @@ -314,7 +624,9 @@ __wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy, struct net_device *dev = wdev->netdev; struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); struct nlattr *tb[APF_MAX + 1]; - int ret_val, packet_filter_subcmd; + int ret_val = 0, apf_subcmd; + uint8_t session_id = adapter->session_id; + static struct hdd_apf_context *context = &apf_context; hdd_enter(); @@ -338,18 +650,64 @@ __wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy, return -EINVAL; } - if (!tb[APF_SET_RESET]) { - hdd_err("attr apf set reset failed"); + if (!tb[APF_SUBCMD]) { + hdd_err("attr apf sub-command failed"); return -EINVAL; } + apf_subcmd = nla_get_u32(tb[APF_SUBCMD]); - packet_filter_subcmd = nla_get_u32(tb[APF_SET_RESET]); + 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; + } - if (packet_filter_subcmd == QCA_WLAN_GET_PACKET_FILTER) - return hdd_get_apf_offload(hdd_ctx); - else - return hdd_set_reset_apf_offload(hdd_ctx, tb, - 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!"); + return -EAGAIN; + } + context->cmd_in_progress = true; + qdf_spin_unlock(&context->lock); + + switch (apf_subcmd) { + /* Legacy APF sub-commands */ + case QCA_WLAN_SET_PACKET_FILTER: + ret_val = hdd_set_reset_apf_offload(hdd_ctx, tb, + adapter); + break; + case QCA_WLAN_GET_PACKET_FILTER: + ret_val = hdd_get_apf_capabilities(hdd_ctx); + break; + + /* APF 3.0 sub-commands */ + case QCA_WLAN_WRITE_PACKET_FILTER: + ret_val = hdd_apf_write_memory(hdd_ctx, tb, session_id); + break; + case QCA_WLAN_READ_PACKET_FILTER: + ret_val = hdd_apf_read_memory(hdd_ctx, tb, session_id); + break; + case QCA_WLAN_ENABLE_PACKET_FILTER: + ret_val = hdd_enable_disable_apf(hdd_ctx, + session_id, + true); + break; + case QCA_WLAN_DISABLE_PACKET_FILTER: + ret_val = hdd_enable_disable_apf(hdd_ctx, + session_id, + false); + break; + default: + hdd_err("Unknown APF Sub-command: %d", apf_subcmd); + ret_val = -ENOTSUPP; + } + + qdf_spin_lock(&context->lock); + context->cmd_in_progress = false; + qdf_spin_unlock(&context->lock); + + return ret_val; } int diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 05efbeeb9950..ca3f0aaf138d 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -92,7 +92,9 @@ #include "wlan_hdd_disa.h" #include "wlan_hdd_request_manager.h" #include "wlan_hdd_he.h" +#ifdef FEATURE_WLAN_APF #include "wlan_hdd_apf.h" +#endif #include #include diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 66d6a1d19d6a..4be37484df2e 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -6754,6 +6754,8 @@ static int hdd_context_deinit(struct hdd_context *hdd_ctx) qdf_list_destroy(&hdd_ctx->hdd_adapters); + hdd_apf_context_destroy(); + return 0; } @@ -8644,6 +8646,8 @@ 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); diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 421f9cb1f7fd..8881bc1b37f9 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -1297,8 +1297,9 @@ QDF_STATUS sme_add_beacon_filter(tHalHandle hal, uint32_t session_id, uint32_t *ie_map); QDF_STATUS sme_remove_beacon_filter(tHalHandle hal, uint32_t session_id); +#ifdef FEATURE_WLAN_APF /** - * sme_get_apf_offload_capabilities() - Get APF offload capabilities + * sme_get_apf_capabilities() - Get APF capabilities * @hal: Global HAL handle * @callback: Callback function to be called with the result * @context: Opaque context to be used by the caller to associate the @@ -1309,12 +1310,66 @@ QDF_STATUS sme_remove_beacon_filter(tHalHandle hal, uint32_t session_id); * * Return: QDF_STATUS enumeration */ -QDF_STATUS sme_get_apf_offload_capabilities(tHalHandle hal, - apf_get_offload_cb callback, - void *context); +QDF_STATUS sme_get_apf_capabilities(tHalHandle hal, + apf_get_offload_cb callback, + void *context); +/** + * sme_set_apf_instructions() - Set APF apf filter instructions. + * @hal: HAL handle + * @apf_set_offload: struct to set apf filter instructions. + * + * APFv2 (Legacy APF) API to set the APF packet filter. + * + * Return: QDF_STATUS enumeration. + */ QDF_STATUS sme_set_apf_instructions(tHalHandle hal, - struct sir_apf_set_offload *); + struct sir_apf_set_offload + *apf_set_offload); + +/** + * sme_set_apf_enable_disable - Send apf enable/disable cmd + * @hal: global hal handle + * @vdev_id: vdev id + * @apf_enable: true: Enable APF Int., false: Disable APF Int. + * + * API to either enable or disable the APF interpreter. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_set_apf_enable_disable(tHalHandle hal, uint8_t vdev_id, + bool apf_enable); + +/** + * sme_apf_write_work_memory - Write into the apf work memory + * @hal: global hal handle + * @write_params: APF parameters for the write operation + * + * API for writing into the APF work memory. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_apf_write_work_memory(tHalHandle hal, + struct wmi_apf_write_memory_params + *write_params); + +/** + * sme_apf_read_work_memory - Read part of apf work memory + * @hal: global hal handle + * @read_params: APF parameters for the get operation + * @callback: callback to handle the the read response + * + * API for issuing a APF read memory request. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS +sme_apf_read_work_memory(tHalHandle hal, + struct wmi_apf_read_memory_params *read_params, + apf_read_mem_cb callback); + +#endif /* FEATURE_WLAN_APF */ + uint32_t sme_get_wni_dot11_mode(tHalHandle hal); QDF_STATUS sme_create_mon_session(tHalHandle hal_handle, uint8_t *bssid); QDF_STATUS sme_set_adaptive_dwelltime_config(tHalHandle hal, diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index df6b6642fffc..9e9d5346d8bc 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -123,6 +123,7 @@ typedef void (*p2p_lo_callback)(void *context, void *event); typedef void (*sme_send_oem_data_rsp_msg)(struct oem_data_rsp *); #endif +#ifdef FEATURE_WLAN_APF /** * typedef apf_get_offload_cb - APF offload callback signature * @context: Opaque context that the client can use to associate the @@ -133,6 +134,17 @@ struct sir_apf_get_offload; typedef void (*apf_get_offload_cb)(void *context, struct sir_apf_get_offload *caps); +/** + * typedef apf_read_mem_cb - APF read memory response callback + * @context: Opaque context that the client can use to associate the + * callback with the request + * @evt: APF read memory response event parameters + */ +typedef void (*apf_read_mem_cb)(void *context, + struct wmi_apf_read_memory_resp_event_params + *evt); +#endif /* FEATURE_WLAN_APF */ + /** * typedef sme_encrypt_decrypt_callback - encrypt/decrypt callback * signature @@ -228,7 +240,6 @@ typedef struct tagSmeStruct { ocb_callback dcc_stats_event_callback; sme_set_thermal_level_callback set_thermal_level_cb; void *apf_get_offload_context; - apf_get_offload_cb apf_get_offload_cb; p2p_lo_callback p2p_lo_event_callback; void *p2p_lo_event_context; #ifdef FEATURE_OEM_DATA_SUPPORT @@ -259,6 +270,10 @@ typedef struct tagSmeStruct { void (*twt_enable_cb)(void *hdd_ctx, struct wmi_twt_enable_complete_event_param *params); void (*twt_disable_cb)(void *hdd_ctx); +#ifdef FEATURE_WLAN_APF + apf_get_offload_cb apf_get_offload_cb; + apf_read_mem_cb apf_read_mem_cb; +#endif } tSmeStruct, *tpSmeStruct; #endif /* #if !defined( __SMEINTERNAL_H ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 85d049d14f01..ea1b4d58548c 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -14115,9 +14115,10 @@ void sme_send_disassoc_req_frame(tHalHandle hal, uint8_t session_id, FL("cds_send_mb_message Failed")); } -QDF_STATUS sme_get_apf_offload_capabilities(tHalHandle hal, - apf_get_offload_cb callback, - void *context) +#ifdef FEATURE_WLAN_APF +QDF_STATUS sme_get_apf_capabilities(tHalHandle hal, + apf_get_offload_cb callback, + void *context) { QDF_STATUS status = QDF_STATUS_SUCCESS; tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); @@ -14147,14 +14148,6 @@ QDF_STATUS sme_get_apf_offload_capabilities(tHalHandle hal, return status; } - -/** - * sme_set_apf_instructions() - Set APF apf filter instructions. - * @hal: HAL handle - * @apf_set_offload: struct to set apf filter instructions. - * - * Return: QDF_STATUS enumeration. - */ QDF_STATUS sme_set_apf_instructions(tHalHandle hal, struct sir_apf_set_offload *req) { @@ -14205,6 +14198,66 @@ QDF_STATUS sme_set_apf_instructions(tHalHandle hal, return status; } +QDF_STATUS sme_set_apf_enable_disable(tHalHandle hal, uint8_t vdev_id, + bool apf_enable) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wma_send_apf_enable_cmd(wma_handle, vdev_id, apf_enable); +} + +QDF_STATUS +sme_apf_write_work_memory(tHalHandle hal, + struct wmi_apf_write_memory_params *write_params) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wma_send_apf_write_work_memory_cmd(wma_handle, write_params); +} + +QDF_STATUS +sme_apf_read_work_memory(tHalHandle hal, + struct wmi_apf_read_memory_params *read_params, + apf_read_mem_cb callback) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + void *wma_handle; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.apf_read_mem_cb = callback; + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed")); + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wma_send_apf_read_work_memory_cmd(wma_handle, read_params); +} +#endif /* FEATURE_WLAN_APF */ + /** * sme_get_wni_dot11_mode() - return configured wni dot11mode * @hal: hal pointer diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index 03bb3e481373..f2d2c4d26b50 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -2148,14 +2148,103 @@ void wma_process_fw_test_cmd(WMA_HANDLE handle, QDF_STATUS wma_send_ht40_obss_scanind(tp_wma_handle wma, struct obss_ht40_scanind *req); +uint32_t wma_get_num_of_setbits_from_bitmask(uint32_t mask); + +#ifdef FEATURE_WLAN_APF +/** + * wma_get_apf_caps_event_handler() - Event handler for get apf capability + * @handle: WMA global handle + * @cmd_param_info: command event data + * @len: Length of @cmd_param_info + * + * Return: 0 on Success or Errno on failure + */ int wma_get_apf_caps_event_handler(void *handle, u_int8_t *cmd_param_info, u_int32_t len); -uint32_t wma_get_num_of_setbits_from_bitmask(uint32_t mask); + +/** + * wma_get_apf_capabilities - Send get apf capability to firmware + * @wma_handle: wma handle + * + * Return: QDF_STATUS enumeration. + */ QDF_STATUS wma_get_apf_capabilities(tp_wma_handle wma); + +/** + * wma_set_apf_instructions - Set apf instructions to firmware + * @wma: wma handle + * @apf_set_offload: APF offload information to set to firmware + * + * Return: QDF_STATUS enumeration + */ QDF_STATUS wma_set_apf_instructions(tp_wma_handle wma, struct sir_apf_set_offload *apf_set_offload); + +/** + * wma_send_apf_enable_cmd - Send apf enable/disable cmd + * @wma_handle: wma handle + * @vdev_id: vdev id + * @apf_enable: true: Enable APF Int., false: Disable APF Int. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS wma_send_apf_enable_cmd(WMA_HANDLE handle, uint8_t vdev_id, + bool apf_enable); + +/** + * wma_send_apf_write_work_memory_cmd - Command to write into the apf work + * memory + * @wma_handle: wma handle + * @write_params: APF parameters for the write operation + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS +wma_send_apf_write_work_memory_cmd(WMA_HANDLE handle, + struct wmi_apf_write_memory_params + *write_params); + +/** + * wma_send_apf_read_work_memory_cmd - Command to get part of apf work memory + * @wma_handle: wma handle + * @callback: HDD callback to receive apf get mem event + * @context: Context for the HDD callback + * @read_params: APF parameters for the get operation + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS +wma_send_apf_read_work_memory_cmd(WMA_HANDLE handle, + struct wmi_apf_read_memory_params + *read_params); + +/** + * wma_apf_read_work_memory_event_handler - Event handler for get apf mem + * operation + * @handle: wma handle + * @evt_buf: Buffer pointer to the event + * @len: Length of the event buffer + * + * Return: status. + */ +int wma_apf_read_work_memory_event_handler(void *handle, uint8_t *evt_buf, + uint32_t len); +#else /* FEATURE_WLAN_APF */ +static inline QDF_STATUS wma_get_apf_capabilities(tp_wma_handle wma) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wma_set_apf_instructions(tp_wma_handle wma, + struct sir_apf_set_offload *apf_set_offload) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_APF */ + void wma_process_set_pdev_ie_req(tp_wma_handle wma, struct set_ie_param *ie_params); void wma_process_set_pdev_ht_ie_req(tp_wma_handle wma, diff --git a/core/wma/src/wma_dev_if.c b/core/wma/src/wma_dev_if.c index beb7360d980a..c063763afe24 100644 --- a/core/wma/src/wma_dev_if.c +++ b/core/wma/src/wma_dev_if.c @@ -1807,6 +1807,7 @@ static int wma_remove_bss_peer(tp_wma_handle wma, void *pdev, return ret_value; } +#ifdef FEATURE_WLAN_APF /* * get_fw_active_apf_mode() - convert HDD APF mode to FW configurable APF * mode @@ -1850,6 +1851,12 @@ static QDF_STATUS wma_config_active_apf_mode(t_wma_handle *wma, uint8_t vdev_id) return wmi_unified_set_active_apf_mode_cmd(wma->wmi_handle, vdev_id, uc_mode, mcbc_mode); } +#else /* FEATURE_WLAN_APF */ +static QDF_STATUS wma_config_active_apf_mode(t_wma_handle *wma, uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_APF */ #ifdef FEATURE_AP_MCC_CH_AVOIDANCE /** diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index f9085a0f6ac7..c3d0f1611af7 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -1635,7 +1635,7 @@ static const u8 *wma_wow_wake_reason_str(A_INT32 wake_reason) case WOW_REASON_ACTION_FRAME_RECV: return "ACTION_FRAME_RECV"; case WOW_REASON_BPF_ALLOW: - return "APF_ALLOW"; + return "BPF_ALLOW"; case WOW_REASON_NAN_DATA: return "NAN_DATA"; case WOW_REASON_OEM_RESPONSE_EVENT: @@ -4381,6 +4381,7 @@ QDF_STATUS wma_process_set_ie_info(tp_wma_handle wma, return ret; } +#ifdef FEATURE_WLAN_APF /** * wma_get_apf_caps_event_handler() - Event handler for get apf capability * @handle: WMA global handle @@ -4431,12 +4432,6 @@ int wma_get_apf_caps_event_handler(void *handle, u_int8_t *cmd_param_info, return 0; } -/** - * wma_get_apf_capabilities - Send get apf capability to firmware - * @wma_handle: wma handle - * - * Return: QDF_STATUS enumeration. - */ QDF_STATUS wma_get_apf_capabilities(tp_wma_handle wma) { QDF_STATUS status = QDF_STATUS_SUCCESS; @@ -4478,13 +4473,6 @@ QDF_STATUS wma_get_apf_capabilities(tp_wma_handle wma) return status; } -/** - * wma_set_apf_instructions - Set apf instructions to firmware - * @wma: wma handle - * @apf_set_offload: apf offload information to set to firmware - * - * Return: QDF_STATUS enumeration - */ QDF_STATUS wma_set_apf_instructions(tp_wma_handle wma, struct sir_apf_set_offload *apf_set_offload) { @@ -4568,6 +4556,141 @@ QDF_STATUS wma_set_apf_instructions(tp_wma_handle wma, return QDF_STATUS_SUCCESS; } +QDF_STATUS wma_send_apf_enable_cmd(WMA_HANDLE handle, uint8_t vdev_id, + bool apf_enable) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tp_wma_handle wma = (tp_wma_handle) handle; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE(FL("WMA is closed, can not issue get APF capab")); + return QDF_STATUS_E_INVAL; + } + + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BPF_OFFLOAD)) { + WMA_LOGE(FL("APF cababilities feature bit not enabled")); + return QDF_STATUS_E_FAILURE; + } + + status = wmi_unified_send_apf_enable_cmd(wma->wmi_handle, vdev_id, + apf_enable); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("Failed to send apf enable/disable cmd"); + return QDF_STATUS_E_FAILURE; + } + + if (apf_enable) + WMA_LOGD("Sent APF Enable on vdevid: %d", vdev_id); + else + WMA_LOGD("Sent APF Disable on vdevid: %d", vdev_id); + + return status; +} + +QDF_STATUS +wma_send_apf_write_work_memory_cmd(WMA_HANDLE handle, + struct wmi_apf_write_memory_params + *write_params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tp_wma_handle wma = (tp_wma_handle) handle; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE(FL("WMA is closed, can not issue write APF mem")); + return QDF_STATUS_E_INVAL; + } + + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BPF_OFFLOAD)) { + WMA_LOGE(FL("APF cababilities feature bit not enabled")); + return QDF_STATUS_E_FAILURE; + } + + if (wmi_unified_send_apf_write_work_memory_cmd(wma->wmi_handle, + write_params)) { + WMA_LOGE(FL("Failed to send APF write mem command")); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Sent APF wite mem on vdevid: %d", write_params->vdev_id); + return status; +} + +int wma_apf_read_work_memory_event_handler(void *handle, uint8_t *evt_buf, + uint32_t len) +{ + tp_wma_handle wma_handle; + wmi_unified_t wmi_handle; + struct wmi_apf_read_memory_resp_event_params evt_params = {0}; + QDF_STATUS status; + tpAniSirGlobal pmac = cds_get_context(QDF_MODULE_ID_PE); + + WMA_LOGI(FL("handle:%pK event:%pK len:%u"), handle, evt_buf, len); + + wma_handle = handle; + if (!wma_handle) { + WMA_LOGE(FL("NULL wma_handle")); + return -EINVAL; + } + + wmi_handle = wma_handle->wmi_handle; + if (!wmi_handle) { + WMA_LOGE(FL("NULL wmi_handle")); + return -EINVAL; + } + + if (!pmac) { + WMA_LOGE(FL("Invalid pmac")); + return -EINVAL; + } + + if (!pmac->sme.apf_read_mem_cb) { + WMA_LOGE(FL("Callback not registered")); + return -EINVAL; + } + + status = wmi_extract_apf_read_memory_resp_event(wmi_handle, + evt_buf, &evt_params); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE(FL("Event extract failure: %d"), status); + return -EINVAL; + } + + pmac->sme.apf_read_mem_cb(pmac->hHdd, &evt_params); + + return 0; +} + +QDF_STATUS wma_send_apf_read_work_memory_cmd(WMA_HANDLE handle, + struct wmi_apf_read_memory_params + *read_params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tp_wma_handle wma = (tp_wma_handle) handle; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE(FL("WMA is closed, can not issue read APF memory")); + return QDF_STATUS_E_INVAL; + } + + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BPF_OFFLOAD)) { + WMA_LOGE(FL("APF cababilities feature bit not enabled")); + return QDF_STATUS_E_FAILURE; + } + + if (wmi_unified_send_apf_read_work_memory_cmd(wma->wmi_handle, + read_params)) { + WMA_LOGE(FL("Failed to send APF read memory command")); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Sent APF read memory on vdevid: %d", read_params->vdev_id); + return status; +} +#endif /* FEATURE_WLAN_APF */ + /** * wma_set_tx_rx_aggregation_size() - sets tx rx aggregation sizes * @tx_rx_aggregation_size: aggregation size parameters diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 28406887a362..027dfdfac9b9 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -3033,6 +3033,30 @@ static void wma_register_stats_events(wmi_unified_t wmi_handle) } #endif +#ifdef FEATURE_WLAN_APF +static void wma_register_apf_events(tp_wma_handle wma_handle) +{ + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_INFO, + "wma_handle is NULL\n"); + return; + } + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_apf_capability_info_event_id, + wma_get_apf_caps_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_apf_get_vdev_work_memory_resp_event_id, + wma_apf_read_work_memory_event_handler, + WMA_RX_SERIALIZER_CTX); +} +#else /* FEATURE_WLAN_APF */ +static void wma_register_apf_events(tp_wma_handle wma_handle) +{ +} +#endif /* FEATURE_WLAN_APF */ + /** * wma_open() - Allocate wma context and initialize it. * @cds_context: cds context @@ -3492,10 +3516,6 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc, wmi_peer_delete_response_event_id, wma_peer_delete_handler, WMA_RX_SERIALIZER_CTX); - wmi_unified_register_event_handler(wma_handle->wmi_handle, - wmi_apf_capability_info_event_id, - wma_get_apf_caps_event_handler, - WMA_RX_SERIALIZER_CTX); wmi_unified_register_event_handler(wma_handle->wmi_handle, wmi_chan_info_event_id, wma_chan_info_event_handler, @@ -3571,6 +3591,7 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc, WMA_RX_SERIALIZER_CTX); #endif + wma_register_apf_events(wma_handle); return QDF_STATUS_SUCCESS;