mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-10 14:19:09 -04:00
qcacld-3.0: Move sar related functions to wlan_hdd_sar_limits.c
Move sar related functions from wlan_hdd_cfg80211.c to wlan_hdd_sar_limits.c. Change-Id: I65f4e33469d5fc2dd09ae37fd0138b3d3d2c5f9d CRs-Fixed: 2638028
This commit is contained in:
parent
cb8b11de04
commit
c7d8c585ee
4 changed files with 571 additions and 555 deletions
|
|
@ -11999,517 +11999,6 @@ static int wlan_hdd_cfg80211_setband(struct wiphy *wiphy,
|
|||
return errno;
|
||||
}
|
||||
|
||||
/**
|
||||
* wlan_hdd_cfg80211_sar_convert_limit_set() - Convert limit set value
|
||||
* @nl80211_value: Vendor command attribute value
|
||||
* @wmi_value: Pointer to return converted WMI return value
|
||||
*
|
||||
* Convert NL80211 vendor command value for SAR limit set to WMI value
|
||||
* Return: 0 on success, -1 on invalid value
|
||||
*/
|
||||
static int wlan_hdd_cfg80211_sar_convert_limit_set(u32 nl80211_value,
|
||||
u32 *wmi_value)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (nl80211_value) {
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE:
|
||||
*wmi_value = WMI_SAR_FEATURE_OFF;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0:
|
||||
*wmi_value = WMI_SAR_FEATURE_ON_SET_0;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1:
|
||||
*wmi_value = WMI_SAR_FEATURE_ON_SET_1;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2:
|
||||
*wmi_value = WMI_SAR_FEATURE_ON_SET_2;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3:
|
||||
*wmi_value = WMI_SAR_FEATURE_ON_SET_3;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4:
|
||||
*wmi_value = WMI_SAR_FEATURE_ON_SET_4;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER:
|
||||
*wmi_value = WMI_SAR_FEATURE_ON_USER_DEFINED;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0:
|
||||
*wmi_value = WMI_SAR_FEATURE_ON_SAR_V2_0;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef WLAN_FEATURE_SARV1_TO_SARV2
|
||||
/**
|
||||
* hdd_convert_sarv1_to_sarv2() - convert SAR V1 BDF reference to SAR V2
|
||||
* @hdd_ctx: The HDD global context
|
||||
* @tb: The parsed array of netlink attributes
|
||||
* @sar_limit_cmd: The WMI command to be filled
|
||||
*
|
||||
* This feature/function is designed to solve the following problem:
|
||||
* 1) Userspace application was written to use SARv1 BDF entries
|
||||
* 2) Product is configured with SAR V2 BDF entries
|
||||
*
|
||||
* So if this feature is enabled, and if the firmware is configured
|
||||
* with SAR V2 support, and if the incoming request is to enable a SAR
|
||||
* V1 BDF entry, then the WMI command is generated to actually
|
||||
* configure a SAR V2 BDF entry.
|
||||
*
|
||||
* Return: true if conversion was performed and @sar_limit_cmd is
|
||||
* ready to be sent to firmware. Otherwise false in which case the
|
||||
* normal parsing logic should be applied.
|
||||
*/
|
||||
|
||||
static bool
|
||||
hdd_convert_sarv1_to_sarv2(struct hdd_context *hdd_ctx,
|
||||
struct nlattr *tb[],
|
||||
struct sar_limit_cmd_params *sar_limit_cmd)
|
||||
{
|
||||
struct nlattr *attr;
|
||||
uint32_t bdf_index, set;
|
||||
struct sar_limit_cmd_row *row;
|
||||
|
||||
hdd_enter();
|
||||
if (hdd_ctx->sar_version != SAR_VERSION_2) {
|
||||
hdd_debug("SAR version: %d", hdd_ctx->sar_version);
|
||||
return false;
|
||||
}
|
||||
|
||||
attr = tb[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE];
|
||||
if (!attr)
|
||||
return false;
|
||||
|
||||
bdf_index = nla_get_u32(attr);
|
||||
|
||||
if ((bdf_index >= QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0) &&
|
||||
(bdf_index <= QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4)) {
|
||||
set = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0;
|
||||
} else if (bdf_index == QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE) {
|
||||
set = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE;
|
||||
bdf_index = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Need two rows to hold the per-chain V2 power index
|
||||
* To disable SARv2 limit, send chain, num_limits_row and
|
||||
* power limit set to 0 (except power index 0xff)
|
||||
*/
|
||||
row = qdf_mem_malloc(2 * sizeof(*row));
|
||||
if (!row)
|
||||
return false;
|
||||
|
||||
if (wlan_hdd_cfg80211_sar_convert_limit_set(
|
||||
set, &sar_limit_cmd->sar_enable)) {
|
||||
hdd_err("Failed to convert SAR limit to WMI value");
|
||||
return false;
|
||||
}
|
||||
|
||||
sar_limit_cmd->commit_limits = 1;
|
||||
sar_limit_cmd->num_limit_rows = 2;
|
||||
sar_limit_cmd->sar_limit_row_list = row;
|
||||
row[0].limit_value = bdf_index;
|
||||
row[1].limit_value = row[0].limit_value;
|
||||
row[0].chain_id = 0;
|
||||
row[1].chain_id = 1;
|
||||
row[0].validity_bitmap = WMI_SAR_CHAIN_ID_VALID_MASK;
|
||||
row[1].validity_bitmap = WMI_SAR_CHAIN_ID_VALID_MASK;
|
||||
|
||||
hdd_exit();
|
||||
return true;
|
||||
}
|
||||
|
||||
#else /* WLAN_FEATURE_SARV1_TO_SARV2 */
|
||||
static bool
|
||||
hdd_convert_sarv1_to_sarv2(struct hdd_context *hdd_ctx,
|
||||
struct nlattr *tb[],
|
||||
struct sar_limit_cmd_params *sar_limit_cmd)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* WLAN_FEATURE_SARV1_TO_SARV2 */
|
||||
|
||||
/**
|
||||
* wlan_hdd_cfg80211_sar_convert_band() - Convert WLAN band value
|
||||
* @nl80211_value: Vendor command attribute value
|
||||
* @wmi_value: Pointer to return converted WMI return value
|
||||
*
|
||||
* Convert NL80211 vendor command value for SAR BAND to WMI value
|
||||
* Return: 0 on success, -1 on invalid value
|
||||
*/
|
||||
static int wlan_hdd_cfg80211_sar_convert_band(u32 nl80211_value, u32 *wmi_value)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (nl80211_value) {
|
||||
case HDD_NL80211_BAND_2GHZ:
|
||||
*wmi_value = WMI_SAR_2G_ID;
|
||||
break;
|
||||
case HDD_NL80211_BAND_5GHZ:
|
||||
*wmi_value = WMI_SAR_5G_ID;
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* wlan_hdd_cfg80211_sar_convert_modulation() - Convert WLAN modulation value
|
||||
* @nl80211_value: Vendor command attribute value
|
||||
* @wmi_value: Pointer to return converted WMI return value
|
||||
*
|
||||
* Convert NL80211 vendor command value for SAR Modulation to WMI value
|
||||
* Return: 0 on success, -1 on invalid value
|
||||
*/
|
||||
static int wlan_hdd_cfg80211_sar_convert_modulation(u32 nl80211_value,
|
||||
u32 *wmi_value)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (nl80211_value) {
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK:
|
||||
*wmi_value = WMI_SAR_MOD_CCK;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_OFDM:
|
||||
*wmi_value = WMI_SAR_MOD_OFDM;
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void hdd_store_sar_config(struct hdd_context *hdd_ctx,
|
||||
struct sar_limit_cmd_params *sar_limit_cmd)
|
||||
{
|
||||
/* Free the previously stored sar_limit_cmd */
|
||||
wlan_hdd_free_sar_config(hdd_ctx);
|
||||
|
||||
hdd_ctx->sar_cmd_params = sar_limit_cmd;
|
||||
}
|
||||
|
||||
void wlan_hdd_free_sar_config(struct hdd_context *hdd_ctx)
|
||||
{
|
||||
struct sar_limit_cmd_params *sar_limit_cmd;
|
||||
|
||||
if (!hdd_ctx->sar_cmd_params)
|
||||
return;
|
||||
|
||||
sar_limit_cmd = hdd_ctx->sar_cmd_params;
|
||||
hdd_ctx->sar_cmd_params = NULL;
|
||||
qdf_mem_free(sar_limit_cmd->sar_limit_row_list);
|
||||
qdf_mem_free(sar_limit_cmd);
|
||||
}
|
||||
|
||||
#define SAR_LIMITS_SAR_ENABLE QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE
|
||||
#define SAR_LIMITS_NUM_SPECS QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS
|
||||
#define SAR_LIMITS_SPEC QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC
|
||||
#define SAR_LIMITS_SPEC_BAND QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND
|
||||
#define SAR_LIMITS_SPEC_CHAIN QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN
|
||||
#define SAR_LIMITS_SPEC_MODULATION \
|
||||
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION
|
||||
#define SAR_LIMITS_SPEC_POWER_LIMIT \
|
||||
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT
|
||||
#define SAR_LIMITS_SPEC_POWER_LIMIT_INDEX \
|
||||
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX
|
||||
#define SAR_LIMITS_MAX QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX
|
||||
|
||||
static const struct nla_policy
|
||||
sar_limits_policy[SAR_LIMITS_MAX + 1] = {
|
||||
[SAR_LIMITS_SAR_ENABLE] = {.type = NLA_U32},
|
||||
[SAR_LIMITS_NUM_SPECS] = {.type = NLA_U32},
|
||||
[SAR_LIMITS_SPEC_BAND] = {.type = NLA_U32},
|
||||
[SAR_LIMITS_SPEC_CHAIN] = {.type = NLA_U32},
|
||||
[SAR_LIMITS_SPEC_MODULATION] = {.type = NLA_U32},
|
||||
[SAR_LIMITS_SPEC_POWER_LIMIT] = {.type = NLA_U32},
|
||||
[SAR_LIMITS_SPEC_POWER_LIMIT_INDEX] = {.type = NLA_U32},
|
||||
};
|
||||
|
||||
/**
|
||||
* hdd_extract_sar_nested_attrs() - Extract nested SAR attribute
|
||||
* @spec: nested nla attribue
|
||||
* @row: output to hold extract nested attribute
|
||||
*
|
||||
* This function extracts nested SAR attribute one at a time which means
|
||||
* for each nested attribute this has to be invoked from
|
||||
* __wlan_hdd_set_sar_power_limits().
|
||||
*
|
||||
* Return: On success - 0
|
||||
* On Failure - Negative value
|
||||
*/
|
||||
static int hdd_extract_sar_nested_attrs(struct nlattr *spec[],
|
||||
struct sar_limit_cmd_row *row)
|
||||
{
|
||||
uint32_t limit;
|
||||
uint32_t band;
|
||||
uint32_t modulation;
|
||||
int ret;
|
||||
|
||||
row->validity_bitmap = 0;
|
||||
|
||||
if (spec[SAR_LIMITS_SPEC_POWER_LIMIT]) {
|
||||
limit = nla_get_u32(spec[SAR_LIMITS_SPEC_POWER_LIMIT]);
|
||||
row->limit_value = limit;
|
||||
} else if (spec[SAR_LIMITS_SPEC_POWER_LIMIT_INDEX]) {
|
||||
limit = nla_get_u32(spec[SAR_LIMITS_SPEC_POWER_LIMIT_INDEX]);
|
||||
row->limit_value = limit;
|
||||
} else {
|
||||
hdd_err("SAR Spec does not have power limit or index value");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (spec[SAR_LIMITS_SPEC_BAND]) {
|
||||
band = nla_get_u32(spec[SAR_LIMITS_SPEC_BAND]);
|
||||
ret = wlan_hdd_cfg80211_sar_convert_band(band, &row->band_id);
|
||||
if (ret) {
|
||||
hdd_err("Invalid SAR Band attr");
|
||||
return ret;
|
||||
}
|
||||
|
||||
row->validity_bitmap |= WMI_SAR_BAND_ID_VALID_MASK;
|
||||
}
|
||||
|
||||
if (spec[SAR_LIMITS_SPEC_CHAIN]) {
|
||||
row->chain_id = nla_get_u32(spec[SAR_LIMITS_SPEC_CHAIN]);
|
||||
row->validity_bitmap |= WMI_SAR_CHAIN_ID_VALID_MASK;
|
||||
}
|
||||
|
||||
if (spec[SAR_LIMITS_SPEC_MODULATION]) {
|
||||
modulation = nla_get_u32(spec[SAR_LIMITS_SPEC_MODULATION]);
|
||||
ret = wlan_hdd_cfg80211_sar_convert_modulation(modulation,
|
||||
&row->mod_id);
|
||||
if (ret) {
|
||||
hdd_err("Invalid SAR Modulation attr");
|
||||
return ret;
|
||||
}
|
||||
|
||||
row->validity_bitmap |= WMI_SAR_MOD_ID_VALID_MASK;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* __wlan_hdd_set_sar_power_limits() - Set SAR power limits
|
||||
* @wiphy: Pointer to wireless phy
|
||||
* @wdev: Pointer to wireless device
|
||||
* @data: Pointer to data
|
||||
* @data_len: Length of @data
|
||||
*
|
||||
* This function is used to setup Specific Absorption Rate limit specs.
|
||||
*
|
||||
* Return: 0 on success, negative errno on failure
|
||||
*/
|
||||
static int __wlan_hdd_set_sar_power_limits(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data, int data_len)
|
||||
{
|
||||
struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
|
||||
struct nlattr *spec[SAR_LIMITS_MAX + 1];
|
||||
struct nlattr *tb[SAR_LIMITS_MAX + 1];
|
||||
struct nlattr *spec_list;
|
||||
struct sar_limit_cmd_params *sar_limit_cmd;
|
||||
int ret = -EINVAL, i = 0, rem = 0;
|
||||
QDF_STATUS status;
|
||||
uint32_t num_limit_rows = 0;
|
||||
struct sar_limit_cmd_row *row;
|
||||
uint32_t sar_enable;
|
||||
|
||||
hdd_enter();
|
||||
|
||||
if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
|
||||
hdd_err("Command not allowed in FTM mode");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (wlan_hdd_validate_context(hdd_ctx))
|
||||
return -EINVAL;
|
||||
|
||||
if (wlan_cfg80211_nla_parse(tb, SAR_LIMITS_MAX, data, data_len,
|
||||
sar_limits_policy)) {
|
||||
hdd_err("Invalid SAR attributes");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tb[SAR_LIMITS_SAR_ENABLE]) {
|
||||
sar_enable = nla_get_u32(tb[SAR_LIMITS_SAR_ENABLE]);
|
||||
|
||||
if ((sar_enable >=
|
||||
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0 &&
|
||||
sar_enable <=
|
||||
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4) &&
|
||||
hdd_ctx->sar_version == SAR_VERSION_2 &&
|
||||
!hdd_ctx->config->enable_sar_conversion) {
|
||||
hdd_err("SARV1 to SARV2 is disabled from ini");
|
||||
return -EINVAL;
|
||||
} else if (sar_enable ==
|
||||
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0 &&
|
||||
hdd_ctx->sar_version == SAR_VERSION_1) {
|
||||
hdd_err("FW expects SARV1 given command is SARV2");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
sar_limit_cmd = qdf_mem_malloc(sizeof(struct sar_limit_cmd_params));
|
||||
if (!sar_limit_cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
wlan_hdd_sar_timers_reset(hdd_ctx);
|
||||
|
||||
/* is special SAR V1 => SAR V2 logic enabled and applicable? */
|
||||
if (hdd_ctx->config->enable_sar_conversion &&
|
||||
(hdd_convert_sarv1_to_sarv2(hdd_ctx, tb, sar_limit_cmd)))
|
||||
goto send_sar_limits;
|
||||
|
||||
/* Vendor command manadates all SAR Specs in single call */
|
||||
sar_limit_cmd->commit_limits = 1;
|
||||
sar_limit_cmd->sar_enable = WMI_SAR_FEATURE_NO_CHANGE;
|
||||
if (tb[SAR_LIMITS_SAR_ENABLE]) {
|
||||
uint32_t *sar_ptr = &sar_limit_cmd->sar_enable;
|
||||
|
||||
sar_enable = nla_get_u32(tb[SAR_LIMITS_SAR_ENABLE]);
|
||||
ret = wlan_hdd_cfg80211_sar_convert_limit_set(sar_enable,
|
||||
sar_ptr);
|
||||
if (ret) {
|
||||
hdd_err("Invalid SAR Enable attr");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
hdd_debug("attr sar sar_enable %d", sar_limit_cmd->sar_enable);
|
||||
|
||||
if (tb[SAR_LIMITS_NUM_SPECS]) {
|
||||
num_limit_rows = nla_get_u32(tb[SAR_LIMITS_NUM_SPECS]);
|
||||
hdd_debug("attr sar num_limit_rows %u", num_limit_rows);
|
||||
}
|
||||
|
||||
if (num_limit_rows > MAX_SAR_LIMIT_ROWS_SUPPORTED) {
|
||||
hdd_err("SAR Spec list exceed supported size");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (num_limit_rows == 0)
|
||||
goto send_sar_limits;
|
||||
|
||||
row = qdf_mem_malloc(sizeof(*row) * num_limit_rows);
|
||||
if (!row) {
|
||||
hdd_err("Failed to allocate memory for sar_limit_row_list");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sar_limit_cmd->num_limit_rows = num_limit_rows;
|
||||
sar_limit_cmd->sar_limit_row_list = row;
|
||||
|
||||
if (!tb[SAR_LIMITS_SPEC]) {
|
||||
hdd_err("Invalid SAR specification list");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nla_for_each_nested(spec_list, tb[SAR_LIMITS_SPEC], rem) {
|
||||
if (i == num_limit_rows) {
|
||||
hdd_warn("SAR Cmd has excess SPECs in list");
|
||||
break;
|
||||
}
|
||||
|
||||
if (wlan_cfg80211_nla_parse(spec,
|
||||
SAR_LIMITS_MAX,
|
||||
nla_data(spec_list),
|
||||
nla_len(spec_list),
|
||||
sar_limits_policy)) {
|
||||
hdd_err("nla_parse failed for SAR Spec list");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = hdd_extract_sar_nested_attrs(spec, row);
|
||||
if (ret) {
|
||||
hdd_err("Failed to extract SAR nested attrs");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hdd_debug("Spec_ID: %d, Band: %d Chain: %d Mod: %d POW_Limit: %d Validity_Bitmap: %d",
|
||||
i, row->band_id, row->chain_id, row->mod_id,
|
||||
row->limit_value, row->validity_bitmap);
|
||||
|
||||
i++;
|
||||
row++;
|
||||
}
|
||||
|
||||
if (i < sar_limit_cmd->num_limit_rows) {
|
||||
hdd_warn("SAR Cmd has less SPECs in list");
|
||||
sar_limit_cmd->num_limit_rows = i;
|
||||
}
|
||||
|
||||
send_sar_limits:
|
||||
status = sme_set_sar_power_limits(hdd_ctx->mac_handle, sar_limit_cmd);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
hdd_err("Failed to set sar power limits");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* After SSR, the SAR configuration is lost. As SSR is hidden from
|
||||
* userland, this command will not come from userspace after a SSR. To
|
||||
* restore this configuration, save this in hdd context and restore
|
||||
* after re-init.
|
||||
*/
|
||||
hdd_store_sar_config(hdd_ctx, sar_limit_cmd);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (sar_limit_cmd) {
|
||||
qdf_mem_free(sar_limit_cmd->sar_limit_row_list);
|
||||
qdf_mem_free(sar_limit_cmd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#undef SAR_LIMITS_SAR_ENABLE
|
||||
#undef SAR_LIMITS_NUM_SPECS
|
||||
#undef SAR_LIMITS_SPEC
|
||||
#undef SAR_LIMITS_SPEC_BAND
|
||||
#undef SAR_LIMITS_SPEC_CHAIN
|
||||
#undef SAR_LIMITS_SPEC_MODULATION
|
||||
#undef SAR_LIMITS_SPEC_POWER_LIMIT
|
||||
#undef SAR_LIMITS_SPEC_POWER_LIMIT_INDEX
|
||||
#undef SAR_LIMITS_MAX
|
||||
|
||||
/**
|
||||
* wlan_hdd_cfg80211_set_sar_power_limits() - Set SAR power limits
|
||||
* @wiphy: Pointer to wireless phy
|
||||
* @wdev: Pointer to wireless device
|
||||
* @data: Pointer to data
|
||||
* @data_len: Length of @data
|
||||
*
|
||||
* Wrapper function of __wlan_hdd_cfg80211_set_sar_power_limits()
|
||||
*
|
||||
* Return: 0 on success, negative errno on failure
|
||||
*/
|
||||
static int wlan_hdd_cfg80211_set_sar_power_limits(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data,
|
||||
int data_len)
|
||||
{
|
||||
struct osif_psoc_sync *psoc_sync;
|
||||
int errno;
|
||||
|
||||
errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
|
||||
if (errno)
|
||||
return errno;
|
||||
|
||||
errno = __wlan_hdd_set_sar_power_limits(wiphy, wdev, data, data_len);
|
||||
|
||||
osif_psoc_sync_op_stop(psoc_sync);
|
||||
|
||||
return errno;
|
||||
}
|
||||
|
||||
static const struct
|
||||
nla_policy qca_wlan_vendor_attr[QCA_WLAN_VENDOR_ATTR_MAX+1] = {
|
||||
[QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY] = {.type = NLA_U32},
|
||||
|
|
@ -14786,17 +14275,6 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
|
|||
FEATURE_TDLS_VENDOR_COMMANDS
|
||||
FEATURE_SAR_LIMITS_VENDOR_COMMANDS
|
||||
BCN_RECV_FEATURE_VENDOR_COMMANDS
|
||||
|
||||
{
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS,
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
|
||||
WIPHY_VENDOR_CMD_NEED_RUNNING,
|
||||
.doit = wlan_hdd_cfg80211_set_sar_power_limits,
|
||||
vendor_command_policy(sar_limits_policy,
|
||||
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX)
|
||||
},
|
||||
|
||||
FEATURE_VENDOR_SUBCMD_SET_TRACE_LEVEL
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -766,32 +766,6 @@ int wlan_hdd_send_mode_change_event(void);
|
|||
int wlan_hdd_restore_channels(struct hdd_context *hdd_ctx,
|
||||
bool notify_sap_event);
|
||||
|
||||
/**
|
||||
* hdd_store_sar_config() - Store SAR config in HDD context
|
||||
* @hdd_ctx: The HDD context
|
||||
* @sar_limit_cmd: The sar_limit_cmd_params struct to save
|
||||
*
|
||||
* After SSR, the SAR configuration is lost. As SSR is hidden from
|
||||
* userland, this command will not come from userspace after a SSR. To
|
||||
* restore this configuration, save this in hdd context and restore
|
||||
* after re-init.
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void hdd_store_sar_config(struct hdd_context *hdd_ctx,
|
||||
struct sar_limit_cmd_params *sar_limit_cmd);
|
||||
|
||||
/**
|
||||
* hdd_free_sar_config() - Free the resources allocated while storing SAR config
|
||||
* @hdd_ctx: HDD context
|
||||
*
|
||||
* The driver stores the SAR config values in HDD context so that it can be
|
||||
* restored in the case SSR is invoked. Free those resources.
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void wlan_hdd_free_sar_config(struct hdd_context *hdd_ctx);
|
||||
|
||||
/*
|
||||
* wlan_hdd_send_sta_authorized_event: Function to send station authorized
|
||||
* event to user space in case of SAP
|
||||
|
|
|
|||
|
|
@ -305,6 +305,506 @@ cleanup:
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define SAR_LIMITS_SAR_ENABLE QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE
|
||||
#define SAR_LIMITS_NUM_SPECS QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS
|
||||
#define SAR_LIMITS_SPEC QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC
|
||||
#define SAR_LIMITS_SPEC_BAND QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND
|
||||
#define SAR_LIMITS_SPEC_CHAIN QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN
|
||||
#define SAR_LIMITS_SPEC_MODULATION \
|
||||
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION
|
||||
#define SAR_LIMITS_SPEC_POWER_LIMIT \
|
||||
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT
|
||||
#define SAR_LIMITS_SPEC_POWER_LIMIT_INDEX \
|
||||
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX
|
||||
#define SAR_LIMITS_MAX QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX
|
||||
|
||||
const struct nla_policy
|
||||
wlan_hdd_sar_limits_policy[SAR_LIMITS_MAX + 1] = {
|
||||
[SAR_LIMITS_SAR_ENABLE] = {.type = NLA_U32},
|
||||
[SAR_LIMITS_NUM_SPECS] = {.type = NLA_U32},
|
||||
[SAR_LIMITS_SPEC_BAND] = {.type = NLA_U32},
|
||||
[SAR_LIMITS_SPEC_CHAIN] = {.type = NLA_U32},
|
||||
[SAR_LIMITS_SPEC_MODULATION] = {.type = NLA_U32},
|
||||
[SAR_LIMITS_SPEC_POWER_LIMIT] = {.type = NLA_U32},
|
||||
[SAR_LIMITS_SPEC_POWER_LIMIT_INDEX] = {.type = NLA_U32},
|
||||
};
|
||||
|
||||
void hdd_store_sar_config(struct hdd_context *hdd_ctx,
|
||||
struct sar_limit_cmd_params *sar_limit_cmd)
|
||||
{
|
||||
/* Free the previously stored sar_limit_cmd */
|
||||
wlan_hdd_free_sar_config(hdd_ctx);
|
||||
|
||||
hdd_ctx->sar_cmd_params = sar_limit_cmd;
|
||||
}
|
||||
|
||||
void wlan_hdd_free_sar_config(struct hdd_context *hdd_ctx)
|
||||
{
|
||||
struct sar_limit_cmd_params *sar_limit_cmd;
|
||||
|
||||
if (!hdd_ctx->sar_cmd_params)
|
||||
return;
|
||||
|
||||
sar_limit_cmd = hdd_ctx->sar_cmd_params;
|
||||
hdd_ctx->sar_cmd_params = NULL;
|
||||
qdf_mem_free(sar_limit_cmd->sar_limit_row_list);
|
||||
qdf_mem_free(sar_limit_cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* wlan_hdd_cfg80211_sar_convert_limit_set() - Convert limit set value
|
||||
* @nl80211_value: Vendor command attribute value
|
||||
* @wmi_value: Pointer to return converted WMI return value
|
||||
*
|
||||
* Convert NL80211 vendor command value for SAR limit set to WMI value
|
||||
* Return: 0 on success, -1 on invalid value
|
||||
*/
|
||||
static int wlan_hdd_cfg80211_sar_convert_limit_set(u32 nl80211_value,
|
||||
u32 *wmi_value)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (nl80211_value) {
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE:
|
||||
*wmi_value = WMI_SAR_FEATURE_OFF;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0:
|
||||
*wmi_value = WMI_SAR_FEATURE_ON_SET_0;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1:
|
||||
*wmi_value = WMI_SAR_FEATURE_ON_SET_1;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2:
|
||||
*wmi_value = WMI_SAR_FEATURE_ON_SET_2;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3:
|
||||
*wmi_value = WMI_SAR_FEATURE_ON_SET_3;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4:
|
||||
*wmi_value = WMI_SAR_FEATURE_ON_SET_4;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER:
|
||||
*wmi_value = WMI_SAR_FEATURE_ON_USER_DEFINED;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0:
|
||||
*wmi_value = WMI_SAR_FEATURE_ON_SAR_V2_0;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef WLAN_FEATURE_SARV1_TO_SARV2
|
||||
/**
|
||||
* hdd_convert_sarv1_to_sarv2() - convert SAR V1 BDF reference to SAR V2
|
||||
* @hdd_ctx: The HDD global context
|
||||
* @tb: The parsed array of netlink attributes
|
||||
* @sar_limit_cmd: The WMI command to be filled
|
||||
*
|
||||
* This feature/function is designed to solve the following problem:
|
||||
* 1) Userspace application was written to use SARv1 BDF entries
|
||||
* 2) Product is configured with SAR V2 BDF entries
|
||||
*
|
||||
* So if this feature is enabled, and if the firmware is configured
|
||||
* with SAR V2 support, and if the incoming request is to enable a SAR
|
||||
* V1 BDF entry, then the WMI command is generated to actually
|
||||
* configure a SAR V2 BDF entry.
|
||||
*
|
||||
* Return: true if conversion was performed and @sar_limit_cmd is
|
||||
* ready to be sent to firmware. Otherwise false in which case the
|
||||
* normal parsing logic should be applied.
|
||||
*/
|
||||
|
||||
static bool
|
||||
hdd_convert_sarv1_to_sarv2(struct hdd_context *hdd_ctx,
|
||||
struct nlattr *tb[],
|
||||
struct sar_limit_cmd_params *sar_limit_cmd)
|
||||
{
|
||||
struct nlattr *attr;
|
||||
uint32_t bdf_index, set;
|
||||
struct sar_limit_cmd_row *row;
|
||||
|
||||
hdd_enter();
|
||||
if (hdd_ctx->sar_version != SAR_VERSION_2) {
|
||||
hdd_debug("SAR version: %d", hdd_ctx->sar_version);
|
||||
return false;
|
||||
}
|
||||
|
||||
attr = tb[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE];
|
||||
if (!attr)
|
||||
return false;
|
||||
|
||||
bdf_index = nla_get_u32(attr);
|
||||
|
||||
if ((bdf_index >= QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0) &&
|
||||
(bdf_index <= QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4)) {
|
||||
set = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0;
|
||||
} else if (bdf_index == QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE) {
|
||||
set = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE;
|
||||
bdf_index = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Need two rows to hold the per-chain V2 power index
|
||||
* To disable SARv2 limit, send chain, num_limits_row and
|
||||
* power limit set to 0 (except power index 0xff)
|
||||
*/
|
||||
row = qdf_mem_malloc(2 * sizeof(*row));
|
||||
if (!row)
|
||||
return false;
|
||||
|
||||
if (wlan_hdd_cfg80211_sar_convert_limit_set(
|
||||
set, &sar_limit_cmd->sar_enable)) {
|
||||
hdd_err("Failed to convert SAR limit to WMI value");
|
||||
return false;
|
||||
}
|
||||
|
||||
sar_limit_cmd->commit_limits = 1;
|
||||
sar_limit_cmd->num_limit_rows = 2;
|
||||
sar_limit_cmd->sar_limit_row_list = row;
|
||||
row[0].limit_value = bdf_index;
|
||||
row[1].limit_value = row[0].limit_value;
|
||||
row[0].chain_id = 0;
|
||||
row[1].chain_id = 1;
|
||||
row[0].validity_bitmap = WMI_SAR_CHAIN_ID_VALID_MASK;
|
||||
row[1].validity_bitmap = WMI_SAR_CHAIN_ID_VALID_MASK;
|
||||
|
||||
hdd_exit();
|
||||
return true;
|
||||
}
|
||||
|
||||
#else /* WLAN_FEATURE_SARV1_TO_SARV2 */
|
||||
static bool
|
||||
hdd_convert_sarv1_to_sarv2(struct hdd_context *hdd_ctx,
|
||||
struct nlattr *tb[],
|
||||
struct sar_limit_cmd_params *sar_limit_cmd)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* WLAN_FEATURE_SARV1_TO_SARV2 */
|
||||
|
||||
/**
|
||||
* wlan_hdd_cfg80211_sar_convert_band() - Convert WLAN band value
|
||||
* @nl80211_value: Vendor command attribute value
|
||||
* @wmi_value: Pointer to return converted WMI return value
|
||||
*
|
||||
* Convert NL80211 vendor command value for SAR BAND to WMI value
|
||||
* Return: 0 on success, -1 on invalid value
|
||||
*/
|
||||
static int wlan_hdd_cfg80211_sar_convert_band(u32 nl80211_value, u32 *wmi_value)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (nl80211_value) {
|
||||
case HDD_NL80211_BAND_2GHZ:
|
||||
*wmi_value = WMI_SAR_2G_ID;
|
||||
break;
|
||||
case HDD_NL80211_BAND_5GHZ:
|
||||
*wmi_value = WMI_SAR_5G_ID;
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* wlan_hdd_cfg80211_sar_convert_modulation() - Convert WLAN modulation value
|
||||
* @nl80211_value: Vendor command attribute value
|
||||
* @wmi_value: Pointer to return converted WMI return value
|
||||
*
|
||||
* Convert NL80211 vendor command value for SAR Modulation to WMI value
|
||||
* Return: 0 on success, -1 on invalid value
|
||||
*/
|
||||
static int wlan_hdd_cfg80211_sar_convert_modulation(u32 nl80211_value,
|
||||
u32 *wmi_value)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (nl80211_value) {
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK:
|
||||
*wmi_value = WMI_SAR_MOD_CCK;
|
||||
break;
|
||||
case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_OFDM:
|
||||
*wmi_value = WMI_SAR_MOD_OFDM;
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* hdd_extract_sar_nested_attrs() - Extract nested SAR attribute
|
||||
* @spec: nested nla attribue
|
||||
* @row: output to hold extract nested attribute
|
||||
*
|
||||
* This function extracts nested SAR attribute one at a time which means
|
||||
* for each nested attribute this has to be invoked from
|
||||
* __wlan_hdd_set_sar_power_limits().
|
||||
*
|
||||
* Return: On success - 0
|
||||
* On Failure - Negative value
|
||||
*/
|
||||
static int hdd_extract_sar_nested_attrs(struct nlattr *spec[],
|
||||
struct sar_limit_cmd_row *row)
|
||||
{
|
||||
uint32_t limit;
|
||||
uint32_t band;
|
||||
uint32_t modulation;
|
||||
int ret;
|
||||
|
||||
row->validity_bitmap = 0;
|
||||
|
||||
if (spec[SAR_LIMITS_SPEC_POWER_LIMIT]) {
|
||||
limit = nla_get_u32(spec[SAR_LIMITS_SPEC_POWER_LIMIT]);
|
||||
row->limit_value = limit;
|
||||
} else if (spec[SAR_LIMITS_SPEC_POWER_LIMIT_INDEX]) {
|
||||
limit = nla_get_u32(spec[SAR_LIMITS_SPEC_POWER_LIMIT_INDEX]);
|
||||
row->limit_value = limit;
|
||||
} else {
|
||||
hdd_err("SAR Spec does not have power limit or index value");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (spec[SAR_LIMITS_SPEC_BAND]) {
|
||||
band = nla_get_u32(spec[SAR_LIMITS_SPEC_BAND]);
|
||||
ret = wlan_hdd_cfg80211_sar_convert_band(band, &row->band_id);
|
||||
if (ret) {
|
||||
hdd_err("Invalid SAR Band attr");
|
||||
return ret;
|
||||
}
|
||||
|
||||
row->validity_bitmap |= WMI_SAR_BAND_ID_VALID_MASK;
|
||||
}
|
||||
|
||||
if (spec[SAR_LIMITS_SPEC_CHAIN]) {
|
||||
row->chain_id = nla_get_u32(spec[SAR_LIMITS_SPEC_CHAIN]);
|
||||
row->validity_bitmap |= WMI_SAR_CHAIN_ID_VALID_MASK;
|
||||
}
|
||||
|
||||
if (spec[SAR_LIMITS_SPEC_MODULATION]) {
|
||||
modulation = nla_get_u32(spec[SAR_LIMITS_SPEC_MODULATION]);
|
||||
ret = wlan_hdd_cfg80211_sar_convert_modulation(modulation,
|
||||
&row->mod_id);
|
||||
if (ret) {
|
||||
hdd_err("Invalid SAR Modulation attr");
|
||||
return ret;
|
||||
}
|
||||
|
||||
row->validity_bitmap |= WMI_SAR_MOD_ID_VALID_MASK;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* __wlan_hdd_set_sar_power_limits() - Set SAR power limits
|
||||
* @wiphy: Pointer to wireless phy
|
||||
* @wdev: Pointer to wireless device
|
||||
* @data: Pointer to data
|
||||
* @data_len: Length of @data
|
||||
*
|
||||
* This function is used to setup Specific Absorption Rate limit specs.
|
||||
*
|
||||
* Return: 0 on success, negative errno on failure
|
||||
*/
|
||||
static int __wlan_hdd_set_sar_power_limits(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data, int data_len)
|
||||
{
|
||||
struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
|
||||
struct nlattr *spec[SAR_LIMITS_MAX + 1];
|
||||
struct nlattr *tb[SAR_LIMITS_MAX + 1];
|
||||
struct nlattr *spec_list;
|
||||
struct sar_limit_cmd_params *sar_limit_cmd;
|
||||
int ret = -EINVAL, i = 0, rem = 0;
|
||||
QDF_STATUS status;
|
||||
uint32_t num_limit_rows = 0;
|
||||
struct sar_limit_cmd_row *row;
|
||||
uint32_t sar_enable;
|
||||
|
||||
hdd_enter();
|
||||
|
||||
if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
|
||||
hdd_err("Command not allowed in FTM mode");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (wlan_hdd_validate_context(hdd_ctx))
|
||||
return -EINVAL;
|
||||
|
||||
if (wlan_cfg80211_nla_parse(tb, SAR_LIMITS_MAX, data, data_len,
|
||||
wlan_hdd_sar_limits_policy)) {
|
||||
hdd_err("Invalid SAR attributes");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tb[SAR_LIMITS_SAR_ENABLE]) {
|
||||
sar_enable = nla_get_u32(tb[SAR_LIMITS_SAR_ENABLE]);
|
||||
|
||||
if ((sar_enable >=
|
||||
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0 &&
|
||||
sar_enable <=
|
||||
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4) &&
|
||||
hdd_ctx->sar_version == SAR_VERSION_2 &&
|
||||
!hdd_ctx->config->enable_sar_conversion) {
|
||||
hdd_err("SARV1 to SARV2 is disabled from ini");
|
||||
return -EINVAL;
|
||||
} else if (sar_enable ==
|
||||
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0 &&
|
||||
hdd_ctx->sar_version == SAR_VERSION_1) {
|
||||
hdd_err("FW expects SARV1 given command is SARV2");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
sar_limit_cmd = qdf_mem_malloc(sizeof(struct sar_limit_cmd_params));
|
||||
if (!sar_limit_cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
wlan_hdd_sar_timers_reset(hdd_ctx);
|
||||
|
||||
/* is special SAR V1 => SAR V2 logic enabled and applicable? */
|
||||
if (hdd_ctx->config->enable_sar_conversion &&
|
||||
(hdd_convert_sarv1_to_sarv2(hdd_ctx, tb, sar_limit_cmd)))
|
||||
goto send_sar_limits;
|
||||
|
||||
/* Vendor command manadates all SAR Specs in single call */
|
||||
sar_limit_cmd->commit_limits = 1;
|
||||
sar_limit_cmd->sar_enable = WMI_SAR_FEATURE_NO_CHANGE;
|
||||
if (tb[SAR_LIMITS_SAR_ENABLE]) {
|
||||
uint32_t *sar_ptr = &sar_limit_cmd->sar_enable;
|
||||
|
||||
sar_enable = nla_get_u32(tb[SAR_LIMITS_SAR_ENABLE]);
|
||||
ret = wlan_hdd_cfg80211_sar_convert_limit_set(sar_enable,
|
||||
sar_ptr);
|
||||
if (ret) {
|
||||
hdd_err("Invalid SAR Enable attr");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
hdd_debug("attr sar sar_enable %d", sar_limit_cmd->sar_enable);
|
||||
|
||||
if (tb[SAR_LIMITS_NUM_SPECS]) {
|
||||
num_limit_rows = nla_get_u32(tb[SAR_LIMITS_NUM_SPECS]);
|
||||
hdd_debug("attr sar num_limit_rows %u", num_limit_rows);
|
||||
}
|
||||
|
||||
if (num_limit_rows > MAX_SAR_LIMIT_ROWS_SUPPORTED) {
|
||||
hdd_err("SAR Spec list exceed supported size");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (num_limit_rows == 0)
|
||||
goto send_sar_limits;
|
||||
|
||||
row = qdf_mem_malloc(sizeof(*row) * num_limit_rows);
|
||||
if (!row) {
|
||||
hdd_err("Failed to allocate memory for sar_limit_row_list");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sar_limit_cmd->num_limit_rows = num_limit_rows;
|
||||
sar_limit_cmd->sar_limit_row_list = row;
|
||||
|
||||
if (!tb[SAR_LIMITS_SPEC]) {
|
||||
hdd_err("Invalid SAR specification list");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nla_for_each_nested(spec_list, tb[SAR_LIMITS_SPEC], rem) {
|
||||
if (i == num_limit_rows) {
|
||||
hdd_warn("SAR Cmd has excess SPECs in list");
|
||||
break;
|
||||
}
|
||||
|
||||
if (wlan_cfg80211_nla_parse(spec,
|
||||
SAR_LIMITS_MAX,
|
||||
nla_data(spec_list),
|
||||
nla_len(spec_list),
|
||||
wlan_hdd_sar_limits_policy)) {
|
||||
hdd_err("nla_parse failed for SAR Spec list");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = hdd_extract_sar_nested_attrs(spec, row);
|
||||
if (ret) {
|
||||
hdd_err("Failed to extract SAR nested attrs");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hdd_debug("Spec_ID: %d, Band: %d Chain: %d Mod: %d POW_Limit: %d Validity_Bitmap: %d",
|
||||
i, row->band_id, row->chain_id, row->mod_id,
|
||||
row->limit_value, row->validity_bitmap);
|
||||
|
||||
i++;
|
||||
row++;
|
||||
}
|
||||
|
||||
if (i < sar_limit_cmd->num_limit_rows) {
|
||||
hdd_warn("SAR Cmd has less SPECs in list");
|
||||
sar_limit_cmd->num_limit_rows = i;
|
||||
}
|
||||
|
||||
send_sar_limits:
|
||||
status = sme_set_sar_power_limits(hdd_ctx->mac_handle, sar_limit_cmd);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
hdd_err("Failed to set sar power limits");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* After SSR, the SAR configuration is lost. As SSR is hidden from
|
||||
* userland, this command will not come from userspace after a SSR. To
|
||||
* restore this configuration, save this in hdd context and restore
|
||||
* after re-init.
|
||||
*/
|
||||
hdd_store_sar_config(hdd_ctx, sar_limit_cmd);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (sar_limit_cmd) {
|
||||
qdf_mem_free(sar_limit_cmd->sar_limit_row_list);
|
||||
qdf_mem_free(sar_limit_cmd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#undef SAR_LIMITS_SAR_ENABLE
|
||||
#undef SAR_LIMITS_NUM_SPECS
|
||||
#undef SAR_LIMITS_SPEC
|
||||
#undef SAR_LIMITS_SPEC_BAND
|
||||
#undef SAR_LIMITS_SPEC_CHAIN
|
||||
#undef SAR_LIMITS_SPEC_MODULATION
|
||||
#undef SAR_LIMITS_SPEC_POWER_LIMIT
|
||||
#undef SAR_LIMITS_SPEC_POWER_LIMIT_INDEX
|
||||
#undef SAR_LIMITS_MAX
|
||||
|
||||
int wlan_hdd_cfg80211_set_sar_power_limits(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data,
|
||||
int data_len)
|
||||
{
|
||||
struct osif_psoc_sync *psoc_sync;
|
||||
int errno;
|
||||
|
||||
errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
|
||||
if (errno)
|
||||
return errno;
|
||||
|
||||
errno = __wlan_hdd_set_sar_power_limits(wiphy, wdev, data, data_len);
|
||||
|
||||
osif_psoc_sync_op_stop(psoc_sync);
|
||||
|
||||
return errno;
|
||||
}
|
||||
|
||||
int wlan_hdd_cfg80211_get_sar_power_limits(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data,
|
||||
|
|
|
|||
|
|
@ -163,17 +163,81 @@ int wlan_hdd_cfg80211_get_sar_power_limits(struct wiphy *wiphy,
|
|||
const void *data,
|
||||
int data_len);
|
||||
|
||||
#define FEATURE_SAR_LIMITS_VENDOR_COMMANDS \
|
||||
{ \
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID, \
|
||||
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS, \
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | \
|
||||
WIPHY_VENDOR_CMD_NEED_RUNNING, \
|
||||
.doit = wlan_hdd_cfg80211_get_sar_power_limits, \
|
||||
/**
|
||||
* wlan_hdd_cfg80211_set_sar_power_limits() - Set SAR power limits
|
||||
* @wiphy: Pointer to wireless phy
|
||||
* @wdev: Pointer to wireless device
|
||||
* @data: Pointer to data
|
||||
* @data_len: Length of @data
|
||||
*
|
||||
* Wrapper function of __wlan_hdd_cfg80211_set_sar_power_limits()
|
||||
*
|
||||
* Return: 0 on success, negative errno on failure
|
||||
*/
|
||||
int wlan_hdd_cfg80211_set_sar_power_limits(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data,
|
||||
int data_len);
|
||||
|
||||
/**
|
||||
* hdd_store_sar_config() - Store SAR config in HDD context
|
||||
* @hdd_ctx: The HDD context
|
||||
* @sar_limit_cmd: The sar_limit_cmd_params struct to save
|
||||
*
|
||||
* After SSR, the SAR configuration is lost. As SSR is hidden from
|
||||
* userland, this command will not come from userspace after a SSR. To
|
||||
* restore this configuration, save this in hdd context and restore
|
||||
* after re-init.
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void hdd_store_sar_config(struct hdd_context *hdd_ctx,
|
||||
struct sar_limit_cmd_params *sar_limit_cmd);
|
||||
|
||||
/**
|
||||
* hdd_free_sar_config() - Free the resources allocated while storing SAR config
|
||||
* @hdd_ctx: HDD context
|
||||
*
|
||||
* The driver stores the SAR config values in HDD context so that it can be
|
||||
* restored in the case SSR is invoked. Free those resources.
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void wlan_hdd_free_sar_config(struct hdd_context *hdd_ctx);
|
||||
|
||||
extern const struct nla_policy
|
||||
wlan_hdd_sar_limits_policy[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX + 1];
|
||||
|
||||
#define FEATURE_SAR_LIMITS_VENDOR_COMMANDS \
|
||||
{ \
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID, \
|
||||
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS, \
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | \
|
||||
WIPHY_VENDOR_CMD_NEED_RUNNING, \
|
||||
.doit = wlan_hdd_cfg80211_get_sar_power_limits, \
|
||||
vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \
|
||||
}, \
|
||||
{ \
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID, \
|
||||
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS, \
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | \
|
||||
WIPHY_VENDOR_CMD_NEED_RUNNING, \
|
||||
.doit = wlan_hdd_cfg80211_set_sar_power_limits, \
|
||||
vendor_command_policy(wlan_hdd_sar_limits_policy, \
|
||||
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX) \
|
||||
},
|
||||
#else /* FEATURE_SAR_LIMITS */
|
||||
#define FEATURE_SAR_LIMITS_VENDOR_COMMANDS
|
||||
static inline
|
||||
void hdd_store_sar_config(struct hdd_context *hdd_ctx,
|
||||
struct sar_limit_cmd_params *sar_limit_cmd)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void wlan_hdd_free_sar_config(struct hdd_context *hdd_ctx)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* FEATURE_SAR_LIMITS */
|
||||
|
||||
#endif /* __WLAN_HDD_SAR_LIMITS_H */
|
||||
|
|
|
|||
Loading…
Reference in a new issue