drivers: wifi: siwx91x: Add support for set_power_save()
Added power-save mode support to optimize station wake-up timing and reduce power consumption. The device currently supports only legacy power-save mode. This feature can be tested using the Wifi shell: - ps: Enable the PS. By default, the device operates in fast PSP mode. - ps_exit_strategy: Updates mode if enabled; otherwise, follows the configured exit strategy when power-save is enabled. - ps_wakeup_mode: Configures the wake-up behavior. - ps_timeout: Defines the timeout duration for power-save mode. Co-authored-by: Arunmani Alagarsamy <arunmani.a@silabs.com> Signed-off-by: Arunmani Alagarsamy <arunmani.a@silabs.com> Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
This commit is contained in:
parent
b939714204
commit
adae16812e
2 changed files with 140 additions and 0 deletions
|
@ -253,6 +253,139 @@ static enum wifi_mfp_options siwx91x_set_sta_mfp_option(sl_wifi_security_t secur
|
|||
return WIFI_MFP_UNKNOWN;
|
||||
}
|
||||
|
||||
static int siwx91x_get_connected_ap_beacon_interval_ms(void)
|
||||
{
|
||||
sl_wifi_operational_statistics_t sl_stat;
|
||||
sl_wifi_interface_t interface;
|
||||
int status;
|
||||
|
||||
interface = sl_wifi_get_default_interface();
|
||||
if (FIELD_GET(SIWX91X_INTERFACE_MASK, interface) != SL_WIFI_CLIENT_INTERFACE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = sl_wifi_get_operational_statistics(SL_WIFI_CLIENT_INTERFACE, &sl_stat);
|
||||
if (status) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sys_get_le16(sl_stat.beacon_interval) * 1024 / 1000;
|
||||
}
|
||||
|
||||
static int siwx91x_apply_power_save(struct siwx91x_dev *sidev)
|
||||
{
|
||||
sl_wifi_performance_profile_t sl_ps_profile;
|
||||
sl_wifi_interface_t interface;
|
||||
int beacon_interval;
|
||||
int status;
|
||||
|
||||
interface = sl_wifi_get_default_interface();
|
||||
if (FIELD_GET(SIWX91X_INTERFACE_MASK, interface) != SL_WIFI_CLIENT_INTERFACE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sidev->state == WIFI_STATE_INTERFACE_DISABLED) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sl_wifi_get_performance_profile(&sl_ps_profile);
|
||||
|
||||
if (sidev->ps_params.enabled == WIFI_PS_DISABLED) {
|
||||
sl_ps_profile.profile = HIGH_PERFORMANCE;
|
||||
goto out;
|
||||
}
|
||||
if (sidev->ps_params.exit_strategy == WIFI_PS_EXIT_EVERY_TIM) {
|
||||
sl_ps_profile.profile = ASSOCIATED_POWER_SAVE_LOW_LATENCY;
|
||||
} else if (sidev->ps_params.exit_strategy == WIFI_PS_EXIT_CUSTOM_ALGO) {
|
||||
sl_ps_profile.profile = ASSOCIATED_POWER_SAVE;
|
||||
} else {
|
||||
/* Already sanitized by siwx91x_set_power_save() */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sl_ps_profile.monitor_interval = sidev->ps_params.timeout_ms;
|
||||
|
||||
beacon_interval = siwx91x_get_connected_ap_beacon_interval_ms();
|
||||
/* 1000ms is arbitrary sane value */
|
||||
sl_ps_profile.listen_interval = MIN(beacon_interval * sidev->ps_params.listen_interval,
|
||||
1000);
|
||||
|
||||
if (sidev->ps_params.wakeup_mode == WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL &&
|
||||
!sidev->ps_params.listen_interval) {
|
||||
LOG_INF("Disabling listen interval based wakeup until connection establishes");
|
||||
}
|
||||
if (sidev->ps_params.wakeup_mode == WIFI_PS_WAKEUP_MODE_DTIM ||
|
||||
!sidev->ps_params.listen_interval) {
|
||||
sl_ps_profile.dtim_aligned_type = 1;
|
||||
} else if (sidev->ps_params.wakeup_mode == WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL) {
|
||||
sl_ps_profile.dtim_aligned_type = 0;
|
||||
} else {
|
||||
/* Already sanitized by siwx91x_set_power_save() */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
out:
|
||||
status = sl_wifi_set_performance_profile(&sl_ps_profile);
|
||||
return status ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int siwx91x_set_power_save(const struct device *dev, struct wifi_ps_params *params)
|
||||
{
|
||||
struct siwx91x_dev *sidev = dev->data;
|
||||
int status;
|
||||
|
||||
__ASSERT(params, "params cannot be NULL");
|
||||
|
||||
switch (params->type) {
|
||||
case WIFI_PS_PARAM_STATE:
|
||||
sidev->ps_params.enabled = params->enabled;
|
||||
break;
|
||||
case WIFI_PS_PARAM_MODE:
|
||||
if (params->mode != WIFI_PS_MODE_LEGACY) {
|
||||
params->fail_reason = WIFI_PS_PARAM_FAIL_OPERATION_NOT_SUPPORTED;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
break;
|
||||
case WIFI_PS_PARAM_LISTEN_INTERVAL:
|
||||
sidev->ps_params.listen_interval = params->listen_interval;
|
||||
break;
|
||||
case WIFI_PS_PARAM_WAKEUP_MODE:
|
||||
if (params->wakeup_mode != WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL &&
|
||||
params->wakeup_mode != WIFI_PS_WAKEUP_MODE_DTIM) {
|
||||
params->fail_reason = WIFI_PS_PARAM_FAIL_OPERATION_NOT_SUPPORTED;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
sidev->ps_params.wakeup_mode = params->wakeup_mode;
|
||||
break;
|
||||
case WIFI_PS_PARAM_TIMEOUT:
|
||||
/* 1000ms is arbitrary sane value */
|
||||
if (params->timeout_ms < SLI_DEFAULT_MONITOR_INTERVAL ||
|
||||
params->timeout_ms > 1000) {
|
||||
params->fail_reason = WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL;
|
||||
return -EINVAL;
|
||||
}
|
||||
sidev->ps_params.timeout_ms = params->timeout_ms;
|
||||
break;
|
||||
case WIFI_PS_PARAM_EXIT_STRATEGY:
|
||||
if (params->exit_strategy != WIFI_PS_EXIT_EVERY_TIM &&
|
||||
params->exit_strategy != WIFI_PS_EXIT_CUSTOM_ALGO) {
|
||||
params->fail_reason = WIFI_PS_PARAM_FAIL_OPERATION_NOT_SUPPORTED;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
sidev->ps_params.exit_strategy = params->exit_strategy;
|
||||
break;
|
||||
default:
|
||||
params->fail_reason = WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL;
|
||||
return -EINVAL;
|
||||
}
|
||||
status = siwx91x_apply_power_save(sidev);
|
||||
if (status) {
|
||||
params->fail_reason = WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL;
|
||||
return status;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int siwx91x_on_join(sl_wifi_event_t event,
|
||||
char *result, uint32_t result_size, void *arg)
|
||||
{
|
||||
|
@ -275,6 +408,8 @@ static unsigned int siwx91x_on_join(sl_wifi_event_t event,
|
|||
siwx91x_on_join_ipv4(sidev);
|
||||
siwx91x_on_join_ipv6(sidev);
|
||||
|
||||
siwx91x_apply_power_save(sidev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1439,6 +1574,7 @@ static const struct wifi_mgmt_ops siwx91x_mgmt = {
|
|||
.get_stats = siwx91x_stats,
|
||||
#endif
|
||||
.get_version = siwx91x_get_version,
|
||||
.set_power_save = siwx91x_set_power_save,
|
||||
};
|
||||
|
||||
static const struct net_wifi_mgmt_offload siwx91x_api = {
|
||||
|
@ -1452,6 +1588,9 @@ static const struct net_wifi_mgmt_offload siwx91x_api = {
|
|||
};
|
||||
|
||||
static struct siwx91x_dev sidev = {
|
||||
.ps_params.enabled = WIFI_PS_DISABLED,
|
||||
.ps_params.exit_strategy = WIFI_PS_EXIT_EVERY_TIM,
|
||||
.ps_params.wakeup_mode = WIFI_PS_WAKEUP_MODE_DTIM,
|
||||
.max_num_sta = CONFIG_WIFI_MGMT_AP_MAX_NUM_STA,
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ struct siwx91x_dev {
|
|||
enum wifi_iface_state scan_prev_state;
|
||||
scan_result_cb_t scan_res_cb;
|
||||
uint16_t scan_max_bss_cnt;
|
||||
struct wifi_ps_params ps_params;
|
||||
uint8_t max_num_sta;
|
||||
bool reboot_needed;
|
||||
bool hidden_ssid;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue