Skip to content

Commit 8425a1a

Browse files
MarkusLassilabjarki-andreasen
authored andcommitted
[nrf fromtree] modem: backend: uart: Add hw-flow-control for UART
Add Asynchronous UART implementation, which does not drop data when automatic hardware-flow-control is set in the device tree. With automatic hardware flow control, the CTS pin will be automatically deactivated when there are no more asynchronous UART RX buffers available. After buffer space becomes available, and UART RX is restarted, the CTS pin will be activated. Signed-off-by: Markus Lassila <[email protected]> (cherry picked from commit 10bd2de)
1 parent f669de3 commit 8425a1a

File tree

9 files changed

+544
-46
lines changed

9 files changed

+544
-46
lines changed

include/zephyr/modem/backend/uart.h

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,42 @@ struct modem_backend_uart_isr {
3030
uint32_t transmit_buf_put_limit;
3131
};
3232

33+
struct modem_backend_uart_async_common {
34+
uint8_t *transmit_buf;
35+
uint32_t transmit_buf_size;
36+
struct k_work rx_disabled_work;
37+
atomic_t state;
38+
};
39+
40+
#ifdef CONFIG_MODEM_BACKEND_UART_ASYNC_HWFC
41+
42+
struct rx_queue_event {
43+
uint8_t *buf;
44+
size_t len;
45+
};
46+
3347
struct modem_backend_uart_async {
48+
struct modem_backend_uart_async_common common;
49+
struct k_mem_slab rx_slab;
50+
struct k_msgq rx_queue;
51+
struct rx_queue_event rx_event;
52+
struct rx_queue_event rx_queue_buf[CONFIG_MODEM_BACKEND_UART_ASYNC_HWFC_BUFFER_COUNT];
53+
uint32_t rx_buf_size;
54+
uint8_t rx_buf_count;
55+
};
56+
57+
#else
58+
59+
struct modem_backend_uart_async {
60+
struct modem_backend_uart_async_common common;
3461
uint8_t *receive_bufs[2];
3562
uint32_t receive_buf_size;
3663
struct ring_buf receive_rb;
3764
struct k_spinlock receive_rb_lock;
38-
uint8_t *transmit_buf;
39-
uint32_t transmit_buf_size;
40-
struct k_work rx_disabled_work;
41-
atomic_t state;
4265
};
4366

