Skip to content

Commit

Permalink
usb: device_next: use delayable work for TX FIFO in CDC ACM
Browse files Browse the repository at this point in the history
Use delayable work to reduce CPU load when there is no transfer flow in
the host direction. This also improves the performance of poll out, as
introduced in commit commit fed6bde
("usb: device: cdc_acm: send more than 1 byte in poll out")
for the legacy CDC ACM implementation.

Signed-off-by: Johann Fischer <[email protected]>
  • Loading branch information
jfischer-no committed Oct 2, 2024
1 parent 3304357 commit 87d3827
Showing 1 changed file with 18 additions and 7 deletions.
25 changes: 18 additions & 7 deletions subsys/usb/device_next/class/usbd_cdc_acm.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ struct cdc_acm_uart_data {
*/
bool flow_ctrl;
/* USBD CDC ACM TX fifo work */
struct k_work tx_fifo_work;
struct k_work_delayable tx_fifo_work;
/* USBD CDC ACM RX fifo work */
struct k_work rx_fifo_work;
atomic_t state;
Expand Down Expand Up @@ -140,6 +140,12 @@ static ALWAYS_INLINE int cdc_acm_work_submit(struct k_work *work)
return k_work_submit_to_queue(&cdc_acm_work_q, work);
}

static ALWAYS_INLINE int cdc_acm_work_schedule(struct k_work_delayable *work,
k_timeout_t delay)
{

Check notice on line 145 in subsys/usb/device_next/class/usbd_cdc_acm.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

subsys/usb/device_next/class/usbd_cdc_acm.c:145 -static ALWAYS_INLINE int cdc_acm_work_schedule(struct k_work_delayable *work, - k_timeout_t delay) +static ALWAYS_INLINE int cdc_acm_work_schedule(struct k_work_delayable *work, k_timeout_t delay)
return k_work_schedule_for_queue(&cdc_acm_work_q, work, delay);
}

static ALWAYS_INLINE bool check_wq_ctx(const struct device *dev)
{
return k_current_get() == k_work_queue_thread_get(&cdc_acm_work_q);
Expand Down Expand Up @@ -277,7 +283,7 @@ static void usbd_cdc_acm_enable(struct usbd_class_data *const c_data)
cdc_acm_work_submit(&data->irq_cb_work);
} else {
/* Queue pending TX data on IN endpoint */
cdc_acm_work_submit(&data->tx_fifo_work);
cdc_acm_work_schedule(&data->tx_fifo_work, K_NO_WAIT);
}
}
}
Expand Down Expand Up @@ -520,13 +526,14 @@ static int cdc_acm_send_notification(const struct device *dev,
*/
static void cdc_acm_tx_fifo_handler(struct k_work *work)
{
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
struct cdc_acm_uart_data *data;
struct usbd_class_data *c_data;
struct net_buf *buf;
size_t len;
int ret;

data = CONTAINER_OF(work, struct cdc_acm_uart_data, tx_fifo_work);
data = CONTAINER_OF(dwork, struct cdc_acm_uart_data, tx_fifo_work);
c_data = data->c_data;

if (!atomic_test_bit(&data->state, CDC_ACM_CLASS_ENABLED)) {
Expand All @@ -541,7 +548,7 @@ static void cdc_acm_tx_fifo_handler(struct k_work *work)

buf = cdc_acm_buf_alloc(cdc_acm_get_bulk_in(c_data));
if (buf == NULL) {
cdc_acm_work_submit(&data->tx_fifo_work);
cdc_acm_work_schedule(&data->tx_fifo_work, K_MSEC(1));
return;
}

Expand Down Expand Up @@ -819,7 +826,7 @@ static void cdc_acm_irq_cb_handler(struct k_work *work)

if (data->tx_fifo.altered) {
LOG_DBG("tx fifo altered, submit work");
cdc_acm_work_submit(&data->tx_fifo_work);
cdc_acm_work_schedule(&data->tx_fifo_work, K_NO_WAIT);
}

if (atomic_test_bit(&data->state, CDC_ACM_IRQ_RX_ENABLED) &&
Expand Down Expand Up @@ -887,7 +894,11 @@ static void cdc_acm_poll_out(const struct device *dev, const unsigned char c)
k_msleep(1);
}

cdc_acm_work_submit(&data->tx_fifo_work);
/* Schedule with minimal timeout to make it possible to send more than
* one byte per USB transfer. The latency increase is negligible while
* the increased throughput and reduced CPU usage is easily observable.
*/
cdc_acm_work_schedule(&data->tx_fifo_work, K_MSEC(1));
}

#ifdef CONFIG_UART_LINE_CTRL
Expand Down Expand Up @@ -1006,7 +1017,7 @@ static int usbd_cdc_acm_preinit(const struct device *dev)

k_thread_name_set(&cdc_acm_work_q.thread, "cdc_acm_work_q");

k_work_init(&data->tx_fifo_work, cdc_acm_tx_fifo_handler);
k_work_init_delayable(&data->tx_fifo_work, cdc_acm_tx_fifo_handler);
k_work_init(&data->rx_fifo_work, cdc_acm_rx_fifo_handler);
k_work_init(&data->irq_cb_work, cdc_acm_irq_cb_handler);

Expand Down

0 comments on commit 87d3827

Please sign in to comment.