drivers: udc_dwc2: Fix multipart DMA OUT transfers

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ń <tomasz.mon@nordicsemi.no>
This commit is contained in:
Tomasz Moń 2025-01-15 14:44:56 +01:00 committed by Benjamin Cabé
parent 883b77fe3b
commit 45ee2a0b0d

View file

@ -658,17 +658,19 @@ static void dwc2_prep_rx(const struct device *dev, struct net_buf *buf,
sys_write32(doeptsiz, doeptsiz_reg); sys_write32(doeptsiz, doeptsiz_reg);
if (priv->bufferdma) { 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 /* Cannot continue unless buffer is bounced. Device will
* cease to function. Is fatal error appropriate here? * cease to function. Is fatal error appropriate here?
*/ */
return; return;
} }
sys_write32((uint32_t)buf->data, sys_write32((uint32_t)data,
(mem_addr_t)&base->out_ep[ep_idx].doepdma); (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); sys_write32(doepctl, doepctl_reg);
@ -2495,7 +2497,7 @@ static inline void dwc2_handle_out_xfercompl(const struct device *dev,
} }
if (priv->bufferdma && bcnt) { 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); net_buf_add(buf, bcnt);
} }