qcacld-3.0: Save and restore SAR config post SSR

After SSR, SAR configuration is lost.
Since, SSR is hidden from userland, VENDOR_SUBCMD_SET_SAR_LIMITS
to configure SAR shall not come again from userspace after SSR.

To restore SAR configuration, save this in hdd context when the vendor
command comes and restore after re-init.

Change-Id: I083fb72a9fad35af1a84bcc9d8d59976485b9fa3
CRs-Fixed: 2427382
This commit is contained in:
Sourav Mohapatra 2019-04-02 15:02:59 +05:30 • committed by nshrivas
commit 9036f65119
5 changed files with 254 additions and 98 deletions

View file

@ -1592,6 +1592,7 @@ struct hdd_dynamic_mac {
* @g_event_flags: a bitmap of hdd_driver_flags
* @psoc_idle_timeout_work: delayed work for psoc idle shutdown
* @dynamic_nss_chains_support: Per vdev dynamic nss chains update capability
* @sar_cmd_params: SAR command params to be configured to the FW
*/
struct hdd_context {
struct wlan_objmgr_psoc *psoc;
@ -1866,6 +1867,8 @@ struct hdd_context {
uint32_t num_derived_addr;
unsigned long provisioned_intf_addr_mask;
unsigned long derived_intf_addr_mask;
struct sar_limit_cmd_params *sar_cmd_params;
};
/**

View file

@ -10430,17 +10430,116 @@ static int wlan_hdd_cfg80211_sar_convert_modulation(u32 nl80211_value,
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[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX + 1] = {
[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE] = {.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS] = {.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND] = {.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN] = {.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION] = {.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT] = {.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX] = {.type = NLA_U32},
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
@ -10457,12 +10556,14 @@ static int __wlan_hdd_set_sar_power_limits(struct wiphy *wiphy,
const void *data, int data_len)
{
struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
struct nlattr *sar_spec[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX + 1],
*tb[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX + 1],
*sar_spec_list;
struct sar_limit_cmd_params sar_limit_cmd = {0};
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;
mac_handle_t mac_handle;
QDF_STATUS status;
uint32_t num_limit_rows = 0;
struct sar_limit_cmd_row *row;
hdd_enter();
@ -10474,137 +10575,132 @@ static int __wlan_hdd_set_sar_power_limits(struct wiphy *wiphy,
if (wlan_hdd_validate_context(hdd_ctx))
return -EINVAL;
if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX,
data, data_len, sar_limits_policy)) {
if (wlan_cfg80211_nla_parse(tb, SAR_LIMITS_MAX, data, data_len,
sar_limits_policy)) {
hdd_err("Invalid SAR attributes");
return -EINVAL;
}
sar_limit_cmd = qdf_mem_malloc(sizeof(struct sar_limit_cmd_params));
if (!sar_limit_cmd)
return -ENOMEM;
/* is special SAR V1 => SAR V2 logic enabled and applicable? */
if (hdd_convert_sarv1_to_sarv2(hdd_ctx, tb, &sar_limit_cmd))
if (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[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE]) {
if (wlan_hdd_cfg80211_sar_convert_limit_set(nla_get_u32(
tb[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE]),
&sar_limit_cmd.sar_enable) < 0) {
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_enable = nla_get_u32(tb[SAR_LIMITS_SAR_ENABLE]);
uint32_t *sar_ptr = &sar_limit_cmd->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[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS]) {
sar_limit_cmd.num_limit_rows = nla_get_u32(
tb[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS]);
hdd_debug("attr sar num_limit_rows %d",
sar_limit_cmd.num_limit_rows);
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 (sar_limit_cmd.num_limit_rows > MAX_SAR_LIMIT_ROWS_SUPPORTED) {
if (num_limit_rows > MAX_SAR_LIMIT_ROWS_SUPPORTED) {
hdd_err("SAR Spec list exceed supported size");
goto fail;
}
if (sar_limit_cmd.num_limit_rows == 0)
if (num_limit_rows == 0)
goto send_sar_limits;
sar_limit_cmd.sar_limit_row_list = qdf_mem_malloc(sizeof(
struct sar_limit_cmd_row) *
sar_limit_cmd.num_limit_rows);
if (!sar_limit_cmd.sar_limit_row_list) {
ret = -ENOMEM;
goto fail;
}
if (!tb[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC]) {
hdd_err("Invalid SAR SPECs list");
row = qdf_mem_malloc(sizeof(*row) * num_limit_rows);
if (!row) {
hdd_err("Failed to allocate memory for sar_limit_row_list");
goto fail;
}
nla_for_each_nested(sar_spec_list,
tb[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC], rem) {
if (i == sar_limit_cmd.num_limit_rows) {
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(sar_spec,
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX,
nla_data(sar_spec_list),
nla_len(sar_spec_list),
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;
}
sar_limit_cmd.sar_limit_row_list[i].validity_bitmap = 0;
if (sar_spec[
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT]) {
sar_limit_cmd.sar_limit_row_list[i].limit_value =
nla_get_u32(sar_spec[
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT]);
} else if (sar_spec[
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX]) {
sar_limit_cmd.sar_limit_row_list[i].limit_value =
nla_get_u32(sar_spec[
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX]);
} else {
hdd_err("SAR Spec does not have power limit or index value");
ret = hdd_extract_sar_nested_attrs(spec, row);
if (ret) {
hdd_err("Failed to extract SAR nested attrs");
goto fail;
}
if (sar_spec[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND]) {
if (wlan_hdd_cfg80211_sar_convert_band(nla_get_u32(
sar_spec[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND]),
&sar_limit_cmd.sar_limit_row_list[i].band_id)
< 0) {
hdd_err("Invalid SAR Band attr");
goto fail;
}
sar_limit_cmd.sar_limit_row_list[i].validity_bitmap |=
WMI_SAR_BAND_ID_VALID_MASK;
}
if (sar_spec[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN]) {
sar_limit_cmd.sar_limit_row_list[i].chain_id =
nla_get_u32(sar_spec[
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN]);
sar_limit_cmd.sar_limit_row_list[i].validity_bitmap |=
WMI_SAR_CHAIN_ID_VALID_MASK;
}
if (sar_spec[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION]) {
if (wlan_hdd_cfg80211_sar_convert_modulation(nla_get_u32(
sar_spec[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION]),
&sar_limit_cmd.sar_limit_row_list[i].mod_id)
< 0) {
hdd_err("Invalid SAR Modulation attr");
goto fail;
}
sar_limit_cmd.sar_limit_row_list[i].validity_bitmap |=
WMI_SAR_MOD_ID_VALID_MASK;
}
hdd_debug("Spec_ID: %d, Band: %d Chain: %d Mod: %d POW_Limit: %d Validity_Bitmap: %d",
i, sar_limit_cmd.sar_limit_row_list[i].band_id,
sar_limit_cmd.sar_limit_row_list[i].chain_id,
sar_limit_cmd.sar_limit_row_list[i].mod_id,
sar_limit_cmd.sar_limit_row_list[i].limit_value,
sar_limit_cmd.sar_limit_row_list[i].validity_bitmap);
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) {
if (i < sar_limit_cmd->num_limit_rows) {
hdd_warn("SAR Cmd has less SPECs in list");
sar_limit_cmd.num_limit_rows = i;
sar_limit_cmd->num_limit_rows = i;
}
send_sar_limits:
mac_handle = hdd_ctx->mac_handle;
if (sme_set_sar_power_limits(mac_handle, &sar_limit_cmd) ==
QDF_STATUS_SUCCESS)
ret = 0;
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:
qdf_mem_free(sar_limit_cmd.sar_limit_row_list);
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

View file

@ -625,6 +625,32 @@ 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

View file

@ -11522,6 +11522,14 @@ int hdd_wlan_stop_modules(struct hdd_context *hdd_ctx, bool ftm_mode)
/* Free the cache channels of the command SET_DISABLE_CHANNEL_LIST */
wlan_hdd_free_cache_channels(hdd_ctx);
/* Free the resources allocated while storing SAR config. These needs
* to be freed only in the case when it is not SSR. As in the case of
* SSR, the values needs to be intact so that it can be restored during
* reinit path.
*/
if (!is_recovery_stop)
wlan_hdd_free_sar_config(hdd_ctx);
hdd_sap_destroy_ctx_all(hdd_ctx, is_recovery_stop);
hdd_check_for_leaks(hdd_ctx, is_recovery_stop);

View file

@ -1367,6 +1367,27 @@ static void hdd_is_interface_down_during_ssr(struct hdd_context *hdd_ctx)
hdd_exit();
}
/**
* hdd_restore_sar_config - Restore the saved SAR config after SSR
* @hdd_ctx: HDD context
*
* Restore the SAR config that was lost during SSR.
*
* Return: None
*/
static void hdd_restore_sar_config(struct hdd_context *hdd_ctx)
{
QDF_STATUS status;
if (!hdd_ctx->sar_cmd_params)
return;
status = sme_set_sar_power_limits(hdd_ctx->mac_handle,
hdd_ctx->sar_cmd_params);
if (QDF_IS_STATUS_ERROR(status))
hdd_err("Unable to configured SAR after SSR");
}
QDF_STATUS hdd_wlan_re_init(void)
{
struct hdd_context *hdd_ctx = NULL;
@ -1418,6 +1439,8 @@ QDF_STATUS hdd_wlan_re_init(void)
sme_set_chip_pwr_save_fail_cb(hdd_ctx->mac_handle,
hdd_chip_pwr_save_fail_detected_cb);
hdd_restore_sar_config(hdd_ctx);
hdd_send_default_scan_ies(hdd_ctx);
hdd_info("WLAN host driver reinitiation completed!");