From 27486c540795a548db96dcbf69932edbfd9f35f8 Mon Sep 17 00:00:00 2001 From: Chew Zeh Yang Date: Fri, 27 Sep 2024 17:25:30 +0800 Subject: [PATCH] usbd: device_next: cdc: wait IN EP ready before enqueue data to EP Under the current structure of usbd_cdc_acm, there is a possibility that TX data is enqueued to UDC driver before the previous transaction is completed, hence causing the dropped data. This commit adds a mechanism for usbd_cdc_acm driver to wait for IN endpoint to complete existing transaction before allows the subsequent transaction to be enqueued. Signed-off-by: Chew Zeh Yang usbd: device_next: cdc: fix possible CPU hogging issue As pointed out by tmon-nordic, the method to re-queue CDC tx transaction has possible issue of CPU hogging that could start system workqueue and lower priority thread. Instead of keep requeing the tx_fifo work, simply raise altered flag. The pending TX transaction will be triggered when TX transfer completion interrupt is raised. Signed-off-by: Chew Zeh Yang --- subsys/usb/device_next/class/usbd_cdc_acm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/subsys/usb/device_next/class/usbd_cdc_acm.c b/subsys/usb/device_next/class/usbd_cdc_acm.c index eb0abb803cee3d1..f17f12b13479edb 100644 --- a/subsys/usb/device_next/class/usbd_cdc_acm.c +++ b/subsys/usb/device_next/class/usbd_cdc_acm.c @@ -48,6 +48,7 @@ UDC_BUF_POOL_DEFINE(cdc_acm_ep_pool, #define CDC_ACM_IRQ_TX_ENABLED 3 #define CDC_ACM_RX_FIFO_BUSY 4 #define CDC_ACM_LOCK 5 +#define CDC_ACM_TX_EP_BUSY 6 static struct k_work_q cdc_acm_work_q; static K_KERNEL_STACK_DEFINE(cdc_acm_stack, @@ -215,6 +216,8 @@ static int usbd_cdc_acm_request(struct usbd_class_data *const c_data, if (bi->ep == cdc_acm_get_bulk_out(c_data)) { atomic_clear_bit(&data->state, CDC_ACM_RX_FIFO_BUSY); + } else if (bi->ep == cdc_acm_get_bulk_in(c_data)) { + atomic_clear_bit(&data->state, CDC_ACM_TX_EP_BUSY); } goto ep_request_error; @@ -236,6 +239,7 @@ static int usbd_cdc_acm_request(struct usbd_class_data *const c_data, if (bi->ep == cdc_acm_get_bulk_in(c_data)) { /* TX transfer completion */ + atomic_clear_bit(&data->state, CDC_ACM_TX_EP_BUSY); if (data->cb) { cdc_acm_work_submit(&data->irq_cb_work); } @@ -540,6 +544,11 @@ static void cdc_acm_tx_fifo_handler(struct k_work *work) return; } + if (atomic_test_and_set_bit(&data->state, CDC_ACM_TX_EP_BUSY)) { + data->tx_fifo.altered = true; + goto tx_fifo_handler_exit; + } + buf = cdc_acm_buf_alloc(cdc_acm_get_bulk_in(c_data)); if (buf == NULL) { cdc_acm_work_submit(&data->tx_fifo_work);