From 45ee2a0b0d105c390ee8298babe490ea348dc493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Wed, 15 Jan 2025 14:44:56 +0100 Subject: [PATCH] drivers: udc_dwc2: Fix multipart DMA OUT transfers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DMA transfers are supposed to write to buffer tail. Use the proper pointer to make multipart DMA transfers actually write the data to the intended location. The issue was observed on control write transfers where the OUT Data Stage was at least 128 bytes (because endpoint 0 transfer width is limited to 7 bits). The issue is unlikely to happen on non-control transfers because the transfer size width is at least 11 bits (at most 19 bits) and packet size counter is at least 4 bits (at most: 10 bits) which means that at least 2048 byte transfer spanning at least 15 packets (or at least 524288 byte spanning 1023 packets for 19 bits transfer size counter and 10 bits packet counter) is required to necessitate multipart DMA. Signed-off-by: Tomasz Moń --- drivers/usb/udc/udc_dwc2.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/usb/udc/udc_dwc2.c b/drivers/usb/udc/udc_dwc2.c index be50fcef6a4..fd19cadbbfc 100644 --- a/drivers/usb/udc/udc_dwc2.c +++ b/drivers/usb/udc/udc_dwc2.c @@ -658,17 +658,19 @@ static void dwc2_prep_rx(const struct device *dev, struct net_buf *buf, sys_write32(doeptsiz, doeptsiz_reg); if (priv->bufferdma) { - if (!dwc2_dma_buffer_ok_to_use(dev, buf->data, xfersize, cfg->mps)) { + void *data = net_buf_tail(buf); + + if (!dwc2_dma_buffer_ok_to_use(dev, data, xfersize, cfg->mps)) { /* Cannot continue unless buffer is bounced. Device will * cease to function. Is fatal error appropriate here? */ return; } - sys_write32((uint32_t)buf->data, + sys_write32((uint32_t)data, (mem_addr_t)&base->out_ep[ep_idx].doepdma); - sys_cache_data_invd_range(buf->data, xfersize); + sys_cache_data_invd_range(data, xfersize); } sys_write32(doepctl, doepctl_reg); @@ -2495,7 +2497,7 @@ static inline void dwc2_handle_out_xfercompl(const struct device *dev, } if (priv->bufferdma && bcnt) { - sys_cache_data_invd_range(buf->data, bcnt); + sys_cache_data_invd_range(net_buf_tail(buf), bcnt); net_buf_add(buf, bcnt); }