Skip to content

Commit 7b19e4f

Browse files
topisanikartben
authored andcommitted
drivers: udc: stm32: Offload data callbacks to thread
All HAL callback handling is offloaded to a separate thread, as they involve non isr-compatible operations such as mutexes. Fixes #61464 Signed-off-by: Tobias Pisani <[email protected]>
1 parent b80a058 commit 7b19e4f

File tree

2 files changed

+164
-55
lines changed

2 files changed

+164
-55
lines changed

drivers/usb/udc/Kconfig.stm32

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,26 @@ config UDC_STM32
1313
default y
1414
help
1515
STM32 USB device controller driver.
16+
17+
if UDC_STM32
18+
19+
config UDC_STM32_STACK_SIZE
20+
int "UDC controller driver internal thread stack size"
21+
default 512
22+
help
23+
STM32 USB device controller driver internal thread stack size.
24+
25+
config UDC_STM32_THREAD_PRIORITY
26+
int "STM32 USB controller driver thread priority"
27+
default 8
28+
help
29+
STM32 USB device controller driver thread priority.
30+
31+
config UDC_STM32_MAX_QMESSAGES
32+
int "STM32 UDC driver maximum number of ISR event messages"
33+
range 4 64
34+
default 8
35+
help
36+
Maximum number of messages for handling of STM32 USBD ISR events.
37+
38+
endif

drivers/usb/udc/udc_stm32.c

Lines changed: 141 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323

2424
#include "udc_common.h"
2525

26-
#include "stm32_hsem.h"
27-
2826
#include <zephyr/logging/log.h>
2927
LOG_MODULE_REGISTER(udc_stm32, CONFIG_UDC_DRIVER_LOG_LEVEL);
3028

@@ -50,6 +48,8 @@ struct udc_stm32_data {
5048
void (*pcd_prepare)(const struct device *dev);
5149
int (*clk_enable)(void);
5250
int (*clk_disable)(void);
51+
struct k_thread thread_data;
52+
struct k_msgq msgq_data;
5353
};
5454

5555
struct udc_stm32_config {
@@ -60,6 +60,18 @@ struct udc_stm32_config {
6060
uint16_t ep_mps;
6161
};
6262

63+
enum udc_stm32_msg_type {
64+
UDC_STM32_MSG_SETUP,
65+
UDC_STM32_MSG_DATA_OUT,
66+
UDC_STM32_MSG_DATA_IN,
67+
};
68+
69+
struct udc_stm32_msg {
70+
uint8_t type;
71+
uint8_t ep;
72+
uint16_t rx_count;
73+
};
74+
6375
static int udc_stm32_lock(const struct device *dev)
6476
{
6577
return udc_lock_internal(dev, K_FOREVER);
@@ -125,6 +137,26 @@ void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd)
125137
udc_submit_event(priv->dev, UDC_EVT_RESUME, 0);
126138
}
127139

140+
void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
141+
{
142+
struct udc_stm32_data *priv = hpcd2data(hpcd);
143+
struct udc_stm32_msg msg = {.type = UDC_STM32_MSG_SETUP};
144+
int err;
145+
146+
err = k_msgq_put(&priv->msgq_data, &msg, K_NO_WAIT);
147+
148+
if (err < 0) {
149+
LOG_ERR("UDC Message queue overrun");
150+
}
151+
}
152+
153+
void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
154+
{
155+
struct udc_stm32_data *priv = hpcd2data(hpcd);
156+
157+
udc_submit_event(priv->dev, UDC_EVT_SOF, 0);
158+
}
159+
128160
static int usbd_ctrl_feed_dout(const struct device *dev, const size_t length)
129161
{
130162
struct udc_stm32_data *priv = udc_get_private(dev);
@@ -143,57 +175,6 @@ static int usbd_ctrl_feed_dout(const struct device *dev, const size_t length)
143175
return 0;
144176
}
145177

