From 29164f263f8043da941db2572e9622f8bdbda4c6 Mon Sep 17 00:00:00 2001 From: Samuel Ahn Date: Tue, 19 Jan 2016 17:19:29 -0800 Subject: [PATCH] qcacld-2.0: Add support for default TX params in OCB mode When OCB mode is configured, default TX parameters can be provided. These default TX parameters are used if a packet is sent without a TX control header. Change-Id: I72b3799cb0a9e00a60548facf25e57be241d82d7 CRs-Fixed: 964279 --- .../qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_tx.c | 59 ++++++++++++- .../qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c | 86 +++++++++++++++++++ .../CORE/CLD_TXRX/TXRX/ol_txrx_types.h | 3 + .../qcacld-2.0/CORE/HDD/src/wlan_hdd_ocb.c | 17 +++- .../qcacld-2.0/CORE/HDD/src/wlan_hdd_ocb.h | 10 ++- .../wireless/qcacld-2.0/CORE/MAC/inc/sirApi.h | 6 +- .../CORE/SERVICES/COMMON/ol_txrx_ctrl_api.h | 13 +++ .../qcacld-2.0/CORE/SERVICES/WMA/wma_ocb.c | 11 ++- .../CORE/SME/src/sme_common/sme_Api.c | 10 ++- 9 files changed, 206 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_tx.c b/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_tx.c index 26678f8da675..e5bcd611caf2 100644 --- a/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_tx.c +++ b/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_tx.c @@ -552,11 +552,14 @@ ol_tx_non_std_ll( */ #define OCB_HEADER_VERSION 1 static bool parse_ocb_tx_header(adf_nbuf_t msdu, - struct ocb_tx_ctrl_hdr_t *tx_ctrl) + struct ocb_tx_ctrl_hdr_t *tx_ctrl, + bool *tx_ctrl_header_found) { struct ether_header *eth_hdr_p; struct ocb_tx_ctrl_hdr_t *tx_ctrl_hdr; + *tx_ctrl_header_found = false; + /* Check if TX control header is present */ eth_hdr_p = (struct ether_header *) adf_nbuf_data(msdu); if (eth_hdr_p->ether_type != adf_os_htons(ETHERTYPE_OCB_TX)) @@ -570,6 +573,7 @@ static bool parse_ocb_tx_header(adf_nbuf_t msdu, tx_ctrl_hdr = (struct ocb_tx_ctrl_hdr_t*) adf_nbuf_data(msdu); if (tx_ctrl_hdr->version == OCB_HEADER_VERSION) { + *tx_ctrl_header_found = true; if (tx_ctrl) adf_os_mem_copy(tx_ctrl, tx_ctrl_hdr, sizeof(*tx_ctrl_hdr)); } else { @@ -582,6 +586,49 @@ static bool parse_ocb_tx_header(adf_nbuf_t msdu, return true; } +/** + * merge_ocb_tx_ctrl_hdr() - merge the default TX ctrl parameters into + * @tx_ctrl: The destination TX control header. + * @def_ctrl_hdr: The default TX control header. + * + * For each parameter in tx_ctrl, if the parameter is unspecified, the + * equivalent parameter in def_ctrl_hdr will be copied to tx_ctrl. + */ +static void merge_ocb_tx_ctrl_hdr(struct ocb_tx_ctrl_hdr_t *tx_ctrl, + struct ocb_tx_ctrl_hdr_t *def_ctrl_hdr) +{ + if (!tx_ctrl || !def_ctrl_hdr) + return; + + if (!tx_ctrl->channel_freq && def_ctrl_hdr->channel_freq) + tx_ctrl->channel_freq = def_ctrl_hdr->channel_freq; + if (!tx_ctrl->valid_pwr && def_ctrl_hdr->valid_pwr) { + tx_ctrl->pwr = def_ctrl_hdr->pwr; + tx_ctrl->valid_pwr = 1; + } + if (!tx_ctrl->valid_datarate && def_ctrl_hdr->valid_datarate) { + tx_ctrl->datarate = def_ctrl_hdr->datarate; + tx_ctrl->valid_datarate = 1; + } + if (!tx_ctrl->valid_retries && def_ctrl_hdr->valid_retries) { + tx_ctrl->retry_limit = def_ctrl_hdr->retry_limit; + tx_ctrl->valid_retries = 1; + } + if (!tx_ctrl->valid_chain_mask && def_ctrl_hdr->valid_chain_mask) { + tx_ctrl->chain_mask = def_ctrl_hdr->chain_mask; + tx_ctrl->valid_chain_mask = 1; + } + if (!tx_ctrl->valid_expire_tsf && def_ctrl_hdr->valid_expire_tsf) { + tx_ctrl->expire_tsf_hi = def_ctrl_hdr->expire_tsf_hi; + tx_ctrl->expire_tsf_lo = def_ctrl_hdr->expire_tsf_lo; + tx_ctrl->valid_expire_tsf = 1; + } + if (!tx_ctrl->valid_tid && def_ctrl_hdr->valid_tid) { + tx_ctrl->ext_tid = def_ctrl_hdr->ext_tid; + tx_ctrl->valid_tid = 1; + } +} + static inline adf_nbuf_t ol_tx_hl_base( ol_txrx_vdev_handle vdev, @@ -669,10 +716,18 @@ ol_tx_hl_base( /* If the vdev is in OCB mode, parse the tx control header. */ if (vdev->opmode == wlan_op_mode_ocb) { - if (!parse_ocb_tx_header(msdu, &tx_ctrl)) { + bool tx_ctrl_header_found = false; + + if (!parse_ocb_tx_header(msdu, &tx_ctrl, &tx_ctrl_header_found)) { /* There was an error parsing the header. Skip this packet. */ goto MSDU_LOOP_BOTTOM; } + /* If the TX control header was not found, just use the defaults */ + if (!tx_ctrl_header_found && vdev->ocb_def_tx_param) + vos_mem_copy(&tx_ctrl, vdev->ocb_def_tx_param, sizeof(tx_ctrl)); + /* If the TX control header was found, merge the defaults into it */ + else if (tx_ctrl_header_found && vdev->ocb_def_tx_param) + merge_ocb_tx_ctrl_hdr(&tx_ctrl, vdev->ocb_def_tx_param); } txq = ol_tx_classify(vdev, tx_desc, msdu, &tx_msdu_info); diff --git a/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c b/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c index 4f824a5e9c34..0eebb3335e66 100644 --- a/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c +++ b/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx.c @@ -2634,6 +2634,92 @@ exit: return rc; } +#define MAX_TID 15 +#define MAX_DATARATE 7 +#define OCB_HEADER_VERSION 1 + +/** + * ol_txrx_set_ocb_def_tx_param() - Set the default OCB TX parameters + * @vdev: The OCB vdev that will use these defaults. + * @_def_tx_param: The default TX parameters. + * @def_tx_param_size: The size of the _def_tx_param buffer. + * + * Return: true if the default parameters were set correctly, false if there + * is an error, for example an invalid parameter. In the case that false is + * returned, see the kernel log for the error description. + */ +bool ol_txrx_set_ocb_def_tx_param(ol_txrx_vdev_handle vdev, + void *_def_tx_param, uint32_t def_tx_param_size) +{ + struct ocb_tx_ctrl_hdr_t *def_tx_param = + (struct ocb_tx_ctrl_hdr_t *)_def_tx_param; + + if (def_tx_param) { + /* + * Default TX parameters are provided. + * Validate the contents and + * save them in the vdev. + */ + if (def_tx_param_size != sizeof(struct ocb_tx_ctrl_hdr_t)) { + VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_ERROR, + "Invalid size of OCB default TX params"); + return false; + } + + if (def_tx_param->version != OCB_HEADER_VERSION) { + VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_ERROR, + "Invalid version of OCB default TX params"); + return false; + } + + if (def_tx_param->channel_freq) { + int i; + for (i = 0; i < vdev->ocb_channel_count; i++) { + if (vdev->ocb_channel_info[i].chan_freq == + def_tx_param->channel_freq) + break; + } + if (i == vdev->ocb_channel_count) { + VOS_TRACE(VOS_MODULE_ID_TXRX, + VOS_TRACE_LEVEL_ERROR, + "Invalid default channel frequency"); + return false; + } + } + + if (def_tx_param->valid_datarate && + def_tx_param->datarate > MAX_DATARATE) { + VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_ERROR, + "Invalid default datarate"); + return false; + } + + if (def_tx_param->valid_tid && + def_tx_param->ext_tid > MAX_TID) { + VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_ERROR, + "Invalid default TID"); + return false; + } + + if (vdev->ocb_def_tx_param == NULL) + vdev->ocb_def_tx_param = + vos_mem_malloc(sizeof(*vdev->ocb_def_tx_param)); + vos_mem_copy(vdev->ocb_def_tx_param, def_tx_param, + sizeof(*vdev->ocb_def_tx_param)); + } else { + /* + * Default TX parameters are not provided. + * Delete the old defaults. + */ + if (vdev->ocb_def_tx_param) { + vos_mem_free(vdev->ocb_def_tx_param); + vdev->ocb_def_tx_param = NULL; + } + } + + return true; +} + #ifdef IPA_UC_OFFLOAD void ol_txrx_ipa_uc_get_resource( diff --git a/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx_types.h b/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx_types.h index 7101716923b1..92e110287099 100644 --- a/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx_types.h +++ b/drivers/net/wireless/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_txrx_types.h @@ -967,6 +967,9 @@ struct ol_txrx_vdev_t { /* Information about the schedules in the schedule */ struct ol_txrx_ocb_chan_info *ocb_channel_info; uint32_t ocb_channel_count; + + /* Default OCB TX parameter */ + struct ocb_tx_ctrl_hdr_t *ocb_def_tx_param; }; struct ol_rx_reorder_array_elem_t { diff --git a/drivers/net/wireless/qcacld-2.0/CORE/HDD/src/wlan_hdd_ocb.c b/drivers/net/wireless/qcacld-2.0/CORE/HDD/src/wlan_hdd_ocb.c index 008848eb5658..d0cec5795c6b 100644 --- a/drivers/net/wireless/qcacld-2.0/CORE/HDD/src/wlan_hdd_ocb.c +++ b/drivers/net/wireless/qcacld-2.0/CORE/HDD/src/wlan_hdd_ocb.c @@ -753,6 +753,9 @@ static const struct nla_policy qca_wlan_vendor_ocb_set_config_policy[ [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_DEF_TX_PARAM] = { + .type = NLA_BINARY + }, }; static const struct nla_policy qca_wlan_vendor_ocb_set_utc_time_policy[ @@ -899,6 +902,8 @@ static int __wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy, struct nlattr *ndl_active_state_list; uint32_t ndl_active_state_list_len; uint32_t flags = 0; + void *def_tx_param = NULL; + uint32_t def_tx_param_size = 0; int i; uint32_t channel_count, schedule_size; struct sir_ocb_config *config; @@ -956,11 +961,19 @@ static int __wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy, ndl_active_state_list_len = (ndl_active_state_list ? nla_len(ndl_active_state_list) : 0); - /* Get the flags */ + /* Get the flags. This parameter is optional. */ if (tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS]) flags = nla_get_u32(tb[ QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS]); + /* Get the default TX parameters. This parameter is optional. */ + if (tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_DEF_TX_PARAM]) { + def_tx_param_size = nla_len(tb[ + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_DEF_TX_PARAM]); + def_tx_param = nla_data(tb[ + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_DEF_TX_PARAM]); + } + config = hdd_ocb_config_new(channel_count, schedule_size, ndl_chan_list_len, ndl_active_state_list_len); @@ -972,6 +985,8 @@ static int __wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy, config->channel_count = channel_count; config->schedule_size = schedule_size; config->flags = flags; + config->def_tx_param = def_tx_param; + config->def_tx_param_size = def_tx_param_size; /* Read the channel array */ channel_array = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY]; diff --git a/drivers/net/wireless/qcacld-2.0/CORE/HDD/src/wlan_hdd_ocb.h b/drivers/net/wireless/qcacld-2.0/CORE/HDD/src/wlan_hdd_ocb.h index 6f3cf1abe3fc..57c55a40bc23 100644 --- a/drivers/net/wireless/qcacld-2.0/CORE/HDD/src/wlan_hdd_ocb.h +++ b/drivers/net/wireless/qcacld-2.0/CORE/HDD/src/wlan_hdd_ocb.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -90,7 +90,12 @@ struct dot11p_channel_sched { * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY: * array of NDL channel information * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY: - * array of NDL active state configuration + * array of NDL active state configuration + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS: + * configuration flags such as OCB_CONFIG_FLAG_80211_FRAME_MODE + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_DEF_TX_PARAM: + * default TX parameters to use in the case that a packet is sent without + * a TX control header */ enum qca_wlan_vendor_attr_ocb_set_config { QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_INVALID = 0, @@ -101,6 +106,7 @@ enum qca_wlan_vendor_attr_ocb_set_config { QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY, QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY, QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_DEF_TX_PARAM, QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX = QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_AFTER_LAST - 1, diff --git a/drivers/net/wireless/qcacld-2.0/CORE/MAC/inc/sirApi.h b/drivers/net/wireless/qcacld-2.0/CORE/MAC/inc/sirApi.h index b3522b6cc0f5..f1af15720fa4 100644 --- a/drivers/net/wireless/qcacld-2.0/CORE/MAC/inc/sirApi.h +++ b/drivers/net/wireless/qcacld-2.0/CORE/MAC/inc/sirApi.h @@ -6298,8 +6298,8 @@ struct sir_ocb_config_sched { * @dcc_ndl_chan_list: array of dcc channel info * @dcc_ndl_active_state_list_len: size of the active state array * @dcc_ndl_active_state_list: array of active states - * @adapter: the OCB adapter - * @dcc_stats_callback: callback for the response event + * @def_tx_param: default TX parameters + * @def_tx_param_size: size of the default TX parameters */ struct sir_ocb_config { uint8_t session_id; @@ -6312,6 +6312,8 @@ struct sir_ocb_config { void *dcc_ndl_chan_list; uint32_t dcc_ndl_active_state_list_len; void *dcc_ndl_active_state_list; + void *def_tx_param; + uint32_t def_tx_param_size; }; /* The size of the utc time in bytes. */ diff --git a/drivers/net/wireless/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_ctrl_api.h b/drivers/net/wireless/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_ctrl_api.h index 8634bc108466..70bf37bb6857 100644 --- a/drivers/net/wireless/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_ctrl_api.h +++ b/drivers/net/wireless/qcacld-2.0/CORE/SERVICES/COMMON/ol_txrx_ctrl_api.h @@ -1429,6 +1429,19 @@ void ol_txrx_set_ocb_peer(struct ol_txrx_pdev_t *pdev, struct ol_txrx_peer_t *pe */ a_bool_t ol_txrx_get_ocb_peer(struct ol_txrx_pdev_t *pdev, struct ol_txrx_peer_t **peer); +/** + * ol_txrx_set_ocb_def_tx_param() - Set the default OCB TX parameters + * @vdev: The OCB vdev that will use these defaults. + * @_def_tx_param: The default TX parameters. + * @def_tx_param_size: The size of the _def_tx_param buffer. + * + * Return: true if the default parameters were set correctly, false if there + * is an error, for example an invalid parameter. In the case that false is + * returned, see the kernel log for the error description. + */ +bool ol_txrx_set_ocb_def_tx_param(ol_txrx_vdev_handle vdev, + void *def_tx_param, uint32_t def_tx_param_size); + void ol_txrx_display_stats(struct ol_txrx_pdev_t *pdev, uint16_t bitmap); void ol_txrx_clear_stats(struct ol_txrx_pdev_t *pdev, uint16_t bitmap); diff --git a/drivers/net/wireless/qcacld-2.0/CORE/SERVICES/WMA/wma_ocb.c b/drivers/net/wireless/qcacld-2.0/CORE/SERVICES/WMA/wma_ocb.c index 70e47b3f0694..7055622ba0aa 100644 --- a/drivers/net/wireless/qcacld-2.0/CORE/SERVICES/WMA/wma_ocb.c +++ b/drivers/net/wireless/qcacld-2.0/CORE/SERVICES/WMA/wma_ocb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -55,6 +55,7 @@ int wma_ocb_set_config_resp(tp_wma_handle wma_handle, uint8_t status) */ if (status == VOS_STATUS_SUCCESS) { if (vdev && req) { + /* Save the channel info in the vdev */ if (vdev->ocb_channel_info) vos_mem_free(vdev->ocb_channel_info); vdev->ocb_channel_count = @@ -79,6 +80,14 @@ int wma_ocb_set_config_resp(tp_wma_handle wma_handle, uint8_t status) } else { vdev->ocb_channel_info = 0; } + + /* Default TX parameter */ + if (!ol_txrx_set_ocb_def_tx_param(vdev, + req->def_tx_param, req->def_tx_param_size)) { + /* Setting the default param failed */ + WMA_LOGE(FL("Invalid default TX parameters")); + status = VOS_STATUS_E_INVAL; + } } } diff --git a/drivers/net/wireless/qcacld-2.0/CORE/SME/src/sme_common/sme_Api.c b/drivers/net/wireless/qcacld-2.0/CORE/SME/src/sme_common/sme_Api.c index 67bf9446384d..54a70099db73 100644 --- a/drivers/net/wireless/qcacld-2.0/CORE/SME/src/sme_common/sme_Api.c +++ b/drivers/net/wireless/qcacld-2.0/CORE/SME/src/sme_common/sme_Api.c @@ -13276,7 +13276,8 @@ static struct sir_ocb_config *sme_copy_sir_ocb_config(struct sir_ocb_config *src src->channel_count * sizeof(*src->channels) + src->schedule_size * sizeof(*src->schedule) + src->dcc_ndl_chan_list_len + - src->dcc_ndl_active_state_list_len; + src->dcc_ndl_active_state_list_len + + src->def_tx_param_size; dst = vos_mem_malloc(length); if (!dst) @@ -13303,6 +13304,13 @@ static struct sir_ocb_config *sme_copy_sir_ocb_config(struct sir_ocb_config *src vos_mem_copy(dst->dcc_ndl_active_state_list, src->dcc_ndl_active_state_list, src->dcc_ndl_active_state_list_len); + cursor += src->dcc_ndl_active_state_list_len; + if (src->def_tx_param && src->def_tx_param_size) { + dst->def_tx_param = cursor; + vos_mem_copy(dst->def_tx_param, src->def_tx_param, + src->def_tx_param_size); + } + return dst; }