From 4d67c8fbb9e8c30cfddc5fc45208ab81c1b161e3 Mon Sep 17 00:00:00 2001 From: Peng Xu Date: Fri, 16 Oct 2015 16:02:26 -0700 Subject: [PATCH] qcacld-3.0: Vendor command to scale TX power This is for FR23278: Runtime configuration of softAP Tx power. The value that send by the vendor command will set the power levels as below: 0 --- no scaling, 100% 1 --- 50% of max power 2 --- 25% of max power 3 --- 12% of max power 4 --- minimum power Another vendor command is to decrease the power by actual db value. CRs-fixed: 941772 Change-Id: I61d48299b4af361c214e2ab8bb1fa848161431de --- core/hdd/src/wlan_hdd_cfg80211.c | 173 +++++++++++++++++++++++++++++++ core/hdd/src/wlan_hdd_cfg80211.h | 39 +++++++ core/wma/inc/wma_api.h | 2 + core/wma/src/wma_power.c | 59 +++++++++++ 4 files changed, 273 insertions(+) diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index cd1a4864978a..493b6e867bff 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -138,6 +138,8 @@ #define HDD_CHANNEL_14 14 +#define MAX_TXPOWER_SCALE 4 + static const u32 hdd_cipher_suites[] = { WLAN_CIPHER_SUITE_WEP40, WLAN_CIPHER_SUITE_WEP104, @@ -4604,6 +4606,161 @@ static int wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy, return ret; } +/** + * __wlan_hdd_cfg80211_txpower_scale () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_txpower_scale(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = NULL; + int ret = 0; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX + 1]; + uint8_t scale_value; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX, + data, data_len, NULL)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE]) { + hdd_err("attr tx power scale failed"); + return -EINVAL; + } + + scale_value = nla_get_u8(tb + [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE]); + + if (scale_value > MAX_TXPOWER_SCALE) { + hdd_err("Invalid tx power scale level"); + return -EINVAL; + } + + ret = wma_set_tx_power_scale(adapter->sessionId, scale_value); + + if (ret != 0) { + hdd_err("Set tx power scale failed"); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_txpower_scale () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_txpower_scale(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_txpower_scale(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_txpower_scale_decr_db () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = NULL; + int ret = 0; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX + 1]; + uint8_t scale_value; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX, + data, data_len, NULL)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB]) { + hdd_err("attr tx power decrease db value failed"); + return -EINVAL; + } + + scale_value = nla_get_u8(tb + [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB]); + + ret = wma_set_tx_power_scale_decr_db(adapter->sessionId, scale_value); + + if (ret != 0) { + hdd_err("Set tx power decrease db failed"); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_txpower_scale_decr_db () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_txpower_scale_decr_db(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { { .info.vendor_id = QCA_NL80211_VENDOR_ID, @@ -5042,6 +5199,22 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { .doit = wlan_hdd_cfg80211_set_gateway_params }, #endif /* FEATURE_LFR_SUBNET_DETECTION */ + { + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_txpower_scale + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE_DECR_DB, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_txpower_scale_decr_db + }, }; /* diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index 06718f634fdc..0f24a05691bd 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -250,6 +250,8 @@ typedef enum { * @QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE: vendor scan complete * @QCA_NL80211_VENDOR_SUBCMD_OTA_TEST: enable OTA test * @QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG: set gateway parameters + * @QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE: set tx power by percentage + * @QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE_DECR_DB: reduce tx power by DB */ enum qca_nl80211_vendor_subcmds { @@ -364,6 +366,10 @@ enum qca_nl80211_vendor_subcmds { /* OTA test subcommand */ QCA_NL80211_VENDOR_SUBCMD_OTA_TEST = 108, + /* Tx power scaling subcommands */ + QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE = 109, + /* Tx power scaling in db subcommands */ + QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE_DECR_DB = 115, }; @@ -2219,6 +2225,39 @@ enum qca_vendor_attr_ota_test { QCA_WLAN_VENDOR_ATTR_OTA_TEST_AFTER_LAST - 1 }; +/** enum qca_vendor_attr_txpower_scale - vendor sub commands index + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE: scaling value + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_AFTER_LAST: last value + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX: max value + */ +enum qca_vendor_attr_txpower_scale { + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_INVALID, + /* 8-bit unsigned value to indicate the scaling of tx power */ + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX = + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_AFTER_LAST - 1 +}; + +/** + * enum qca_vendor_attr_txpower_scale_decr_db - vendor sub commands index + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB: scaling value + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_AFTER_LAST: last value + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX: max value + */ +enum qca_vendor_attr_txpower_scale_decr_db { + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_INVALID, + /* 8-bit unsigned value to indicate the scaling of tx power */ + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX = + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_AFTER_LAST - 1 +}; + struct cfg80211_bss *wlan_hdd_cfg80211_update_bss_db(hdd_adapter_t *pAdapter, tCsrRoamInfo *pRoamInfo); diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h index 5990477e7ee9..f04500e45ee2 100644 --- a/core/wma/inc/wma_api.h +++ b/core/wma/inc/wma_api.h @@ -235,4 +235,6 @@ static inline CDF_STATUS wma_send_egap_conf_params(WMA_HANDLE handle, return CDF_STATUS_E_NOSUPPORT; } #endif +CDF_STATUS wma_set_tx_power_scale(uint8_t vdev_id, int value); +CDF_STATUS wma_set_tx_power_scale_decr_db(uint8_t vdev_id, int value); #endif diff --git a/core/wma/src/wma_power.c b/core/wma/src/wma_power.c index 72d77b800d97..3793675ca3c4 100644 --- a/core/wma/src/wma_power.c +++ b/core/wma/src/wma_power.c @@ -2252,3 +2252,62 @@ void wma_set_resume_dtim(tp_wma_handle wma) } } +/** + * wma_set_tx_power_scale() - set tx power scale + * @vdev_id: vdev id + * @value: value + * + * Return: CDF_STATUS_SUCCESS for success or error code. + */ +CDF_STATUS wma_set_tx_power_scale(uint8_t vdev_id, int value) +{ + int ret = CDF_STATUS_SUCCESS; + tp_wma_handle wma_handle = + (tp_wma_handle)cds_get_context(CDF_MODULE_ID_WMA); + if (NULL == wma_handle) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (!(wma_handle->interfaces[vdev_id].vdev_up)) { + WMA_LOGE("%s: vdev id %d is not up", __func__, vdev_id); + return CDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, vdev_id, + WMI_VDEV_PARAM_TXPOWER_SCALE, value); + if (ret != 0) + WMA_LOGE("Set tx power scale failed"); + + return ret; +} + +/** + * wma_set_tx_power_scale_decr_db() - decrease power by DB value + * @vdev_id: vdev id + * @value: value + * + * Return: CDF_STATUS_SUCCESS for success or error code. + */ +CDF_STATUS wma_set_tx_power_scale_decr_db(uint8_t vdev_id, int value) +{ + int ret = CDF_STATUS_SUCCESS; + tp_wma_handle wma_handle = + (tp_wma_handle)cds_get_context(CDF_MODULE_ID_WMA); + if (NULL == wma_handle) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (!(wma_handle->interfaces[vdev_id].vdev_up)) { + WMA_LOGE("%s: vdev id %d is not up", __func__, vdev_id); + return CDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, vdev_id, + WMI_VDEV_PARAM_TXPOWER_SCALE_DECR_DB, value); + if (ret != 0) + WMA_LOGE("Decrease tx power value failed"); + + return ret; +}