From 05eb9644dca49490d3e7b7afbe407a6787a4d8cf Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 28 Sep 2020 21:57:41 +0200 Subject: [PATCH] modem: iface_uart: improve RX flow with HW flow control So far all received bytes over UART where blindly drained and pushed to ring_buf. This approach is okay for UART devices without configured HW flow control, as it basically decouples data processing from ISR handler and gives more time before data overrun. However when HW flow control is enabled, such behavior somehow suppresses UART flow control advantage, because data can overrun when pushing to ring_buf. Allow drivers utilizing modem_context framework to pass information about whether HW flow control is enabled or not. If it is enabled, then read data from UART FIFO to the point when RX ring_buf is totally filled and follow such situation by disabling RX interrupt. Incoming data will be paused on HW level, so there is lots of time for RX thread to process ring_buf content. Reenable RX interrupts after all data in ring_buf is processed, so that number of context switches is kept at minimum level. Signed-off-by: Marcin Niestroj --- drivers/modem/modem_iface_uart.c | 12 ++++++++++-- drivers/modem/modem_iface_uart.h | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/modem/modem_iface_uart.c b/drivers/modem/modem_iface_uart.c index 0bed06e56f2..8139ee4d7ae 100644 --- a/drivers/modem/modem_iface_uart.c +++ b/drivers/modem/modem_iface_uart.c @@ -74,8 +74,12 @@ static void modem_iface_uart_isr(const struct device *uart_dev, UINT32_MAX); } if (!partial_size) { - LOG_ERR("Rx buffer doesn't have enough space"); - modem_iface_uart_flush(&ctx->iface); + if (data->hw_flow_control) { + uart_irq_rx_disable(ctx->iface.dev); + } else { + LOG_ERR("Rx buffer doesn't have enough space"); + modem_iface_uart_flush(&ctx->iface); + } break; } @@ -114,6 +118,10 @@ static int modem_iface_uart_read(struct modem_iface *iface, data = (struct modem_iface_uart_data *)(iface->iface_data); *bytes_read = ring_buf_get(&data->rx_rb, buf, size); + if (data->hw_flow_control && *bytes_read == 0) { + uart_irq_rx_enable(iface->dev); + } + return 0; } diff --git a/drivers/modem/modem_iface_uart.h b/drivers/modem/modem_iface_uart.h index 98ef8665fbb..63c472c2bdd 100644 --- a/drivers/modem/modem_iface_uart.h +++ b/drivers/modem/modem_iface_uart.h @@ -20,6 +20,9 @@ extern "C" { #endif struct modem_iface_uart_data { + /* HW flow control */ + bool hw_flow_control; + /* ring buffer char buffer */ char *rx_rb_buf; size_t rx_rb_buf_len;