Refactor Bluetooth init/deinit mechanism

free osi_funcs struct memory duiring failure of controller_init when necessary

components/bt: use s_lp_stat.phy_enabled to control the on/off of phy module

clean up style for controller_disable

clean up some empty functions and unnecessary comments

Added async wakeup src "BTDM_ASYNC_WAKEUP_SRC_TMR"

remove use of assert in controller_init, set error code upon some exceptions

move stop esp_timer early to phase0, add state variable wakeup_timer_started
This commit is contained in:
wangmengyang
2020-12-26 23:44:23 +08:00
committed by baohongde
parent 06ea8a3028
commit ee480b7776

View File

@@ -65,6 +65,7 @@
enum { enum {
BTDM_ASYNC_WAKEUP_SRC_VHCI = 0, BTDM_ASYNC_WAKEUP_SRC_VHCI = 0,
BTDM_ASYNC_WAKEUP_SRC_DISA, BTDM_ASYNC_WAKEUP_SRC_DISA,
BTDM_ASYNC_WAKEUP_SRC_TMR,
BTDM_ASYNC_WAKEUP_SRC_MAX, BTDM_ASYNC_WAKEUP_SRC_MAX,
}; };
@@ -86,7 +87,9 @@ typedef union {
struct { struct {
uint32_t pm_lock_released : 1; // whether power management lock is released uint32_t pm_lock_released : 1; // whether power management lock is released
uint32_t mac_bb_pd : 1; // whether hardware(MAC, BB) is powered down uint32_t mac_bb_pd : 1; // whether hardware(MAC, BB) is powered down
uint32_t reserved : 30; // reserved uint32_t phy_enabled : 1; // whether phy is switched on
uint32_t wakeup_timer_started : 1; // whether wakeup timer is started
uint32_t reserved : 28; // reserved
}; };
uint32_t val; uint32_t val;
} btdm_lpstat_t; } btdm_lpstat_t;
@@ -95,8 +98,6 @@ typedef union {
#define BTDM_MIN_SLEEP_DURATION (24) // threshold of interval in half slots to allow to fall into modem sleep #define BTDM_MIN_SLEEP_DURATION (24) // threshold of interval in half slots to allow to fall into modem sleep
#define BTDM_MODEM_WAKE_UP_DELAY (8) // delay in half slots of modem wake up procedure, including re-enable PHY/RF #define BTDM_MODEM_WAKE_UP_DELAY (8) // delay in half slots of modem wake up procedure, including re-enable PHY/RF
#define BTDM_MODEM_SLEEP_IN_EFFECT (1)
#define BT_DEBUG(...) #define BT_DEBUG(...)
#define BT_API_CALL_CHECK(info, api_call, ret) \ #define BT_API_CALL_CHECK(info, api_call, ret) \
do{\ do{\
@@ -316,6 +317,8 @@ static void interrupt_off_wrapper(int intr_num);
static void btdm_hw_mac_power_up_wrapper(void); static void btdm_hw_mac_power_up_wrapper(void);
static void btdm_hw_mac_power_down_wrapper(void); static void btdm_hw_mac_power_down_wrapper(void);
static void btdm_backup_dma_copy_wrapper(uint32_t reg, uint32_t mem_addr, uint32_t num, bool to_mem); static void btdm_backup_dma_copy_wrapper(uint32_t reg, uint32_t mem_addr, uint32_t num, bool to_mem);
static void btdm_slp_tmr_callback(void *arg);
/* Local variable definition /* Local variable definition
*************************************************************************** ***************************************************************************
*/ */
@@ -364,15 +367,10 @@ static const struct osi_funcs_t osi_funcs_ro = {
._btdm_sleep_exit_phase1 = NULL, ._btdm_sleep_exit_phase1 = NULL,
._btdm_sleep_exit_phase2 = NULL, ._btdm_sleep_exit_phase2 = NULL,
._btdm_sleep_exit_phase3 = btdm_sleep_exit_phase3_wrapper, ._btdm_sleep_exit_phase3 = btdm_sleep_exit_phase3_wrapper,
//._coex_bt_request = coex_bt_request_wrapper,
._coex_wifi_sleep_set = coex_wifi_sleep_set_hook, ._coex_wifi_sleep_set = coex_wifi_sleep_set_hook,
._coex_core_ble_conn_dyn_prio_get = coex_core_ble_conn_dyn_prio_get, ._coex_core_ble_conn_dyn_prio_get = coex_core_ble_conn_dyn_prio_get,
._coex_schm_status_bit_set = coex_schm_status_bit_set_wrapper, ._coex_schm_status_bit_set = coex_schm_status_bit_set_wrapper,
._coex_schm_status_bit_clear = coex_schm_status_bit_clear_wrapper, ._coex_schm_status_bit_clear = coex_schm_status_bit_clear_wrapper,
//._coex_bt_release = coex_bt_release_wrapper,
// ._coex_register_bt_cb = coex_register_bt_cb_wrapper,
// ._coex_bb_reset_lock = coex_bb_reset_lock_wrapper,
//._coex_bb_reset_unlock = coex_bb_reset_unlock_wrapper,
._interrupt_on = interrupt_on_wrapper, ._interrupt_on = interrupt_on_wrapper,
._interrupt_off = interrupt_off_wrapper, ._interrupt_off = interrupt_off_wrapper,
._esp_hw_power_down = btdm_hw_mac_power_down_wrapper, ._esp_hw_power_down = btdm_hw_mac_power_down_wrapper,
@@ -383,37 +381,28 @@ static const struct osi_funcs_t osi_funcs_ro = {
static DRAM_ATTR struct osi_funcs_t *osi_funcs_p; static DRAM_ATTR struct osi_funcs_t *osi_funcs_p;
/* Static variable declare */ /* Static variable declare */
// timestamp when PHY/RF was switched on
// static DRAM_ATTR int64_t s_time_phy_rf_just_enabled = 0;
static DRAM_ATTR esp_bt_controller_status_t btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; static DRAM_ATTR esp_bt_controller_status_t btdm_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE;
static DRAM_ATTR portMUX_TYPE global_int_mux = portMUX_INITIALIZER_UNLOCKED; static DRAM_ATTR portMUX_TYPE global_int_mux = portMUX_INITIALIZER_UNLOCKED;
// measured average low power clock period in micro seconds
static DRAM_ATTR uint32_t btdm_lpcycle_us = 0;
static DRAM_ATTR uint8_t btdm_lpcycle_us_frac = 0; // number of fractional bit for btdm_lpcycle_us
// low power control struct // low power control struct
static DRAM_ATTR btdm_lpcntl_t s_lp_cntl; static DRAM_ATTR btdm_lpcntl_t s_lp_cntl;
// low power status struct
static DRAM_ATTR btdm_lpstat_t s_lp_stat; static DRAM_ATTR btdm_lpstat_t s_lp_stat;
// measured average low power clock period in micro seconds
#ifdef CONFIG_PM_ENABLE static DRAM_ATTR uint32_t btdm_lpcycle_us = 0;
static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock; // number of fractional bit for btdm_lpcycle_us
static DRAM_ATTR esp_pm_lock_handle_t s_light_sleep_pm_lock; // pm_lock to prevent light sleep due to incompatibility currently static DRAM_ATTR uint8_t btdm_lpcycle_us_frac = 0;
#endif // semaphore used for blocking VHCI API to wait for controller to wake up
// used low power clock
static DRAM_ATTR QueueHandle_t s_wakeup_req_sem = NULL; static DRAM_ATTR QueueHandle_t s_wakeup_req_sem = NULL;
// wakeup timer // wakeup timer
static DRAM_ATTR esp_timer_handle_t s_btdm_slp_tmr; static DRAM_ATTR esp_timer_handle_t s_btdm_slp_tmr;
static void btdm_slp_tmr_callback(void *arg); #ifdef CONFIG_PM_ENABLE
static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock;
static inline void btdm_check_and_init_bb(void) // pm_lock to prevent light sleep due to incompatibility currently
{ static DRAM_ATTR esp_pm_lock_handle_t s_light_sleep_pm_lock;
// todo: #endif
// btdm_rf_bb_init_phase2();
}
void btdm_hw_mac_power_down_wrapper(void) void btdm_hw_mac_power_down_wrapper(void)
{ {
@@ -609,7 +598,7 @@ static void *malloc_internal_wrapper(size_t size)
static int IRAM_ATTR read_mac_wrapper(uint8_t mac[6]) static int IRAM_ATTR read_mac_wrapper(uint8_t mac[6])
{ {
int ret = esp_read_mac(mac, ESP_MAC_BT); int ret = esp_read_mac(mac, ESP_MAC_BT);
ESP_LOGI(BTDM_LOG_TAG, "Bluetooth MAC: 0x%02x:%02x:%02x:%02x:%02x:%02x\n", ESP_LOGI(BTDM_LOG_TAG, "Bluetooth MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return ret; return ret;
@@ -680,17 +669,24 @@ static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles)
uncertainty = BTDM_MIN_TIMER_UNCERTAINTY_US; uncertainty = BTDM_MIN_TIMER_UNCERTAINTY_US;
} }
if (esp_timer_start_once(s_btdm_slp_tmr, us_to_sleep - uncertainty) != ESP_OK) { assert (s_lp_stat.wakeup_timer_started == 0);
ESP_LOGW(BTDM_LOG_TAG, "timer start failed"); if (esp_timer_start_once(s_btdm_slp_tmr, us_to_sleep - uncertainty) == ESP_OK) {
s_lp_stat.wakeup_timer_started = 1;
} else {
ESP_LOGE(BTDM_LOG_TAG, "timer start failed");
assert(0);
} }
} }
static void btdm_sleep_enter_phase2_wrapper(void) static void btdm_sleep_enter_phase2_wrapper(void)
{ {
if (btdm_controller_get_sleep_mode() == ESP_BT_SLEEP_MODE_1) { if (btdm_controller_get_sleep_mode() == ESP_BT_SLEEP_MODE_1) {
#if BTDM_MODEM_SLEEP_IN_EFFECT if (s_lp_stat.phy_enabled) {
esp_phy_disable(); esp_phy_disable();
#endif /* BTDM_MODEM_SLEEP_IN_EFFECT */ s_lp_stat.phy_enabled = 0;
} else {
assert(0);
}
if (s_lp_cntl.mac_bb_pd && s_lp_stat.mac_bb_pd == 0) { if (s_lp_cntl.mac_bb_pd && s_lp_stat.mac_bb_pd == 0) {
#if (CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB) #if (CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
@@ -715,13 +711,9 @@ static void btdm_sleep_exit_phase3_wrapper(void)
assert(0); assert(0);
} }
if (btdm_controller_get_sleep_mode() == ESP_BT_SLEEP_MODE_1) { if (btdm_controller_get_sleep_mode() == ESP_BT_SLEEP_MODE_1) {
#if BTDM_MODEM_SLEEP_IN_EFFECT if (s_lp_stat.phy_enabled == 0) {
esp_phy_enable(); esp_phy_enable();
#endif /* BTDM_MODEM_SLEEP_IN_EFFECT */ s_lp_stat.phy_enabled = 1;
btdm_check_and_init_bb();
if (s_lp_cntl.wakeup_timer_required) {
esp_timer_stop(s_btdm_slp_tmr);
} }
} }
} }
@@ -745,6 +737,10 @@ static void IRAM_ATTR btdm_sleep_exit_phase0(void *param)
#endif #endif
btdm_wakeup_request(); btdm_wakeup_request();
if (s_lp_cntl.wakeup_timer_required && s_lp_stat.wakeup_timer_started) {
esp_timer_stop(s_btdm_slp_tmr);
s_lp_stat.wakeup_timer_started = 0;
}
int event = (int) param; int event = (int) param;
if (event == BTDM_ASYNC_WAKEUP_SRC_VHCI || event == BTDM_ASYNC_WAKEUP_SRC_DISA) { if (event == BTDM_ASYNC_WAKEUP_SRC_VHCI || event == BTDM_ASYNC_WAKEUP_SRC_DISA) {
semphr_give_wrapper(s_wakeup_req_sem); semphr_give_wrapper(s_wakeup_req_sem);
@@ -754,8 +750,12 @@ static void IRAM_ATTR btdm_sleep_exit_phase0(void *param)
static void IRAM_ATTR btdm_slp_tmr_callback(void *arg) static void IRAM_ATTR btdm_slp_tmr_callback(void *arg)
{ {
#if (defined CONFIG_PM_ENABLE) || (defined CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB) #if (defined CONFIG_PM_ENABLE) || (defined CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
btdm_vnd_offload_post_from_isr(BTDM_VND_OL_SIG_WAKEUP_TMR, NULL, false); #ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
btdm_vnd_offload_post_from_isr(BTDM_VND_OL_SIG_WAKEUP_TMR, (void *)BTDM_ASYNC_WAKEUP_SRC_TMR, false);
esp_timer_isr_dispatch_need_yield(); esp_timer_isr_dispatch_need_yield();
#else
btdm_vnd_offload_post(BTDM_VND_OL_SIG_WAKEUP_TMR, (void *)BTDM_ASYNC_WAKEUP_SRC_TMR);
#endif
#endif #endif
} }
@@ -901,7 +901,7 @@ esp_err_t esp_bluetooth_stop(void)
esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
{ {
esp_err_t err; esp_err_t err = ESP_FAIL;
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) {
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
@@ -936,7 +936,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
} }
} }
//overwrite some parameters // overwrite some parameters
cfg->magic = ESP_BT_CTRL_CONFIG_MAGIC_VAL; cfg->magic = ESP_BT_CTRL_CONFIG_MAGIC_VAL;
btdm_controller_mem_init(); btdm_controller_mem_init();
@@ -974,6 +974,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
if (s_lp_cntl.enable) { if (s_lp_cntl.enable) {
#if (CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB) #if (CONFIG_PM_POWER_DOWN_WIFI_BT_MAC_BB)
if (!btdm_deep_sleep_mem_init()) { if (!btdm_deep_sleep_mem_init()) {
err = ESP_ERR_NO_MEM;
goto error; goto error;
} }
s_lp_cntl.mac_bb_pd = 1; s_lp_cntl.mac_bb_pd = 1;
@@ -991,10 +992,17 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
} }
if (s_lp_cntl.wakeup_timer_required) { if (s_lp_cntl.wakeup_timer_required) {
#ifndef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
ESP_LOGE(BTDM_LOG_TAG, "ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is required");
err = ESP_ERR_NOT_SUPPORTED;
goto error;
#endif
esp_timer_create_args_t create_args = { esp_timer_create_args_t create_args = {
.callback = btdm_slp_tmr_callback, .callback = btdm_slp_tmr_callback,
.arg = NULL, .arg = NULL,
#ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
.dispatch_method = ESP_TIMER_ISR, .dispatch_method = ESP_TIMER_ISR,
#endif
.name = "btSlp", .name = "btSlp",
}; };
if ((err = esp_timer_create(&create_args, &s_btdm_slp_tmr)) != ESP_OK) { if ((err = esp_timer_create(&create_args, &s_btdm_slp_tmr)) != ESP_OK) {
@@ -1018,16 +1026,19 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac); btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
} else { } else {
ESP_LOGW(BTDM_LOG_TAG, "%s sleep clock not supported", __func__); ESP_LOGW(BTDM_LOG_TAG, "%s sleep clock not supported", __func__);
assert(0); err = ESP_ERR_NOT_SUPPORTED;
goto error;
} }
#ifdef CONFIG_PM_ENABLE #ifdef CONFIG_PM_ENABLE
if (s_lp_cntl.no_light_sleep) { if (s_lp_cntl.no_light_sleep) {
if ((err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "btLS", &s_light_sleep_pm_lock)) != ESP_OK) { if ((err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "btLS", &s_light_sleep_pm_lock)) != ESP_OK) {
err = ESP_ERR_NO_MEM;
goto error; goto error;
} }
} }
if ((err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "bt", &s_pm_lock)) != ESP_OK) { if ((err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "bt", &s_pm_lock)) != ESP_OK) {
err = ESP_ERR_NO_MEM;
goto error; goto error;
} else { } else {
s_lp_stat.pm_lock_released = 1; s_lp_stat.pm_lock_released = 1;
@@ -1046,6 +1057,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
#endif #endif
esp_phy_enable(); esp_phy_enable();
s_lp_stat.phy_enabled = 1;
if (btdm_controller_init(cfg) != 0) { if (btdm_controller_init(cfg) != 0) {
err = ESP_ERR_NO_MEM; err = ESP_ERR_NO_MEM;
@@ -1057,6 +1069,11 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
return ESP_OK; return ESP_OK;
error: error:
if (s_lp_stat.phy_enabled) {
esp_phy_disable();
s_lp_stat.phy_enabled = 0;
}
do { do {
// deinit low power control resources // deinit low power control resources
#ifdef CONFIG_PM_ENABLE #ifdef CONFIG_PM_ENABLE
@@ -1094,6 +1111,11 @@ error:
} while (0); } while (0);
esp_unregister_shutdown_handler((shutdown_handler_t)esp_bluetooth_stop); esp_unregister_shutdown_handler((shutdown_handler_t)esp_bluetooth_stop);
if (osi_funcs_p != NULL) {
free(osi_funcs_p);
osi_funcs_p = NULL;
}
return err; return err;
} }
@@ -1106,7 +1128,12 @@ esp_err_t esp_bt_controller_deinit(void)
btdm_controller_deinit(); btdm_controller_deinit();
periph_module_disable(PERIPH_BT_MODULE); periph_module_disable(PERIPH_BT_MODULE);
esp_phy_disable(); if (s_lp_stat.phy_enabled) {
esp_phy_disable();
s_lp_stat.phy_enabled = 0;
} else {
assert(0);
}
// deinit low power control resources // deinit low power control resources
do { do {
@@ -1127,7 +1154,10 @@ esp_err_t esp_bt_controller_deinit(void)
s_lp_stat.pm_lock_released = 0; s_lp_stat.pm_lock_released = 0;
#endif #endif
if (s_lp_cntl.wakeup_timer_required) { if (s_lp_cntl.wakeup_timer_required) {
esp_timer_stop(s_btdm_slp_tmr); if (s_lp_stat.wakeup_timer_started) {
esp_timer_stop(s_btdm_slp_tmr);
}
s_lp_stat.wakeup_timer_started = 0;
esp_timer_delete(s_btdm_slp_tmr); esp_timer_delete(s_btdm_slp_tmr);
s_btdm_slp_tmr = NULL; s_btdm_slp_tmr = NULL;
} }
@@ -1152,7 +1182,7 @@ esp_err_t esp_bt_controller_deinit(void)
esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode)
{ {
int ret; int ret = ESP_OK;
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) { if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_INITED) {
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
@@ -1174,39 +1204,40 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode)
if (s_lp_cntl.no_light_sleep) { if (s_lp_cntl.no_light_sleep) {
esp_pm_lock_acquire(s_light_sleep_pm_lock); esp_pm_lock_acquire(s_light_sleep_pm_lock);
} }
esp_pm_lock_acquire(s_pm_lock); esp_pm_lock_acquire(s_pm_lock);
s_lp_stat.pm_lock_released = 0; s_lp_stat.pm_lock_released = 0;
#endif #endif
if (btdm_controller_get_sleep_mode() == ESP_BT_SLEEP_MODE_1) { if (s_lp_cntl.enable) {
btdm_controller_enable_sleep(true); btdm_controller_enable_sleep(true);
} }
} while (0); } while (0);
// inititalize bluetooth baseband if (btdm_controller_enable(mode) != 0) {
btdm_check_and_init_bb(); ret = ESP_ERR_INVALID_STATE;
ret = btdm_controller_enable(mode); goto error;
if (ret) {
// disable low power mode
do {
btdm_controller_enable_sleep(false);
#ifdef CONFIG_PM_ENABLE
if (s_lp_cntl.no_light_sleep) {
esp_pm_lock_release(s_light_sleep_pm_lock);
}
if (s_lp_stat.pm_lock_released == 0) {
esp_pm_lock_release(s_pm_lock);
s_lp_stat.pm_lock_released = 1;
}
#endif
} while (0);
return ESP_ERR_INVALID_STATE;
} }
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_ENABLED; btdm_controller_status = ESP_BT_CONTROLLER_STATUS_ENABLED;
return ESP_OK; return ret;
error:
// disable low power mode
do {
btdm_controller_enable_sleep(false);
#ifdef CONFIG_PM_ENABLE
if (s_lp_cntl.no_light_sleep) {
esp_pm_lock_release(s_light_sleep_pm_lock);
}
if (s_lp_stat.pm_lock_released == 0) {
esp_pm_lock_release(s_pm_lock);
s_lp_stat.pm_lock_released = 1;
}
#endif
} while (0);
return ret;
} }
esp_err_t esp_bt_controller_disable(void) esp_err_t esp_bt_controller_disable(void)
@@ -1225,7 +1256,6 @@ esp_err_t esp_bt_controller_disable(void)
coex_disable(); coex_disable();
#endif #endif
// esp_phy_disable();
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
// disable low power mode // disable low power mode