Merge branch 'fix/fix_coverity_issues' into 'master'

fix(esp_hw_support): fix coverity issues in esp_hw_support

Closes IDF-13819, IDF-13892, and IDF-13894

See merge request espressif/esp-idf!42566
This commit is contained in:
Wu Zheng Hui
2025-10-17 16:53:49 +08:00
3 changed files with 64 additions and 33 deletions
+13 -2
View File
@@ -579,9 +579,20 @@ uint64_t esp_sleep_get_gpio_wakeup_status(void);
#endif //SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
/**
* @brief Set power down mode for an RTC power domain in sleep mode
* @brief Configure power domain options for sleep mode
*
* If not set set using this API, all power domains default to ESP_PD_OPTION_AUTO.
* This function provides power domain management for sleep mode, allowing users
* to control which power domains remain active during sleep to maintain required
* functionality. The function supports:
* - Automatic power management (ESP_PD_OPTION_AUTO): Power domains are controlled
* automatically based on system requirements and other peripheral usage.
* - Manual power control (ESP_PD_OPTION_ON/ESP_PD_OPTION_OFF): User can force
* specific power domains to stay on or off during sleep.
*
* The management strategy uses reference counting when in manual mode, allowing
* multiple subsystems to request and release power domain resources safely without
* interfering with each other. Power domains will only change state when all
* users have released their requirements.
*
* @param domain power domain to configure
* @param option power down option (ESP_PD_OPTION_OFF, ESP_PD_OPTION_ON, or ESP_PD_OPTION_AUTO)
+30 -28
View File
@@ -605,37 +605,39 @@ static void regdma_link_update_branch_write_wait_next_wrapper(void *link, regdma
void regdma_link_update_next(void *link, int nentry, ...)
{
if (!link) {
return;
}
va_list args;
va_start(args, nentry);
if (link) {
regdma_entry_buf_t next;
memset(next, 0, sizeof(regdma_entry_buf_t));
for (int i = 0; i < nentry && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
next[i] = va_arg(args, void *);
}
regdma_entry_buf_t next;
memset(next, 0, sizeof(regdma_entry_buf_t));
for (int i = 0; i < nentry && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
next[i] = va_arg(args, void *);
}
regdma_link_head_t head = REGDMA_LINK_HEAD(link);
if (head.branch) {
typedef void (*update_branch_fn_t)(void *, regdma_entry_buf_t *);
static const update_branch_fn_t updatefn_b[] = {
[0] = regdma_link_update_branch_continuous_next_wrapper,
[1] = regdma_link_update_branch_addr_map_next_wrapper,
[2] = regdma_link_update_branch_write_wait_next_wrapper,
[3] = regdma_link_update_branch_write_wait_next_wrapper
};
assert((head.mode < ARRAY_SIZE(updatefn_b)));
(*updatefn_b[head.mode])(link, &next);
} else {
typedef void (*update_fn_t)(void *, void *);
static const update_fn_t updatefn[] = {
[0] = regdma_link_update_continuous_next_wrapper,
[1] = regdma_link_update_addr_map_next_wrapper,
[2] = regdma_link_update_write_wait_next_wrapper,
[3] = regdma_link_update_write_wait_next_wrapper
};
assert((head.mode < ARRAY_SIZE(updatefn)));
(*updatefn[head.mode])(link, next[0]);
}
regdma_link_head_t head = REGDMA_LINK_HEAD(link);
if (head.branch) {
typedef void (*update_branch_fn_t)(void *, regdma_entry_buf_t *);
static const update_branch_fn_t updatefn_b[] = {
[0] = regdma_link_update_branch_continuous_next_wrapper,
[1] = regdma_link_update_branch_addr_map_next_wrapper,
[2] = regdma_link_update_branch_write_wait_next_wrapper,
[3] = regdma_link_update_branch_write_wait_next_wrapper
};
assert((head.mode < ARRAY_SIZE(updatefn_b)));
(*updatefn_b[head.mode])(link, &next);
} else {
typedef void (*update_fn_t)(void *, void *);
static const update_fn_t updatefn[] = {
[0] = regdma_link_update_continuous_next_wrapper,
[1] = regdma_link_update_addr_map_next_wrapper,
[2] = regdma_link_update_write_wait_next_wrapper,
[3] = regdma_link_update_write_wait_next_wrapper
};
assert((head.mode < ARRAY_SIZE(updatefn)));
(*updatefn[head.mode])(link, next[0]);
}
va_end(args);
}
+21 -3
View File
@@ -2452,19 +2452,37 @@ esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain, esp_sleep_pd_option_
esp_os_enter_critical_safe(&s_config.lock);
int refs = 0;
if (s_config.domain[domain].pd_option == ESP_PD_OPTION_AUTO) {
// If domain is currently in auto mode, transition to the new mode directly
// - If option is ESP_PD_OPTION_ON: set refs to 1
// - If option is ESP_PD_OPTION_OFF: set refs to 0
// - If option is ESP_PD_OPTION_AUTO: no change in refs
s_config.domain[domain].refs = (option == ESP_PD_OPTION_ON) ? 1 : 0;
s_config.domain[domain].pd_option = option;
} else {
if (option == ESP_PD_OPTION_AUTO) {
// If switching from manual to auto mode, reset references and return to auto management
s_config.domain[domain].refs = 0;
s_config.domain[domain].pd_option = option;
} else {
refs = (option == ESP_PD_OPTION_ON) ? s_config.domain[domain].refs++ \
: (option == ESP_PD_OPTION_OFF) ? --s_config.domain[domain].refs \
: s_config.domain[domain].refs;
// Manual mode operations (ESP_PD_OPTION_ON/ESP_PD_OPTION_OFF)
// The reference counting implements the following state machine:
// - ON operations increment references, only update pd_option when refs transitions from 0 to 1
// - OFF operations decrement references, only update pd_option when refs transitions from 1 to 0
// - This provides symmetric reference counting for resource management
if (option == ESP_PD_OPTION_ON) {
// Get refs value after incrementing: this ensures pd_option is updated when transitioning
// from 0->1 (first request) but not on subsequent increments
refs = s_config.domain[domain].refs++;
} else if (option == ESP_PD_OPTION_OFF) {
// Get refs value after decrementing: this ensures pd_option is updated when transitioning
// from 1->0 (last release) but not on intermediate decrements
refs = --s_config.domain[domain].refs;
}
if (refs == 0) {
// Only update pd_option when reference count reaches 0, indicating all users have released
s_config.domain[domain].pd_option = option;
} else if (refs < 0) {
// Error case: reference count went negative, which indicates unbalanced ON/OFF calls
s_config.domain[domain].refs = 0;
err = ESP_ERR_INVALID_STATE;
}