67+
#endif /* CONFIG_MODEM_BACKEND_UART_ASYNC_HWFC */
68+
4469
struct modem_backend_uart {
4570
const struct device *uart;
4671
struct modem_pipe pipe;
@@ -60,7 +85,7 @@ struct modem_backend_uart {
6085

6186
struct modem_backend_uart_config {
6287
const struct device *uart;
63-
uint8_t *receive_buf;
88+
uint8_t *receive_buf __aligned(sizeof(uint32_t));
6489
uint32_t receive_buf_size;
6590
uint8_t *transmit_buf;
6691
uint32_t transmit_buf_size;

subsys/modem/backends/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ zephyr_library()
66
zephyr_library_sources_ifdef(CONFIG_MODEM_BACKEND_TTY modem_backend_tty.c)
77
zephyr_library_sources_ifdef(CONFIG_MODEM_BACKEND_UART modem_backend_uart.c)
88
zephyr_library_sources_ifdef(CONFIG_MODEM_BACKEND_UART_ISR modem_backend_uart_isr.c)
9-
zephyr_library_sources_ifdef(CONFIG_MODEM_BACKEND_UART_ASYNC modem_backend_uart_async.c)
9+
if(CONFIG_MODEM_BACKEND_UART_ASYNC)
10+
zephyr_library_sources_ifdef(CONFIG_MODEM_BACKEND_UART_ASYNC_HWFC modem_backend_uart_async_hwfc.c)
11+
zephyr_library_sources_ifndef(CONFIG_MODEM_BACKEND_UART_ASYNC_HWFC modem_backend_uart_async.c)
12+
endif()

subsys/modem/backends/Kconfig

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,19 @@ config MODEM_BACKEND_UART_ASYNC_RECEIVE_IDLE_TIMEOUT_MS
4848
int "Modem async UART receive idle timeout in milliseconds"
4949
default 30
5050

51-
endif
51+
config MODEM_BACKEND_UART_ASYNC_HWFC
52+
bool "Hardware flow control (HWFC) for the modem async UART backend"
53+
select EXPERIMENTAL
54+
55+
if MODEM_BACKEND_UART_ASYNC_HWFC
56+
57+
config MODEM_BACKEND_UART_ASYNC_HWFC_BUFFER_COUNT
58+
int "Modem async UART HWFC buffer count"
59+
range 2 4
60+
default 3
61+
62+
endif # MODEM_BACKEND_UART_ASYNC_HWFC
63+
64+
endif # MODEM_BACKEND_UART_ASYNC
5265

5366
endif # MODEM_BACKEND_UART

subsys/modem/backends/modem_backend_uart.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ struct modem_pipe *modem_backend_uart_init(struct modem_backend_uart *backend,
4545

4646
#ifdef CONFIG_MODEM_BACKEND_UART_ASYNC
4747
if (modem_backend_uart_async_is_supported(backend)) {
48-
modem_backend_uart_async_init(backend, config);
48+
if (modem_backend_uart_async_init(backend, config)) {
49+
return NULL;
50+
}
4951
return &backend->pipe;
5052
}
5153
#endif /* CONFIG_MODEM_BACKEND_UART_ASYNC */

subsys/modem/backends/modem_backend_uart_async.c

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ enum {
2222

2323
static bool modem_backend_uart_async_is_uart_stopped(struct modem_backend_uart *backend)
2424
{
25-
if (!atomic_test_bit(&backend->async.state,
25+
if (!atomic_test_bit(&backend->async.common.state,
2626
MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT) &&
27-
!atomic_test_bit(&backend->async.state,
27+
!atomic_test_bit(&backend->async.common.state,
2828
MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT) &&
29-
!atomic_test_bit(&backend->async.state,
29+
!atomic_test_bit(&backend->async.common.state,
3030
MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT) &&
31-
!atomic_test_bit(&backend->async.state,
31+
!atomic_test_bit(&backend->async.common.state,
3232
MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT)) {
3333
return true;
3434
}
@@ -38,7 +38,7 @@ static bool modem_backend_uart_async_is_uart_stopped(struct modem_backend_uart *
3838

3939
static bool modem_backend_uart_async_is_open(struct modem_backend_uart *backend)
4040
{
41-
return atomic_test_bit(&backend->async.state,
41+
return atomic_test_bit(&backend->async.common.state,
4242
MODEM_BACKEND_UART_ASYNC_STATE_OPEN_BIT);
4343
}
4444

@@ -56,7 +56,7 @@ static void modem_backend_uart_async_event_handler(const struct device *dev,
5656

5757
switch (evt->type) {
5858
case UART_TX_DONE:
59-
atomic_clear_bit(&backend->async.state,
59+
atomic_clear_bit(&backend->async.common.state,
6060
MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT);
6161
k_work_submit(&backend->transmit_idle_work);
6262
break;
@@ -65,22 +65,22 @@ static void modem_backend_uart_async_event_handler(const struct device *dev,
6565
if (modem_backend_uart_async_is_open(backend)) {
6666
LOG_WRN("Transmit aborted (%zu sent)", evt->data.tx.len);
6767
}
68-
atomic_clear_bit(&backend->async.state,
68+
atomic_clear_bit(&backend->async.common.state,
6969
MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT);
7070
k_work_submit(&backend->transmit_idle_work);
7171

7272
break;
7373

7474
case UART_RX_BUF_REQUEST:
75-
if (!atomic_test_and_set_bit(&backend->async.state,
75+
if (!atomic_test_and_set_bit(&backend->async.common.state,
7676
MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT)) {
7777
uart_rx_buf_rsp(backend->uart, backend->async.receive_bufs[0],
7878
backend->async.receive_buf_size);
7979

8080
break;
8181
}
8282

83-
if (!atomic_test_and_set_bit(&backend->async.state,
83+
if (!atomic_test_and_set_bit(&backend->async.common.state,
8484
MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT)) {
8585
uart_rx_buf_rsp(backend->uart, backend->async.receive_bufs[1],
8686
backend->async.receive_buf_size);
@@ -93,14 +93,14 @@ static void modem_backend_uart_async_event_handler(const struct device *dev,
9393

9494
case UART_RX_BUF_RELEASED:
9595
if (evt->data.rx_buf.buf == backend->async.receive_bufs[0]) {
96-
atomic_clear_bit(&backend->async.state,
96+
atomic_clear_bit(&backend->async.common.state,
9797
MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT);
9898

9999
break;
100100
}
101101

102102
if (evt->data.rx_buf.buf == backend->async.receive_bufs[1]) {
103-
atomic_clear_bit(&backend->async.state,
103+
atomic_clear_bit(&backend->async.common.state,
104104
MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT);
105105

106106
break;
@@ -131,7 +131,7 @@ static void modem_backend_uart_async_event_handler(const struct device *dev,
131131
break;
132132

133133
case UART_RX_DISABLED:
134-
atomic_clear_bit(&backend->async.state,
134+
atomic_clear_bit(&backend->async.common.state,
135135
MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT);
136136
break;
137137

@@ -144,7 +144,7 @@ static void modem_backend_uart_async_event_handler(const struct device *dev,
144144
}
145145

146146
if (modem_backend_uart_async_is_uart_stopped(backend)) {
147-
k_work_submit(&backend->async.rx_disabled_work);
147+
k_work_submit(&backend->async.common.rx_disabled_work);
148148
}
149149
}
150150

@@ -153,12 +153,13 @@ static int modem_backend_uart_async_open(void *data)
153153
struct modem_backend_uart *backend = (struct modem_backend_uart *)data;
154154
int ret;
155155

156-
atomic_clear(&backend->async.state);
156+
atomic_clear(&backend->async.common.state);
157157
ring_buf_reset(&backend->async.receive_rb);
158158

159-
atomic_set_bit(&backend->async.state, MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT);
160-
atomic_set_bit(&backend->async.state, MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT);
161-
atomic_set_bit(&backend->async.state, MODEM_BACKEND_UART_ASYNC_STATE_OPEN_BIT);
159+
atomic_set_bit(&backend->async.common.state,
160+
MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT);
161+
atomic_set_bit(&backend->async.common.state, MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT);
162+
atomic_set_bit(&backend->async.common.state, MODEM_BACKEND_UART_ASYNC_STATE_OPEN_BIT);
162163

163164
/* Receive buffers are used internally by UART, receive ring buffer is
164165
* used to store received data.
@@ -167,7 +168,7 @@ static int modem_backend_uart_async_open(void *data)
167168
backend->async.receive_buf_size,
168169
CONFIG_MODEM_BACKEND_UART_ASYNC_RECEIVE_IDLE_TIMEOUT_MS * 1000L);
169170
if (ret < 0) {
170-
atomic_clear(&backend->async.state);
171+
atomic_clear(&backend->async.common.state);
171172
return ret;
172173
}
173174

@@ -197,7 +198,7 @@ static void advertise_receive_buf_stats(struct modem_backend_uart *backend)
197198

198199
static uint32_t get_transmit_buf_size(struct modem_backend_uart *backend)
199200
{
200-
return backend->async.transmit_buf_size;
201+
return backend->async.common.transmit_buf_size;
201202
}
202203

203204
static int modem_backend_uart_async_transmit(void *data, const uint8_t *buf, size_t size)
@@ -207,7 +208,7 @@ static int modem_backend_uart_async_transmit(void *data, const uint8_t *buf, siz
207208
uint32_t bytes_to_transmit;
208209
int ret;
209210

210-
transmitting = atomic_test_and_set_bit(&backend->async.state,
211+
transmitting = atomic_test_and_set_bit(&backend->async.common.state,
211212
MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT);
212213
if (transmitting) {
213214
return 0;
@@ -217,9 +218,9 @@ static int modem_backend_uart_async_transmit(void *data, const uint8_t *buf, siz
217218
bytes_to_transmit = MIN(size, get_transmit_buf_size(backend));
218219

219220
/* Copy buf to transmit buffer which is passed to UART */
220-
memcpy(backend->async.transmit_buf, buf, bytes_to_transmit);
221+
memcpy(backend->async.common.transmit_buf, buf, bytes_to_transmit);
221222

222-
ret = uart_tx(backend->uart, backend->async.transmit_buf, bytes_to_transmit,
223+
ret = uart_tx(backend->uart, backend->async.common.transmit_buf, bytes_to_transmit,
223224
CONFIG_MODEM_BACKEND_UART_ASYNC_TRANSMIT_TIMEOUT_MS * 1000L);
224225

225226
#if CONFIG_MODEM_STATS
@@ -263,7 +264,7 @@ static int modem_backend_uart_async_close(void *data)
263264
{
264265
struct modem_backend_uart *backend = (struct modem_backend_uart *)data;
265266

266-
atomic_clear_bit(&backend->async.state, MODEM_BACKEND_UART_ASYNC_STATE_OPEN_BIT);
267+
atomic_clear_bit(&backend->async.common.state, MODEM_BACKEND_UART_ASYNC_STATE_OPEN_BIT);
267268
uart_tx_abort(backend->uart);
268269
uart_rx_disable(backend->uart);
269270
return 0;
@@ -284,8 +285,11 @@ bool modem_backend_uart_async_is_supported(struct modem_backend_uart *backend)
284285

285286
static void modem_backend_uart_async_notify_closed(struct k_work *item)
286287
{
288+
struct modem_backend_uart_async_common *common =
289+
CONTAINER_OF(item, struct modem_backend_uart_async_common, rx_disabled_work);
290+
287291
struct modem_backend_uart_async *async =
288-
CONTAINER_OF(item, struct modem_backend_uart_async, rx_disabled_work);
292+
CONTAINER_OF(common, struct modem_backend_uart_async, common);
289293

290294
struct modem_backend_uart *backend =
291295
CONTAINER_OF(async, struct modem_backend_uart, async);
@@ -310,8 +314,8 @@ static void init_stats(struct modem_backend_uart *backend)
310314
}
311315
#endif
312316

313-
void modem_backend_uart_async_init(struct modem_backend_uart *backend,
314-
const struct modem_backend_uart_config *config)
317+
int modem_backend_uart_async_init(struct modem_backend_uart *backend,
318+
const struct modem_backend_uart_config *config)
315319
{
316320
uint32_t receive_buf_size_quarter = config->receive_buf_size / 4;
317321

@@ -324,12 +328,15 @@ void modem_backend_uart_async_init(struct modem_backend_uart *backend,
324328
ring_buf_init(&backend->async.receive_rb, (receive_buf_size_quarter * 2),
325329
&config->receive_buf[receive_buf_size_quarter * 2]);
326330

327-
backend->async.transmit_buf = config->transmit_buf;
328-
backend->async.transmit_buf_size = config->transmit_buf_size;
329-
k_work_init(&backend->async.rx_disabled_work, modem_backend_uart_async_notify_closed);
331+
backend->async.common.transmit_buf = config->transmit_buf;
332+
backend->async.common.transmit_buf_size = config->transmit_buf_size;
333+
k_work_init(&backend->async.common.rx_disabled_work,
334+
modem_backend_uart_async_notify_closed);
330335
modem_pipe_init(&backend->pipe, backend, &modem_backend_uart_async_api);
331336

332337
#if CONFIG_MODEM_STATS
333338
init_stats(backend);
334339
#endif
340+
341+
return 0;
335342
}

subsys/modem/backends/modem_backend_uart_async.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ extern "C" {
1515

1616
bool modem_backend_uart_async_is_supported(struct modem_backend_uart *backend);
1717

18-
void modem_backend_uart_async_init(struct modem_backend_uart *backend,
19-
const struct modem_backend_uart_config *config);
18+
int modem_backend_uart_async_init(struct modem_backend_uart *backend,
19+
const struct modem_backend_uart_config *config);
2020

2121
#ifdef __cplusplus
2222
}

0 commit comments

Comments
 (0)