From aa56e1af2ea617a8a91e1d8becd7144ddc162145 Mon Sep 17 00:00:00 2001 From: Li Shuai Date: Fri, 20 Mar 2026 10:51:20 +0800 Subject: [PATCH] feat(esp_hw_support): support sleep retention module runtime attach and detach --- .../include/esp_private/sleep_retention.h | 3 + components/esp_hw_support/sleep_retention.c | 140 ++++++++++++++++++ 2 files changed, 143 insertions(+) diff --git a/components/esp_hw_support/include/esp_private/sleep_retention.h b/components/esp_hw_support/include/esp_private/sleep_retention.h index 00387b19dae..0e8ba7418e2 100644 --- a/components/esp_hw_support/include/esp_private/sleep_retention.h +++ b/components/esp_hw_support/include/esp_private/sleep_retention.h @@ -161,6 +161,9 @@ esp_err_t sleep_retention_module_allocate(sleep_retention_module_t module); */ esp_err_t sleep_retention_module_free(sleep_retention_module_t module); +esp_err_t sleep_retention_module_attach(sleep_retention_module_t module); +esp_err_t sleep_retention_module_detach(sleep_retention_module_t module); + /** * @brief Force take the power lock so that during sleep the power domain won't be powered off. * diff --git a/components/esp_hw_support/sleep_retention.c b/components/esp_hw_support/sleep_retention.c index 3bcfc7c4094..b5b69cd328e 100644 --- a/components/esp_hw_support/sleep_retention.c +++ b/components/esp_hw_support/sleep_retention.c @@ -387,6 +387,16 @@ void sleep_retention_dump_entries(FILE *out) regdma_link_dump(out, s_retention.retention.lists[s_retention.highpri].entries[entry], entry); } } + for (int n = 0; n < ARRAY_SIZE(s_retention.context); n++) { + for (regdma_link_priority_t priority = 0; priority < SLEEP_RETENTION_REGDMA_LINK_NR_PRIORITIES; priority++) { + for (int e = 0; e < ARRAY_SIZE(s_retention.context[0].lists[priority].entries); e++) { + fprintf(out, "\nsleep retention context[%d] priority %d entries[%d] context:\n", n, priority, e); + void *head = s_retention.context[n].lists[priority].entries[e]; + void *tail = s_retention.context[n].lists[priority].entries_tail; + regdma_link_dump_sublink(out, head, tail, e); + } + } + } fflush(out); _lock_release_recursive(&s_retention.lock); } @@ -505,6 +515,23 @@ static bool entries_detach(struct module_sleep_retention_context *ctx, regdma_li return (is_head || is_tail); } +static void entries_attach(struct module_sleep_retention_context *ctx, regdma_link_priority_t priority, sleep_retention_entries_t *entries, void *tail) +{ + _lock_acquire_recursive(&s_retention.lock); + regdma_link_update_next_safe(tail, ctx->lists[priority].entries[0], ctx->lists[priority].entries[1], + ctx->lists[priority].entries[2], ctx->lists[priority].entries[3] +#if (REGDMA_LINK_ENTRY_NUM == 5) + , ctx->lists[priority].entries[4] +#endif + ); + memcpy(ctx->lists[priority].entries, entries, sizeof(sleep_retention_entries_t)); + if (ctx->lists[priority].entries_tail == NULL) { + ctx->lists[priority].entries_tail = tail; + } + entries_context_refresh(ctx, priority); + _lock_release_recursive(&s_retention.lock); +} + static void module_entries_destroy(sleep_retention_entries_t *entries) { for (int entry = 0; entry < ARRAY_SIZE(*entries); entry++) { @@ -1008,6 +1035,119 @@ esp_err_t sleep_retention_module_free(sleep_retention_module_t module) return err; } +static void module_entries_move(sleep_retention_module_t module, struct module_sleep_retention_context *s, struct module_sleep_retention_context *d) +{ + void *tail = NULL, *prev_tail = NULL; + sleep_retention_entries_t entries, next_entries; + regdma_link_priority_t priority = 0; + + memset(&entries, 0, sizeof(sleep_retention_entries_t)); + memset(&next_entries, 0, sizeof(sleep_retention_entries_t)); + + _lock_acquire_recursive(&s_retention.lock); + do { + bool exist = module_entries_get(s, priority, module, &entries, &tail, &next_entries, &prev_tail); + if (exist) { + entries_detach(s, priority, &entries, tail, &next_entries, prev_tail); + entries_attach(d, priority, &entries, tail); + } else { + priority++; + } + retention_entries_join(); + } while (priority < SLEEP_RETENTION_REGDMA_LINK_NR_PRIORITIES); + _lock_release_recursive(&s_retention.lock); +} + +static esp_err_t passive_module_attach(sleep_retention_module_t module) +{ + assert(module >= SLEEP_RETENTION_MODULE_MIN && module <= SLEEP_RETENTION_MODULE_MAX); + + esp_err_t err = ESP_OK; + _lock_acquire_recursive(&s_retention.lock); + assert(module_is_passive(instance(module)) && "Illegal dependency"); + assert(module_runtime_attach(instance(module)) && "Illegal dependency"); + assert(module_is_inited(module) && "All passive module must be inited first!"); + if (module_is_inited(module) && module_is_created(module) && !module_is_retained(module)) { + module_entries_move(module, &s_retention.context[1], &s_retention.retention); + s_retention.retention_modules.bitmap[module >> 5] |= BIT(module % 32); + err = module_action_wrapper(module, (BIT(31) | action(0)), passive_module_attach); + } + _lock_release_recursive(&s_retention.lock); + return err; +} + +esp_err_t sleep_retention_module_attach(sleep_retention_module_t module) +{ + if (module < SLEEP_RETENTION_MODULE_MIN || module > SLEEP_RETENTION_MODULE_MAX) { + return ESP_ERR_INVALID_ARG; + } + + esp_err_t err = ESP_OK; + _lock_acquire_recursive(&s_retention.lock); + if (!module_is_passive(instance(module))) { + if (module_is_inited(module) && module_is_created(module) && !module_is_retained(module)) { + if (module_runtime_attach(instance(module))) { + module_entries_move(module, &s_retention.context[1], &s_retention.retention); + s_retention.retention_modules.bitmap[module >> 5] |= BIT(module % 32); + err = module_action_wrapper(module, action(0), passive_module_attach); + } else { + err = ESP_ERR_NOT_SUPPORTED; + } + } else { + err = ESP_ERR_INVALID_STATE; + } + } else { + err = ESP_ERR_NOT_ALLOWED; + } + _lock_release_recursive(&s_retention.lock); + return err; +} + +static esp_err_t passive_module_detach(sleep_retention_module_t module) +{ + assert(module >= SLEEP_RETENTION_MODULE_MIN && module <= SLEEP_RETENTION_MODULE_MAX); + + esp_err_t err = ESP_OK; + _lock_acquire_recursive(&s_retention.lock); + assert(module_is_passive(instance(module)) && "Illegal dependency"); + assert(module_runtime_attach(instance(module)) && "Illegal dependency"); + assert(module_is_inited(module) && "All passive module must be inited first!"); + if (module_is_inited(module) && module_is_created(module) && module_is_retained(module)) { + module_entries_move(module, &s_retention.retention, &s_retention.context[1]); + s_retention.retention_modules.bitmap[module >> 5] &= ~BIT(module % 32); + err = module_action_wrapper(module, (BIT(31) | action(0)), passive_module_detach); + } + _lock_release_recursive(&s_retention.lock); + return err; +} + +esp_err_t sleep_retention_module_detach(sleep_retention_module_t module) +{ + if (module < SLEEP_RETENTION_MODULE_MIN || module > SLEEP_RETENTION_MODULE_MAX) { + return ESP_ERR_INVALID_ARG; + } + + esp_err_t err = ESP_OK; + _lock_acquire_recursive(&s_retention.lock); + if (!module_is_passive(instance(module))) { + if (module_is_inited(module) && module_is_created(module) && module_is_retained(module)) { + if (module_runtime_attach(instance(module))) { + module_entries_move(module, &s_retention.retention, &s_retention.context[1]); + s_retention.retention_modules.bitmap[module >> 5] &= ~BIT(module % 32); + err = module_action_wrapper(module, action(0), passive_module_detach); + } else { + err = ESP_ERR_NOT_SUPPORTED; + } + } else { + err = ESP_ERR_INVALID_STATE; + } + } else { + err = ESP_ERR_NOT_ALLOWED; + } + _lock_release_recursive(&s_retention.lock); + return err; +} + static esp_err_t empty_create(void *args) { return ESP_OK;