@@ -253,6 +253,139 @@ static enum wifi_mfp_options siwx91x_set_sta_mfp_option(sl_wifi_security_t secur
253
253
return WIFI_MFP_UNKNOWN ;
254
254
}
255
255
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
+
256
389
static unsigned int siwx91x_on_join (sl_wifi_event_t event ,
257
390
char * result , uint32_t result_size , void * arg )
258
391
{
@@ -275,6 +408,8 @@ static unsigned int siwx91x_on_join(sl_wifi_event_t event,
275
408
siwx91x_on_join_ipv4 (sidev );
276
409
siwx91x_on_join_ipv6 (sidev );
277
410
411
+ siwx91x_apply_power_save (sidev );
412
+
278
413
return 0 ;
279
414
}
280
415
@@ -1439,6 +1574,7 @@ static const struct wifi_mgmt_ops siwx91x_mgmt = {
1439
1574
.get_stats = siwx91x_stats ,
1440
1575
#endif
1441
1576
.get_version = siwx91x_get_version ,
1577
+ .set_power_save = siwx91x_set_power_save ,
1442
1578
};
1443
1579
1444
1580
static const struct net_wifi_mgmt_offload siwx91x_api = {
@@ -1452,6 +1588,9 @@ static const struct net_wifi_mgmt_offload siwx91x_api = {
1452
1588
};
1453
1589
1454
1590
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 ,
1455
1594
.max_num_sta = CONFIG_WIFI_MGMT_AP_MAX_NUM_STA ,
1456
1595
};
1457
1596
0 commit comments