Skip to content

Commit c23af30

Browse files
andreasmuellerrettichschnidi
authored andcommitted
[sg noup] net: ppp: simple flow control for interrupt based UART
This is required for the lb_radio_gateway, so that we can create back-pressure towards Linux if we get too much data. Issue: SG-21138 (cherry picked from commit 040ad4d)
1 parent c052fb7 commit c23af30

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

drivers/net/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ config NET_PPP_RINGBUF_SIZE
5050
PPP ring buffer size when passing data from RX ISR to worker
5151
thread that will pass the data to IP stack.
5252

53+
config NET_PPP_RINGBUF_MIN_SPACE
54+
int "Minimum space in RX ring buffer before enabling flow-control"
55+
default 50
56+
help
57+
Minimum number of free bytes in RX ring buffer. If remaning space reaches this limit, UART
58+
flow-control is enabled.
59+
5360
config NET_PPP_RX_STACK_SIZE
5461
int "Size of the stack allocated for receiving data from modem"
5562
default 768

drivers/net/ppp.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ LOG_MODULE_REGISTER(net_ppp, LOG_LEVEL);
2929
#include <zephyr/net/net_core.h>
3030
#include <zephyr/sys/ring_buffer.h>
3131
#include <zephyr/sys/crc.h>
32+
#include <zephyr/drivers/gpio.h>
3233
#include <zephyr/drivers/uart.h>
3334
#include <zephyr/drivers/console/uart_mux.h>
3435
#include <zephyr/random/random.h>
@@ -50,6 +51,8 @@ BUILD_ASSERT(UART_YIELD_INTERVAL_BYTES * 8 * 1000 /
5051
"current UART k_yield() interval & speed leads to blocking time > 5 ms");
5152
#endif
5253

54+
#define RX_RINGBUF_MIN_SPACE CONFIG_NET_PPP_RINGBUF_MIN_SPACE
55+
5356
enum ppp_driver_state {
5457
STATE_HDLC_FRAME_START,
5558
STATE_HDLC_FRAME_ADDRESS,
@@ -59,6 +62,33 @@ enum ppp_driver_state {
5962
#define PPP_WORKQ_PRIORITY CONFIG_NET_PPP_RX_PRIORITY
6063
#define PPP_WORKQ_STACK_SIZE CONFIG_NET_PPP_RX_STACK_SIZE
6164

65+
#define UART_RTS_NODE DT_ALIAS(ppp_uart_rts)
66+
67+
/*
68+
* Note regarding synchronization: this variable is written both from a thread and an interrupt,
69+
* however since the interrupt only writes the variable when the ring buffer is (mostly) full and
70+
* the thread only when the ring buffer is empty, there is no issue in reality (there might be an
71+
* issue in case of the dongle, which uses USB CDC ACM instead of UART though).
72+
*/
73+
static bool uart_ready_for_data = true;
74+
75+
static void flow_control_set_rts(const struct device *uart, const bool ready_for_data) {
76+
if (uart_ready_for_data == ready_for_data) {
77+
return;
78+
}
79+
uart_ready_for_data = ready_for_data;
80+
81+
#ifdef CONFIG_UART_LINE_CTRL
82+
uart_line_ctrl_set(uart, UART_LINE_CTRL_RTS, ready_for_data ? 1 : 0);
83+
#else /* CONFIG_UART_LINE_CTRL */
84+
if (ready_for_data) {
85+
uart_irq_rx_enable(uart);
86+
} else {
87+
uart_irq_rx_disable(uart);
88+
}
89+
#endif /* CONFIG_UART_LINE_CTRL */
90+
}
91+
6292
K_KERNEL_STACK_DEFINE(ppp_workq, PPP_WORKQ_STACK_SIZE);
6393

6494
struct ppp_driver_context {
@@ -888,6 +918,11 @@ static int ppp_consume_ringbuf(struct ppp_driver_context *ppp)
888918
LOG_DBG("Cannot flush ring buffer (%d)", ret);
889919
}
890920

921+
if (ring_buf_is_empty(&ppp->rx_ringbuf)) {
922+
LOG_DBG("ringbuf empty, enabling UART");
923+
flow_control_set_rts(ppp->dev, true);
924+
}
925+
891926
return -EAGAIN;
892927
}
893928

@@ -1029,6 +1064,11 @@ static void ppp_uart_isr(const struct device *uart, void *user_data)
10291064
break;
10301065
}
10311066

1067+
if (ring_buf_space_get(&context->rx_ringbuf) < RX_RINGBUF_MIN_SPACE) {
1068+
LOG_DBG("ringbuf almost full, disabling UART");
1069+
flow_control_set_rts(uart, false);
1070+
}
1071+
10321072
k_work_submit_to_queue(&context->cb_workq, &context->cb_work);
10331073
}
10341074
}

0 commit comments

Comments
 (0)