diff --git a/firmware/libcommon/include/llist_irqsafe.h b/firmware/libcommon/include/llist_irqsafe.h index 8aafcfbd..e6c893a9 100644 --- a/firmware/libcommon/include/llist_irqsafe.h +++ b/firmware/libcommon/include/llist_irqsafe.h @@ -34,7 +34,7 @@ static inline void llist_add_tail_irqsafe(struct llist_head *_new, local_irq_save(x); llist_add_tail(_new, head); - __enable_irq(); + local_irq_restore(x); } static inline struct llist_head *llist_head_dequeue_irqsafe(struct llist_head *head) diff --git a/firmware/libcommon/source/card_emu.c b/firmware/libcommon/source/card_emu.c index 9c908502..a1d44837 100644 --- a/firmware/libcommon/source/card_emu.c +++ b/firmware/libcommon/source/card_emu.c @@ -219,19 +219,31 @@ struct card_handle { static void card_handle_reset(struct card_handle *ch) { struct msgb *msg; + unsigned long x; card_emu_uart_update_wt(ch->uart_chan, 0); - /* release any buffers we may still own */ - if (ch->uart_tx_msg) { - usb_buf_free(ch->uart_tx_msg); - ch->uart_tx_msg = NULL; - } + /* Release any buffers we may still own. + * uart_tx_msg + uart_tx_queue are shared with the UART IRQ handler, + * that preempts us here -> needs atomic detach and free */ + local_irq_save(x); + msg = ch->uart_tx_msg; + ch->uart_tx_msg = NULL; + local_irq_restore(x); + if (msg) + usb_buf_free(msg); + if (ch->uart_rx_msg) { usb_buf_free(ch->uart_rx_msg); ch->uart_rx_msg = NULL; } - while ((msg = msgb_dequeue(&ch->uart_tx_queue))) { + + while (1) { + local_irq_save(x); + msg = msgb_dequeue(&ch->uart_tx_queue); + local_irq_restore(x); + if (!msg) + break; usb_buf_free(msg); } } diff --git a/firmware/libcommon/source/mode_cardemu.c b/firmware/libcommon/source/mode_cardemu.c index 3a0808d9..6c1ac8d7 100644 --- a/firmware/libcommon/source/mode_cardemu.c +++ b/firmware/libcommon/source/mode_cardemu.c @@ -737,7 +737,8 @@ static void dispatch_usb_command_cardem(struct msgb *msg, struct cardem_inst *ci switch (hdr->msg_type) { case SIMTRACE_MSGT_DT_CEMU_TX_DATA: queue = card_emu_get_uart_tx_queue(ci->ch); - llist_add_tail(&msg->list, queue); + /* drained from the USART IRQ handler at highest NVIC prio */ + llist_add_tail_irqsafe(&msg->list, queue); card_emu_have_new_uart_tx(ci->ch); break; case SIMTRACE_MSGT_DT_CEMU_SET_ATR: