Skip to content

Commit adae168

Browse files
ArunmaniAlagarsamy2710kartben
authored andcommitted
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>
1 parent b939714 commit adae168

File tree

2 files changed

+140
-0
lines changed

2 files changed

+140
-0
lines changed

drivers/wifi/siwx91x/siwx91x_wifi.c

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,139 @@ static enum wifi_mfp_options siwx91x_set_sta_mfp_option(sl_wifi_security_t secur
253253
return WIFI_MFP_UNKNOWN;
254254
}
255255

256+
static int siwx91x_get_connected_ap_beacon_interval_ms(void)
257+
{
258+
sl_wifi_operational_statistics_t sl_stat;
259+
sl_wifi_interface_t interface;
260+
int status;
261+
262+
interface = sl_wifi_get_default_interface();
263+
if (FIELD_GET(SIWX91X_INTERFACE_MASK, interface) != SL_WIFI_CLIENT_INTERFACE) {
264+
return 0;
265+
}
266+
267+
status = sl_wifi_get_operational_statistics(SL_WIFI_CLIENT_INTERFACE, &sl_stat);
268+
if (status) {
269+
return 0;
270+
}
271+
272+
return sys_get_le16(sl_stat.beacon_interval) * 1024 / 1000;
273+
}
274+
275+
static int siwx91x_apply_power_save(struct siwx91x_dev *sidev)
276+
{
277+
sl_wifi_performance_profile_t sl_ps_profile;
278+
sl_wifi_interface_t interface;
279+
int beacon_interval;
280+
int status;
281+
282+
interface = sl_wifi_get_default_interface();
283+
if (FIELD_GET(SIWX91X_INTERFACE_MASK, interface) != SL_WIFI_CLIENT_INTERFACE) {
284+
return 0;
285+
}
286+
287+
if (sidev->state == WIFI_STATE_INTERFACE_DISABLED) {
288+
return 0;
289+
}
290+
291+
sl_wifi_get_performance_profile(&sl_ps_profile);
292+
293+
if (sidev->ps_params.enabled == WIFI_PS_DISABLED) {
294+
sl_ps_profile.profile = HIGH_PERFORMANCE;
295+
goto out;
296+
}
297+
if (sidev->ps_params.exit_strategy == WIFI_PS_EXIT_EVERY_TIM) {
298+
sl_ps_profile.profile = ASSOCIATED_POWER_SAVE_LOW_LATENCY;
299+
} else if (sidev->ps_params.exit_strategy == WIFI_PS_EXIT_CUSTOM_ALGO) {
300+
sl_ps_profile.profile = ASSOCIATED_POWER_SAVE;
301+
} else {
302+
/* Already sanitized by siwx91x_set_power_save() */
303+
return -EINVAL;
304+
}
305+
306+
sl_ps_profile.monitor_interval = sidev->ps_params.timeout_ms;
307+
308+
beacon_interval = siwx91x_get_connected_ap_beacon_interval_ms();
309+
/* 1000ms is arbitrary sane value */
310+
sl_ps_profile.listen_interval = MIN(beacon_interval * sidev->ps_params.listen_interval,
311+
1000);
312+
313+
if (sidev->ps_params.wakeup_mode == WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL &&
314+
!sidev->ps_params.listen_interval) {
315+
LOG_INF("Disabling listen interval based wakeup until connection establishes");
316+
}
317+
if (sidev->ps_params.wakeup_mode == WIFI_PS_WAKEUP_MODE_DTIM ||
318+
!sidev->ps_params.listen_interval) {
319+
sl_ps_profile.dtim_aligned_type = 1;
320+
} else if (sidev->ps_params.wakeup_mode == WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL) {
321+
sl_ps_profile.dtim_aligned_type = 0;
322+
} else {
323+
/* Already sanitized by siwx91x_set_power_save() */
324+
return -EINVAL;
325+
}
326+
327+
out:
328+
status = sl_wifi_set_performance_profile(&sl_ps_profile);
329+
return status ? -EIO : 0;
330+
}
331+
332+
static int siwx91x_set_power_save(const struct device *dev, struct wifi_ps_params *params)
333+
{
334+
struct siwx91x_dev *sidev = dev->data;
335+
int status;
336+
337+
__ASSERT(params, "params cannot be NULL");
338+
339+
switch (params->type) {
340+
case WIFI_PS_PARAM_STATE:
341+
sidev->ps_params.enabled = params->enabled;
342+
break;
343+
case WIFI_PS_PARAM_MODE:
344+
if (params->mode != WIFI_PS_MODE_LEGACY) {
345+
params->fail_reason = WIFI_PS_PARAM_FAIL_OPERATION_NOT_SUPPORTED;
346+
return -ENOTSUP;
347+
}
348+
break;
349+
case WIFI_PS_PARAM_LISTEN_INTERVAL:
350+
sidev->ps_params.listen_interval = params->listen_interval;
351+
break;
352+
case WIFI_PS_PARAM_WAKEUP_MODE:
353+
if (params->wakeup_mode != WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL &&
354+
params->wakeup_mode != WIFI_PS_WAKEUP_MODE_DTIM) {
355+
params->fail_reason = WIFI_PS_PARAM_FAIL_OPERATION_NOT_SUPPORTED;
356+
return -ENOTSUP;
357+
}
358+
sidev->ps_params.wakeup_mode = params->wakeup_mode;
359+
break;
360+
case WIFI_PS_PARAM_TIMEOUT:
361+
/* 1000ms is arbitrary sane value */
362+
if (params->timeout_ms < SLI_DEFAULT_MONITOR_INTERVAL ||
363+
params->timeout_ms > 1000) {
364+
params->fail_reason = WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL;
365+
return -EINVAL;
366+
}
367+
sidev->ps_params.timeout_ms = params->timeout_ms;
368+
break;
369+
case WIFI_PS_PARAM_EXIT_STRATEGY:
370+
if (params->exit_strategy != WIFI_PS_EXIT_EVERY_TIM &&
371+
params->exit_strategy != WIFI_PS_EXIT_CUSTOM_ALGO) {
372+
params->fail_reason = WIFI_PS_PARAM_FAIL_OPERATION_NOT_SUPPORTED;
373+
return -ENOTSUP;
374+
}
375+
sidev->ps_params.exit_strategy = params->exit_strategy;
376+
break;
377+
default:
378+
params->fail_reason = WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL;
379+
return -EINVAL;
380+
}
381+
status = siwx91x_apply_power_save(sidev);
382+
if (status) {
383+
params->fail_reason = WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL;
384+
return status;
385+
}
386+
return 0;
387+
}
388+
256389
static unsigned int siwx91x_on_join(sl_wifi_event_t event,
257390
char *result, uint32_t result_size, void *arg)
258391
{
@@ -275,6 +408,8 @@ static unsigned int siwx91x_on_join(sl_wifi_event_t event,
275408
siwx91x_on_join_ipv4(sidev);
276409
siwx91x_on_join_ipv6(sidev);
277410

411+
siwx91x_apply_power_save(sidev);
412+
278413
return 0;
279414
}
280415

@@ -1439,6 +1574,7 @@ static const struct wifi_mgmt_ops siwx91x_mgmt = {
14391574
.get_stats = siwx91x_stats,
14401575
#endif
14411576
.get_version = siwx91x_get_version,
1577+
.set_power_save = siwx91x_set_power_save,
14421578
};
14431579

14441580
static const struct net_wifi_mgmt_offload siwx91x_api = {
@@ -1452,6 +1588,9 @@ static const struct net_wifi_mgmt_offload siwx91x_api = {
14521588
};
14531589

14541590
static struct siwx91x_dev sidev = {
1591+
.ps_params.enabled = WIFI_PS_DISABLED,
1592+
.ps_params.exit_strategy = WIFI_PS_EXIT_EVERY_TIM,
1593+
.ps_params.wakeup_mode = WIFI_PS_WAKEUP_MODE_DTIM,
14551594
.max_num_sta = CONFIG_WIFI_MGMT_AP_MAX_NUM_STA,
14561595
};
14571596

drivers/wifi/siwx91x/siwx91x_wifi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ struct siwx91x_dev {
2121
enum wifi_iface_state scan_prev_state;
2222
scan_result_cb_t scan_res_cb;
2323
uint16_t scan_max_bss_cnt;
24+
struct wifi_ps_params ps_params;
2425
uint8_t max_num_sta;
2526
bool reboot_needed;
2627
bool hidden_ssid;

0 commit comments

Comments
 (0)