mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
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:
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user