146-
void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
147-
{
148-
struct udc_stm32_data *priv = hpcd2data(hpcd);
149-
struct usb_setup_packet *setup = (void *)priv->pcd.Setup;
150-
const struct device *dev = priv->dev;
151-
struct net_buf *buf;
152-
int err;
153-
154-
buf = udc_ctrl_alloc(dev, USB_CONTROL_EP_OUT,
155-
sizeof(struct usb_setup_packet));
156-
if (buf == NULL) {
157-
LOG_ERR("Failed to allocate for setup");
158-
return;
159-
}
160-
161-
udc_ep_buf_set_setup(buf);
162-
memcpy(buf->data, setup, 8);
163-
net_buf_add(buf, 8);
164-
165-
udc_ctrl_update_stage(dev, buf);
166-
167-
if (!buf->len) {
168-
return;
169-
}
170-
171-
if ((setup->bmRequestType == 0) &&
172-
(setup->bRequest == USB_SREQ_SET_ADDRESS)) {
173-
/* HAL requires we set the address before submitting status */
174-
HAL_PCD_SetAddress(&priv->pcd, setup->wValue);
175-
}
176-
177-
if (udc_ctrl_stage_is_data_out(dev)) {
178-
/* Allocate and feed buffer for data OUT stage */
179-
err = usbd_ctrl_feed_dout(dev, udc_data_stage_length(buf));
180-
if (err == -ENOMEM) {
181-
udc_submit_ep_event(dev, buf, err);
182-
}
183-
} else if (udc_ctrl_stage_is_data_in(dev)) {
184-
udc_ctrl_submit_s_in_status(dev);
185-
} else {
186-
udc_ctrl_submit_s_status(dev);
187-
}
188-
}
189-
190-
void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
191-
{
192-
struct udc_stm32_data *priv = hpcd2data(hpcd);
193-
194-
udc_submit_event(priv->dev, UDC_EVT_SOF, 0);
195-
}
196-
197178
static void udc_stm32_flush_tx_fifo(const struct device *dev)
198179
{
199180
struct udc_stm32_data *priv = udc_get_private(dev);
@@ -275,6 +256,36 @@ void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
275256
{
276257
uint32_t rx_count = HAL_PCD_EP_GetRxCount(hpcd, epnum);
277258
struct udc_stm32_data *priv = hpcd2data(hpcd);
259+
struct udc_stm32_msg msg = {
260+
.type = UDC_STM32_MSG_DATA_OUT,
261+
.ep = epnum,
262+
.rx_count = rx_count,
263+
};
264+
int err;
265+
266+
err = k_msgq_put(&priv->msgq_data, &msg, K_NO_WAIT);
267+
if (err != 0) {
268+
LOG_ERR("UDC Message queue overrun");
269+
}
270+
}
271+
272+
void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
273+
{
274+
struct udc_stm32_data *priv = hpcd2data(hpcd);
275+
struct udc_stm32_msg msg = {
276+
.type = UDC_STM32_MSG_DATA_IN,
277+
.ep = epnum,
278+
};
279+
int err;
280+
281+
err = k_msgq_put(&priv->msgq_data, &msg, K_NO_WAIT);
282+
if (err != 0) {
283+
LOG_ERR("UDC Message queue overrun");
284+
}
285+
}
286+
287+
static void handle_msg_data_out(struct udc_stm32_data *priv, uint8_t epnum, uint16_t rx_count)
288+
{
278289
const struct device *dev = priv->dev;
279290
uint8_t ep = epnum | USB_EP_DIR_OUT;
280291
struct net_buf *buf;
@@ -312,9 +323,8 @@ void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
312323
}
313324
}
314325

315-
void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
326+
static void handle_msg_data_in(struct udc_stm32_data *priv, uint8_t epnum)
316327
{
317-
struct udc_stm32_data *priv = hpcd2data(hpcd);
318328
const struct device *dev = priv->dev;
319329
uint8_t ep = epnum | USB_EP_DIR_IN;
320330
struct net_buf *buf;
@@ -378,6 +388,69 @@ void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
378388
}
379389
}
380390

