Merge branch 'bugfix/phy_regi2c_critical_section_v4.4' into 'release/v4.4'

esp_phy: use spinlock to avoid regi2c access conflicts (v4.4)

See merge request espressif/esp-idf!17691
This commit is contained in:
Michael (XIAO Xufeng) 2022-04-07 19:23:51 +08:00
commit b436132f9f
9 changed files with 104 additions and 43 deletions

View File

@ -52,6 +52,10 @@ uint8_t regi2c_ctrl_read_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_ad
void regi2c_ctrl_write_reg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data);
void regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data);
/* enter the critical section that protects internal registers. Don't use it in SDK. Use the functions above. */
void regi2c_enter_critical(void);
void regi2c_exit_critical(void);
#endif // BOOTLOADER_BUILD
/* Convenience macros for the above functions, these use register definitions

View File

@ -65,6 +65,10 @@ uint8_t regi2c_ctrl_read_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_ad
void regi2c_ctrl_write_reg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data);
void regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data);
/* enter the critical section that protects internal registers. Don't use it in SDK. Use the functions above. */
void regi2c_enter_critical(void);
void regi2c_exit_critical(void);
#endif // BOOTLOADER_BUILD
/* Convenience macros for the above functions, these use register definitions

View File

@ -79,6 +79,10 @@ uint8_t regi2c_ctrl_read_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_ad
void regi2c_ctrl_write_reg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data);
void regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data);
/* enter the critical section that protects internal registers. Don't use it in SDK. Use the functions above. */
void regi2c_enter_critical(void);
void regi2c_exit_critical(void);
#endif // BOOTLOADER_BUILD
/* Convenience macros for the above functions, these use register definitions

View File

@ -60,6 +60,10 @@ uint8_t regi2c_ctrl_read_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_ad
void regi2c_ctrl_write_reg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data);
void regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data);
/* enter the critical section that protects internal registers. Don't use it in SDK. Use the functions above. */
void regi2c_enter_critical(void);
void regi2c_exit_critical(void);
#endif // BOOTLOADER_BUILD
/* Convenience macros for the above functions, these use register definitions

View File

@ -63,6 +63,10 @@ uint8_t regi2c_ctrl_read_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_ad
void regi2c_ctrl_write_reg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data);
void regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data);
/* enter the critical section that protects internal registers. Don't use it in SDK. Use the functions above. */
void regi2c_enter_critical(void);
void regi2c_exit_critical(void);
#endif // BOOTLOADER_BUILD
/* Convenience macros for the above functions, these use register definitions

View File

@ -14,32 +14,42 @@ static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
uint8_t IRAM_ATTR regi2c_ctrl_read_reg(uint8_t block, uint8_t host_id, uint8_t reg_add)
{
portENTER_CRITICAL_ISR(&mux);
portENTER_CRITICAL_SAFE(&mux);
uint8_t value = i2c_read_reg_raw(block, host_id, reg_add);
portEXIT_CRITICAL_ISR(&mux);
portEXIT_CRITICAL_SAFE(&mux);
return value;
}
uint8_t IRAM_ATTR regi2c_ctrl_read_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb)
{
portENTER_CRITICAL_ISR(&mux);
portENTER_CRITICAL_SAFE(&mux);
uint8_t value = i2c_read_reg_mask_raw(block, host_id, reg_add, msb, lsb);
portEXIT_CRITICAL_ISR(&mux);
portEXIT_CRITICAL_SAFE(&mux);
return value;
}
void IRAM_ATTR regi2c_ctrl_write_reg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data)
{
portENTER_CRITICAL_ISR(&mux);
portENTER_CRITICAL_SAFE(&mux);
i2c_write_reg_raw(block, host_id, reg_add, data);
portEXIT_CRITICAL_ISR(&mux);
portEXIT_CRITICAL_SAFE(&mux);
}
void IRAM_ATTR regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data)
{
portENTER_CRITICAL_ISR(&mux);
portENTER_CRITICAL_SAFE(&mux);
i2c_write_reg_mask_raw(block, host_id, reg_add, msb, lsb, data);
portEXIT_CRITICAL_ISR(&mux);
portEXIT_CRITICAL_SAFE(&mux);
}
void IRAM_ATTR regi2c_enter_critical(void)
{
portENTER_CRITICAL_SAFE(&mux);
}
void IRAM_ATTR regi2c_exit_critical(void)
{
portEXIT_CRITICAL_SAFE(&mux);
}
/**

View File

@ -1,5 +1,7 @@
idf_build_get_property(idf_target IDF_TARGET)
set(srcs "src/phy_override.c" "src/lib_printf.c")
if(CONFIG_ESP32_NO_BLOBS OR CONFIG_ESP32S2_NO_BLOBS)
set(link_binary_libs 0)
set(ldfragments)
@ -9,11 +11,10 @@ else()
endif()
if(IDF_TARGET STREQUAL "esp32h2")
set(srcs "src/phy_init_esp32hxx.c")
list(APPEND srcs "src/phy_init_esp32hxx.c")
else()
set(srcs "src/phy_init.c")
list(APPEND srcs "src/phy_init.c")
endif()
list(APPEND srcs "src/lib_printf.c")
idf_build_get_property(build_dir BUILD_DIR)
@ -24,23 +25,23 @@ if(CONFIG_ESP_PHY_MULTIPLE_INIT_DATA_BIN)
endif()
if(CONFIG_ESP_PHY_MULTIPLE_INIT_DATA_BIN_EMBED)
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include" "${idf_target}/include"
PRIV_REQUIRES nvs_flash
LDFRAGMENTS "${ldfragments}"
EMBED_FILES "${build_dir}/phy_multiple_init_data.bin"
)
else()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include" "${idf_target}/include"
PRIV_REQUIRES nvs_flash
LDFRAGMENTS "${ldfragments}"
)
set(embed_files "${build_dir}/phy_multiple_init_data.bin")
endif()
# [refactor-todo]: requires "driver" component for adc_power_acquire/release()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include" "${idf_target}/include"
PRIV_REQUIRES nvs_flash driver
LDFRAGMENTS "${ldfragments}"
EMBED_FILES ${embed_files}
)
set(target_name "${idf_target}")
target_link_libraries(${COMPONENT_LIB} PUBLIC "-L \"${CMAKE_CURRENT_SOURCE_DIR}/lib/${target_name}\"")
# Override functions in PHY lib with the functions in 'phy_override.c'
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u include_esp_phy_override")
if(link_binary_libs)
target_link_libraries(${COMPONENT_LIB} PUBLIC phy)

View File

@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include "regi2c_ctrl.h"
#include "driver/adc.h"
/*
* This file is used to override the hooks provided by the PHY lib for some system features.
* Call phy_override() so that this file will be linked.
*/
static bool s_wifi_adc_xpd_flag;
void include_esp_phy_override(void)
{
/* When this empty function is called, all functions below will be linked. */
}
/* Coordinate ADC power with other modules. */
// It seems that it is only required on ESP32, but we still compile it for all chips, in case it is
// called by PHY unexpectedly.
void set_xpd_sar(bool en)
{
if (s_wifi_adc_xpd_flag == en) {
/* ignore repeated calls to set_xpd_sar when the state is already correct */
return;
}
s_wifi_adc_xpd_flag = en;
if (en) {
adc_power_acquire();
} else {
adc_power_release();
}
}
//add spinlock protection
void phy_i2c_enter_critical(void)
{
regi2c_enter_critical();
}
void phy_i2c_exit_critical(void)
{
regi2c_exit_critical();
}

View File

@ -15,7 +15,6 @@
#include "esp_wpa.h"
#include "esp_netif.h"
#include "tcpip_adapter_compatible/tcpip_adapter_compat.h"
#include "driver/adc.h"
#include "driver/adc2_wifi_private.h"
#include "esp_coexist_internal.h"
#include "esp_phy_init.h"
@ -57,7 +56,6 @@ uint64_t g_wifi_feature_caps =
#endif
0;
static bool s_wifi_adc_xpd_flag;
static const char* TAG = "wifi_init";
@ -288,24 +286,6 @@ void wifi_apb80m_release(void)
}
#endif //CONFIG_PM_ENABLE
/* Coordinate ADC power with other modules. This overrides the function from PHY lib. */
// It seems that it is only required on ESP32, but we still compile it for all chips, in case it is
// called by PHY unexpectedly.
void set_xpd_sar(bool en)
{
if (s_wifi_adc_xpd_flag == en) {
/* ignore repeated calls to set_xpd_sar when the state is already correct */
return;
}
s_wifi_adc_xpd_flag = en;
if (en) {
adc_power_acquire();
} else {
adc_power_release();
}
}
#ifndef CONFIG_ESP_WIFI_FTM_ENABLE
void ieee80211_ftm_attach(void)
{