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.
This commit is contained in:
Andrzej Kaczmarek
2022-02-03 11:27:02 +01:00
parent b8c1d516d9
commit 7491ac024d
3 changed files with 62 additions and 0 deletions
@@ -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);
@@ -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)
{
@@ -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)
{