drivers: wifi: siwx91x: Extract Power Save related functions
siwx91x_wifi.c starts to contains to much code. Let's simplify it by grouping all the power-save related functions in a separated file. Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
This commit is contained in:
parent
9a1ebee72b
commit
5818738668
@ -2,7 +2,11 @@
|
||||
# Copyright (c) 2024 Silicon Laboratories Inc.
|
||||
|
||||
if(CONFIG_WIFI_SILABS_SIWX91X)
|
||||
zephyr_library_sources(siwx91x_wifi.c siwx91x_wifi_ap.c siwx91x_wifi_scan.c)
|
||||
zephyr_library_sources(
|
||||
siwx91x_wifi.c
|
||||
siwx91x_wifi_ap.c
|
||||
siwx91x_wifi_scan.c
|
||||
siwx91x_wifi_ps.c)
|
||||
|
||||
if(CONFIG_WIFI_SILABS_SIWX91X_NET_STACK_OFFLOAD)
|
||||
zephyr_library_sources(siwx91x_wifi_socket.c)
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
#include <nwp.h>
|
||||
#include "siwx91x_wifi.h"
|
||||
#include "siwx91x_wifi_ap.h"
|
||||
#include "siwx91x_wifi_ps.h"
|
||||
#include "siwx91x_wifi_scan.h"
|
||||
#include "siwx91x_wifi_socket.h"
|
||||
|
||||
@ -30,12 +31,6 @@ LOG_MODULE_REGISTER(siwx91x_wifi);
|
||||
|
||||
NET_BUF_POOL_FIXED_DEFINE(siwx91x_tx_pool, 1, _NET_ETH_MAX_FRAME_SIZE, 0, NULL);
|
||||
|
||||
enum {
|
||||
REQUEST_TWT = 0,
|
||||
SUGGEST_TWT = 1,
|
||||
DEMAND_TWT = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
STATE_IDLE = 0x00,
|
||||
/* Failover Roam */
|
||||
@ -191,203 +186,6 @@ 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) {
|
||||
LOG_ERR("Wi-Fi not in station mode");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sidev->state == WIFI_STATE_INTERFACE_DISABLED) {
|
||||
LOG_ERR("Command given in invalid state");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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 int siwx91x_get_power_save_config(const struct device *dev, struct wifi_ps_config *config)
|
||||
{
|
||||
sl_wifi_performance_profile_t sl_ps_profile;
|
||||
struct siwx91x_dev *sidev = dev->data;
|
||||
sl_wifi_interface_t interface;
|
||||
uint16_t beacon_interval;
|
||||
sl_status_t status;
|
||||
|
||||
__ASSERT(config, "config cannot be NULL");
|
||||
|
||||
interface = sl_wifi_get_default_interface();
|
||||
if (FIELD_GET(SIWX91X_INTERFACE_MASK, interface) != SL_WIFI_CLIENT_INTERFACE) {
|
||||
LOG_ERR("Wi-Fi not in station mode");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sidev->state == WIFI_STATE_INTERFACE_DISABLED) {
|
||||
LOG_ERR("Command given in invalid state");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
status = sl_wifi_get_performance_profile(&sl_ps_profile);
|
||||
if (status != SL_STATUS_OK) {
|
||||
LOG_ERR("Failed to get power save profile: 0x%x", status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
switch (sl_ps_profile.profile) {
|
||||
case HIGH_PERFORMANCE:
|
||||
config->ps_params.enabled = WIFI_PS_DISABLED;
|
||||
break;
|
||||
case ASSOCIATED_POWER_SAVE_LOW_LATENCY:
|
||||
config->ps_params.enabled = WIFI_PS_ENABLED;
|
||||
config->ps_params.exit_strategy = WIFI_PS_EXIT_EVERY_TIM;
|
||||
break;
|
||||
case ASSOCIATED_POWER_SAVE:
|
||||
config->ps_params.enabled = WIFI_PS_ENABLED;
|
||||
config->ps_params.exit_strategy = WIFI_PS_EXIT_CUSTOM_ALGO;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (sl_ps_profile.dtim_aligned_type) {
|
||||
config->ps_params.wakeup_mode = WIFI_PS_WAKEUP_MODE_DTIM;
|
||||
} else {
|
||||
config->ps_params.wakeup_mode = WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL;
|
||||
|
||||
beacon_interval = siwx91x_get_connected_ap_beacon_interval_ms();
|
||||
if (beacon_interval > 0) {
|
||||
config->ps_params.listen_interval =
|
||||
sl_ps_profile.listen_interval / beacon_interval;
|
||||
}
|
||||
}
|
||||
|
||||
/* Device supports only legacy power-save mode */
|
||||
config->ps_params.mode = WIFI_PS_MODE_LEGACY;
|
||||
config->ps_params.timeout_ms = sl_ps_profile.monitor_interval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int siwx91x_on_join(sl_wifi_event_t event,
|
||||
char *result, uint32_t result_size, void *arg)
|
||||
{
|
||||
@ -929,138 +727,6 @@ static int siwx91x_dev_init(const struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int siwx91x_convert_z_sl_twt_req_type(enum wifi_twt_setup_cmd z_req_cmd)
|
||||
{
|
||||
switch (z_req_cmd) {
|
||||
case WIFI_TWT_SETUP_CMD_REQUEST:
|
||||
return REQUEST_TWT;
|
||||
case WIFI_TWT_SETUP_CMD_SUGGEST:
|
||||
return SUGGEST_TWT;
|
||||
case WIFI_TWT_SETUP_CMD_DEMAND:
|
||||
return DEMAND_TWT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int siwx91x_set_twt_setup(struct wifi_twt_params *params)
|
||||
{
|
||||
sl_status_t status;
|
||||
int twt_req_type = siwx91x_convert_z_sl_twt_req_type(params->setup_cmd);
|
||||
|
||||
sl_wifi_twt_request_t twt_req = {
|
||||
.twt_retry_interval = 5,
|
||||
.wake_duration_unit = 0,
|
||||
.wake_int_mantissa = params->setup.twt_mantissa,
|
||||
.un_announced_twt = !params->setup.announce,
|
||||
.wake_duration = params->setup.twt_wake_interval,
|
||||
.triggered_twt = params->setup.trigger,
|
||||
.wake_int_exp = params->setup.twt_exponent,
|
||||
.implicit_twt = 1,
|
||||
.twt_flow_id = params->flow_id,
|
||||
.twt_enable = 1,
|
||||
.req_type = twt_req_type,
|
||||
};
|
||||
|
||||
if (twt_req_type < 0) {
|
||||
params->fail_reason = WIFI_TWT_FAIL_CMD_EXEC_FAIL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!params->setup.twt_info_disable) {
|
||||
params->fail_reason = WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (params->setup.responder) {
|
||||
params->fail_reason = WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* implicit -> won't do renegotiation
|
||||
* explicit -> must do renegotiation for each session
|
||||
*/
|
||||
if (!params->setup.implicit) {
|
||||
/* explicit twt is not supported */
|
||||
params->fail_reason = WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (params->setup.twt_wake_interval > 255 * 256) {
|
||||
twt_req.wake_duration_unit = 1;
|
||||
twt_req.wake_duration = params->setup.twt_wake_interval / 1024;
|
||||
} else {
|
||||
twt_req.wake_duration_unit = 0;
|
||||
twt_req.wake_duration = params->setup.twt_wake_interval / 256;
|
||||
}
|
||||
|
||||
status = sl_wifi_enable_target_wake_time(&twt_req);
|
||||
if (status != SL_STATUS_OK) {
|
||||
params->fail_reason = WIFI_TWT_FAIL_CMD_EXEC_FAIL;
|
||||
params->resp_status = WIFI_TWT_RESP_NOT_RECEIVED;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int siwx91x_set_twt_teardown(struct wifi_twt_params *params)
|
||||
{
|
||||
sl_status_t status;
|
||||
sl_wifi_twt_request_t twt_req = { };
|
||||
|
||||
twt_req.twt_enable = 0;
|
||||
|
||||
if (params->teardown.teardown_all) {
|
||||
twt_req.twt_flow_id = 0xFF;
|
||||
} else {
|
||||
twt_req.twt_flow_id = params->flow_id;
|
||||
}
|
||||
|
||||
status = sl_wifi_disable_target_wake_time(&twt_req);
|
||||
if (status != SL_STATUS_OK) {
|
||||
params->fail_reason = WIFI_TWT_FAIL_CMD_EXEC_FAIL;
|
||||
params->teardown_status = WIFI_TWT_TEARDOWN_FAILED;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
params->teardown_status = WIFI_TWT_TEARDOWN_SUCCESS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int siwx91x_set_twt(const struct device *dev, struct wifi_twt_params *params)
|
||||
{
|
||||
sl_wifi_interface_t interface = sl_wifi_get_default_interface();
|
||||
struct siwx91x_dev *sidev = dev->data;
|
||||
|
||||
__ASSERT(params, "params cannot be a NULL");
|
||||
|
||||
if (FIELD_GET(SIWX91X_INTERFACE_MASK, interface) != SL_WIFI_CLIENT_INTERFACE) {
|
||||
params->fail_reason = WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (sidev->state != WIFI_STATE_DISCONNECTED && sidev->state != WIFI_STATE_INACTIVE &&
|
||||
sidev->state != WIFI_STATE_COMPLETED) {
|
||||
LOG_ERR("Command given in invalid state");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (params->negotiation_type != WIFI_TWT_INDIVIDUAL) {
|
||||
params->fail_reason = WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (params->operation == WIFI_TWT_SETUP) {
|
||||
return siwx91x_set_twt_setup(params);
|
||||
} else if (params->operation == WIFI_TWT_TEARDOWN) {
|
||||
return siwx91x_set_twt_teardown(params);
|
||||
}
|
||||
params->fail_reason = WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static const struct wifi_mgmt_ops siwx91x_mgmt = {
|
||||
.scan = siwx91x_scan,
|
||||
.connect = siwx91x_connect,
|
||||
@ -1072,12 +738,12 @@ static const struct wifi_mgmt_ops siwx91x_mgmt = {
|
||||
.iface_status = siwx91x_status,
|
||||
.mode = siwx91x_mode,
|
||||
.set_twt = siwx91x_set_twt,
|
||||
.set_power_save = siwx91x_set_power_save,
|
||||
.get_power_save_config = siwx91x_get_power_save_config,
|
||||
#if defined(CONFIG_NET_STATISTICS_WIFI)
|
||||
.get_stats = siwx91x_stats,
|
||||
#endif
|
||||
.get_version = siwx91x_get_version,
|
||||
.set_power_save = siwx91x_set_power_save,
|
||||
.get_power_save_config = siwx91x_get_power_save_config,
|
||||
};
|
||||
|
||||
static const struct net_wifi_mgmt_offload siwx91x_api = {
|
||||
|
||||
346
drivers/wifi/siwx91x/siwx91x_wifi_ps.c
Normal file
346
drivers/wifi/siwx91x/siwx91x_wifi_ps.c
Normal file
@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Antmicro
|
||||
* Copyright (c) 2024-2025 Silicon Laboratories Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <nwp.h>
|
||||
#include "siwx91x_wifi.h"
|
||||
#include "siwx91x_wifi_ps.h"
|
||||
|
||||
LOG_MODULE_DECLARE(siwx91x_wifi);
|
||||
|
||||
enum {
|
||||
REQUEST_TWT = 0,
|
||||
SUGGEST_TWT = 1,
|
||||
DEMAND_TWT = 2,
|
||||
};
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
LOG_ERR("Wi-Fi not in station mode");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sidev->state == WIFI_STATE_INTERFACE_DISABLED) {
|
||||
LOG_ERR("Command given in invalid state");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int siwx91x_get_power_save_config(const struct device *dev, struct wifi_ps_config *config)
|
||||
{
|
||||
sl_wifi_performance_profile_t sl_ps_profile;
|
||||
struct siwx91x_dev *sidev = dev->data;
|
||||
sl_wifi_interface_t interface;
|
||||
uint16_t beacon_interval;
|
||||
sl_status_t status;
|
||||
|
||||
__ASSERT(config, "config cannot be NULL");
|
||||
|
||||
interface = sl_wifi_get_default_interface();
|
||||
if (FIELD_GET(SIWX91X_INTERFACE_MASK, interface) != SL_WIFI_CLIENT_INTERFACE) {
|
||||
LOG_ERR("Wi-Fi not in station mode");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sidev->state == WIFI_STATE_INTERFACE_DISABLED) {
|
||||
LOG_ERR("Command given in invalid state");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
status = sl_wifi_get_performance_profile(&sl_ps_profile);
|
||||
if (status != SL_STATUS_OK) {
|
||||
LOG_ERR("Failed to get power save profile: 0x%x", status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
switch (sl_ps_profile.profile) {
|
||||
case HIGH_PERFORMANCE:
|
||||
config->ps_params.enabled = WIFI_PS_DISABLED;
|
||||
break;
|
||||
case ASSOCIATED_POWER_SAVE_LOW_LATENCY:
|
||||
config->ps_params.enabled = WIFI_PS_ENABLED;
|
||||
config->ps_params.exit_strategy = WIFI_PS_EXIT_EVERY_TIM;
|
||||
break;
|
||||
case ASSOCIATED_POWER_SAVE:
|
||||
config->ps_params.enabled = WIFI_PS_ENABLED;
|
||||
config->ps_params.exit_strategy = WIFI_PS_EXIT_CUSTOM_ALGO;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (sl_ps_profile.dtim_aligned_type) {
|
||||
config->ps_params.wakeup_mode = WIFI_PS_WAKEUP_MODE_DTIM;
|
||||
} else {
|
||||
config->ps_params.wakeup_mode = WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL;
|
||||
|
||||
beacon_interval = siwx91x_get_connected_ap_beacon_interval_ms();
|
||||
if (beacon_interval > 0) {
|
||||
config->ps_params.listen_interval =
|
||||
sl_ps_profile.listen_interval / beacon_interval;
|
||||
}
|
||||
}
|
||||
|
||||
/* Device supports only legacy power-save mode */
|
||||
config->ps_params.mode = WIFI_PS_MODE_LEGACY;
|
||||
config->ps_params.timeout_ms = sl_ps_profile.monitor_interval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int siwx91x_convert_z_sl_twt_req_type(enum wifi_twt_setup_cmd z_req_cmd)
|
||||
{
|
||||
switch (z_req_cmd) {
|
||||
case WIFI_TWT_SETUP_CMD_REQUEST:
|
||||
return REQUEST_TWT;
|
||||
case WIFI_TWT_SETUP_CMD_SUGGEST:
|
||||
return SUGGEST_TWT;
|
||||
case WIFI_TWT_SETUP_CMD_DEMAND:
|
||||
return DEMAND_TWT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int siwx91x_set_twt_setup(struct wifi_twt_params *params)
|
||||
{
|
||||
sl_status_t status;
|
||||
int twt_req_type = siwx91x_convert_z_sl_twt_req_type(params->setup_cmd);
|
||||
|
||||
sl_wifi_twt_request_t twt_req = {
|
||||
.twt_retry_interval = 5,
|
||||
.wake_duration_unit = 0,
|
||||
.wake_int_mantissa = params->setup.twt_mantissa,
|
||||
.un_announced_twt = !params->setup.announce,
|
||||
.wake_duration = params->setup.twt_wake_interval,
|
||||
.triggered_twt = params->setup.trigger,
|
||||
.wake_int_exp = params->setup.twt_exponent,
|
||||
.implicit_twt = 1,
|
||||
.twt_flow_id = params->flow_id,
|
||||
.twt_enable = 1,
|
||||
.req_type = twt_req_type,
|
||||
};
|
||||
|
||||
if (twt_req_type < 0) {
|
||||
params->fail_reason = WIFI_TWT_FAIL_CMD_EXEC_FAIL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!params->setup.twt_info_disable) {
|
||||
params->fail_reason = WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (params->setup.responder) {
|
||||
params->fail_reason = WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* implicit -> won't do renegotiation
|
||||
* explicit -> must do renegotiation for each session
|
||||
*/
|
||||
if (!params->setup.implicit) {
|
||||
/* explicit twt is not supported */
|
||||
params->fail_reason = WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (params->setup.twt_wake_interval > 255 * 256) {
|
||||
twt_req.wake_duration_unit = 1;
|
||||
twt_req.wake_duration = params->setup.twt_wake_interval / 1024;
|
||||
} else {
|
||||
twt_req.wake_duration_unit = 0;
|
||||
twt_req.wake_duration = params->setup.twt_wake_interval / 256;
|
||||
}
|
||||
|
||||
status = sl_wifi_enable_target_wake_time(&twt_req);
|
||||
if (status != SL_STATUS_OK) {
|
||||
params->fail_reason = WIFI_TWT_FAIL_CMD_EXEC_FAIL;
|
||||
params->resp_status = WIFI_TWT_RESP_NOT_RECEIVED;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int siwx91x_set_twt_teardown(struct wifi_twt_params *params)
|
||||
{
|
||||
sl_status_t status;
|
||||
sl_wifi_twt_request_t twt_req = { };
|
||||
|
||||
twt_req.twt_enable = 0;
|
||||
|
||||
if (params->teardown.teardown_all) {
|
||||
twt_req.twt_flow_id = 0xFF;
|
||||
} else {
|
||||
twt_req.twt_flow_id = params->flow_id;
|
||||
}
|
||||
|
||||
status = sl_wifi_disable_target_wake_time(&twt_req);
|
||||
if (status != SL_STATUS_OK) {
|
||||
params->fail_reason = WIFI_TWT_FAIL_CMD_EXEC_FAIL;
|
||||
params->teardown_status = WIFI_TWT_TEARDOWN_FAILED;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
params->teardown_status = WIFI_TWT_TEARDOWN_SUCCESS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int siwx91x_set_twt(const struct device *dev, struct wifi_twt_params *params)
|
||||
{
|
||||
sl_wifi_interface_t interface = sl_wifi_get_default_interface();
|
||||
struct siwx91x_dev *sidev = dev->data;
|
||||
|
||||
__ASSERT(params, "params cannot be a NULL");
|
||||
|
||||
if (FIELD_GET(SIWX91X_INTERFACE_MASK, interface) != SL_WIFI_CLIENT_INTERFACE) {
|
||||
params->fail_reason = WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (sidev->state != WIFI_STATE_DISCONNECTED && sidev->state != WIFI_STATE_INACTIVE &&
|
||||
sidev->state != WIFI_STATE_COMPLETED) {
|
||||
LOG_ERR("Command given in invalid state");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (params->negotiation_type != WIFI_TWT_INDIVIDUAL) {
|
||||
params->fail_reason = WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (params->operation == WIFI_TWT_SETUP) {
|
||||
return siwx91x_set_twt_setup(params);
|
||||
} else if (params->operation == WIFI_TWT_TEARDOWN) {
|
||||
return siwx91x_set_twt_teardown(params);
|
||||
}
|
||||
params->fail_reason = WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
20
drivers/wifi/siwx91x/siwx91x_wifi_ps.h
Normal file
20
drivers/wifi/siwx91x/siwx91x_wifi_ps.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Silicon Laboratories Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef SIWX91X_WIFI_PS_H
|
||||
#define SIWX91X_WIFI_PS_H
|
||||
|
||||
struct device;
|
||||
struct siwx91x_dev;
|
||||
struct wifi_twt_params;
|
||||
struct wifi_ps_config;
|
||||
struct wifi_ps_params;
|
||||
|
||||
int siwx91x_set_twt(const struct device *dev, struct wifi_twt_params *params);
|
||||
int siwx91x_set_power_save(const struct device *dev, struct wifi_ps_params *params);
|
||||
int siwx91x_get_power_save_config(const struct device *dev, struct wifi_ps_config *config);
|
||||
|
||||
int siwx91x_apply_power_save(struct siwx91x_dev *sidev);
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user