391+
static void handle_msg_setup(struct udc_stm32_data *priv)
392+
{
393+
struct usb_setup_packet *setup = (void *)priv->pcd.Setup;
394+
const struct device *dev = priv->dev;
395+
struct net_buf *buf;
396+
int err;
397+
398+
buf = udc_ctrl_alloc(dev, USB_CONTROL_EP_OUT, sizeof(struct usb_setup_packet));
399+
if (buf == NULL) {
400+
LOG_ERR("Failed to allocate for setup");
401+
return;
402+
}
403+
404+
udc_ep_buf_set_setup(buf);
405+
memcpy(buf->data, setup, 8);
406+
net_buf_add(buf, 8);
407+
408+
udc_ctrl_update_stage(dev, buf);
409+
410+
if (!buf->len) {
411+
return;
412+
}
413+
414+
if ((setup->bmRequestType == 0) && (setup->bRequest == USB_SREQ_SET_ADDRESS)) {
415+
/* HAL requires we set the address before submitting status */
416+
HAL_PCD_SetAddress(&priv->pcd, setup->wValue);
417+
}
418+
419+
if (udc_ctrl_stage_is_data_out(dev)) {
420+
/* Allocate and feed buffer for data OUT stage */
421+
err = usbd_ctrl_feed_dout(dev, udc_data_stage_length(buf));
422+
if (err == -ENOMEM) {
423+
udc_submit_ep_event(dev, buf, err);
424+
}
425+
} else if (udc_ctrl_stage_is_data_in(dev)) {
426+
udc_ctrl_submit_s_in_status(dev);
427+
} else {
428+
udc_ctrl_submit_s_status(dev);
429+
}
430+
}
431+
432+
static void udc_stm32_thread_handler(void *arg1, void *arg2, void *arg3)
433+
{
434+
const struct device *dev = arg1;
435+
struct udc_stm32_data *priv = udc_get_private(dev);
436+
struct udc_stm32_msg msg;
437+
438+
while (true) {
439+
k_msgq_get(&priv->msgq_data, &msg, K_FOREVER);
440+
switch (msg.type) {
441+
case UDC_STM32_MSG_SETUP:
442+
handle_msg_setup(priv);
443+
break;
444+
case UDC_STM32_MSG_DATA_IN:
445+
handle_msg_data_in(priv, msg.ep);
446+
break;
447+
case UDC_STM32_MSG_DATA_OUT:
448+
handle_msg_data_out(priv, msg.ep, msg.rx_count);
449+
break;
450+
}
451+
}
452+
}
453+
381454
#if DT_INST_NODE_HAS_PROP(0, disconnect_gpios)
382455
void HAL_PCDEx_SetConnectionState(PCD_HandleTypeDef *hpcd, uint8_t state)
383456
{
@@ -1128,6 +1201,10 @@ static const struct gpio_dt_spec ulpi_reset =
11281201
GPIO_DT_SPEC_GET_OR(DT_PHANDLE(DT_INST(0, st_stm32_otghs), phys), reset_gpios, {0});
11291202
#endif
11301203

1204+
static char udc_msgq_buf_0[CONFIG_UDC_STM32_MAX_QMESSAGES * sizeof(struct udc_stm32_msg)];
1205+
1206+
K_THREAD_STACK_DEFINE(udc_stm32_stack_0, CONFIG_UDC_STM32_STACK_SIZE);
1207+
11311208
static int udc_stm32_driver_init0(const struct device *dev)
11321209
{
11331210
struct udc_stm32_data *priv = udc_get_private(dev);
@@ -1185,6 +1262,15 @@ static int udc_stm32_driver_init0(const struct device *dev)
11851262
priv->clk_disable = priv_clock_disable;
11861263
priv->pcd_prepare = priv_pcd_prepare;
11871264

1265+
k_msgq_init(&priv->msgq_data, udc_msgq_buf_0, sizeof(struct udc_stm32_msg),
1266+
CONFIG_UDC_STM32_MAX_QMESSAGES);
1267+
1268+
k_thread_create(&priv->thread_data, udc_stm32_stack_0,
1269+
K_THREAD_STACK_SIZEOF(udc_stm32_stack_0), udc_stm32_thread_handler,
1270+
(void *)dev, NULL, NULL, K_PRIO_COOP(CONFIG_UDC_STM32_THREAD_PRIORITY),
1271+
K_ESSENTIAL, K_NO_WAIT);
1272+
k_thread_name_set(&priv->thread_data, dev->name);
1273+
11881274
IRQ_CONNECT(UDC_STM32_IRQ, UDC_STM32_IRQ_PRI, udc_stm32_irq,
11891275
DEVICE_DT_INST_GET(0), 0);
11901276

0 commit comments

Comments
 (0)