From 7491ac024dd9d728032f018f6577488e59cf3431 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Mon, 31 Jan 2022 15:53:44 +0100 Subject: [PATCH] nimble/transport/cmac: Flush UART on CMAC error When CMAC is used with HCI bridge over UART we should wait for all data to be flushed from UART before asserting on error, otherwise we will lose debug events. --- .../include/cmac_driver/cmac_shared.h | 1 + .../dialog_cmac/cmac_driver/src/cmac_host.c | 49 +++++++++++++++++++ .../dialog_cmac/cmac_driver/src/cmac_mbox.c | 12 +++++ 3 files changed, 62 insertions(+) diff --git a/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_shared.h b/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_shared.h index 4e37bb8b8..da3a3cf61 100644 --- a/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_shared.h +++ b/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_shared.h @@ -142,6 +142,7 @@ typedef int (cmac_mbox_read_cb)(const void *data, uint16_t len); typedef void (cmac_mbox_write_notif_cb)(void); void cmac_mbox_set_read_cb(cmac_mbox_read_cb *cb); void cmac_mbox_set_write_notif_cb(cmac_mbox_write_notif_cb *cb); +int cmac_mbox_has_data(void); int cmac_mbox_read(void); int cmac_mbox_write(const void *data, uint16_t len); diff --git a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_host.c b/nimble/transport/dialog_cmac/cmac_driver/src/cmac_host.c index df81c582b..965db1398 100644 --- a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_host.c +++ b/nimble/transport/dialog_cmac/cmac_driver/src/cmac_host.c @@ -65,6 +65,13 @@ static struct os_event g_cmac_host_rand_ev = { static void cmac_host_rand_chk_fill(void); +#if MYNEWT_VAL(BLE_HCI_BRIDGE) && MYNEWT_VAL_CHOICE(BLE_HCI_TRANSPORT, uart) +static void cmac_host_error_w4flush(struct os_event *ev); +static struct os_event g_cmac_host_error_ev = { + .ev_cb = cmac_host_error_w4flush +}; +#endif + static void cmac2sys_isr(void) { @@ -105,6 +112,14 @@ cmac2sys_isr(void) for (;;); } #endif + +#if MYNEWT_VAL(BLE_HCI_BRIDGE) && MYNEWT_VAL_CHOICE(BLE_HCI_TRANSPORT, uart) + NVIC_DisableIRQ(CMAC2SYS_IRQn); + /* Wait until UART is flushed and then assert */ + cmac_host_error_w4flush(NULL); + return; +#endif + /* XXX CMAC is in error state, need to recover */ assert(0); return; @@ -147,6 +162,40 @@ cmac_host_rand_chk_fill(void) } } +#if MYNEWT_VAL(BLE_HCI_BRIDGE) && MYNEWT_VAL_CHOICE(BLE_HCI_TRANSPORT, uart) +#if MYNEWT_VAL(BLE_HCI_UART_PORT) < 0 || MYNEWT_VAL(BLE_HCI_UART_PORT) > 2 +#error Invalid BLE_HCI_UART_PORT +#endif +static void +cmac_host_error_w4flush(struct os_event *ev) +{ + static UART_Type * const regs[] = { + (void *)UART, + (void *)UART2, + (void *)UART3 + }; + + if (!ev) { + /* Move to task context, we do not want to spin in interrupt */ + os_eventq_put(os_eventq_dflt_get(), &g_cmac_host_error_ev); + return; + } + + do { + cmac_mbox_read(); + while ((regs[MYNEWT_VAL(BLE_HCI_UART_PORT)]->UART_LSR_REG & + UART_UART_LSR_REG_UART_TEMT_Msk) == 0) { + /* Wait until both FIFO and shift registers are empty */ + } + } while (cmac_mbox_has_data()); + + /* Reset CMAC */ + CRG_TOP->CLK_RADIO_REG |= CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Msk; + + assert(0); +} +#endif + void cmac_host_signal2cmac(void) { diff --git a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_mbox.c b/nimble/transport/dialog_cmac/cmac_driver/src/cmac_mbox.c index 88764c4df..36f4e25e1 100644 --- a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_mbox.c +++ b/nimble/transport/dialog_cmac/cmac_driver/src/cmac_mbox.c @@ -46,6 +46,18 @@ cmac_mbox_set_write_notif_cb(cmac_mbox_write_notif_cb *cb) g_cmac_mbox_write_notif_cb = cb; } +int +cmac_mbox_has_data(void) +{ +#if MYNEWT_VAL(BLE_HOST) || MYNEWT_VAL(BLE_HCI_BRIDGE) + volatile struct cmac_mbox *mbox = &g_cmac_shared_data->mbox_c2s; +#else + volatile struct cmac_mbox *mbox = &g_cmac_shared_data.mbox_s2c; +#endif + + return mbox->rd_off != mbox->wr_off; +} + int cmac_mbox_read(void) {